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 CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  Super lightweight JSX syntax highlighter, around 1KB after minified and gzipped
5
5
 
6
- > ⚠️ Still in experiment! Use it in production with caution!
6
+ ![img](https://repository-images.githubusercontent.com/453236442/9416c941-9c40-4dbe-a73e-0e0d21993802)
7
7
 
8
8
  ### Usage
9
9
 
package/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export function highlight(code: string): string
2
+ export function tokenize(code: string): Array<[number, string]>
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
- if (isCommentStart(token[0] + token[1])) {
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(token[0])) {
172
+ } else if (token.split('').every(ch => signs.has(ch))) {
185
173
  return T_SIGN
186
174
  } else if (
187
- token[0] === token[0].toUpperCase() ||
188
- token === 'null'
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 = !jsx.tag && jsx.child && !jsx.expr
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 && !string.entered && (curr === '<' && isIdentifierChar(next) || c_n === '</')) {
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
- current = curr
238
- } else if (string.entered) {
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
- } else if (
248
- !comment.entered &&
249
- isCommentStart(c_n)
250
- ) {
251
- comment.type = next === '/' ? 0 : 1
252
- comment.entered = true
253
- append()
254
- current = c_n
255
- i++
256
- } else if (comment.entered) {
257
- current += curr
258
- if (comment.type === 0 && next === '\n') {
259
- comment.entered = false
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
- } else if (comment.type === 1 && (c_n === '*/')) {
262
- comment.entered = false
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.0.7",
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",