sugar-high 0.4.1 → 0.4.4
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/lib/index.mjs +190 -72
- package/package.json +2 -2
package/lib/index.mjs
CHANGED
|
@@ -144,8 +144,16 @@ function isIdentifier(str) {
|
|
|
144
144
|
return isIdentifierChar(str[0]) && (str.length === 1 || isWord(str.slice(1)))
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
function isStrTemplateChr(chr) {
|
|
148
|
+
return chr === '`'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function isSingleQuotes(chr) {
|
|
152
|
+
return chr === '"' || chr === "'"
|
|
153
|
+
}
|
|
154
|
+
|
|
147
155
|
function isStringQuotation(chr) {
|
|
148
|
-
return chr
|
|
156
|
+
return isSingleQuotes(chr) || isStrTemplateChr(chr)
|
|
149
157
|
}
|
|
150
158
|
|
|
151
159
|
function isCommentStart(str) {
|
|
@@ -168,16 +176,28 @@ export function tokenize(code) {
|
|
|
168
176
|
/** @type {Array<[number, string]>} */
|
|
169
177
|
const tokens = []
|
|
170
178
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
let __jsxEnter = false
|
|
180
|
+
/**
|
|
181
|
+
* @type {0 | 1 | 2}
|
|
182
|
+
* 0 for not in jsx
|
|
183
|
+
* 1 for open jsx tag
|
|
184
|
+
* 2 for closing jsx tag
|
|
185
|
+
**/
|
|
186
|
+
let __jsxTag = 0
|
|
187
|
+
let __jsxExpr = false
|
|
188
|
+
|
|
189
|
+
// only match paired (open + close) tags, not self-closing tags
|
|
190
|
+
let __jsxStack = 0
|
|
191
|
+
const __jsxChild = () => __jsxEnter && !__jsxExpr && !__jsxTag
|
|
192
|
+
const inJsxTag = () => __jsxTag && !__jsxChild()
|
|
193
|
+
const inJsxLiterals = () => !__jsxTag && __jsxChild() && !__jsxExpr && __jsxStack > 0
|
|
194
|
+
|
|
195
|
+
/** @type {string | 0} */
|
|
196
|
+
let __strQuote = 0
|
|
197
|
+
let __strTemplateExprStack = 0
|
|
198
|
+
let __strTemplateQuoteStack = 0
|
|
199
|
+
const inStrTemplateLiterals = () => (__strTemplateQuoteStack > __strTemplateExprStack)
|
|
200
|
+
const inStrTemplateExpr = () => __strTemplateQuoteStack > 0 && (__strTemplateQuoteStack === __strTemplateExprStack)
|
|
181
201
|
|
|
182
202
|
/**
|
|
183
203
|
*
|
|
@@ -185,7 +205,10 @@ export function tokenize(code) {
|
|
|
185
205
|
* @returns {number}
|
|
186
206
|
*/
|
|
187
207
|
function classify(token) {
|
|
188
|
-
|
|
208
|
+
const isJsxLiterals = inJsxLiterals()
|
|
209
|
+
if (isJsxLiterals) {
|
|
210
|
+
return T_JSX_LITERALS
|
|
211
|
+
} else if (keywords.has(token)) {
|
|
189
212
|
return last[1] === '.' ? T_IDENTIFIER : T_KEYWORD
|
|
190
213
|
} else if (token === '\n') {
|
|
191
214
|
return T_BREAK
|
|
@@ -193,16 +216,17 @@ export function tokenize(code) {
|
|
|
193
216
|
return T_SPACE
|
|
194
217
|
} else if (token.split('').every(ch => signs.has(ch))) {
|
|
195
218
|
return T_SIGN
|
|
196
|
-
} else if (inJsxLiterals()) {
|
|
197
|
-
return T_JSX_LITERALS
|
|
198
219
|
} else if (isCls(token)) {
|
|
199
220
|
return inJsxTag() ? T_IDENTIFIER : T_CLS_NUMBER
|
|
200
221
|
} else {
|
|
201
|
-
return isIdentifier(token) ? T_IDENTIFIER : T_STRING
|
|
222
|
+
return isIdentifier(token) && !inStrTemplateLiterals() && (__strQuote !== `"` && __strQuote !== `'`) ? T_IDENTIFIER : T_STRING
|
|
202
223
|
}
|
|
203
224
|
}
|
|
204
225
|
|
|
205
|
-
const append = (_type) => {
|
|
226
|
+
const append = (_type, _token) => {
|
|
227
|
+
if (_token) {
|
|
228
|
+
current = _token
|
|
229
|
+
}
|
|
206
230
|
if (current) {
|
|
207
231
|
type = _type || classify(current)
|
|
208
232
|
/** @type [number, string] */
|
|
@@ -220,36 +244,137 @@ export function tokenize(code) {
|
|
|
220
244
|
const next = code[i + 1]
|
|
221
245
|
const p_c = prev + curr // previous and current
|
|
222
246
|
const c_n = curr + next // current and next
|
|
223
|
-
const isJsxLiterals = inJsxLiterals()
|
|
224
247
|
|
|
225
|
-
if (
|
|
226
|
-
|
|
248
|
+
if (isSingleQuotes(curr)) {
|
|
249
|
+
append()
|
|
250
|
+
if (prev !== `\\`) {
|
|
251
|
+
if (__strQuote && curr === __strQuote) {
|
|
252
|
+
__strQuote = 0
|
|
253
|
+
} else if (!__strQuote) {
|
|
254
|
+
__strQuote = curr
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
append(T_STRING, curr)
|
|
259
|
+
continue
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (!inStrTemplateLiterals()) {
|
|
263
|
+
if (prev !== '\\n' && isStrTemplateChr(curr)) {
|
|
264
|
+
append()
|
|
265
|
+
append(T_STRING, curr)
|
|
266
|
+
__strTemplateQuoteStack++
|
|
267
|
+
continue
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (inStrTemplateLiterals()) {
|
|
272
|
+
if (prev !== '\\n' && isStrTemplateChr(curr)) {
|
|
273
|
+
if (__strTemplateQuoteStack > 0) {
|
|
274
|
+
append()
|
|
275
|
+
__strTemplateQuoteStack--
|
|
276
|
+
append(T_STRING, curr)
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (c_n === '${') {
|
|
282
|
+
__strTemplateExprStack++
|
|
283
|
+
append(T_STRING)
|
|
284
|
+
append(T_SIGN, c_n)
|
|
285
|
+
i++
|
|
286
|
+
continue
|
|
287
|
+
}
|
|
227
288
|
}
|
|
228
289
|
|
|
229
|
-
if (
|
|
230
|
-
|
|
290
|
+
if (inStrTemplateExpr() && curr === '}') {
|
|
291
|
+
append()
|
|
292
|
+
__strTemplateExprStack--
|
|
293
|
+
append(T_SIGN, curr)
|
|
294
|
+
continue
|
|
231
295
|
}
|
|
232
296
|
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
297
|
+
if (__jsxChild()) {
|
|
298
|
+
if (curr === '{') {
|
|
299
|
+
append()
|
|
300
|
+
append(T_SIGN, curr)
|
|
301
|
+
__jsxExpr = true
|
|
302
|
+
continue
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (__jsxEnter) {
|
|
307
|
+
// <: open tag sign
|
|
308
|
+
if (!__jsxTag && curr === '<') {
|
|
309
|
+
append()
|
|
310
|
+
__jsxTag = 1
|
|
311
|
+
current = curr
|
|
312
|
+
if (next === '/') {
|
|
313
|
+
__jsxTag = 2
|
|
314
|
+
current = c_n
|
|
315
|
+
i++
|
|
316
|
+
}
|
|
317
|
+
append(T_SIGN)
|
|
318
|
+
continue
|
|
319
|
+
}
|
|
320
|
+
if (__jsxTag) {
|
|
321
|
+
// >: open tag close sign or closing tag closing sign
|
|
322
|
+
if (curr === '>' && prev !== '/') {
|
|
323
|
+
append()
|
|
324
|
+
if (__jsxTag === 1) {
|
|
325
|
+
__jsxTag = 0
|
|
326
|
+
__jsxStack++
|
|
327
|
+
} else {
|
|
328
|
+
__jsxTag = 0
|
|
329
|
+
__jsxEnter = false
|
|
330
|
+
}
|
|
331
|
+
append(T_SIGN, curr)
|
|
332
|
+
continue
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// >: tag self close sign or close tag sign
|
|
336
|
+
if (c_n === '/>' || c_n === '</') {
|
|
337
|
+
append()
|
|
338
|
+
if (c_n === '/>') {
|
|
339
|
+
__jsxTag = 0
|
|
340
|
+
}
|
|
341
|
+
if (c_n === '</') {
|
|
342
|
+
__jsxStack--
|
|
343
|
+
}
|
|
344
|
+
current = c_n
|
|
345
|
+
i++
|
|
346
|
+
append(T_SIGN)
|
|
347
|
+
continue
|
|
348
|
+
}
|
|
237
349
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
350
|
+
// <: open tag sign
|
|
351
|
+
if (curr === '<') {
|
|
352
|
+
append()
|
|
353
|
+
current = curr
|
|
354
|
+
append(T_SIGN)
|
|
355
|
+
continue
|
|
356
|
+
}
|
|
242
357
|
}
|
|
243
358
|
}
|
|
359
|
+
|
|
244
360
|
// if it's not in a jsx tag declaration or a string, close child if next is jsx close tag
|
|
245
|
-
if (!
|
|
246
|
-
|
|
247
|
-
|
|
361
|
+
if (!__jsxTag && (curr === '<' && isIdentifierChar(next) || c_n === '</')) {
|
|
362
|
+
__jsxTag = next === '/' ? 2 : 1
|
|
363
|
+
|
|
364
|
+
if (curr === '<' && next !== '/') {
|
|
365
|
+
__jsxEnter = true
|
|
366
|
+
}
|
|
248
367
|
}
|
|
249
368
|
|
|
250
369
|
const isQuotationChar = isStringQuotation(curr)
|
|
251
|
-
const
|
|
252
|
-
|
|
370
|
+
const isStringTemplateLiterals = inStrTemplateLiterals()
|
|
371
|
+
const isRegexChar = !__jsxEnter && isRegexStart(c_n)
|
|
372
|
+
const isJsxLiterals = inJsxLiterals()
|
|
373
|
+
|
|
374
|
+
// string quotation
|
|
375
|
+
if (isQuotationChar || isStringTemplateLiterals || isSingleQuotes(__strQuote)) {
|
|
376
|
+
current += curr
|
|
377
|
+
} else if (isRegexChar) {
|
|
253
378
|
append()
|
|
254
379
|
const [lastType, lastToken] = last
|
|
255
380
|
// Special cases that are not considered as regex:
|
|
@@ -267,34 +392,23 @@ export function tokenize(code) {
|
|
|
267
392
|
append()
|
|
268
393
|
continue
|
|
269
394
|
}
|
|
395
|
+
|
|
270
396
|
const start = i++
|
|
271
|
-
const leftQuote = code[start]
|
|
272
|
-
let foundClose = false
|
|
273
397
|
|
|
274
398
|
// end of line of end of file
|
|
275
399
|
const isEof = () => i >= code.length
|
|
276
400
|
const isEol = () => isEof() || code[i] === '\n'
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
} else {
|
|
288
|
-
// regex
|
|
289
|
-
for (; !isEol(); i++) {
|
|
290
|
-
if (code[i] === '/' && code[i - 1] !== '\\') {
|
|
291
|
-
foundClose = true
|
|
292
|
-
// append regex flags
|
|
293
|
-
while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
|
|
294
|
-
i++
|
|
295
|
-
}
|
|
296
|
-
break
|
|
401
|
+
|
|
402
|
+
let foundClose = false
|
|
403
|
+
// regex
|
|
404
|
+
for (; !isEol(); i++) {
|
|
405
|
+
if (code[i] === '/' && code[i - 1] !== '\\') {
|
|
406
|
+
foundClose = true
|
|
407
|
+
// append regex flags
|
|
408
|
+
while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
|
|
409
|
+
i++
|
|
297
410
|
}
|
|
411
|
+
break
|
|
298
412
|
}
|
|
299
413
|
}
|
|
300
414
|
if (start !== i && foundClose) {
|
|
@@ -327,27 +441,38 @@ export function tokenize(code) {
|
|
|
327
441
|
)
|
|
328
442
|
) {
|
|
329
443
|
current += curr
|
|
444
|
+
if (next === '<') {
|
|
445
|
+
append()
|
|
446
|
+
}
|
|
330
447
|
} else {
|
|
331
448
|
append()
|
|
332
449
|
current = curr
|
|
333
450
|
append()
|
|
334
451
|
}
|
|
335
452
|
} else {
|
|
336
|
-
if (
|
|
453
|
+
if (__jsxExpr && curr === '}') {
|
|
454
|
+
append()
|
|
455
|
+
current = curr
|
|
456
|
+
append()
|
|
457
|
+
__jsxExpr = false
|
|
458
|
+
} else if (
|
|
337
459
|
// it's jsx literals and is not a jsx bracket
|
|
338
460
|
(isJsxLiterals && !jsxBrackets.has(curr)) ||
|
|
339
461
|
// same type char as previous one in current token
|
|
340
|
-
isWord(curr) === isWord(current[current.length - 1]) &&
|
|
341
|
-
!signs.has(curr)
|
|
462
|
+
((isWord(curr) === isWord(current[current.length - 1]) || __jsxChild()) && !signs.has(curr))
|
|
342
463
|
) {
|
|
343
464
|
current += curr
|
|
344
|
-
if (next === '<') {
|
|
345
|
-
append(T_JSX_LITERALS);
|
|
346
|
-
}
|
|
347
465
|
} else {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
466
|
+
if (p_c === '</') {
|
|
467
|
+
current = p_c
|
|
468
|
+
}
|
|
469
|
+
append()
|
|
470
|
+
|
|
471
|
+
if (p_c !== '</') {
|
|
472
|
+
current = curr
|
|
473
|
+
|
|
474
|
+
}
|
|
475
|
+
if ((c_n === '</' || c_n === '/>')) {
|
|
351
476
|
current = c_n
|
|
352
477
|
append()
|
|
353
478
|
i++
|
|
@@ -355,13 +480,6 @@ export function tokenize(code) {
|
|
|
355
480
|
else if (jsxBrackets.has(curr)) append()
|
|
356
481
|
}
|
|
357
482
|
}
|
|
358
|
-
|
|
359
|
-
if (jsx.child && curr === '{') {
|
|
360
|
-
jsx.expr = true
|
|
361
|
-
}
|
|
362
|
-
if (jsx.child && jsx.expr && curr === '}') {
|
|
363
|
-
jsx.expr = false
|
|
364
|
-
}
|
|
365
483
|
}
|
|
366
484
|
|
|
367
485
|
append()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sugar-high",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./lib/index.mjs",
|
|
6
6
|
"description": "Super lightweight JSX syntax highlighter",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"build": "next build docs"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"codice": "^0.0.
|
|
19
|
+
"codice": "^0.0.10",
|
|
20
20
|
"next": "12.1.6-canary.6",
|
|
21
21
|
"react": "18.0.0",
|
|
22
22
|
"react-dom": "18.0.0",
|