sugar-high 1.2.1 → 1.3.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
@@ -1,6 +1,7 @@
1
1
  # Sugar High
2
2
 
3
- [![npm][npm-badge]][npm]
3
+ [![version][npm-version-badge]][npm]
4
+ [![downloads][npm-downloads-badge]][npm]
4
5
 
5
6
  Super lightweight syntax highlighter for JavaScript and JSX—about **1 kB** minified and gzipped. Works in the browser or any JS runtime that can set HTML strings.
6
7
 
@@ -33,7 +34,15 @@ import { rust } from 'sugar-high/presets'
33
34
  const html = highlight(source, { ...rust })
34
35
  ```
35
36
 
36
- Available presets: `c`, `css`, `diff`, `go`, `java`, `python`, and `rust`.
37
+ Available presets: `c`, `css`, `diff`, `go`, `java`, `json`, `python`, and `rust`.
38
+
39
+ The `json` preset highlights quoted object keys as `property` tokens, keeping them distinct from string values:
40
+
41
+ ```js
42
+ import { json } from 'sugar-high/presets'
43
+
44
+ const html = highlight('{"name": "Alice"}', json)
45
+ ```
37
46
 
38
47
  For more language presets and syntax color themes, see **[sugar-high.vercel.app](https://sugar-high.vercel.app/)**.
39
48
 
@@ -108,6 +117,7 @@ MIT
108
117
 
109
118
  <!-- Definitions -->
110
119
 
111
- [npm-badge]: https://img.shields.io/npm/v/sugar-high.svg
120
+ [npm-version-badge]: https://img.shields.io/npm/v/sugar-high?style=flat&colorA=000000&colorB=000000
121
+ [npm-downloads-badge]: https://img.shields.io/npm/dt/sugar-high.svg?style=flat&colorA=000000&colorB=000000
112
122
 
113
123
  [npm]: https://www.npmjs.com/package/sugar-high
package/lib/index.d.ts CHANGED
@@ -11,6 +11,8 @@ type HighlightOptions = {
11
11
  * or null/undefined or a number below 1 for default JS single-quoted string rules.
12
12
  */
13
13
  onQuote?: (curr: string, i: number, code: string) => number | null | undefined
14
+ /** Highlight quoted object keys followed by `:` as `property` tokens. */
15
+ quotedKeys?: boolean
14
16
  lineClassName?: (line: string, index: number) => string | null | undefined
15
17
  }
16
18
 
package/lib/index.js CHANGED
@@ -235,13 +235,18 @@ function isSign(ch) {
235
235
  return Signs.has(ch)
236
236
  }
237
237
 
238
+ const HtmlEntities = /** @type {Record<string, string>} */ ({
239
+ '&': '&amp;',
240
+ '<': '&lt;',
241
+ '>': '&gt;',
242
+ '"': '&quot;',
243
+ "'": '&#039;',
244
+ })
245
+
246
+ /** @param {string} str */
238
247
  function encode(str) {
239
- return str
240
- .replace(/&/g, '&amp;')
241
- .replace(/</g, '&lt;')
242
- .replace(/>/g, '&gt;')
243
- .replace(/"/g, '&quot;')
244
- .replace(/'/g, '&#039;')
248
+ if (!/[&<>"']/.test(str)) return str
249
+ return str.replace(/[&<>"']/g, chr => HtmlEntities[chr])
245
250
  }
246
251
 
247
252
  function isWord(chr) {
@@ -301,6 +306,12 @@ function isRegexStart(str) {
301
306
  return str[0] === '/' && !isCommentStart_Js(str[0], str[1])
302
307
  }
303
308
 
309
+ function isPropertyKey(code, quoteEnd) {
310
+ let i = quoteEnd + 1
311
+ while (i < code.length && /\s/.test(code[i])) i++
312
+ return code[i] === ':'
313
+ }
314
+
304
315
  /**
305
316
  * @param {string} code
306
317
  * @param {{
@@ -309,6 +320,7 @@ function isRegexStart(str) {
309
320
  * onCommentStart?: (curr: string, next: string) => number | boolean
310
321
  * onCommentEnd?: (prev: string, curr: string) => number | boolean
311
322
  * onQuote?: (curr: string, i: number, code: string) => number | null | undefined
323
+ * quotedKeys?: boolean
312
324
  * lineClassName?: (line: string, index: number) => string | null | undefined
313
325
  * } | undefined} options
314
326
  * Optional `onQuote(curr, i, code)` at `code[i] === "'"`: return length to consume from `i` (>= 1),
@@ -364,6 +376,7 @@ function tokenize(code, options) {
364
376
 
365
377
  /** @type {string | null} */
366
378
  let __strQuote = null
379
+ let __strTokenStart = 0
367
380
  let __regexQuoteStart = false
368
381
  let __strTemplateExprStack = 0
369
382
  let __strTemplateQuoteStack = 0
@@ -479,15 +492,23 @@ function tokenize(code, options) {
479
492
  // Inside jsx literals or template literals, string quotation is still part of it.
480
493
  if (isSingleQuotes(curr) && !inJsxLiterals() && !inStrTemplateLiterals()) {
481
494
  append()
495
+ let isStringClose = false
482
496
  if (prev !== `\\`) {
483
497
  if (__strQuote && curr === __strQuote) {
484
498
  __strQuote = null
499
+ isStringClose = true
485
500
  } else if (!__strQuote) {
486
501
  __strQuote = curr
502
+ __strTokenStart = tokens.length
487
503
  }
488
504
  }
489
505
 
490
506
  append(T_STRING, curr)
507
+ if (mergedOptions.quotedKeys && isStringClose && isPropertyKey(code, i)) {
508
+ for (let tokenIndex = __strTokenStart; tokenIndex < tokens.length; tokenIndex++) {
509
+ tokens[tokenIndex][0] = T_PROPERTY
510
+ }
511
+ }
491
512
  continue
492
513
  }
493
514
 
@@ -770,8 +791,11 @@ function tokenize(code, options) {
770
791
  isJsxLiterals
771
792
  )
772
793
  ) {
773
- current += curr
774
- if (next === '<') {
794
+ let end = i + 1
795
+ while (code[end] === ' ') end++
796
+ current += code.slice(i, end)
797
+ i = end - 1
798
+ if (code[end] === '<') {
775
799
  append()
776
800
  }
777
801
  } else {
@@ -966,6 +990,7 @@ function toHtml(lines) {
966
990
  * onCommentStart?: (curr: string, next: string) => number | boolean
967
991
  * onCommentEnd?: (curr: string, prev: string) => number | boolean
968
992
  * onQuote?: (curr: string, i: number, code: string) => number | null | undefined
993
+ * quotedKeys?: boolean
969
994
  * lineClassName?: (line: string, index: number) => string | null | undefined
970
995
  * } | undefined} options
971
996
  * `onQuote` same as `tokenize`.
@@ -4,6 +4,7 @@ type LanguageConfig = {
4
4
  onCommentStart?(curr: string, next: string): 0 | 1 | 2
5
5
  onCommentEnd?(prev: string, curr: string): 0 | 1 | 2
6
6
  onQuote?(curr: string, i: number, code: string): number | null | undefined
7
+ quotedKeys?: boolean
7
8
  lineClassName?(line: string, index: number): string | null | undefined
8
9
  }
9
10
 
@@ -14,3 +15,4 @@ export const c: LanguageConfig
14
15
  export const go: LanguageConfig
15
16
  export const java: LanguageConfig
16
17
  export const diff: LanguageConfig
18
+ export const json: LanguageConfig
@@ -5,3 +5,4 @@ export * as c from './lang/c.js'
5
5
  export * as go from './lang/go.js'
6
6
  export * as java from './lang/java.js'
7
7
  export * as diff from './lang/diff.js'
8
+ export * as json from './lang/json.js'
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+
3
+ export const keywords = new Set(['true', 'false', 'null'])
4
+ export const quotedKeys = true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sugar-high",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/huozhi/sugar-high.git",