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.
Files changed (3) hide show
  1. package/README.md +15 -22
  2. package/lib/index.mjs +51 -25
  3. 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
- ![img](https://repository-images.githubusercontent.com/453236442/82cf2807-78f0-4009-bbdf-d7e753f73cf4)
6
+ ![img](https://repository-images.githubusercontent.com/453236442/94994be5-72fa-479f-8b87-2dc14fe40329)
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
- .sh__class {
39
- color: #2d5e9d;
40
- }
41
- .sh__identifier {
42
- color: #2d333b;
43
- }
44
- .sh__sign {
45
- color: #8996a3;
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
- content: attr(data-line-number);
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 tag
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
- /** @type {{ tag: boolean; child: boolean; expr: boolean }} */
168
- const jsx = { tag: false, child: false, expr: false }
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 inJsxLiterals = () => !jsx.tag && jsx.child && !jsx.expr
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
- !inJsxLiterals() &&
184
- (
185
- isWord(chr0) &&
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 : inJsxLiterals() ? T_JSX_LITERALS : T_STRING
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 = !isCloseElementEnd && !isCloseElementEnd
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: `()` before `/` operator is still in expression
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 && !'()'.includes(lastToken)) ||
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 data-line-number="${lineNo++}" class="sh__line">${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(token => (
357
- `<span class="sh__${types[token[0]]}">${encode(token[1])}</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.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
- "next": "12.1.4",
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
  }