markdown-magic 3.0.3 → 3.0.5

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 (39) hide show
  1. package/README.md +295 -101
  2. package/cli.js +4 -1
  3. package/lib/block-parser.js +32 -28
  4. package/lib/block-parser.test.js +2 -0
  5. package/lib/cli.js +101 -19
  6. package/lib/cli.test.js +12 -12
  7. package/lib/index.js +418 -119
  8. package/lib/process-contents.js +61 -23
  9. package/lib/process-file.js +40 -4
  10. package/lib/transforms/code.js +33 -10
  11. package/lib/transforms/file.js +4 -2
  12. package/lib/transforms/index.js +114 -0
  13. package/lib/transforms/sectionToc.js +2 -2
  14. package/lib/transforms/toc.js +22 -4
  15. package/lib/transforms/wordCount.js +2 -2
  16. package/lib/utils/fs.js +8 -172
  17. package/lib/utils/fs.test.js +4 -162
  18. package/lib/utils/hash-file.js +28 -0
  19. package/lib/utils/logs.js +16 -2
  20. package/lib/utils/syntax.js +1 -0
  21. package/lib/utils/text.js +1 -1
  22. package/lib/utils/toposort.js +131 -0
  23. package/package.json +4 -3
  24. package/lib/utils/md/filters.js +0 -20
  25. package/lib/utils/md/find-code-blocks.js +0 -88
  26. package/lib/utils/md/find-date.js +0 -32
  27. package/lib/utils/md/find-frontmatter.js +0 -92
  28. package/lib/utils/md/find-frontmatter.test.js +0 -17
  29. package/lib/utils/md/find-html-tags.js +0 -105
  30. package/lib/utils/md/find-images-md.js +0 -27
  31. package/lib/utils/md/find-images.js +0 -107
  32. package/lib/utils/md/find-links.js +0 -220
  33. package/lib/utils/md/find-unmatched-html-tags.js +0 -32
  34. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +0 -14
  35. package/lib/utils/md/fixtures/file-with-frontmatter.md +0 -32
  36. package/lib/utils/md/fixtures/file-with-links.md +0 -153
  37. package/lib/utils/md/md.test.js +0 -105
  38. package/lib/utils/md/parse.js +0 -146
  39. package/lib/utils/md/utils.js +0 -19
@@ -12,26 +12,11 @@ const defaultOptions = {
12
12
  }
13
13
 
14
14
  function parseBlocks(contents, opts = {}) {
15
- const options = Object.assign({}, defaultOptions, opts)
16
- const { syntax, open, close } = options
17
- if (!open) {
18
- throw new Error('Missing options.open')
19
- }
20
- if (!close) {
21
- throw new Error('Missing options.close')
22
- }
23
- if (!syntax) {
24
- throw new Error('Missing options.syntax')
25
- }
26
- const syntaxInfo = getSyntaxInfo(syntax)
27
- if (!syntaxInfo.pattern) {
28
- throw new Error(`Unknown syntax "${syntax}"`)
29
- }
30
- const [ openComment, closeComment ] = syntaxInfo.pattern
15
+ const _options = Object.assign({}, defaultOptions, opts)
16
+ const { syntax, open, close } = _options
31
17
 
32
18
  const patterns = getBlockRegex({
33
- openComment,
34
- closeComment,
19
+ syntax,
35
20
  openText: open,
36
21
  closeText: close
37
22
  })
@@ -65,10 +50,13 @@ function parseBlocks(contents, opts = {}) {
65
50
  // console.log('isBalanced', isBalanced)
66
51
  const balanced = (closeCount > openCount) ? true : isBalanced
67
52
  if (!balanced) {
68
- throw new Error(`Blocks are unbalanced.
69
- ${openCount} "${open}" open tags.
70
- ${closeCount} "${close}" close tags.
71
- `)
53
+ throw new Error(`[Parsing error]
54
+
55
+ Comment blocks are unbalanced in string
56
+
57
+ Details:
58
+ - Found ${openCount} "${open}" open tags.
59
+ - Found ${closeCount} "${close}" close tags.\n\n`)
72
60
  }
73
61
 
74
62
  /* New regex works! */
@@ -131,7 +119,9 @@ function parseBlocks(contents, opts = {}) {
131
119
  options = legacyParseOptions(paramString)
132
120
  context.isLegacy = true
133
121
  } else {
134
- // console.log('paramString', paramString)
122
+ if (paramString[0] === '(' && paramString[paramString.length - 1] === ')') {
123
+ paramString = paramString.replace(/^\(/, '').replace(/\)$/g, '')
124
+ }
135
125
  options = parse(paramString)
136
126
  }
137
127
 
@@ -238,22 +228,36 @@ function legacyParseOptions(options) {
238
228
  /**
239
229
  * Get Regex pattern to match block
240
230
  * @param {object} options
241
- * @param {string} [options.openEmoji] - emoji
242
- * @param {string} [options.openComment] - comment syntax open
243
- * @param {string} [options.closeComment] - comment syntax open
231
+ * @param {string} [options.syntax] - comment open text
244
232
  * @param {string} [options.openText] - comment open text
233
+ * @param {string} [options.openEmoji] - emoji
245
234
  * @param {string} [options.closeText] - comment close text
246
235
  * @param {boolean} [options.allowMissingTransforms] - Allow for missing transform key
247
236
  * @returns {RegexPatterns}
248
237
  */
249
238
  function getBlockRegex({
250
239
  openEmoji,
251
- openComment,
252
- closeComment,
240
+ syntax = SYNTAX,
253
241
  openText = '',
254
242
  closeText = '',
255
243
  allowMissingTransforms = false
256
244
  }) {
245
+ if (!openText) {
246
+ throw new Error('Missing options.open')
247
+ }
248
+ if (!closeText) {
249
+ throw new Error('Missing options.close')
250
+ }
251
+ if (!syntax) {
252
+ throw new Error('Missing options.syntax')
253
+ }
254
+
255
+ const syntaxInfo = getSyntaxInfo(syntax)
256
+ if (!syntaxInfo.pattern) {
257
+ throw new Error(`Unknown syntax "${syntax}"`)
258
+ }
259
+
260
+ const [ openComment, closeComment ] = syntaxInfo.pattern
257
261
  // https://regex101.com/r/SU2g1Q/1
258
262
  // https://regex101.com/r/SU2g1Q/2
259
263
  // https://regex101.com/r/SU2g1Q/3
@@ -404,7 +404,9 @@ This content will be dynamically replaced with code from the file lines 22 throu
404
404
 
405
405
  test('Parse md blocks', () => {
406
406
  const parsedValue = parseBlocks(mdText, defaultOpts)
407
+ /*
407
408
  deepLog(parsedValue)
409
+ /** */
408
410
  assert.equal(parsedValue.blocks, [
409
411
  {
410
412
  index: 1,
package/lib/cli.js CHANGED
@@ -14,6 +14,8 @@ const cwd = process.cwd()
14
14
  const defaultConfigPath = 'md.config.js'
15
15
 
16
16
  const ARRAY_REGEX = /^\[(.*)\]$/
17
+ const NOT_OBJECT_LIKE = /^{[^:,]*}/
18
+ const IS_KEY_VALUE_NON_ARRAY = /^([A-Za-z0-9_]*)=\s?([^\[\{]]*)([^\[\{]*)$/
17
19
 
18
20
  function isArrayLike(str) {
19
21
  if (typeof str !== 'string') return false
@@ -88,26 +90,34 @@ function getGlobGroupsFromArgs(args, opts = {}) {
88
90
  let reserved = []
89
91
  let otherOpts = []
90
92
  let /** @type {string|undefined} */ cacheKey = ''
93
+ // console.log('args', args)
91
94
  for (let i = 0; i < args.length; i++) {
92
95
  const isLastArg = (args.length - 1) === i
93
96
  const arg = args[i]
94
97
  const prevArg = args[i - 1]
95
98
  const looksLikeFile = stringLooksLikeFile(arg) // @TODO verify file exists?
96
- // console.log('looksLikeFile', looksLikeFile)
97
- // console.log('cacheKey', cacheKey)
99
+
98
100
  // console.log('arg', arg)
101
+ // console.log('looksLikeFile', looksLikeFile)
102
+ // console.log('collection', collection)
103
+
104
+ // console.log('cacheKey', cacheKey)
99
105
 
100
106
  if (looksLikeFile && typeof cacheKey !== 'undefined') {
101
107
  // @TODO verify file exists?
102
108
  collection.push(arg)
103
- } else if (arg.match(/^-+/)) {
109
+ } else if (arg.match(/^-+/) && !arg.match(/=/)) {
104
110
  cacheKey = arg
111
+ // console.log('cacheKey', cacheKey)
112
+ // console.log('collection', collection)
113
+ // console.log('arg', arg)
105
114
  if (collection.length) {
106
115
  const val = getValue(preceding)
116
+ // console.log('val', val)
107
117
  reserved.push(val)
108
118
  globGroups.push({
109
119
  key: trimLeadingDashes(val),
110
- raw: val,
120
+ rawKey: val,
111
121
  values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
112
122
  })
113
123
  collection = []
@@ -127,24 +137,34 @@ function getGlobGroupsFromArgs(args, opts = {}) {
127
137
  /** */
128
138
  collection = addValue(arg, collection)
129
139
  } else {
130
- if (!cacheKey && isGlob(arg)) {
140
+ if (!cacheKey && isGlob(arg) && !arg.match(/=/) || (arg.match(NOT_OBJECT_LIKE) && !isArrayLike(arg))) {
141
+ // console.log('GLOB MATCH', arg, isGlob(arg))
131
142
  collection = addValue(arg, collection)
132
143
  } else if (!looksLikeFile) {
133
144
  /* Pass through non matching args */
134
145
  /*
135
146
  console.log('ADD otherOpts', arg)
136
147
  /** */
137
- otherOpts.push(arg)
148
+ if (arg.match(IS_KEY_VALUE_NON_ARRAY)) {
149
+ // quote quote wrap
150
+ otherOpts.push(arg.replace(IS_KEY_VALUE_NON_ARRAY, '$1="$2$3"'))
151
+ } else {
152
+ otherOpts.push(arg)
153
+ }
154
+
138
155
  }
139
156
  }
140
-
157
+
158
+ // console.log('end', collection)
141
159
  if (isLastArg && collection.length) {
160
+ // console.log('isLastArg', isLastArg)
142
161
  const val = getValue(preceding)
143
162
  reserved.push(val)
144
163
  globGroups.push({
145
164
  key: trimLeadingDashes(val),
146
- raw: val,
147
- values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
165
+ rawKey: val,
166
+ values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x)),
167
+ // last: 'last'
148
168
  })
149
169
  collection = []
150
170
  }
@@ -163,6 +183,7 @@ async function runCli(options = {}) {
163
183
  console.log('argv', argv)
164
184
  console.log('options', options)
165
185
  /** */
186
+ options.files = []
166
187
  /* If raw args found, process them further */
167
188
  if (argv.length && (options._ && options._.length || (options.file || options.files))) {
168
189
  // if (isGlob(argv[0])) {
@@ -174,9 +195,11 @@ async function runCli(options = {}) {
174
195
  globKeys: ['files', 'file']
175
196
  })
176
197
  const { globGroups, otherOpts } = globParse
198
+ /*
177
199
  console.log('globGroups', globGroups)
200
+ console.log('globParse', globParse)
178
201
  // deepLog(globParse)
179
- // console.log('globParse', globParse)
202
+ /** */
180
203
  if (globGroups.length) {
181
204
  const globGroupByKey = globGroups.reduce((acc, curr, i) => {
182
205
  acc[curr.key] = globGroups[i]
@@ -184,10 +207,16 @@ async function runCli(options = {}) {
184
207
  }, {})
185
208
  // console.log('globGroupByKey', globGroupByKey)
186
209
 
210
+
187
211
  if (globGroupByKey.file) {
188
- options.glob = globGroupByKey.file.values
189
- } else if (globGroupByKey['']) {
190
- options.glob = globGroupByKey[''].values
212
+ options.files = options.files.concat(globGroupByKey.file.values)
213
+ delete options.file
214
+ }
215
+ if (globGroupByKey.files) {
216
+ options.files = options.files.concat(globGroupByKey.files.values)
217
+ }
218
+ if (globGroupByKey['']) {
219
+ options.files = options.files.concat(globGroupByKey[''].values)
191
220
  }
192
221
 
193
222
  if (globGroupByKey.ignore) {
@@ -200,21 +229,67 @@ async function runCli(options = {}) {
200
229
  }
201
230
 
202
231
  /* Parse for weird CLI inputs */
203
- const extraParse = parse(otherOpts.join(' '))
204
232
 
233
+ /* Handle -- and - flags */
234
+ let newArray = []
235
+ for (let i = 0; i < otherOpts.length; i++) {
236
+ const curr = otherOpts[i]
237
+ const prev = newArray[i - 1]
238
+ if (curr.match(/^-+/)) {
239
+ const cleanX = curr.replace(/^-+/, '')
240
+ const equal = (cleanX.indexOf('=') === -1) ? '=' : ' '
241
+ newArray.push(cleanX + equal)
242
+ continue
243
+ }
244
+ if (prev && prev.match(/=\s?$/) && (curr.match(/^\s?=/) || curr.trim() === '=')) {
245
+ continue
246
+ }
247
+ newArray.push(curr + ' ')
248
+ }
249
+
250
+ const optString = newArray.join('')
251
+ const extraParse = parse(optString)
205
252
  /*
206
- // console.log('otherOpts', otherOpts)
253
+ console.log('optStringArr', newArray)
254
+ console.log('optString', optString)
255
+ console.log('otherOpts strings', otherOpts)
207
256
  console.log('nicely handed CLI args')
208
- console.log(extraParse)
257
+ console.log('extraParse', extraParse)
209
258
  process.exit(1)
210
259
  /** */
211
260
 
261
+ if (extraParse.file) {
262
+ options.files = options.files.concat(extraParse.file)
263
+ delete extraParse.file
264
+ }
265
+
266
+ if (extraParse.files) {
267
+ options.files = options.files.concat(extraParse.files)
268
+ delete extraParse.files
269
+ }
270
+
271
+ if (extraParse['--files']) {
272
+ options.files = options.files.concat(extraParse['--files'])
273
+ delete extraParse['--files']
274
+ }
275
+
276
+ // console.log('options.files', options.files)
277
+
278
+ options.files = options.files.map((x) => {
279
+ if (typeof x === 'string' && x.match(/,/)) {
280
+ return x.split(',')
281
+ }
282
+ return x
283
+ })
284
+ .flat()
285
+ .filter(onlyUnique)
286
+
212
287
  delete options._
213
288
  opts = {
214
289
  ...options,
215
290
  ...extraParse
216
291
  }
217
- // console.log('opts', opts)
292
+ //console.log('opts', opts)
218
293
  }
219
294
  if (opts.config) {
220
295
  configFile = opts.config
@@ -228,12 +303,19 @@ async function runCli(options = {}) {
228
303
  ...opts,
229
304
  }
230
305
 
231
- mergedConfig.outputDir = mergedConfig.output || mergedConfig.outputDir
306
+ if (mergedConfig.output || mergedConfig.outputDir) {
307
+ mergedConfig.outputDir = mergedConfig.output || mergedConfig.outputDir
308
+ }
232
309
  /*
233
310
  console.log('mergedConfig', mergedConfig)
311
+ process.exit(1)
234
312
  // return
235
313
  /** */
236
- await markdownMagic(mergedConfig)
314
+ return markdownMagic(mergedConfig)
315
+ }
316
+
317
+ function onlyUnique(value, index, self) {
318
+ return self.indexOf(value) === index
237
319
  }
238
320
 
239
321
  module.exports = {
package/lib/cli.test.js CHANGED
@@ -101,7 +101,7 @@ node ./cli.js test/fixtures/md/**.md debug --transform test/fixtures/md/transfor
101
101
  assert.equal(globData.globGroups, [
102
102
  {
103
103
  key: '',
104
- raw: '',
104
+ rawKey: '',
105
105
  values: [
106
106
  'test/fixtures/md/basic.md',
107
107
  'test/fixtures/md/error-missing-transforms-two.md',
@@ -128,7 +128,7 @@ node ./cli.js test/fixtures/md/**.md debug --transform test/fixtures/md/transfor
128
128
  },
129
129
  {
130
130
  key: 'transform',
131
- raw: '--transform',
131
+ rawKey: '--transform',
132
132
  values: [
133
133
  'test/fixtures/md/transform-code.md',
134
134
  'test/fixtures/md/transform-custom.md',
@@ -140,7 +140,7 @@ node ./cli.js test/fixtures/md/**.md debug --transform test/fixtures/md/transfor
140
140
  },
141
141
  {
142
142
  key: 'ignore',
143
- raw: '--ignore',
143
+ rawKey: '--ignore',
144
144
  values: [
145
145
  'test/fixtures/output/basic.md',
146
146
  'test/fixtures/output/block-no-transform.md',
@@ -168,13 +168,13 @@ node ./cli.js test/fixtures/md/**.md debug --transform test/fixtures/md/transfor
168
168
  },
169
169
  {
170
170
  key: 'whatever',
171
- raw: '--whatever',
171
+ rawKey: '--whatever',
172
172
  values: [
173
173
  'test/fixtures/md/syntax-legacy-colon.md',
174
174
  'test/fixtures/md/syntax-legacy-query.md'
175
175
  ]
176
176
  },
177
- { key: 'fun', raw: '--fun', values: [ 'lol.md' ] }
177
+ { key: 'fun', rawKey: '--fun', values: [ 'lol.md' ] }
178
178
  ])
179
179
  })
180
180
 
@@ -193,7 +193,7 @@ test('test 2', () => {
193
193
  deepLogger(globData)
194
194
  /** */
195
195
  assert.equal(globData, {
196
- globGroups: [ { key: 'file', raw: '--file', values: [ '**.md', 'funky**.md' ] } ],
196
+ globGroups: [ { key: 'file', rawKey: '--file', values: [ '**.md', 'funky**.md' ] } ],
197
197
  otherOpts: [ 'billy', '--foo', 'bar*123' ]
198
198
  })
199
199
  })
@@ -213,7 +213,7 @@ test('Handles multiple string values and groups them', () => {
213
213
  globGroups: [
214
214
  {
215
215
  key: '',
216
- raw: '',
216
+ rawKey: '',
217
217
  values: [ 'test/fixtures/md/bar.md', 'test/fixtures/output/foo.md' ]
218
218
  }
219
219
  ],
@@ -236,7 +236,7 @@ test('Handles multiple string GLOB values and groups them', () => {
236
236
  globGroups: [
237
237
  {
238
238
  key: '',
239
- raw: '',
239
+ rawKey: '',
240
240
  values: [ 'test/fixtures/md/**.md', 'test/fixtures/output/**.md' ]
241
241
  }
242
242
  ],
@@ -270,7 +270,7 @@ test('Handles globKey set with multiple file/glob like values supplied afterward
270
270
  deepLogger(globData)
271
271
  /** */
272
272
  assert.equal(globData, {
273
- globGroups: [ { key: 'file', raw: '--file', values: [
273
+ globGroups: [ { key: 'file', rawKey: '--file', values: [
274
274
  'foobar.md',
275
275
  'funktown/bar.md',
276
276
  '**.md',
@@ -308,7 +308,7 @@ node ./cli.js --file 'test/fixtures/md/**.md' 'test/fixtures/output/**.md' '[foo
308
308
  globGroups: [
309
309
  {
310
310
  key: 'file',
311
- raw: '--file',
311
+ rawKey: '--file',
312
312
  values: [
313
313
  'funktown/bar.md',
314
314
  'test/fixtures/md/**.md',
@@ -370,12 +370,12 @@ test('Handles string arrays if globKeys set', () => {
370
370
  globGroups: [
371
371
  {
372
372
  key: 'file',
373
- raw: '--file',
373
+ rawKey: '--file',
374
374
  values: [ '**.md', /xyz\*\*\.md/, 'funky**.md' ]
375
375
  },
376
376
  {
377
377
  key: 'fuzz',
378
- raw: '--fuzz',
378
+ rawKey: '--fuzz',
379
379
  values: [
380
380
  'test/fixtures/output/basic.md',
381
381
  'test/fixtures/output/block-no-transform.md',