sugar-high 0.1.1 → 0.2.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 +5 -3
- package/lib/index.mjs +67 -43
- package/package.json +8 -4
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
|
|
|
@@ -33,7 +33,7 @@ Then make your own theme with customized colors by token type and put in global
|
|
|
33
33
|
* Class, number and null
|
|
34
34
|
* sign
|
|
35
35
|
* comment
|
|
36
|
-
*
|
|
36
|
+
* jsxliterals
|
|
37
37
|
*/
|
|
38
38
|
.sh__class {
|
|
39
39
|
color: #2d5e9d;
|
|
@@ -53,7 +53,9 @@ Then make your own theme with customized colors by token type and put in global
|
|
|
53
53
|
.sh__comment {
|
|
54
54
|
color: #a19595;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
.sh__jsxliterals {
|
|
57
|
+
color: #03066e;
|
|
58
|
+
}
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
### LICENSE
|
package/lib/index.mjs
CHANGED
|
@@ -74,7 +74,7 @@ const signs = new Set([
|
|
|
74
74
|
'\\',
|
|
75
75
|
])
|
|
76
76
|
|
|
77
|
-
const types = [
|
|
77
|
+
export const types = [
|
|
78
78
|
'identifier',
|
|
79
79
|
'keyword',
|
|
80
80
|
'string',
|
|
@@ -83,6 +83,7 @@ const types = [
|
|
|
83
83
|
'comment',
|
|
84
84
|
'break',
|
|
85
85
|
'space',
|
|
86
|
+
'jsxliterals'
|
|
86
87
|
]
|
|
87
88
|
|
|
88
89
|
/**
|
|
@@ -95,6 +96,7 @@ const types = [
|
|
|
95
96
|
* 5 - comment
|
|
96
97
|
* 6 - break
|
|
97
98
|
* 7 - space
|
|
99
|
+
* 8 - jsx literals
|
|
98
100
|
*
|
|
99
101
|
*/
|
|
100
102
|
const [
|
|
@@ -106,6 +108,7 @@ const [
|
|
|
106
108
|
T_COMMENT,
|
|
107
109
|
T_BREAK,
|
|
108
110
|
T_SPACE,
|
|
111
|
+
T_JSX_LITERALS,
|
|
109
112
|
] = types.map((_, i) => i)
|
|
110
113
|
|
|
111
114
|
function isSpaces(str) {
|
|
@@ -123,8 +126,16 @@ function encode(str) {
|
|
|
123
126
|
.replace(/[^\S\r\n]/g, ' ')
|
|
124
127
|
}
|
|
125
128
|
|
|
129
|
+
function isWord(chr) {
|
|
130
|
+
return /^[\w_]+$/.test(chr)
|
|
131
|
+
}
|
|
132
|
+
|
|
126
133
|
function isIdentifierChar(chr) {
|
|
127
|
-
return
|
|
134
|
+
return /^[a-zA-Z_$]$/.test(chr)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isIdentifier(str) {
|
|
138
|
+
return isIdentifierChar(str[0]) && (str.length === 1 || isWord(str.slice(1)))
|
|
128
139
|
}
|
|
129
140
|
|
|
130
141
|
function isStringQuotation(chr) {
|
|
@@ -147,7 +158,7 @@ function isRegexStart(str) {
|
|
|
147
158
|
export function tokenize(code) {
|
|
148
159
|
let current = ''
|
|
149
160
|
let type = -1
|
|
150
|
-
let
|
|
161
|
+
let last = [null, null]
|
|
151
162
|
/** @type {Array<[number, string]>} */
|
|
152
163
|
const tokens = []
|
|
153
164
|
|
|
@@ -160,45 +171,38 @@ export function tokenize(code) {
|
|
|
160
171
|
const inJsxLiterals = () => !jsx.tag && jsx.child && !jsx.expr
|
|
161
172
|
|
|
162
173
|
function classify(token) {
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
165
|
-
return T_COMMENT
|
|
166
|
-
} else if (keywords.has(token)) {
|
|
174
|
+
const chr0 = token[0]
|
|
175
|
+
if (keywords.has(token)) {
|
|
167
176
|
return T_KEYWORD
|
|
168
177
|
} else if (token === '\n') {
|
|
169
178
|
return T_BREAK
|
|
170
|
-
} else if (token
|
|
179
|
+
} else if (isSpaces(token)) {
|
|
171
180
|
return T_SPACE
|
|
172
181
|
} else if (token.split('').every(ch => signs.has(ch))) {
|
|
173
182
|
return T_SIGN
|
|
174
183
|
} else if (
|
|
175
|
-
(
|
|
176
|
-
// is quoted string
|
|
177
|
-
(isStringQuotation(chr0) && !isStringQuotation(chr1)) ||
|
|
178
|
-
// is regex
|
|
179
|
-
(!jsx.tag && isRegexStart(chr0 + chr1) && token[token.length - 1] === '/')
|
|
180
|
-
)
|
|
181
|
-
) {
|
|
182
|
-
return T_STRING
|
|
183
|
-
} else if (
|
|
184
184
|
!inJsxLiterals() &&
|
|
185
185
|
(
|
|
186
|
-
|
|
186
|
+
isWord(chr0) &&
|
|
187
187
|
chr0 === chr0.toUpperCase() ||
|
|
188
188
|
token === 'null'
|
|
189
189
|
)
|
|
190
190
|
) {
|
|
191
191
|
return T_CLS_NUMBER
|
|
192
192
|
} else {
|
|
193
|
-
return T_IDENTIFIER
|
|
193
|
+
return isIdentifier(token) ? T_IDENTIFIER : inJsxLiterals() ? T_JSX_LITERALS : T_STRING
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
const append = () => {
|
|
197
|
+
const append = (_type) => {
|
|
198
198
|
if (current) {
|
|
199
|
-
type = classify(current)
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
type = _type || classify(current)
|
|
200
|
+
/** @type [number, string] */
|
|
201
|
+
const pair = [type, current]
|
|
202
|
+
if (type !== T_SPACE && type !== T_BREAK) {
|
|
203
|
+
last = pair
|
|
204
|
+
}
|
|
205
|
+
tokens.push(pair)
|
|
202
206
|
}
|
|
203
207
|
current = ''
|
|
204
208
|
}
|
|
@@ -222,42 +226,62 @@ export function tokenize(code) {
|
|
|
222
226
|
jsx.child = false
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
) {
|
|
229
|
+
const isQuotationChar = isStringQuotation(curr)
|
|
230
|
+
const isRegexChar = !jsx.tag && isRegexStart(c_n)
|
|
231
|
+
if (isQuotationChar || isRegexChar) {
|
|
228
232
|
append()
|
|
229
|
-
|
|
233
|
+
const [lastType, lastToken] = last
|
|
234
|
+
// Special cases that are not considered as regex:
|
|
235
|
+
// * (expr1) / expr2: `()` before `/` operator is still in expression
|
|
236
|
+
// * <non comment start>/ expr: non comment start before `/` is not regex
|
|
237
|
+
if (
|
|
238
|
+
isRegexChar &&
|
|
239
|
+
lastType &&
|
|
240
|
+
!(
|
|
241
|
+
(lastType === T_SIGN && !'()'.includes(lastToken)) ||
|
|
242
|
+
lastType === T_COMMENT
|
|
243
|
+
)
|
|
244
|
+
) {
|
|
230
245
|
current = curr
|
|
231
246
|
append()
|
|
232
247
|
continue
|
|
233
248
|
}
|
|
234
|
-
|
|
235
|
-
let
|
|
236
|
-
|
|
249
|
+
const start = i++
|
|
250
|
+
let foundClose = false
|
|
251
|
+
|
|
252
|
+
// end of line of end of file
|
|
253
|
+
const isEol = () => i >= code.length || code[i] === '\n'
|
|
237
254
|
// string quotation
|
|
238
|
-
if (
|
|
239
|
-
for (;
|
|
240
|
-
if (isStringQuotation(code[
|
|
241
|
-
|
|
255
|
+
if (isQuotationChar) {
|
|
256
|
+
for (; !isEol(); i++) {
|
|
257
|
+
if (isStringQuotation(code[i]) && code[i] === code[start]) {
|
|
258
|
+
foundClose = true
|
|
242
259
|
break
|
|
243
260
|
}
|
|
244
261
|
}
|
|
245
262
|
} else {
|
|
246
263
|
// regex
|
|
247
|
-
for (;
|
|
248
|
-
if (code[
|
|
249
|
-
|
|
264
|
+
for (; !isEol(); i++) {
|
|
265
|
+
if (code[i] === '/' && code[i - 1] !== '\\') {
|
|
266
|
+
foundClose = true
|
|
267
|
+
// append regex flags
|
|
268
|
+
while (start !== i && /^[a-z]$/.test(code[i + 1]) && !isEol()) {
|
|
269
|
+
i++
|
|
270
|
+
};
|
|
250
271
|
break
|
|
251
272
|
}
|
|
252
273
|
}
|
|
253
274
|
}
|
|
254
|
-
if (
|
|
255
|
-
current
|
|
256
|
-
|
|
257
|
-
|
|
275
|
+
if (start !== i && foundClose) {
|
|
276
|
+
// If current line is fully closed with string quotes or regex slashes,
|
|
277
|
+
// add them to tokens
|
|
278
|
+
current = code.slice(start, i + 1)
|
|
279
|
+
append(T_STRING)
|
|
258
280
|
} else {
|
|
281
|
+
// If it doesn't match any of the above, just leave it as operator and move on
|
|
259
282
|
current = curr
|
|
260
283
|
append()
|
|
284
|
+
i = start
|
|
261
285
|
}
|
|
262
286
|
} else if (isCommentStart(c_n)) {
|
|
263
287
|
const start = i
|
|
@@ -267,7 +291,7 @@ export function tokenize(code) {
|
|
|
267
291
|
for (; i < code.length && code[i - 1] + code[i] !== '*/'; i++);
|
|
268
292
|
}
|
|
269
293
|
current = code.slice(start, i + 1)
|
|
270
|
-
append()
|
|
294
|
+
append(T_COMMENT)
|
|
271
295
|
} else if (curr === ' ' || curr === '\n') {
|
|
272
296
|
if (
|
|
273
297
|
curr === ' ' &&
|
|
@@ -285,7 +309,7 @@ export function tokenize(code) {
|
|
|
285
309
|
} else {
|
|
286
310
|
if (
|
|
287
311
|
(isJsxLiterals && !jsxBrackets.has(curr)) ||
|
|
288
|
-
|
|
312
|
+
isWord(curr) === isWord(current[current.length - 1]) &&
|
|
289
313
|
!signs.has(curr)
|
|
290
314
|
) {
|
|
291
315
|
current += curr
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sugar-high",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./lib/index.mjs",
|
|
6
6
|
"description": "Super lightweight JSX syntax highlighter",
|
|
@@ -11,10 +11,14 @@
|
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"scripts": {
|
|
14
|
-
"
|
|
15
|
-
"
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"dev": "next dev docs",
|
|
16
|
+
"build": "next build docs"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
|
-
"
|
|
19
|
+
"next": "12.1.1-canary.15",
|
|
20
|
+
"react": "18.0.0-rc.2",
|
|
21
|
+
"react-dom": "18.0.0-rc.2",
|
|
22
|
+
"vitest": "~0.6.0"
|
|
19
23
|
}
|
|
20
24
|
}
|