markdown-magic 3.0.0 → 3.0.2

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 (49) hide show
  1. package/README.md +43 -29
  2. package/lib/block-parser-js.test.js +148 -156
  3. package/lib/block-parser.js +255 -262
  4. package/lib/block-parser.test.js +43 -6
  5. package/lib/cli.js +30 -19
  6. package/lib/cli.test.js +73 -73
  7. package/lib/globals.d.ts +66 -0
  8. package/lib/index.js +43 -9
  9. package/lib/process-contents.js +80 -39
  10. package/lib/process-file.js +4 -1
  11. package/lib/transforms/code.js +4 -10
  12. package/lib/transforms/file.js +7 -10
  13. package/lib/transforms/index.js +0 -0
  14. package/lib/transforms/remote.js +2 -3
  15. package/lib/transforms/sectionToc.js +18 -0
  16. package/lib/transforms/toc.js +10 -335
  17. package/lib/types.js +11 -0
  18. package/lib/utils/fs.js +21 -19
  19. package/lib/utils/fs.test.js +4 -5
  20. package/lib/utils/logs.js +7 -2
  21. package/lib/utils/md/filters.js +5 -5
  22. package/lib/utils/md/find-code-blocks.js +16 -8
  23. package/lib/utils/md/find-frontmatter.js +11 -13
  24. package/lib/utils/md/find-frontmatter.test.js +2 -2
  25. package/lib/utils/md/find-html-tags.js +1 -1
  26. package/lib/utils/md/find-images-md.js +27 -0
  27. package/lib/utils/md/find-images.js +39 -34
  28. package/lib/utils/md/find-links.js +72 -54
  29. package/lib/utils/md/find-unmatched-html-tags.js +1 -2
  30. package/lib/utils/md/fixtures/file-with-links.md +10 -0
  31. package/lib/utils/md/md.test.js +72 -4
  32. package/lib/utils/md/parse.js +91 -67
  33. package/lib/utils/regex-timeout.js +2 -1
  34. package/lib/utils/regex.js +3 -2
  35. package/lib/utils/remoteRequest.js +1 -0
  36. package/lib/utils/syntax.js +3 -0
  37. package/lib/utils/text.js +71 -3
  38. package/lib/utils/text.test.js +3 -9
  39. package/lib/utils/toc.js +315 -0
  40. package/package.json +7 -3
  41. package/lib/options-parser.js +0 -498
  42. package/lib/options-parser.test.js +0 -1237
  43. package/lib/utils/html-to-json/compat.js +0 -42
  44. package/lib/utils/html-to-json/format.js +0 -64
  45. package/lib/utils/html-to-json/index.js +0 -37
  46. package/lib/utils/html-to-json/lexer.js +0 -345
  47. package/lib/utils/html-to-json/parser.js +0 -146
  48. package/lib/utils/html-to-json/stringify.js +0 -37
  49. package/lib/utils/html-to-json/tags.js +0 -171
@@ -1,13 +1,7 @@
1
1
 
2
- const { optionsParse } = require('./options-parser')
2
+ const { parse } = require('oparser')
3
3
  const { getSyntaxInfo } = require('./utils/syntax')
4
- const {
5
- getFirstCharacter,
6
- getLastCharacter,
7
- getTextBetweenChars,
8
- stripIndent,
9
- findMinIndent
10
- } = require('./utils/text')
4
+ const { getTextBetweenChars, findMinIndent } = require('./utils/text')
11
5
  const { OPEN_WORD, CLOSE_WORD, SYNTAX } = require('./defaults')
12
6
  // Alt parser https://github.com/LesterLyu/fast-formula-parser/blob/master/grammar/lexing.js
13
7
 
@@ -18,7 +12,6 @@ const defaultOptions = {
18
12
  }
19
13
 
20
14
  function parseBlocks(contents, opts = {}) {
21
- const blocks = []
22
15
  const options = Object.assign({}, defaultOptions, opts)
23
16
  const { syntax, open, close } = options
24
17
  if (!open) {
@@ -35,25 +28,41 @@ function parseBlocks(contents, opts = {}) {
35
28
  throw new Error(`Unknown syntax "${syntax}"`)
36
29
  }
37
30
  const [ openComment, closeComment ] = syntaxInfo.pattern
31
+
32
+ const patterns = getBlockRegex({
33
+ openComment,
34
+ closeComment,
35
+ openText: open,
36
+ closeText: close
37
+ })
38
+
39
+ const newerRegex = patterns.blockPattern
40
+ // console.log('newerRegex', newerRegex)
41
+
42
+ /*
38
43
  const regexToUse = getBlockRegex({
39
44
  openComment,
40
45
  closeComment,
41
46
  openText: open,
42
47
  closeText: close
43
48
  })
44
- // console.log('regexToUse', regexToUse)
45
- const paramsRegex = new RegExp(`([\\s\\S]*?)${closeComment}`, 'gm')
46
- //console.log('paramsRegex', paramsRegex)
47
- const trimRegex = new RegExp(`${closeComment}$`)
48
- // ([ \t]*)(?:\/\*(?:.*|\r?|\n?|\s*)XYZ:START\s*([(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)((?:.|\r?\n)*?)\/\*(?:.*|\r?|\n?|\s*)XYZ:END(?:.|\r?\n)*?\*\/
49
-
50
- let openTagRegex = getOpenCommentRegex(open, openComment, closeComment)
51
- let closeTagRegex = getClosingCommentRegex(close, openComment, closeComment)
49
+ console.log('regexToUse', regexToUse)
50
+ */
51
+
52
+ // let openTagRegex = getOpenCommentRegex(open, openComment, closeComment)
53
+ // let closeTagRegex = getClosingCommentRegex(close, openComment, closeComment)
52
54
  // console.log('openTagRegex', openTagRegex)
55
+ // console.log('patterns.openPattern', patterns.openPattern)
53
56
  // console.log('closeTagRegex', closeTagRegex)
54
-
57
+ // console.log('patterns.closePattern', patterns.closePattern)
58
+
55
59
  /* Verify comment blocks aren't broken (redos) */
56
- const { isBalanced, openCount, closeCount } = verifyTagsBalanced(contents, openTagRegex, closeTagRegex)
60
+ const { isBalanced, openCount, closeCount } = verifyTagsBalanced(
61
+ contents,
62
+ patterns.openPattern,
63
+ patterns.closePattern
64
+ )
65
+ // console.log('isBalanced', isBalanced)
57
66
  const balanced = (closeCount > openCount) ? true : isBalanced
58
67
  if (!balanced) {
59
68
  throw new Error(`Blocks are unbalanced.
@@ -61,173 +70,125 @@ function parseBlocks(contents, opts = {}) {
61
70
  ${closeCount} "${close}" close tags.
62
71
  `)
63
72
  }
64
- let index = 0
65
- while ((commentMatches = regexToUse.exec(contents)) !== null) {
66
- index++
67
- let props = {}
73
+
74
+ /* New regex works! */
75
+ const newBlocks = []
76
+ let blockIndex = 0
77
+ let newMatches
78
+ while ((newMatches = newerRegex.exec(contents)) !== null) {
79
+ blockIndex++
68
80
  let paramString = ''
69
- const [ block, spaces, __type, params ] = commentMatches
70
- const isMultiline = block.indexOf('\n') > -1
71
- let context = {
72
- isMultiline,
81
+ let options = {}
82
+ const [ block, spaces, openTag, type, params = '', content, closeTag ] = newMatches
83
+
84
+ let transformType = type
85
+ paramString = params.trim()
86
+
87
+ /* Account for dashes in transform name. E.g. funky-name-here */
88
+ const dashInTransform = params.match(/^(-[^\s]*)/)
89
+ if (dashInTransform && dashInTransform[1]) {
90
+ transformType = type + dashInTransform[1]
91
+ paramString = paramString.replace(dashInTransform[1], '')
73
92
  }
74
- // console.log('commentMatches', commentMatches)
75
- const indentation = spaces || ''
76
- /* Remove trailing -- if no params */
77
- const type = __type.replace(/-*$/, '')
78
93
  /*
79
- console.log('index', commentMatches.index)
94
+ console.log('index', newMatches.index)
80
95
  console.log('block', block)
81
96
  console.log('type', type)
82
97
  console.log('params', params)
83
98
  console.log('spaces', `"${spaces}"`)
84
99
  /** */
100
+ const isMultiline = block.indexOf('\n') > -1
101
+ const indentation = spaces || ''
102
+ let context = {
103
+ isMultiline,
104
+ }
105
+ // console.log('newMatches', newMatches)
85
106
  // This is necessary to avoid infinite loops
86
- if (commentMatches.index === regexToUse.lastIndex) {
87
- regexToUse.lastIndex++
107
+ if (newMatches.index === newerRegex.lastIndex) {
108
+ newerRegex.lastIndex++
88
109
  }
110
+ const openValue = indentation + openTag
111
+ const openStart = newMatches.index + indentation.length
112
+ const openEnd = openStart + openTag.length
89
113
 
90
- openTagRegex = getOpenCommentRegex(open, openComment, closeComment)
91
- // console.log('openTagRegex', openTagRegex)
92
- const openingTag = getOpeningTags(block, {
93
- pattern: openTagRegex,
94
- open: openComment,
95
- close: closeComment
96
- })
97
- closeTagRegex = getClosingCommentRegex(close, openComment, closeComment)
98
- // console.log('closeTagRegex', closeTagRegex)
99
- const closingTag = getClosingTags(block, {
100
- pattern: closeTagRegex
101
- })
102
- /*
103
- console.log('openingTag', openingTag)
104
- console.log('closingTag', closingTag)
105
- /** */
106
- if (!openingTag || !closingTag) {
107
- continue;
108
- }
109
-
110
- const openingTagLength = openingTag.length //+ indentation.length
111
- const contentEndPosition = block.indexOf(closingTag.tag, openingTagLength)
112
- const content = getTextBetweenChars(block, openingTagLength, contentEndPosition)
113
- // console.log('content', content)
114
- let originalContent = content
115
- const contentEndsWithNewLine = getLastCharacter(originalContent) === '\n'
116
- const openEndsWithNewLine = getLastCharacter(openingTag.tag) === '\n'
117
-
118
- const closeTag = (contentEndsWithNewLine) ? `\n${closingTag.tag}` : closingTag.tag
119
-
120
- // Move new line to beginning of closing tag
121
- // if (originalContent.match(/\n$/)) {
122
- if (contentEndsWithNewLine) {
123
- // originalContent = originalContent.replace(/\n$/, '')
124
- originalContent = originalContent.slice(0, -1)
125
- }
126
- /* Strip indentation */
127
- originalContent = stripIndent(originalContent, indentation.length)
128
- // originalContent = originalContent.replace(/^\s+|\s+$/g, '')
129
- /*
130
- console.log('originalContent')
131
- console.log(`"${originalContent}"`)
132
- /** */
133
-
134
- /* strip brackets (functionName) or [functionName] or {functionName} */
135
- const cleanType = stripBrackets(type)
136
- const shift = (openEndsWithNewLine) ? 1 : 0
137
- const lineOpen = contents.substr(0, commentMatches.index).split('\n').length
138
- const lineClose = contents.substr(0, regexToUse.lastIndex).split('\n').length
139
- const contentStart = commentMatches.index + openingTag.tag.length - shift //+ indentation.length
114
+
115
+ const closeEnd = newerRegex.lastIndex
116
+ // const finIndentation = (lineOpen === lineClose) ? '' : indentation
117
+
118
+ const lineOpen = contents.substr(0, openStart).split('\n').length
119
+ const lineClose = contents.substr(0, closeEnd).split('\n').length
120
+
121
+ const contentStart = openStart + openTag.length // + indentation.length// - shift //+ indentation.length
122
+ const contentEnd = contentStart + content.length // + finIndentation.length // + shift
140
123
  /* If single line comment block, remove indentation */
141
124
  const finIndentation = (lineOpen === lineClose) ? '' : indentation
142
- const contentEnd = contentStart + content.length + finIndentation.length + shift
143
125
 
144
- // if (cleanType && !cleanType.match(/^-+/)) {
145
- if (cleanType && getFirstCharacter(cleanType) !== '-') {
146
- // console.log('params', params)
147
- // const paramValue = params.match(/([\s\S]*?)-->/gm)
148
- const paramValue = params.match(paramsRegex)
149
- // console.log('paramValue', paramValue)
150
- if (paramValue) {
151
- // paramString = paramValue[0].replace(/-*>$/, '').trim()
152
- paramString = paramValue[0].replace(trimRegex, '').trim()
153
- // console.log('clean', `${cleanType}`)
154
- // console.log('param', `${paramString}`)
155
- // console.log('type ', `${__type}`)
156
- // console.log('──────────────────────')
157
- // console.log(`${cleanType} "${paramString}" "${__type}"`)
158
- if (paramString) {
159
- // console.log('paramString', `"${paramString}"`)
160
- // Legacy v1 options parser
161
- if (getFirstCharacter(paramString) === ':' || getFirstCharacter(paramString) === '?') {
162
- context.isLegacy = true
163
- // paramString = paramString.replace(/\s?\)\s*$/, '').substring(1)
164
- paramString = paramString.split(')')[0].substring(1)
165
- // console.log('fixed paramString', paramString)
166
- props = legacyParseOptions(paramString)
167
- } else {
168
- if (type.startsWith('(') && paramString.endsWith(')')) {
169
- paramString = paramString.replace(/\)$/, '')
170
- }
171
- props = optionsParse(paramString)
172
-
173
- }
174
- } else if (!paramString && __type.match(/^\(.*\)$/)) {
175
- context.isLegacy = true
176
- }
177
- }
178
- /*
179
- console.log(regexToUse)
180
- console.log(`cleanType "${cleanType}" at ${regexToUse.lastIndex} using props:`)
181
- console.log(props)
182
- console.log('───────────────────────')
183
- /** */
126
+ /* If old syntax XYZ?foo | XYZ:foo */
127
+ if (paramString.match(/^:|^\?/)) {
128
+ paramString = paramString.split(')')[0]
129
+ paramString = paramString.replace(/^:/, '').replace(/^\?/, '').replace(/\)$/g, '')
130
+ // console.log('paramString', `"${paramString}"`)
131
+ options = legacyParseOptions(paramString)
132
+ context.isLegacy = true
133
+ } else {
134
+ // console.log('paramString', paramString)
135
+ options = parse(paramString)
184
136
  }
185
137
 
186
- /* Add found block */
187
- blocks.push({
188
- index: index,
189
- type: cleanType,
190
- options: props,
138
+ // console.log('open start', openStart)
139
+ // console.log('openEnd', openEnd)
140
+ // console.log('options', options)
141
+
142
+ const blockData = {
143
+ index: blockIndex,
144
+ type: transformType,
145
+ options,
191
146
  context,
192
147
  /* Open Tag */
193
148
  open: {
194
- value: openingTag.tag,
195
- start: commentMatches.index,
196
- end: contentStart
149
+ value: openValue,
150
+ start: openStart,
151
+ end: openEnd
197
152
  },
198
153
  /* Inner Content */
199
154
  content: {
200
- value: originalContent,
155
+ value: content,
201
156
  start: contentStart,
202
157
  end: contentEnd,
203
- indentation: findMinIndent(originalContent),
158
+ indentation: findMinIndent(content),
204
159
  },
205
160
  /* Close Tag */
206
161
  close: {
207
162
  value: closeTag,
208
163
  start: contentEnd,
209
- end: regexToUse.lastIndex
164
+ end: closeEnd
210
165
  },
211
166
  /* Full Block */
212
167
  block: {
213
168
  indentation: finIndentation,
214
169
  lines: [lineOpen, lineClose],
215
- start: commentMatches.index,
216
- end: regexToUse.lastIndex,
170
+ start: openStart,
171
+ end: closeEnd,
217
172
  // position: [ commentMatches.index, regexToUse.lastIndex ],
218
- rawType: (context.isLegacy) ? type.replace(/^\s?\(/, '') : type,
173
+ // rawType: (context.isLegacy) ? type.replace(/^\s?\(/, '') : type,
219
174
  rawArgs: paramString,
220
175
  rawContent: getTextBetweenChars(contents, contentStart, contentEnd),
221
176
  value: block,
222
177
  },
223
- })
178
+ }
179
+ // console.log('blockData', blockData)
180
+ newBlocks.push(blockData)
224
181
  }
182
+
225
183
  return {
226
184
  // Close but no single line newPattern: newGetBlockRegex({ openComment, commentClose, start: START, ending: END }),
227
- pattern: regexToUse,
228
- COMMENT_OPEN_REGEX: openTagRegex,
229
- COMMENT_CLOSE_REGEX: closeTagRegex,
230
- blocks
185
+ // pattern: regexToUse,
186
+ pattern: newerRegex,
187
+ // COMMENT_OPEN_REGEX: openTagRegex,
188
+ // COMMENT_CLOSE_REGEX: closeTagRegex,
189
+ COMMENT_OPEN_REGEX: patterns.openPattern,
190
+ COMMENT_CLOSE_REGEX: patterns.closePattern,
191
+ blocks: newBlocks
231
192
  }
232
193
  }
233
194
 
@@ -241,124 +202,6 @@ function verifyTagsBalanced(str, open, close) {
241
202
  }
242
203
  }
243
204
 
244
- function getOpeningTags(block, {
245
- pattern,
246
- open,
247
- close
248
- }) {
249
- // console.log(block.match(/^\/\*+(.*)\*\//))
250
- // console.log('openTagRegex', pattern)
251
- let matches
252
- while ((matches = pattern.exec(block)) !== null) {
253
- if (matches.index === pattern.lastIndex) {
254
- pattern.lastIndex++ // avoid infinite loops with zero-width matches
255
- }
256
- const [ tag, spaces, tagStart, tagEnd ] = matches
257
- /*
258
- console.log('FULL Open Tag >>>>>', tag)
259
- console.log('openTag Start', "'"+tagStart+"'");
260
- console.log('openTag End', "'"+tagEnd+"'");
261
- /**/
262
- return {
263
- tag,
264
- spaces: spaces || '',
265
- length: tag.length,
266
- tagStart,
267
- tagEnd,
268
- }
269
- }
270
- // // Fallthrough
271
- // // const fallbackRegex = new RegExp(`^([ \\t]*)(${open}([\\s\\S]*?)${close})\\n?`)
272
- // const fallbackRegex = new RegExp(`^([ \\t]*)(\\b${open}\\b([\\s\\S]*?)${close})\\n?`)
273
- // // const xyz = block.match(/^([ \t]*)(\/\*+([\s\S]*?)\*+\/)/)
274
- // const fallbackMatch= block.match(fallbackRegex)
275
- // if (fallbackMatch) {
276
- // /*
277
- // console.log('fallbackRegex', fallbackRegex)
278
- // console.log('fall through', `"${block}"`)
279
- // console.log('xyz', xyz)
280
- // /** */
281
- // return {
282
- // fallthrough: true,
283
- // tag: fallbackMatch[0],
284
- // spaces: fallbackMatch[1] || '',
285
- // length: fallbackMatch[0].length,
286
- // }
287
- // }
288
- }
289
-
290
- function getClosingTags(block, {
291
- pattern,
292
- // open,
293
- // close
294
- }) {
295
- // console.log('closeTagRegex', closeTagRegex)
296
- let matches
297
- while ((matches = pattern.exec(block)) !== null) {
298
- if (matches.index === pattern.lastIndex) {
299
- pattern.lastIndex++ // avoid infinite loops with zero-width matches
300
- }
301
- const [ _tag, spaces, tagStart, tagEnd] = matches
302
- /*
303
- console.log('FULL CLOSE Tag >>>>>', matches[0])
304
- console.log('closeTag Start', "'"+matches[1]+"'");
305
- console.log('closeTag End', "'"+matches[2]+"'");
306
- /**/
307
- const tag = spaces + tagStart + tagEnd
308
- return {
309
- tag: tag,
310
- length: tag.length,
311
- spaces: spaces || '',
312
- tagStart,
313
- tagEnd
314
- }
315
- }
316
- }
317
-
318
-
319
- const EMOJI = '\\u00a9|\\u00ae|[\\u2000-\\u3300]|\\ud83c[\\ud000-\\udfff]|\\ud83d[\\ud000-\\udfff]|\\ud83e[\\ud000-\\udfff]'
320
-
321
- /**
322
- * Get Regex pattern to match block
323
- * @param {object} options
324
- * @param {string} [options.openComment] - comment syntax open
325
- * @param {string} [options.closeComment] - comment syntax open
326
- * @param {string} [options.openText] - comment open text
327
- * @param {string} [options.closeText] - comment close text
328
- * @returns {RegExp}
329
- */
330
- function getBlockRegex({ openComment, closeComment, openText, closeText }) {
331
- return new RegExp(
332
- `([ \\t]*)(?:${openComment}(?:.*|\\r?|\\n?|\\s*)${openText}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.*?|.*?\\r?\\n?)*?)${openComment}(?:.*|\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment}`,
333
- 'gmi'
334
- )
335
- }
336
-
337
- /* // Named matches
338
- (?<leading>[ \t]*)(?:<!-{2,}(?:.*|\r?|\n?|\s*)MD-MAGIC-EXAMPLE:START\s*(?<key>[(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)([\s\S]*?)-->(?<content>(?:.*?|.*?\r?\n?)*?)<!-{2,}(?:.*|\r?|\n?|\s*)MD-MAGIC-EXAMPLE:END(?:.|\r?\n)*?-{2,}>
339
- */
340
- function newGetBlockRegex({ commentOpen, commentClose, start, ending }) {
341
- // https://regex101.com/r/C9WSk8/1 close but breaks on single line blocks. Maybe needs lookahead https://stackoverflow.com/questions/7124778/how-can-i-match-anything-up-until-this-sequence-of-characters-in-a-regular-exp
342
- return new RegExp(
343
- `([ \\t]*)(?:${commentOpen}(?:.*|\\r?|\\n?|\\s*)${start}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)([\\s\\S]*?)${commentClose}((?:.*?|.*?\\r?\\n?)*?)${commentOpen}(?:.*|\\r?|\\n?|\\s*)${ending}(?:.|\\r?\\n)*?${commentClose}`,
344
- 'gmi'
345
- )
346
- }
347
-
348
- function getOpenCommentRegex(word, open, close) {
349
- // console.log('open', open)
350
- const boundary = word.indexOf('/') > -1 ? '' : '\\b'
351
- // console.log('boundary', boundary)
352
- // return new RegExp(`(\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
353
- return new RegExp(`([ \\t]*)(${open}(?:.|\r?|\n?|\\s*)${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close}\n?)`, 'gi')
354
- }
355
-
356
- function getClosingCommentRegex(word, open, close) {
357
- const boundary = word.indexOf('/') > -1 ? '' : '\\b'
358
- return new RegExp(`${close}(?:.|\\r?\\n)*?([ \t]*)((?:${open}(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close})`, 'gi')
359
- // return new RegExp(`--\\>(?:.|\\r?\\n)*?([ \t]*)((?:\\<\\!--(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${word}:END)((?:.|\\r?\\n)*?--\\>)`, 'gi')
360
- }
361
-
362
205
  /**
363
206
  * Strip brackets from string (functionName) or [functionName] or {functionName}
364
207
  * @param {string} str
@@ -383,6 +226,156 @@ function legacyParseOptions(options) {
383
226
  }
384
227
 
385
228
 
229
+ /* TODO someday Named matches
230
+ (?<leading>[ \t]*)(?:<!-{2,}(?:.*|\r?|\n?|\s*)MD-MAGIC-EXAMPLE:START\s*(?<key>[(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)([\s\S]*?)-->(?<content>(?:.*?|.*?\r?\n?)*?)<!-{2,}(?:.*|\r?|\n?|\s*)MD-MAGIC-EXAMPLE:END(?:.|\r?\n)*?-{2,}>
231
+ */
232
+
233
+ /**
234
+ * Block matching patterns
235
+ * @typedef {{blockPattern: RegExp, openPattern: RegExp, closePattern: RegExp}} RegexPatterns
236
+ */
237
+
238
+ /**
239
+ * Get Regex pattern to match block
240
+ * @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
244
+ * @param {string} [options.openText] - comment open text
245
+ * @param {string} [options.closeText] - comment close text
246
+ * @param {boolean} [options.allowMissingTransforms] - Allow for missing transform key
247
+ * @returns {RegexPatterns}
248
+ */
249
+ function getBlockRegex({
250
+ openEmoji,
251
+ openComment,
252
+ closeComment,
253
+ openText = '',
254
+ closeText = '',
255
+ allowMissingTransforms = false
256
+ }) {
257
+ // https://regex101.com/r/SU2g1Q/1
258
+ // https://regex101.com/r/SU2g1Q/2
259
+ // https://regex101.com/r/SU2g1Q/3
260
+ // https://regex101.com/r/SU2g1Q/4
261
+ // https://regex101.com/r/SU2g1Q/5
262
+ // https://regex101.com/r/SU2g1Q/6
263
+ // /([ \t]*)(<!-{2,}(?:.|\r?|\n?|\s*)\bdoc-gen\b)((?:.|\r?\n)*?)-{2,}>([\s\S]*?.*)\n?<!-{2,}(?:.*|\r?|\n?|\s*)end-doc-gen(?:.|\r?\n)*?-{2,}>/gim
264
+ // /([ \t]*)(<!-{2,}(?:\r?|\n?|\s*)\bdoc-gen\b)\s*([(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*((?:.|\r?\n)*?)-{2,}>([\s\S]*?.*)\n?<!-{2,}(?:.*|\r?|\n?|\s*)end-doc-gen(?:.|\r?\n)*?-{2,}>/
265
+ const emojiPat = (openEmoji) ? `(?:\\s*${openEmoji})?` : '(?:\\s*⛔️)?'
266
+ const boundary = openText.indexOf('/') > -1 ? '' : '\\b'
267
+ const matchWord = `${boundary}${openText}${boundary}`
268
+ const hasOne = (allowMissingTransforms) ? '*' : '+'
269
+ const open = `((?:${openComment}${emojiPat}(?:\\r?|\\n?|\\s*)${matchWord})\\s*[(\\[\\{]*([A-Za-z0-9_$]${hasOne})[)\\]\\}]*\\s*((?:.|\\r?\\n)*?)${closeComment}\\n?)`
270
+ const close = `(\\n?[ \\t]*${openComment}${emojiPat}(?:\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment})`
271
+ // const close = `(\\n?${openComment}(?:.*|\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment})`
272
+ const blockPattern = new RegExp(`([ \\t]*)${open}([\\s\\S]*?.*)${close}`, 'gmi')
273
+ const openPattern = new RegExp(open, 'gi')
274
+ const closePattern = new RegExp(close, 'gi')
275
+
276
+ return {
277
+ blockPattern,
278
+ openPattern,
279
+ closePattern
280
+ }
281
+ }
282
+
283
+ // function getOpeningTags(block, {
284
+ // pattern,
285
+ // open,
286
+ // close
287
+ // }) {
288
+ // // console.log(block.match(/^\/\*+(.*)\*\//))
289
+ // // console.log('openTagRegex', pattern)
290
+ // let matches
291
+ // while ((matches = pattern.exec(block)) !== null) {
292
+ // if (matches.index === pattern.lastIndex) {
293
+ // pattern.lastIndex++ // avoid infinite loops with zero-width matches
294
+ // }
295
+ // const [ tag, spaces, tagStart, tagEnd ] = matches
296
+ // /*
297
+ // console.log('FULL Open Tag >>>>>', tag)
298
+ // console.log('openTag Start', "'"+tagStart+"'");
299
+ // console.log('openTag End', "'"+tagEnd+"'");
300
+ // /**/
301
+ // return {
302
+ // tag,
303
+ // spaces: spaces || '',
304
+ // length: tag.length,
305
+ // tagStart,
306
+ // tagEnd,
307
+ // }
308
+ // }
309
+ // }
310
+
311
+ // function getClosingTags(block, {
312
+ // pattern,
313
+ // // open,
314
+ // // close
315
+ // }) {
316
+ // // console.log('closeTagRegex', closeTagRegex)
317
+ // let matches
318
+ // while ((matches = pattern.exec(block)) !== null) {
319
+ // if (matches.index === pattern.lastIndex) {
320
+ // pattern.lastIndex++ // avoid infinite loops with zero-width matches
321
+ // }
322
+ // const [ _tag, spaces, tagStart, tagEnd] = matches
323
+ // /*
324
+ // console.log('FULL CLOSE Tag >>>>>', matches[0])
325
+ // console.log('closeTag Start', "'"+matches[1]+"'");
326
+ // console.log('closeTag End', "'"+matches[2]+"'");
327
+ // /**/
328
+ // const tag = spaces + tagStart + tagEnd
329
+ // return {
330
+ // tag: tag,
331
+ // length: tag.length,
332
+ // spaces: spaces || '',
333
+ // tagStart,
334
+ // tagEnd
335
+ // }
336
+ // }
337
+ // }
338
+
339
+ // /**
340
+ // * Get Regex pattern to match block
341
+ // * @param {object} options
342
+ // * @param {string} [options.openComment] - comment syntax open
343
+ // * @param {string} [options.closeComment] - comment syntax open
344
+ // * @param {string} [options.openText] - comment open text
345
+ // * @param {string} [options.closeText] - comment close text
346
+ // * @returns {RegExp}
347
+ // */
348
+ // function getBlockRegexOld({ openComment, closeComment, openText, closeText }) {
349
+ // // /([ \t]*)(<!-{2,}(?:.|\r?|\n?|\s*)\bdoc-gen\b)((?:.|\r?\n)*?)-{2,}>(.*)<!-{2,}(?:.*|\r?|\n?|\s*)end-doc-gen(?:.|\r?\n)*?-{2,}>/i singleline
350
+ // return new RegExp(
351
+ // `([ \\t]*)(?:${openComment}(?:.*|\\r?|\\n?|\\s*)${openText}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.*?|.*?\\r?\\n?)*?)${openComment}(?:.*|\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment}`,
352
+ // 'gmi'
353
+ // )
354
+ // }
355
+
356
+
357
+ // function newGetBlockRegex({ commentOpen, commentClose, start, ending }) {
358
+ // // https://regex101.com/r/C9WSk8/1 close but breaks on single line blocks. Maybe needs lookahead https://stackoverflow.com/questions/7124778/how-can-i-match-anything-up-until-this-sequence-of-characters-in-a-regular-exp
359
+ // return new RegExp(
360
+ // `([ \\t]*)(?:${commentOpen}(?:.*|\\r?|\\n?|\\s*)${start}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)([\\s\\S]*?)${commentClose}((?:.*?|.*?\\r?\\n?)*?)${commentOpen}(?:.*|\\r?|\\n?|\\s*)${ending}(?:.|\\r?\\n)*?${commentClose}`,
361
+ // 'gmi'
362
+ // )
363
+ // }
364
+
365
+ // function getOpenCommentRegex(word, open, close) {
366
+ // // console.log('open', open)
367
+ // const boundary = word.indexOf('/') > -1 ? '' : '\\b'
368
+ // // console.log('boundary', boundary)
369
+ // // return new RegExp(`(\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
370
+ // return new RegExp(`([ \\t]*)(${open}(?:.|\r?|\n?|\\s*)${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close}\n?)`, 'gi')
371
+ // }
372
+
373
+ // function getClosingCommentRegex(word, open, close) {
374
+ // const boundary = word.indexOf('/') > -1 ? '' : '\\b'
375
+ // return new RegExp(`${close}(?:.|\\r?\\n)*?([ \t]*)((?:${open}(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close})`, 'gi')
376
+ // // return new RegExp(`--\\>(?:.|\\r?\\n)*?([ \t]*)((?:\\<\\!--(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${word}:END)((?:.|\\r?\\n)*?--\\>)`, 'gi')
377
+ // }
378
+
386
379
  module.exports = {
387
380
  getBlockRegex,
388
381
  parseBlocks,