markdown-magic 3.0.0 → 3.0.1
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.
- package/README.md +43 -29
- package/lib/block-parser-js.test.js +148 -156
- package/lib/block-parser.js +255 -262
- package/lib/block-parser.test.js +43 -6
- package/lib/cli.js +30 -19
- package/lib/cli.test.js +73 -73
- package/lib/globals.d.ts +66 -0
- package/lib/index.js +43 -9
- package/lib/process-contents.js +80 -39
- package/lib/process-file.js +4 -1
- package/lib/transforms/code.js +4 -10
- package/lib/transforms/file.js +7 -10
- package/lib/transforms/index.js +0 -0
- package/lib/transforms/remote.js +2 -3
- package/lib/transforms/sectionToc.js +18 -0
- package/lib/transforms/toc.js +10 -335
- package/lib/types.js +11 -0
- package/lib/utils/fs.js +21 -19
- package/lib/utils/fs.test.js +4 -5
- package/lib/utils/logs.js +7 -2
- package/lib/utils/md/filters.js +5 -5
- package/lib/utils/md/find-code-blocks.js +16 -8
- package/lib/utils/md/find-frontmatter.js +11 -13
- package/lib/utils/md/find-frontmatter.test.js +2 -2
- package/lib/utils/md/find-html-tags.js +1 -1
- package/lib/utils/md/find-images-md.js +27 -0
- package/lib/utils/md/find-images.js +39 -34
- package/lib/utils/md/find-links.js +72 -54
- package/lib/utils/md/find-unmatched-html-tags.js +1 -2
- package/lib/utils/md/fixtures/file-with-links.md +10 -0
- package/lib/utils/md/md.test.js +72 -4
- package/lib/utils/md/parse.js +91 -67
- package/lib/utils/regex-timeout.js +2 -1
- package/lib/utils/regex.js +3 -2
- package/lib/utils/remoteRequest.js +1 -0
- package/lib/utils/syntax.js +3 -0
- package/lib/utils/text.js +71 -3
- package/lib/utils/text.test.js +3 -9
- package/lib/utils/toc.js +315 -0
- package/package.json +7 -3
- package/lib/options-parser.js +0 -498
- package/lib/options-parser.test.js +0 -1237
- package/lib/utils/html-to-json/compat.js +0 -42
- package/lib/utils/html-to-json/format.js +0 -64
- package/lib/utils/html-to-json/index.js +0 -37
- package/lib/utils/html-to-json/lexer.js +0 -345
- package/lib/utils/html-to-json/parser.js +0 -146
- package/lib/utils/html-to-json/stringify.js +0 -37
- package/lib/utils/html-to-json/tags.js +0 -171
package/lib/options-parser.js
DELETED
|
@@ -1,498 +0,0 @@
|
|
|
1
|
-
const { parseJSON } = require('json-alexander')
|
|
2
|
-
|
|
3
|
-
// alt approach maybe https://github.com/etienne-dldc/literal-parser
|
|
4
|
-
const RESERVED = '__private'
|
|
5
|
-
const SPACES = '__SPACE__'
|
|
6
|
-
const NEWLINE = '__NEWLINE__'
|
|
7
|
-
const BREAK = '__OPT_BREAK__'
|
|
8
|
-
const SURROUNDING_QUOTES = /^("|'|`)|("|'|`)$/g
|
|
9
|
-
const STARTS_WITH_VALID_CHAR = /^[A-Za-z0-9_]/
|
|
10
|
-
const ARRAY_REGEX = /^\[(.*)\]$/
|
|
11
|
-
const OBJECT_REGEX = /^\{(.*)\}$/
|
|
12
|
-
const TRAILING_COMMAS = /,+$/
|
|
13
|
-
const TRAILING_ARRAY_COMMAS = /(?:,*[^\S]*)+?]$/
|
|
14
|
-
// https://regex101.com/r/cy7mLe/1
|
|
15
|
-
const TRAILING_OBJECT_COMMAS = /(?:,*[^\S]*)*?}$/
|
|
16
|
-
|
|
17
|
-
function isArrayLike(str) {
|
|
18
|
-
if (typeof str !== 'string') return false
|
|
19
|
-
return Boolean(ARRAY_REGEX.test(str))
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function isObjectLike(str) {
|
|
23
|
-
if (typeof str !== 'string') return false
|
|
24
|
-
return Boolean(OBJECT_REGEX.test(str))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function convert(value) {
|
|
28
|
-
// console.log(typeof value)
|
|
29
|
-
// console.log('convert preparse value', value)
|
|
30
|
-
if (value === 'false') {
|
|
31
|
-
return false
|
|
32
|
-
}
|
|
33
|
-
if (value === 'true') {
|
|
34
|
-
return true
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const isNumber = Number(value)
|
|
38
|
-
if (typeof isNumber === 'number' && !isNaN(isNumber)) {
|
|
39
|
-
return isNumber
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
/* Trim trailing commas in arrays */
|
|
44
|
-
if (isArrayLike(value)) {
|
|
45
|
-
value = value.replace(TRAILING_ARRAY_COMMAS, ']')
|
|
46
|
-
} else if (isObjectLike(value)) {
|
|
47
|
-
/* Trim trailing commas in object */
|
|
48
|
-
value = value.replace(TRAILING_OBJECT_COMMAS, '}')
|
|
49
|
-
}
|
|
50
|
-
const val = parseJSON(value) // last attempt to format an array like [ one, two ]
|
|
51
|
-
// console.log('parseJSON val', val)
|
|
52
|
-
// if (typeof val === 'string' && val.match(/^\[/) && val.match(/\]$/)) {
|
|
53
|
-
// const inner = val.match(/^\[(.*)\]/)
|
|
54
|
-
// if (inner && inner[1]) {
|
|
55
|
-
// const newVal = inner[1].split(', ').map((x) => {
|
|
56
|
-
// return convert(x.trim())
|
|
57
|
-
// })
|
|
58
|
-
// return newVal
|
|
59
|
-
// }
|
|
60
|
-
// }
|
|
61
|
-
// console.log('post parse', value)
|
|
62
|
-
return val
|
|
63
|
-
} catch (err) {
|
|
64
|
-
// console.log('parse error', err)
|
|
65
|
-
// console.log('json val', value)
|
|
66
|
-
/* Convert array looking string into values */
|
|
67
|
-
if (typeof value === 'string' && ARRAY_REGEX.test(value)) {
|
|
68
|
-
const inner = value.match(ARRAY_REGEX)
|
|
69
|
-
if (inner && inner[1]) {
|
|
70
|
-
const composeValue = inner[1]
|
|
71
|
-
.replace(TRAILING_COMMAS, '') // remove dangling commas JSON alt MATCH_DANGLING_COMMAS /}(,[^}]*?)]}?$/
|
|
72
|
-
.split(',')
|
|
73
|
-
.reduce((acc, curr) => {
|
|
74
|
-
const open = (curr.match(/{/g) || []).length
|
|
75
|
-
const close = (curr.match(/}/g) || []).length
|
|
76
|
-
const arrayOpen = (curr.match(/\[/g) || []).length
|
|
77
|
-
const arrayClose = (curr.match(/\]/g) || []).length
|
|
78
|
-
acc.objectOpenCount += open
|
|
79
|
-
acc.objectCloseCount += close
|
|
80
|
-
acc.arrayOpenCount += arrayOpen
|
|
81
|
-
acc.arrayCloseCount += arrayClose
|
|
82
|
-
const sealObject = acc.objectOpenCount > 0 && acc.objectOpenCount === acc.objectCloseCount
|
|
83
|
-
const sealArray = acc.arrayOpenCount > 0 && acc.arrayOpenCount === acc.arrayCloseCount
|
|
84
|
-
|
|
85
|
-
if (acc.objectOpenCount > 0 && !sealObject || acc.arrayOpenCount > 0 && !sealArray) {
|
|
86
|
-
// if (curr.match(/:|{/)) {
|
|
87
|
-
return {
|
|
88
|
-
...acc,
|
|
89
|
-
next: acc.next + curr + ','
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (sealObject || sealArray) {
|
|
94
|
-
return {
|
|
95
|
-
...acc,
|
|
96
|
-
...(!sealObject) ? {} : {
|
|
97
|
-
objectOpenCount: 0,
|
|
98
|
-
objectCloseCount: 0,
|
|
99
|
-
},
|
|
100
|
-
...(!sealArray) ? {} : {
|
|
101
|
-
arrayOpenCount: 0,
|
|
102
|
-
arrayCloseCount: 0,
|
|
103
|
-
},
|
|
104
|
-
next: '',
|
|
105
|
-
values: acc.values.concat(acc.next + curr)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// default
|
|
110
|
-
return {
|
|
111
|
-
...acc,
|
|
112
|
-
values: acc.values.concat(curr)
|
|
113
|
-
}
|
|
114
|
-
}, {
|
|
115
|
-
next: '',
|
|
116
|
-
values: [],
|
|
117
|
-
arrayOpenCount: 0,
|
|
118
|
-
arrayCloseCount: 0,
|
|
119
|
-
objectOpenCount: 0,
|
|
120
|
-
objectCloseCount: 0,
|
|
121
|
-
})
|
|
122
|
-
// console.log('composeValue', composeValue)
|
|
123
|
-
if (composeValue.values.length) {
|
|
124
|
-
const newVal = composeValue.values.map((x) => {
|
|
125
|
-
// console.log('x', x)
|
|
126
|
-
return convert(x.trim())
|
|
127
|
-
})
|
|
128
|
-
return newVal
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* Fix fallthrough strings remove surrounding strings
|
|
134
|
-
if (value.startsWith('"') && value.endsWith('"')) {
|
|
135
|
-
return value.replace(/^"|"$/g, '')
|
|
136
|
-
}
|
|
137
|
-
if (value.startsWith("'") && value.endsWith("'")) {
|
|
138
|
-
return value.replace(/^'|'$/g, '')
|
|
139
|
-
}
|
|
140
|
-
*/
|
|
141
|
-
}
|
|
142
|
-
return value
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
function fixSpaceStrings(val) {
|
|
147
|
-
// console.log('val', val)
|
|
148
|
-
if (typeof val === 'string') {
|
|
149
|
-
return val
|
|
150
|
-
.replace(/__SPACE__/g, ' ')
|
|
151
|
-
.replace(/__NEWLINE__/g, '\n')
|
|
152
|
-
}
|
|
153
|
-
return val
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Parse string of key value options
|
|
158
|
-
* @param {string} input - string of options. Can be multiline
|
|
159
|
-
* @returns {Record<string, any>}
|
|
160
|
-
*/
|
|
161
|
-
function optionsParse(input) {
|
|
162
|
-
if (typeof input === 'undefined' || input === null || input === '') {
|
|
163
|
-
return {}
|
|
164
|
-
}
|
|
165
|
-
// https://regex101.com/r/bx8DXm/1/ Match everything but spaces/newlines
|
|
166
|
-
// var pattern = /("|'|{)[^"}]+("|'|})|(\S+)/g
|
|
167
|
-
var pattern = /(\S+)/g
|
|
168
|
-
|
|
169
|
-
//var y = /("|{)[^"}]+("|})|([^\r\n\t\f\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+)/gm
|
|
170
|
-
|
|
171
|
-
const cleanLines = input
|
|
172
|
-
//.replace(/\n/g, NEWLINE)
|
|
173
|
-
// Remove JS comment blocks and single line comments https://regex101.com/r/XKHU18/2 | alt https://regex101.com/r/ywd8TT/1
|
|
174
|
-
.replace(/\s+\/\*[\s\S]*?\*\/|\s+\/\/.*$/gm, '')
|
|
175
|
-
/* Temporarily replace newlines with placeholder */
|
|
176
|
-
.replace(/\n(?=(?:(?:[^"]*(?:")){2})*[^"]*(?:")[^"]*$)/g, NEWLINE)
|
|
177
|
-
.replace(/\n(?=(?:(?:[^']*(?:')){2})*[^']*(?:')[^']*$)/g, NEWLINE)
|
|
178
|
-
.replace(/\n(?=(?:(?:[^`]*(?:`)){2})*[^`]*(?:`)[^`]*$)/g, NEWLINE)
|
|
179
|
-
/* Temporarily replace spaces with placeholder */
|
|
180
|
-
// bob="co ol" steve="c ool" --> add temp spaces
|
|
181
|
-
.replace(/\s(?=(?:(?:[^"]*(?:")){2})*[^"]*(?:")[^"]*$)/g, SPACES)
|
|
182
|
-
// bob='co ol' steve='c ool' --> add temp spaces
|
|
183
|
-
.replace(/\s(?=(?:(?:[^']*(?:')){2})*[^']*(?:')[^']*$)/g, SPACES)
|
|
184
|
-
// bob=`co ol` steve=`c ool` --> add temp spaces
|
|
185
|
-
.replace(/\s(?=(?:(?:[^`]*(?:`)){2})*[^`]*(?:`)[^`]*$)/g, SPACES)
|
|
186
|
-
// .replace(/ /g, SPACES)
|
|
187
|
-
// matchspaces inside quotes https://regex101.com/r/DqJ4TD/1
|
|
188
|
-
// .replace(/\s+(?=(?:(?:[^"']*(?:"|')){2})*[^"']*(?:"|')[^"']*$)/g, SPACES)
|
|
189
|
-
.split(/\n/)
|
|
190
|
-
.filter((line) => {
|
|
191
|
-
/* Trim single line comments like:
|
|
192
|
-
// xyz
|
|
193
|
-
## abc
|
|
194
|
-
/* foo bar * /
|
|
195
|
-
*/
|
|
196
|
-
return !line.trim().match(/^(\/\/+|\/\*+|#+)/gm)
|
|
197
|
-
})
|
|
198
|
-
// .map((x) => x.trim().replace(/ /g, SPACES)) // c="tons of" weird inner quotes"
|
|
199
|
-
.join('\n')
|
|
200
|
-
//.replace(/ /g, SPACES)
|
|
201
|
-
//console.log('cleanLines', cleanLines)
|
|
202
|
-
|
|
203
|
-
var lines = cleanLines
|
|
204
|
-
.replace(/__SPACE__([a-zA-Z]*)=/g, `${BREAK}$1=`)
|
|
205
|
-
// Fix out of option new line replacements https://regex101.com/r/ttlXyt/1
|
|
206
|
-
.replace(/__NEWLINE__(?:__SPACE__)*__OPT_BREAK__/g, BREAK)
|
|
207
|
-
.match(pattern)
|
|
208
|
-
.map(fixSpaceStrings)
|
|
209
|
-
/* if BREAK split string again */
|
|
210
|
-
.map((item) => {
|
|
211
|
-
return item.split(BREAK)
|
|
212
|
-
}).flat()
|
|
213
|
-
|
|
214
|
-
// console.log('lines', lines)
|
|
215
|
-
var isEnding = /(['"}\]]|true,?|false,?)$/
|
|
216
|
-
// var isEnding = /(['"}\]]|true,?|false,?|[A-Za-z0-9"']+,?)$/ // false positive on arrays
|
|
217
|
-
var isKeyValNoQuotes = /^[A-Za-z]+=[A-Za-z0-9!*_\-\/\\]/
|
|
218
|
-
//var isKeyValNoQuotes = /^[A-Za-z]+=\S+/
|
|
219
|
-
|
|
220
|
-
// @TODO Get real json matcher
|
|
221
|
-
var isJsonLike = /[{[]/
|
|
222
|
-
|
|
223
|
-
const values = lines.reduce((acc, curr, i) => {
|
|
224
|
-
let alreadyAdded = false
|
|
225
|
-
const isLastLoop = lines.length === (i + 1)
|
|
226
|
-
const nextItem = lines[i + 1] || ''
|
|
227
|
-
const hasText = curr.match(STARTS_WITH_VALID_CHAR)
|
|
228
|
-
/*
|
|
229
|
-
console.log('___________________')
|
|
230
|
-
console.log('isLastLoop', isLastLoop)
|
|
231
|
-
console.log('RESERVED', acc[RESERVED])
|
|
232
|
-
console.log("current item", `|${curr}|`)
|
|
233
|
-
console.log('next item ', `|${nextItem}|`)
|
|
234
|
-
console.log('===================')
|
|
235
|
-
/** */
|
|
236
|
-
|
|
237
|
-
/* If has no = its a true boolean. e.g isThingy */
|
|
238
|
-
if (hasText && acc[RESERVED].match(STARTS_WITH_VALID_CHAR) && !isValuePair(acc[RESERVED])) {
|
|
239
|
-
// console.log('xxxxxxx', acc[RESERVED])
|
|
240
|
-
acc[acc[RESERVED]] = true
|
|
241
|
-
acc[RESERVED] = ''
|
|
242
|
-
// return fails, need to refine which runs first
|
|
243
|
-
// return acc
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* If has no = its a true boolean
|
|
247
|
-
if (
|
|
248
|
-
hasText
|
|
249
|
-
&& !curr.match(isEnding)
|
|
250
|
-
&& acc[RESERVED].match(isEnding)
|
|
251
|
-
&& !acc[RESERVED].match(isJsonLike)
|
|
252
|
-
) {
|
|
253
|
-
console.log('end', curr)
|
|
254
|
-
// console.log('acc[RESERVED]', acc[RESERVED])
|
|
255
|
-
const kv = getKeyAndValueFromString(acc[RESERVED], 'boolean')
|
|
256
|
-
if (kv) {
|
|
257
|
-
acc[kv.key] = kv.value
|
|
258
|
-
acc[RESERVED] = ''
|
|
259
|
-
return acc
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
*/
|
|
263
|
-
|
|
264
|
-
if (!acc[RESERVED].match(/^[A-Za-z]+={+/) && isValuePair(curr) && curr.match(isEnding)) {
|
|
265
|
-
const kv = getKeyAndValueFromString(curr, 'one')
|
|
266
|
-
// console.log('kv', kv)
|
|
267
|
-
if (kv) {
|
|
268
|
-
// console.log(`ADDED`, kv)
|
|
269
|
-
acc[kv.key] = kv.value
|
|
270
|
-
return acc
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (curr.match(isKeyValNoQuotes)) {
|
|
275
|
-
// console.log('curr', curr)
|
|
276
|
-
const kv = getKeyAndValueFromString(curr, 'curr.match(isKeyValNoQuotes)')
|
|
277
|
-
// console.log('no quotes')
|
|
278
|
-
if (kv) {
|
|
279
|
-
acc[kv.key] = kv.value
|
|
280
|
-
return acc
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const updated = acc[RESERVED] + curr
|
|
285
|
-
// console.log('SET reserve', `"${updated}"`)
|
|
286
|
-
if (!updated.match(isEnding) && updated.match(isKeyValNoQuotes)) {
|
|
287
|
-
// console.log('UPDATED HERE', updated)
|
|
288
|
-
const kv = getKeyAndValueFromString(updated, 'fall')
|
|
289
|
-
if (kv) {
|
|
290
|
-
acc[kv.key] = kv.value
|
|
291
|
-
acc[RESERVED] = ''
|
|
292
|
-
return acc
|
|
293
|
-
}
|
|
294
|
-
} else {
|
|
295
|
-
// Handle trailing option commas funny='what', funky="cool", weird=what, case
|
|
296
|
-
if (!updated.match(isJsonLike) && updated.match(TRAILING_COMMAS)) {
|
|
297
|
-
const kv = getKeyAndValueFromString(updated.replace(TRAILING_COMMAS, ''), 'commas')
|
|
298
|
-
acc[kv.key] = kv.value
|
|
299
|
-
acc[RESERVED] = ''
|
|
300
|
-
return acc
|
|
301
|
-
}
|
|
302
|
-
// console.log('ALREADy', updated)
|
|
303
|
-
alreadyAdded = true
|
|
304
|
-
acc[RESERVED] = updated
|
|
305
|
-
//return acc
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (
|
|
309
|
-
acc[RESERVED].match(isEnding)
|
|
310
|
-
&& nextItem.match(/^[A-Za-z0-9_-]/)
|
|
311
|
-
&& isBalanced(acc[RESERVED]) // If value is balanced brackets {[()]}
|
|
312
|
-
) {
|
|
313
|
-
const kv = getKeyAndValueFromString(acc[RESERVED], 'xxxx')
|
|
314
|
-
if (kv) {
|
|
315
|
-
acc[kv.key] = kv.value
|
|
316
|
-
acc[RESERVED] = ''
|
|
317
|
-
return acc
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// If ends in number foo=2 or bar=3, but ignore foo=[2 and foo=[{2
|
|
322
|
-
if (isValuePair(curr) && curr.match(/\d,?$/) && !curr.match(/=\{?\[/)) {
|
|
323
|
-
const kv = getKeyAndValueFromString(acc[RESERVED], 'numberMatch')
|
|
324
|
-
if (kv) {
|
|
325
|
-
acc[kv.key] = kv.value
|
|
326
|
-
acc[RESERVED] = ''
|
|
327
|
-
return acc
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (!isLastLoop) {
|
|
332
|
-
return acc
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// If last loop and still no match and looks like KV. Parse it
|
|
336
|
-
if (isLastLoop) {
|
|
337
|
-
// console.log("acc[RESERVED]", acc[RESERVED])
|
|
338
|
-
// console.log('acc[RESERVED] + curr', acc[RESERVED] + curr)
|
|
339
|
-
/* If value empty but __private have accumulated values */
|
|
340
|
-
if (acc[RESERVED]) {
|
|
341
|
-
// if (acc[RESERVED] && (acc[RESERVED].match(isEnding) || isValuePair(acc[RESERVED]))) {
|
|
342
|
-
const valueToCheck = (curr.match(isEnding) && !alreadyAdded) ? acc[RESERVED] + curr : acc[RESERVED]
|
|
343
|
-
// console.log('valueToCheck', valueToCheck)
|
|
344
|
-
const kv = getKeyAndValueFromString(valueToCheck, 'lastLoop')
|
|
345
|
-
if (kv) {
|
|
346
|
-
acc[kv.key] = kv.value
|
|
347
|
-
acc[RESERVED] = ''
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return acc
|
|
353
|
-
}, {
|
|
354
|
-
[RESERVED]: '',
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
// console.log('values', values)
|
|
358
|
-
delete values[RESERVED]
|
|
359
|
-
|
|
360
|
-
return values
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
function isValuePair(str) {
|
|
364
|
-
return str.match(/=/) // && !str.match(/=\[/)
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// https://melvingeorge.me/blog/check-if-string-contain-emojis-javascript OR https://www.npmjs.com/package/emoji-regex
|
|
368
|
-
function hasEmoji(str) {
|
|
369
|
-
const regexExp = /^(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/gi;
|
|
370
|
-
return regexExp.test(str)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Verify brackets are balanced
|
|
375
|
-
* @param {string} str - string with code
|
|
376
|
-
* @return {Boolean}
|
|
377
|
-
*/
|
|
378
|
-
function isBalanced(str) {
|
|
379
|
-
return !str.split('').reduce((uptoPrevChar, thisChar) => {
|
|
380
|
-
if (thisChar === '(' || thisChar === '{' || thisChar === '[') {
|
|
381
|
-
return ++uptoPrevChar
|
|
382
|
-
} else if (thisChar === ')' || thisChar === '}' || thisChar === ']') {
|
|
383
|
-
return --uptoPrevChar
|
|
384
|
-
}
|
|
385
|
-
return uptoPrevChar
|
|
386
|
-
}, 0)
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
function getKeyAndValueFromString(string, callLocation) {
|
|
390
|
-
/*
|
|
391
|
-
console.log(`getKeyAndValueFromString from ${callLocation}`)
|
|
392
|
-
console.log(`|${string}|`)
|
|
393
|
-
/** */
|
|
394
|
-
if (!string) return
|
|
395
|
-
// const keyValueRegex = /([A-Za-z-_$]+)=['{"]?(.*)['}"]?/g
|
|
396
|
-
// const match = keyValueRegex.exec(string)
|
|
397
|
-
// if (!match) {
|
|
398
|
-
// return
|
|
399
|
-
// }
|
|
400
|
-
// console.log('getKeyAndValueFromString')
|
|
401
|
-
const [key] = string.split('=')
|
|
402
|
-
/* If no key or key starts with --- */
|
|
403
|
-
if (!key || key.charAt(0) === '-' || hasEmoji(key)) {
|
|
404
|
-
return
|
|
405
|
-
}
|
|
406
|
-
// console.log('string', string)
|
|
407
|
-
|
|
408
|
-
// console.log('values', values)
|
|
409
|
-
/* If no value, isThing === true */
|
|
410
|
-
const hasEqual = string.indexOf('=') > -1
|
|
411
|
-
if (!hasEqual) {
|
|
412
|
-
return {
|
|
413
|
-
key,
|
|
414
|
-
value: true,
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
let value = string.substring(string.indexOf('=') + 1)
|
|
419
|
-
// Trim trailing commas
|
|
420
|
-
.replace(TRAILING_COMMAS, '')
|
|
421
|
-
|
|
422
|
-
/*
|
|
423
|
-
console.log('key', key)
|
|
424
|
-
console.log('value', value)
|
|
425
|
-
/** */
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const leadingCurleyBrackets = value.match(/^{{2,}/)
|
|
429
|
-
const trailingCurleyBrackets = value.match(/}{2,}$/)
|
|
430
|
-
if (leadingCurleyBrackets && trailingCurleyBrackets) {
|
|
431
|
-
const len = leadingCurleyBrackets[0].length <= trailingCurleyBrackets[0].length ? leadingCurleyBrackets : trailingCurleyBrackets
|
|
432
|
-
const trimLength = len[0].length
|
|
433
|
-
const trimLeading = new RegExp(`^{{${trimLength}}`)
|
|
434
|
-
const trimTrailing = new RegExp(`}{${trimLength}}$`)
|
|
435
|
-
if (trimLength) {
|
|
436
|
-
value = value
|
|
437
|
-
// Trim extra leading brackets
|
|
438
|
-
.replace(trimLeading, '{')
|
|
439
|
-
// Trim extra trailing brackets
|
|
440
|
-
.replace(trimTrailing, '}')
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// console.log('xvalue', value)
|
|
445
|
-
// let value = value
|
|
446
|
-
// .replace(/^{{2,}/, '{')
|
|
447
|
-
// .replace(/}{2,}$/, '}')
|
|
448
|
-
// .replace(/^\[{2,}/, '[')
|
|
449
|
-
// .replace(/\]{2,}$/, ']')
|
|
450
|
-
|
|
451
|
-
// If Doesn't look like JSON object
|
|
452
|
-
if (value.match(/^{[^:,]*}/)) {
|
|
453
|
-
value = removeSurroundingBrackets(value)
|
|
454
|
-
// If looks like array in brackets {[ thing, thing, thing ]}
|
|
455
|
-
} else if (value.match(/^{\s*\[\s*[^:]*\s*\]\s*\}/)) {
|
|
456
|
-
// Match { [ one, two ,3,4 ] }
|
|
457
|
-
value = removeSurroundingBrackets(value)
|
|
458
|
-
// If matches {` stuff `} & {[ stuff ]}
|
|
459
|
-
} else if (value.match(/^{(?:`|\[)([\s\S]*?)(?:`|\])}$/)) {
|
|
460
|
-
value = removeSurroundingBrackets(value)
|
|
461
|
-
}
|
|
462
|
-
// console.log('value', value)
|
|
463
|
-
|
|
464
|
-
/* Check if remaining value is surrounded by quotes */
|
|
465
|
-
const surroundingQuotes = value.match(SURROUNDING_QUOTES) || []
|
|
466
|
-
const hasSurroundingQuotes = surroundingQuotes.length === 2 && (surroundingQuotes[0] === surroundingQuotes[1])
|
|
467
|
-
/*
|
|
468
|
-
console.log('surroundingQuotes', surroundingQuotes)
|
|
469
|
-
console.log('hasSurroundingQuotes', hasSurroundingQuotes)
|
|
470
|
-
/** */
|
|
471
|
-
|
|
472
|
-
// console.log('yvalue', value)
|
|
473
|
-
return {
|
|
474
|
-
key,
|
|
475
|
-
value: hasSurroundingQuotes ? value.replace(SURROUNDING_QUOTES, '') : convert(value),
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function removeSurroundingBrackets(val) {
|
|
480
|
-
return val.replace(/^{/, '').replace(/}$/, '')
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Parse string of key value options. Template tag version
|
|
485
|
-
* @param {string} input - string of options. Can be multiline
|
|
486
|
-
* @returns {Record<string, any>}
|
|
487
|
-
*/
|
|
488
|
-
function options(input = '', ...substitutions) {
|
|
489
|
-
let str = String.raw(input, ...substitutions)
|
|
490
|
-
return optionsParse(str)
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
module.exports = {
|
|
494
|
-
isArrayLike,
|
|
495
|
-
isObjectLike,
|
|
496
|
-
optionsParse,
|
|
497
|
-
options
|
|
498
|
-
}
|