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/lib/lang.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { LanguageName } from './index.js'
2
+ import type { ParseOptions } from './core.js'
3
+
4
+ export type Language = Readonly<{
5
+ id: LanguageName
6
+ /** Preferred file extension without a leading dot. */
7
+ extension: string
8
+ aliases: readonly string[]
9
+ config?: ParseOptions
10
+ }>
11
+
12
+ export const languages: readonly Language[]
13
+ /** Normalize a language name, fence alias, or extension to its canonical name. */
14
+ export function lang(name: string): LanguageName | undefined
package/lib/lang.js ADDED
@@ -0,0 +1,132 @@
1
+ // @ts-check
2
+
3
+ import * as c from './presets/lang/c.js'
4
+ import * as cpp from './presets/lang/cpp.js'
5
+ import * as csharp from './presets/lang/csharp.js'
6
+ import * as css from './presets/lang/css.js'
7
+ import * as diff from './presets/lang/diff.js'
8
+ import * as dockerfile from './presets/lang/dockerfile.js'
9
+ import * as go from './presets/lang/go.js'
10
+ import * as html from './presets/lang/html.js'
11
+ import * as graphql from './presets/lang/graphql.js'
12
+ import * as hcl from './presets/lang/hcl.js'
13
+ import * as java from './presets/lang/java.js'
14
+ import * as json from './presets/lang/json.js'
15
+ import * as javascript from './presets/lang/javascript.js'
16
+ import * as kotlin from './presets/lang/kotlin.js'
17
+ import * as markdown from './presets/lang/markdown.js'
18
+ import * as php from './presets/lang/php.js'
19
+ import * as powershell from './presets/lang/powershell.js'
20
+ import * as python from './presets/lang/python.js'
21
+ import * as rust from './presets/lang/rust.js'
22
+ import * as shell from './presets/lang/shell.js'
23
+ import * as sql from './presets/lang/sql.js'
24
+ import * as swift from './presets/lang/swift.js'
25
+ import * as toml from './presets/lang/toml.js'
26
+ import * as typescript from './presets/lang/typescript.js'
27
+ import * as yaml from './presets/lang/yaml.js'
28
+
29
+ /**
30
+ * @typedef {import('./core.js').ParseOptions} ParseOptions
31
+ * @typedef {{
32
+ * id: string
33
+ * extension: string
34
+ * aliases: readonly string[]
35
+ * config?: ParseOptions
36
+ * }} Language
37
+ */
38
+
39
+ /**
40
+ * Disable JavaScript-only scanner modes for a non-JavaScript language.
41
+ * @param {ParseOptions} config
42
+ * @returns {ParseOptions}
43
+ */
44
+ function nonJavaScript(config) {
45
+ return {
46
+ ...config,
47
+ jsx: false,
48
+ regex: false,
49
+ templateStrings: false,
50
+ }
51
+ }
52
+
53
+ /** @type {readonly Language[]} */
54
+ const languages = [
55
+ { id: 'javascript', extension: 'js', aliases: ['js', 'jsx', 'node'], config: javascript },
56
+ { id: 'typescript', extension: 'ts', aliases: ['ts', 'tsx'], config: typescript },
57
+ { id: 'css', extension: 'css', aliases: ['scss'], config: nonJavaScript(css) },
58
+ { id: 'python', extension: 'py', aliases: ['py', 'python3'], config: nonJavaScript(python) },
59
+ { id: 'c', extension: 'c', aliases: [], config: nonJavaScript(c) },
60
+ { id: 'go', extension: 'go', aliases: ['golang'], config: nonJavaScript(go) },
61
+ { id: 'java', extension: 'java', aliases: [], config: nonJavaScript(java) },
62
+ { id: 'rust', extension: 'rs', aliases: ['rs'], config: nonJavaScript(rust) },
63
+ { id: 'json', extension: 'json', aliases: ['jsonc'], config: nonJavaScript(json) },
64
+ { id: 'diff', extension: 'diff', aliases: ['patch'], config: nonJavaScript(diff) },
65
+ { id: 'shell', extension: 'sh', aliases: ['sh', 'bash', 'zsh'], config: nonJavaScript(shell) },
66
+ { id: 'cpp', extension: 'cpp', aliases: ['c++', 'cc', 'cxx'], config: nonJavaScript(cpp) },
67
+ { id: 'csharp', extension: 'cs', aliases: ['c#', 'cs', 'dotnet'], config: nonJavaScript(csharp) },
68
+ { id: 'sql', extension: 'sql', aliases: [], config: nonJavaScript(sql) },
69
+ { id: 'html', extension: 'html', aliases: ['htm', 'xml'], config: html },
70
+ { id: 'yaml', extension: 'yaml', aliases: ['yml'], config: nonJavaScript(yaml) },
71
+ { id: 'markdown', extension: 'md', aliases: ['md', 'mdx'], config: nonJavaScript(markdown) },
72
+ { id: 'kotlin', extension: 'kt', aliases: ['kts'], config: nonJavaScript(kotlin) },
73
+ { id: 'swift', extension: 'swift', aliases: [], config: nonJavaScript(swift) },
74
+ { id: 'php', extension: 'php', aliases: [], config: nonJavaScript(php) },
75
+ { id: 'toml', extension: 'toml', aliases: [], config: nonJavaScript(toml) },
76
+ { id: 'powershell', extension: 'ps1', aliases: ['pwsh'], config: nonJavaScript(powershell) },
77
+ { id: 'dockerfile', extension: 'dockerfile', aliases: ['docker'], config: nonJavaScript(dockerfile) },
78
+ { id: 'graphql', extension: 'graphql', aliases: ['gql'], config: nonJavaScript(graphql) },
79
+ { id: 'hcl', extension: 'hcl', aliases: ['terraform', 'tf'], config: nonJavaScript(hcl) },
80
+ ]
81
+
82
+ /** @param {string} value */
83
+ function normalizeLanguageName(value) {
84
+ return value.trim().toLowerCase().replace(/^\./, '')
85
+ }
86
+
87
+ /** @type {Map<string, Language>} */
88
+ const languageLookup = new Map()
89
+
90
+ for (const language of languages) {
91
+ const names = new Set([language.id, language.extension, ...language.aliases])
92
+ for (const name of names) {
93
+ const normalized = normalizeLanguageName(name)
94
+ const existing = languageLookup.get(normalized)
95
+ if (existing && existing !== language) {
96
+ throw new Error(
97
+ `Language name "${normalized}" is shared by "${existing.id}" and "${language.id}"`
98
+ )
99
+ }
100
+ languageLookup.set(normalized, language)
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Find canonical language metadata using a name, alias, or preferred extension.
106
+ * @param {string} name
107
+ * @returns {Language | undefined}
108
+ */
109
+ function findLanguage(name) {
110
+ if (typeof name !== 'string') return undefined
111
+ return languageLookup.get(normalizeLanguageName(name))
112
+ }
113
+
114
+ /**
115
+ * Find metadata only when the input is already a canonical language name.
116
+ * Direct highlighting uses this stricter lookup; integrations resolve aliases first.
117
+ * @param {string} name
118
+ * @returns {Language | undefined}
119
+ */
120
+ /**
121
+ * Resolve a name, alias, or extension to its canonical language name.
122
+ * @param {string} name
123
+ * @returns {string | undefined}
124
+ */
125
+ function lang(name) {
126
+ return findLanguage(name)?.id
127
+ }
128
+
129
+ export {
130
+ lang,
131
+ languages,
132
+ }
@@ -0,0 +1,22 @@
1
+ // @ts-check
2
+ import { onCommentEnd, onCommentStart } from './clike-base.js'
3
+
4
+ export const keywords = new Set([
5
+ 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'break',
6
+ 'case', 'catch', 'class', 'compl', 'concept', 'const', 'consteval', 'constexpr',
7
+ 'constinit', 'const_cast', 'continue', 'co_await', 'co_return', 'co_yield', 'decltype',
8
+ 'default', 'delete', 'do', 'dynamic_cast', 'else', 'enum', 'explicit', 'export',
9
+ 'extern', 'false', 'for', 'friend', 'goto', 'if', 'inline', 'mutable', 'namespace',
10
+ 'new', 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'private',
11
+ 'protected', 'public', 'register', 'reinterpret_cast', 'requires', 'return', 'sizeof',
12
+ 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this',
13
+ 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union',
14
+ 'using', 'virtual', 'volatile', 'while', 'xor', 'xor_eq',
15
+ ])
16
+
17
+ export const typeKeywords = new Set([
18
+ 'bool', 'char', 'char8_t', 'char16_t', 'char32_t', 'double', 'float', 'int', 'long',
19
+ 'short', 'signed', 'unsigned', 'void', 'wchar_t',
20
+ ])
21
+
22
+ export { onCommentEnd, onCommentStart }
@@ -0,0 +1,21 @@
1
+ // @ts-check
2
+ import { onCommentEnd, onCommentStart } from './clike-base.js'
3
+
4
+ export const keywords = new Set([
5
+ 'abstract', 'as', 'async', 'await', 'base', 'break', 'case', 'catch', 'checked',
6
+ 'class', 'const', 'continue', 'default', 'delegate', 'do', 'else', 'enum', 'event',
7
+ 'explicit', 'extern', 'false', 'finally', 'fixed', 'for', 'foreach', 'from', 'get',
8
+ 'global', 'goto', 'if', 'implicit', 'in', 'init', 'interface', 'internal', 'into', 'is',
9
+ 'join', 'let', 'lock', 'namespace', 'new', 'null', 'on', 'operator', 'orderby', 'out',
10
+ 'override', 'params', 'partial', 'private', 'protected', 'public', 'readonly', 'record',
11
+ 'ref', 'remove', 'required', 'return', 'sealed', 'select', 'set', 'sizeof', 'stackalloc',
12
+ 'static', 'struct', 'switch', 'this', 'throw', 'true', 'try', 'typeof', 'unchecked',
13
+ 'unsafe', 'using', 'value', 'virtual', 'volatile', 'when', 'where', 'while', 'with', 'yield',
14
+ ])
15
+
16
+ export const typeKeywords = new Set([
17
+ 'bool', 'byte', 'char', 'decimal', 'double', 'dynamic', 'float', 'int', 'long', 'nint',
18
+ 'nuint', 'object', 'sbyte', 'short', 'string', 'uint', 'ulong', 'ushort', 'void',
19
+ ])
20
+
21
+ export { onCommentEnd, onCommentStart }
@@ -12,3 +12,8 @@ export const onCommentStart = (currentChar, nextChar) => {
12
12
  export const onCommentEnd = (prevChar, currChar) => {
13
13
  return '*/' === (prevChar + currChar) ? 1 : 0
14
14
  }
15
+
16
+ export const onLiteral = (curr, index, code) => {
17
+ if (curr !== '#') return 0
18
+ return code.slice(index).match(/^#(?:[\da-f]{8}|[\da-f]{6}|[\da-f]{4}|[\da-f]{3})(?![\w-])/i)?.[0].length || 0
19
+ }
@@ -2,10 +2,16 @@
2
2
 
3
3
  export const keywords = new Set([])
4
4
 
5
- export const lineClassName = (line) => {
6
- if (line.startsWith('+') && !line.startsWith('+++')) return 'sh__line--diff-add'
7
- if (line.startsWith('-') && !line.startsWith('---')) return 'sh__line--diff-remove'
8
- if (line.startsWith('@@')) return 'sh__line--diff-hunk'
9
- if (/^(diff --git|index |--- |\+\+\+ )/.test(line)) return 'sh__line--diff-meta'
10
- return undefined
5
+ export const annotateLine = (line) => {
6
+ let annotation = ''
7
+ if (line.value.startsWith('+') && !line.value.startsWith('+++')) annotation = 'diff-add'
8
+ else if (line.value.startsWith('-') && !line.value.startsWith('---')) annotation = 'diff-remove'
9
+ else if (line.value.startsWith('@@')) annotation = 'diff-hunk'
10
+ else if (/^(diff --git|index |--- |\+\+\+ )/.test(line.value)) {
11
+ annotation = 'diff-meta'
12
+ for (const token of line.tokens) {
13
+ if (token.type === 'property') token.type = 'identifier'
14
+ }
15
+ }
16
+ if (annotation) line.annotations.push(annotation)
11
17
  }
@@ -0,0 +1,5 @@
1
+ // @ts-check
2
+ import { onCommentEnd, onCommentStart } from './hash-comment-base.js'
3
+ export const caseInsensitive = true
4
+ export const keywords = new Set(['add','arg','cmd','copy','entrypoint','env','expose','from','healthcheck','label','maintainer','onbuild','run','shell','stopsignal','user','volume','workdir'])
5
+ export { onCommentEnd, onCommentStart }
@@ -0,0 +1,5 @@
1
+ // @ts-check
2
+ import { onCommentEnd, onCommentStart } from './hash-comment-base.js'
3
+ export const keywords = new Set(['directive','enum','extend','fragment','implements','input','interface','mutation','on','query','repeatable','scalar','schema','subscription','type','union'])
4
+ export const typeKeywords = new Set(['Boolean','Float','ID','Int','String'])
5
+ export { onCommentEnd, onCommentStart }
@@ -0,0 +1,7 @@
1
+ // @ts-check
2
+
3
+ /** @param {string} currentChar */
4
+ export const onCommentStart = (currentChar) => currentChar === '#' ? 1 : 0
5
+
6
+ /** @param {string} _prevChar @param {string} currChar */
7
+ export const onCommentEnd = (_prevChar, currChar) => currChar === '\n' ? 1 : 0
@@ -0,0 +1,4 @@
1
+ // @ts-check
2
+ export const keywords = new Set(['false','for','if','in','null','true'])
3
+ export const onCommentStart = (curr, next) => curr === '#' ? 1 : curr + next === '//' ? 1 : curr + next === '/*' ? 2 : 0
4
+ export const onCommentEnd = (prev, curr) => curr === '\n' ? 1 : prev + curr === '*/' ? 2 : 0
@@ -0,0 +1,14 @@
1
+ // @ts-check
2
+ import { tokenize as tokenizeJavaScript } from './javascript-runtime.js'
3
+
4
+ export const keywords = new Set([])
5
+ export const jsx = true
6
+ export const regex = false
7
+ export const templateStrings = false
8
+ export const tokenize = tokenizeJavaScript
9
+
10
+ export const onCommentStart = (_currentChar, _nextChar, index, code) =>
11
+ code.startsWith('<!--', index) ? 2 : 0
12
+
13
+ export const onCommentEnd = (_prevChar, _currChar, index, code) =>
14
+ code.slice(index - 2, index + 1) === '-->' ? 2 : 0