sugar-high 1.3.0 → 2.0.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 +128 -43
- package/lib/core.d.ts +117 -0
- package/lib/core.js +202 -0
- package/lib/index.d.ts +39 -24
- package/lib/index.js +15 -1007
- package/lib/lang.d.ts +14 -0
- package/lib/lang.js +132 -0
- package/lib/presets/lang/cpp.js +22 -0
- package/lib/presets/lang/csharp.js +21 -0
- package/lib/presets/lang/css.js +5 -0
- package/lib/presets/lang/diff.js +12 -6
- package/lib/presets/lang/dockerfile.js +5 -0
- package/lib/presets/lang/graphql.js +5 -0
- package/lib/presets/lang/hash-comment-base.js +7 -0
- package/lib/presets/lang/hcl.js +4 -0
- package/lib/presets/lang/html.js +14 -0
- package/lib/presets/lang/javascript-runtime.js +781 -0
- package/lib/presets/lang/javascript.js +6 -0
- package/lib/presets/lang/json.js +4 -0
- package/lib/presets/lang/kotlin.js +5 -0
- package/lib/presets/lang/markdown.js +15 -0
- package/lib/presets/lang/php.js +5 -0
- package/lib/presets/lang/plain-base.js +4 -0
- package/lib/presets/lang/powershell.js +5 -0
- package/lib/presets/lang/shell.js +10 -0
- package/lib/presets/lang/sql.js +31 -0
- package/lib/presets/lang/swift.js +5 -0
- package/lib/presets/lang/toml.js +5 -0
- package/lib/presets/lang/typescript.js +7 -0
- package/lib/presets/lang/yaml.js +10 -0
- package/lib/shared.js +149 -0
- package/package.json +15 -10
- package/lib/presets/index.d.ts +0 -18
- package/lib/presets/index.js +0 -8
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { tokenize as tokenizeJavaScript } from './javascript-runtime.js'
|
|
3
|
+
|
|
4
|
+
// JavaScript includes JSX and preserves the lightweight TypeScript heuristic used by the default
|
|
5
|
+
// highlighter. Use the TypeScript preset to force TS/TSX behavior for ambiguous snippets.
|
|
6
|
+
export const tokenize = tokenizeJavaScript
|
package/lib/presets/lang/json.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import { onCommentEnd, onCommentStart } from './clike-base.js'
|
|
4
|
+
|
|
3
5
|
export const keywords = new Set(['true', 'false', 'null'])
|
|
4
6
|
export const quotedKeys = true
|
|
7
|
+
// JSONC is treated as the comment-tolerant JSON dialect rather than a separate language.
|
|
8
|
+
export { onCommentEnd, onCommentStart }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { onCommentEnd, onCommentStart } from './clike-base.js'
|
|
3
|
+
export const keywords = new Set(['as','break','by','catch','class','companion','const','constructor','continue','data','do','else','enum','false','finally','for','fun','get','if','import','in','infix','init','interface','internal','is','lateinit','noinline','null','object','open','operator','out','override','package','private','protected','public','reified','return','sealed','set','suspend','tailrec','this','throw','true','try','typealias','val','var','vararg','when','where','while'])
|
|
4
|
+
export const typeKeywords = new Set(['Any','Boolean','Byte','Char','Double','Float','Int','Long','Nothing','Short','String','Unit'])
|
|
5
|
+
export { onCommentEnd, onCommentStart }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { onCommentEnd, onCommentStart } from './plain-base.js'
|
|
3
|
+
|
|
4
|
+
export const keywords = new Set([])
|
|
5
|
+
|
|
6
|
+
export const annotateLine = (line) => {
|
|
7
|
+
let annotation = ''
|
|
8
|
+
if (/^#{1,6}\s/.test(line.value)) annotation = 'markdown-heading'
|
|
9
|
+
else if (/^\s*>/.test(line.value)) annotation = 'markdown-quote'
|
|
10
|
+
else if (/^\s*(?:[-*+] |\d+[.)] )/.test(line.value)) annotation = 'markdown-list'
|
|
11
|
+
else if (/^\s*```/.test(line.value)) annotation = 'markdown-fence'
|
|
12
|
+
if (annotation) line.annotations.push(annotation)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { onCommentEnd, onCommentStart }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
export const keywords = new Set(['abstract','and','array','as','break','callable','case','catch','class','clone','const','continue','declare','default','do','echo','else','elseif','empty','enddeclare','endfor','endforeach','endif','endswitch','endwhile','enum','eval','exit','extends','false','final','finally','fn','for','foreach','from','function','global','goto','if','implements','include','include_once','instanceof','insteadof','interface','isset','list','match','namespace','new','null','or','print','private','protected','public','readonly','require','require_once','return','static','switch','throw','trait','true','try','unset','use','var','while','xor','yield'])
|
|
3
|
+
export const typeKeywords = new Set(['bool','float','int','iterable','mixed','never','object','string','void'])
|
|
4
|
+
export const onCommentStart = (curr, next) => curr === '#' ? 1 : curr + next === '//' ? 1 : curr + next === '/*' ? 2 : 0
|
|
5
|
+
export const onCommentEnd = (prev, curr) => curr === '\n' ? 1 : prev + curr === '*/' ? 2 : 0
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
export const caseInsensitive = true
|
|
3
|
+
export const keywords = new Set(['begin','break','catch','class','continue','data','define','do','dynamicparam','else','elseif','end','enum','exit','filter','finally','for','foreach','from','function','if','in','param','process','return','switch','throw','trap','try','until','using','while'])
|
|
4
|
+
export const onCommentStart = (curr, next) => curr === '#' ? 1 : curr + next === '<#' ? 2 : 0
|
|
5
|
+
export const onCommentEnd = (prev, curr) => curr === '\n' ? 1 : prev + curr === '#>' ? 2 : 0
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { onCommentEnd, onCommentStart } from './hash-comment-base.js'
|
|
3
|
+
|
|
4
|
+
export const keywords = new Set([
|
|
5
|
+
'case', 'coproc', 'do', 'done', 'elif', 'else', 'esac', 'export', 'fi', 'for',
|
|
6
|
+
'function', 'if', 'in', 'local', 'readonly', 'return', 'select', 'then', 'time',
|
|
7
|
+
'until', 'while',
|
|
8
|
+
])
|
|
9
|
+
|
|
10
|
+
export { onCommentEnd, onCommentStart }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
export const keywords = new Set([
|
|
4
|
+
'add', 'all', 'alter', 'and', 'as', 'asc', 'between', 'by', 'case', 'check',
|
|
5
|
+
'column', 'constraint', 'create', 'cross', 'database', 'default', 'delete', 'desc',
|
|
6
|
+
'distinct', 'drop', 'else', 'end', 'exists', 'foreign', 'from', 'full', 'group',
|
|
7
|
+
'having', 'in', 'index', 'inner', 'insert', 'into', 'is', 'join', 'key', 'left',
|
|
8
|
+
'like', 'limit', 'not', 'null', 'offset', 'on', 'or', 'order', 'outer', 'primary',
|
|
9
|
+
'references', 'right', 'select', 'set', 'table', 'then', 'union', 'unique', 'update',
|
|
10
|
+
'values', 'view', 'when', 'where', 'with',
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
export const typeKeywords = new Set([
|
|
14
|
+
'bigint', 'binary', 'bit', 'blob', 'boolean', 'char', 'date', 'datetime', 'decimal',
|
|
15
|
+
'double', 'float', 'int', 'integer', 'interval', 'json', 'numeric', 'real', 'smallint',
|
|
16
|
+
'text', 'time', 'timestamp', 'uuid', 'varchar',
|
|
17
|
+
])
|
|
18
|
+
|
|
19
|
+
export const caseInsensitive = true
|
|
20
|
+
|
|
21
|
+
export const onCommentStart = (currentChar, nextChar) => {
|
|
22
|
+
const pair = currentChar + nextChar
|
|
23
|
+
if (pair === '--') return 1
|
|
24
|
+
if (pair === '/*') return 2
|
|
25
|
+
return 0
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const onCommentEnd = (prevChar, currChar) => {
|
|
29
|
+
if (currChar === '\n') return 1
|
|
30
|
+
return prevChar + currChar === '*/' ? 2 : 0
|
|
31
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { onCommentEnd, onCommentStart } from './clike-base.js'
|
|
3
|
+
export const keywords = new Set(['as','associatedtype','break','case','catch','class','continue','convenience','default','defer','deinit','didSet','do','dynamic','else','enum','extension','fallthrough','false','fileprivate','final','for','func','get','guard','if','import','in','indirect','infix','init','inout','internal','is','lazy','let','mutating','nil','nonmutating','open','operator','override','precedencegroup','private','protocol','public','repeat','required','rethrows','return','self','set','some','static','struct','subscript','super','switch','throw','throws','true','try','typealias','unowned','var','weak','where','while','willSet'])
|
|
4
|
+
export const typeKeywords = new Set(['Any','Bool','Character','Double','Float','Int','Never','String','UInt','Void'])
|
|
5
|
+
export { onCommentEnd, onCommentStart }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { onCommentEnd, onCommentStart } from './hash-comment-base.js'
|
|
3
|
+
|
|
4
|
+
export const keywords = new Set([
|
|
5
|
+
'false', 'False', 'FALSE', 'no', 'No', 'NO', 'null', 'Null', 'NULL',
|
|
6
|
+
'off', 'Off', 'OFF', 'on', 'On', 'ON', 'true', 'True', 'TRUE', 'yes', 'Yes', 'YES',
|
|
7
|
+
])
|
|
8
|
+
|
|
9
|
+
export const quotedKeys = true
|
|
10
|
+
export { onCommentEnd, onCommentStart }
|
package/lib/shared.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
const TokenTypes = /** @type {const} */ ('identifier keyword string class property entity jsxliterals sign comment break space'.split(' '))
|
|
4
|
+
const [
|
|
5
|
+
T_IDENTIFIER, T_KEYWORD, T_STRING, T_CLASS, T_PROPERTY, T_ENTITY,
|
|
6
|
+
T_JSX_LITERALS, T_SIGN, T_COMMENT, T_BREAK, T_SPACE,
|
|
7
|
+
] = TokenTypes.map((_, index) => index)
|
|
8
|
+
|
|
9
|
+
const SugarHigh = /** @type {const} */ ({
|
|
10
|
+
TokenTypes,
|
|
11
|
+
TokenMap: new Map(TokenTypes.map((type, index) => [type, index])),
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
/** @param {string} value @param {Array<[number, string]>} tokens */
|
|
15
|
+
function assemble(value, tokens) {
|
|
16
|
+
const lines = []
|
|
17
|
+
let lineIndex = 0
|
|
18
|
+
/** @type {Array<[number, string]>} */
|
|
19
|
+
const lineTokens = []
|
|
20
|
+
let lastWasBreak = false
|
|
21
|
+
|
|
22
|
+
/** @param {Array<[number, string]>} tokens */
|
|
23
|
+
function flushLine(tokens) {
|
|
24
|
+
lines.push({
|
|
25
|
+
index: lineIndex++,
|
|
26
|
+
value: tokens.map(([, tokenValue]) => tokenValue).join(''),
|
|
27
|
+
tokens: tokens.map(([type, tokenValue]) => ({
|
|
28
|
+
type: TokenTypes[type],
|
|
29
|
+
value: tokenValue,
|
|
30
|
+
})),
|
|
31
|
+
annotations: [],
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
36
|
+
const token = tokens[index]
|
|
37
|
+
const [type, value] = token
|
|
38
|
+
if (type !== T_BREAK) {
|
|
39
|
+
if (value.includes('\n')) {
|
|
40
|
+
const values = value.split('\n')
|
|
41
|
+
for (let part = 0; part < values.length; part++) {
|
|
42
|
+
lineTokens.push([type, values[part]])
|
|
43
|
+
if (part < values.length - 1) {
|
|
44
|
+
flushLine(lineTokens)
|
|
45
|
+
lineTokens.length = 0
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
lineTokens.push(token)
|
|
50
|
+
}
|
|
51
|
+
lastWasBreak = false
|
|
52
|
+
} else {
|
|
53
|
+
if (lastWasBreak) flushLine([])
|
|
54
|
+
else {
|
|
55
|
+
flushLine(lineTokens)
|
|
56
|
+
lineTokens.length = 0
|
|
57
|
+
}
|
|
58
|
+
if (index === tokens.length - 1) flushLine([])
|
|
59
|
+
lastWasBreak = true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (lineTokens.length) flushLine(lineTokens)
|
|
64
|
+
return { value, lines }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {import('./core.js').ParsedCode} parsed
|
|
69
|
+
* @param {import('./core.js').DisplayOptions | undefined} options
|
|
70
|
+
*/
|
|
71
|
+
function generate(parsed, options) {
|
|
72
|
+
const cx = options?.cx
|
|
73
|
+
const mark = options?.mark
|
|
74
|
+
const markLine = options?.markLine
|
|
75
|
+
|
|
76
|
+
return parsed.lines.map((parsedLine) => {
|
|
77
|
+
const line = {
|
|
78
|
+
index: parsedLine.index,
|
|
79
|
+
value: parsedLine.value,
|
|
80
|
+
tokens: parsedLine.tokens,
|
|
81
|
+
annotations: parsedLine.annotations,
|
|
82
|
+
className: `sh__line${parsedLine.annotations.map(annotation => ` sh__line--${annotation}`).join('')}`,
|
|
83
|
+
style: {},
|
|
84
|
+
properties: {},
|
|
85
|
+
}
|
|
86
|
+
markLine?.(line)
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
type: 'element',
|
|
90
|
+
tagName: 'span',
|
|
91
|
+
children: parsedLine.tokens.map(({ type, value }) => {
|
|
92
|
+
const extraClassName = cx?.[type]
|
|
93
|
+
const token = {
|
|
94
|
+
type,
|
|
95
|
+
value,
|
|
96
|
+
className: `sh__token--${type}${extraClassName ? ` ${extraClassName}` : ''}`,
|
|
97
|
+
style: { color: `var(--sh-${type})` },
|
|
98
|
+
properties: {},
|
|
99
|
+
}
|
|
100
|
+
mark?.(token)
|
|
101
|
+
return {
|
|
102
|
+
type: 'element',
|
|
103
|
+
tokenType: token.type,
|
|
104
|
+
tagName: 'span',
|
|
105
|
+
children: [{ type: 'text', value: token.value }],
|
|
106
|
+
properties: {
|
|
107
|
+
...token.properties,
|
|
108
|
+
className: token.className,
|
|
109
|
+
style: token.style,
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
}),
|
|
113
|
+
properties: {
|
|
114
|
+
...line.properties,
|
|
115
|
+
className: line.className,
|
|
116
|
+
style: line.style,
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const entities = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }
|
|
123
|
+
/** @param {string} value */
|
|
124
|
+
const encode = (value) => value.replace(/[&<>"']/g, character => entities[character])
|
|
125
|
+
|
|
126
|
+
/** @param {Record<string, any>} values */
|
|
127
|
+
function attributes(values) {
|
|
128
|
+
const style = Object.entries(values.style || {})
|
|
129
|
+
.map(([key, value]) => `${key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`)}:${value}`).join(';')
|
|
130
|
+
const properties = Object.entries(values)
|
|
131
|
+
.filter(([key, value]) => /^[\w:-]+$/.test(key) && key !== 'className' && key !== 'style' && value !== false && value != null)
|
|
132
|
+
.map(([key, value]) => value === true ? key : `${key}="${encode(String(value))}"`).join(' ')
|
|
133
|
+
return `class="${encode(values.className || '')}"${style ? ` style="${encode(style)}"` : ''}${properties ? ` ${properties}` : ''}`
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** @param {Array<any>} lines */
|
|
137
|
+
function toHtml(lines) {
|
|
138
|
+
return lines.map(line => {
|
|
139
|
+
const children = line.children.map(token => {
|
|
140
|
+
return `<${token.tagName} ${attributes(token.properties)}>${encode(token.children[0].value)}</${token.tagName}>`
|
|
141
|
+
}).join('')
|
|
142
|
+
return `<${line.tagName} ${attributes(line.properties)}>${children}</${line.tagName}>`
|
|
143
|
+
}).join('\n')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export {
|
|
147
|
+
assemble, encode, generate, SugarHigh, toHtml, TokenTypes, T_BREAK, T_CLASS, T_COMMENT, T_ENTITY, T_IDENTIFIER,
|
|
148
|
+
T_JSX_LITERALS, T_KEYWORD, T_PROPERTY, T_SIGN, T_SPACE, T_STRING,
|
|
149
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sugar-high",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/huozhi/sugar-high.git",
|
|
@@ -14,23 +14,28 @@
|
|
|
14
14
|
"types": "./lib/index.d.ts",
|
|
15
15
|
"default": "./lib/index.js"
|
|
16
16
|
},
|
|
17
|
-
"./
|
|
18
|
-
"types": "./lib/
|
|
19
|
-
"default": "./lib/
|
|
17
|
+
"./core": {
|
|
18
|
+
"types": "./lib/core.d.ts",
|
|
19
|
+
"default": "./lib/core.js"
|
|
20
|
+
},
|
|
21
|
+
"./lang": {
|
|
22
|
+
"types": "./lib/lang.d.ts",
|
|
23
|
+
"default": "./lib/lang.js"
|
|
20
24
|
}
|
|
21
25
|
},
|
|
22
|
-
"description": "
|
|
26
|
+
"description": "Lightweight, zero-dependency syntax highlighting for popular programming languages",
|
|
23
27
|
"files": [
|
|
24
28
|
"lib"
|
|
25
29
|
],
|
|
26
30
|
"license": "MIT",
|
|
27
|
-
"scripts": {
|
|
28
|
-
"test": "vitest",
|
|
29
|
-
"build": "echo 'package requires no build'"
|
|
30
|
-
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "22.12.0",
|
|
33
33
|
"typescript": "6.0.2",
|
|
34
34
|
"vitest": "^3.0.2"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "vitest",
|
|
38
|
+
"build": "echo 'package requires no build'",
|
|
39
|
+
"benchmark": "node scripts/benchmark.mjs"
|
|
35
40
|
}
|
|
36
|
-
}
|
|
41
|
+
}
|
package/lib/presets/index.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
type LanguageConfig = {
|
|
2
|
-
keywords: Set<string>
|
|
3
|
-
typeKeywords?: Set<string>
|
|
4
|
-
onCommentStart?(curr: string, next: string): 0 | 1 | 2
|
|
5
|
-
onCommentEnd?(prev: string, curr: string): 0 | 1 | 2
|
|
6
|
-
onQuote?(curr: string, i: number, code: string): number | null | undefined
|
|
7
|
-
quotedKeys?: boolean
|
|
8
|
-
lineClassName?(line: string, index: number): string | null | undefined
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const css: LanguageConfig
|
|
12
|
-
export const rust: LanguageConfig
|
|
13
|
-
export const python: LanguageConfig
|
|
14
|
-
export const c: LanguageConfig
|
|
15
|
-
export const go: LanguageConfig
|
|
16
|
-
export const java: LanguageConfig
|
|
17
|
-
export const diff: LanguageConfig
|
|
18
|
-
export const json: LanguageConfig
|
package/lib/presets/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export * as css from './lang/css.js'
|
|
2
|
-
export * as rust from './lang/rust.js'
|
|
3
|
-
export * as python from './lang/python.js'
|
|
4
|
-
export * as c from './lang/c.js'
|
|
5
|
-
export * as go from './lang/go.js'
|
|
6
|
-
export * as java from './lang/java.js'
|
|
7
|
-
export * as diff from './lang/diff.js'
|
|
8
|
-
export * as json from './lang/json.js'
|