markdown-magic 2.6.0 → 3.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.
Files changed (61) hide show
  1. package/README.md +6 -10
  2. package/cli.js +5 -82
  3. package/lib/block-parser-js.test.js +179 -0
  4. package/lib/block-parser.js +389 -0
  5. package/lib/{utils/new-parser.test.js → block-parser.test.js} +168 -50
  6. package/lib/cli.js +234 -0
  7. package/lib/cli.test.js +409 -0
  8. package/lib/defaults.js +12 -0
  9. package/lib/index.js +319 -184
  10. package/lib/index.test.js +11 -0
  11. package/lib/options-parser.js +498 -0
  12. package/lib/options-parser.test.js +1237 -0
  13. package/lib/process-contents.js +330 -0
  14. package/lib/process-file.js +34 -0
  15. package/lib/transforms/code.js +67 -22
  16. package/lib/transforms/file.js +13 -10
  17. package/lib/transforms/remote.js +9 -6
  18. package/lib/transforms/toc.js +136 -64
  19. package/lib/transforms/wordCount.js +5 -0
  20. package/lib/utils/fs.js +340 -0
  21. package/lib/utils/fs.test.js +268 -0
  22. package/lib/utils/html-to-json/compat.js +42 -0
  23. package/lib/utils/html-to-json/format.js +64 -0
  24. package/lib/utils/html-to-json/index.js +37 -0
  25. package/lib/utils/html-to-json/lexer.js +345 -0
  26. package/lib/utils/html-to-json/parser.js +146 -0
  27. package/lib/utils/html-to-json/stringify.js +37 -0
  28. package/lib/utils/html-to-json/tags.js +171 -0
  29. package/lib/utils/index.js +19 -0
  30. package/{cli-utils.js → lib/utils/load-config.js} +2 -6
  31. package/lib/utils/logs.js +89 -0
  32. package/lib/utils/md/filters.js +20 -0
  33. package/lib/utils/md/find-code-blocks.js +80 -0
  34. package/lib/utils/md/find-date.js +32 -0
  35. package/lib/utils/md/find-frontmatter.js +94 -0
  36. package/lib/utils/md/find-frontmatter.test.js +17 -0
  37. package/lib/utils/md/find-html-tags.js +105 -0
  38. package/lib/utils/md/find-images.js +102 -0
  39. package/lib/utils/md/find-links.js +202 -0
  40. package/lib/utils/md/find-unmatched-html-tags.js +33 -0
  41. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +14 -0
  42. package/lib/utils/md/fixtures/file-with-frontmatter.md +32 -0
  43. package/lib/utils/md/fixtures/file-with-links.md +143 -0
  44. package/lib/utils/md/md.test.js +37 -0
  45. package/lib/utils/md/parse.js +122 -0
  46. package/lib/utils/md/utils.js +19 -0
  47. package/lib/utils/regex-timeout.js +83 -0
  48. package/lib/utils/regex.js +38 -5
  49. package/lib/utils/remoteRequest.js +54 -0
  50. package/lib/utils/syntax.js +79 -0
  51. package/lib/utils/text.js +260 -0
  52. package/lib/utils/text.test.js +311 -0
  53. package/package.json +26 -26
  54. package/index.js +0 -46
  55. package/lib/processFile.js +0 -154
  56. package/lib/transforms/index.js +0 -114
  57. package/lib/updateContents.js +0 -125
  58. package/lib/utils/_md.test.js +0 -63
  59. package/lib/utils/new-parser.js +0 -412
  60. package/lib/utils/weird-parse.js +0 -230
  61. package/lib/utils/weird-parse.test.js +0 -217
@@ -1,412 +0,0 @@
1
-
2
- const weirdParse = require('./weird-parse')
3
-
4
- const html = {
5
- tags: ['<!--', '-->'],
6
- pattern: ['<!--+', '-->'],
7
- }
8
-
9
- const jsx = {
10
- tags: ['{/*', '*/}'],
11
- pattern: [
12
- '\{\/\\*+',
13
- '\\*+/\}'
14
- ]
15
- }
16
-
17
- const yaml = {
18
- tags: ['##', '##'],
19
- pattern: [
20
- '##+',
21
- '##+'
22
- ],
23
- converter: (str) => {
24
- return str.split('\n').map((line) => {
25
- return line[0] === '#' ? line : `#${line}`
26
- }).join()
27
- }
28
- }
29
-
30
- const syntaxMap = {
31
- // <!-- x -->
32
- md: html,
33
- // <!-- x -->
34
- html: html,
35
- // /* x */
36
- js: {
37
- tags: ['/*', '*/'],
38
- pattern: [
39
- '\/\\*+', // '\/\*[\*\n\s\t]+', //
40
- '\\*+/'
41
- ],
42
- },
43
- // {/* x */}
44
- jsx: jsx,
45
- mdx: jsx,
46
- // ## x ##
47
- yaml: yaml,
48
- yml: yaml
49
- }
50
-
51
- function convertCommentSyntax({
52
- str,
53
- from,
54
- to
55
- }) {
56
- const [ openPattern, closePattern ] = syntaxMap[from].pattern
57
- const [ openTag, closeTag ] = syntaxMap[to].tags
58
- const match = ` *?\\${openPattern}([\\s\\S]*?)?${closePattern}\\n\\n*?`
59
- // const match = `${openPattern}(.*|\\r?|\\n?|\\s*)*${closePattern}`
60
- const regexToUse = new RegExp(match, 'g')
61
- // console.log('regexToUse', regexToUse)
62
- const found = str.match(regexToUse)
63
- if (!found) {
64
- return str
65
- }
66
- const newComment = found[0].replace(regexToUse, `${openTag}$1${closeTag}`)
67
- const converter = syntaxMap[to].converter
68
- const newText = (converter) ? converter(newComment) : newComment
69
- return str.replace(regexToUse, newText)
70
- }
71
-
72
- const defaultOptions = {
73
- syntax: 'md',
74
- open: `DOCS:START`,
75
- close: `DOCS:END`,
76
- }
77
-
78
- function parseBlocks(contents, options = defaultOptions) {
79
- const { syntax } = options
80
- const transformsToRun = []
81
- // const blockRegex = new RegExp(
82
- // `(.*)(?:\\<\\!--(?:.*|\r?|\n?|\\s*)${matchWord}:START(?:(?:.|\\r?\\n)*?(?:\\()(.*)\\))?(.|\\r?\\n)*?)?<\!--(?:.*|\r?|\n?|\\s*)${matchWord}:END(?:.|\\r?\\n)*?--\\>`,
83
- // 'gm'
84
- // )
85
- // `(?:.*)(?:\\<\\!--(?:.*|\\r?|\\n?|\\s*)${matchWord}:START\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.|\\r?\\n)*?)<\!--(?:.*|\\r?|\\n?|\\s*)${matchWord}:END(?:.|\\r?\\n)*?--\\>`,
86
- const START = options.open
87
- const END = options.close
88
-
89
- const [ commentOpen, commentClose ] = syntaxMap[syntax].pattern
90
- // const regexToUse = new RegExp(
91
- // `([ \\t]*)(?:\\<\\!--(?:.*|\\r?|\\n?|\\s*)${matchWord}:START\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.|\\r?\\n)*?)<\!--(?:.*|\\r?|\\n?|\\s*)${matchWord}:END(?:.|\\r?\\n)*?--\\>`,
92
- // 'gmi'
93
- // )
94
- const regexToUse = new RegExp(
95
- `([ \\t]*)(?:${commentOpen}(?:.*|\\r?|\\n?|\\s*)${START}\\s*([(\\[\\{]*[A-Za-z0-9_$-]*[)\\]\\}]*)\\s*)((?:.|\\r?\\n)*?)${commentOpen}(?:.*|\\r?|\\n?|\\s*)${END}(?:.|\\r?\\n)*?${commentClose}`,
96
- 'gmi'
97
- )
98
- const paramsRegex = new RegExp(`([\\s\\S]*?)${commentClose}`, 'gm')
99
- const trimRegex = new RegExp(`${commentClose}$`)
100
-
101
- // console.log('paramsRegex', paramsRegex)
102
- // ([ \t]*)(?:\/\*(?:.*|\r?|\n?|\s*)XYZ:START\s*([(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)((?:.|\r?\n)*?)\/\*(?:.*|\r?|\n?|\s*)XYZ:END(?:.|\r?\n)*?\*\/
103
- // console.log('regexToUse', regexToUse)
104
-
105
- let openTagRegex = matchOpeningCommentTag(START, commentOpen, commentClose)
106
- let closeTagRegex = matchClosingCommentTag(END, commentOpen, commentClose)
107
- while ((commentMatches = regexToUse.exec(contents)) !== null) {
108
- let props = {}
109
- let meta = {}
110
- const [ block, spaces, action, params ] = commentMatches
111
- const indentation = spaces || ''
112
- /*
113
- console.log('index', commentMatches.index)
114
- console.log('block', block)
115
- console.log('action', action)
116
- console.log('params', params)
117
- console.log('spaces', `"${spaces}"`)
118
- /** */
119
- // This is necessary to avoid infinite loops
120
- if (commentMatches.index === regexToUse.lastIndex) {
121
- regexToUse.lastIndex++
122
- }
123
-
124
- openTagRegex = matchOpeningCommentTag(START, commentOpen, commentClose)
125
- const openingTag = getOpeningTags(block, {
126
- pattern: openTagRegex,
127
- open: commentOpen,
128
- close: commentClose
129
- })
130
- closeTagRegex = matchClosingCommentTag(END, commentOpen, commentClose)
131
- const closingTag = getClosingTags(block, {
132
- pattern: closeTagRegex
133
- })
134
- /*
135
- console.log('openingTag', openingTag)
136
- console.log('closingTag', closingTag)
137
- /** */
138
- const openingTagLength = openingTag.length //+ indentation.length
139
- const contentEndPosition = block.indexOf(closingTag.tag, openingTagLength)
140
- const content = getTextBetween(block, openingTagLength, contentEndPosition)
141
- // console.log('contentcontent', content)
142
- let originalContent = content
143
- const contentEndsWithNewLine = getLastCharacter(originalContent) === '\n'
144
- const openEndsWithNewLine = getLastCharacter(openingTag.tag) === '\n'
145
- const isMultiline = block.indexOf('\n') > -1
146
- meta.isMultiline = isMultiline
147
- const closeTag = (contentEndsWithNewLine) ? `\n${closingTag.tag}` : closingTag.tag
148
-
149
- // Move new line to beginning of closing tag
150
- // if (originalContent.match(/\n$/)) {
151
- if (contentEndsWithNewLine) {
152
- // originalContent = originalContent.replace(/\n$/, '')
153
- originalContent = originalContent.slice(0, -1)
154
- }
155
-
156
- // Strip indentation
157
- originalContent = stripIndent(originalContent, indentation.length)
158
- // console.log('originalContent')
159
- // console.log(`"${originalContent}"`)
160
- // originalContent = originalContent.replace(/^\s+|\s+$/g, '')
161
-
162
- // (functionName) or [functionName] or {functionName}
163
- const transform = action.replace(/[(\[\{]*([A-Z-a-z0-9_$-]*)[)\]\}]*/, '$1')
164
- // if (transform && !transform.match(/^-+/)) {
165
- if (transform && getFirstCharacter(transform) !== '-') {
166
- // console.log('params', params)
167
- // const paramValue = params.match(/([\s\S]*?)-->/gm)
168
- const paramValue = params.match(paramsRegex)
169
- let paramString
170
- if (paramValue) {
171
- // paramString = paramValue[0].replace(/-*>$/, '').trim()
172
- paramString = paramValue[0].replace(trimRegex, '').trim()
173
- // console.log('paramString', paramString)
174
- if (paramString) {
175
- // Legacy v1 options parser
176
- if (getFirstCharacter(paramString) === ':') {
177
- meta.isLegacy = true
178
- paramString = paramString.replace(/\s?\)\s?$/, '').substring(1)
179
- props = legacyParseOptions(paramString)
180
- } else {
181
- props = weirdParse(paramString)
182
- }
183
- }
184
- }
185
- /*
186
- console.log(regexToUse)
187
- console.log(`transform "${transform}" at ${regexToUse.lastIndex} using props:`)
188
- console.log(props)
189
- console.log('───────────────────────')
190
- /** */
191
- const shift = (openEndsWithNewLine) ? 1 : 0
192
- const contentStart = commentMatches.index + openingTag.tag.length - shift //+ indentation.length
193
- const contentEnd = contentStart + content.length + indentation.length + shift
194
- //const addOne = (contentEndsWithNewLine) ? 1 : 0
195
- transformsToRun.push({
196
- transform,
197
- args: props,
198
- // content: originalContent,
199
- block: {
200
- indentation,
201
- start: commentMatches.index,
202
- end: regexToUse.lastIndex,
203
- contentStart,
204
- contentEnd,
205
- contentIndent: minIndent(originalContent),
206
- openTag: openingTag.tag,
207
- content: originalContent,
208
- closeTag: closeTag,
209
- // full: `${openingTag.tag}${indentString(originalContent, indentation.length)}${closeTag}`,
210
- // full: indentString(`${openingTag.tag}${originalContent}${closeTag}`, indentation.length),
211
- // full: indentString(`${stripIndent(openingTag.tag, indentation.length)}${originalContent}${stripIndent(closeTag, indentation.length)}`, indentation.length)
212
- },
213
- raw: {
214
- transform: (meta.isLegacy) ? action.replace(/^\s?\(/, '') : action,
215
- args: paramString,
216
- content: getTextBetween(contents, contentStart, contentEnd),
217
- block: block,
218
- },
219
- meta,
220
- })
221
- }
222
- }
223
-
224
- // const newer =
225
- // /(?:.*)(?:\<\!--(?:.*|\r?|\n?|\s*)DOCS:START\s*([(\[\{][A-Z-a-z_$-]*[)\]\}])\s*)((?:.|\r?\n)*?)<\!--(?:.*|\r?|\n?|\s*)DOCS:END(?:.|\r?\n)*?--\>/gmi
226
- // // console.log('newera', newer)
227
- /*
228
- const comments = content.match(newerString)
229
- console.log('comments', comments)
230
- const commentRegexInside = /<\!-*\s*([\s\S]*?) ?-*\>\n*?/g
231
- if (comments) {
232
- // console.log('comments', comments)
233
- // console.log(comments.length)
234
- comments.forEach((text) => {
235
- console.log('text', text)
236
- const inside = commentRegexInside.exec(text)
237
- console.log('inside', inside)
238
- if (inside) {
239
- const config = inside[1].replace(`${matchWord}:START`, '').trim()
240
- // console.log(formatProps(config))
241
- }
242
- })
243
- }*/
244
-
245
- return {
246
- pattern: regexToUse,
247
- commentOpen: openTagRegex,
248
- commentClose: closeTagRegex,
249
- transforms: transformsToRun
250
- }
251
- }
252
-
253
- function replaceTextBetween(origin, startIndex, endIndex, insertion) {
254
- return origin.substring(0, startIndex) + insertion + origin.substring(endIndex)
255
- }
256
-
257
- function replaceContent(origin, insertion, data) {
258
- return replaceTextBetween(origin, data.block.contentStart, data.block.contentEnd, insertion)
259
- }
260
-
261
- function getFirstCharacter(str) {
262
- return str.charAt(0)
263
- }
264
-
265
- function getLastCharacter(str) {
266
- return str.substr(-1)
267
- }
268
-
269
- function getLeadingSpaces(text) {
270
- return text.match(/^\s/) ? text : ''
271
- }
272
-
273
- function getTextBetween(text, start, end) {
274
- return text.slice(start, end)
275
- }
276
-
277
- function stripIndent(string, indentation) {
278
- const indent = typeof indentation !== 'undefined' ? indentation : minIndent(string);
279
- if (indent === 0) {
280
- return string
281
- }
282
- const regex = new RegExp(`^[ \\t]{${indent}}`, 'gm')
283
- return string.replace(regex, '')
284
- }
285
-
286
- // https://github.com/jamiebuilds/min-indent/blob/master/index.js
287
- function minIndent(string) {
288
- const match = string.match(/^[ \t]*(?=\S)/gm)
289
- if (!match) return 0
290
- return match.reduce((r, a) => Math.min(r, a.length), Infinity)
291
- }
292
-
293
- function indentString(string, count = 1, options = {}) {
294
- const {
295
- indent = ' ',
296
- includeEmptyLines = false
297
- } = options;
298
- if (count === 0) return string
299
- const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm
300
- return string.replace(regex, indent.repeat(count))
301
- }
302
-
303
- function getOpeningTags(block, {
304
- pattern,
305
- open,
306
- close
307
- }) {
308
- // console.log(block.match(/^\/\*+(.*)\*\//))
309
- // console.log('openTagRegex', pattern)
310
- let matches
311
- while ((matches = pattern.exec(block)) !== null) {
312
- if (matches.index === pattern.lastIndex) {
313
- pattern.lastIndex++ // avoid infinite loops with zero-width matches
314
- }
315
- const [ tag, spaces, tagStart, tagEnd ] = matches
316
- /*
317
- console.log('FULL Open Tag >>>>>', tag)
318
- console.log('openTag Start', "'"+tagStart+"'");
319
- console.log('openTag End', "'"+tagEnd+"'");
320
- /**/
321
- return {
322
- tag,
323
- spaces: spaces || '',
324
- length: tag.length,
325
- tagStart,
326
- tagEnd,
327
- }
328
- }
329
- // Fallthrough
330
- const fallbackRegex = new RegExp(`^([ \\t]*)(${open}([\\s\\S]*?)${close})\\n?`)
331
- // const xyz = block.match(/^([ \t]*)(\/\*+([\s\S]*?)\*+\/)/)
332
- const xyz = block.match(fallbackRegex)
333
- /*
334
- console.log('fallbackRegex', fallbackRegex)
335
- console.log('fall through', `"${block}"`)
336
- console.log('xyz', xyz)
337
- /** */
338
- return {
339
- tag: xyz[0],
340
- spaces: xyz[1] || '',
341
- length: xyz[0].length,
342
- }
343
- }
344
-
345
- function getClosingTags(block, {
346
- pattern,
347
- // open,
348
- // close
349
- }) {
350
- // console.log('closeTagRegex', closeTagRegex)
351
- let matches
352
- while ((matches = pattern.exec(block)) !== null) {
353
- if (matches.index === pattern.lastIndex) {
354
- pattern.lastIndex++ // avoid infinite loops with zero-width matches
355
- }
356
- const [ _tag, spaces, tagStart, tagEnd] = matches
357
- /*
358
- console.log('FULL CLOSE Tag >>>>>', matches[0])
359
- console.log('closeTag Start', "'"+matches[1]+"'");
360
- console.log('closeTag End', "'"+matches[2]+"'");
361
- /**/
362
- const tag = spaces + tagStart + tagEnd
363
- return {
364
- tag: tag,
365
- length: tag.length,
366
- spaces: spaces || '',
367
- tagStart,
368
- tagEnd
369
- }
370
- }
371
- }
372
-
373
- function removeComments(str) {
374
- // /([^\s]*)?([ \\t]*)\<\!-+\s?([\s\S]*?)?-+\>\n*?([^\s]*)?/gi
375
- const pattern = new RegExp(`([^\\s]*)?([ \\t]*)<!-+\\s?([\\s\\S]*?)?-+>\n*?([^\\s]*)?`, 'gi')
376
- return str.replace(pattern, '')
377
- }
378
-
379
- function matchOpeningCommentTag(word, open, close) {
380
- // console.log('open', open)
381
- // return new RegExp(`(\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
382
- return new RegExp(`([ \\t]*)(${open}(?:.|\r?|\n?|\\s*)\\b${word}\\b)((?:.|\\r?\\n)*?${close}\n?)`, 'gi')
383
- // return new RegExp(`([ \\t]*)(\\<\\!--(?:.*|\r?|\n?|\s*)${word}:START)((?:.|\\r?\\n)*?--\\>\n?)`, 'gi')
384
- }
385
-
386
- function matchClosingCommentTag(word, open, close) {
387
- return new RegExp(`${close}(?:.|\\r?\\n)*?([ \t]*)((?:${open}(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?\\b${word}\\b)((?:.|\\r?\\n)*?${close})`, 'gi')
388
- // return new RegExp(`--\\>(?:.|\\r?\\n)*?([ \t]*)((?:\\<\\!--(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${word}:END)((?:.|\\r?\\n)*?--\\>)`, 'gi')
389
- }
390
-
391
-
392
- function legacyParseOptions(options) {
393
- const returnOptions = {}
394
- if (!options) {
395
- return returnOptions
396
- }
397
- options.split('&').map((opt, i) => { // eslint-disable-line
398
- const getValues = opt.split(/=(.+)/)
399
- if (getValues[0] && getValues[1]) {
400
- returnOptions[getValues[0]] = getValues[1]
401
- }
402
- })
403
- return returnOptions
404
- }
405
-
406
-
407
- module.exports = {
408
- getTextBetween,
409
- replaceTextBetween,
410
- replaceContent,
411
- parseBlocks,
412
- }
@@ -1,230 +0,0 @@
1
- const { parseJSON } = require('json-alexander')
2
-
3
- function convert(value) {
4
- if (value === 'false') {
5
- return false
6
- }
7
- if (value === 'true') {
8
- return true
9
- }
10
-
11
- const isNumber = Number(value)
12
- if (typeof isNumber === 'number' && !isNaN(isNumber)) {
13
- return isNumber
14
- }
15
-
16
- // console.log(typeof value)
17
- // console.log('value', value)
18
- try {
19
- const val = parseJSON(value) // last attempt to format an array like [ one, two ]
20
- if (typeof val === 'string' && val.match(/^\[/) && val.match(/\]$/)) {
21
- const inner = val.match(/^\[(.*)\]/)
22
- if (inner && inner[1]) {
23
- const newVal = inner[1].split(', ').map((x) => {
24
- return convert(x.trim())
25
- })
26
- return newVal
27
- }
28
- }
29
- return val
30
- } catch (err) {
31
- console.log('val', value)
32
- console.log('err', err)
33
- }
34
- return value
35
- }
36
-
37
- const RESERVED = '__private'
38
-
39
- function doWeirdParse(x) {
40
- // https://regex101.com/r/bx8DXm/1/ Match everything but spaces/newlines
41
- var y = /("|'|{)[^"}]+("|'|})|(\S+)/g
42
-
43
- const cleanLines = x
44
- .split(/\n/)
45
- .filter((line) => {
46
- // Trim all comment blocks
47
- return !line.trim().match(/^(\/\/+|\/\*+|#+)/gm)
48
- })
49
- .join('\n')
50
-
51
- var lines = cleanLines.match(y)
52
- // console.log('lines', lines.length)
53
- // console.log('lines', lines)
54
- var isEnding = /(['"}\]]|true,?|false,?)$/
55
-
56
- const values = lines.reduce((acc, curr, i) => {
57
- const isLastLoop = lines.length === (i + 1)
58
- const nextItem = lines[i + 1] || ''
59
- const hasText = curr.match(/^[A-Za-z]/)
60
- let alreadyAdded = false
61
-
62
- /*
63
- console.log('isLastLoop', isLastLoop)
64
- console.log('RESERVED', acc[RESERVED])
65
- console.log("current item", curr)
66
- console.log('next item ', nextItem)
67
- /** */
68
-
69
- // If has no = its a true boolean. e.g isThingy
70
- if (hasText && acc[RESERVED].match(/^[A-Za-z]/) && !isValuePair(acc[RESERVED])) {
71
- // console.log('xxxxxxx', acc[RESERVED])
72
- acc[trimTrailingComma(acc[RESERVED])] = true
73
- acc[RESERVED] = ''
74
- }
75
- // If has no = its a true boolean
76
- if (hasText && !curr.match(isEnding) && acc[RESERVED].match(isEnding)) {
77
- // console.log('end', curr)
78
- const kv = getKeyAndValueFromString(acc[RESERVED])
79
- if (kv) {
80
- acc[kv.key] = kv.value
81
- }
82
- acc[RESERVED] = ''
83
- }
84
-
85
- if (!acc[RESERVED].match(/^[A-Za-z]+={+/) && isValuePair(curr) && curr.match(isEnding)) {
86
- const kv = getKeyAndValueFromString(curr)
87
- if (kv) {
88
- // console.log(`ADDED`, kv)
89
- acc[kv.key] = kv.value
90
- }
91
- } else {
92
- // console.log('Add', curr)
93
- alreadyAdded = true
94
- acc[RESERVED] = acc[RESERVED] + curr
95
- }
96
-
97
-
98
- if (acc[RESERVED].match(isEnding) && nextItem.match(/^[A-Za-z0-9_-]/)) {
99
- const kv = getKeyAndValueFromString(acc[RESERVED])
100
- if (kv) {
101
- // console.log(`acc[RESERVED].match(isEnding)`, kv)
102
- acc[kv.key] = kv.value
103
- }
104
- acc[RESERVED] = ''
105
- }
106
-
107
- // If ends in number foo=2 or bar=3,
108
- if (isValuePair(curr) && curr.match(/\d,?$/)) {
109
- const kv = getKeyAndValueFromString(acc[RESERVED])
110
- if (kv) {
111
- // console.log(`acc[RESERVED].match(isEnding)`, kv)
112
- acc[kv.key] = kv.value
113
- }
114
- acc[RESERVED] = ''
115
- }
116
-
117
- // If last loop and still no match and looks like KV. Parse it
118
- if (isLastLoop) {
119
- // If single isCool boolean
120
- if (hasText && !curr.match(/=/)) {
121
- // console.log(`ADDED`, kv)
122
- // acc[curr] = true
123
- // acc[RESERVED] = ''
124
- }
125
- // console.log('currrrrr', curr)
126
- // console.log("acc[RESERVED]", acc[RESERVED])
127
- // console.log('combined', acc[RESERVED] + curr)
128
- // If value empty but __private have accumulated values
129
- if (acc[RESERVED]) {
130
- // if (acc[RESERVED] && (acc[RESERVED].match(isEnding) || isValuePair(acc[RESERVED]))) {
131
- const valueToCheck = (curr.match(isEnding) && !alreadyAdded) ? acc[RESERVED] + curr : acc[RESERVED]
132
- // console.log('valueToCheck', valueToCheck)
133
- const kv = getKeyAndValueFromString(valueToCheck)
134
- if (kv) {
135
- // console.log(`acc[RESERVED].match(isEnding)`, kv)
136
- acc[kv.key] = kv.value
137
- }
138
- acc[RESERVED] = ''
139
- }
140
- }
141
-
142
- return acc
143
- }, {
144
- [RESERVED]: '',
145
- })
146
-
147
- delete values[RESERVED]
148
-
149
- /* // If no keys last attempt to parse
150
- if (!Object.keys(values).length) {
151
- const kv = getKeyAndValueFromString(x)
152
- if (kv) {
153
- return {
154
- [`${kv.key}`]: kv.value
155
- }
156
- }
157
- }
158
- */
159
-
160
- return values
161
- }
162
-
163
- function isValuePair(str) {
164
- return str.match(/=/)
165
- }
166
-
167
- // https://melvingeorge.me/blog/check-if-string-contain-emojis-javascript OR https://www.npmjs.com/package/emoji-regex
168
- function hasEmoji(str) {
169
- const regexExp = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi;
170
- return regexExp.test(str)
171
- }
172
-
173
- function getKeyAndValueFromString(string) {
174
- if (!string) return
175
- // const keyValueRegex = /([A-Za-z-_$]+)=['{"]?(.*)['}"]?/g
176
- // const match = keyValueRegex.exec(string)
177
- // if (!match) {
178
- //   return
179
- // }
180
- // console.log('getKeyAndValueFromString')
181
-
182
- const [key, ...values] = string.split('=')
183
- /* If no key or key starts with --- */
184
- if (!key || key.charAt(0) === '-' || hasEmoji(key)) {
185
- return
186
- }
187
- // console.log('string', string)
188
- // console.log('key', key)
189
- // console.log('values', values)
190
- /* If no value, isThing === true */
191
- if (!values.length) {
192
- return {
193
- key: key,
194
- value: true,
195
- }
196
- }
197
-
198
- const value = values.join('')
199
-
200
- let cleanValue = value
201
- .replace(/^{{2,}/, '{')
202
- .replace(/}{2,}$/, '}')
203
- .replace(/^\[{2,}/, '[')
204
- .replace(/\]{2,}$/, ']')
205
- // Trim trailing commas
206
- .replace(/,$/, '')
207
-
208
- if (value.match(/^{[^:,]*}/)) {
209
- cleanValue = removeSurroundingBrackets(cleanValue)
210
- } else if (value.match(/^{\s*\[\s*[^:]*\s*\]\s*\}/)) {
211
- // Match { [ one, two ,3,4 ]   }
212
- cleanValue = removeSurroundingBrackets(cleanValue)
213
- }
214
-
215
- return {
216
- key: key,
217
- value: convert(cleanValue),
218
- }
219
- }
220
-
221
- function trimTrailingComma(str = '') {
222
- // Trim trailing commas
223
- return str.replace(/,$/, '')
224
- }
225
-
226
- function removeSurroundingBrackets(val) {
227
- return val.replace(/^{/, '').replace(/}$/, '')
228
- }
229
-
230
- module.exports = doWeirdParse