markdown-magic 3.7.0 → 4.0.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.
@@ -1,171 +0,0 @@
1
- const path = require('path')
2
- const fs = require('fs').promises
3
- const { test } = require('uvu')
4
- const assert = require('uvu/assert')
5
- const { parseBlocks } = require('./block-parser')
6
- const { deepLog } = require('./utils/logs')
7
-
8
- test('JS file parse', async () => {
9
- const contents = await fs.readFile(path.join(__dirname, '../test/fixtures/js/simple.js'), 'utf-8')
10
- const blocks = parseBlocks(contents, {
11
- syntax: 'js',
12
- open: 'GENERATED',
13
- close: 'END-GENERATED',
14
- })
15
- /*
16
- deepLog(blocks.blocks)
17
- /** */
18
- assert.equal(blocks.blocks, [
19
- {
20
- index: 1,
21
- type: 'a',
22
- options: {},
23
- context: { isMultiline: true },
24
- open: { value: '/* ⛔️ GENERATED a */\n', start: 96, end: 117 },
25
- content: {
26
- value: '// comment inside',
27
- start: 117,
28
- end: 134,
29
- indentation: 0
30
- },
31
- close: { value: '\n/* END-GENERATED */', start: 134, end: 154 },
32
- block: {
33
- indentation: '',
34
- lines: [ 7, 9 ],
35
- start: 96,
36
- end: 154,
37
- rawArgs: '',
38
- rawContent: '// comment inside',
39
- value: '/* ⛔️ GENERATED a */\n// comment inside\n/* END-GENERATED */'
40
- }
41
- },
42
- {
43
- index: 2,
44
- type: 'b',
45
- options: {},
46
- context: { isMultiline: true },
47
- open: { value: '/* GENERATED b */\n', start: 156, end: 174 },
48
- content: {
49
- value: '/* comment inside */',
50
- start: 174,
51
- end: 194,
52
- indentation: 0
53
- },
54
- close: { value: '\n/* END-GENERATED */', start: 194, end: 214 },
55
- block: {
56
- indentation: '',
57
- lines: [ 11, 13 ],
58
- start: 156,
59
- end: 214,
60
- rawArgs: '',
61
- rawContent: '/* comment inside */',
62
- value: '/* GENERATED b */\n/* comment inside */\n/* END-GENERATED */'
63
- }
64
- },
65
- {
66
- index: 3,
67
- type: 'c',
68
- options: {},
69
- context: { isMultiline: true },
70
- open: { value: '/* GENERATED c */\n', start: 216, end: 234 },
71
- content: {
72
- value: '/* \n comment inside \n*/',
73
- start: 234,
74
- end: 258,
75
- indentation: 0
76
- },
77
- close: { value: '\n/* END-GENERATED */', start: 258, end: 278 },
78
- block: {
79
- indentation: '',
80
- lines: [ 15, 19 ],
81
- start: 216,
82
- end: 278,
83
- rawArgs: '',
84
- rawContent: '/* \n comment inside \n*/',
85
- value: '/* GENERATED c */\n/* \n comment inside \n*/\n/* END-GENERATED */'
86
- }
87
- },
88
- {
89
- index: 4,
90
- type: 'd',
91
- options: {},
92
- context: { isMultiline: true },
93
- open: { value: '/* GENERATED d */\n', start: 280, end: 298 },
94
- content: {
95
- value: '/**\n * comment inside \n */',
96
- start: 298,
97
- end: 324,
98
- indentation: 0
99
- },
100
- close: { value: '\n/* END-GENERATED */', start: 324, end: 344 },
101
- block: {
102
- indentation: '',
103
- lines: [ 21, 25 ],
104
- start: 280,
105
- end: 344,
106
- rawArgs: '',
107
- rawContent: '/**\n * comment inside \n */',
108
- value: '/* GENERATED d */\n/**\n * comment inside \n */\n/* END-GENERATED */'
109
- }
110
- },
111
- {
112
- index: 5,
113
- type: 'e',
114
- options: {},
115
- context: { isMultiline: true },
116
- open: { value: '/* GENERATED e */\n', start: 346, end: 364 },
117
- content: {
118
- value: '/****************\n comment inside \n******************/',
119
- start: 364,
120
- end: 418,
121
- indentation: 0
122
- },
123
- close: { value: '\n/* END-GENERATED */', start: 418, end: 438 },
124
- block: {
125
- indentation: '',
126
- lines: [ 27, 31 ],
127
- start: 346,
128
- end: 438,
129
- rawArgs: '',
130
- rawContent: '/****************\n comment inside \n******************/',
131
- value: '/* GENERATED e */\n' +
132
- '/****************\n' +
133
- ' comment inside \n' +
134
- '******************/\n' +
135
- '/* END-GENERATED */'
136
- }
137
- },
138
- {
139
- index: 6,
140
- type: 'MyCodeGen',
141
- options: { yay: 'nice' },
142
- context: { isMultiline: true },
143
- open: {
144
- value: "/* GENERATED MyCodeGen yay='nice' */\n",
145
- start: 455,
146
- end: 492
147
- },
148
- content: {
149
- value: "/* Awesome */\nconsole.log('noooo')",
150
- start: 492,
151
- end: 526,
152
- indentation: 0
153
- },
154
- close: { value: '\n/* END-GENERATED */', start: 526, end: 546 },
155
- block: {
156
- indentation: '',
157
- lines: [ 35, 38 ],
158
- start: 455,
159
- end: 546,
160
- rawArgs: "yay='nice'",
161
- rawContent: "/* Awesome */\nconsole.log('noooo')",
162
- value: "/* GENERATED MyCodeGen yay='nice' */\n" +
163
- '/* Awesome */\n' +
164
- "console.log('noooo')\n" +
165
- '/* END-GENERATED */'
166
- }
167
- }
168
- ])
169
- })
170
-
171
- test.run()
@@ -1,405 +0,0 @@
1
-
2
- const { parse } = require('oparser')
3
- const { getSyntaxInfo } = require('./utils/syntax')
4
- const { getTextBetweenChars, findMinIndent } = require('./utils/text')
5
- const { OPEN_WORD, CLOSE_WORD, SYNTAX } = require('./defaults')
6
- // Alt parser https://github.com/LesterLyu/fast-formula-parser/blob/master/grammar/lexing.js
7
-
8
- const defaultOptions = {
9
- syntax: SYNTAX,
10
- open: OPEN_WORD,
11
- close: CLOSE_WORD,
12
- }
13
-
14
- function parseBlocks(contents, opts = {}) {
15
- const _options = Object.assign({}, defaultOptions, opts)
16
- const { syntax, open, close } = _options
17
-
18
- const patterns = getBlockRegex({
19
- syntax,
20
- openText: open,
21
- closeText: close
22
- })
23
-
24
- // console.log(patterns)
25
-
26
- const newerRegex = patterns.blockPattern
27
- /*
28
- console.log('newerRegex', newerRegex)
29
- console.log('open', patterns.openPattern)
30
- console.log('close', patterns.closePattern)
31
- /** */
32
-
33
- /*
34
- const regexToUse = getBlockRegex({
35
- openComment,
36
- closeComment,
37
- openText: open,
38
- closeText: close
39
- })
40
- console.log('regexToUse', regexToUse)
41
- */
42
-
43
- // let openTagRegex = getOpenCommentRegex(open, openComment, closeComment)
44
- // let closeTagRegex = getClosingCommentRegex(close, openComment, closeComment)
45
- // console.log('openTagRegex', openTagRegex)
46
- // console.log('patterns.openPattern', patterns.openPattern)
47
- // console.log('closeTagRegex', closeTagRegex)
48
- // console.log('patterns.closePattern', patterns.closePattern)
49
-
50
- /* Verify comment blocks aren't broken (redos) */
51
- const { isBalanced, openCount, closeCount } = verifyTagsBalanced(
52
- contents,
53
- patterns.openPattern,
54
- patterns.closePattern
55
- )
56
- /*
57
- console.log('isBalanced', isBalanced)
58
- /** */
59
-
60
- const balanced = (closeCount > openCount) ? true : isBalanced
61
- if (!balanced) {
62
- throw new Error(`[Parsing error]
63
-
64
- Comment blocks are unbalanced in string
65
-
66
- Details:
67
- - Found ${openCount} "${open}" open tags.
68
- - Found ${closeCount} "${close}" close tags.\n\n`)
69
- }
70
-
71
- /* New regex works! */
72
- const newBlocks = []
73
- let blockIndex = 0
74
- let newMatches
75
- while ((newMatches = newerRegex.exec(contents)) !== null) {
76
- blockIndex++
77
- let paramString = ''
78
- let options = {}
79
- const [ block, spaces, openTag, type, params = '', content, closeTag ] = newMatches
80
-
81
- let transformType = type
82
- paramString = params.trim()
83
-
84
- /* Account for dashes in transform name. E.g. funky-name-here */
85
- const dashInTransform = params.match(/^(-[^\s]*)/)
86
- if (dashInTransform && dashInTransform[1]) {
87
- transformType = type + dashInTransform[1]
88
- paramString = paramString.replace(dashInTransform[1], '')
89
- }
90
- /*
91
- console.log('index', newMatches.index)
92
- console.log('block', block)
93
- console.log('type', type)
94
- console.log('params', params)
95
- console.log('spaces', `"${spaces}"`)
96
- /** */
97
- const isMultiline = block.indexOf('\n') > -1
98
- const indentation = spaces || ''
99
- // console.log('indentation', `"${indentation}"`)
100
- let context = {
101
- isMultiline,
102
- }
103
- // console.log('newMatches', newMatches)
104
- // This is necessary to avoid infinite loops
105
- if (newMatches.index === newerRegex.lastIndex) {
106
- newerRegex.lastIndex++
107
- }
108
- const openValue = indentation + openTag
109
- const openStart = newMatches.index + indentation.length
110
- const openEnd = openStart + openTag.length
111
-
112
-
113
- const closeEnd = newerRegex.lastIndex
114
- // const finIndentation = (lineOpen === lineClose) ? '' : indentation
115
-
116
- const lineOpen = contents.substr(0, openStart).split('\n').length
117
- const lineClose = contents.substr(0, closeEnd).split('\n').length
118
-
119
- const contentStart = openStart + openTag.length // + indentation.length// - shift //+ indentation.length
120
- const contentEnd = contentStart + content.length // + finIndentation.length // + shift
121
- /* If single line comment block, remove indentation */
122
- const finIndentation = (lineOpen === lineClose) ? '' : indentation
123
-
124
- /* If old syntax XYZ?foo | XYZ:foo */
125
- if (paramString.match(/^:|^\?/)) {
126
- paramString = paramString.split(')')[0]
127
- paramString = paramString.replace(/^:/, '').replace(/^\?/, '').replace(/\)$/g, '')
128
- // console.log('paramString', `"${paramString}"`)
129
- options = legacyParseOptions(paramString)
130
- context.isLegacy = true
131
- } else {
132
- if (paramString[0] === '(' && paramString[paramString.length - 1] === ')') {
133
- paramString = paramString.replace(/^\(/, '').replace(/\)$/g, '')
134
- }
135
- options = parse(paramString)
136
- }
137
-
138
- // console.log('open start', openStart)
139
- // console.log('openEnd', openEnd)
140
- // console.log('options', options)
141
-
142
- // context.hasNoBlankLine = content.indexOf('\n') === -1
143
-
144
- const blockData = {
145
- index: blockIndex,
146
- type: transformType,
147
- options,
148
- context,
149
- /* Open Tag */
150
- open: {
151
- value: openValue,
152
- start: openStart,
153
- end: openEnd
154
- },
155
- /* Inner Content */
156
- content: {
157
- value: content,
158
- start: contentStart,
159
- end: contentEnd,
160
- indentation: findMinIndent(content),
161
- },
162
- /* Close Tag */
163
- close: {
164
- value: closeTag,
165
- start: contentEnd,
166
- end: closeEnd
167
- },
168
- /* Full Block */
169
- block: {
170
- indentation: finIndentation,
171
- lines: [lineOpen, lineClose],
172
- start: openStart,
173
- end: closeEnd,
174
- // position: [ commentMatches.index, regexToUse.lastIndex ],
175
- // rawType: (context.isLegacy) ? type.replace(/^\s?\(/, '') : type,
176
- rawArgs: paramString,
177
- rawContent: getTextBetweenChars(contents, contentStart, contentEnd),
178
- value: block,
179
- },
180
- }
181
- // console.log('blockData', blockData)
182
- newBlocks.push(blockData)
183
- }
184
-
185
- // console.log("NEW BLOCKS", newBlocks)
186
- // process.exit(1)
187
- return {
188
- // Close but no single line newPattern: newGetBlockRegex({ openComment, commentClose, start: START, ending: END }),
189
- // pattern: regexToUse,
190
- pattern: newerRegex,
191
- // COMMENT_OPEN_REGEX: openTagRegex,
192
- // COMMENT_CLOSE_REGEX: closeTagRegex,
193
- COMMENT_OPEN_REGEX: patterns.openPattern,
194
- COMMENT_CLOSE_REGEX: patterns.closePattern,
195
- blocks: newBlocks
196
- }
197
- }
198
-
199
- function verifyTagsBalanced(str, open, close) {
200
- const openCount = (str.match(open) || []).length
201
- // console.log('openCount', openCount)
202
- const closeCount = (str.match(close) || []).length
203
- // console.log('closeCount', closeCount)
204
- return {
205
- isBalanced: openCount === closeCount,
206
- openCount,
207
- closeCount
208
- }
209
- }
210
-
211
- /**
212
- * Strip brackets from string (functionName) or [functionName] or {functionName}
213
- * @param {string} str
214
- * @returns {string}
215
- */
216
- function stripBrackets(str) {
217
- return str.replace(/[(\[\{]*([A-Z-a-z0-9_$-]*)[)\]\}]*/, '$1')
218
- }
219
-
220
- function legacyParseOptions(options) {
221
- const returnOptions = {}
222
- if (!options) {
223
- return returnOptions
224
- }
225
- options.split('&').map((opt, i) => { // eslint-disable-line
226
- const getValues = opt.split(/=(.+)/)
227
- if (getValues[0] && getValues[1]) {
228
- returnOptions[getValues[0]] = getValues[1]
229
- }
230
- })
231
- return returnOptions
232
- }
233
-
234
-
235
- /* TODO someday Named matches
236
- (?<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,}>
237
- */
238
-
239
- /**
240
- * Block matching patterns
241
- * @typedef {{blockPattern: RegExp, openPattern: RegExp, closePattern: RegExp}} RegexPatterns
242
- */
243
-
244
- /**
245
- * Get Regex pattern to match block
246
- * @param {object} options
247
- * @param {string} [options.syntax] - comment open text
248
- * @param {string} [options.openText] - comment open text
249
- * @param {string} [options.openEmoji] - emoji
250
- * @param {string} [options.closeText] - comment close text
251
- * @param {boolean} [options.allowMissingTransforms] - Allow for missing transform key
252
- * @returns {RegexPatterns}
253
- */
254
- function getBlockRegex({
255
- openEmoji,
256
- syntax = SYNTAX,
257
- openText = '',
258
- closeText = '',
259
- allowMissingTransforms = false
260
- }) {
261
- if (!openText) {
262
- throw new Error('Missing options.open')
263
- }
264
- if (!closeText) {
265
- throw new Error('Missing options.close')
266
- }
267
- if (!syntax) {
268
- throw new Error('Missing options.syntax')
269
- }
270
-
271
- const syntaxInfo = getSyntaxInfo(syntax)
272
- if (!syntaxInfo.pattern) {
273
- throw new Error(`Unknown syntax "${syntax}"`)
274
- }
275
-
276
- const [ openComment, closeComment ] = syntaxInfo.pattern
277
- // https://regex101.com/r/SU2g1Q/1
278
- // https://regex101.com/r/SU2g1Q/2
279
- // https://regex101.com/r/SU2g1Q/3
280
- // https://regex101.com/r/SU2g1Q/4
281
- // https://regex101.com/r/SU2g1Q/5
282
- // https://regex101.com/r/SU2g1Q/6
283
- // /([ \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
284
- // /([ \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,}>/
285
- const emojiPat = (openEmoji) ? `(?:\\s*${openEmoji})?` : '(?:\\s*⛔️)?'
286
- const boundary = openText.indexOf('/') > -1 ? '' : '\\b'
287
- const matchWord = `${boundary}${openText}${boundary}`
288
- const hasOne = (allowMissingTransforms) ? '*' : '+'
289
- const open = `((?:${openComment}${emojiPat}(?:\\r?|\\n?|\\s*)${matchWord})\\s*[(\\[\\{]*([A-Za-z0-9_$]${hasOne})[)\\]\\}]*\\s*((?:.|\\r?\\n)*?)${closeComment}\\n?)`
290
- // const close = `(\\n?[ \\t]?${openComment}${emojiPat}(?:\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment})`
291
- const close = `(\\n?[ \\t]*${openComment}${emojiPat}(?:\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment})`
292
- // const close = `(\\n?${openComment}(?:.*|\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment})`
293
- const blockPattern = new RegExp(`([ \\t]*)${open}([\\s\\S]*?)${close}`, 'gmi')
294
- // 👇 repeat error with .* on weird contents
295
- // const blockPattern = new RegExp(`([ \\t]*)${open}([\\s\\S]*?.*)${close}`, 'gmi')
296
- const openPattern = new RegExp(open, 'gi')
297
- const closePattern = new RegExp(close, 'gi')
298
-
299
- return {
300
- blockPattern,
301
- openPattern,
302
- closePattern
303
- }
304
- }
305
-
306
- // function getOpeningTags(block, {
307
- // pattern,
308
- // open,
309
- // close
310
- // }) {
311
- // // console.log(block.match(/^\/\*+(.*)\*\//))
312
- // // console.log('openTagRegex', pattern)
313
- // let matches
314
- // while ((matches = pattern.exec(block)) !== null) {
315
- // if (matches.index === pattern.lastIndex) {
316
- // pattern.lastIndex++ // avoid infinite loops with zero-width matches
317
- // }
318
- // const [ tag, spaces, tagStart, tagEnd ] = matches
319
- // /*
320
- // console.log('FULL Open Tag >>>>>', tag)
321
- // console.log('openTag Start', "'"+tagStart+"'");
322
- // console.log('openTag End', "'"+tagEnd+"'");
323
- // /**/
324
- // return {
325
- // tag,
326
- // spaces: spaces || '',
327
- // length: tag.length,
328
- // tagStart,
329
- // tagEnd,
330
- // }
331
- // }
332
- // }
333
-
334
- // function getClosingTags(block, {
335
- // pattern,
336
- // // open,
337
- // // close
338
- // }) {
339
- // // console.log('closeTagRegex', closeTagRegex)
340
- // let matches
341
- // while ((matches = pattern.exec(block)) !== null) {
342
- // if (matches.index === pattern.lastIndex) {
343
- // pattern.lastIndex++ // avoid infinite loops with zero-width matches
344
- // }
345
- // const [ _tag, spaces, tagStart, tagEnd] = matches
346
- // /*
347
- // console.log('FULL CLOSE Tag >>>>>', matches[0])
348
- // console.log('closeTag Start', "'"+matches[1]+"'");
349
- // console.log('closeTag End', "'"+matches[2]+"'");
350
- // /**/
351
- // const tag = spaces + tagStart + tagEnd
352
- // return {
353
- // tag: tag,
354
- // length: tag.length,
355
- // spaces: spaces || '',
356
- // tagStart,
357
- // tagEnd
358
- // }
359
- // }
360
- // }
361
-
362
- // /**
363
- // * Get Regex pattern to match block
364
- // * @param {object} options
365
- // * @param {string} [options.openComment] - comment syntax open
366
- // * @param {string} [options.closeComment] - comment syntax open
367
- // * @param {string} [options.openText] - comment open text
368
- // * @param {string} [options.closeText] - comment close text
369
- // * @returns {RegExp}
370
- // */
371
- // function getBlockRegexOld({ openComment, closeComment, openText, closeText }) {
372
- // // /([ \t]*)(<!-{2,}(?:.|\r?|\n?|\s*)\bdoc-gen\b)((?:.|\r?\n)*?)-{2,}>(.*)<!-{2,}(?:.*|\r?|\n?|\s*)end-doc-gen(?:.|\r?\n)*?-{2,}>/i singleline
373
- // return new RegExp(
374
- // `([ \\t]*)(?:${openComment}(?:.*|\\r?|\\n?|\\s*)${openText}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.*?|.*?\\r?\\n?)*?)${openComment}(?:.*|\\r?|\\n?|\\s*)${closeText}(?:.|\\r?\\n)*?${closeComment}`,
375
- // 'gmi'
376
- // )
377
- // }
378
-
379
-
380
- // function newGetBlockRegex({ commentOpen, commentClose, start, ending }) {
381
- // // 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
382
- // return new RegExp(
383
- // `([ \\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}`,
384
- // 'gmi'
385
- // )
386
- // }
387
-
388
- // function getOpenCommentRegex(word, open, close) {
389
- // // console.log('open', open)
390
- // const boundary = word.indexOf('/') > -1 ? '' : '\\b'
391
- // // console.log('boundary', boundary)
392
- // // return new RegExp(`(\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
393
- // return new RegExp(`([ \\t]*)(${open}(?:.|\r?|\n?|\\s*)${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close}\n?)`, 'gi')
394
- // }
395
-
396
- // function getClosingCommentRegex(word, open, close) {
397
- // const boundary = word.indexOf('/') > -1 ? '' : '\\b'
398
- // return new RegExp(`${close}(?:.|\\r?\\n)*?([ \t]*)((?:${open}(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${boundary}${word}${boundary})((?:.|\\r?\\n)*?${close})`, 'gi')
399
- // // return new RegExp(`--\\>(?:.|\\r?\\n)*?([ \t]*)((?:\\<\\!--(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${word}:END)((?:.|\\r?\\n)*?--\\>)`, 'gi')
400
- // }
401
-
402
- module.exports = {
403
- getBlockRegex,
404
- parseBlocks,
405
- }