@blcklab/yuirinx 0.1.1 → 0.1.2
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 +47 -64
- package/dist/cjs/core/index.cjs +36 -7
- package/dist/cjs/index.cjs +37 -8
- package/dist/cjs/languages/c.cjs +1 -1
- package/dist/cjs/languages/cpp.cjs +1 -1
- package/dist/cjs/languages/csharp.cjs +1 -1
- package/dist/cjs/languages/css.cjs +2 -2
- package/dist/cjs/languages/dart.cjs +1 -1
- package/dist/cjs/languages/go.cjs +1 -1
- package/dist/cjs/languages/java.cjs +1 -1
- package/dist/cjs/languages/javascript.cjs +65 -6
- package/dist/cjs/languages/jsx.cjs +65 -6
- package/dist/cjs/languages/kotlin.cjs +1 -1
- package/dist/cjs/languages/markdown.cjs +30 -6
- package/dist/cjs/languages/php.cjs +1 -1
- package/dist/cjs/languages/python.cjs +1 -1
- package/dist/cjs/languages/ruby.cjs +1 -1
- package/dist/cjs/languages/rust.cjs +1 -1
- package/dist/cjs/languages/scss.cjs +2 -2
- package/dist/cjs/languages/sql.cjs +1 -1
- package/dist/cjs/languages/swift.cjs +1 -1
- package/dist/cjs/languages/tsx.cjs +65 -6
- package/dist/cjs/languages/typescript.cjs +65 -6
- package/dist/esm/core/create-highlighter.js +132 -0
- package/dist/esm/core/errors.js +10 -0
- package/dist/esm/core/escape.js +17 -0
- package/dist/esm/core/grammar.js +103 -0
- package/dist/esm/core/index.js +4 -536
- package/dist/esm/core/renderer.js +215 -0
- package/dist/esm/core/tokenizer.js +107 -0
- package/dist/esm/core/types.js +0 -0
- package/dist/esm/index.js +8 -558
- package/dist/esm/languages/bash.js +9 -21
- package/dist/esm/languages/c.js +2 -82
- package/dist/esm/languages/cpp.js +2 -82
- package/dist/esm/languages/csharp.js +2 -82
- package/dist/esm/languages/css.js +2 -64
- package/dist/esm/languages/dart.js +2 -82
- package/dist/esm/languages/dockerfile.js +3 -12
- package/dist/esm/languages/go.js +2 -82
- package/dist/esm/languages/graphql.js +8 -20
- package/dist/esm/languages/html.js +2 -44
- package/dist/esm/languages/ini.js +2 -5
- package/dist/esm/languages/java.js +2 -82
- package/dist/esm/languages/javascript.js +2 -229
- package/dist/esm/languages/json.js +2 -5
- package/dist/esm/languages/jsx.js +2 -229
- package/dist/esm/languages/kotlin.js +2 -82
- package/dist/esm/languages/markdown.js +32 -11
- package/dist/esm/languages/nginx.js +2 -5
- package/dist/esm/languages/php.js +3 -83
- package/dist/esm/languages/plaintext.js +1 -2
- package/dist/esm/languages/python.js +10 -25
- package/dist/esm/languages/ruby.js +9 -24
- package/dist/esm/languages/rust.js +2 -82
- package/dist/esm/languages/scss.js +2 -64
- package/dist/esm/languages/shared/c-family.js +55 -0
- package/dist/esm/languages/shared/css.js +48 -0
- package/dist/esm/languages/shared/ecmascript.js +261 -0
- package/dist/esm/languages/shared/helpers.js +52 -0
- package/dist/esm/languages/shared/markup.js +41 -0
- package/dist/esm/languages/shell.js +1 -115
- package/dist/esm/languages/sql.js +11 -32
- package/dist/esm/languages/svelte.js +2 -44
- package/dist/esm/languages/swift.js +2 -82
- package/dist/esm/languages/toml.js +2 -5
- package/dist/esm/languages/tsx.js +2 -229
- package/dist/esm/languages/typescript.js +2 -229
- package/dist/esm/languages/vue.js +2 -44
- package/dist/esm/languages/xml.js +2 -44
- package/dist/esm/languages/yaml.js +2 -5
- package/dist/esm/singleton.js +24 -0
- package/dist/esm/themes/index.js +3 -188
- package/dist/esm/themes/yuirinx-aurora.js +1 -2
- package/dist/esm/themes/yuirinx-noir.js +1 -2
- package/dist/esm/themes/yuirinx-pearl.js +1 -2
- package/dist/types/core/errors.d.cts +1 -1
- package/dist/types/core/errors.d.ts +1 -1
- package/dist/types/core/index.d.cts +1 -1
- package/dist/types/core/index.d.ts +1 -1
- package/dist/types/core/types.d.cts +5 -1
- package/dist/types/core/types.d.ts +5 -1
- package/dist/types/singleton.d.cts +1 -1
- package/dist/types/singleton.d.ts +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
<img src="https://img.shields.io/github/license/blcklab/yuirinx?style=flat-square" alt="license" />
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
8
|
# Yuirinx
|
|
11
9
|
|
|
12
10
|
A lightweight, synchronous syntax highlighter for modern JavaScript and TypeScript applications.
|
|
@@ -56,13 +54,7 @@ Add your preferred layout styles:
|
|
|
56
54
|
overflow-x: auto;
|
|
57
55
|
padding: 1.25rem;
|
|
58
56
|
border-radius: 1rem;
|
|
59
|
-
font-family:
|
|
60
|
-
ui-monospace,
|
|
61
|
-
SFMono-Regular,
|
|
62
|
-
Menlo,
|
|
63
|
-
Monaco,
|
|
64
|
-
Consolas,
|
|
65
|
-
monospace;
|
|
57
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
66
58
|
font-size: 0.875rem;
|
|
67
59
|
line-height: 1.7;
|
|
68
60
|
tab-size: 2;
|
|
@@ -71,16 +63,16 @@ Add your preferred layout styles:
|
|
|
71
63
|
|
|
72
64
|
## Features
|
|
73
65
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
- Zero runtime dependencies
|
|
67
|
+
- Synchronous API with no setup step
|
|
68
|
+
- Safe HTML escaping
|
|
69
|
+
- Individually importable languages and themes
|
|
70
|
+
- ESM and CommonJS support
|
|
71
|
+
- Inline-style and CSS-class rendering
|
|
72
|
+
- Token API for custom renderers
|
|
73
|
+
- Custom language and theme registration
|
|
74
|
+
- Works in browsers, Node.js, workers, serverless, and edge runtimes
|
|
75
|
+
- Safe plaintext fallback for unsupported languages
|
|
84
76
|
|
|
85
77
|
## Tree-Shakable by Design
|
|
86
78
|
|
|
@@ -107,19 +99,16 @@ import { yuirinxPearl } from "@blcklab/yuirinx/theme/yuirinx-pearl";
|
|
|
107
99
|
import { yuirinxAurora } from "@blcklab/yuirinx/theme/yuirinx-aurora";
|
|
108
100
|
```
|
|
109
101
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
- **Yuirinx Noir** — a refined dark theme for documentation and long code samples
|
|
103
|
+
- **Yuirinx Pearl** — a warm light theme with comfortable contrast
|
|
104
|
+
- **Yuirinx Aurora** — an expressive dark theme for showcases and landing pages
|
|
113
105
|
|
|
114
106
|
Register more than one theme when your app supports theme switching:
|
|
115
107
|
|
|
116
108
|
```ts
|
|
117
109
|
const highlighter = createHighlighter({
|
|
118
110
|
languages: [typescript],
|
|
119
|
-
themes: [
|
|
120
|
-
yuirinxNoir,
|
|
121
|
-
yuirinxPearl,
|
|
122
|
-
],
|
|
111
|
+
themes: [yuirinxNoir, yuirinxPearl],
|
|
123
112
|
});
|
|
124
113
|
```
|
|
125
114
|
|
|
@@ -151,10 +140,7 @@ The colors are deterministic, theme-aware, and stable across server and browser
|
|
|
151
140
|
Inline styles work without extra setup. If you want full control through your own stylesheet, use class mode:
|
|
152
141
|
|
|
153
142
|
```ts
|
|
154
|
-
import {
|
|
155
|
-
createHighlighter,
|
|
156
|
-
themeToCss,
|
|
157
|
-
} from "@blcklab/yuirinx";
|
|
143
|
+
import { createHighlighter, themeToCss } from "@blcklab/yuirinx";
|
|
158
144
|
|
|
159
145
|
const html = highlighter.highlight(code, {
|
|
160
146
|
lang: "typescript",
|
|
@@ -167,20 +153,17 @@ const css = themeToCss(yuirinxNoir);
|
|
|
167
153
|
|
|
168
154
|
Class mode is useful for:
|
|
169
155
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
156
|
+
- Content Security Policies that restrict inline styles
|
|
157
|
+
- Automatic light and dark mode
|
|
158
|
+
- Shared application stylesheets
|
|
159
|
+
- Custom token styling
|
|
174
160
|
|
|
175
161
|
## Token API
|
|
176
162
|
|
|
177
163
|
Use the lower-level token API when rendering code through Vue, React, a terminal, or another custom interface:
|
|
178
164
|
|
|
179
165
|
```ts
|
|
180
|
-
const tokens = highlighter.tokenize(
|
|
181
|
-
`const enabled = true;`,
|
|
182
|
-
"typescript",
|
|
183
|
-
);
|
|
166
|
+
const tokens = highlighter.tokenize(`const enabled = true;`, "typescript");
|
|
184
167
|
|
|
185
168
|
for (const token of tokens) {
|
|
186
169
|
console.log(token.type, token.value);
|
|
@@ -193,16 +176,16 @@ Each token includes its type, source value, and original character offsets.
|
|
|
193
176
|
|
|
194
177
|
Yuirinx includes independently importable grammars for popular web, systems, application, and configuration languages, including:
|
|
195
178
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
179
|
+
- JavaScript, TypeScript, JSX, and TSX
|
|
180
|
+
- HTML, XML, CSS, and SCSS
|
|
181
|
+
- JSON, YAML, TOML, and INI
|
|
182
|
+
- Markdown
|
|
183
|
+
- Bash and shell scripts
|
|
184
|
+
- Python, PHP, Ruby, and SQL
|
|
185
|
+
- C, C++, C#, Java, Kotlin, Swift, Dart, Go, and Rust
|
|
186
|
+
- Vue and Svelte
|
|
187
|
+
- Dockerfile, Nginx, and GraphQL
|
|
188
|
+
- Plaintext
|
|
206
189
|
|
|
207
190
|
Each grammar also registers common aliases such as `js`, `ts`, `py`, `md`, `yml`, `sh`, and `c++`.
|
|
208
191
|
|
|
@@ -212,12 +195,12 @@ Yuirinx treats source code as untrusted text.
|
|
|
212
195
|
|
|
213
196
|
It:
|
|
214
197
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
198
|
+
- Escapes HTML-sensitive characters
|
|
199
|
+
- Never evaluates or executes source code
|
|
200
|
+
- Does not use `eval` or `new Function`
|
|
201
|
+
- Does not require DOM access
|
|
202
|
+
- Preserves malformed and unfinished source safely
|
|
203
|
+
- Falls back to escaped plaintext when a grammar is unavailable
|
|
221
204
|
|
|
222
205
|
The returned HTML is intended for normal HTML content contexts. Do not place it directly inside JavaScript, CSS, or URL contexts.
|
|
223
206
|
|
|
@@ -225,16 +208,16 @@ The returned HTML is intended for normal HTML content contexts. Do not place it
|
|
|
225
208
|
|
|
226
209
|
Complete guides and API documentation are available in the project repository:
|
|
227
210
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
211
|
+
- [Getting started](https://github.com/blcklab/yuirinx/blob/main/docs/getting-started.md)
|
|
212
|
+
- [API reference](https://github.com/blcklab/yuirinx/blob/main/docs/api.md)
|
|
213
|
+
- [Rendering and styling](https://github.com/blcklab/yuirinx/blob/main/docs/rendering.md)
|
|
214
|
+
- [Languages and aliases](https://github.com/blcklab/yuirinx/blob/main/docs/languages.md)
|
|
215
|
+
- [Themes](https://github.com/blcklab/yuirinx/blob/main/docs/themes.md)
|
|
216
|
+
- [Custom languages](https://github.com/blcklab/yuirinx/blob/main/docs/custom-languages.md)
|
|
217
|
+
- [Custom themes](https://github.com/blcklab/yuirinx/blob/main/docs/custom-themes.md)
|
|
218
|
+
- [Browser and framework usage](https://github.com/blcklab/yuirinx/blob/main/docs/browser-and-frameworks.md)
|
|
219
|
+
- [Security](https://github.com/blcklab/yuirinx/blob/main/docs/security.md)
|
|
220
|
+
- [Limitations](https://github.com/blcklab/yuirinx/blob/main/docs/limitations.md)
|
|
238
221
|
|
|
239
222
|
## Project Status
|
|
240
223
|
|
package/dist/cjs/core/index.cjs
CHANGED
|
@@ -171,6 +171,13 @@ function classForToken(type, prefix) {
|
|
|
171
171
|
const safeType = sanitizeClassPart(type.replace(/\./g, "-")) || "plain";
|
|
172
172
|
return `${safeClassPrefix(prefix)}${safeType}`;
|
|
173
173
|
}
|
|
174
|
+
function classesForToken(type, prefix) {
|
|
175
|
+
const parts = type.split(".").filter(Boolean);
|
|
176
|
+
if (parts.length === 0) return [classForToken("plain", prefix)];
|
|
177
|
+
return parts.map(
|
|
178
|
+
(_, index) => classForToken(parts.slice(0, index + 1).join("."), prefix)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
174
181
|
function classForFallbackLine(index, prefix) {
|
|
175
182
|
return `${safeClassPrefix(prefix)}fallback-line-${index}`;
|
|
176
183
|
}
|
|
@@ -305,7 +312,8 @@ function renderTokens(tokens, options, theme) {
|
|
|
305
312
|
const escaped = escapeHtml(token.value);
|
|
306
313
|
if (token.type === "plain") return escaped;
|
|
307
314
|
if (mode === "classes") {
|
|
308
|
-
|
|
315
|
+
const classes = classesForToken(token.type, prefix);
|
|
316
|
+
return `<span class="${escapeHtml(classes.join(" "))}">${escaped}</span>`;
|
|
309
317
|
}
|
|
310
318
|
const declarations = styleToDeclarations(
|
|
311
319
|
resolveTokenStyle(theme, token.type)
|
|
@@ -335,7 +343,10 @@ function themeToCss(theme, options = {}) {
|
|
|
335
343
|
].filter(Boolean);
|
|
336
344
|
lines.push(`${selector}{${declarations.join(";")}}`);
|
|
337
345
|
}
|
|
338
|
-
|
|
346
|
+
const tokenStyles = Object.entries(theme.tokens).sort(
|
|
347
|
+
([left], [right]) => left.split(".").length - right.split(".").length
|
|
348
|
+
);
|
|
349
|
+
for (const [type, style] of tokenStyles) {
|
|
339
350
|
const declarations = styleToDeclarations(style);
|
|
340
351
|
if (declarations)
|
|
341
352
|
lines.push(
|
|
@@ -424,11 +435,13 @@ function tokenizeCompiled(code, grammar, maxStateDepth) {
|
|
|
424
435
|
);
|
|
425
436
|
}
|
|
426
437
|
const context = {
|
|
438
|
+
source: code,
|
|
427
439
|
language: grammar.id,
|
|
428
440
|
state: stateName,
|
|
429
441
|
stack: publicStack(grammar.id, stack),
|
|
430
442
|
offset
|
|
431
443
|
};
|
|
444
|
+
if (rule.when && !rule.when(match, context)) continue;
|
|
432
445
|
const tokenType = resolveValue(
|
|
433
446
|
rule.type,
|
|
434
447
|
match,
|
|
@@ -470,7 +483,14 @@ function createHighlighter(options = {}) {
|
|
|
470
483
|
const grammars = /* @__PURE__ */ new Map();
|
|
471
484
|
const canonicalIds = /* @__PURE__ */ new Set();
|
|
472
485
|
const themes = /* @__PURE__ */ new Map();
|
|
473
|
-
const
|
|
486
|
+
const requestedMaxStateDepth = options.maxStateDepth ?? 64;
|
|
487
|
+
if (!Number.isFinite(requestedMaxStateDepth) || !Number.isInteger(requestedMaxStateDepth) || requestedMaxStateDepth < 2) {
|
|
488
|
+
throw new YuirinxError(
|
|
489
|
+
"YUIRINX_INVALID_OPTION",
|
|
490
|
+
"maxStateDepth must be a finite integer greater than or equal to 2."
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
const maxStateDepth = requestedMaxStateDepth;
|
|
474
494
|
const compiledPlaintext = compileGrammar(plaintextGrammar);
|
|
475
495
|
const plaintextIds = /* @__PURE__ */ new Set([
|
|
476
496
|
normalizeId(plaintextGrammar.id),
|
|
@@ -534,7 +554,7 @@ function createHighlighter(options = {}) {
|
|
|
534
554
|
};
|
|
535
555
|
const tokenize = (code, language) => tokenizeCompiled(code, resolveGrammar(language).grammar, maxStateDepth);
|
|
536
556
|
const render = (tokens, renderOptions = {}) => renderTokens(tokens, renderOptions, resolveTheme(renderOptions.theme));
|
|
537
|
-
const highlight = (code, highlightOptions) => {
|
|
557
|
+
const highlight = (code, highlightOptions = {}) => {
|
|
538
558
|
const language = highlightOptions.lang ?? options.defaultLanguage ?? "plaintext";
|
|
539
559
|
const resolved = resolveGrammar(language);
|
|
540
560
|
const theme = resolveTheme(highlightOptions.theme);
|
|
@@ -555,11 +575,20 @@ function createHighlighter(options = {}) {
|
|
|
555
575
|
render,
|
|
556
576
|
registerLanguage,
|
|
557
577
|
registerTheme,
|
|
558
|
-
hasLanguage: (language) =>
|
|
578
|
+
hasLanguage: (language) => {
|
|
579
|
+
const id = normalizeId(language);
|
|
580
|
+
return plaintextIds.has(id) || grammars.has(id);
|
|
581
|
+
},
|
|
559
582
|
hasTheme: (theme) => themes.has(normalizeId(theme)),
|
|
560
|
-
getLanguage: (language) =>
|
|
583
|
+
getLanguage: (language) => {
|
|
584
|
+
const id = normalizeId(language);
|
|
585
|
+
return grammars.get(id)?.source ?? (plaintextIds.has(id) ? plaintextGrammar : void 0);
|
|
586
|
+
},
|
|
561
587
|
getTheme: (theme) => themes.get(normalizeId(theme)),
|
|
562
|
-
listLanguages: () => Object.freeze([
|
|
588
|
+
listLanguages: () => Object.freeze([
|
|
589
|
+
"plaintext",
|
|
590
|
+
...[...canonicalIds].filter((id) => id !== "plaintext")
|
|
591
|
+
]),
|
|
563
592
|
listThemes: () => Object.freeze([...themes.keys()])
|
|
564
593
|
};
|
|
565
594
|
}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -176,6 +176,13 @@ function classForToken(type, prefix) {
|
|
|
176
176
|
const safeType = sanitizeClassPart(type.replace(/\./g, "-")) || "plain";
|
|
177
177
|
return `${safeClassPrefix(prefix)}${safeType}`;
|
|
178
178
|
}
|
|
179
|
+
function classesForToken(type, prefix) {
|
|
180
|
+
const parts = type.split(".").filter(Boolean);
|
|
181
|
+
if (parts.length === 0) return [classForToken("plain", prefix)];
|
|
182
|
+
return parts.map(
|
|
183
|
+
(_, index) => classForToken(parts.slice(0, index + 1).join("."), prefix)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
179
186
|
function classForFallbackLine(index, prefix) {
|
|
180
187
|
return `${safeClassPrefix(prefix)}fallback-line-${index}`;
|
|
181
188
|
}
|
|
@@ -310,7 +317,8 @@ function renderTokens(tokens, options, theme) {
|
|
|
310
317
|
const escaped = escapeHtml(token.value);
|
|
311
318
|
if (token.type === "plain") return escaped;
|
|
312
319
|
if (mode === "classes") {
|
|
313
|
-
|
|
320
|
+
const classes = classesForToken(token.type, prefix);
|
|
321
|
+
return `<span class="${escapeHtml(classes.join(" "))}">${escaped}</span>`;
|
|
314
322
|
}
|
|
315
323
|
const declarations = styleToDeclarations(
|
|
316
324
|
resolveTokenStyle(theme, token.type)
|
|
@@ -340,7 +348,10 @@ function themeToCss(theme, options = {}) {
|
|
|
340
348
|
].filter(Boolean);
|
|
341
349
|
lines.push(`${selector}{${declarations.join(";")}}`);
|
|
342
350
|
}
|
|
343
|
-
|
|
351
|
+
const tokenStyles = Object.entries(theme.tokens).sort(
|
|
352
|
+
([left], [right]) => left.split(".").length - right.split(".").length
|
|
353
|
+
);
|
|
354
|
+
for (const [type, style] of tokenStyles) {
|
|
344
355
|
const declarations = styleToDeclarations(style);
|
|
345
356
|
if (declarations)
|
|
346
357
|
lines.push(
|
|
@@ -429,11 +440,13 @@ function tokenizeCompiled(code, grammar, maxStateDepth) {
|
|
|
429
440
|
);
|
|
430
441
|
}
|
|
431
442
|
const context = {
|
|
443
|
+
source: code,
|
|
432
444
|
language: grammar.id,
|
|
433
445
|
state: stateName,
|
|
434
446
|
stack: publicStack(grammar.id, stack),
|
|
435
447
|
offset
|
|
436
448
|
};
|
|
449
|
+
if (rule.when && !rule.when(match, context)) continue;
|
|
437
450
|
const tokenType = resolveValue(
|
|
438
451
|
rule.type,
|
|
439
452
|
match,
|
|
@@ -475,7 +488,14 @@ function createHighlighter(options = {}) {
|
|
|
475
488
|
const grammars = /* @__PURE__ */ new Map();
|
|
476
489
|
const canonicalIds = /* @__PURE__ */ new Set();
|
|
477
490
|
const themes = /* @__PURE__ */ new Map();
|
|
478
|
-
const
|
|
491
|
+
const requestedMaxStateDepth = options.maxStateDepth ?? 64;
|
|
492
|
+
if (!Number.isFinite(requestedMaxStateDepth) || !Number.isInteger(requestedMaxStateDepth) || requestedMaxStateDepth < 2) {
|
|
493
|
+
throw new YuirinxError(
|
|
494
|
+
"YUIRINX_INVALID_OPTION",
|
|
495
|
+
"maxStateDepth must be a finite integer greater than or equal to 2."
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
const maxStateDepth = requestedMaxStateDepth;
|
|
479
499
|
const compiledPlaintext = compileGrammar(plaintextGrammar);
|
|
480
500
|
const plaintextIds = /* @__PURE__ */ new Set([
|
|
481
501
|
normalizeId(plaintextGrammar.id),
|
|
@@ -539,7 +559,7 @@ function createHighlighter(options = {}) {
|
|
|
539
559
|
};
|
|
540
560
|
const tokenize2 = (code, language) => tokenizeCompiled(code, resolveGrammar(language).grammar, maxStateDepth);
|
|
541
561
|
const render2 = (tokens, renderOptions = {}) => renderTokens(tokens, renderOptions, resolveTheme(renderOptions.theme));
|
|
542
|
-
const highlight2 = (code, highlightOptions) => {
|
|
562
|
+
const highlight2 = (code, highlightOptions = {}) => {
|
|
543
563
|
const language = highlightOptions.lang ?? options.defaultLanguage ?? "plaintext";
|
|
544
564
|
const resolved = resolveGrammar(language);
|
|
545
565
|
const theme = resolveTheme(highlightOptions.theme);
|
|
@@ -560,18 +580,27 @@ function createHighlighter(options = {}) {
|
|
|
560
580
|
render: render2,
|
|
561
581
|
registerLanguage: registerLanguage2,
|
|
562
582
|
registerTheme: registerTheme2,
|
|
563
|
-
hasLanguage: (language) =>
|
|
583
|
+
hasLanguage: (language) => {
|
|
584
|
+
const id = normalizeId(language);
|
|
585
|
+
return plaintextIds.has(id) || grammars.has(id);
|
|
586
|
+
},
|
|
564
587
|
hasTheme: (theme) => themes.has(normalizeId(theme)),
|
|
565
|
-
getLanguage: (language) =>
|
|
588
|
+
getLanguage: (language) => {
|
|
589
|
+
const id = normalizeId(language);
|
|
590
|
+
return grammars.get(id)?.source ?? (plaintextIds.has(id) ? plaintextGrammar : void 0);
|
|
591
|
+
},
|
|
566
592
|
getTheme: (theme) => themes.get(normalizeId(theme)),
|
|
567
|
-
listLanguages: () => Object.freeze([
|
|
593
|
+
listLanguages: () => Object.freeze([
|
|
594
|
+
"plaintext",
|
|
595
|
+
...[...canonicalIds].filter((id) => id !== "plaintext")
|
|
596
|
+
]),
|
|
568
597
|
listThemes: () => Object.freeze([...themes.keys()])
|
|
569
598
|
};
|
|
570
599
|
}
|
|
571
600
|
|
|
572
601
|
// src/singleton.ts
|
|
573
602
|
var defaultHighlighter = createHighlighter();
|
|
574
|
-
function highlight(code, options) {
|
|
603
|
+
function highlight(code, options = {}) {
|
|
575
604
|
return defaultHighlighter.highlight(code, options);
|
|
576
605
|
}
|
|
577
606
|
function tokenize(code, language) {
|
package/dist/cjs/languages/c.cjs
CHANGED
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -32,7 +32,7 @@ var punctuationRule = {
|
|
|
32
32
|
};
|
|
33
33
|
var operatorRule = {
|
|
34
34
|
type: "operator",
|
|
35
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
35
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
36
36
|
};
|
|
37
37
|
var doubleStringRule = {
|
|
38
38
|
type: "string",
|
|
@@ -61,7 +61,7 @@ function createCssGrammar(options) {
|
|
|
61
61
|
{ type: "number", pattern: /(?:\b\d*\.\d+|\b\d+)(?:e[+-]?\d+)?/i },
|
|
62
62
|
{
|
|
63
63
|
type: "unit",
|
|
64
|
-
pattern: /(
|
|
64
|
+
pattern: /(?:%(?![\w-])|(?:px|r?em|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|s|ms|deg|rad|turn)\b)/i
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
type: "selector",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -38,7 +38,7 @@ var punctuationRule = {
|
|
|
38
38
|
};
|
|
39
39
|
var operatorRule = {
|
|
40
40
|
type: "operator",
|
|
41
|
-
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])
|
|
41
|
+
pattern: /(?:===|!==|>>>|<<=|>>=|=>|==|!=|<=|>=|&&|\|\||\?\?|\?\.|\+\+|--|\+=|-=|\*=|\/=|%=|\*\*|<<|>>|[+\-*/%=&|!<>^~?])/
|
|
42
42
|
};
|
|
43
43
|
var numberRule = {
|
|
44
44
|
type: "number",
|
|
@@ -163,6 +163,18 @@ var BUILTINS = [
|
|
|
163
163
|
"process",
|
|
164
164
|
"window"
|
|
165
165
|
];
|
|
166
|
+
function canStartRegex(source, offset) {
|
|
167
|
+
const before = source.slice(0, offset).trimEnd();
|
|
168
|
+
if (!before) return true;
|
|
169
|
+
const previous = before[before.length - 1] ?? "";
|
|
170
|
+
if (/[([{,:;=!?&|+\-*%^~<>]/.test(previous)) return true;
|
|
171
|
+
const word = /[A-Za-z_$][\w$]*$/.exec(before)?.[0];
|
|
172
|
+
return Boolean(
|
|
173
|
+
word && /^(?:await|case|delete|do|else|in|instanceof|new|of|return|throw|typeof|void|yield)$/.test(
|
|
174
|
+
word
|
|
175
|
+
)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
166
178
|
function createEcmaGrammar(options) {
|
|
167
179
|
const keywordValues = options.typescript ? [...JS_KEYWORDS, ...TS_KEYWORDS] : JS_KEYWORDS;
|
|
168
180
|
const rootRules = [
|
|
@@ -173,16 +185,23 @@ function createEcmaGrammar(options) {
|
|
|
173
185
|
{ type: "string", pattern: /`/, push: "template" }
|
|
174
186
|
];
|
|
175
187
|
if (options.jsx) {
|
|
188
|
+
if (options.typescript) {
|
|
189
|
+
rootRules.push({
|
|
190
|
+
type: "operator",
|
|
191
|
+
pattern: /<(?=[A-Za-z_$][\w$]*(?:\s+extends\s+[^>]+)?,?>\s*\()/
|
|
192
|
+
});
|
|
193
|
+
}
|
|
176
194
|
rootRules.push({
|
|
177
195
|
type: "tag.punctuation",
|
|
178
|
-
pattern:
|
|
179
|
-
push: "
|
|
196
|
+
pattern: /<(?=[A-Za-z_$>])/,
|
|
197
|
+
push: "jsxTagName"
|
|
180
198
|
});
|
|
181
199
|
}
|
|
182
200
|
rootRules.push(
|
|
183
201
|
{
|
|
184
202
|
type: "regex",
|
|
185
|
-
pattern: /\/(?![/*\s])(?:\\.|\[(?:\\.|[^\]\\])*\]|[^/\\\r\n])+\/[dgimsuvy]
|
|
203
|
+
pattern: /\/(?![/*\s])(?:\\.|\[(?:\\.|[^\]\\])*\]|[^/\\\r\n])+\/[dgimsuvy]*/,
|
|
204
|
+
when: (_match, context) => canStartRegex(context.source, context.offset)
|
|
186
205
|
},
|
|
187
206
|
numberRule,
|
|
188
207
|
{ type: "boolean", pattern: /\b(?:true|false)\b/ },
|
|
@@ -228,14 +247,54 @@ function createEcmaGrammar(options) {
|
|
|
228
247
|
{ include: "root" }
|
|
229
248
|
]
|
|
230
249
|
},
|
|
231
|
-
|
|
250
|
+
jsxTagName: {
|
|
251
|
+
rules: [
|
|
252
|
+
{ type: "tag.punctuation", pattern: />/, next: "jsxChildren" },
|
|
253
|
+
{ type: "tag.punctuation", pattern: /\/>/, pop: true },
|
|
254
|
+
whitespaceRule,
|
|
255
|
+
{
|
|
256
|
+
type: "tag",
|
|
257
|
+
pattern: /[A-Za-z_$][\w$.-]*/,
|
|
258
|
+
next: "jsxAttributes"
|
|
259
|
+
},
|
|
260
|
+
punctuationRule
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
jsxAttributes: {
|
|
232
264
|
rules: [
|
|
233
|
-
{ type: "tag.punctuation", pattern:
|
|
265
|
+
{ type: "tag.punctuation", pattern: /\/>/, pop: true },
|
|
266
|
+
{ type: "tag.punctuation", pattern: />/, next: "jsxChildren" },
|
|
234
267
|
whitespaceRule,
|
|
235
268
|
{ type: "attribute.value", pattern: /"(?:\\.|[^"\\])*"?/ },
|
|
236
269
|
{ type: "attribute.value", pattern: /'(?:\\.|[^'\\])*'?/ },
|
|
237
270
|
{ type: "punctuation", pattern: /{/, push: "jsxExpression" },
|
|
238
271
|
{ type: "operator", pattern: /=/ },
|
|
272
|
+
{ type: "attribute", pattern: /[A-Za-z_$][\w$.-]*/ },
|
|
273
|
+
punctuationRule
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
jsxChildren: {
|
|
277
|
+
fallbackType: "plain",
|
|
278
|
+
rules: [
|
|
279
|
+
{
|
|
280
|
+
type: "tag.punctuation",
|
|
281
|
+
pattern: /<\/(?=[A-Za-z_$>])/,
|
|
282
|
+
push: "jsxClosingTag"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
type: "tag.punctuation",
|
|
286
|
+
pattern: /<(?=[A-Za-z_$>])/,
|
|
287
|
+
push: "jsxTagName"
|
|
288
|
+
},
|
|
289
|
+
{ type: "punctuation", pattern: /{/, push: "jsxExpression" },
|
|
290
|
+
{ type: "plain", pattern: /[^<{]+/ },
|
|
291
|
+
{ type: "plain", pattern: /[<{]/ }
|
|
292
|
+
]
|
|
293
|
+
},
|
|
294
|
+
jsxClosingTag: {
|
|
295
|
+
rules: [
|
|
296
|
+
{ type: "tag.punctuation", pattern: />/, pop: 2 },
|
|
297
|
+
whitespaceRule,
|
|
239
298
|
{ type: "tag", pattern: /[A-Za-z_$][\w$.-]*/ },
|
|
240
299
|
punctuationRule
|
|
241
300
|
]
|