sugar-high 2.2.1 → 2.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
@@ -57,7 +57,7 @@ behavior.
57
57
 
58
58
  `javascript`, `typescript`, `css`, `python`, `c`, `go`, `java`, `rust`, `json`, `diff`, `shell`,
59
59
  `cpp`, `csharp`, `sql`, `html`, `yaml`, `markdown`, `plaintext`, `ruby`, `kotlin`, `swift`, `php`,
60
- `toml`, `powershell`, `dockerfile`, `graphql`, and `hcl`.
60
+ `toml`, `powershell`, `dockerfile`, `graphql`, `hcl`, `zig`, and `lua`.
61
61
 
62
62
  Related dialects share one implementation: JavaScript includes JSX, TypeScript includes TSX, JSON
63
63
  includes JSONC comments, Shell includes sh/Bash/Zsh, and HCL includes Terraform.
package/lib/core.d.ts CHANGED
@@ -89,7 +89,13 @@ export type ParseOptions = {
89
89
  keywords?: Set<string>
90
90
  typeKeywords?: Set<string>
91
91
  onCommentStart?: (curr: string, next: string, index: number, code: string) => number | boolean
92
- onCommentEnd?: (prev: string, curr: string, index: number, code: string) => number | boolean
92
+ onCommentEnd?: (
93
+ prev: string,
94
+ curr: string,
95
+ index: number,
96
+ code: string,
97
+ start: number,
98
+ ) => number | boolean
93
99
  onLiteral?: (curr: string, index: number, code: string) => number | null | undefined
94
100
  onQuote?: (curr: string, index: number, code: string) => number | null | undefined
95
101
  quotedKeys?: boolean
package/lib/core.js CHANGED
@@ -53,7 +53,7 @@ function tokenize(code, options) {
53
53
  if (commentType) {
54
54
  const start = i++
55
55
  while (i < code.length) {
56
- if (onCommentEnd(code[i - 1], code[i], i, code) == commentType) {
56
+ if (onCommentEnd(code[i - 1], code[i], i, code, start) == commentType) {
57
57
  i++
58
58
  break
59
59
  }
@@ -154,7 +154,7 @@ export { generate, parse, render, SugarHigh, tokenize }
154
154
  * @property {Set<string>} [keywords]
155
155
  * @property {Set<string>} [typeKeywords]
156
156
  * @property {(curr: string, next: string, index: number, code: string) => number | boolean} [onCommentStart]
157
- * @property {(prev: string, curr: string, index: number, code: string) => number | boolean} [onCommentEnd]
157
+ * @property {(prev: string, curr: string, index: number, code: string, start: number) => number | boolean} [onCommentEnd]
158
158
  * @property {(curr: string, index: number, code: string) => number | null | undefined} [onLiteral]
159
159
  * @property {(curr: string, index: number, code: string) => number | null | undefined} [onQuote]
160
160
  * @property {boolean} [quotedKeys]
package/lib/index.d.ts CHANGED
@@ -35,6 +35,8 @@ export type LanguageName =
35
35
  | 'dockerfile'
36
36
  | 'graphql'
37
37
  | 'hcl'
38
+ | 'zig'
39
+ | 'lua'
38
40
 
39
41
  export type HighlightOptions = DisplayOptions & {
40
42
  /** Canonical language name. Fence and extension aliases must be normalized first. */
package/lib/index.js CHANGED
@@ -4,12 +4,7 @@ import {
4
4
  parse,
5
5
  render,
6
6
  } from './core.js'
7
- import { languages } from './lang.js'
8
-
9
- /** @param {string | undefined} name */
10
- function configFor(name) {
11
- return languages.find(({ id }) => id === (name || 'javascript'))?.config
12
- }
7
+ import { configFor } from './presets/configs.js'
13
8
 
14
9
  /** @param {string} code @param {HighlightOptions | undefined} options */
15
10
  function highlight(code, options) {
@@ -0,0 +1,10 @@
1
+ export const keywords: Set<string>;
2
+ export function onCommentStart(curr: string, next: string, index: number, code: string): number;
3
+ export function onCommentEnd(
4
+ prev: string,
5
+ curr: string,
6
+ index: number,
7
+ code: string,
8
+ start: number,
9
+ ): number;
10
+ export function onLiteral(curr: string, index: number, code: string): number;
@@ -0,0 +1,45 @@
1
+ // @ts-check
2
+
3
+ export const keywords = new Set([
4
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'goto', 'if', 'in',
5
+ 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
6
+ ])
7
+
8
+ /**
9
+ * @param {string} curr
10
+ * @param {string} next
11
+ * @param {number} index
12
+ * @param {string} code
13
+ */
14
+ export function onCommentStart(curr, next, index, code) {
15
+ if (curr === '#' && index === 0 && next === '!') return 1
16
+ if (curr + next !== '--') return 0
17
+ return /^--\[=*\[/.test(code.slice(index)) ? 2 : 1
18
+ }
19
+
20
+ /**
21
+ * @param {string} _prev
22
+ * @param {string} curr
23
+ * @param {number} index
24
+ * @param {string} code
25
+ * @param {number} start
26
+ */
27
+ export function onCommentEnd(_prev, curr, index, code, start) {
28
+ if (curr === '\n') return 1
29
+ if (curr !== ']') return 0
30
+ const opener = code.slice(start).match(/^--\[(=*)\[/)
31
+ if (!opener) return 0
32
+ const closing = `]${opener[1]}]`
33
+ if (code.slice(index - closing.length + 1, index + 1) === closing) return 2
34
+ return 0
35
+ }
36
+
37
+ /** @param {string} curr @param {number} index @param {string} code */
38
+ export function onLiteral(curr, index, code) {
39
+ if (curr !== '[') return 0
40
+ const opener = code.slice(index).match(/^\[(=*)\[/)
41
+ if (!opener) return 0
42
+ const closing = `]${opener[1]}]`
43
+ const end = code.indexOf(closing, index + opener[0].length)
44
+ return end === -1 ? code.length - index : end + closing.length - index
45
+ }
@@ -1,4 +1,5 @@
1
1
  export const keywords: Set<never>;
2
+ export function tokenize(code: string): Array<[number, string]>;
2
3
  export function annotateLine(line: any): void;
3
4
  import { onCommentEnd } from '../presets/plain-base.js';
4
5
  import { onCommentStart } from '../presets/plain-base.js';
@@ -1,8 +1,91 @@
1
1
  // @ts-check
2
+ import { T_IDENTIFIER, T_SIGN } from '../shared.js'
2
3
  import { onCommentEnd, onCommentStart } from '../presets/plain-base.js'
3
4
 
4
5
  export const keywords = new Set([])
5
6
 
7
+ /** @param {string} code */
8
+ export const tokenize = (code) => {
9
+ /** @type {Array<[number, string]>} */
10
+ const tokens = []
11
+ let fence = ''
12
+ let fenceQuoted = false
13
+
14
+ /** @param {number} type @param {string} value */
15
+ const append = (type, value) => {
16
+ if (!value) return
17
+ const previous = tokens[tokens.length - 1]
18
+ if (previous?.[0] === type) previous[1] += value
19
+ else tokens.push([type, value])
20
+ }
21
+
22
+ for (const part of code.match(/[^\n]*(?:\n|$)/g) || []) {
23
+ if (!part) continue
24
+ const newline = part.endsWith('\n') ? '\n' : ''
25
+ const line = newline ? part.slice(0, -1) : part
26
+ /** @type {Array<[number, number]>} */
27
+ const ranges = []
28
+ const container = line.match(/^(?: {0,3}>[ \t]?)*/)?.[0] || ''
29
+ if (!fence || fenceQuoted) {
30
+ for (const match of container.matchAll(/>/g)) {
31
+ ranges.push([match.index, match.index + 1])
32
+ }
33
+ }
34
+
35
+ let start = container.length
36
+ let spaces = 0
37
+ while (spaces < 3 && line[start] === ' ') {
38
+ start++
39
+ spaces++
40
+ }
41
+ const fenceMarker = line.slice(start).match(/^(`{3,}|~{3,})/)?.[1]
42
+
43
+ if (fence) {
44
+ if (
45
+ fenceMarker?.[0] === fence[0] &&
46
+ fenceMarker.length >= fence.length &&
47
+ /^\s*$/.test(line.slice(start + fenceMarker.length))
48
+ ) {
49
+ ranges.push([start, start + fenceMarker.length])
50
+ fence = ''
51
+ fenceQuoted = false
52
+ }
53
+ } else if (fenceMarker) {
54
+ ranges.push([start, start + fenceMarker.length])
55
+ fence = fenceMarker
56
+ fenceQuoted = container.includes('>')
57
+ } else {
58
+ const prefix = line.slice(start).match(
59
+ /^(#{1,6}(?=\s)|(?:[-+*]|\d+[.)])(?=\s)|(?:(?:\*\s*){3,}|(?:-\s*){3,}|(?:_\s*){3,})$)/,
60
+ )?.[1]
61
+ if (prefix) ranges.push([start, start + prefix.length])
62
+
63
+ for (const match of line.matchAll(/(`+)(.*?)\1|(\*{1,3}|_{1,3}|~{2})(?=\S)(.*?\S)\3/g)) {
64
+ const marker = match[1] || match[3]
65
+ if (
66
+ line[match.index - 1] === '\\' ||
67
+ (marker[0] === '_' && /\w/.test(line[match.index - 1] || ''))
68
+ ) continue
69
+ ranges.push(
70
+ [match.index, match.index + marker.length],
71
+ [match.index + match[0].length - marker.length, match.index + match[0].length],
72
+ )
73
+ }
74
+ }
75
+
76
+ let offset = 0
77
+ for (const [rangeStart, rangeEnd] of ranges.sort((a, b) => a[0] - b[0])) {
78
+ if (rangeStart < offset) continue
79
+ append(T_IDENTIFIER, line.slice(offset, rangeStart))
80
+ append(T_SIGN, line.slice(rangeStart, rangeEnd))
81
+ offset = rangeEnd
82
+ }
83
+ append(T_IDENTIFIER, line.slice(offset) + newline)
84
+ }
85
+
86
+ return tokens
87
+ }
88
+
6
89
  export const annotateLine = (line) => {
7
90
  let annotation = ''
8
91
  if (/^#{1,6}\s/.test(line.value)) annotation = 'markdown-heading'
@@ -0,0 +1,5 @@
1
+ export const keywords: Set<string>;
2
+ export const typeKeywords: Set<string>;
3
+ export function onCommentStart(curr: string, next: string): number;
4
+ export function onCommentEnd(prev: string, curr: string): number;
5
+ export function onLiteral(curr: string, index: number, code: string): number;
@@ -0,0 +1,29 @@
1
+ // @ts-check
2
+
3
+ export const keywords = new Set([
4
+ 'addrspace', 'align', 'allowzero', 'and', 'anyframe', 'anytype', 'asm', 'async', 'await', 'break',
5
+ 'callconv', 'catch', 'comptime', 'const', 'continue', 'defer', 'else', 'enum', 'errdefer', 'error',
6
+ 'export', 'extern', 'false', 'fn', 'for', 'if', 'inline', 'linksection', 'noalias', 'noinline',
7
+ 'nosuspend', 'null', 'opaque', 'or', 'orelse', 'packed', 'pub', 'resume', 'return', 'struct',
8
+ 'suspend', 'switch', 'test', 'threadlocal', 'true', 'try', 'undefined', 'union', 'unreachable',
9
+ 'usingnamespace', 'var', 'volatile', 'while',
10
+ ])
11
+
12
+ export const typeKeywords = new Set([
13
+ 'anyerror', 'anyopaque', 'bool', 'c_char', 'c_int', 'c_long', 'c_longdouble', 'c_longlong',
14
+ 'c_short', 'c_uint', 'c_ulong', 'c_ulonglong', 'c_ushort', 'comptime_float', 'comptime_int',
15
+ 'f16', 'f32', 'f64', 'f80', 'f128', 'i8', 'i16', 'i32', 'i64', 'i128', 'isize', 'noreturn',
16
+ 'type', 'u8', 'u16', 'u32', 'u64', 'u128', 'usize', 'void',
17
+ ])
18
+
19
+ export const onCommentStart = (curr, next) => curr + next === '//' ? 1 : 0
20
+ export const onCommentEnd = (_prev, curr) => curr === '\n' ? 1 : 0
21
+
22
+ /** @param {string} curr @param {number} index @param {string} code */
23
+ export function onLiteral(curr, index, code) {
24
+ if (curr !== '\\' || code[index + 1] !== '\\') return 0
25
+ const lineStart = code.lastIndexOf('\n', index - 1) + 1
26
+ if (code.slice(lineStart, index).trim()) return 0
27
+ const lineEnd = code.indexOf('\n', index + 2)
28
+ return (lineEnd === -1 ? code.length : lineEnd) - index
29
+ }
package/lib/lang.js CHANGED
@@ -1,32 +1,10 @@
1
1
  // @ts-check
2
2
 
3
- import * as c from './lang/c.js'
4
- import * as cpp from './lang/cpp.js'
5
- import * as csharp from './lang/csharp.js'
6
- import * as css from './lang/css.js'
7
- import * as diff from './lang/diff.js'
8
- import * as dockerfile from './lang/dockerfile.js'
9
- import * as go from './lang/go.js'
10
- import * as html from './lang/html.js'
11
- import * as graphql from './lang/graphql.js'
12
- import * as hcl from './lang/hcl.js'
13
- import * as java from './lang/java.js'
14
- import * as json from './lang/json.js'
15
- import * as javascript from './lang/javascript.js'
16
- import * as kotlin from './lang/kotlin.js'
17
- import * as markdown from './lang/markdown.js'
18
- import * as php from './lang/php.js'
19
- import * as plaintext from './lang/plaintext.js'
20
- import * as powershell from './lang/powershell.js'
21
- import * as python from './lang/python.js'
22
- import * as ruby from './lang/ruby.js'
23
- import * as rust from './lang/rust.js'
24
- import * as shell from './lang/shell.js'
25
- import * as sql from './lang/sql.js'
26
- import * as swift from './lang/swift.js'
27
- import * as toml from './lang/toml.js'
28
- import * as typescript from './lang/typescript.js'
29
- import * as yaml from './lang/yaml.js'
3
+ import {
4
+ c, cpp, csharp, css, diff, dockerfile, go, graphql, hcl, html, java, javascript, json,
5
+ kotlin, lua, markdown, nonJavaScript, php, plaintext, powershell, python, ruby, rust, shell, sql,
6
+ swift, toml, typescript, yaml, zig,
7
+ } from './presets/configs.js'
30
8
 
31
9
  /**
32
10
  * @typedef {import('./core.js').ParseOptions} ParseOptions
@@ -38,20 +16,6 @@ import * as yaml from './lang/yaml.js'
38
16
  * }} Language
39
17
  */
40
18
 
41
- /**
42
- * Disable JavaScript-only scanner modes for a non-JavaScript language.
43
- * @param {ParseOptions} config
44
- * @returns {ParseOptions}
45
- */
46
- function nonJavaScript(config) {
47
- return {
48
- ...config,
49
- jsx: false,
50
- regex: false,
51
- templateStrings: false,
52
- }
53
- }
54
-
55
19
  /** @type {readonly Language[]} */
56
20
  const languages = [
57
21
  { id: 'javascript', extension: 'js', aliases: ['js', 'jsx', 'node'], config: javascript },
@@ -81,6 +45,8 @@ const languages = [
81
45
  { id: 'dockerfile', extension: 'dockerfile', aliases: ['docker'], config: nonJavaScript(dockerfile) },
82
46
  { id: 'graphql', extension: 'graphql', aliases: ['gql'], config: nonJavaScript(graphql) },
83
47
  { id: 'hcl', extension: 'hcl', aliases: ['terraform', 'tf'], config: nonJavaScript(hcl) },
48
+ { id: 'zig', extension: 'zig', aliases: [], config: nonJavaScript(zig) },
49
+ { id: 'lua', extension: 'lua', aliases: [], config: nonJavaScript(lua) },
84
50
  ]
85
51
 
86
52
  /** @param {string} value */
@@ -2,11 +2,11 @@
2
2
  export const onCommentStart = (currentChar, nextChar) => {
3
3
  const pair = currentChar + nextChar
4
4
  if (pair === '//') return 1
5
- if (pair === '/*') return 1
5
+ if (pair === '/*') return 2
6
6
  return 0
7
7
  }
8
8
 
9
9
  export const onCommentEnd = (prevChar, currChar) => {
10
10
  if (currChar === '\n') return 1
11
- return prevChar + currChar === '*/' ? 1 : 0
11
+ return prevChar + currChar === '*/' ? 2 : 0
12
12
  }
@@ -0,0 +1,92 @@
1
+ // @ts-check
2
+
3
+ import * as c from '../lang/c.js'
4
+ import * as cpp from '../lang/cpp.js'
5
+ import * as csharp from '../lang/csharp.js'
6
+ import * as css from '../lang/css.js'
7
+ import * as diff from '../lang/diff.js'
8
+ import * as dockerfile from '../lang/dockerfile.js'
9
+ import * as go from '../lang/go.js'
10
+ import * as graphql from '../lang/graphql.js'
11
+ import * as hcl from '../lang/hcl.js'
12
+ import * as html from '../lang/html.js'
13
+ import * as java from '../lang/java.js'
14
+ import * as javascript from '../lang/javascript.js'
15
+ import * as json from '../lang/json.js'
16
+ import * as kotlin from '../lang/kotlin.js'
17
+ import * as lua from '../lang/lua.js'
18
+ import * as markdown from '../lang/markdown.js'
19
+ import * as php from '../lang/php.js'
20
+ import * as plaintext from '../lang/plaintext.js'
21
+ import * as powershell from '../lang/powershell.js'
22
+ import * as python from '../lang/python.js'
23
+ import * as ruby from '../lang/ruby.js'
24
+ import * as rust from '../lang/rust.js'
25
+ import * as shell from '../lang/shell.js'
26
+ import * as sql from '../lang/sql.js'
27
+ import * as swift from '../lang/swift.js'
28
+ import * as toml from '../lang/toml.js'
29
+ import * as typescript from '../lang/typescript.js'
30
+ import * as yaml from '../lang/yaml.js'
31
+ import * as zig from '../lang/zig.js'
32
+
33
+ /**
34
+ * Disable JavaScript-only scanner modes for a non-JavaScript language.
35
+ * @param {import('../core.js').ParseOptions} config
36
+ * @returns {import('../core.js').ParseOptions}
37
+ */
38
+ function nonJavaScript(config) {
39
+ return {
40
+ ...config,
41
+ jsx: false,
42
+ regex: false,
43
+ templateStrings: false,
44
+ }
45
+ }
46
+
47
+ function createConfigs() {
48
+ return {
49
+ javascript,
50
+ typescript,
51
+ css: nonJavaScript(css),
52
+ python: nonJavaScript(python),
53
+ c: nonJavaScript(c),
54
+ go: nonJavaScript(go),
55
+ java: nonJavaScript(java),
56
+ rust: nonJavaScript(rust),
57
+ json: nonJavaScript(json),
58
+ diff: nonJavaScript(diff),
59
+ shell: nonJavaScript(shell),
60
+ cpp: nonJavaScript(cpp),
61
+ csharp: nonJavaScript(csharp),
62
+ sql: nonJavaScript(sql),
63
+ html,
64
+ yaml: nonJavaScript(yaml),
65
+ markdown: nonJavaScript(markdown),
66
+ plaintext: nonJavaScript(plaintext),
67
+ ruby: nonJavaScript(ruby),
68
+ kotlin: nonJavaScript(kotlin),
69
+ swift: nonJavaScript(swift),
70
+ php: nonJavaScript(php),
71
+ toml: nonJavaScript(toml),
72
+ powershell: nonJavaScript(powershell),
73
+ dockerfile: nonJavaScript(dockerfile),
74
+ graphql: nonJavaScript(graphql),
75
+ hcl: nonJavaScript(hcl),
76
+ zig: nonJavaScript(zig),
77
+ lua: nonJavaScript(lua),
78
+ }
79
+ }
80
+
81
+ const configs = /* @__PURE__ */ createConfigs()
82
+
83
+ /** @param {string | undefined} name */
84
+ function configFor(name) {
85
+ return configs[name || 'javascript']
86
+ }
87
+
88
+ export {
89
+ c, configFor, configs, cpp, csharp, css, diff, dockerfile, go, graphql, hcl, html, java,
90
+ javascript, json, kotlin, lua, markdown, nonJavaScript, php, plaintext, powershell, python, ruby,
91
+ rust, shell, sql, swift, toml, typescript, yaml, zig,
92
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sugar-high",
3
- "version": "2.2.1",
3
+ "version": "2.3.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/huozhi/sugar-high.git",