markdown-magic 2.5.1 → 2.6.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 +20 -0
- package/cli.js +0 -0
- package/lib/index.js +219 -0
- package/lib/processFile.js +2 -1
- package/lib/transforms/toc.js +5 -3
- package/lib/updateContents.js +8 -2
- package/lib/utils/_md.test.js +63 -0
- package/lib/utils/new-parser.js +412 -0
- package/lib/utils/new-parser.test.js +324 -0
- package/lib/utils/regex.js +20 -6
- package/lib/utils/weird-parse.js +230 -0
- package/lib/utils/weird-parse.test.js +217 -0
- package/package.json +17 -3
- package/.github/FUNDING.yml +0 -1
- package/.github/workflows/test.yml +0 -40
- package/.travis.yml +0 -10
- package/examples/basic-usage.js +0 -5
- package/examples/generate-readme.js +0 -37
- package/examples/package.json +0 -14
- package/examples/plugin-example.js +0 -16
- package/markdown.config.js +0 -13
- package/test/fixtures/CODE-test.md +0 -21
- package/test/fixtures/CUSTOM-async.md +0 -9
- package/test/fixtures/CUSTOM-test.md +0 -9
- package/test/fixtures/FILE-test.md +0 -11
- package/test/fixtures/REMOTE-test.md +0 -12
- package/test/fixtures/TOC-test.md +0 -39
- package/test/fixtures/custom-match-word-test.md +0 -9
- package/test/fixtures/local-code-file-lines.js +0 -6
- package/test/fixtures/local-code-file.js +0 -6
- package/test/fixtures/nested/file.md +0 -9
- package/test/fixtures/test.md +0 -432
- package/test/main.test.js +0 -319
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
const { inspect } = require('util')
|
|
2
|
+
const { test } = require('uvu')
|
|
3
|
+
const assert = require('uvu/assert')
|
|
4
|
+
const weirdParse = require('./weird-parse')
|
|
5
|
+
const { parseBlocks } = require('./new-parser')
|
|
6
|
+
|
|
7
|
+
function deepLog(v) {
|
|
8
|
+
console.log(inspect(v, {showHidden: false, depth: null}))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const md = `<h1 id="jdjdj">Netlify + FaunaDB
|
|
12
|
+
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-faunadb-example&stack=fauna">
|
|
13
|
+
<img src="https://www.netlify.com/img/deploy/button.svg">
|
|
14
|
+
</a>
|
|
15
|
+
</h1>
|
|
16
|
+
|
|
17
|
+
<\!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
|
|
18
|
+
nice
|
|
19
|
+
<\!-- XYZ:END -->
|
|
20
|
+
|
|
21
|
+
<\!-- XYZ:START {functionName} foo={{ rad: 'blue' }} -->
|
|
22
|
+
nice
|
|
23
|
+
<\!-- XYZ:END -->
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
<\!-- XYZ:START {functionName} foo={{ rad: 'red' }} -->
|
|
27
|
+
nice
|
|
28
|
+
<\!-- XYZ:END -->
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
<\!-- XYZ:START [wootName] foo=['one', 'two'] -->
|
|
32
|
+
nice
|
|
33
|
+
<\!-- XYZ:END -->
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
<\!-- XYZ:START -->
|
|
37
|
+
lol
|
|
38
|
+
<\!-- XYZ:END -->
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<\!-- xyz:start (lowerCase) foo=['one', 'two'] heading=false -->
|
|
42
|
+
nice
|
|
43
|
+
<\!-- XYZ:END -->
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<\!-- XYZ:START(cool)
|
|
47
|
+
width={999}
|
|
48
|
+
height={{111}}
|
|
49
|
+
numberAsString="12345"
|
|
50
|
+
great={["scoot", "sco ot", 'scooo ttt']}
|
|
51
|
+
nice={{ value: nice, cool: "true" }}
|
|
52
|
+
soclose=[jdjdjd, hdhfhfhffh]
|
|
53
|
+
rad="boss"
|
|
54
|
+
cool=true notCool=false
|
|
55
|
+
nooooo={[one, two, 3, 4]}
|
|
56
|
+
numberZero=0,
|
|
57
|
+
xyz=999,
|
|
58
|
+
nope=false,
|
|
59
|
+
// comment
|
|
60
|
+
yes={true} -->
|
|
61
|
+
|
|
62
|
+
actual content
|
|
63
|
+
|
|
64
|
+
<\!-- XYZ:END -->
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
<img src="https://www.netlify.com/img/deploy/button.svg"/>
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
<img src="https://www.hehhehehehe.com/img/deploy/button.svg" />
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
<\!-- XYZ:START(cool) xxx
|
|
74
|
+
hhddh=cool -->
|
|
75
|
+
wowow
|
|
76
|
+
whatever we want
|
|
77
|
+
<\!-- XYZ:END -->
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
<\!-- XYZ:START(hhh) -->
|
|
81
|
+
xyz
|
|
82
|
+
<\!-- XYZ:END -->
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
<\!-- XYZ:START(cool) isCool -->
|
|
86
|
+
nice
|
|
87
|
+
<\!-- XYZ:END -->
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
<button
|
|
91
|
+
great={[one, two, 3, 4]}
|
|
92
|
+
>
|
|
93
|
+
wow
|
|
94
|
+
</button>
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
<\!-- XYZ:START(niceeeee)
|
|
98
|
+
xxx
|
|
99
|
+
// comment here
|
|
100
|
+
hhddh=cool
|
|
101
|
+
-->
|
|
102
|
+
contents
|
|
103
|
+
<\!-- XYZ:END -->
|
|
104
|
+
|
|
105
|
+
<button
|
|
106
|
+
width={999}
|
|
107
|
+
great={["scoot", "scoot"]}
|
|
108
|
+
nice={{ value: nice, cool: true }}
|
|
109
|
+
rad="boss"
|
|
110
|
+
cool=true
|
|
111
|
+
nope=false
|
|
112
|
+
what='xnxnx'
|
|
113
|
+
isLoading
|
|
114
|
+
src="https://user-images.githubusercontent.com/532272/123136878-46f1a300-d408-11eb-82f2-ad452498457b.jpg"
|
|
115
|
+
>
|
|
116
|
+
coooooll
|
|
117
|
+
</button>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
<hr />
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
<br />
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
<ReactComponent>lolol</ReactComponent>
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
<ReactComponent width={123} lol={["no", "cool"]}>
|
|
130
|
+
lolol
|
|
131
|
+
</ReactComponent>
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
<OtherComponent width={123} lol={["no", "cool"]} nice={{ value: "nice", cool: true }}>
|
|
135
|
+
lolol
|
|
136
|
+
</OtherComponent>
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
<table style="width:100%">
|
|
140
|
+
<tr>
|
|
141
|
+
<th>Firstname</th>
|
|
142
|
+
<th>Lastname</th>
|
|
143
|
+
<th>Age</th>
|
|
144
|
+
</tr>
|
|
145
|
+
<tr>
|
|
146
|
+
<td>Jill</td>
|
|
147
|
+
<td>Smith</td>
|
|
148
|
+
<td>50</td>
|
|
149
|
+
</tr>
|
|
150
|
+
<tr>
|
|
151
|
+
<td>Eve</td>
|
|
152
|
+
<td>Jackson</td>
|
|
153
|
+
<td>94</td>
|
|
154
|
+
</tr>
|
|
155
|
+
</table>
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
<div>
|
|
159
|
+
<p>
|
|
160
|
+
<img align="right" isLoading={false} width="250" src="https://user-images.githubusercontent.com/532272/123136878-46f1a300-d408-11eb-82f2-ad452498457b.jpg" />
|
|
161
|
+
</p>
|
|
162
|
+
<p>
|
|
163
|
+
cool
|
|
164
|
+
</p>
|
|
165
|
+
<div>
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
<p>
|
|
169
|
+
<img align="left" width="250" src="https://user-images.githubusercontent.com/532272/123136889-4953fd00-d408-11eb-8a3e-f82f1d073298.jpg" />
|
|
170
|
+
</p>
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
Add a little magic to your markdown
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
## About
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
<img align="right" width="200" height="183" src="https://cloud.githubusercontent.com/assets/532272/21507867/3376e9fe-cc4a-11e6-9350-7ec4f680da36.gif" />Markdown magic uses comment blocks in markdown files to automatically sync or transform its contents.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
Markdown magic uses comment blocks in markdown files to automatically sync or transform its contents. <img align="right" width="200" height="183" src="https://cloud.githubusercontent.com/assets/532272/21507867/3376e9fe-cc4a-11e6-9350-7ec4f680da36.gif" />
|
|
183
|
+
`
|
|
184
|
+
|
|
185
|
+
test('parser', () => {
|
|
186
|
+
const parsedValue = parseBlocks(md)
|
|
187
|
+
/*
|
|
188
|
+
console.log('parsedValue')
|
|
189
|
+
deepLog(parsedValue)
|
|
190
|
+
/** */
|
|
191
|
+
assert.equal(true, true)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const inlineOne = `<!--XYZ:START functionName foo={{ rad: 'bar' }}-->99<!--XYZ:END-->`
|
|
195
|
+
const inlineTwo = ` <!-- XYZ:START transformX foo=111 -->99<!-- XYZ:END -->`
|
|
196
|
+
test('inline parser', () => {
|
|
197
|
+
const one = parseBlocks(inlineOne)
|
|
198
|
+
/*
|
|
199
|
+
console.log('inline one')
|
|
200
|
+
deepLog(one)
|
|
201
|
+
/** */
|
|
202
|
+
// assert.equal(one, [
|
|
203
|
+
// {
|
|
204
|
+
// transform: 'functionName',
|
|
205
|
+
// args: { foo: { rad: 'bar' } },
|
|
206
|
+
// location: 66
|
|
207
|
+
// }
|
|
208
|
+
// ])
|
|
209
|
+
const two = parseBlocks(inlineTwo)
|
|
210
|
+
//*
|
|
211
|
+
console.log('inline two ───────────────────────')
|
|
212
|
+
deepLog(two)
|
|
213
|
+
/** */
|
|
214
|
+
assert.equal(two, [
|
|
215
|
+
{ transform: 'transformX', args: { foo: 111 }, location: 55 }
|
|
216
|
+
])
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
const fnBlocks = `
|
|
220
|
+
<!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
|
|
221
|
+
nice
|
|
222
|
+
<!-- XYZ:END -->
|
|
223
|
+
|
|
224
|
+
<!-- XYZ:START {functionName} foo={{ rad: 'blue' }} -->
|
|
225
|
+
nice
|
|
226
|
+
<!-- XYZ:END -->
|
|
227
|
+
|
|
228
|
+
<!-- XYZ:START (functionName) foo={{ rad: 'red' }} -->
|
|
229
|
+
nice
|
|
230
|
+
<!-- XYZ:END -->
|
|
231
|
+
|
|
232
|
+
<!-- XYZ:START [functionName] foo={{ rad: 'purple' }} -->
|
|
233
|
+
nice
|
|
234
|
+
<!-- XYZ:END -->
|
|
235
|
+
|
|
236
|
+
<!-- XYZ:START {{functionName}} foo={{ rad: 'black' }} -->
|
|
237
|
+
nice
|
|
238
|
+
<!-- XYZ:END -->
|
|
239
|
+
|
|
240
|
+
<!-- XYZ:START ((functionName)) foo={{ rad: 'white' }} -->
|
|
241
|
+
nice
|
|
242
|
+
<!-- XYZ:END -->
|
|
243
|
+
|
|
244
|
+
<!-- XYZ:START [[functionName]] foo={{ rad: 'orange' }} -->
|
|
245
|
+
nice
|
|
246
|
+
<!-- XYZ:END -->
|
|
247
|
+
`
|
|
248
|
+
|
|
249
|
+
test('function names', () => {
|
|
250
|
+
const parsedValue = parseBlocks(fnBlocks)
|
|
251
|
+
/*
|
|
252
|
+
console.log('fn names')
|
|
253
|
+
deepLog(parsedValue)
|
|
254
|
+
/** */
|
|
255
|
+
assert.equal(parsedValue, [
|
|
256
|
+
{
|
|
257
|
+
transform: 'functionName',
|
|
258
|
+
args: { foo: { rad: 'yellow' } },
|
|
259
|
+
location: 78
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
transform: 'functionName',
|
|
263
|
+
args: { foo: { rad: 'blue' } },
|
|
264
|
+
location: 157
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
transform: 'functionName',
|
|
268
|
+
args: { foo: { rad: 'red' } },
|
|
269
|
+
location: 235
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
transform: 'functionName',
|
|
273
|
+
args: { foo: { rad: 'purple' } },
|
|
274
|
+
location: 316
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
transform: 'functionName',
|
|
278
|
+
args: { foo: { rad: 'black' } },
|
|
279
|
+
location: 398
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
transform: 'functionName',
|
|
283
|
+
args: { foo: { rad: 'white' } },
|
|
284
|
+
location: 480
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
transform: 'functionName',
|
|
288
|
+
args: { foo: { rad: 'orange' } },
|
|
289
|
+
location: 563
|
|
290
|
+
}
|
|
291
|
+
])
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
const backwardCompat = `
|
|
296
|
+
<!-- XYZ:START functionName foo={{ rad: 'yellow' }} -->
|
|
297
|
+
nice
|
|
298
|
+
<!-- XYZ:END -->
|
|
299
|
+
|
|
300
|
+
<!-- XYZ:START lol width={999}
|
|
301
|
+
height={{111}}
|
|
302
|
+
numberAsString="12345"
|
|
303
|
+
great={["scoot", "sco ot", 'scooo ttt']}
|
|
304
|
+
nope=false -->
|
|
305
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer vitae mauris arcu, eu pretium nisi. Praesent fringilla ornare ullamcorper. Pellentesque diam orci, sodales in blandit ut, placerat quis felis. Vestibulum at sem massa, in tempus nisi. Vivamus ut fermentum odio. Etiam porttitor faucibus volutpat. Vivamus vitae mi ligula, non hendrerit urna. Suspendisse potenti. Quisque eget massa a massa semper mollis.
|
|
306
|
+
<!-- XYZ:END -->
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
<!-- XYZ:START (CODE:src=./relative/path/to/code.js&lines=22-44) -->
|
|
310
|
+
This content will be dynamically replaced with code from the file lines 22 through 44
|
|
311
|
+
<!-- XYZ:END -->
|
|
312
|
+
`
|
|
313
|
+
|
|
314
|
+
test.only('function names', () => {
|
|
315
|
+
const parsedValue = parseBlocks(backwardCompat)
|
|
316
|
+
//*
|
|
317
|
+
console.log('backwardCompat')
|
|
318
|
+
deepLog(parsedValue)
|
|
319
|
+
/** */
|
|
320
|
+
// assert.equal(parsedValue, [])
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
test.run()
|
package/lib/utils/regex.js
CHANGED
|
@@ -15,11 +15,6 @@ module.exports.matchClosingCommentTag = function (word) {
|
|
|
15
15
|
|
|
16
16
|
module.exports.removeLeadingAndTrailingLineBreaks = /^(?:[\t ]*(?:\r?\n|\r))+|\s+$/g
|
|
17
17
|
|
|
18
|
-
// Regex to remove all comment blocks
|
|
19
|
-
const removeCommentsREGEX = / *?\<\!-- ([\s\S]*?) ?--\>\n\n*?/g
|
|
20
|
-
// content.replace(removeComments, '')
|
|
21
|
-
|
|
22
|
-
|
|
23
18
|
const jsRegex = /\/\* Step([\s\S]*?)\*\//g
|
|
24
19
|
const ymlRegex = / *?# Step([\s\S]*?) #\n*?/g
|
|
25
20
|
const htmlRegex = / *?\<\!-- Step([\s\S]*?) ?--\>\n*?/
|
|
@@ -59,4 +54,23 @@ function getSteps() {
|
|
|
59
54
|
}).map((item) => {
|
|
60
55
|
return item.value
|
|
61
56
|
})
|
|
62
|
-
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Regex to remove all comment blocks
|
|
60
|
+
const REMOVE_COMMENTS_REGEX = / *?\<\!-- ([\s\S]*?) ?--\>\n\n*?/g
|
|
61
|
+
// content.replace(removeComments, '')
|
|
62
|
+
|
|
63
|
+
// https://github.com/vendia/blog/commit/0c231fa928423ab050fbdb8d308eaa905b553aff
|
|
64
|
+
const HIDDEN_FRONTMATTER_REGEX = /^<!--.*((.|\r?\n)*?.*-->)/g
|
|
65
|
+
const FRONTMATTER_REGEX = /^---.*((.|\r?\n)*?.*---)/g
|
|
66
|
+
|
|
67
|
+
const LEADING_NEW_LINE_REGEX = /^(\r?\n|\r)/
|
|
68
|
+
const SQUARE_BRACKETS_REGEX = /^\[(\\.|[^\]])+\]/
|
|
69
|
+
const TABEL_ROW_REGEX = /^\s*\|.*?\|\s*$/
|
|
70
|
+
/**
|
|
71
|
+
* Validates whether a text is Markdown table row (starts and ends with a pipe).
|
|
72
|
+
*
|
|
73
|
+
* @param {string} text The text to validate.
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
const isTableRow = (text) => text.match(TABEL_ROW_REGEX);
|
|
@@ -0,0 +1,230 @@
|
|
|
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
|