@fuzdev/fuz_code 0.37.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.
Files changed (76) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +185 -0
  3. package/dist/Code.svelte +146 -0
  4. package/dist/Code.svelte.d.ts +79 -0
  5. package/dist/Code.svelte.d.ts.map +1 -0
  6. package/dist/CodeHighlight.svelte +205 -0
  7. package/dist/CodeHighlight.svelte.d.ts +101 -0
  8. package/dist/CodeHighlight.svelte.d.ts.map +1 -0
  9. package/dist/code_sample.d.ts +8 -0
  10. package/dist/code_sample.d.ts.map +1 -0
  11. package/dist/code_sample.js +2 -0
  12. package/dist/grammar_clike.d.ts +12 -0
  13. package/dist/grammar_clike.d.ts.map +1 -0
  14. package/dist/grammar_clike.js +43 -0
  15. package/dist/grammar_css.d.ts +11 -0
  16. package/dist/grammar_css.d.ts.map +1 -0
  17. package/dist/grammar_css.js +70 -0
  18. package/dist/grammar_js.d.ts +11 -0
  19. package/dist/grammar_js.d.ts.map +1 -0
  20. package/dist/grammar_js.js +180 -0
  21. package/dist/grammar_json.d.ts +11 -0
  22. package/dist/grammar_json.d.ts.map +1 -0
  23. package/dist/grammar_json.js +35 -0
  24. package/dist/grammar_markdown.d.ts +8 -0
  25. package/dist/grammar_markdown.d.ts.map +1 -0
  26. package/dist/grammar_markdown.js +228 -0
  27. package/dist/grammar_markup.d.ts +31 -0
  28. package/dist/grammar_markup.d.ts.map +1 -0
  29. package/dist/grammar_markup.js +192 -0
  30. package/dist/grammar_svelte.d.ts +12 -0
  31. package/dist/grammar_svelte.d.ts.map +1 -0
  32. package/dist/grammar_svelte.js +150 -0
  33. package/dist/grammar_ts.d.ts +11 -0
  34. package/dist/grammar_ts.d.ts.map +1 -0
  35. package/dist/grammar_ts.js +95 -0
  36. package/dist/highlight_manager.d.ts +25 -0
  37. package/dist/highlight_manager.d.ts.map +1 -0
  38. package/dist/highlight_manager.js +139 -0
  39. package/dist/highlight_priorities.d.ts +3 -0
  40. package/dist/highlight_priorities.d.ts.map +1 -0
  41. package/dist/highlight_priorities.gen.d.ts +4 -0
  42. package/dist/highlight_priorities.gen.d.ts.map +1 -0
  43. package/dist/highlight_priorities.gen.js +58 -0
  44. package/dist/highlight_priorities.js +55 -0
  45. package/dist/syntax_styler.d.ts +277 -0
  46. package/dist/syntax_styler.d.ts.map +1 -0
  47. package/dist/syntax_styler.js +426 -0
  48. package/dist/syntax_styler_global.d.ts +3 -0
  49. package/dist/syntax_styler_global.d.ts.map +1 -0
  50. package/dist/syntax_styler_global.js +18 -0
  51. package/dist/syntax_token.d.ts +34 -0
  52. package/dist/syntax_token.d.ts.map +1 -0
  53. package/dist/syntax_token.js +27 -0
  54. package/dist/theme.css +98 -0
  55. package/dist/theme_highlight.css +160 -0
  56. package/dist/theme_variables.css +20 -0
  57. package/dist/tokenize_syntax.d.ts +28 -0
  58. package/dist/tokenize_syntax.d.ts.map +1 -0
  59. package/dist/tokenize_syntax.js +194 -0
  60. package/package.json +117 -0
  61. package/src/lib/code_sample.ts +10 -0
  62. package/src/lib/grammar_clike.ts +48 -0
  63. package/src/lib/grammar_css.ts +84 -0
  64. package/src/lib/grammar_js.ts +215 -0
  65. package/src/lib/grammar_json.ts +38 -0
  66. package/src/lib/grammar_markdown.ts +289 -0
  67. package/src/lib/grammar_markup.ts +225 -0
  68. package/src/lib/grammar_svelte.ts +165 -0
  69. package/src/lib/grammar_ts.ts +114 -0
  70. package/src/lib/highlight_manager.ts +182 -0
  71. package/src/lib/highlight_priorities.gen.ts +71 -0
  72. package/src/lib/highlight_priorities.ts +110 -0
  73. package/src/lib/syntax_styler.ts +583 -0
  74. package/src/lib/syntax_styler_global.ts +20 -0
  75. package/src/lib/syntax_token.ts +49 -0
  76. package/src/lib/tokenize_syntax.ts +270 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax_styler.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/syntax_styler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,426 @@
1
+ import { SyntaxToken } from './syntax_token.js';
2
+ import { tokenize_syntax } from './tokenize_syntax.js';
3
+ /**
4
+ * Based on Prism (https://github.com/PrismJS/prism)
5
+ * by Lea Verou (https://lea.verou.me/)
6
+ *
7
+ * MIT license
8
+ *
9
+ * @see LICENSE
10
+ */
11
+ export class SyntaxStyler {
12
+ langs = {
13
+ plaintext: {},
14
+ };
15
+ // constructor() {
16
+ // TODO this API? problem is the grammars rely on mutating existing grammars in the `syntax_styler`,
17
+ // so for now adding grammars will remain inherently stateful
18
+ // export interface SyntaxStylerOptions {
19
+ // grammars?: AddGrammar[];
20
+ // }
21
+ // options: SyntaxStylerOptions = {}
22
+ // const {grammars} = options;
23
+ // if (grammars) {
24
+ // for (const add_grammar of grammars) {
25
+ // this.langs[id] =
26
+ // add_grammar(this);
27
+ // }
28
+ // }
29
+ // }
30
+ add_lang(id, grammar, aliases) {
31
+ // Normalize grammar once at registration for optimal runtime performance
32
+ // Use a visited set to handle circular references
33
+ this.normalize_grammar(grammar, new Set());
34
+ // After normalization, grammar has the shape of SyntaxGrammar
35
+ const normalized = grammar;
36
+ this.langs[id] = normalized;
37
+ if (aliases !== undefined) {
38
+ for (var alias of aliases) {
39
+ this.langs[alias] = normalized;
40
+ }
41
+ }
42
+ }
43
+ add_extended_lang(base_id, extension_id, extension, aliases) {
44
+ // extend_grammar returns already normalized grammar
45
+ var grammar = this.extend_grammar(base_id, extension);
46
+ // Store the normalized grammar directly
47
+ this.langs[extension_id] = grammar;
48
+ if (aliases !== undefined) {
49
+ for (var alias of aliases) {
50
+ this.langs[alias] = grammar;
51
+ }
52
+ }
53
+ return grammar;
54
+ }
55
+ get_lang(id) {
56
+ var lang = this.langs[id];
57
+ if (lang === undefined) {
58
+ throw Error(`The language "${id}" has no grammar.`);
59
+ }
60
+ return lang;
61
+ }
62
+ /**
63
+ * Generates HTML with syntax highlighting from source code.
64
+ *
65
+ * **Process:**
66
+ * 1. Runs `before_tokenize` hook
67
+ * 2. Tokenizes code using the provided or looked-up grammar
68
+ * 3. Runs `after_tokenize` hook
69
+ * 4. Runs `wrap` hook on each token
70
+ * 5. Converts tokens to HTML with CSS classes
71
+ *
72
+ * **Parameter Relationship:**
73
+ * - `lang` is ALWAYS required for hook context and identification
74
+ * - `grammar` is optional; when undefined, automatically looks up via `this.get_lang(lang)`
75
+ * - When both are provided, `grammar` is used for tokenization, `lang` for metadata
76
+ *
77
+ * **Use cases:**
78
+ * - Standard usage: `stylize(code, 'ts')` - uses registered TypeScript grammar
79
+ * - Custom grammar: `stylize(code, 'ts', customGrammar)` - uses custom grammar but keeps 'ts' label
80
+ * - Extended grammar: `stylize(code, 'custom', this.extend_grammar('ts', extension))` - new language variant
81
+ *
82
+ * @param text - The source code to syntax highlight.
83
+ * @param lang - Language identifier (e.g., 'ts', 'css', 'html'). Used for:
84
+ * - Grammar lookup when `grammar` is undefined
85
+ * - Hook context (`lang` field passed to hooks)
86
+ * - Language identification in output
87
+ * @param grammar - Optional custom grammar object. When undefined, automatically
88
+ * looks up the grammar via `this.get_lang(lang)`. Provide this to use a custom
89
+ * or modified grammar instead of the registered one.
90
+ *
91
+ * @returns HTML string with syntax highlighting using CSS classes (`.token_*`)
92
+ *
93
+ * @example
94
+ * // Standard usage - uses registered grammar
95
+ * stylize('var foo = true;', 'ts');
96
+ *
97
+ * @example
98
+ * // Custom grammar - overrides registered grammar
99
+ * const customGrammar = { keyword: [...], string: [...] };
100
+ * stylize('var foo = false;', 'ts', customGrammar);
101
+ *
102
+ * @example
103
+ * // Extended grammar - builds on existing grammar
104
+ * const extended = this.extend_grammar('ts', { customToken: [...] });
105
+ * stylize('var foo = 42;', 'ts-extended', extended);
106
+ */
107
+ stylize(text, lang, grammar = this.get_lang(lang)) {
108
+ var ctx = {
109
+ code: text,
110
+ grammar,
111
+ lang,
112
+ tokens: undefined,
113
+ };
114
+ this.run_hook_before_tokenize(ctx);
115
+ const c = ctx;
116
+ c.tokens = tokenize_syntax(c.code, c.grammar);
117
+ this.run_hook_after_tokenize(c);
118
+ return this.stringify_token(c.tokens, c.lang);
119
+ }
120
+ /**
121
+ * Inserts tokens _before_ another token in a language definition or any other grammar.
122
+ *
123
+ * ## Usage
124
+ *
125
+ * This helper method makes it easy to modify existing languages. For example, the CSS language definition
126
+ * not only defines CSS styling for CSS documents, but also needs to define styling for CSS embedded
127
+ * in HTML through `<style>` elements. To do this, it needs to modify `syntax_styler.get_lang('markup')` and add the
128
+ * appropriate tokens. However, `syntax_styler.get_lang('markup')` is a regular JS object literal, so if you do
129
+ * this:
130
+ *
131
+ * ```js
132
+ * syntax_styler.get_lang('markup').style = {
133
+ * // token
134
+ * };
135
+ * ```
136
+ *
137
+ * then the `style` token will be added (and processed) at the end. `insert_before` allows you to insert tokens
138
+ * before existing tokens. For the CSS example above, you would use it like this:
139
+ *
140
+ * ```js
141
+ * grammar_insert_before('markup', 'cdata', {
142
+ * 'style': {
143
+ * // token
144
+ * }
145
+ * });
146
+ * ```
147
+ *
148
+ * ## Special cases
149
+ *
150
+ * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
151
+ * will be ignored.
152
+ *
153
+ * This behavior can be used to insert tokens after `before`:
154
+ *
155
+ * ```js
156
+ * grammar_insert_before('markup', 'comment', {
157
+ * 'comment': syntax_styler.get_lang('markup').comment,
158
+ * // tokens after 'comment'
159
+ * });
160
+ * ```
161
+ *
162
+ * ## Limitations
163
+ *
164
+ * The main problem `insert_before` has to solve is iteration order. Since ES2015, the iteration order for object
165
+ * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
166
+ * differently when keys are deleted and re-inserted. So `insert_before` can't be implemented by temporarily
167
+ * deleting properties which is necessary to insert at arbitrary positions.
168
+ *
169
+ * To solve this problem, `insert_before` doesn't actually insert the given tokens into the target object.
170
+ * Instead, it will create a new object and replace all references to the target object with the new one. This
171
+ * can be done without temporarily deleting properties, so the iteration order is well-defined.
172
+ *
173
+ * However, only references that can be reached from `syntax_styler.langs` or `insert` will be replaced. I.e. if
174
+ * you hold the target object in a variable, then the value of the variable will not change.
175
+ *
176
+ * ```js
177
+ * var oldMarkup = syntax_styler.get_lang('markup');
178
+ * var newMarkup = grammar_insert_before('markup', 'comment', { ... });
179
+ *
180
+ * assert(oldMarkup !== syntax_styler.get_lang('markup'));
181
+ * assert(newMarkup === syntax_styler.get_lang('markup'));
182
+ * ```
183
+ *
184
+ * @param inside - The property of `root` (e.g. a language id in `syntax_styler.langs`) that contains the
185
+ * object to be modified.
186
+ * @param before - The key to insert before.
187
+ * @param insert - An object containing the key-value pairs to be inserted.
188
+ * @param root - The object containing `inside`, i.e. the object that contains the
189
+ * object to be modified.
190
+ *
191
+ * Defaults to `syntax_styler.langs`.
192
+ *
193
+ * @returns the new grammar object
194
+ */
195
+ grammar_insert_before(inside, before, insert, root = this.langs) {
196
+ var grammar = root[inside];
197
+ var updated = {};
198
+ for (var token in grammar) {
199
+ if (token === before) {
200
+ for (var new_token in insert) {
201
+ updated[new_token] = insert[new_token];
202
+ }
203
+ }
204
+ // Do not insert tokens which also occur in insert.
205
+ if (!Object.hasOwn(insert, token)) {
206
+ updated[token] = grammar[token];
207
+ }
208
+ }
209
+ // Normalize the updated grammar to ensure inserted patterns have consistent shape
210
+ this.normalize_grammar(updated, new Set());
211
+ // After normalization, cast to SyntaxGrammar
212
+ const normalized = updated;
213
+ var old = root[inside];
214
+ root[inside] = normalized;
215
+ // Update references in other language definitions
216
+ depth_first_search(this.langs, (o, key, value) => {
217
+ if (value === old && key !== inside) {
218
+ o[key] = normalized;
219
+ }
220
+ });
221
+ return normalized;
222
+ }
223
+ /**
224
+ * Converts the given token or token stream to an HTML representation.
225
+ *
226
+ * Runs the `wrap` hook on each `SyntaxToken`.
227
+ *
228
+ * @param o - The token or token stream to be converted.
229
+ * @param lang - The name of current language.
230
+ * @returns The HTML representation of the token or token stream.
231
+ */
232
+ stringify_token(o, lang) {
233
+ if (typeof o === 'string') {
234
+ return o
235
+ .replace(/&/g, '&amp;')
236
+ .replace(/</g, '&lt;')
237
+ .replace(/\u00a0/g, ' ');
238
+ }
239
+ if (Array.isArray(o)) {
240
+ var s = '';
241
+ for (var e of o) {
242
+ s += this.stringify_token(e, lang);
243
+ }
244
+ return s;
245
+ }
246
+ var ctx = {
247
+ type: o.type,
248
+ content: this.stringify_token(o.content, lang),
249
+ tag: 'span',
250
+ classes: [`token_${o.type}`],
251
+ attributes: {},
252
+ lang,
253
+ };
254
+ var aliases = o.alias;
255
+ // alias is always an array after normalization
256
+ for (const a of aliases) {
257
+ ctx.classes.push(`token_${a}`);
258
+ }
259
+ this.run_hook_wrap(ctx);
260
+ var attributes = '';
261
+ for (var name in ctx.attributes) {
262
+ attributes += ' ' + name + '="' + (ctx.attributes[name] || '').replace(/"/g, '&quot;') + '"';
263
+ }
264
+ return ('<' +
265
+ ctx.tag +
266
+ ' class="' +
267
+ ctx.classes.join(' ') +
268
+ '"' +
269
+ attributes +
270
+ '>' +
271
+ ctx.content +
272
+ '</' +
273
+ ctx.tag +
274
+ '>');
275
+ }
276
+ /**
277
+ * Creates a deep copy of the language with the given id and appends the given tokens.
278
+ *
279
+ * If a token in `extension` also appears in the copied language, then the existing token in the copied language
280
+ * will be overwritten at its original position.
281
+ *
282
+ * ## Best practices
283
+ *
284
+ * Since the position of overwriting tokens (token in `extension` that overwrite tokens in the copied language)
285
+ * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
286
+ * understand the language definition because, normally, the order of tokens matters in the grammars.
287
+ *
288
+ * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
289
+ * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
290
+ *
291
+ * @param base_id - The id of the language to extend. This has to be a key in `syntax_styler.langs`.
292
+ * @param extension - The new tokens to append.
293
+ * @returns the new grammar
294
+ */
295
+ extend_grammar(base_id, extension) {
296
+ // Merge normalized base with un-normalized extension
297
+ const extended = { ...structuredClone(this.get_lang(base_id)), ...extension };
298
+ // Normalize the extension parts
299
+ this.normalize_grammar(extended, new Set());
300
+ // Return as SyntaxGrammar
301
+ return extended;
302
+ }
303
+ /**
304
+ * Normalize a single pattern to have consistent shape.
305
+ * This ensures all patterns have the same object shape for V8 optimization.
306
+ */
307
+ normalize_pattern(pattern, visited) {
308
+ const p = pattern instanceof RegExp ? { pattern } : pattern;
309
+ let regex = p.pattern;
310
+ // Add global flag if greedy and not already present
311
+ if ((p.greedy ?? false) && !regex.global) {
312
+ const flags = regex.flags;
313
+ regex = new RegExp(regex.source, flags.includes('g') ? flags : flags + 'g');
314
+ }
315
+ // Normalize alias to always be an array
316
+ let normalized_alias = [];
317
+ if (p.alias) {
318
+ normalized_alias = Array.isArray(p.alias) ? p.alias : [p.alias];
319
+ }
320
+ // Recursively normalize the inside grammar if present
321
+ let normalized_inside = null;
322
+ if (p.inside) {
323
+ this.normalize_grammar(p.inside, visited);
324
+ // After normalization, cast to SyntaxGrammar
325
+ normalized_inside = p.inside;
326
+ }
327
+ return {
328
+ pattern: regex,
329
+ lookbehind: p.lookbehind ?? false,
330
+ greedy: p.greedy ?? false,
331
+ alias: normalized_alias,
332
+ inside: normalized_inside,
333
+ };
334
+ }
335
+ /**
336
+ * Normalize a grammar to have consistent object shapes.
337
+ * This performs several optimizations:
338
+ * 1. Merges `rest` property into main grammar
339
+ * 2. Ensures all pattern values are arrays
340
+ * 3. Normalizes all pattern objects to have consistent shapes
341
+ * 4. Adds global flag to greedy patterns
342
+ *
343
+ * This is called once at registration time to avoid runtime overhead.
344
+ * @param visited - Set of grammar object IDs already normalized (for circular references)
345
+ */
346
+ normalize_grammar(grammar, visited) {
347
+ // Check if we've already normalized this grammar (circular reference)
348
+ const grammar_id = id_of(grammar);
349
+ if (visited.has(grammar_id)) {
350
+ return;
351
+ }
352
+ visited.add(grammar_id);
353
+ // Step 1: Merge rest into grammar first
354
+ if (grammar.rest) {
355
+ for (const token in grammar.rest) {
356
+ if (!grammar[token]) {
357
+ // Don't overwrite existing tokens
358
+ grammar[token] = grammar.rest[token];
359
+ }
360
+ }
361
+ delete grammar.rest;
362
+ }
363
+ // Step 2: Normalize all patterns
364
+ for (const key in grammar) {
365
+ if (key === 'rest')
366
+ continue;
367
+ const value = grammar[key];
368
+ if (!value) {
369
+ grammar[key] = [];
370
+ continue;
371
+ }
372
+ // Always store as array of normalized patterns
373
+ const patterns = Array.isArray(value) ? value : [value];
374
+ grammar[key] = patterns.map((p) => this.normalize_pattern(p, visited));
375
+ }
376
+ }
377
+ // TODO add some builtins
378
+ plugins = {};
379
+ // TODO maybe extend/compose an event listener?
380
+ hooks_before_tokenize = [];
381
+ hooks_after_tokenize = [];
382
+ hooks_wrap = [];
383
+ add_hook_before_tokenize(cb) {
384
+ this.hooks_before_tokenize.push(cb);
385
+ }
386
+ add_hook_after_tokenize(cb) {
387
+ this.hooks_after_tokenize.push(cb);
388
+ }
389
+ add_hook_wrap(cb) {
390
+ this.hooks_wrap.push(cb);
391
+ }
392
+ run_hook_before_tokenize(ctx) {
393
+ for (var cb of this.hooks_before_tokenize) {
394
+ cb(ctx);
395
+ }
396
+ }
397
+ run_hook_after_tokenize(ctx) {
398
+ for (var cb of this.hooks_after_tokenize) {
399
+ cb(ctx);
400
+ }
401
+ }
402
+ run_hook_wrap(ctx) {
403
+ for (var cb of this.hooks_wrap) {
404
+ cb(ctx);
405
+ }
406
+ }
407
+ }
408
+ const depth_first_search = (o, cb, visited = new Set()) => {
409
+ for (var key in o) {
410
+ cb(o, key, o[key]);
411
+ var property = o[key];
412
+ if (property &&
413
+ typeof property === 'object' &&
414
+ !(property instanceof RegExp) &&
415
+ !visited.has(id_of(property))) {
416
+ visited.add(id_of(property));
417
+ depth_first_search(property, cb, visited);
418
+ }
419
+ }
420
+ };
421
+ var unique_id = 0;
422
+ /**
423
+ * Returns a unique number for the given object. Later calls will still return the same number.
424
+ */
425
+ const ID = Symbol('id');
426
+ const id_of = (obj) => (obj[ID] ??= ++unique_id);
@@ -0,0 +1,3 @@
1
+ import { SyntaxStyler } from './syntax_styler.js';
2
+ export declare const syntax_styler_global: SyntaxStyler;
3
+ //# sourceMappingURL=syntax_styler_global.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax_styler_global.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/syntax_styler_global.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAUhD,eAAO,MAAM,oBAAoB,cAAqB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { SyntaxStyler } from './syntax_styler.js';
2
+ import { add_grammar_markup } from './grammar_markup.js';
3
+ import { add_grammar_css } from './grammar_css.js';
4
+ import { add_grammar_clike } from './grammar_clike.js';
5
+ import { add_grammar_js } from './grammar_js.js';
6
+ import { add_grammar_ts } from './grammar_ts.js';
7
+ import { add_grammar_svelte } from './grammar_svelte.js';
8
+ import { add_grammar_json } from './grammar_json.js';
9
+ import { add_grammar_markdown } from './grammar_markdown.js';
10
+ export const syntax_styler_global = new SyntaxStyler();
11
+ add_grammar_markup(syntax_styler_global);
12
+ add_grammar_css(syntax_styler_global);
13
+ add_grammar_clike(syntax_styler_global);
14
+ add_grammar_js(syntax_styler_global);
15
+ add_grammar_ts(syntax_styler_global);
16
+ add_grammar_svelte(syntax_styler_global);
17
+ add_grammar_json(syntax_styler_global);
18
+ add_grammar_markdown(syntax_styler_global);
@@ -0,0 +1,34 @@
1
+ export declare class SyntaxToken {
2
+ /**
3
+ * The type of the token.
4
+ *
5
+ * This is usually the key of a pattern in a `Grammar`.
6
+ */
7
+ type: string;
8
+ /**
9
+ * The strings or tokens contained by this token.
10
+ *
11
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
12
+ */
13
+ content: string | SyntaxTokenStream;
14
+ /**
15
+ * The alias(es) of the token.
16
+ * Always an array, even if empty or single value.
17
+ */
18
+ alias: Array<string>;
19
+ length: number;
20
+ constructor(type: string, content: string | SyntaxTokenStream, alias: string | Array<string> | undefined, matched_str?: string);
21
+ }
22
+ /**
23
+ * A token stream is an array of strings and `SyntaxToken` objects.
24
+ *
25
+ * Syntax token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
26
+ * them.
27
+ *
28
+ * 1. No adjacent strings.
29
+ * 2. No empty strings.
30
+ *
31
+ * The only exception here is the token stream that only contains the empty string and nothing else.
32
+ */
33
+ export type SyntaxTokenStream = Array<string | SyntaxToken>;
34
+ //# sourceMappingURL=syntax_token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax_token.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/syntax_token.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACvB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAEpC;;;OAGG;IACH,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;gBAGd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,iBAAiB,EACnC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,EACzC,WAAW,GAAE,MAAW;CAQzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC"}
@@ -0,0 +1,27 @@
1
+ export class SyntaxToken {
2
+ /**
3
+ * The type of the token.
4
+ *
5
+ * This is usually the key of a pattern in a `Grammar`.
6
+ */
7
+ type;
8
+ /**
9
+ * The strings or tokens contained by this token.
10
+ *
11
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
12
+ */
13
+ content;
14
+ /**
15
+ * The alias(es) of the token.
16
+ * Always an array, even if empty or single value.
17
+ */
18
+ alias;
19
+ length;
20
+ constructor(type, content, alias, matched_str = '') {
21
+ this.type = type;
22
+ this.content = content;
23
+ // Normalize alias to always be an array
24
+ this.alias = alias ? (Array.isArray(alias) ? alias : [alias]) : [];
25
+ this.length = matched_str.length;
26
+ }
27
+ }
package/dist/theme.css ADDED
@@ -0,0 +1,98 @@
1
+ .token_processing_instruction,
2
+ .token_doctype,
3
+ .token_cdata,
4
+ .token_punctuation {
5
+ color: var(--text_color_5);
6
+ }
7
+
8
+ .token_tag,
9
+ .token_constant,
10
+ .token_symbol,
11
+ .token_deleted,
12
+ .token_keyword,
13
+ .token_null,
14
+ .token_boolean,
15
+ .token_interpolation_punctuation,
16
+ .token_heading,
17
+ .token_heading_punctuation,
18
+ .token_tag_punctuation {
19
+ color: var(--color_a_5);
20
+ }
21
+
22
+ .token_comment,
23
+ .token_char,
24
+ .token_inserted,
25
+ .token_blockquote,
26
+ .token_blockquote_punctuation {
27
+ color: var(--color_b_5);
28
+ }
29
+
30
+ .token_builtin,
31
+ .token_class_name,
32
+ .token_number {
33
+ color: var(--color_j_5);
34
+ }
35
+
36
+ .token_attr_value,
37
+ .token_attr_quote,
38
+ .token_string,
39
+ .token_template_punctuation,
40
+ .token_inline_code,
41
+ .token_code_punctuation {
42
+ color: var(--color_h_5);
43
+ }
44
+
45
+ /* attr_equals must be after attr_value */
46
+ .token_attr_equals {
47
+ color: var(--text_color_5);
48
+ }
49
+
50
+ .token_selector,
51
+ .token_function,
52
+ .token_regex,
53
+ .token_important,
54
+ .token_variable {
55
+ color: var(--color_e_5);
56
+ }
57
+
58
+ .token_atrule {
59
+ color: var(--color_f_5);
60
+ }
61
+
62
+ .token_attr_name,
63
+ .token_property,
64
+ .token_decorator,
65
+ .token_decorator_name,
66
+ .token_link_text_wrapper,
67
+ .token_link_text,
68
+ .token_link_punctuation {
69
+ color: var(--color_i_5);
70
+ }
71
+
72
+ .token_special_keyword,
73
+ .token_namespace,
74
+ .token_rule {
75
+ color: var(--color_g_5);
76
+ }
77
+
78
+ .token_at_keyword,
79
+ .token_url {
80
+ color: var(--color_d_5);
81
+ }
82
+
83
+ .token_url {
84
+ text-decoration: underline;
85
+ }
86
+
87
+ .token_strikethrough {
88
+ text-decoration: line-through;
89
+ }
90
+
91
+ .token_important,
92
+ .token_bold {
93
+ font-weight: bold;
94
+ }
95
+
96
+ .token_italic {
97
+ font-style: italic;
98
+ }