initial push

This commit is contained in:
Niccolo Borgioli 2023-11-16 13:29:00 +01:00
commit bc2f6242b2
No known key found for this signature in database
GPG Key ID: D93C615F75EE4F0B
7 changed files with 334 additions and 0 deletions

176
.gitignore vendored Normal file
View File

@ -0,0 +1,176 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
\*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
\*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
\*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
\*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v20.9.0

23
README.md Normal file
View File

@ -0,0 +1,23 @@
# Markdown import plugin
This is a `markdown-it` plugin to include/import raw files from your filesystem.
## Features
- No dependencies
- Recursive import
- Import whatever file
- Customizable RegEx
## Installation
```bash
npm install @nicco.io/markdown-it-import
```
## Similar works
There are two very similar plugins, which this one is def. inspired by, however while the one can only import `.md` files, the other cannot select single lines.
- https://github.com/camelaissani/markdown-it-include
- https://github.com/h-hg/markdown-it-import

BIN
bun.lockb Executable file

Binary file not shown.

47
package.json Normal file
View File

@ -0,0 +1,47 @@
{
"name": "@nicco.io/markdown-it-import",
"version": "1.0.0-rc.0",
"description": "Markdown-it plugin which adds the ability to include markdown fragment files.",
"keywords": [
"markdown-it-plugin",
"markdown-it",
"markdown",
"include"
],
"repository": {
"type": "git",
"url": "https://github.com/cupcakearmy/markdown-it-import"
},
"license": "MIT",
"author": {
"name": "cupcakearmy",
"email": "hi@nicco.io",
"url": "https://github.com/cupcakearmy"
},
"type": "module",
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./dist/index.js"
}
},
"types": "./dist/src/index.d.ts",
"files": [
"./dist"
],
"scripts": {
"build": "rm -rf ./dist && tsc && bun build ./src/index.ts --outfile dist/index.js --target node"
},
"devDependencies": {
"bun-types": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"engines": {
"node": ">=14"
},
"publishConfig": {
"access": "public"
}
}

69
src/index.ts Normal file
View File

@ -0,0 +1,69 @@
import fs from 'node:fs'
import path from 'node:path'
import process from 'node:process'
const defaultOptions = {
matcher: /@import\((?<file>.+)\)(\s*?\[(?<range>\d+-\d+)\])?/g,
root: process.cwd(),
}
export type Options = Partial<typeof defaultOptions>
export function importPlugin(md: any, options: Options = {}) {
// Options
const o = Object.assign(defaultOptions, options)
// Parser
function parse(code: string, alreadyVisited: string[] = []) {
if (!o.matcher.global) throw new Error('RegExp must be global')
o.matcher.lastIndex = 0 // Reset Regexp
const newFiles = []
while (true) {
const match = o.matcher.exec(code)
if (!match) break
// Get groups
const file = match.groups?.['file']?.trim()
if (!file) throw new Error('Regexp must expose a named group "file"')
const range = match.groups?.['range']
?.trim()
.split('-')
.map((n) => parseInt(n))
// Load content
const filename = path.resolve(o.root, file)
if (alreadyVisited.includes(filename)) throw new Error(`cycles are not allowed, already parsed "${filename}"`)
newFiles.push(filename)
const exists = fs.existsSync(filename)
if (!exists) throw new Error(`cannot locate file "${filename}"`)
let contents = fs.readFileSync(filename, 'utf-8')
// Apply line range
if (range) {
const lines = contents.split('\n')
const maxLines = lines.length
const start = range[0]
const end = range[1]
if (start === undefined || end === undefined) throw new Error(`invalid range "${match.groups?.['range']}"`)
if (end < start) throw new Error(`end position "${end}" cannot be smaller than start "${start}"`)
if (start < 1) throw new Error(`start position "${start}" needs to be at least 1`)
if (end > maxLines) throw new Error(`end position "${end}" is higher than the file contents "${maxLines}"`)
contents = lines.slice(start - 1, end).join('\n')
}
// Recursion
contents = parse(contents, [...alreadyVisited, ...newFiles])
// Replace
code = code.slice(0, match.index) + contents + code.slice(match.index + match[0].length, code.length)
}
return code
}
// Mount hook
md.core.ruler.before('normalize', 'include', (state: any) => {
state.src = parse(state.src)
})
}

18
tsconfig.json Normal file
View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"lib": ["ESNext"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"composite": true,
"strict": true,
"types": [
"bun-types" // add Bun global
]
},
"include": ["./src"]
}