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.
@@ -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 &nbsp;&nbsp;&nbsp;
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()
@@ -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