markdown-magic 3.0.2 → 3.0.4

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 (40) 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 -22
  6. package/lib/cli.test.js +12 -12
  7. package/lib/index.js +418 -119
  8. package/lib/process-contents.js +59 -23
  9. package/lib/process-file.js +39 -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/globals.d.ts +0 -66
  25. package/lib/utils/md/filters.js +0 -20
  26. package/lib/utils/md/find-code-blocks.js +0 -88
  27. package/lib/utils/md/find-date.js +0 -32
  28. package/lib/utils/md/find-frontmatter.js +0 -92
  29. package/lib/utils/md/find-frontmatter.test.js +0 -17
  30. package/lib/utils/md/find-html-tags.js +0 -105
  31. package/lib/utils/md/find-images-md.js +0 -27
  32. package/lib/utils/md/find-images.js +0 -107
  33. package/lib/utils/md/find-links.js +0 -220
  34. package/lib/utils/md/find-unmatched-html-tags.js +0 -32
  35. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +0 -14
  36. package/lib/utils/md/fixtures/file-with-frontmatter.md +0 -32
  37. package/lib/utils/md/fixtures/file-with-links.md +0 -153
  38. package/lib/utils/md/md.test.js +0 -105
  39. package/lib/utils/md/parse.js +0 -146
  40. 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,9 +14,8 @@ const cwd = process.cwd()
14
14
  const defaultConfigPath = 'md.config.js'
15
15
 
16
16
  const ARRAY_REGEX = /^\[(.*)\]$/
17
-
18
- /** @type {BUILD_VERSION} */
19
- const x = 'f'
17
+ const NOT_OBJECT_LIKE = /^{[^:,]*}/
18
+ const IS_KEY_VALUE_NON_ARRAY = /^([A-Za-z0-9_]*)=\s?([^\[\{]]*)([^\[\{]*)$/
20
19
 
21
20
  function isArrayLike(str) {
22
21
  if (typeof str !== 'string') return false
@@ -91,26 +90,34 @@ function getGlobGroupsFromArgs(args, opts = {}) {
91
90
  let reserved = []
92
91
  let otherOpts = []
93
92
  let /** @type {string|undefined} */ cacheKey = ''
93
+ // console.log('args', args)
94
94
  for (let i = 0; i < args.length; i++) {
95
95
  const isLastArg = (args.length - 1) === i
96
96
  const arg = args[i]
97
97
  const prevArg = args[i - 1]
98
98
  const looksLikeFile = stringLooksLikeFile(arg) // @TODO verify file exists?
99
- // console.log('looksLikeFile', looksLikeFile)
100
- // console.log('cacheKey', cacheKey)
99
+
101
100
  // console.log('arg', arg)
101
+ // console.log('looksLikeFile', looksLikeFile)
102
+ // console.log('collection', collection)
103
+
104
+ // console.log('cacheKey', cacheKey)
102
105
 
103
106
  if (looksLikeFile && typeof cacheKey !== 'undefined') {
104
107
  // @TODO verify file exists?
105
108
  collection.push(arg)
106
- } else if (arg.match(/^-+/)) {
109
+ } else if (arg.match(/^-+/) && !arg.match(/=/)) {
107
110
  cacheKey = arg
111
+ // console.log('cacheKey', cacheKey)
112
+ // console.log('collection', collection)
113
+ // console.log('arg', arg)
108
114
  if (collection.length) {
109
115
  const val = getValue(preceding)
116
+ // console.log('val', val)
110
117
  reserved.push(val)
111
118
  globGroups.push({
112
119
  key: trimLeadingDashes(val),
113
- raw: val,
120
+ rawKey: val,
114
121
  values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
115
122
  })
116
123
  collection = []
@@ -130,24 +137,34 @@ function getGlobGroupsFromArgs(args, opts = {}) {
130
137
  /** */
131
138
  collection = addValue(arg, collection)
132
139
  } else {
133
- 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))
134
142
  collection = addValue(arg, collection)
135
143
  } else if (!looksLikeFile) {
136
144
  /* Pass through non matching args */
137
145
  /*
138
146
  console.log('ADD otherOpts', arg)
139
147
  /** */
140
- 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
+
141
155
  }
142
156
  }
143
-
157
+
158
+ // console.log('end', collection)
144
159
  if (isLastArg && collection.length) {
160
+ // console.log('isLastArg', isLastArg)
145
161
  const val = getValue(preceding)
146
162
  reserved.push(val)
147
163
  globGroups.push({
148
164
  key: trimLeadingDashes(val),
149
- raw: val,
150
- values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x))
165
+ rawKey: val,
166
+ values: collection.filter(removeNodeModules).map((x) => coerceStringToRegex(x)),
167
+ // last: 'last'
151
168
  })
152
169
  collection = []
153
170
  }
@@ -166,6 +183,7 @@ async function runCli(options = {}) {
166
183
  console.log('argv', argv)
167
184
  console.log('options', options)
168
185
  /** */
186
+ options.files = []
169
187
  /* If raw args found, process them further */
170
188
  if (argv.length && (options._ && options._.length || (options.file || options.files))) {
171
189
  // if (isGlob(argv[0])) {
@@ -177,9 +195,11 @@ async function runCli(options = {}) {
177
195
  globKeys: ['files', 'file']
178
196
  })
179
197
  const { globGroups, otherOpts } = globParse
198
+ /*
180
199
  console.log('globGroups', globGroups)
200
+ console.log('globParse', globParse)
181
201
  // deepLog(globParse)
182
- // console.log('globParse', globParse)
202
+ /** */
183
203
  if (globGroups.length) {
184
204
  const globGroupByKey = globGroups.reduce((acc, curr, i) => {
185
205
  acc[curr.key] = globGroups[i]
@@ -187,10 +207,16 @@ async function runCli(options = {}) {
187
207
  }, {})
188
208
  // console.log('globGroupByKey', globGroupByKey)
189
209
 
210
+
190
211
  if (globGroupByKey.file) {
191
- options.glob = globGroupByKey.file.values
192
- } else if (globGroupByKey['']) {
193
- 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)
194
220
  }
195
221
 
196
222
  if (globGroupByKey.ignore) {
@@ -203,21 +229,67 @@ async function runCli(options = {}) {
203
229
  }
204
230
 
205
231
  /* Parse for weird CLI inputs */
206
- const extraParse = parse(otherOpts.join(' '))
207
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)
208
252
  /*
209
- // console.log('otherOpts', otherOpts)
253
+ console.log('optStringArr', newArray)
254
+ console.log('optString', optString)
255
+ console.log('otherOpts strings', otherOpts)
210
256
  console.log('nicely handed CLI args')
211
- console.log(extraParse)
257
+ console.log('extraParse', extraParse)
212
258
  process.exit(1)
213
259
  /** */
214
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
+
215
287
  delete options._
216
288
  opts = {
217
289
  ...options,
218
290
  ...extraParse
219
291
  }
220
- // console.log('opts', opts)
292
+ //console.log('opts', opts)
221
293
  }
222
294
  if (opts.config) {
223
295
  configFile = opts.config
@@ -231,12 +303,19 @@ async function runCli(options = {}) {
231
303
  ...opts,
232
304
  }
233
305
 
234
- mergedConfig.outputDir = mergedConfig.output || mergedConfig.outputDir
306
+ if (mergedConfig.output || mergedConfig.outputDir) {
307
+ mergedConfig.outputDir = mergedConfig.output || mergedConfig.outputDir
308
+ }
235
309
  /*
236
310
  console.log('mergedConfig', mergedConfig)
311
+ process.exit(1)
237
312
  // return
238
313
  /** */
239
- await markdownMagic(mergedConfig)
314
+ return markdownMagic(mergedConfig)
315
+ }
316
+
317
+ function onlyUnique(value, index, self) {
318
+ return self.indexOf(value) === index
240
319
  }
241
320
 
242
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',