sugar-high 0.5.5 → 0.6.0

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
@@ -35,18 +35,24 @@ Then make your own theme with customized colors by token type and put in global
35
35
  * keyword
36
36
  * string
37
37
  * Class, number and null
38
+ * property
39
+ * entity
40
+ * jsx literals
38
41
  * sign
39
42
  * comment
40
- * jsxliterals
43
+ * break
44
+ * space
41
45
  */
42
46
  :root {
43
47
  --sh-class: #2d5e9d;
44
48
  --sh-identifier: #354150;
45
49
  --sh-sign: #8996a3;
50
+ --sh-property: #0550ae;
51
+ --sh-entity: #249a97;
52
+ --sh-jsxliterals: #6266d1;
46
53
  --sh-string: #00a99a;
47
54
  --sh-keyword: #f47067;
48
55
  --sh-comment: #a19595;
49
- --sh-jsxliterals: #6266d1;
50
56
  }
51
57
  ```
52
58
 
@@ -70,6 +76,16 @@ pre code {
70
76
  }
71
77
  ```
72
78
 
79
+ ### Line Highlight
80
+
81
+ Use `.sh__line:nth-child(<line number>)` to highlight specific line.
82
+
83
+ ```css
84
+ .sh__line:nth-child(5) {
85
+ background: #f5f5f5;
86
+ }
87
+ ```
88
+
73
89
  #### CSS Class Names
74
90
 
75
91
  You can use `.sh__token--<token type>` to customize the output node of each token.
@@ -76,42 +76,48 @@ const signs = new Set([
76
76
  ...jsxBrackets,
77
77
  ])
78
78
 
79
- const types = [
79
+
80
+ /**
81
+ *
82
+ * 0 - identifier
83
+ * 1 - keyword
84
+ * 2 - string
85
+ * 3 - Class, number and null
86
+ * 4 - property
87
+ * 5 - entity
88
+ * 6 - jsx literals
89
+ * 7 - sign
90
+ * 8 - comment
91
+ * 9 - break
92
+ * 10 - space
93
+ *
94
+ */
95
+ const types = /** @type {const} */ ([
80
96
  'identifier',
81
97
  'keyword',
82
98
  'string',
83
99
  'class',
100
+ 'property',
101
+ 'entity',
102
+ 'jsxliterals',
84
103
  'sign',
85
104
  'comment',
86
105
  'break',
87
106
  'space',
88
- 'jsxliterals'
89
- ]
90
-
91
- /**
92
- *
93
- * 0 - identifier
94
- * 1 - keyword
95
- * 2 - string
96
- * 3 - Class, number and null
97
- * 4 - sign
98
- * 5 - comment
99
- * 6 - break
100
- * 7 - space
101
- * 8 - jsx literals
102
- *
103
- */
107
+ ])
104
108
  const [
105
109
  T_IDENTIFIER,
106
110
  T_KEYWORD,
107
111
  T_STRING,
108
112
  T_CLS_NUMBER,
113
+ T_PROPERTY,
114
+ T_ENTITY,
115
+ T_JSX_LITERALS,
109
116
  T_SIGN,
110
117
  T_COMMENT,
111
118
  T_BREAK,
112
119
  T_SPACE,
113
- T_JSX_LITERALS,
114
- ] = types.map((_, i) => i)
120
+ ] = /** @types {const} */ types.map((_, i) => i)
115
121
 
116
122
  function isSpaces(str) {
117
123
  return /^[^\S\r\n]+$/g.test(str)
@@ -185,8 +191,10 @@ function isRegexStart(str) {
185
191
  function tokenize(code) {
186
192
  let current = ''
187
193
  let type = -1
188
- /** @type {[number | null, string | null]} */
189
- let last = [null, null]
194
+ /** @type {[number, string]} */
195
+ let last = [-1, '']
196
+ /** @type {[number, string]} */
197
+ let beforeLast = [-2, '']
190
198
  /** @type {Array<[number, string]>} */
191
199
  const tokens = []
192
200
 
@@ -205,7 +213,9 @@ function tokenize(code) {
205
213
  // only match paired (open + close) tags, not self-closing tags
206
214
  let __jsxStack = 0
207
215
  const __jsxChild = () => __jsxEnter && !__jsxExpr && !__jsxTag
216
+ // < __content__ >
208
217
  const inJsxTag = () => __jsxTag && !__jsxChild()
218
+ // {'__content__'}
209
219
  const inJsxLiterals = () => !__jsxTag && __jsxChild() && !__jsxExpr && __jsxStack > 0
210
220
 
211
221
  /** @type {string | null} */
@@ -215,6 +225,7 @@ function tokenize(code) {
215
225
  const inStringQuotes = () => __strQuote !== null
216
226
  const inStrTemplateLiterals = () => (__strTemplateQuoteStack > __strTemplateExprStack)
217
227
  const inStrTemplateExpr = () => __strTemplateQuoteStack > 0 && (__strTemplateQuoteStack === __strTemplateExprStack)
228
+ const inStringContent = () => inStringQuotes() || inStrTemplateLiterals()
218
229
 
219
230
  /**
220
231
  *
@@ -224,15 +235,22 @@ function tokenize(code) {
224
235
  function classify(token) {
225
236
  const isLineBreak = token === '\n'
226
237
  // First checking if they're attributes values
227
- if (inJsxTag() && inStringQuotes()) {
228
- return T_STRING
238
+ if (inJsxTag()) {
239
+ if (inStringQuotes()) {
240
+ return T_STRING
241
+ }
242
+
243
+ const [, lastToken] = last
244
+ if (isIdentifier(token)) {
245
+ // classify jsx open tag
246
+ if ((lastToken === '<' || lastToken === '</'))
247
+ return T_ENTITY
248
+ }
229
249
  }
230
250
  // Then determine if they're jsx literals
231
251
  const isJsxLiterals = inJsxLiterals()
232
- if (isJsxLiterals) {
233
- return T_JSX_LITERALS
252
+ if (isJsxLiterals) return T_JSX_LITERALS
234
253
 
235
- }
236
254
  // Determine strings first before other types
237
255
  if (inStringQuotes()) {
238
256
  return T_STRING
@@ -247,10 +265,13 @@ function tokenize(code) {
247
265
  } else if (isCls(token)) {
248
266
  return inJsxTag() ? T_IDENTIFIER : T_CLS_NUMBER
249
267
  } else {
268
+ if (isIdentifier(token)) {
269
+ const isLastPropDot = last[1] === '.' && isIdentifier(beforeLast[1])
250
270
 
251
- return isIdentifier(token) &&
252
- !inStrTemplateLiterals() &&
253
- (!isSingleQuotes(__strQuote)) ? T_IDENTIFIER : T_STRING
271
+ if (!inStringContent() && !isLastPropDot) return T_IDENTIFIER
272
+ if (isLastPropDot) return T_PROPERTY
273
+ }
274
+ return T_STRING
254
275
  }
255
276
  }
256
277
 
@@ -263,6 +284,7 @@ function tokenize(code) {
263
284
  /** @type [number, string] */
264
285
  const pair = [type, current]
265
286
  if (type !== T_SPACE && type !== T_BREAK) {
287
+ beforeLast = last
266
288
  last = pair
267
289
  }
268
290
  tokens.push(pair)
@@ -401,6 +423,25 @@ function tokenize(code) {
401
423
  append(T_SIGN)
402
424
  continue
403
425
  }
426
+
427
+ // jsx property
428
+ // `-` in data-prop
429
+ if (next === '-' && !inStringContent() && !inJsxLiterals()) {
430
+ if (current) {
431
+ append(T_PROPERTY, current + curr + next)
432
+ i += 1
433
+ continue
434
+ }
435
+ }
436
+ // `=` in property=<value>
437
+ if (next === '=') {
438
+ const prop = current ? (current + curr) : curr
439
+ if (isIdentifier(prop)) {
440
+ current = prop
441
+ append(T_PROPERTY)
442
+ }
443
+ continue
444
+ }
404
445
  }
405
446
  }
406
447
 
@@ -430,7 +471,7 @@ function tokenize(code) {
430
471
  // * <non comment start>/ expr: non comment start before `/` is not regex
431
472
  if (
432
473
  isRegexChar &&
433
- lastType &&
474
+ lastType !== -1 &&
434
475
  !(
435
476
  (lastType === T_SIGN && ')' !== lastToken) ||
436
477
  lastType === T_COMMENT
@@ -594,7 +635,7 @@ function highlight(code) {
594
635
  }
595
636
 
596
637
  // namespace
597
- const SugarHigh = {
638
+ const SugarHigh = /** @type {const} */ {
598
639
  TokenTypes: types,
599
640
  }
600
641
 
package/package.json CHANGED
@@ -1,30 +1,29 @@
1
1
  {
2
2
  "name": "sugar-high",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
+ "types": "./lib/index.d.ts",
5
6
  "exports": {
6
- "types": "./index.d.mts",
7
- "default": "./lib/index.mjs"
7
+ "types": "./lib/index.d.ts",
8
+ "default": "./lib/index.js"
8
9
  },
9
10
  "description": "Super lightweight JSX syntax highlighter",
10
11
  "files": [
11
- "lib",
12
- "index.d.mts",
13
- "*.md"
12
+ "lib"
14
13
  ],
15
14
  "license": "MIT",
16
- "scripts": {
17
- "test": "vitest run",
18
- "dev": "next dev docs",
19
- "build": "next build docs"
20
- },
21
15
  "devDependencies": {
22
16
  "codice": "^0.2.0",
23
- "next": "13.4.20-canary.31",
17
+ "next": "14.1.0",
24
18
  "react": "^18.2.0",
25
19
  "react-dom": "^18.2.0",
26
20
  "sugar-high": "link:./",
27
- "vitest": "^0.34.4"
21
+ "vitest": "^1.2.2"
28
22
  },
29
- "packageManager": "pnpm@8.7.1"
30
- }
23
+ "packageManager": "pnpm@8.7.1",
24
+ "scripts": {
25
+ "test": "vitest run",
26
+ "dev": "next dev docs",
27
+ "build": "next build docs"
28
+ }
29
+ }
File without changes