markdown-magic 2.6.1 → 3.0.1

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 (58) hide show
  1. package/README.md +47 -37
  2. package/cli.js +5 -82
  3. package/lib/block-parser-js.test.js +171 -0
  4. package/lib/block-parser.js +382 -0
  5. package/lib/block-parser.test.js +479 -0
  6. package/lib/cli.js +245 -0
  7. package/lib/cli.test.js +409 -0
  8. package/lib/defaults.js +12 -0
  9. package/lib/globals.d.ts +66 -0
  10. package/lib/index.js +353 -184
  11. package/lib/index.test.js +11 -0
  12. package/lib/process-contents.js +371 -0
  13. package/lib/process-file.js +37 -0
  14. package/lib/transforms/code.js +67 -28
  15. package/lib/transforms/file.js +17 -17
  16. package/lib/transforms/index.js +0 -114
  17. package/lib/transforms/remote.js +8 -6
  18. package/lib/transforms/sectionToc.js +18 -0
  19. package/lib/transforms/toc.js +12 -265
  20. package/lib/transforms/wordCount.js +5 -0
  21. package/lib/types.js +11 -0
  22. package/lib/utils/fs.js +342 -0
  23. package/lib/utils/fs.test.js +267 -0
  24. package/lib/utils/index.js +19 -0
  25. package/{cli-utils.js → lib/utils/load-config.js} +2 -6
  26. package/lib/utils/logs.js +94 -0
  27. package/lib/utils/md/filters.js +20 -0
  28. package/lib/utils/md/find-code-blocks.js +88 -0
  29. package/lib/utils/md/find-date.js +32 -0
  30. package/lib/utils/md/find-frontmatter.js +92 -0
  31. package/lib/utils/md/find-frontmatter.test.js +17 -0
  32. package/lib/utils/md/find-html-tags.js +105 -0
  33. package/lib/utils/md/find-images-md.js +27 -0
  34. package/lib/utils/md/find-images.js +107 -0
  35. package/lib/utils/md/find-links.js +220 -0
  36. package/lib/utils/md/find-unmatched-html-tags.js +32 -0
  37. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +14 -0
  38. package/lib/utils/md/fixtures/file-with-frontmatter.md +32 -0
  39. package/lib/utils/md/fixtures/file-with-links.md +153 -0
  40. package/lib/utils/md/md.test.js +105 -0
  41. package/lib/utils/md/parse.js +146 -0
  42. package/lib/utils/md/utils.js +19 -0
  43. package/lib/utils/regex-timeout.js +84 -0
  44. package/lib/utils/regex.js +40 -6
  45. package/lib/utils/remoteRequest.js +55 -0
  46. package/lib/utils/syntax.js +82 -0
  47. package/lib/utils/text.js +328 -0
  48. package/lib/utils/text.test.js +305 -0
  49. package/lib/utils/toc.js +315 -0
  50. package/package.json +30 -26
  51. package/index.js +0 -46
  52. package/lib/processFile.js +0 -154
  53. package/lib/updateContents.js +0 -125
  54. package/lib/utils/_md.test.js +0 -63
  55. package/lib/utils/new-parser.js +0 -412
  56. package/lib/utils/new-parser.test.js +0 -324
  57. package/lib/utils/weird-parse.js +0 -230
  58. package/lib/utils/weird-parse.test.js +0 -217
@@ -0,0 +1,479 @@
1
+ const { test } = require('uvu')
2
+ const assert = require('uvu/assert')
3
+ const { parseBlocks } = require('./block-parser')
4
+ const { deepLog } = require('./utils/logs')
5
+
6
+ const md = `<h1 id="jdjdj">Netlify + FaunaDB &nbsp;&nbsp;&nbsp;
7
+ <a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-faunadb-example&stack=fauna">
8
+ <img src="https://www.netlify.com/img/deploy/button.svg">
9
+ </a>
10
+ </h1>
11
+
12
+ <\!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
13
+ nice
14
+ <\!-- XYZ:END -->
15
+
16
+ <\!-- XYZ:START {functionName} foo={{ rad: 'blue' }} -->
17
+ nice
18
+ <\!-- XYZ:END -->
19
+
20
+
21
+ <\!-- XYZ:START {functionName} foo={{ rad: 'red' }} -->
22
+ nice
23
+ <\!-- XYZ:END -->
24
+
25
+
26
+ <\!-- XYZ:START [wootName] foo=['one', 'two'] -->
27
+ nice
28
+ <\!-- XYZ:END -->
29
+
30
+
31
+ <\!-- XYZ:START -->
32
+ lol
33
+ <\!-- XYZ:END -->
34
+
35
+ <!-- XYZ:START funky-key-here kldskjfjslfjs -->
36
+ lol
37
+ <!-- XYZ:END -->
38
+
39
+ <\!-- xyz:start (lowerCase) foo=['one', 'two'] heading=false -->
40
+ nice
41
+ <\!-- XYZ:END -->
42
+
43
+
44
+ <\!-- XYZ:START(cool)
45
+ width={999}
46
+ height={{111}}
47
+ numberAsString="12345"
48
+ great={["scoot", "sco ot", 'scooo ttt']}
49
+ nice={{ value: nice, cool: "true" }}
50
+ soclose=[jdjdjd, hdhfhfhffh]
51
+ rad="boss"
52
+ cool=true notCool=false
53
+ nooooo={[one, two, 3, 4]}
54
+ numberZero=0,
55
+ xyz=999,
56
+ nope=false,
57
+ // comment
58
+ yes={true} -->
59
+
60
+ actual content
61
+
62
+ <\!-- XYZ:END -->
63
+
64
+
65
+ <img src="https://www.netlify.com/img/deploy/button.svg"/>
66
+
67
+
68
+ <img src="https://www.hehhehehehe.com/img/deploy/button.svg" />
69
+
70
+
71
+ <\!-- XYZ:START(cool) xxx
72
+ hhddh=cool -->
73
+ wowow
74
+ whatever we want 
75
+ <\!-- XYZ:END -->
76
+
77
+
78
+ <\!-- XYZ:START(hhh) -->
79
+ xyz
80
+ <\!-- XYZ:END -->
81
+
82
+
83
+ <\!-- XYZ:START(cool) isCool -->
84
+ nice
85
+ <\!-- XYZ:END -->
86
+
87
+
88
+ <button 
89
+ great={[one, two, 3, 4]}
90
+ >
91
+ wow
92
+ </button>
93
+
94
+
95
+ <\!-- XYZ:START(niceeeee)
96
+ xxx
97
+ // comment here
98
+ hhddh=cool
99
+ -->
100
+ contents
101
+ <\!-- XYZ:END -->
102
+
103
+ <button 
104
+ width={999}
105
+ great={["scoot", "scoot"]}
106
+ nice={{ value: nice, cool: true }}
107
+ rad="boss"
108
+ cool=true 
109
+ nope=false 
110
+ what='xnxnx'
111
+ isLoading 
112
+ src="https://user-images.githubusercontent.com/532272/123136878-46f1a300-d408-11eb-82f2-ad452498457b.jpg"
113
+ >
114
+ coooooll
115
+ </button>
116
+
117
+
118
+ <hr />
119
+
120
+
121
+ <br />
122
+
123
+
124
+ <ReactComponent>lolol</ReactComponent>
125
+
126
+
127
+ <ReactComponent width={123} lol={["no", "cool"]}>
128
+ lolol
129
+ </ReactComponent>
130
+
131
+
132
+ <OtherComponent width={123} lol={["no", "cool"]} nice={{ value: "nice", cool: true }}>
133
+ lolol
134
+ </OtherComponent>
135
+
136
+
137
+ <table style="width:100%">
138
+ <tr>
139
+ <th>Firstname</th>
140
+ <th>Lastname</th>
141
+ <th>Age</th>
142
+ </tr>
143
+ <tr>
144
+ <td>Jill</td>
145
+ <td>Smith</td>
146
+ <td>50</td>
147
+ </tr>
148
+ <tr>
149
+ <td>Eve</td>
150
+ <td>Jackson</td>
151
+ <td>94</td>
152
+ </tr>
153
+ </table>
154
+
155
+
156
+ <div>
157
+ <p>
158
+ <img align="right" isLoading={false} width="250" src="https://user-images.githubusercontent.com/532272/123136878-46f1a300-d408-11eb-82f2-ad452498457b.jpg" />
159
+ </p>
160
+ <p>
161
+ cool
162
+ </p>
163
+ <div>
164
+
165
+
166
+ <p>
167
+ <img align="left" width="250" src="https://user-images.githubusercontent.com/532272/123136889-4953fd00-d408-11eb-8a3e-f82f1d073298.jpg" />
168
+ </p>
169
+
170
+
171
+ Add a little magic to your markdown
172
+
173
+
174
+ ## About
175
+
176
+
177
+ <img align="right" width="200" height="183" src="https://cloud.githubusercontent.com/assets/532272/21507867/3376e9fe-cc4a-11e6-9350-7ec4f680da36.gif" />Markdown magic uses comment blocks in markdown files to automatically sync or transform its contents.
178
+
179
+
180
+ Markdown magic uses comment blocks in markdown files to automatically sync or transform its contents. <img align="right" width="200" height="183" src="https://cloud.githubusercontent.com/assets/532272/21507867/3376e9fe-cc4a-11e6-9350-7ec4f680da36.gif" />
181
+ `
182
+
183
+ test('verify parser', () => {
184
+ const parsedValue = parseBlocks(md, {
185
+ open: 'XYZ:START',
186
+ close: 'XYZ:END'
187
+ })
188
+ /*
189
+ console.log('parsedValue')
190
+ deepLog(parsedValue)
191
+ // process.exit(1)
192
+ /** */
193
+ assert.equal(typeof parsedValue, 'object')
194
+ assert.equal(parsedValue.blocks.length, 11)
195
+ })
196
+
197
+ test('inline parser', () => {
198
+ const inlineOne = `<!--XYZ:START functionName foo={{ rad: 'bar' }}-->99<!--XYZ:END-->`
199
+ const one = parseBlocks(inlineOne, {
200
+ open: 'XYZ:START',
201
+ close: 'XYZ:END'
202
+ })
203
+ /*
204
+ console.log('inline one')
205
+ deepLog(one)
206
+ /** */
207
+ const values = [
208
+ {
209
+ type: 'functionName',
210
+ options: { foo: { rad: 'bar' } },
211
+ location: 66
212
+ }
213
+ ]
214
+ values.forEach((val, i) => {
215
+ const stub = val
216
+ const currentItem = one.blocks[i]
217
+ assert.equal(stub.type, currentItem.type, `${stub.type} ${i} transform`)
218
+ assert.equal(stub.options, currentItem.options, `${stub.type} ${i} options`)
219
+ })
220
+
221
+ const inlineTwo = ` <!-- XYZ:START transformX foo=111 -->99<!-- XYZ:END -->`
222
+ const two = parseBlocks(inlineTwo, {
223
+ open: 'XYZ:START',
224
+ close: 'XYZ:END'
225
+ })
226
+ /*
227
+ console.log('inline two ───────────────────────')
228
+ deepLog(two)
229
+ /** */
230
+ const valuesTwo = [
231
+ {
232
+ type: 'transformX',
233
+ options: { foo: 111 },
234
+ location: 55
235
+ }
236
+ ]
237
+ valuesTwo.forEach((val, i) => {
238
+ const stub = val
239
+ const currentItem = two.blocks[i]
240
+ assert.equal(stub.type, currentItem.type, `${stub.type} ${i} transform`)
241
+ assert.equal(stub.options, currentItem.options, `${stub.type} ${i} options`)
242
+ })
243
+ })
244
+
245
+ const fnBlocks = `
246
+ <!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
247
+ nice
248
+ <!-- XYZ:END -->
249
+
250
+ <!-- XYZ:START {functionName} foo={{ rad: 'blue' }} -->
251
+ nice
252
+ <!-- XYZ:END -->
253
+
254
+ <!-- XYZ:START (functionName) foo={{ rad: 'red' }} -->
255
+ nice
256
+ <!-- XYZ:END -->
257
+
258
+ <!-- XYZ:START [functionName] foo={{ rad: 'purple' }} -->
259
+ nice
260
+ <!-- XYZ:END -->
261
+
262
+ <!-- XYZ:START {{functionName}} foo={{ rad: 'black' }} -->
263
+ nice
264
+ <!-- XYZ:END -->
265
+
266
+ <!-- XYZ:START ((functionName)) foo={{ rad: 'white' }} -->
267
+ nice
268
+ <!-- XYZ:END -->
269
+
270
+ <!-- XYZ:START [[functionName]] foo={{ rad: 'orange' }} -->
271
+ nice
272
+ <!-- XYZ:END -->
273
+ `
274
+
275
+ test('Handles function names', () => {
276
+ const parsedValue = parseBlocks(fnBlocks, {
277
+ open: 'XYZ:START',
278
+ close: 'XYZ:END'
279
+ })
280
+ /*
281
+ console.log('fn names')
282
+ deepLog(parsedValue)
283
+ /** */
284
+ assert.equal(Array.isArray(parsedValue.blocks), true)
285
+ assert.equal(parsedValue.blocks.length, 7)
286
+
287
+ const values = [
288
+ {
289
+ type: 'functionName',
290
+ options: { foo: { rad: 'yellow' } },
291
+ location: 78
292
+ },
293
+ {
294
+ type: 'functionName',
295
+ options: { foo: { rad: 'blue' } },
296
+ location: 157
297
+ },
298
+ {
299
+ type: 'functionName',
300
+ options: { foo: { rad: 'red' } },
301
+ location: 235
302
+ },
303
+ {
304
+ type: 'functionName',
305
+ options: { foo: { rad: 'purple' } },
306
+ location: 316
307
+ },
308
+ {
309
+ type: 'functionName',
310
+ options: { foo: { rad: 'black' } },
311
+ location: 398
312
+ },
313
+ {
314
+ type: 'functionName',
315
+ options: { foo: { rad: 'white' } },
316
+ location: 480
317
+ },
318
+ {
319
+ type: 'functionName',
320
+ options: { foo: { rad: 'orange' } },
321
+ location: 563
322
+ }
323
+ ]
324
+
325
+ values.forEach((val, i) => {
326
+ const stub = val
327
+ const currentItem = parsedValue.blocks[i]
328
+ assert.equal(stub.type, currentItem.type, `${stub.type} ${i} transform`)
329
+ assert.equal(stub.options, currentItem.options, `${stub.type} ${i} options`)
330
+ })
331
+ })
332
+
333
+
334
+ test('different function names', () => {
335
+ const backwardCompat = `
336
+ <!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
337
+ nice
338
+ <!-- XYZ:END -->
339
+
340
+ <!-- XYZ:START lol width={999}
341
+ height={{111}}
342
+ numberAsString="12345"
343
+ great={["scoot", "sco ot", 'scooo ttt']}
344
+ nope=false -->
345
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vitae mauris arcu, eu pretium nisi. Praesent fringilla ornare ullamcorper. Pellentesque diam orci, sodales in blandit ut, placerat quis felis. Vestibulum at sem massa, in tempus nisi. Vivamus ut fermentum odio. Etiam porttitor faucibus volutpat. Vivamus vitae mi ligula, non hendrerit urna. Suspendisse potenti. Quisque eget massa a massa semper mollis.
346
+ <!-- XYZ:END -->
347
+
348
+ <!-- XYZ:START (CODE:src=./relative/path/to/code.js&lines=22-44) -->
349
+ This content will be dynamically replaced with code from the file lines 22 through 44
350
+ <!-- XYZ:END -->
351
+ `
352
+ const parsedValue = parseBlocks(backwardCompat, {
353
+ open: 'XYZ:START',
354
+ close: 'XYZ:END'
355
+ })
356
+ /*
357
+ console.log('backwardCompat')
358
+ deepLog(parsedValue)
359
+ /** */
360
+ const answers = [
361
+ {
362
+ type: 'functionName',
363
+ options: { foo: { rad: 'yellow' } },
364
+ },
365
+ {
366
+ type: 'lol',
367
+ options: {
368
+ width: 999,
369
+ height: 111,
370
+ numberAsString: '12345',
371
+ great: [ 'scoot', 'sco ot', 'scooo ttt' ],
372
+ nope: false
373
+ },
374
+ },
375
+ {
376
+ type: 'CODE',
377
+ options: { src: './relative/path/to/code.js', lines: '22-44' },
378
+ },
379
+ ]
380
+ parsedValue.blocks.forEach((transform, i) => {
381
+ const stub = answers[i]
382
+ assert.equal(transform.type, stub.type, `type: ${stub.type} at index ${i}`)
383
+ assert.equal(transform.options, stub.options, `options: ${stub.type} at index ${i}`)
384
+ })
385
+ })
386
+
387
+ const defaultOpts = {
388
+ syntax: 'md',
389
+ open: 'DOCS:START',
390
+ close: 'DOCS:END',
391
+ }
392
+
393
+ const mdText = `
394
+ Very nice
395
+
396
+ <!-- DOCS:START(TOC) foo={{ rad: 'orange' }} ------>
397
+ ok
398
+ <!-- DOCS:END -->
399
+
400
+ <!-- DOCS:START (CODE:src=./relative/path/to/code.js&lines=22-44) -->
401
+ This content will be dynamically replaced with code from the file lines 22 through 44
402
+ <!-- DOCS:END -->
403
+ `
404
+
405
+ test('Parse md blocks', () => {
406
+ const parsedValue = parseBlocks(mdText, defaultOpts)
407
+ deepLog(parsedValue)
408
+ assert.equal(parsedValue.blocks, [
409
+ {
410
+ index: 1,
411
+ type: 'TOC',
412
+ options: { foo: { rad: 'orange' } },
413
+ context: { isMultiline: true },
414
+ open: {
415
+ value: "<!-- DOCS:START(TOC) foo={{ rad: 'orange' }} ------>\n",
416
+ start: 12,
417
+ end: 65
418
+ },
419
+ content: { value: 'ok', start: 65, end: 67, indentation: 0 },
420
+ close: { value: '\n<!-- DOCS:END -->', start: 67, end: 85 },
421
+ block: {
422
+ indentation: '',
423
+ lines: [ 4, 6 ],
424
+ start: 12,
425
+ end: 85,
426
+ rawArgs: "foo={{ rad: 'orange' }}",
427
+ rawContent: 'ok',
428
+ value: "<!-- DOCS:START(TOC) foo={{ rad: 'orange' }} ------>\n" +
429
+ 'ok\n' +
430
+ '<!-- DOCS:END -->'
431
+ }
432
+ },
433
+ {
434
+ index: 2,
435
+ type: 'CODE',
436
+ options: { src: './relative/path/to/code.js', lines: '22-44' },
437
+ context: { isMultiline: true, isLegacy: true },
438
+ open: {
439
+ value: '<!-- DOCS:START (CODE:src=./relative/path/to/code.js&lines=22-44) -->\n',
440
+ start: 87,
441
+ end: 157
442
+ },
443
+ content: {
444
+ value: 'This content will be dynamically replaced with code from the file lines 22 through 44',
445
+ start: 157,
446
+ end: 242,
447
+ indentation: 0
448
+ },
449
+ close: { value: '\n<!-- DOCS:END -->', start: 242, end: 260 },
450
+ block: {
451
+ indentation: '',
452
+ lines: [ 8, 10 ],
453
+ start: 87,
454
+ end: 260,
455
+ rawArgs: 'src=./relative/path/to/code.js&lines=22-44',
456
+ rawContent: 'This content will be dynamically replaced with code from the file lines 22 through 44',
457
+ value: '<!-- DOCS:START (CODE:src=./relative/path/to/code.js&lines=22-44) -->\n' +
458
+ 'This content will be dynamically replaced with code from the file lines 22 through 44\n' +
459
+ '<!-- DOCS:END -->'
460
+ }
461
+ }
462
+ ], 'Array contains details')
463
+ })
464
+
465
+ test('Returns empty array', () => {
466
+ assert.equal(parseBlocks('', defaultOpts).blocks, [])
467
+ assert.equal(parseBlocks(' ', defaultOpts).blocks, [])
468
+ assert.equal(parseBlocks(`
469
+
470
+
471
+ `, defaultOpts).blocks, [])
472
+ assert.equal(parseBlocks(`
473
+ # No block in here
474
+
475
+ nope
476
+ `, defaultOpts).blocks, [])
477
+ })
478
+
479
+ test.run()
package/lib/cli.js ADDED
@@ -0,0 +1,245 @@
1
+
2
+ const path = require('path')
3
+ const isGlob = require('is-glob')
4
+ const isValidFilePath = require('is-valid-path')
5
+ const { loadConfig } = require('./utils/load-config')
6
+ const { findUp } = require('./utils/fs')
7
+ const { markdownMagic } = require('./')
8
+ const { parse } = require('oparser')
9
+ const { deepLog } = require('./utils/logs')
10
+ const { REGEX_REGEX, escapeRegexString } = require('./utils/regex')
11
+ const { getFirstCharacter, isUpperCase } = require('./utils/text')
12
+ const argv = process.argv.slice(2)
13
+ const cwd = process.cwd()
14
+ const defaultConfigPath = 'md.config.js'
15
+
16
+ const ARRAY_REGEX = /^\[(.*)\]$/
17
+
18
+ /** @type {BUILD_VERSION} */
19
+ const x = 'f'
20
+
21
+ function isArrayLike(str) {
22
+ if (typeof str !== 'string') return false
23
+ return Boolean(ARRAY_REGEX.test(str))
24
+ }
25
+
26
+ async function getBaseDir(opts = {}) {
27
+ const { currentDir = cwd } = opts
28
+ const gitDir = await findUp(currentDir, '.git')
29
+ return (gitDir) ? path.dirname(gitDir) : currentDir
30
+ }
31
+
32
+ function stringLooksLikeFile(value) {
33
+ return !value.match(/^-+/) // isn't option looking
34
+ && isValidFilePath(value)
35
+ && (
36
+ path.basename(value).indexOf('.') > -1 // has period
37
+ || getFirstCharacter(value) === '_' // starts with _
38
+ // || isUpperCase(value) // is all caps
39
+ )
40
+ }
41
+
42
+ function getValue(val) {
43
+ return (val[1] !== '=') ? val[1] : val[0]
44
+ }
45
+
46
+ function trimLeadingDashes(value) {
47
+ return value.replace(/^-+/, '')
48
+ }
49
+
50
+ function removeNodeModules(value = '') {
51
+ if (typeof value !== 'string') {
52
+ return true
53
+ }
54
+ return !value.match(/node_modules\//)
55
+ }
56
+
57
+ function coerceStringToRegex(str) {
58
+ const isRegex = str.match(REGEX_REGEX)
59
+ if (!isRegex) {
60
+ return str
61
+ }
62
+ const [ _match, pattern, flags ] = isRegex
63
+ return new RegExp(escapeRegexString(pattern), flags)
64
+ }
65
+
66
+ function convertToArray(str = '') {
67
+ const { fixedArray } = parse(`fixedArray=${str}`)
68
+ return (fixedArray || [])
69
+ }
70
+
71
+ function addValue(value, currentCollection) {
72
+ if (isArrayLike(value)) {
73
+ const array = convertToArray(value)
74
+ // uniquify returned array
75
+ return Array.from(new Set(currentCollection.concat(array)))
76
+ }
77
+ if (currentCollection.indexOf(value) > -1) {
78
+ return currentCollection
79
+ }
80
+ return currentCollection.concat(value)
81
+ }
82
+
83
+ /*
84
+ node ./cli.js test/fixtures/md/**.md debug --transform test/fixtures/md/transform-**.md 1233535235 = hahah funky=hi --ignore test/fixtures/output/**.md --lol --whatever test/fixtures/md/syntax-**.md --foo=bar --fun lol.md what=no.md x 'xno.md' what
85
+ */
86
+ function getGlobGroupsFromArgs(args, opts = {}) {
87
+ const globKeys = opts.globKeys || []
88
+ let preceding = ['', '']
89
+ let collection = []
90
+ let globGroups = []
91
+ let reserved = []
92
+ let otherOpts = []
93
+ let /** @type {string|undefined} */ cacheKey = ''
94
+ for (let i = 0; i < args.length; i++) {
95
+ const isLastArg = (args.length - 1) === i
96
+ const arg = args[i]
97
+ const prevArg = args[i - 1]
98
+ const looksLikeFile = stringLooksLikeFile(arg) // @TODO verify file exists?
99
+ // console.log('looksLikeFile', looksLikeFile)
100
+ // console.log('cacheKey', cacheKey)
101
+ // console.log('arg', arg)
102
+
103
+ if (looksLikeFile && typeof cacheKey !== 'undefined') {
104
+ // @TODO verify file exists?
105
+ collection.push(arg)
106
+ } else if (arg.match(/^-+/)) {
107
+ cacheKey = arg
108
+ if (collection.length) {
109
+ const val = getValue(preceding)
110
+ reserved.push(val)
111
+ globGroups.push({
112
+ key: trimLeadingDashes(val),
113
+ raw: val,
114
+ values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
115
+ })
116
+ collection = []
117
+ }
118
+ preceding = [ prevArg, arg ]
119
+ } else if (cacheKey && arg.match(/=/)) {
120
+ // console.log('FOOO', arg)
121
+ cacheKey = undefined
122
+ }
123
+
124
+ const cleanKey = trimLeadingDashes(cacheKey || '')
125
+ const isDefinedGlobKey = globKeys.includes(cleanKey) || globKeys.includes(cacheKey)
126
+ // console.log(`isDefinedGlobKey: ${cleanKey}`, isDefinedGlobKey)
127
+ if (isDefinedGlobKey && (isGlob(arg) || looksLikeFile)) {
128
+ /*
129
+ console.log('ADD collection.push', arg)
130
+ /** */
131
+ collection = addValue(arg, collection)
132
+ } else {
133
+ if (!cacheKey && isGlob(arg)) {
134
+ collection = addValue(arg, collection)
135
+ } else if (!looksLikeFile) {
136
+ /* Pass through non matching args */
137
+ /*
138
+ console.log('ADD otherOpts', arg)
139
+ /** */
140
+ otherOpts.push(arg)
141
+ }
142
+ }
143
+
144
+ if (isLastArg && collection.length) {
145
+ const val = getValue(preceding)
146
+ reserved.push(val)
147
+ globGroups.push({
148
+ key: trimLeadingDashes(val),
149
+ raw: val,
150
+ values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
151
+ })
152
+ collection = []
153
+ }
154
+ }
155
+
156
+ return {
157
+ globGroups,
158
+ otherOpts: otherOpts.filter((opt) => !reserved.includes(opt))
159
+ }
160
+ }
161
+
162
+ async function runCli(options = {}) {
163
+ let configFile
164
+ let opts = {}
165
+ /*
166
+ console.log('argv', argv)
167
+ console.log('options', options)
168
+ /** */
169
+ /* If raw args found, process them further */
170
+ if (argv.length && (options._ && options._.length || (options.file || options.files))) {
171
+ // if (isGlob(argv[0])) {
172
+ // console.log('glob', argv[0])
173
+ // options.glob = argv[0]
174
+ // }
175
+ const globParse = getGlobGroupsFromArgs(argv, {
176
+ /* CLI args that should be glob keys */
177
+ globKeys: ['files', 'file']
178
+ })
179
+ const { globGroups, otherOpts } = globParse
180
+ console.log('globGroups', globGroups)
181
+ // deepLog(globParse)
182
+ // console.log('globParse', globParse)
183
+ if (globGroups.length) {
184
+ const globGroupByKey = globGroups.reduce((acc, curr, i) => {
185
+ acc[curr.key] = globGroups[i]
186
+ return acc
187
+ }, {})
188
+ // console.log('globGroupByKey', globGroupByKey)
189
+
190
+ if (globGroupByKey.file) {
191
+ options.glob = globGroupByKey.file.values
192
+ } else if (globGroupByKey['']) {
193
+ options.glob = globGroupByKey[''].values
194
+ }
195
+
196
+ if (globGroupByKey.ignore) {
197
+ options.ignore = globGroupByKey.ignore.values
198
+ }
199
+
200
+ /*
201
+ deepLog(options)
202
+ /** */
203
+ }
204
+
205
+ /* Parse for weird CLI inputs */
206
+ const extraParse = parse(otherOpts.join(' '))
207
+
208
+ /*
209
+ // console.log('otherOpts', otherOpts)
210
+ console.log('nicely handed CLI args')
211
+ console.log(extraParse)
212
+ process.exit(1)
213
+ /** */
214
+
215
+ delete options._
216
+ opts = {
217
+ ...options,
218
+ ...extraParse
219
+ }
220
+ // console.log('opts', opts)
221
+ }
222
+ if (opts.config) {
223
+ configFile = opts.config
224
+ } else {
225
+ const baseDir = await getBaseDir()
226
+ configFile = await findUp(baseDir, defaultConfigPath)
227
+ }
228
+ const config = (configFile) ? loadConfig(configFile) : {}
229
+ const mergedConfig = {
230
+ ...config,
231
+ ...opts,
232
+ }
233
+
234
+ mergedConfig.outputDir = mergedConfig.output || mergedConfig.outputDir
235
+ /*
236
+ console.log('mergedConfig', mergedConfig)
237
+ // return
238
+ /** */
239
+ await markdownMagic(mergedConfig)
240
+ }
241
+
242
+ module.exports = {
243
+ getGlobGroupsFromArgs,
244
+ runCli
245
+ }