markdown-magic 4.0.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +1 -0
- package/package.json +13 -8
- package/src/cli-run.js +159 -0
- package/src/utils/fs.test.js +1 -0
- package/src/utils/remoteRequest.js +0 -20
package/cli.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-magic",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Automatically update markdown files with content from external sources",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,6 +22,11 @@
|
|
|
22
22
|
"docs": "node examples/generate-readme.js",
|
|
23
23
|
"test": "uvu . '.test.([mc]js|[jt]sx?)$'",
|
|
24
24
|
"cli": "node ./cli.js --path 'README.md' --config ./markdown.config.js",
|
|
25
|
+
"bundle": "npm run bundle:all",
|
|
26
|
+
"bundle:all": "npm run bundle:mac && npm run bundle:linux && npm run bundle:windows",
|
|
27
|
+
"bundle:mac": "bun build ./cli.js --compile --minify --target=bun-darwin-arm64 --outfile dist/md-magic-darwin-arm64 && bun build ./cli.js --compile --minify --target=bun-darwin-x64 --outfile dist/md-magic-darwin-x64",
|
|
28
|
+
"bundle:linux": "bun build ./cli.js --compile --minify --target=bun-linux-x64 --outfile dist/md-magic-linux-x64 && bun build ./cli.js --compile --minify --target=bun-linux-arm64 --outfile dist/md-magic-linux-arm64",
|
|
29
|
+
"bundle:windows": "bun build ./cli.js --compile --minify --target=bun-windows-x64 --outfile dist/md-magic-windows-x64.exe",
|
|
25
30
|
"postpublish": "git push origin && git push origin --tags",
|
|
26
31
|
"release:patch": "pnpm version patch --git-tag-version && pnpm publish",
|
|
27
32
|
"release:minor": "pnpm version minor --git-tag-version && pnpm publish",
|
|
@@ -36,9 +41,10 @@
|
|
|
36
41
|
},
|
|
37
42
|
"dependencies": {
|
|
38
43
|
"@davidwells/md-utils": "0.0.53",
|
|
39
|
-
"
|
|
40
|
-
"comment-block-
|
|
41
|
-
"comment-block-
|
|
44
|
+
"color-convert": "^2.0.1",
|
|
45
|
+
"comment-block-parser": "1.1.2",
|
|
46
|
+
"comment-block-replacer": "0.1.4",
|
|
47
|
+
"comment-block-transformer": "0.2.3",
|
|
42
48
|
"globrex": "^0.1.2",
|
|
43
49
|
"gray-matter": "^4.0.3",
|
|
44
50
|
"is-glob": "^4.0.3",
|
|
@@ -48,11 +54,10 @@
|
|
|
48
54
|
"module-alias": "^2.2.3",
|
|
49
55
|
"mri": "^1.2.0",
|
|
50
56
|
"node-fetch": "^2.7.0",
|
|
51
|
-
"oparser": "^3.0.
|
|
57
|
+
"oparser": "^3.0.24",
|
|
52
58
|
"punycode": "^2.3.1",
|
|
53
59
|
"smart-glob": "^1.0.2",
|
|
54
|
-
"string-width": "^4.2.3"
|
|
55
|
-
"sync-request": "^6.1.0"
|
|
60
|
+
"string-width": "^4.2.3"
|
|
56
61
|
},
|
|
57
62
|
"devDependencies": {
|
|
58
63
|
"concordance": "^5.0.1",
|
|
@@ -65,5 +70,5 @@
|
|
|
65
70
|
"publishConfig": {
|
|
66
71
|
"access": "public"
|
|
67
72
|
},
|
|
68
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "4c7432d3518d9c6eac0019df43863ffc5857d417"
|
|
69
74
|
}
|
package/src/cli-run.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
2
3
|
const { loadConfig } = require('./utils/load-config')
|
|
3
4
|
const { findUp } = require('./utils/fs')
|
|
4
5
|
const { markdownMagic } = require('./')
|
|
6
|
+
const { processFile } = require('comment-block-replacer')
|
|
5
7
|
const { parse } = require('oparser')
|
|
8
|
+
const defaultTransforms = require('./transforms')
|
|
6
9
|
const { getGlobGroupsFromArgs } = require('./globparse')
|
|
7
10
|
// const { deepLog } = require('./utils/logs')
|
|
8
11
|
// const { uxParse } = require('./argparse/argparse')
|
|
@@ -10,6 +13,75 @@ const argv = process.argv.slice(2)
|
|
|
10
13
|
const cwd = process.cwd()
|
|
11
14
|
const defaultConfigPath = 'md.config.js'
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Render markdown with ANSI styling for terminal output
|
|
18
|
+
* @param {string} content
|
|
19
|
+
*/
|
|
20
|
+
// async function renderMarkdown(content) {
|
|
21
|
+
// const { render, themes } = await import('markdansi')
|
|
22
|
+
// const githubDark = {
|
|
23
|
+
// ...themes.default,
|
|
24
|
+
// heading: { color: 'white', bold: true },
|
|
25
|
+
// strong: { bold: true },
|
|
26
|
+
// emph: { italic: true },
|
|
27
|
+
// inlineCode: { color: 'yellow' },
|
|
28
|
+
// blockCode: { color: 'white' },
|
|
29
|
+
// link: { color: 'cyan', underline: true },
|
|
30
|
+
// quote: { color: 'gray', italic: true },
|
|
31
|
+
// hr: { color: 'gray', dim: true },
|
|
32
|
+
// listMarker: { color: 'blue' },
|
|
33
|
+
// tableHeader: { color: 'white', bold: true },
|
|
34
|
+
// tableCell: { color: 'white' },
|
|
35
|
+
// }
|
|
36
|
+
// return render(content, { theme: githubDark })
|
|
37
|
+
// }
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Read all data from stdin
|
|
41
|
+
* @returns {Promise<string>}
|
|
42
|
+
*/
|
|
43
|
+
function readStdin() {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
let data = ''
|
|
46
|
+
process.stdin.setEncoding('utf8')
|
|
47
|
+
process.stdin.on('data', chunk => data += chunk)
|
|
48
|
+
process.stdin.on('end', () => resolve(data))
|
|
49
|
+
process.stdin.on('error', reject)
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Interpret escape sequences in string (e.g., \n -> newline)
|
|
55
|
+
* @param {string} str
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
function interpretEscapes(str) {
|
|
59
|
+
if (!str) return str
|
|
60
|
+
return str.replace(/\\n/g, '\n').replace(/\\t/g, '\t')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if string looks like markdown content vs a file path
|
|
65
|
+
* @param {string} str
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
function isMarkdownContent(str) {
|
|
69
|
+
if (!str) return false
|
|
70
|
+
// Has newlines (real or escaped) = likely content
|
|
71
|
+
if (str.includes('\n') || str.includes('\\n')) return true
|
|
72
|
+
// Has markdown comment blocks = likely content
|
|
73
|
+
if (str.includes('<!--')) return true
|
|
74
|
+
// Check if file exists
|
|
75
|
+
try {
|
|
76
|
+
if (fs.existsSync(str)) return false
|
|
77
|
+
} catch (e) {
|
|
78
|
+
// ignore
|
|
79
|
+
}
|
|
80
|
+
// Has markdown heading at start = likely content
|
|
81
|
+
if (str.startsWith('#')) return true
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
|
|
13
85
|
async function getBaseDir(opts = {}) {
|
|
14
86
|
const { currentDir = cwd } = opts
|
|
15
87
|
const gitDir = await findUp(currentDir, '.git')
|
|
@@ -21,6 +93,93 @@ function findSingleDashStrings(arr) {
|
|
|
21
93
|
}
|
|
22
94
|
|
|
23
95
|
async function runCli(options = {}, rawArgv) {
|
|
96
|
+
if (options.help || options.h) {
|
|
97
|
+
console.log(`
|
|
98
|
+
Usage: md-magic [options] [files...]
|
|
99
|
+
|
|
100
|
+
Options:
|
|
101
|
+
--files, --file Files or glob patterns to process
|
|
102
|
+
--config Path to config file (default: md.config.js)
|
|
103
|
+
--output Output directory
|
|
104
|
+
--open Opening comment keyword (default: docs)
|
|
105
|
+
--close Closing comment keyword (default: /docs)
|
|
106
|
+
--pretty Render output with ANSI styling
|
|
107
|
+
--dry Dry run - show what would be changed
|
|
108
|
+
--debug Show debug output
|
|
109
|
+
--help, -h Show this help message
|
|
110
|
+
--version, -v Show version
|
|
111
|
+
|
|
112
|
+
Examples:
|
|
113
|
+
md-magic README.md
|
|
114
|
+
md-magic --files "**/*.md"
|
|
115
|
+
md-magic --config ./my-config.js
|
|
116
|
+
|
|
117
|
+
Stdin/stdout mode:
|
|
118
|
+
cat file.md | md-magic
|
|
119
|
+
echo "<!-- docs TOC --><!-- /docs -->" | md-magic
|
|
120
|
+
md-magic "# Title\\n<!-- docs TOC --><!-- /docs -->"
|
|
121
|
+
`)
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (options.version || options.v) {
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
const pkg = require('../package.json')
|
|
128
|
+
console.log(`${pkg.name} v${pkg.version}`)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check if first positional arg is markdown content (before stdin check)
|
|
133
|
+
const firstArg = options._ && options._[0]
|
|
134
|
+
const openKeyword = options.open || 'docs'
|
|
135
|
+
const closeKeyword = options.close || (options.open && options.open !== 'docs' ? `/${options.open}` : '/docs')
|
|
136
|
+
if (firstArg && isMarkdownContent(firstArg)) {
|
|
137
|
+
const content = interpretEscapes(firstArg)
|
|
138
|
+
const result = await processFile({
|
|
139
|
+
content,
|
|
140
|
+
syntax: 'md',
|
|
141
|
+
open: openKeyword,
|
|
142
|
+
close: closeKeyword,
|
|
143
|
+
transforms: defaultTransforms,
|
|
144
|
+
dryRun: true,
|
|
145
|
+
})
|
|
146
|
+
// TODO future pretty option
|
|
147
|
+
// if (options.pretty) {
|
|
148
|
+
// console.log(await renderMarkdown(result.updatedContents))
|
|
149
|
+
// } else {
|
|
150
|
+
// console.log()
|
|
151
|
+
// console.log(result.updatedContents)
|
|
152
|
+
// }
|
|
153
|
+
console.log(result.updatedContents)
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Check for stdin pipe (when no positional file args provided)
|
|
158
|
+
const hasNoFileArgs = !options._ || options._.length === 0
|
|
159
|
+
const hasPipedInput = !process.stdin.isTTY && hasNoFileArgs
|
|
160
|
+
if (hasPipedInput) {
|
|
161
|
+
const content = await readStdin()
|
|
162
|
+
if (content.trim()) {
|
|
163
|
+
const result = await processFile({
|
|
164
|
+
content,
|
|
165
|
+
syntax: 'md',
|
|
166
|
+
open: openKeyword,
|
|
167
|
+
close: closeKeyword,
|
|
168
|
+
transforms: defaultTransforms,
|
|
169
|
+
dryRun: true, // Don't write files
|
|
170
|
+
})
|
|
171
|
+
// TODO future pretty option
|
|
172
|
+
// if (options.pretty) {
|
|
173
|
+
// console.log(await renderMarkdown(result.updatedContents))
|
|
174
|
+
// } else {
|
|
175
|
+
// console.log()
|
|
176
|
+
// console.log(result.updatedContents)
|
|
177
|
+
// }
|
|
178
|
+
console.log(result.updatedContents)
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
24
183
|
let configFile
|
|
25
184
|
let opts = {}
|
|
26
185
|
|
package/src/utils/fs.test.js
CHANGED
|
@@ -1,28 +1,9 @@
|
|
|
1
1
|
const fetch = require('node-fetch')
|
|
2
|
-
const request = require('sync-request')
|
|
3
2
|
|
|
4
3
|
function formatUrl(url = '') {
|
|
5
4
|
return url.match(/^https?:\/\//) ? url : `https://${url}`
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
function remoteRequestSync(url, settings = {}, srcPath) {
|
|
9
|
-
let body
|
|
10
|
-
const finalUrl = formatUrl(url)
|
|
11
|
-
try {
|
|
12
|
-
// @ts-expect-error
|
|
13
|
-
const res = request('GET', finalUrl)
|
|
14
|
-
body = res.getBody('utf8')
|
|
15
|
-
} catch (e) {
|
|
16
|
-
console.log(`⚠️ WARNING: REMOTE URL "${finalUrl}" NOT FOUND`)
|
|
17
|
-
const msg = (e.message || '').split('\n')[0] + `\nFix "${url}" value in ${srcPath}`
|
|
18
|
-
console.log(msg)
|
|
19
|
-
if (settings.failOnMissingRemote) {
|
|
20
|
-
throw new Error(msg)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return body
|
|
24
|
-
}
|
|
25
|
-
|
|
26
7
|
async function remoteRequest(url, settings = {}, srcPath) {
|
|
27
8
|
let body
|
|
28
9
|
const finalUrl = formatUrl(url)
|
|
@@ -45,7 +26,6 @@ async function remoteRequest(url, settings = {}, srcPath) {
|
|
|
45
26
|
}
|
|
46
27
|
|
|
47
28
|
module.exports = {
|
|
48
|
-
remoteRequestSync,
|
|
49
29
|
remoteRequest
|
|
50
30
|
}
|
|
51
31
|
|