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.
Files changed (66) hide show
  1. package/package.json +7 -7
  2. package/src/argparse/README.md +3 -8
  3. package/src/argparse/argparse.js +7 -313
  4. package/src/argparse/argparse.test.js +168 -90
  5. package/src/argparse/index.js +2 -2
  6. package/src/argparse/splitOutsideQuotes.js +3 -75
  7. package/src/cli-run.js +97 -166
  8. package/src/cli-run.test.js +71 -3
  9. package/src/globparse.js +14 -159
  10. package/src/index.dependency-graph.test.js +49 -0
  11. package/src/index.js +41 -11
  12. package/src/transforms/code/index.js +19 -13
  13. package/src/transforms/index.js +12 -1
  14. package/src/utils/format-md.js +165 -12
  15. package/src/utils/format-md.test.js +175 -0
  16. package/src/utils/remoteRequest.js +30 -6
  17. package/types/src/argparse/argparse.d.ts +2 -32
  18. package/types/src/argparse/argparse.d.ts.map +1 -1
  19. package/types/src/argparse/index.d.ts +2 -2
  20. package/types/src/argparse/splitOutsideQuotes.d.ts +2 -1
  21. package/types/src/argparse/splitOutsideQuotes.d.ts.map +1 -1
  22. package/types/src/cli-run.d.ts +4 -2
  23. package/types/src/cli-run.d.ts.map +1 -1
  24. package/types/src/globparse.d.ts +11 -17
  25. package/types/src/globparse.d.ts.map +1 -1
  26. package/types/src/index.d.ts +36 -9
  27. package/types/src/index.d.ts.map +1 -1
  28. package/types/src/transforms/code/index.d.ts.map +1 -1
  29. package/types/src/utils/format-md.d.ts +12 -0
  30. package/types/src/utils/format-md.d.ts.map +1 -1
  31. package/types/src/utils/fs.d.ts +1 -1
  32. package/types/src/utils/remoteRequest.d.ts.map +1 -1
  33. package/types/_tests/config.d.ts +0 -4
  34. package/types/_tests/config.d.ts.map +0 -1
  35. package/types/_tests/errors.test.d.ts +0 -2
  36. package/types/_tests/errors.test.d.ts.map +0 -1
  37. package/types/_tests/fixtures/js/simple.d.ts +0 -8
  38. package/types/_tests/fixtures/js/simple.d.ts.map +0 -1
  39. package/types/_tests/fixtures/local-code-file-lines.d.ts +0 -1
  40. package/types/_tests/fixtures/local-code-file-lines.d.ts.map +0 -1
  41. package/types/_tests/fixtures/local-code-file.d.ts +0 -2
  42. package/types/_tests/fixtures/local-code-file.d.ts.map +0 -1
  43. package/types/_tests/fixtures/local-code-id.d.ts +0 -3
  44. package/types/_tests/fixtures/local-code-id.d.ts.map +0 -1
  45. package/types/_tests/transforms-toc.test.d.ts +0 -2
  46. package/types/_tests/transforms-toc.test.d.ts.map +0 -1
  47. package/types/_tests/transforms.test.d.ts +0 -2
  48. package/types/_tests/transforms.test.d.ts.map +0 -1
  49. package/types/_tests/utils/diff.d.ts +0 -3
  50. package/types/_tests/utils/diff.d.ts.map +0 -1
  51. package/types/src/argparse/argparse.test.d.ts +0 -2
  52. package/types/src/argparse/argparse.test.d.ts.map +0 -1
  53. package/types/src/argparse/splitOutsideQuotes.test.d.ts +0 -2
  54. package/types/src/argparse/splitOutsideQuotes.test.d.ts.map +0 -1
  55. package/types/src/cli-run.test.d.ts +0 -2
  56. package/types/src/cli-run.test.d.ts.map +0 -1
  57. package/types/src/globparse.test.d.ts +0 -2
  58. package/types/src/globparse.test.d.ts.map +0 -1
  59. package/types/src/index.test.d.ts +0 -2
  60. package/types/src/index.test.d.ts.map +0 -1
  61. package/types/src/transforms/code/resolve-github-file.test.d.ts +0 -2
  62. package/types/src/transforms/code/resolve-github-file.test.d.ts.map +0 -1
  63. package/types/src/utils/fs.test.d.ts +0 -2
  64. package/types/src/utils/fs.test.d.ts.map +0 -1
  65. package/types/src/utils/text.test.d.ts +0 -2
  66. 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('./globparse')
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 defaultConfigPath = 'md.config.js'
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
- function findSingleDashStrings(arr) {
104
- return arr.filter(str => str.match(/^-[^-]/))
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 Files or glob patterns to process
114
- --config Path to config file (default: md.config.js)
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
- const result = uxParse(rawArgv)
201
- console.log('───────────────────────────────')
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 findUp(baseDir, defaultConfigPath)
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
- return markdownMagic(mergedConfig)
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
+ }
@@ -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 = true
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.run()
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 path = require('path')
2
- const isGlob = require('is-glob')
3
- const isValidFilePath = require('is-valid-path')
4
- const { parse } = require('oparser')
5
- const { getFirstCharacter } = require('./utils/text')
6
- const { REGEX_REGEX, escapeRegexString } = require('./utils/regex')
7
-
8
- const ARRAY_REGEX = /^\[(.*)\]$/
9
- const NOT_OBJECT_LIKE = /^{[^:,]*}/
10
- const IS_KEY_VALUE_NON_ARRAY = /^([A-Za-z0-9_.-]*)=\s?([^\[\{]]*)([^\[\{]*)$/
11
- const IS_KEY_VALUE_IN_QUOTES = /^([A-Za-z0-9_.-]*)=\s?("|')(.*)(\2)$/
12
- const IS_KEY_VALUE_START_WITH_QUOTE = /^([A-Za-z0-9_.-]*)=\s?("|')(.*)/
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()