sugar-high 0.3.0 → 0.4.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 +15 -22
- package/lib/index.mjs +51 -25
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Super lightweight JSX syntax highlighter, around 1KB after minified and gzipped
|
|
5
5
|
|
|
6
|
-

|
|
7
7
|
|
|
8
8
|
### Usage
|
|
9
9
|
|
|
@@ -35,26 +35,14 @@ Then make your own theme with customized colors by token type and put in global
|
|
|
35
35
|
* comment
|
|
36
36
|
* jsxliterals
|
|
37
37
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
.sh__string {
|
|
48
|
-
color: #00a99a;
|
|
49
|
-
}
|
|
50
|
-
.sh__keyword {
|
|
51
|
-
color: #f47067;
|
|
52
|
-
}
|
|
53
|
-
.sh__comment {
|
|
54
|
-
color: #a19595;
|
|
55
|
-
}
|
|
56
|
-
.sh__jsxliterals {
|
|
57
|
-
color: #03066e;
|
|
38
|
+
:root {
|
|
39
|
+
--sh-class: #2d5e9d;
|
|
40
|
+
--sh-identifier: #354150;
|
|
41
|
+
--sh-sign: #8996a3;
|
|
42
|
+
--sh-string: #00a99a;
|
|
43
|
+
--sh-keyword: #f47067;
|
|
44
|
+
--sh-comment: #a19595;
|
|
45
|
+
--sh-jsxliterals: #6266d1;
|
|
58
46
|
}
|
|
59
47
|
```
|
|
60
48
|
|
|
@@ -65,8 +53,13 @@ Then make your own theme with customized colors by token type and put in global
|
|
|
65
53
|
Sugar high provide `.sh_line` class name for each line. To display line number, define the `.sh_line::before` element with CSS will enable line numbers automatically.
|
|
66
54
|
|
|
67
55
|
```css
|
|
56
|
+
pre code {
|
|
57
|
+
counter-reset: sh-line-number;
|
|
58
|
+
}
|
|
59
|
+
|
|
68
60
|
.sh__line::before {
|
|
69
|
-
|
|
61
|
+
counter-increment: sh-line-number 1;
|
|
62
|
+
content: counter(sh-line-number);
|
|
70
63
|
margin-right: 24px;
|
|
71
64
|
text-align: right;
|
|
72
65
|
color: #a4a4a4;
|
package/lib/index.mjs
CHANGED
|
@@ -129,6 +129,13 @@ function isWord(chr) {
|
|
|
129
129
|
return /^[\w_]+$/.test(chr)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
function isCls(str) {
|
|
133
|
+
const chr0 = str[0]
|
|
134
|
+
return isWord(chr0) &&
|
|
135
|
+
chr0 === chr0.toUpperCase() ||
|
|
136
|
+
str === 'null'
|
|
137
|
+
}
|
|
138
|
+
|
|
132
139
|
function isIdentifierChar(chr) {
|
|
133
140
|
return /^[a-zA-Z_$]$/.test(chr)
|
|
134
141
|
}
|
|
@@ -161,35 +168,37 @@ export function tokenize(code) {
|
|
|
161
168
|
/** @type {Array<[number, string]>} */
|
|
162
169
|
const tokens = []
|
|
163
170
|
|
|
164
|
-
// jsx.tag for entering open or closed
|
|
171
|
+
// jsx.tag for entering open or closed tags
|
|
172
|
+
// jsx.close for is the closing sign of open or close tags
|
|
165
173
|
// jsx.child for entering children
|
|
166
174
|
// jsx.expr for entering {expression}
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
// jsx.end for entering close tag
|
|
176
|
+
/** @type {{ tag: boolean; close: boolean; child: boolean; expr: boolean; end: boolean }} */
|
|
177
|
+
const jsx = { tag: false, close: false, child: false, expr: false, end: false }
|
|
169
178
|
|
|
170
|
-
const
|
|
179
|
+
const inJsxTag = () => jsx.tag || jsx.close
|
|
180
|
+
const inJsxLiterals = () => !inJsxTag() && jsx.child && !jsx.expr
|
|
171
181
|
|
|
182
|
+
/**
|
|
183
|
+
*
|
|
184
|
+
* @param {string} token
|
|
185
|
+
* @returns {number}
|
|
186
|
+
*/
|
|
172
187
|
function classify(token) {
|
|
173
|
-
const chr0 = token[0]
|
|
174
188
|
if (keywords.has(token)) {
|
|
175
|
-
return T_KEYWORD
|
|
189
|
+
return last[1] === '.' ? T_IDENTIFIER : T_KEYWORD
|
|
176
190
|
} else if (token === '\n') {
|
|
177
191
|
return T_BREAK
|
|
178
192
|
} else if (isSpaces(token)) {
|
|
179
193
|
return T_SPACE
|
|
180
194
|
} else if (token.split('').every(ch => signs.has(ch))) {
|
|
181
195
|
return T_SIGN
|
|
182
|
-
} else if (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
chr0 === chr0.toUpperCase() ||
|
|
187
|
-
token === 'null'
|
|
188
|
-
)
|
|
189
|
-
) {
|
|
190
|
-
return T_CLS_NUMBER
|
|
196
|
+
} else if (inJsxLiterals()) {
|
|
197
|
+
return T_JSX_LITERALS
|
|
198
|
+
} else if (isCls(token)) {
|
|
199
|
+
return inJsxTag() ? T_IDENTIFIER : T_CLS_NUMBER
|
|
191
200
|
} else {
|
|
192
|
-
return isIdentifier(token) ? T_IDENTIFIER :
|
|
201
|
+
return isIdentifier(token) ? T_IDENTIFIER : T_STRING
|
|
193
202
|
}
|
|
194
203
|
}
|
|
195
204
|
|
|
@@ -209,15 +218,28 @@ export function tokenize(code) {
|
|
|
209
218
|
const curr = code[i]
|
|
210
219
|
const prev = code[i - 1]
|
|
211
220
|
const next = code[i + 1]
|
|
212
|
-
const c_n = curr + next // current and next
|
|
213
221
|
const p_c = prev + curr // previous and current
|
|
222
|
+
const c_n = curr + next // current and next
|
|
214
223
|
const isJsxLiterals = inJsxLiterals()
|
|
215
224
|
|
|
225
|
+
if (jsx.close && (last[1] === '>' || last[1] === '/>')) {
|
|
226
|
+
jsx.close = false
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!jsx.tag && (c_n === '</' || c_n === '/>')) {
|
|
230
|
+
jsx.end = true
|
|
231
|
+
}
|
|
232
|
+
|
|
216
233
|
if (jsx.tag) {
|
|
217
234
|
const isOpenElementEnd = curr === '>'
|
|
218
235
|
const isCloseElementEnd = p_c === '/>'
|
|
219
|
-
jsx.child = !
|
|
236
|
+
jsx.child = !jsx.end && (isOpenElementEnd && !isCloseElementEnd)
|
|
237
|
+
|
|
220
238
|
jsx.tag = !(isOpenElementEnd || isCloseElementEnd)
|
|
239
|
+
jsx.close = isOpenElementEnd || isCloseElementEnd
|
|
240
|
+
if (jsx.end && (isCloseElementEnd || isOpenElementEnd)) {
|
|
241
|
+
jsx.end = false
|
|
242
|
+
}
|
|
221
243
|
}
|
|
222
244
|
// if it's not in a jsx tag declaration or a string, close child if next is jsx close tag
|
|
223
245
|
if (!jsx.tag && (curr === '<' && isIdentifierChar(next) || c_n === '</')) {
|
|
@@ -231,13 +253,13 @@ export function tokenize(code) {
|
|
|
231
253
|
append()
|
|
232
254
|
const [lastType, lastToken] = last
|
|
233
255
|
// Special cases that are not considered as regex:
|
|
234
|
-
// * (expr1) / expr2: `
|
|
256
|
+
// * (expr1) / expr2: `)` before `/` operator is still in expression
|
|
235
257
|
// * <non comment start>/ expr: non comment start before `/` is not regex
|
|
236
258
|
if (
|
|
237
259
|
isRegexChar &&
|
|
238
260
|
lastType &&
|
|
239
261
|
!(
|
|
240
|
-
(lastType === T_SIGN &&
|
|
262
|
+
(lastType === T_SIGN && ')' !== lastToken) ||
|
|
241
263
|
lastType === T_COMMENT
|
|
242
264
|
)
|
|
243
265
|
) {
|
|
@@ -312,13 +334,18 @@ export function tokenize(code) {
|
|
|
312
334
|
}
|
|
313
335
|
} else {
|
|
314
336
|
if (
|
|
337
|
+
// it's jsx literals and is not a jsx bracket
|
|
315
338
|
(isJsxLiterals && !jsxBrackets.has(curr)) ||
|
|
339
|
+
// same type char as previous one in current token
|
|
316
340
|
isWord(curr) === isWord(current[current.length - 1]) &&
|
|
317
341
|
!signs.has(curr)
|
|
318
342
|
) {
|
|
319
343
|
current += curr
|
|
344
|
+
if (next === '<') {
|
|
345
|
+
append(T_JSX_LITERALS);
|
|
346
|
+
}
|
|
320
347
|
} else {
|
|
321
|
-
append()
|
|
348
|
+
append(c_n === '</' ? T_JSX_LITERALS : undefined)
|
|
322
349
|
current = curr
|
|
323
350
|
if (c_n === '</' || c_n === '/>') {
|
|
324
351
|
current = c_n
|
|
@@ -347,14 +374,13 @@ export function tokenize(code) {
|
|
|
347
374
|
* @return {Array<string>}
|
|
348
375
|
*/
|
|
349
376
|
function generate(tokens) {
|
|
350
|
-
let lineNo = 1
|
|
351
377
|
const linesHtml = []
|
|
352
|
-
const createLine = (content) => `<span
|
|
378
|
+
const createLine = (content) => `<span class="sh__line">${content}</span>`
|
|
353
379
|
|
|
354
380
|
function flushLine(tokens) {
|
|
355
381
|
linesHtml.push(createLine(
|
|
356
|
-
tokens.map(
|
|
357
|
-
`<span
|
|
382
|
+
tokens.map(([type, value]) => (
|
|
383
|
+
`<span style="color: var(--sh-${types[type]})">${encode(value)}</span>`
|
|
358
384
|
))
|
|
359
385
|
.join('')
|
|
360
386
|
))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sugar-high",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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.3",
|
|
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
|
}
|