sugar-high 0.0.7 → 0.1.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 +1 -1
- package/index.d.ts +2 -0
- package/lib/index.mjs +74 -58
- package/package.json +2 -1
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
|
-
|
|
6
|
+

|
|
7
7
|
|
|
8
8
|
### Usage
|
|
9
9
|
|
package/index.d.ts
ADDED
package/lib/index.mjs
CHANGED
|
@@ -147,15 +147,9 @@ function isRegexStart(str) {
|
|
|
147
147
|
export function tokenize(code) {
|
|
148
148
|
let current = ''
|
|
149
149
|
let type = -1
|
|
150
|
+
let nonSpaceType = -1
|
|
150
151
|
/** @type {Array<[number, string]>} */
|
|
151
152
|
const tokens = []
|
|
152
|
-
// string.type = 0 for string or string template
|
|
153
|
-
// string.type = 1 for regex
|
|
154
|
-
const string = { entered: false, type: 0 }
|
|
155
|
-
|
|
156
|
-
// comment.type = 0 for single line comments
|
|
157
|
-
// comment.type = 1 for multi-line comments
|
|
158
|
-
const comment = { entered: false, type: 0 }
|
|
159
153
|
|
|
160
154
|
// jsx.tag for entering open or closed tag
|
|
161
155
|
// jsx.child for entering children
|
|
@@ -163,29 +157,36 @@ export function tokenize(code) {
|
|
|
163
157
|
/** @type {{ tag: boolean; child: boolean; expr: boolean }} */
|
|
164
158
|
const jsx = { tag: false, child: false, expr: false }
|
|
165
159
|
|
|
160
|
+
const inJsxLiterals = () => !jsx.tag && jsx.child && !jsx.expr
|
|
161
|
+
|
|
166
162
|
function classify(token) {
|
|
167
|
-
|
|
163
|
+
const [chr0, chr1] = [token[0], token[1]]
|
|
164
|
+
if (isCommentStart(chr0 + chr1)) {
|
|
168
165
|
return T_COMMENT
|
|
169
166
|
} else if (keywords.has(token)) {
|
|
170
167
|
return T_KEYWORD
|
|
171
168
|
} else if (token === '\n') {
|
|
172
169
|
return T_BREAK
|
|
173
|
-
} else if (
|
|
174
|
-
(
|
|
175
|
-
// is quoted string
|
|
176
|
-
(isStringQuotation(token[0]) && !isStringQuotation(token[1])) ||
|
|
177
|
-
// is regex
|
|
178
|
-
(!jsx.tag && isRegexStart(token[0] + token[1]) && token[token.length - 1] === '/')
|
|
179
|
-
)
|
|
180
|
-
) {
|
|
181
|
-
return T_STRING
|
|
182
170
|
} else if (token === ' ') {
|
|
183
171
|
return T_SPACE
|
|
184
|
-
} else if (signs.has(
|
|
172
|
+
} else if (token.split('').every(ch => signs.has(ch))) {
|
|
185
173
|
return T_SIGN
|
|
186
174
|
} else if (
|
|
187
|
-
|
|
188
|
-
|
|
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
|
+
!inJsxLiterals() &&
|
|
185
|
+
(
|
|
186
|
+
isIdentifierChar(chr0) &&
|
|
187
|
+
chr0 === chr0.toUpperCase() ||
|
|
188
|
+
token === 'null'
|
|
189
|
+
)
|
|
189
190
|
) {
|
|
190
191
|
return T_CLS_NUMBER
|
|
191
192
|
} else {
|
|
@@ -196,6 +197,7 @@ export function tokenize(code) {
|
|
|
196
197
|
const append = () => {
|
|
197
198
|
if (current) {
|
|
198
199
|
type = classify(current)
|
|
200
|
+
if (type !== T_SPACE && type !== T_BREAK) nonSpaceType = type
|
|
199
201
|
tokens.push([type, current])
|
|
200
202
|
}
|
|
201
203
|
current = ''
|
|
@@ -205,8 +207,8 @@ export function tokenize(code) {
|
|
|
205
207
|
const prev = code[i - 1]
|
|
206
208
|
const next = code[i + 1]
|
|
207
209
|
const c_n = curr + next // current and next
|
|
208
|
-
const p_c = prev + curr // previous and current
|
|
209
|
-
const isJsxLiterals =
|
|
210
|
+
const p_c = prev + curr // previous and current
|
|
211
|
+
const isJsxLiterals = inJsxLiterals()
|
|
210
212
|
|
|
211
213
|
if (jsx.tag) {
|
|
212
214
|
const isOpenElementEnd = curr === '>'
|
|
@@ -215,55 +217,57 @@ export function tokenize(code) {
|
|
|
215
217
|
jsx.tag = !(isOpenElementEnd || isCloseElementEnd)
|
|
216
218
|
}
|
|
217
219
|
// if it's not in a jsx tag declaration or a string, close child if next is jsx close tag
|
|
218
|
-
if (!jsx.tag &&
|
|
220
|
+
if (!jsx.tag && (curr === '<' && isIdentifierChar(next) || c_n === '</')) {
|
|
219
221
|
jsx.tag = true
|
|
220
222
|
jsx.child = false
|
|
221
223
|
}
|
|
222
|
-
|
|
223
|
-
if (jsx.child && curr === '{') {
|
|
224
|
-
jsx.expr = true
|
|
225
|
-
}
|
|
226
|
-
if (jsx.child && jsx.expr && curr === '}') {
|
|
227
|
-
jsx.expr = false
|
|
228
|
-
}
|
|
229
224
|
|
|
230
225
|
if (
|
|
231
|
-
!string.entered &&
|
|
232
226
|
(isStringQuotation(curr) || !jsx.tag && isRegexStart(c_n))
|
|
233
227
|
) {
|
|
234
|
-
string.entered = true
|
|
235
|
-
string.type = isStringQuotation(curr) ? 0 : 1
|
|
236
228
|
append()
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
current += curr
|
|
240
|
-
if (string.type === 0 && isStringQuotation(curr)) {
|
|
241
|
-
string.entered = false
|
|
242
|
-
append()
|
|
243
|
-
} else if (string.type === 1 && prev !== '\\' && curr === '/') {
|
|
244
|
-
string.entered = false
|
|
229
|
+
if (!(nonSpaceType === T_SIGN || nonSpaceType === T_COMMENT)) {
|
|
230
|
+
current = curr
|
|
245
231
|
append()
|
|
232
|
+
continue
|
|
246
233
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
234
|
+
let j = i + 1
|
|
235
|
+
let strEnd = i
|
|
236
|
+
const inString = () => j < code.length && code[j] !== '\n'
|
|
237
|
+
// string quotation
|
|
238
|
+
if (isStringQuotation(curr)) {
|
|
239
|
+
for (; inString(); j++) {
|
|
240
|
+
if (isStringQuotation(code[j])) {
|
|
241
|
+
strEnd = j
|
|
242
|
+
break
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
// regex
|
|
247
|
+
for (; inString(); j++) {
|
|
248
|
+
if (code[j] === '/' && code[j - 1] !== '\\') {
|
|
249
|
+
strEnd = j
|
|
250
|
+
break
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (strEnd !== i) {
|
|
255
|
+
current = code.slice(i, strEnd + 1)
|
|
260
256
|
append()
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
current
|
|
257
|
+
i = j
|
|
258
|
+
} else {
|
|
259
|
+
current = curr
|
|
264
260
|
append()
|
|
265
|
-
i++
|
|
266
261
|
}
|
|
262
|
+
} else if (isCommentStart(c_n)) {
|
|
263
|
+
const start = i
|
|
264
|
+
if (next === '/') {
|
|
265
|
+
for (; i < code.length && code[i] !== '\n'; i++);
|
|
266
|
+
} else {
|
|
267
|
+
for (; i < code.length && code[i - 1] + code[i] !== '*/'; i++);
|
|
268
|
+
}
|
|
269
|
+
current = code.slice(start, i + 1)
|
|
270
|
+
append()
|
|
267
271
|
} else if (curr === ' ' || curr === '\n') {
|
|
268
272
|
if (
|
|
269
273
|
curr === ' ' &&
|
|
@@ -296,6 +300,13 @@ export function tokenize(code) {
|
|
|
296
300
|
else if (jsxBrackets.has(curr)) append()
|
|
297
301
|
}
|
|
298
302
|
}
|
|
303
|
+
|
|
304
|
+
if (jsx.child && curr === '{') {
|
|
305
|
+
jsx.expr = true
|
|
306
|
+
}
|
|
307
|
+
if (jsx.child && jsx.expr && curr === '}') {
|
|
308
|
+
jsx.expr = false
|
|
309
|
+
}
|
|
299
310
|
}
|
|
300
311
|
|
|
301
312
|
append()
|
|
@@ -320,6 +331,11 @@ function generate(tokens) {
|
|
|
320
331
|
return output
|
|
321
332
|
}
|
|
322
333
|
|
|
334
|
+
/**
|
|
335
|
+
*
|
|
336
|
+
* @param {string} code
|
|
337
|
+
* @returns {string}
|
|
338
|
+
*/
|
|
323
339
|
export function highlight(code) {
|
|
324
340
|
const tokens = tokenize(code)
|
|
325
341
|
const output = generate(tokens).join('')
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sugar-high",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./lib/index.mjs",
|
|
6
6
|
"description": "Super lightweight JSX syntax highlighter",
|
|
7
7
|
"files": [
|
|
8
8
|
"lib",
|
|
9
|
+
"index.d.ts",
|
|
9
10
|
"*.md"
|
|
10
11
|
],
|
|
11
12
|
"license": "MIT",
|