Skip to content

Commit a5d3f6d

Browse files
committed
feat(cli): add --json output, .md-ignore support, improve error msgs
1 parent d156a5e commit a5d3f6d

5 files changed

Lines changed: 77 additions & 26 deletions

File tree

packages/core/src/cli-run.js

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ function interpretEscapes(str) {
6060
return str.replace(/\\n/g, '\n').replace(/\\t/g, '\t')
6161
}
6262

63+
/**
64+
* JSON.stringify replacer that handles RegExp objects
65+
* @param {string} key
66+
* @param {any} value
67+
*/
68+
function jsonReplacer(key, value) {
69+
if (value instanceof RegExp) {
70+
return value.toString()
71+
}
72+
return value
73+
}
74+
6375
/**
6476
* Check if string looks like markdown content vs a file path
6577
* @param {string} str
@@ -103,6 +115,7 @@ Options:
103115
--output Output directory
104116
--open Opening comment keyword (default: docs)
105117
--close Closing comment keyword (default: /docs)
118+
--json Output full result as JSON
106119
--pretty Render output with ANSI styling
107120
--dry Dry run - show what would be changed
108121
--debug Show debug output
@@ -130,7 +143,12 @@ Stdin/stdout mode:
130143
}
131144

132145
// Check if first positional arg is markdown content (before stdin check)
133-
const firstArg = options._ && options._[0]
146+
// Handle case where mri assigns content to a flag (e.g., --json '# content')
147+
let firstArg = options._ && options._[0]
148+
const outputJson = options.json === true || (typeof options.json === 'string' && isMarkdownContent(options.json))
149+
if (typeof options.json === 'string' && isMarkdownContent(options.json)) {
150+
firstArg = options.json
151+
}
134152
const openKeyword = options.open || 'docs'
135153
const closeKeyword = options.close || (options.open && options.open !== 'docs' ? `/${options.open}` : '/docs')
136154
if (firstArg && isMarkdownContent(firstArg)) {
@@ -143,14 +161,12 @@ Stdin/stdout mode:
143161
transforms: defaultTransforms,
144162
dryRun: true,
145163
})
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)
164+
console.log('result', result)
165+
if (outputJson) {
166+
console.log(JSON.stringify(result, jsonReplacer, 2))
167+
} else {
168+
console.log(result.updatedContents)
169+
}
154170
return
155171
}
156172

@@ -168,14 +184,11 @@ Stdin/stdout mode:
168184
transforms: defaultTransforms,
169185
dryRun: true, // Don't write files
170186
})
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)
187+
if (outputJson) {
188+
console.log(JSON.stringify(result, jsonReplacer, 2))
189+
} else {
190+
console.log(result.updatedContents)
191+
}
179192
return
180193
}
181194
}

packages/core/src/index.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const remoteTransform = require('./transforms/remote')
1313
const installTransform = require('./transforms/install')
1414
const { getSyntaxInfo } = require('./utils/syntax')
1515
const { onlyUnique, getCodeLocation, pluralize } = require('./utils')
16-
const { readFile, resolveOutputPath, resolveFlatPath } = require('./utils/fs')
16+
const { readFile, resolveOutputPath, resolveFlatPath, hasIgnoreFile } = require('./utils/fs')
1717
const stringBreak = require('./utils/string-break')
1818
const { processFile } = require('comment-block-replacer')
1919
const { blockTransformer } = require('comment-block-transformer')
@@ -257,7 +257,10 @@ async function markdownMagic(globOrOpts = {}, options = {}) {
257257

258258
let files = []
259259
try {
260-
files = (await Promise.all(pathsPromise)).flat().filter(onlyUnique)
260+
files = (await Promise.all(pathsPromise))
261+
.flat()
262+
.filter(onlyUnique)
263+
.filter((f) => !hasIgnoreFile(f))
261264
// opts.files = files
262265
} catch (e) {
263266
// console.log(e.message)
@@ -541,12 +544,16 @@ async function markdownMagic(globOrOpts = {}, options = {}) {
541544
let planMsg = `${count} Found ${transformsToRun.length} transforms in ${item.srcPath}`
542545
planTotal = planTotal + transformsToRun.length
543546
// logger(`Found ${transformsToRun.length} transforms in ${item.srcPath}`)
547+
const maxPrefixLen = Math.max(...transformsToRun.map((t) => {
548+
return `"${t.transform}" on line ${t.lines[0]}`.length
549+
}))
544550
transformsToRun.forEach((trn) => {
545551
const line = trn.lines[0]
552+
const prefix = `"${trn.transform}" on line ${line}`
553+
const paddedPrefix = prefix.padEnd(maxPrefixLen)
546554
const location = getCodeLocation(item.srcPath, line)
547-
const planData = ` - "${trn.transform}" at line ${line} ${location}`
555+
const planData = ` - ${paddedPrefix} ${location}`
548556
planMsg += `\n${planData}`
549-
// logger(` - "${trn.transform}" at line ${trn.lines[0]}`)
550557
})
551558
const newLine = plan.length !== i + 1 ? '\n' : ''
552559
return `${planMsg}${newLine}`

packages/core/src/transforms/code/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ module.exports = async function CODE(api) {
9191
if (src === './relative/path/to/code.js') {
9292
return api.content
9393
} else {
94-
console.log(`FILE NOT FOUND ${codeFilePath}`)
95-
throw e
94+
const err = new Error(`FILE NOT FOUND: ${codeFilePath}\n Referenced in: ${srcPath}\n src="${src}"`)
95+
err.code = 'ENOENT'
96+
throw err
9697
}
9798
}
9899
}

packages/core/src/transforms/file.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,15 @@ module.exports = function FILE(api) {
2323
if (options.src === './path/to/file') {
2424
return api.content
2525
}
26-
console.log(`FILE NOT FOUND ${resolvedFilePath}`)
27-
throw e
26+
const err = new Error(`FILE NOT FOUND: ${resolvedFilePath}
27+
28+
Referenced in: ${srcPath}
29+
30+
Via the "src" attribute: src="${options.src}"
31+
32+
`)
33+
err.code = 'ENOENT'
34+
throw err
2835
}
2936
}
3037

packages/core/src/utils/fs.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,34 @@ function isLocalPath(filePath) {
192192
return _isLocalPath(filePath)
193193
}
194194

195+
const fsSync = require('fs')
196+
197+
/**
198+
* Check if file's directory or any parent has .md-ignore
199+
* @param {string} filePath - Absolute path to file
200+
* @returns {boolean} True if should be ignored
201+
*/
202+
function hasIgnoreFile(filePath) {
203+
let dir = dirname(filePath)
204+
const root = resolve('/')
205+
while (dir !== root) {
206+
const ignoreFile = join(dir, '.md-ignore')
207+
if (fsSync.existsSync(ignoreFile)) {
208+
return true
209+
}
210+
const parent = dirname(dir)
211+
if (parent === dir) break
212+
dir = parent
213+
}
214+
return false
215+
}
216+
195217
module.exports = {
196218
isLocalPath,
197219
writeFile,
198-
readFile,
220+
readFile,
199221
findUp,
222+
hasIgnoreFile,
200223
resolveOutputPath,
201224
resolveFlatPath,
202225
resolveCommonParent,

0 commit comments

Comments
 (0)