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