markdown-magic 4.8.0 → 4.10.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/package.json +7 -7
- package/src/argparse/README.md +3 -8
- package/src/argparse/argparse.js +7 -313
- package/src/argparse/argparse.test.js +168 -90
- package/src/argparse/index.js +2 -2
- package/src/argparse/splitOutsideQuotes.js +3 -75
- package/src/cli-run.js +97 -166
- package/src/cli-run.test.js +71 -3
- package/src/globparse.js +14 -159
- package/src/index.dependency-graph.test.js +49 -0
- package/src/index.js +41 -11
- package/src/transforms/code/index.js +19 -13
- package/src/transforms/index.js +12 -1
- package/src/utils/format-md.js +165 -12
- package/src/utils/format-md.test.js +175 -0
- package/src/utils/remoteRequest.js +30 -6
- package/types/src/argparse/argparse.d.ts +2 -32
- package/types/src/argparse/argparse.d.ts.map +1 -1
- package/types/src/argparse/index.d.ts +2 -2
- package/types/src/argparse/splitOutsideQuotes.d.ts +2 -1
- package/types/src/argparse/splitOutsideQuotes.d.ts.map +1 -1
- package/types/src/cli-run.d.ts +4 -2
- package/types/src/cli-run.d.ts.map +1 -1
- package/types/src/globparse.d.ts +11 -17
- package/types/src/globparse.d.ts.map +1 -1
- package/types/src/index.d.ts +36 -9
- package/types/src/index.d.ts.map +1 -1
- package/types/src/transforms/code/index.d.ts.map +1 -1
- package/types/src/utils/format-md.d.ts +12 -0
- package/types/src/utils/format-md.d.ts.map +1 -1
- package/types/src/utils/fs.d.ts +1 -1
- package/types/src/utils/remoteRequest.d.ts.map +1 -1
- package/types/_tests/config.d.ts +0 -4
- package/types/_tests/config.d.ts.map +0 -1
- package/types/_tests/errors.test.d.ts +0 -2
- package/types/_tests/errors.test.d.ts.map +0 -1
- package/types/_tests/fixtures/js/simple.d.ts +0 -8
- package/types/_tests/fixtures/js/simple.d.ts.map +0 -1
- package/types/_tests/fixtures/local-code-file-lines.d.ts +0 -1
- package/types/_tests/fixtures/local-code-file-lines.d.ts.map +0 -1
- package/types/_tests/fixtures/local-code-file.d.ts +0 -2
- package/types/_tests/fixtures/local-code-file.d.ts.map +0 -1
- package/types/_tests/fixtures/local-code-id.d.ts +0 -3
- package/types/_tests/fixtures/local-code-id.d.ts.map +0 -1
- package/types/_tests/transforms-toc.test.d.ts +0 -2
- package/types/_tests/transforms-toc.test.d.ts.map +0 -1
- package/types/_tests/transforms.test.d.ts +0 -2
- package/types/_tests/transforms.test.d.ts.map +0 -1
- package/types/_tests/utils/diff.d.ts +0 -3
- package/types/_tests/utils/diff.d.ts.map +0 -1
- package/types/src/argparse/argparse.test.d.ts +0 -2
- package/types/src/argparse/argparse.test.d.ts.map +0 -1
- package/types/src/argparse/splitOutsideQuotes.test.d.ts +0 -2
- package/types/src/argparse/splitOutsideQuotes.test.d.ts.map +0 -1
- package/types/src/cli-run.test.d.ts +0 -2
- package/types/src/cli-run.test.d.ts.map +0 -1
- package/types/src/globparse.test.d.ts +0 -2
- package/types/src/globparse.test.d.ts.map +0 -1
- package/types/src/index.test.d.ts +0 -2
- package/types/src/index.test.d.ts.map +0 -1
- package/types/src/transforms/code/resolve-github-file.test.d.ts +0 -2
- package/types/src/transforms/code/resolve-github-file.test.d.ts.map +0 -1
- package/types/src/utils/fs.test.d.ts +0 -2
- package/types/src/utils/fs.test.d.ts.map +0 -1
- package/types/src/utils/text.test.d.ts +0 -2
- package/types/src/utils/text.test.d.ts.map +0 -1
package/src/cli-run.js
CHANGED
|
@@ -4,14 +4,11 @@ const { loadConfig } = require('./utils/load-config')
|
|
|
4
4
|
const { findUp } = require('./utils/fs')
|
|
5
5
|
const { markdownMagic } = require('./')
|
|
6
6
|
const { processFile } = require('comment-block-replacer')
|
|
7
|
-
const { parse } = require('oparser')
|
|
8
7
|
const defaultTransforms = require('./transforms')
|
|
9
|
-
const { getGlobGroupsFromArgs } = require('
|
|
10
|
-
// const { deepLog } = require('./utils/logs')
|
|
11
|
-
// const { uxParse } = require('./argparse/argparse')
|
|
8
|
+
const { dxParse, getGlobGroupsFromArgs } = require('@davidwells/dx-args')
|
|
12
9
|
const argv = process.argv.slice(2)
|
|
13
10
|
const cwd = process.cwd()
|
|
14
|
-
const
|
|
11
|
+
const defaultConfigPaths = ['md.config.js', 'markdown.config.js']
|
|
15
12
|
|
|
16
13
|
/**
|
|
17
14
|
* Render markdown with ANSI styling for terminal output
|
|
@@ -100,18 +97,31 @@ async function getBaseDir(opts = {}) {
|
|
|
100
97
|
return (gitDir) ? path.dirname(gitDir) : currentDir
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Find the first config file that exists in parent dirs
|
|
102
|
+
* @param {string} baseDir
|
|
103
|
+
* @param {Array<string>} configPaths
|
|
104
|
+
* @returns {Promise<string|undefined>}
|
|
105
|
+
*/
|
|
106
|
+
async function findFirstConfig(baseDir, configPaths = []) {
|
|
107
|
+
for (let i = 0; i < configPaths.length; i++) {
|
|
108
|
+
const configPath = configPaths[i]
|
|
109
|
+
const found = await findUp(baseDir, configPath)
|
|
110
|
+
if (found) {
|
|
111
|
+
return found
|
|
112
|
+
}
|
|
113
|
+
}
|
|
105
114
|
}
|
|
106
115
|
|
|
107
|
-
async function runCli(options = {}, rawArgv) {
|
|
116
|
+
async function runCli(options = {}, rawArgv, deps = {}) {
|
|
108
117
|
if (options.help || options.h) {
|
|
109
118
|
console.log(`
|
|
110
119
|
Usage: md-magic [options] [files...]
|
|
111
120
|
|
|
112
121
|
Options:
|
|
113
|
-
--files, --file
|
|
114
|
-
|
|
122
|
+
--files, --file, --path
|
|
123
|
+
Files or glob patterns to process
|
|
124
|
+
--config Path to config file (default: md.config.js or markdown.config.js)
|
|
115
125
|
--output Output directory
|
|
116
126
|
--open Opening comment keyword (default: docs)
|
|
117
127
|
--close Closing comment keyword (default: /docs)
|
|
@@ -125,6 +135,7 @@ Options:
|
|
|
125
135
|
Examples:
|
|
126
136
|
md-magic README.md
|
|
127
137
|
md-magic --files "**/*.md"
|
|
138
|
+
md-magic --path "**/*.md" # alias for --files
|
|
128
139
|
md-magic --config ./my-config.js
|
|
129
140
|
|
|
130
141
|
Stdin/stdout mode:
|
|
@@ -196,165 +207,15 @@ Stdin/stdout mode:
|
|
|
196
207
|
let configFile
|
|
197
208
|
let opts = {}
|
|
198
209
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
deepLog(result)
|
|
203
|
-
process.exit(1)
|
|
204
|
-
// process.exit(1)
|
|
205
|
-
/** */
|
|
206
|
-
|
|
207
|
-
/*
|
|
208
|
-
console.log('argv', argv)
|
|
209
|
-
console.log('options', options)
|
|
210
|
-
/** */
|
|
211
|
-
options.files = []
|
|
212
|
-
/* If raw args found, process them further */
|
|
213
|
-
if (argv.length && (options._ && options._.length || (options.file || options.files))) {
|
|
214
|
-
// if (isGlob(argv[0])) {
|
|
215
|
-
// console.log('glob', argv[0])
|
|
216
|
-
// options.glob = argv[0]
|
|
217
|
-
// }
|
|
218
|
-
const globParse = getGlobGroupsFromArgs(argv, {
|
|
219
|
-
/* CLI args that should be glob keys */
|
|
220
|
-
globKeys: ['files', 'file']
|
|
221
|
-
})
|
|
222
|
-
const { globGroups, otherOpts } = globParse
|
|
223
|
-
/*
|
|
224
|
-
console.log('globGroups', globGroups)
|
|
225
|
-
console.log('globParse', globParse)
|
|
226
|
-
// deepLog(globParse)
|
|
227
|
-
process.exit(1)
|
|
228
|
-
/** */
|
|
229
|
-
/* Parse for weird CLI inputs */
|
|
230
|
-
|
|
231
|
-
/* Handle -- and - flags */
|
|
232
|
-
let newArray = []
|
|
233
|
-
for (let i = 0; i < otherOpts.length; i++) {
|
|
234
|
-
const curr = otherOpts[i]
|
|
235
|
-
const prev = newArray[i - 1]
|
|
236
|
-
const next = otherOpts[i + 1] || ''
|
|
237
|
-
const isLast = otherOpts.length === i + 1
|
|
238
|
-
// console.log('curr', curr)
|
|
239
|
-
// console.log('prev', prev)
|
|
240
|
-
if (curr.match(/^-+/)) {
|
|
241
|
-
const cleanX = curr.replace(/^-+/, '')
|
|
242
|
-
if (next.match(/^-+/) || isLast) {
|
|
243
|
-
newArray.push(cleanX + '= true ')
|
|
244
|
-
continue
|
|
245
|
-
}
|
|
246
|
-
// If the current option is the last option, don't add an equal sign
|
|
247
|
-
const equal = (cleanX.indexOf('=') === -1 || isLast) ? '=' : ' '
|
|
248
|
-
const final = cleanX + equal
|
|
249
|
-
newArray.push(final)
|
|
250
|
-
continue
|
|
251
|
-
}
|
|
252
|
-
if (prev && prev.match(/=\s?$/) && (curr.match(/^\s?=/) || curr.trim() === '=')) {
|
|
253
|
-
continue
|
|
254
|
-
}
|
|
255
|
-
newArray.push(curr + ' ')
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const optString = newArray.join('')
|
|
259
|
-
const extraParse = parse(optString)
|
|
260
|
-
const singleDashStrings = findSingleDashStrings(otherOpts).map((x) => x.replace(/^-+/, ''))
|
|
261
|
-
// console.log('singleDashStrings', singleDashStrings)
|
|
262
|
-
// console.log('before options', options)
|
|
263
|
-
// console.log('before extraParse', extraParse)
|
|
264
|
-
|
|
265
|
-
const STRIP_SINGLE_DASH_OPTIONS = true
|
|
266
|
-
if (STRIP_SINGLE_DASH_OPTIONS && singleDashStrings.length) {
|
|
267
|
-
for (let i = 0; i < singleDashStrings.length; i++) {
|
|
268
|
-
const word = singleDashStrings[i]
|
|
269
|
-
// Loop over all letters of single dash options -word and remove any corresponding letter: true
|
|
270
|
-
for (let j = 0; j < word.length; j++) {
|
|
271
|
-
const letter = word[j]
|
|
272
|
-
if (options[letter]) {
|
|
273
|
-
delete options[letter]
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
// console.log('after options', options)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (extraParse.test) {
|
|
281
|
-
/*
|
|
282
|
-
console.log('optStringArr', newArray)
|
|
283
|
-
console.log('optString', optString)
|
|
284
|
-
console.log('otherOpts strings', otherOpts)
|
|
285
|
-
console.log('nicely handed CLI args')
|
|
286
|
-
console.log('extraParse', extraParse)
|
|
287
|
-
process.exit(1)
|
|
288
|
-
/** */
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (globGroups.length) {
|
|
293
|
-
const globGroupByKey = globGroups.reduce((acc, curr, i) => {
|
|
294
|
-
acc[curr.key] = globGroups[i]
|
|
295
|
-
return acc
|
|
296
|
-
}, {})
|
|
297
|
-
// console.log('globGroupByKey', globGroupByKey)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (globGroupByKey.file) {
|
|
301
|
-
options.files = options.files.concat(globGroupByKey.file.values)
|
|
302
|
-
delete options.file
|
|
303
|
-
}
|
|
304
|
-
if (globGroupByKey.files) {
|
|
305
|
-
options.files = options.files.concat(globGroupByKey.files.values)
|
|
306
|
-
}
|
|
307
|
-
if (globGroupByKey['']) {
|
|
308
|
-
options.files = options.files.concat(globGroupByKey[''].values)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (globGroupByKey.ignore) {
|
|
312
|
-
options.ignore = globGroupByKey.ignore.values
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/*
|
|
316
|
-
deepLog(options)
|
|
317
|
-
/** */
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (extraParse.file) {
|
|
321
|
-
options.files = options.files.concat(extraParse.file)
|
|
322
|
-
delete extraParse.file
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (extraParse.files) {
|
|
326
|
-
options.files = options.files.concat(extraParse.files)
|
|
327
|
-
delete extraParse.files
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (extraParse['--files']) {
|
|
331
|
-
options.files = options.files.concat(extraParse['--files'])
|
|
332
|
-
delete extraParse['--files']
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// console.log('options.files', options.files)
|
|
336
|
-
|
|
337
|
-
options.files = options.files.map((x) => {
|
|
338
|
-
if (typeof x === 'string' && x.match(/,/)) {
|
|
339
|
-
return x.split(',')
|
|
340
|
-
}
|
|
341
|
-
return x
|
|
342
|
-
})
|
|
343
|
-
.flat()
|
|
344
|
-
.filter(onlyUnique)
|
|
345
|
-
|
|
346
|
-
delete options._
|
|
347
|
-
opts = {
|
|
348
|
-
...options,
|
|
349
|
-
...extraParse
|
|
350
|
-
}
|
|
351
|
-
//console.log('opts', opts)
|
|
210
|
+
const cliArgv = Array.isArray(rawArgv) ? rawArgv : argv
|
|
211
|
+
if (cliArgv.length) {
|
|
212
|
+
opts = parseCliArgv(cliArgv)
|
|
352
213
|
}
|
|
353
214
|
if (opts.config) {
|
|
354
215
|
configFile = opts.config
|
|
355
216
|
} else {
|
|
356
217
|
const baseDir = await getBaseDir()
|
|
357
|
-
configFile = await
|
|
218
|
+
configFile = await findFirstConfig(baseDir, defaultConfigPaths)
|
|
358
219
|
}
|
|
359
220
|
const config = (configFile) ? loadConfig(configFile) : {}
|
|
360
221
|
const mergedConfig = {
|
|
@@ -371,7 +232,75 @@ Stdin/stdout mode:
|
|
|
371
232
|
process.exit(1)
|
|
372
233
|
// return
|
|
373
234
|
/** */
|
|
374
|
-
|
|
235
|
+
const runMarkdownMagic = deps.markdownMagic || markdownMagic
|
|
236
|
+
return runMarkdownMagic(mergedConfig)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function parseCliArgv(rawArgv = []) {
|
|
240
|
+
return normalizeCliOptions(dxParse(rawArgv, {
|
|
241
|
+
globKeys: ['files', 'file', 'path', 'ignore']
|
|
242
|
+
}))
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function normalizeCliOptions(parsed) {
|
|
246
|
+
const mergedOptions = parsed.mergedOptions || {}
|
|
247
|
+
const opts = {
|
|
248
|
+
...mergedOptions,
|
|
249
|
+
files: []
|
|
250
|
+
}
|
|
251
|
+
const globGroupByKey = parsed.globGroups.reduce((acc, curr) => {
|
|
252
|
+
acc[curr.key] = curr
|
|
253
|
+
return acc
|
|
254
|
+
}, {})
|
|
255
|
+
|
|
256
|
+
if (globGroupByKey.file) {
|
|
257
|
+
opts.files = opts.files.concat(globGroupByKey.file.values)
|
|
258
|
+
}
|
|
259
|
+
if (globGroupByKey.files) {
|
|
260
|
+
opts.files = opts.files.concat(globGroupByKey.files.values)
|
|
261
|
+
}
|
|
262
|
+
if (globGroupByKey.path) {
|
|
263
|
+
opts.files = opts.files.concat(globGroupByKey.path.values)
|
|
264
|
+
}
|
|
265
|
+
if (globGroupByKey['']) {
|
|
266
|
+
opts.files = opts.files.concat(globGroupByKey[''].values)
|
|
267
|
+
}
|
|
268
|
+
if (globGroupByKey.ignore) {
|
|
269
|
+
opts.ignore = globGroupByKey.ignore.values
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (mergedOptions.file) {
|
|
273
|
+
opts.files = opts.files.concat(mergedOptions.file)
|
|
274
|
+
delete opts.file
|
|
275
|
+
}
|
|
276
|
+
if (mergedOptions.files) {
|
|
277
|
+
opts.files = opts.files.concat(mergedOptions.files)
|
|
278
|
+
}
|
|
279
|
+
if (mergedOptions.path) {
|
|
280
|
+
opts.files = opts.files.concat(mergedOptions.path)
|
|
281
|
+
delete opts.path
|
|
282
|
+
}
|
|
283
|
+
if (mergedOptions['--files']) {
|
|
284
|
+
opts.files = opts.files.concat(mergedOptions['--files'])
|
|
285
|
+
delete opts['--files']
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
delete opts._
|
|
289
|
+
delete opts.file
|
|
290
|
+
delete opts.path
|
|
291
|
+
opts.files = normalizeFileList(opts.files)
|
|
292
|
+
return opts
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function normalizeFileList(files = []) {
|
|
296
|
+
return files.map((x) => {
|
|
297
|
+
if (typeof x === 'string' && x.match(/,/)) {
|
|
298
|
+
return x.split(',')
|
|
299
|
+
}
|
|
300
|
+
return x
|
|
301
|
+
})
|
|
302
|
+
.flat()
|
|
303
|
+
.filter(onlyUnique)
|
|
375
304
|
}
|
|
376
305
|
|
|
377
306
|
function onlyUnique(value, index, self) {
|
|
@@ -380,5 +309,7 @@ function onlyUnique(value, index, self) {
|
|
|
380
309
|
|
|
381
310
|
module.exports = {
|
|
382
311
|
getGlobGroupsFromArgs,
|
|
312
|
+
parseCliArgv,
|
|
313
|
+
normalizeCliOptions,
|
|
383
314
|
runCli
|
|
384
|
-
}
|
|
315
|
+
}
|
package/src/cli-run.test.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const { test } = require('uvu')
|
|
2
2
|
const assert = require('uvu/assert')
|
|
3
|
+
const path = require('path')
|
|
3
4
|
const { deepLog } = require('./utils/logs')
|
|
4
|
-
const { getGlobGroupsFromArgs, runCli } = require('./cli-run')
|
|
5
|
+
const { getGlobGroupsFromArgs, parseCliArgv, runCli } = require('./cli-run')
|
|
5
6
|
|
|
6
|
-
const DEBUG =
|
|
7
|
+
const DEBUG = process.argv.includes('--debug')
|
|
7
8
|
const logger = (DEBUG) ? console.log : () => {}
|
|
8
9
|
const deepLogger = (DEBUG) ? deepLog : () => {}
|
|
9
10
|
|
|
@@ -16,7 +17,74 @@ function logInput(rawArgs) {
|
|
|
16
17
|
|
|
17
18
|
test('Exports API', () => {
|
|
18
19
|
assert.equal(typeof runCli, 'function', 'undefined val')
|
|
20
|
+
assert.equal(typeof parseCliArgv, 'function', 'undefined val')
|
|
19
21
|
assert.equal(typeof getGlobGroupsFromArgs, 'function', 'undefined val')
|
|
20
22
|
})
|
|
21
23
|
|
|
22
|
-
test
|
|
24
|
+
test('CLI parser uses dxParse for forgiving single-dash file and config options', () => {
|
|
25
|
+
const rawArgv = [ '-files', 'README.md', '-config', 'md.config.js', '-dry' ]
|
|
26
|
+
const result = parseCliArgv(rawArgv)
|
|
27
|
+
deepLogger('result', result)
|
|
28
|
+
assert.equal(result, {
|
|
29
|
+
files: ['README.md'],
|
|
30
|
+
config: 'md.config.js',
|
|
31
|
+
dry: true
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('CLI parser maps file/path globs and ignore groups into markdown-magic options', () => {
|
|
36
|
+
const rawArgv = [
|
|
37
|
+
'--path',
|
|
38
|
+
'docs/**/*.md',
|
|
39
|
+
'--file',
|
|
40
|
+
'README.md',
|
|
41
|
+
'--ignore',
|
|
42
|
+
'dist/**/*.md',
|
|
43
|
+
'--output',
|
|
44
|
+
'out'
|
|
45
|
+
]
|
|
46
|
+
const result = parseCliArgv(rawArgv)
|
|
47
|
+
deepLogger('result', result)
|
|
48
|
+
assert.equal(result, {
|
|
49
|
+
files: ['README.md', 'docs/**/*.md'],
|
|
50
|
+
ignore: ['dist/**/*.md'],
|
|
51
|
+
output: 'out'
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('CLI parser keeps shell-expanded files out of command options', () => {
|
|
56
|
+
const rawArgv = [
|
|
57
|
+
'CONTRIBUTING.md',
|
|
58
|
+
'NOTES.md',
|
|
59
|
+
'README.md',
|
|
60
|
+
'foo',
|
|
61
|
+
'bar',
|
|
62
|
+
'=',
|
|
63
|
+
'false'
|
|
64
|
+
]
|
|
65
|
+
const result = parseCliArgv(rawArgv)
|
|
66
|
+
deepLogger('result', result)
|
|
67
|
+
assert.equal(result, {
|
|
68
|
+
files: ['CONTRIBUTING.md', 'NOTES.md', 'README.md'],
|
|
69
|
+
foo: true,
|
|
70
|
+
bar: false
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('runCli sends dxParse-normalized options to markdownMagic', async () => {
|
|
75
|
+
const configFile = path.join(__dirname, '..', '..', '..', 'md.config.js')
|
|
76
|
+
const rawArgv = [ '-files', 'README.md', '-config', configFile, '-dry' ]
|
|
77
|
+
let receivedConfig
|
|
78
|
+
const result = await runCli({ _: ['README.md'] }, rawArgv, {
|
|
79
|
+
markdownMagic: async (config) => {
|
|
80
|
+
receivedConfig = config
|
|
81
|
+
return config
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
assert.equal(result, receivedConfig)
|
|
85
|
+
assert.equal(receivedConfig.files, ['README.md'])
|
|
86
|
+
assert.equal(receivedConfig.config, configFile)
|
|
87
|
+
assert.equal(receivedConfig.dry, true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test.run()
|
package/src/globparse.js
CHANGED
|
@@ -1,163 +1,18 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const IS_INTEGER = /^([A-Za-z0-9_.-]*)=\s?-?\d*(\.(?=\d))?\d*$/
|
|
14
|
-
const IS_BOOLEAN_OR_NULL = /^([A-Za-z0-9_.-]*)=\s?true|false|null|undefined\s?/
|
|
15
|
-
|
|
16
|
-
function isArrayLike(str) {
|
|
17
|
-
if (typeof str !== 'string') return false
|
|
18
|
-
return Boolean(ARRAY_REGEX.test(str))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function stringLooksLikeFile(value) {
|
|
22
|
-
return !value.match(/^-+/) // isn't option looking
|
|
23
|
-
&& isValidFilePath(value)
|
|
24
|
-
&& (
|
|
25
|
-
path.basename(value).indexOf('.') > -1 // has period
|
|
26
|
-
|| getFirstCharacter(value) === '_' // starts with _
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getValue(val) {
|
|
31
|
-
return (val[1] !== '=') ? val[1] : val[0]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function trimLeadingDashes(value) {
|
|
35
|
-
return value.replace(/^-+/, '')
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function removeNodeModules(value = '') {
|
|
39
|
-
if (typeof value !== 'string') {
|
|
40
|
-
return true
|
|
41
|
-
}
|
|
42
|
-
return !value.match(/node_modules\//)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function coerceStringToRegex(str) {
|
|
46
|
-
const isRegex = str.match(REGEX_REGEX)
|
|
47
|
-
if (!isRegex) {
|
|
48
|
-
return str
|
|
49
|
-
}
|
|
50
|
-
const [ _match, pattern, flags ] = isRegex
|
|
51
|
-
return new RegExp(escapeRegexString(pattern), flags)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function convertToArray(str = '') {
|
|
55
|
-
const { fixedArray } = parse(`fixedArray=${str}`)
|
|
56
|
-
return (fixedArray || [])
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function addValue(value, currentCollection) {
|
|
60
|
-
if (isArrayLike(value)) {
|
|
61
|
-
const array = convertToArray(value)
|
|
62
|
-
return Array.from(new Set(currentCollection.concat(array)))
|
|
63
|
-
}
|
|
64
|
-
if (currentCollection.indexOf(value) > -1) {
|
|
65
|
-
return currentCollection
|
|
66
|
-
}
|
|
67
|
-
return currentCollection.concat(value)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function customIsGlob(arg) {
|
|
71
|
-
// If looks like json object, return false
|
|
72
|
-
if (arg.match(/^{[^}]*:[^}]*}/)) {
|
|
73
|
-
return false
|
|
74
|
-
}
|
|
75
|
-
return isGlob(arg)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function getGlobGroupsFromArgs(args, opts = {}) {
|
|
79
|
-
const globKeys = opts.globKeys || []
|
|
80
|
-
let preceding = ['', '']
|
|
81
|
-
let collection = []
|
|
82
|
-
let globGroups = []
|
|
83
|
-
let reserved = []
|
|
84
|
-
let otherOpts = []
|
|
85
|
-
let cacheKey = ''
|
|
86
|
-
|
|
87
|
-
for (let i = 0; i < args.length; i++) {
|
|
88
|
-
const isLastArg = (args.length - 1) === i
|
|
89
|
-
const arg = args[i]
|
|
90
|
-
const prevArg = args[i - 1]
|
|
91
|
-
const looksLikeFile = stringLooksLikeFile(arg)
|
|
92
|
-
|
|
93
|
-
if (looksLikeFile && typeof cacheKey !== 'undefined') {
|
|
94
|
-
collection.push(arg)
|
|
95
|
-
} else if (arg.match(/^-+/) && !arg.match(/=/)) {
|
|
96
|
-
cacheKey = arg
|
|
97
|
-
if (collection.length) {
|
|
98
|
-
const val = getValue(preceding)
|
|
99
|
-
reserved.push(val)
|
|
100
|
-
globGroups.push({
|
|
101
|
-
key: trimLeadingDashes(val),
|
|
102
|
-
rawKey: val,
|
|
103
|
-
values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
|
|
104
|
-
})
|
|
105
|
-
collection = []
|
|
106
|
-
}
|
|
107
|
-
preceding = [ prevArg, arg ]
|
|
108
|
-
} else if (cacheKey && arg.match(/=/)) {
|
|
109
|
-
cacheKey = undefined
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const cleanKey = trimLeadingDashes(cacheKey || '')
|
|
113
|
-
const isDefinedGlobKey = globKeys.includes(cleanKey) || globKeys.includes(cacheKey)
|
|
114
|
-
|
|
115
|
-
if (isDefinedGlobKey && (isGlob(arg) || looksLikeFile)) {
|
|
116
|
-
collection = addValue(arg, collection)
|
|
117
|
-
} else {
|
|
118
|
-
const notObjectLike = arg.match(NOT_OBJECT_LIKE) && !isArrayLike(arg)
|
|
119
|
-
if (
|
|
120
|
-
(notObjectLike) ||
|
|
121
|
-
!cacheKey && customIsGlob(arg) && !arg.match(/=/)
|
|
122
|
-
) {
|
|
123
|
-
collection = addValue(arg, collection)
|
|
124
|
-
} else if (!looksLikeFile) {
|
|
125
|
-
if (
|
|
126
|
-
arg.match(IS_KEY_VALUE_IN_QUOTES)
|
|
127
|
-
|| arg.match(IS_KEY_VALUE_START_WITH_QUOTE)
|
|
128
|
-
|| arg.match(IS_INTEGER)
|
|
129
|
-
|| arg.match(IS_BOOLEAN_OR_NULL)
|
|
130
|
-
) {
|
|
131
|
-
otherOpts.push(arg)
|
|
132
|
-
} else if (arg.match(IS_KEY_VALUE_NON_ARRAY)) {
|
|
133
|
-
otherOpts.push(arg.replace(IS_KEY_VALUE_NON_ARRAY, '$1="$2$3"'))
|
|
134
|
-
} else {
|
|
135
|
-
otherOpts.push(arg)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (isLastArg && collection.length) {
|
|
141
|
-
const val = getValue(preceding)
|
|
142
|
-
reserved.push(val)
|
|
143
|
-
globGroups.push({
|
|
144
|
-
key: trimLeadingDashes(val),
|
|
145
|
-
rawKey: val,
|
|
146
|
-
values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x)),
|
|
147
|
-
})
|
|
148
|
-
collection = []
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
globGroups,
|
|
154
|
-
otherOpts: otherOpts.filter((opt) => !reserved.includes(opt))
|
|
155
|
-
}
|
|
156
|
-
}
|
|
1
|
+
const {
|
|
2
|
+
getGlobGroupsFromArgs,
|
|
3
|
+
isArrayLike,
|
|
4
|
+
stringLooksLikeFile,
|
|
5
|
+
getValue,
|
|
6
|
+
trimLeadingDashes,
|
|
7
|
+
removeNodeModules,
|
|
8
|
+
coerceStringToRegex,
|
|
9
|
+
convertToArray,
|
|
10
|
+
addValue,
|
|
11
|
+
customIsGlob,
|
|
12
|
+
} = require('@davidwells/dx-args')
|
|
157
13
|
|
|
158
14
|
module.exports = {
|
|
159
15
|
getGlobGroupsFromArgs,
|
|
160
|
-
// Export helpers for testing
|
|
161
16
|
isArrayLike,
|
|
162
17
|
stringLooksLikeFile,
|
|
163
18
|
getValue,
|
|
@@ -166,5 +21,5 @@ module.exports = {
|
|
|
166
21
|
coerceStringToRegex,
|
|
167
22
|
convertToArray,
|
|
168
23
|
addValue,
|
|
169
|
-
customIsGlob
|
|
170
|
-
}
|
|
24
|
+
customIsGlob,
|
|
25
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { __private } = require('./')
|
|
4
|
+
|
|
5
|
+
test('createDependencyGraph includes every known dependency edge', () => {
|
|
6
|
+
const blockItems = [
|
|
7
|
+
{
|
|
8
|
+
id: '/docs/main.md',
|
|
9
|
+
blocks: [{}],
|
|
10
|
+
dependencies: ['/docs/dep-a.md', '/docs/dep-z.md']
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: '/docs/dep-a.md',
|
|
14
|
+
blocks: [{}],
|
|
15
|
+
dependencies: []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: '/docs/dep-z.md',
|
|
19
|
+
blocks: [{}],
|
|
20
|
+
dependencies: []
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const { graph } = __private.createDependencyGraph(blockItems)
|
|
25
|
+
assert.ok(graph.find((edge) => edge[0] === '/docs/main.md' && edge[1] === '/docs/dep-a.md'))
|
|
26
|
+
assert.ok(graph.find((edge) => edge[0] === '/docs/main.md' && edge[1] === '/docs/dep-z.md'))
|
|
27
|
+
assert.is(graph.filter((edge) => edge[0] === '/docs/main.md').length, 2)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('createDependencyGraph skips dependencies outside the file set', () => {
|
|
31
|
+
const blockItems = [
|
|
32
|
+
{
|
|
33
|
+
id: '/docs/main.md',
|
|
34
|
+
blocks: [{}],
|
|
35
|
+
dependencies: ['/docs/dep-a.md', '/external/file.js']
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: '/docs/dep-a.md',
|
|
39
|
+
blocks: [{}],
|
|
40
|
+
dependencies: []
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
const { graph } = __private.createDependencyGraph(blockItems)
|
|
45
|
+
assert.is(graph.length, 1)
|
|
46
|
+
assert.equal(graph[0], ['/docs/main.md', '/docs/dep-a.md'])
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test.run()
|