sugar-high 0.7.4 → 0.8.0
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.d.ts +13 -2
- package/lib/index.js +59 -28
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
type HighlightOptions = {
|
|
2
|
+
keywords?: Set<string>
|
|
3
|
+
onCommentStart?: (curr: string, next: string) => boolean
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function highlight(code: string, options?: HighlightOptions): string
|
|
7
|
+
export function tokenize(code: string, options?: HighlightOptions): Array<[number, string]>
|
|
3
8
|
export function generate(tokens: Array<[number, string]>): Array<any>
|
|
9
|
+
export const SugarHigh: {
|
|
10
|
+
TokenTypes: {
|
|
11
|
+
[key: number]: string
|
|
12
|
+
}
|
|
13
|
+
TokenMap: Map<string, number>
|
|
14
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const JSXBrackets = new Set(['<', '>', '{', '}', '[', ']'])
|
|
4
|
+
const Keywords_Js = new Set([
|
|
5
5
|
'for',
|
|
6
6
|
'do',
|
|
7
7
|
'while',
|
|
@@ -45,7 +45,7 @@ const keywords = new Set([
|
|
|
45
45
|
'static',
|
|
46
46
|
])
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const Signs = new Set([
|
|
49
49
|
'+',
|
|
50
50
|
'-',
|
|
51
51
|
'*',
|
|
@@ -73,9 +73,13 @@ const signs = new Set([
|
|
|
73
73
|
'#',
|
|
74
74
|
'@',
|
|
75
75
|
'\\',
|
|
76
|
-
...
|
|
76
|
+
...JSXBrackets,
|
|
77
77
|
])
|
|
78
78
|
|
|
79
|
+
const DefaultOptions = {
|
|
80
|
+
keywords: Keywords_Js,
|
|
81
|
+
onCommentStart: isCommentStart_Js,
|
|
82
|
+
}
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
85
|
*
|
|
@@ -92,7 +96,7 @@ const signs = new Set([
|
|
|
92
96
|
* 10 - space
|
|
93
97
|
*
|
|
94
98
|
*/
|
|
95
|
-
const
|
|
99
|
+
const TokenTypes = /** @type {const} */ ([
|
|
96
100
|
'identifier',
|
|
97
101
|
'keyword',
|
|
98
102
|
'string',
|
|
@@ -117,14 +121,14 @@ const [
|
|
|
117
121
|
T_COMMENT,
|
|
118
122
|
T_BREAK,
|
|
119
123
|
T_SPACE,
|
|
120
|
-
] = /** @types {const} */
|
|
124
|
+
] = /** @types {const} */ TokenTypes.map((_, i) => i)
|
|
121
125
|
|
|
122
126
|
function isSpaces(str) {
|
|
123
127
|
return /^[^\S\r\n]+$/g.test(str)
|
|
124
128
|
}
|
|
125
129
|
|
|
126
130
|
function isSign(ch) {
|
|
127
|
-
return
|
|
131
|
+
return Signs.has(ch)
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
function encode(str) {
|
|
@@ -175,20 +179,26 @@ function isStringQuotation(chr) {
|
|
|
175
179
|
return isSingleQuotes(chr) || isStrTemplateChr(chr)
|
|
176
180
|
}
|
|
177
181
|
|
|
178
|
-
function
|
|
179
|
-
str =
|
|
182
|
+
function isCommentStart_Js(curr, next) {
|
|
183
|
+
const str = curr + next
|
|
180
184
|
return str === '//' || str === '/*'
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
function isRegexStart(str) {
|
|
184
|
-
return str[0] === '/' && !
|
|
188
|
+
return str[0] === '/' && !isCommentStart_Js(str[0], str[1])
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
/**
|
|
188
192
|
* @param {string} code
|
|
193
|
+
* @param {{ keywords: Set<string> }} options
|
|
189
194
|
* @return {Array<[number, string]>}
|
|
190
195
|
*/
|
|
191
|
-
function tokenize(code) {
|
|
196
|
+
function tokenize(code, options) {
|
|
197
|
+
const {
|
|
198
|
+
keywords,
|
|
199
|
+
onCommentStart,
|
|
200
|
+
} = { ...DefaultOptions, ...options }
|
|
201
|
+
|
|
192
202
|
let current = ''
|
|
193
203
|
let type = -1
|
|
194
204
|
/** @type {[number, string]} */
|
|
@@ -220,9 +230,11 @@ function tokenize(code) {
|
|
|
220
230
|
|
|
221
231
|
/** @type {string | null} */
|
|
222
232
|
let __strQuote = null
|
|
233
|
+
let __regexQuoteStart = false
|
|
223
234
|
let __strTemplateExprStack = 0
|
|
224
235
|
let __strTemplateQuoteStack = 0
|
|
225
236
|
const inStringQuotes = () => __strQuote !== null
|
|
237
|
+
const inRegexQuotes = () => __regexQuoteStart
|
|
226
238
|
const inStrTemplateLiterals = () => (__strTemplateQuoteStack > __strTemplateExprStack)
|
|
227
239
|
const inStrTemplateExpr = () => __strTemplateQuoteStack > 0 && (__strTemplateQuoteStack === __strTemplateExprStack)
|
|
228
240
|
const inStringContent = () => inStringQuotes() || inStrTemplateLiterals()
|
|
@@ -275,12 +287,20 @@ function tokenize(code) {
|
|
|
275
287
|
}
|
|
276
288
|
}
|
|
277
289
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
290
|
+
/**
|
|
291
|
+
*
|
|
292
|
+
* @param {number} type_
|
|
293
|
+
* @param {string} token_
|
|
294
|
+
*/
|
|
295
|
+
const append = (type_, token_) => {
|
|
296
|
+
if (type_ || token_) {
|
|
297
|
+
const nType = TokenTypes[type_]
|
|
298
|
+
}
|
|
299
|
+
if (token_) {
|
|
300
|
+
current = token_
|
|
281
301
|
}
|
|
282
302
|
if (current) {
|
|
283
|
-
type =
|
|
303
|
+
type = type_ || classify(current)
|
|
284
304
|
/** @type [number, string] */
|
|
285
305
|
const pair = [type, current]
|
|
286
306
|
if (type !== T_SPACE && type !== T_BREAK) {
|
|
@@ -456,7 +476,13 @@ function tokenize(code) {
|
|
|
456
476
|
|
|
457
477
|
// current and next char can form a jsx open or close tag
|
|
458
478
|
if (curr === '<' && (next === '/' || isAlpha(next))) {
|
|
459
|
-
|
|
479
|
+
if (
|
|
480
|
+
!inStringContent() &&
|
|
481
|
+
!inJsxLiterals() &&
|
|
482
|
+
!inRegexQuotes()
|
|
483
|
+
) {
|
|
484
|
+
__jsxEnter = true
|
|
485
|
+
}
|
|
460
486
|
}
|
|
461
487
|
}
|
|
462
488
|
|
|
@@ -487,6 +513,7 @@ function tokenize(code) {
|
|
|
487
513
|
continue
|
|
488
514
|
}
|
|
489
515
|
|
|
516
|
+
__regexQuoteStart = true
|
|
490
517
|
const start = i++
|
|
491
518
|
|
|
492
519
|
// end of line of end of file
|
|
@@ -494,17 +521,20 @@ function tokenize(code) {
|
|
|
494
521
|
const isEol = () => isEof() || code[i] === '\n'
|
|
495
522
|
|
|
496
523
|
let foundClose = false
|
|
497
|
-
|
|
524
|
+
|
|
525
|
+
// traverse to find closing regex slash
|
|
498
526
|
for (; !isEol(); i++) {
|
|
499
527
|
if (code[i] === '/' && code[i - 1] !== '\\') {
|
|
500
528
|
foundClose = true
|
|
501
|
-
// append regex flags
|
|
529
|
+
// end of regex, append regex flags
|
|
502
530
|
while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
|
|
503
531
|
i++
|
|
504
532
|
}
|
|
505
533
|
break
|
|
506
534
|
}
|
|
507
535
|
}
|
|
536
|
+
__regexQuoteStart = false
|
|
537
|
+
|
|
508
538
|
if (start !== i && foundClose) {
|
|
509
539
|
// If current line is fully closed with string quotes or regex slashes,
|
|
510
540
|
// add them to tokens
|
|
@@ -516,7 +546,7 @@ function tokenize(code) {
|
|
|
516
546
|
append()
|
|
517
547
|
i = start
|
|
518
548
|
}
|
|
519
|
-
} else if (
|
|
549
|
+
} else if (onCommentStart(curr, next)) {
|
|
520
550
|
append()
|
|
521
551
|
const start = i
|
|
522
552
|
if (next === '/') {
|
|
@@ -551,9 +581,9 @@ function tokenize(code) {
|
|
|
551
581
|
__jsxExpr = false
|
|
552
582
|
} else if (
|
|
553
583
|
// it's jsx literals and is not a jsx bracket
|
|
554
|
-
(isJsxLiterals && !
|
|
584
|
+
(isJsxLiterals && !JSXBrackets.has(curr)) ||
|
|
555
585
|
// same type char as previous one in current token
|
|
556
|
-
((isWord(curr) === isWord(current[current.length - 1]) || __jsxChild()) && !
|
|
586
|
+
((isWord(curr) === isWord(current[current.length - 1]) || __jsxChild()) && !Signs.has(curr))
|
|
557
587
|
) {
|
|
558
588
|
current += curr
|
|
559
589
|
} else {
|
|
@@ -571,7 +601,7 @@ function tokenize(code) {
|
|
|
571
601
|
append()
|
|
572
602
|
i++
|
|
573
603
|
}
|
|
574
|
-
else if (
|
|
604
|
+
else if (JSXBrackets.has(curr)) append()
|
|
575
605
|
}
|
|
576
606
|
}
|
|
577
607
|
}
|
|
@@ -618,8 +648,8 @@ function generate(tokens) {
|
|
|
618
648
|
value: value, // to encode
|
|
619
649
|
}],
|
|
620
650
|
properties: {
|
|
621
|
-
className: `sh__token--${
|
|
622
|
-
style: `color: var(--sh-${
|
|
651
|
+
className: `sh__token--${TokenTypes[type]}`,
|
|
652
|
+
style: `color: var(--sh-${TokenTypes[type]})`,
|
|
623
653
|
},
|
|
624
654
|
}
|
|
625
655
|
))
|
|
@@ -680,10 +710,11 @@ function toHtml(lines) {
|
|
|
680
710
|
/**
|
|
681
711
|
*
|
|
682
712
|
* @param {string} code
|
|
713
|
+
* @param {{ keywords: Set<string> } | undefined} options
|
|
683
714
|
* @returns {string}
|
|
684
715
|
*/
|
|
685
|
-
function highlight(code) {
|
|
686
|
-
const tokens = tokenize(code)
|
|
716
|
+
function highlight(code, options) {
|
|
717
|
+
const tokens = tokenize(code, options)
|
|
687
718
|
const lines = generate(tokens)
|
|
688
719
|
const output = toHtml(lines)
|
|
689
720
|
return output
|
|
@@ -691,8 +722,8 @@ function highlight(code) {
|
|
|
691
722
|
|
|
692
723
|
// namespace
|
|
693
724
|
const SugarHigh = /** @type {const} */ {
|
|
694
|
-
TokenTypes
|
|
695
|
-
TokenMap: new Map(
|
|
725
|
+
TokenTypes,
|
|
726
|
+
TokenMap: new Map(TokenTypes.map((type, i) => [type, i])),
|
|
696
727
|
}
|
|
697
728
|
|
|
698
729
|
export {
|