Skip to content

Commit d156a5e

Browse files
committed
block parser cli
1 parent 59c370f commit d156a5e

6 files changed

Lines changed: 174 additions & 3 deletions

File tree

packages/block-parser/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
.pnp.js
77

88
types
9+
dist
910

1011
# testing
1112
/coverage

packages/block-parser/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,31 @@ A standalone block parser for parsing comment blocks in markdown and other file
88
npm install comment-block-parser
99
```
1010

11+
## CLI
12+
13+
Parse comment blocks from the command line.
14+
15+
```bash
16+
# Parse from argument
17+
comment-block-parser --match auto '# Title\n<!-- auto TOC -->content<!-- /auto -->'
18+
19+
# Parse from stdin
20+
cat file.md | comment-block-parser --match auto
21+
22+
# Extract specific data with jq
23+
cat file.md | comment-block-parser --find auto | jq '.blocks[0].options'
24+
```
25+
26+
### CLI Options
27+
28+
```
29+
--open, --match, --find Opening comment keyword (default: doc-gen)
30+
--close Closing comment keyword (auto-derived from open)
31+
--syntax Comment syntax: md, js, html, etc (default: md)
32+
--help, -h Show help
33+
--version, -v Show version
34+
```
35+
1136
## Example
1237

1338
The library works with a variety of [syntaxes](#supported-syntaxes).

packages/block-parser/cli.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#!/usr/bin/env node
2+
// CLI for parsing comment blocks from markdown and other files
3+
const mri = require('mri')
4+
const { parseBlocks } = require('./src/index')
5+
6+
const argv = process.argv.slice(2)
7+
const options = mri(argv)
8+
9+
/**
10+
* Read all data from stdin
11+
* @returns {Promise<string>}
12+
*/
13+
function readStdin() {
14+
return new Promise((resolve, reject) => {
15+
let data = ''
16+
process.stdin.setEncoding('utf8')
17+
process.stdin.on('data', chunk => data += chunk)
18+
process.stdin.on('end', () => resolve(data))
19+
process.stdin.on('error', reject)
20+
})
21+
}
22+
23+
/**
24+
* Interpret escape sequences in string (e.g., \n -> newline)
25+
* @param {string} str
26+
* @returns {string}
27+
*/
28+
function interpretEscapes(str) {
29+
if (!str) return str
30+
return str.replace(/\\n/g, '\n').replace(/\\t/g, '\t')
31+
}
32+
33+
/**
34+
* JSON.stringify replacer that handles RegExp objects
35+
* @param {string} _key
36+
* @param {any} value
37+
*/
38+
function jsonReplacer(_key, value) {
39+
if (value instanceof RegExp) {
40+
return value.toString()
41+
}
42+
return value
43+
}
44+
45+
/**
46+
* Check if string looks like content vs a file path
47+
* @param {string} str
48+
* @returns {boolean}
49+
*/
50+
function isContent(str) {
51+
if (!str) return false
52+
if (str.includes('\n') || str.includes('\\n')) return true
53+
if (str.includes('<!--')) return true
54+
if (str.startsWith('#')) return true
55+
return false
56+
}
57+
58+
async function run() {
59+
if (options.help || options.h) {
60+
console.log(`
61+
Usage: block-parser [options] [content]
62+
63+
Options:
64+
--open Opening comment keyword (default: doc-gen)
65+
--close Closing comment keyword (default: end-doc-gen)
66+
--syntax Comment syntax: md, js, html, etc (default: md)
67+
--help, -h Show this help message
68+
--version, -v Show version
69+
70+
Examples:
71+
block-parser "# Title\\n<!-- doc-gen TOC --><!-- end-doc-gen -->"
72+
echo "<!-- doc-gen TOC --><!-- end-doc-gen -->" | block-parser
73+
block-parser --open auto --close /auto "<!-- auto TOC --><!-- /auto -->"
74+
`)
75+
return
76+
}
77+
78+
if (options.version || options.v) {
79+
const pkg = require('./package.json')
80+
console.log(`${pkg.name} v${pkg.version}`)
81+
return
82+
}
83+
84+
const word = options.open || options.match || options.find
85+
const openKeyword = word || 'doc-gen'
86+
const closeKeyword = options.close || (word && word !== 'doc-gen' ? `/${word}` : 'end-doc-gen')
87+
const syntax = options.syntax || 'md'
88+
89+
// Check if first positional arg is content
90+
let firstArg = options._ && options._[0]
91+
// Handle mri assigning content to a flag
92+
if (typeof options.open === 'string' && isContent(options.open)) {
93+
firstArg = options.open
94+
}
95+
96+
if (firstArg && isContent(firstArg)) {
97+
const content = interpretEscapes(firstArg)
98+
const result = parseBlocks(content, {
99+
syntax,
100+
open: openKeyword,
101+
close: closeKeyword,
102+
})
103+
console.log(JSON.stringify(result, jsonReplacer, 2))
104+
return
105+
}
106+
107+
// Check for stdin pipe
108+
const hasNoFileArgs = !options._ || options._.length === 0
109+
if (!process.stdin.isTTY && hasNoFileArgs) {
110+
const content = await readStdin()
111+
if (content.trim()) {
112+
const result = parseBlocks(content, {
113+
syntax,
114+
open: openKeyword,
115+
close: closeKeyword,
116+
})
117+
console.log(JSON.stringify(result, jsonReplacer, 2))
118+
return
119+
}
120+
}
121+
122+
// No input provided
123+
console.error('No input provided. Use --help for usage.')
124+
process.exit(1)
125+
}
126+
127+
run().catch(err => {
128+
console.error(err.message)
129+
process.exit(1)
130+
})

packages/block-parser/package.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
"description": "Block parser for markdown-magic - Parse comment blocks in markdown and other files",
55
"main": "src/index.js",
66
"types": "types/index.d.ts",
7+
"bin": {
8+
"comment-block-parser": "cli.js"
9+
},
710
"files": [
811
"src",
912
"types",
13+
"cli.js",
1014
"README.md",
1115
"package.json"
1216
],
@@ -29,14 +33,20 @@
2933
"benchmark": "node test/benchmark.js",
3034
"types": "tsc --emitDeclarationOnly --outDir types",
3135
"build": "pnpm run types",
32-
"clean": "rimraf types",
36+
"bundle": "npm run bundle:all",
37+
"bundle:all": "npm run bundle:mac && npm run bundle:linux && npm run bundle:windows",
38+
"bundle:mac": "bun build ./cli.js --compile --minify --target=bun-darwin-arm64 --outfile dist/block-parser-darwin-arm64 && bun build ./cli.js --compile --minify --target=bun-darwin-x64 --outfile dist/block-parser-darwin-x64",
39+
"bundle:linux": "bun build ./cli.js --compile --minify --target=bun-linux-x64 --outfile dist/block-parser-linux-x64 && bun build ./cli.js --compile --minify --target=bun-linux-arm64 --outfile dist/block-parser-linux-arm64",
40+
"bundle:windows": "bun build ./cli.js --compile --minify --target=bun-windows-x64 --outfile dist/block-parser-windows-x64.exe",
41+
"clean": "rimraf types dist",
3342
"publish": "git push origin && git push origin --tags",
3443
"release:patch": "pnpm version patch && pnpm publish --no-git-checks",
3544
"release:minor": "pnpm version minor && pnpm publish --no-git-checks",
3645
"release:major": "pnpm version major && pnpm publish --no-git-checks"
3746
},
3847
"dependencies": {
3948
"dedent": "^1.6.0",
49+
"mri": "^1.2.0",
4050
"oparser": "^3.0.24"
4151
},
4252
"devDependencies": {

packages/block-parser/src/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ const defaultOptions = {
1515
close: CLOSE_WORD,
1616
}
1717

18-
19-
2018
/**
2119
* Details about the open tag
2220
* @typedef {Object} OpenBlock
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Title
2+
3+
<!-- auto TOC cool -->
4+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
5+
<!-- /auto -->
6+
7+
## One

0 commit comments

Comments
 (0)