yaxa-svelte 2.0.3 → 2.1.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 +4 -2
- package/dist/components/blocks/FAQ.svelte.d.ts +1 -1
- package/dist/components/blocks/FeatureGrid.svelte.d.ts +1 -1
- package/dist/components/blocks/Testimonials.svelte.d.ts +1 -1
- package/dist/components/elements/Avatar.svelte.d.ts +7 -25
- package/dist/components/elements/Badge.svelte.d.ts +15 -57
- package/dist/components/elements/Button.svelte.d.ts +19 -77
- package/dist/components/elements/Carousel.svelte.d.ts +2 -54
- package/dist/components/elements/CodeBlock.svelte +509 -43
- package/dist/components/elements/CodeBlock.test.js +354 -0
- package/dist/components/elements/CodeDiff.svelte +14 -0
- package/dist/components/elements/CodeDiff.test.js +16 -0
- package/dist/components/elements/EmptyState.svelte.d.ts +6 -26
- package/dist/components/elements/Icon.svelte.d.ts +6 -22
- package/dist/components/elements/Kbd.svelte.d.ts +5 -19
- package/dist/components/elements/Progress.svelte.d.ts +9 -35
- package/dist/components/elements/Skeleton.svelte.d.ts +8 -32
- package/dist/components/elements/Terminal.svelte.d.ts +1 -1
- package/dist/components/elements/Timeline.svelte.d.ts +4 -16
- package/dist/components/elements/Tree.svelte.d.ts +3 -13
- package/dist/components/elements/VirtualList.svelte.d.ts +3 -13
- package/dist/components/forms/Combobox.svelte.d.ts +7 -29
- package/dist/components/forms/Input.svelte.d.ts +9 -35
- package/dist/components/forms/MultiSelect.svelte.d.ts +7 -29
- package/dist/components/forms/NumberInput.svelte.d.ts +7 -29
- package/dist/components/forms/Select.svelte.d.ts +7 -29
- package/dist/components/forms/Switch.svelte.d.ts +8 -32
- package/dist/components/forms/Textarea.svelte.d.ts +11 -45
- package/dist/components/layout/Card.svelte.d.ts +10 -42
- package/dist/components/layout/Container.svelte.d.ts +7 -25
- package/dist/components/layout/DashboardShell.svelte.d.ts +1 -31
- package/dist/components/layout/ResizablePanels.svelte.d.ts +1 -35
- package/dist/components/navigation/CommandPalette.dom.test.d.ts +1 -0
- package/dist/components/navigation/CommandPalette.dom.test.js +76 -0
- package/dist/components/navigation/Stepper.svelte.d.ts +3 -13
- package/dist/components/overlays/Alert.svelte.d.ts +5 -19
- package/dist/components/overlays/Drawer.svelte.d.ts +3 -13
- package/dist/components/overlays/Modal.svelte.d.ts +6 -22
- package/dist/components/overlays/NotificationCenter.svelte.d.ts +1 -1
- package/dist/components/overlays/Slideover.svelte.d.ts +5 -19
- package/dist/components/overlays/Toast.svelte.d.ts +12 -44
- package/dist/components/saas/OrgSwitcher.svelte.d.ts +1 -1
- package/dist/components/saas/PasskeyUI.svelte.d.ts +1 -1
- package/dist/server/polar/index.d.ts +2 -1
- package/dist/server/polar/index.js +9 -8
- package/dist/server/polar/webhook.js +14 -11
- package/dist/server/polar/webhook.test.js +81 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +12 -1
- package/dist/utils/cn.d.ts +2 -2
- package/package.json +11 -13
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
| 'decorator';
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Zero-WASM Multi-Language Pure JavaScript Tokenizer with Svelte 5 Rune Recognition
|
|
35
|
+
// Zero-WASM Multi-Language Pure JavaScript Tokenizer with Svelte 5 Rune Recognition & Multi-Line State
|
|
36
36
|
export function tokenizeCode(code: string, language: string = 'typescript'): Token[][] {
|
|
37
37
|
const lines = code.split('\n');
|
|
38
38
|
const lang = language.toLowerCase();
|
|
@@ -41,42 +41,150 @@
|
|
|
41
41
|
const isLatex = ['latex', 'tex', 'math'].includes(lang);
|
|
42
42
|
const isVue = lang === 'vue';
|
|
43
43
|
const isJsx = ['tsx', 'jsx', 'react'].includes(lang);
|
|
44
|
+
const isTs = ['typescript', 'ts', 'tsx'].includes(lang);
|
|
45
|
+
const isJs = ['javascript', 'js', 'jsx', 'mjs', 'cjs'].includes(lang);
|
|
44
46
|
const isSvelte = ['svelte', 'svelte5', 'sv'].includes(lang);
|
|
45
47
|
const isHtml = ['html', 'xml', 'svg'].includes(lang);
|
|
46
48
|
const isPython = ['python', 'py'].includes(lang);
|
|
47
|
-
const
|
|
49
|
+
const isRust = ['rust', 'rs'].includes(lang);
|
|
50
|
+
const isGo = ['go', 'golang'].includes(lang);
|
|
51
|
+
const isSql = ['sql', 'pgsql', 'postgres', 'postgresql', 'mysql', 'sqlite'].includes(lang);
|
|
52
|
+
const isGraphQL = ['graphql', 'gql'].includes(lang);
|
|
48
53
|
const isBash = ['bash', 'sh', 'zsh', 'shell'].includes(lang);
|
|
54
|
+
const isJson = ['json', 'jsonc', 'json5'].includes(lang);
|
|
55
|
+
const isCss = ['css', 'scss', 'postcss', 'tailwind', 'tailwindcss'].includes(lang);
|
|
56
|
+
const isYaml = ['yaml', 'yml'].includes(lang);
|
|
57
|
+
const isToml = ['toml', 'cargo'].includes(lang);
|
|
58
|
+
|
|
59
|
+
let multilineState:
|
|
60
|
+
| null
|
|
61
|
+
| { type: 'comment'; delimiter: '/*' | '<!--' }
|
|
62
|
+
| { type: 'string'; delimiter: '"""' | "'''" | '`' } = null;
|
|
49
63
|
|
|
50
64
|
return lines.map((line) => {
|
|
51
|
-
if (!line)
|
|
65
|
+
if (!line) {
|
|
66
|
+
if (multilineState !== null) {
|
|
67
|
+
return [{ text: '', type: multilineState.type }];
|
|
68
|
+
}
|
|
69
|
+
return [{ text: '', type: 'plain' }];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const tokens: Token[] = [];
|
|
73
|
+
let remaining = line;
|
|
52
74
|
|
|
53
|
-
//
|
|
54
|
-
if (
|
|
55
|
-
|
|
75
|
+
// Handle multi-line comment or string continuation from previous line
|
|
76
|
+
if (multilineState !== null) {
|
|
77
|
+
if (multilineState.type === 'comment') {
|
|
78
|
+
const closeDelim = multilineState.delimiter === '/*' ? '*/' : '-->';
|
|
79
|
+
const closeIdx = remaining.indexOf(closeDelim);
|
|
80
|
+
if (closeIdx !== -1) {
|
|
81
|
+
const endIdx = closeIdx + closeDelim.length;
|
|
82
|
+
tokens.push({ text: remaining.slice(0, endIdx), type: 'comment' });
|
|
83
|
+
remaining = remaining.slice(endIdx);
|
|
84
|
+
multilineState = null;
|
|
85
|
+
} else {
|
|
86
|
+
tokens.push({ text: remaining, type: 'comment' });
|
|
87
|
+
return tokens;
|
|
88
|
+
}
|
|
89
|
+
} else if (multilineState.type === 'string') {
|
|
90
|
+
const delim = multilineState.delimiter;
|
|
91
|
+
if (delim === '`') {
|
|
92
|
+
const closeMatch = remaining.match(/^(?:[^`\\]|\\.)*?`/);
|
|
93
|
+
if (closeMatch) {
|
|
94
|
+
tokens.push({ text: closeMatch[0], type: 'string' });
|
|
95
|
+
remaining = remaining.slice(closeMatch[0].length);
|
|
96
|
+
multilineState = null;
|
|
97
|
+
} else {
|
|
98
|
+
tokens.push({ text: remaining, type: 'string' });
|
|
99
|
+
return tokens;
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
// Python triple quotes """ or '''
|
|
103
|
+
const closeIdx = remaining.indexOf(delim);
|
|
104
|
+
if (closeIdx !== -1) {
|
|
105
|
+
const endIdx = closeIdx + delim.length;
|
|
106
|
+
tokens.push({ text: remaining.slice(0, endIdx), type: 'string' });
|
|
107
|
+
remaining = remaining.slice(endIdx);
|
|
108
|
+
multilineState = null;
|
|
109
|
+
} else {
|
|
110
|
+
tokens.push({ text: remaining, type: 'string' });
|
|
111
|
+
return tokens;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Special full-line Markdown rules
|
|
118
|
+
if (isMarkdown && remaining === line) {
|
|
119
|
+
// Fenced code blocks (```lang or ~~~lang)
|
|
120
|
+
const fenceMatch = remaining.match(/^(\s*(?:`{3,}|~{3,})[\w-]*\s*)$/);
|
|
121
|
+
if (fenceMatch) {
|
|
122
|
+
return [{ text: fenceMatch[1], type: 'macro' }];
|
|
123
|
+
}
|
|
124
|
+
// Frontmatter & Horizontal rule (--- or ***)
|
|
125
|
+
const hrMatch = remaining.match(/^(\s*(?:---|___|\*\*\*)\s*)$/);
|
|
126
|
+
if (hrMatch) {
|
|
127
|
+
return [{ text: hrMatch[1], type: 'punctuation' }];
|
|
128
|
+
}
|
|
129
|
+
// Markdown Headings (# Header)
|
|
130
|
+
const headingMatch = remaining.match(/^(#{1,6}\s+)(.*)$/);
|
|
56
131
|
if (headingMatch) {
|
|
57
132
|
return [
|
|
58
133
|
{ text: headingMatch[1], type: 'punctuation' },
|
|
59
134
|
{ text: headingMatch[2], type: 'heading' }
|
|
60
135
|
];
|
|
61
136
|
}
|
|
62
|
-
|
|
137
|
+
// Blockquotes (> Quote)
|
|
138
|
+
const blockquoteMatch = remaining.match(/^(\s*>\s+)(.*)$/);
|
|
63
139
|
if (blockquoteMatch) {
|
|
64
140
|
return [
|
|
65
141
|
{ text: blockquoteMatch[1], type: 'punctuation' },
|
|
66
142
|
{ text: blockquoteMatch[2], type: 'italic' }
|
|
67
143
|
];
|
|
68
144
|
}
|
|
145
|
+
// Lists & Task checkboxes (- [x] Item, * Item, 1. Item)
|
|
146
|
+
const listMatch = remaining.match(/^(\s*(?:[-*+]|\d+\.)(?:\s+\[[ xX]\])?\s+)(.*)$/);
|
|
147
|
+
if (listMatch) {
|
|
148
|
+
return [
|
|
149
|
+
{ text: listMatch[1], type: 'punctuation' },
|
|
150
|
+
{ text: listMatch[2], type: 'plain' }
|
|
151
|
+
];
|
|
152
|
+
}
|
|
69
153
|
}
|
|
70
154
|
|
|
71
|
-
const tokens: Token[] = [];
|
|
72
|
-
let remaining = line;
|
|
73
|
-
|
|
74
155
|
while (remaining.length > 0) {
|
|
75
156
|
// 1. Comments
|
|
157
|
+
if (!isLatex && remaining.startsWith('/*')) {
|
|
158
|
+
const closeIdx = remaining.indexOf('*/', 2);
|
|
159
|
+
if (closeIdx !== -1) {
|
|
160
|
+
const endIdx = closeIdx + 2;
|
|
161
|
+
tokens.push({ text: remaining.slice(0, endIdx), type: 'comment' });
|
|
162
|
+
remaining = remaining.slice(endIdx);
|
|
163
|
+
continue;
|
|
164
|
+
} else {
|
|
165
|
+
tokens.push({ text: remaining, type: 'comment' });
|
|
166
|
+
multilineState = { type: 'comment', delimiter: '/*' };
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if ((isMarkdown || isHtml || isSvelte || isVue) && remaining.startsWith('<!--')) {
|
|
172
|
+
const closeIdx = remaining.indexOf('-->', 4);
|
|
173
|
+
if (closeIdx !== -1) {
|
|
174
|
+
const endIdx = closeIdx + 3;
|
|
175
|
+
tokens.push({ text: remaining.slice(0, endIdx), type: 'comment' });
|
|
176
|
+
remaining = remaining.slice(endIdx);
|
|
177
|
+
continue;
|
|
178
|
+
} else {
|
|
179
|
+
tokens.push({ text: remaining, type: 'comment' });
|
|
180
|
+
multilineState = { type: 'comment', delimiter: '<!--' };
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
76
185
|
if (
|
|
77
|
-
(!isLatex &&
|
|
78
|
-
((
|
|
79
|
-
((isPython || isBash || lang === 'env' || lang === 'yaml' || lang === 'yml') &&
|
|
186
|
+
(!isLatex && remaining.startsWith('//')) ||
|
|
187
|
+
((isPython || isBash || lang === 'env' || isYaml || isToml || isGraphQL) &&
|
|
80
188
|
remaining.startsWith('#')) ||
|
|
81
189
|
(isLatex && remaining.startsWith('%')) ||
|
|
82
190
|
(isSql && remaining.startsWith('--'))
|
|
@@ -85,7 +193,190 @@
|
|
|
85
193
|
break;
|
|
86
194
|
}
|
|
87
195
|
|
|
88
|
-
// 2.
|
|
196
|
+
// 2. Python & TOML Triple-Quoted Strings (Docstrings / Multiline)
|
|
197
|
+
if ((isPython || isToml) && (remaining.startsWith('"""') || remaining.startsWith("'''"))) {
|
|
198
|
+
const delim = remaining.startsWith('"""') ? '"""' : "'''";
|
|
199
|
+
const closeIdx = remaining.indexOf(delim, 3);
|
|
200
|
+
if (closeIdx !== -1) {
|
|
201
|
+
const endIdx = closeIdx + 3;
|
|
202
|
+
tokens.push({ text: remaining.slice(0, endIdx), type: 'string' });
|
|
203
|
+
remaining = remaining.slice(endIdx);
|
|
204
|
+
continue;
|
|
205
|
+
} else {
|
|
206
|
+
tokens.push({ text: remaining, type: 'string' });
|
|
207
|
+
multilineState = { type: 'string', delimiter: delim };
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 3. Multi-line Template Literals (Backticks) for JS / TS / Svelte / Vue
|
|
213
|
+
if ((isJs || isTs || isSvelte || isVue) && remaining.startsWith('`')) {
|
|
214
|
+
const fullBacktickMatch = remaining.match(/^(`(?:[^`\\]|\\.)*`)/);
|
|
215
|
+
if (fullBacktickMatch) {
|
|
216
|
+
tokens.push({ text: fullBacktickMatch[0], type: 'string' });
|
|
217
|
+
remaining = remaining.slice(fullBacktickMatch[0].length);
|
|
218
|
+
continue;
|
|
219
|
+
} else {
|
|
220
|
+
tokens.push({ text: remaining, type: 'string' });
|
|
221
|
+
multilineState = { type: 'string', delimiter: '`' };
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 4. JSON Object Keys ("key":)
|
|
227
|
+
if (isJson) {
|
|
228
|
+
const jsonKeyMatch = remaining.match(/^("(?:[^"\\]|\\.)*")(?=\s*:)/);
|
|
229
|
+
if (jsonKeyMatch) {
|
|
230
|
+
tokens.push({ text: jsonKeyMatch[1], type: 'attr' });
|
|
231
|
+
remaining = remaining.slice(jsonKeyMatch[1].length);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 4b. YAML Key-Value Pairs, Anchors, Aliases & Directives
|
|
237
|
+
if (isYaml) {
|
|
238
|
+
// Anchors & Aliases (&anchor, *alias)
|
|
239
|
+
const anchorMatch = remaining.match(/^([&*][\w.-]+)/);
|
|
240
|
+
if (anchorMatch) {
|
|
241
|
+
tokens.push({ text: anchorMatch[0], type: 'macro' });
|
|
242
|
+
remaining = remaining.slice(anchorMatch[0].length);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Tags (!!str, !!int, !!map, !custom)
|
|
247
|
+
const yamlTagMatch = remaining.match(/^(!{1,2}[\w.-]+)/);
|
|
248
|
+
if (yamlTagMatch) {
|
|
249
|
+
tokens.push({ text: yamlTagMatch[0], type: 'directive' });
|
|
250
|
+
remaining = remaining.slice(yamlTagMatch[0].length);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Document start/end markers (--- or ...)
|
|
255
|
+
if (remaining === line) {
|
|
256
|
+
const docMarkerMatch = remaining.match(/^(\s*(?:---|(?:\.\.\.))\s*)$/);
|
|
257
|
+
if (docMarkerMatch) {
|
|
258
|
+
tokens.push({ text: docMarkerMatch[1], type: 'punctuation' });
|
|
259
|
+
remaining = remaining.slice(docMarkerMatch[1].length);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Quoted keys before ':'
|
|
265
|
+
const yamlQuotedKeyMatch = remaining.match(
|
|
266
|
+
/^("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')(?=\s*:(?:\s|$))/
|
|
267
|
+
);
|
|
268
|
+
if (yamlQuotedKeyMatch) {
|
|
269
|
+
tokens.push({ text: yamlQuotedKeyMatch[1], type: 'attr' });
|
|
270
|
+
remaining = remaining.slice(yamlQuotedKeyMatch[1].length);
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Bare keys before ':'
|
|
275
|
+
const yamlKeyMatch = remaining.match(/^([\w.-]+)(?=\s*:(?:\s|$))/);
|
|
276
|
+
if (yamlKeyMatch) {
|
|
277
|
+
tokens.push({ text: yamlKeyMatch[0], type: 'attr' });
|
|
278
|
+
remaining = remaining.slice(yamlKeyMatch[0].length);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// YAML booleans, nulls & block scalar indicators
|
|
283
|
+
const yamlKwMatch = remaining.match(/^(true|false|yes|no|on|off|null|~|[|>][+-]?)\b/i);
|
|
284
|
+
if (yamlKwMatch) {
|
|
285
|
+
tokens.push({ text: yamlKwMatch[0], type: 'keyword' });
|
|
286
|
+
remaining = remaining.slice(yamlKwMatch[0].length);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 4c. TOML Table Headers & Key-Value Pairs
|
|
292
|
+
if (isToml) {
|
|
293
|
+
// Table headers ([table] or [[array_of_tables]])
|
|
294
|
+
const tomlTableMatch = remaining.match(/^(\[\[?[\w.:"-]+\]\]?)/);
|
|
295
|
+
if (tomlTableMatch) {
|
|
296
|
+
tokens.push({ text: tomlTableMatch[0], type: 'directive' });
|
|
297
|
+
remaining = remaining.slice(tomlTableMatch[0].length);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Quoted keys before '='
|
|
302
|
+
const tomlQuotedKeyMatch = remaining.match(
|
|
303
|
+
/^("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')(?=\s*=)/
|
|
304
|
+
);
|
|
305
|
+
if (tomlQuotedKeyMatch) {
|
|
306
|
+
tokens.push({ text: tomlQuotedKeyMatch[1], type: 'attr' });
|
|
307
|
+
remaining = remaining.slice(tomlQuotedKeyMatch[1].length);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Bare or dotted keys before '='
|
|
312
|
+
const tomlKeyMatch = remaining.match(/^([\w.-]+)(?=\s*=)/);
|
|
313
|
+
if (tomlKeyMatch) {
|
|
314
|
+
tokens.push({ text: tomlKeyMatch[0], type: 'attr' });
|
|
315
|
+
remaining = remaining.slice(tomlKeyMatch[0].length);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Special TOML float constants (+inf, -inf, nan)
|
|
320
|
+
const tomlFloatMatch = remaining.match(/^([+-]?(?:inf|nan))\b/i);
|
|
321
|
+
if (tomlFloatMatch) {
|
|
322
|
+
tokens.push({ text: tomlFloatMatch[0], type: 'number' });
|
|
323
|
+
remaining = remaining.slice(tomlFloatMatch[0].length);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// 4d. ISO Dates / Timestamps for YAML & TOML
|
|
329
|
+
if (isYaml || isToml) {
|
|
330
|
+
const dateMatch = remaining.match(
|
|
331
|
+
/^(\d{4}-\d{2}-\d{2}(?:[Tt\s]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})?)?|\d{2}:\d{2}:\d{2}(?:\.\d+)?)\b/
|
|
332
|
+
);
|
|
333
|
+
if (dateMatch) {
|
|
334
|
+
tokens.push({ text: dateMatch[0], type: 'number' });
|
|
335
|
+
remaining = remaining.slice(dateMatch[0].length);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// 5. CSS & Tailwind CSS v4 At-Rules, Variables & Colors
|
|
341
|
+
if (isCss) {
|
|
342
|
+
// Tailwind v4 & CSS At-rules (@theme, @utility, @source, @plugin, @import, @custom-variant, etc.)
|
|
343
|
+
const atRuleMatch = remaining.match(
|
|
344
|
+
/^(@(?:theme|utility|custom-variant|source|plugin|import|apply|keyframes|media|supports|container|layer|font-face|page|starting-style))\b/
|
|
345
|
+
);
|
|
346
|
+
if (atRuleMatch) {
|
|
347
|
+
tokens.push({ text: atRuleMatch[0], type: 'directive' });
|
|
348
|
+
remaining = remaining.slice(atRuleMatch[0].length);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// CSS Custom Properties / Design Tokens (--color-primary-500, etc.)
|
|
353
|
+
const cssVarMatch = remaining.match(/^(--[\w-]+)/);
|
|
354
|
+
if (cssVarMatch) {
|
|
355
|
+
tokens.push({ text: cssVarMatch[0], type: 'macro' });
|
|
356
|
+
remaining = remaining.slice(cssVarMatch[0].length);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Hex Color Literals (#ff3e00, #18181b, etc.)
|
|
361
|
+
const hexColorMatch = remaining.match(
|
|
362
|
+
/^#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})\b/
|
|
363
|
+
);
|
|
364
|
+
if (hexColorMatch) {
|
|
365
|
+
tokens.push({ text: hexColorMatch[0], type: 'number' });
|
|
366
|
+
remaining = remaining.slice(hexColorMatch[0].length);
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// CSS Properties before colon (e.g. display:, background-color:)
|
|
371
|
+
const cssPropMatch = remaining.match(/^([\w-]+)(?=\s*:)/);
|
|
372
|
+
if (cssPropMatch && !cssPropMatch[0].startsWith('-')) {
|
|
373
|
+
tokens.push({ text: cssPropMatch[0], type: 'keyword' });
|
|
374
|
+
remaining = remaining.slice(cssPropMatch[0].length);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 6. LaTeX Math Macros and Math Blocks
|
|
89
380
|
if (isLatex) {
|
|
90
381
|
const macroMatch = remaining.match(/^(\\[a-zA-Z]+|\\\[|\\\]|\\\(|\\\))/);
|
|
91
382
|
if (macroMatch) {
|
|
@@ -101,7 +392,7 @@
|
|
|
101
392
|
}
|
|
102
393
|
}
|
|
103
394
|
|
|
104
|
-
//
|
|
395
|
+
// 7. Markdown Formatting (Bold, Italic, Code, Links)
|
|
105
396
|
if (isMarkdown) {
|
|
106
397
|
const codeMatch = remaining.match(/^(`[^`]+`)/);
|
|
107
398
|
if (codeMatch) {
|
|
@@ -124,17 +415,7 @@
|
|
|
124
415
|
}
|
|
125
416
|
}
|
|
126
417
|
|
|
127
|
-
//
|
|
128
|
-
const strMatch = remaining.match(
|
|
129
|
-
/^("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/
|
|
130
|
-
);
|
|
131
|
-
if (strMatch) {
|
|
132
|
-
tokens.push({ text: strMatch[0], type: 'string' });
|
|
133
|
-
remaining = remaining.slice(strMatch[0].length);
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// 5. Python Decorators (@decorator)
|
|
418
|
+
// 8. Python Decorators (@decorator)
|
|
138
419
|
if (isPython) {
|
|
139
420
|
const decMatch = remaining.match(/^(@\w+)/);
|
|
140
421
|
if (decMatch) {
|
|
@@ -144,7 +425,190 @@
|
|
|
144
425
|
}
|
|
145
426
|
}
|
|
146
427
|
|
|
147
|
-
//
|
|
428
|
+
// 9. Python Built-in Types & Modern Typing Constructs (Python 3.0 to 3.13+)
|
|
429
|
+
if (isPython) {
|
|
430
|
+
const pyTypeMatch = remaining.match(
|
|
431
|
+
/^(str|int|float|bool|dict|list|tuple|set|bytes|Any|Optional|Union|Callable|Literal|TypeIs|TypeGuard|Self)\b/
|
|
432
|
+
);
|
|
433
|
+
if (pyTypeMatch) {
|
|
434
|
+
tokens.push({ text: pyTypeMatch[0], type: 'macro' });
|
|
435
|
+
remaining = remaining.slice(pyTypeMatch[0].length);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// 10. TypeScript / JavaScript Primitive Types & Type Operators (TS 5.x / TS 6 & ES2026)
|
|
441
|
+
if (isTs || isJs) {
|
|
442
|
+
const tsTypeMatch = remaining.match(
|
|
443
|
+
/^(string|number|boolean|unknown|never|any|void|readonly|satisfies|keyof|infer|Promise|Record|Array|Partial|Omit|Pick|Awaited|ReturnType|Parameters|ConstructorParameters|InstanceType|Extract|Exclude|NonNullable|Uppercase|Lowercase|Capitalize|Uncapitalize|Disposable|AsyncDisposable|BigInt|Symbol)\b/
|
|
444
|
+
);
|
|
445
|
+
if (tsTypeMatch) {
|
|
446
|
+
tokens.push({ text: tsTypeMatch[0], type: 'macro' });
|
|
447
|
+
remaining = remaining.slice(tsTypeMatch[0].length);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// 10b. Rust Attributes, Macro Invocations, Lifetimes & Standard Types
|
|
453
|
+
if (isRust) {
|
|
454
|
+
// Rust Attributes (#[derive(Debug, Clone)], #![no_std])
|
|
455
|
+
const rustAttrMatch = remaining.match(/^#(!?\[[\w:,()=\s"-]+\])/);
|
|
456
|
+
if (rustAttrMatch) {
|
|
457
|
+
tokens.push({ text: rustAttrMatch[0], type: 'decorator' });
|
|
458
|
+
remaining = remaining.slice(rustAttrMatch[0].length);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Rust Macro Invocations (println!, vec!, format!, panic!, etc.)
|
|
463
|
+
const rustMacroMatch = remaining.match(
|
|
464
|
+
/^(println|eprintln|print|eprint|format|vec|panic|assert|assert_eq|assert_ne|todo|unimplemented|unreachable|write|writeln|cfg|include|env|concat)!/
|
|
465
|
+
);
|
|
466
|
+
if (rustMacroMatch) {
|
|
467
|
+
tokens.push({ text: rustMacroMatch[0], type: 'macro' });
|
|
468
|
+
remaining = remaining.slice(rustMacroMatch[0].length);
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Rust Lifetimes ('a, 'static)
|
|
473
|
+
const lifetimeMatch = remaining.match(/^'(?:static|[a-z_]\w*)(?!')\b/);
|
|
474
|
+
if (lifetimeMatch) {
|
|
475
|
+
tokens.push({ text: lifetimeMatch[0], type: 'macro' });
|
|
476
|
+
remaining = remaining.slice(lifetimeMatch[0].length);
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Rust Primitive & Standard Types
|
|
481
|
+
const rustTypeMatch = remaining.match(
|
|
482
|
+
/^(i8|i16|i32|i64|i128|isize|u8|u16|u32|u64|u128|usize|f32|f64|bool|char|str|String|Option|Result|Vec|Box|Rc|Arc|Cell|RefCell|Mutex|RwLock|HashMap|HashSet|BTreeMap|BTreeSet|Self|None|Some|Ok|Err)\b/
|
|
483
|
+
);
|
|
484
|
+
if (rustTypeMatch) {
|
|
485
|
+
tokens.push({ text: rustTypeMatch[0], type: 'macro' });
|
|
486
|
+
remaining = remaining.slice(rustTypeMatch[0].length);
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// 10c. Go Primitive Types & Built-ins
|
|
492
|
+
if (isGo) {
|
|
493
|
+
const goTypeMatch = remaining.match(
|
|
494
|
+
/^(string|int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|uintptr|byte|rune|float32|float64|complex64|complex128|error|any|bool)\b/
|
|
495
|
+
);
|
|
496
|
+
if (goTypeMatch) {
|
|
497
|
+
tokens.push({ text: goTypeMatch[0], type: 'macro' });
|
|
498
|
+
remaining = remaining.slice(goTypeMatch[0].length);
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const goBuiltinMatch = remaining.match(
|
|
503
|
+
/^(make|len|cap|new|append|copy|close|delete|panic|recover|print|println|complex|real|imag)\b(?=\s*\()/
|
|
504
|
+
);
|
|
505
|
+
if (goBuiltinMatch) {
|
|
506
|
+
tokens.push({ text: goBuiltinMatch[0], type: 'function' });
|
|
507
|
+
remaining = remaining.slice(goBuiltinMatch[0].length);
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// 10d. SQL Data Types & Clauses
|
|
513
|
+
if (isSql) {
|
|
514
|
+
// SQL Standard Data Types
|
|
515
|
+
const sqlTypeMatch = remaining.match(
|
|
516
|
+
/^(INTEGER|INT|BIGINT|SMALLINT|TINYINT|SERIAL|BIGSERIAL|VARCHAR|TEXT|CHAR|CHARACTER|BOOLEAN|BOOL|DATE|TIME|TIMESTAMP|TIMESTAMPTZ|NUMERIC|DECIMAL|FLOAT|REAL|DOUBLE\s+PRECISION|DOUBLE|JSON|JSONB|UUID|BLOB|BYTEA|ARRAY|INTERVAL)\b/i
|
|
517
|
+
);
|
|
518
|
+
if (sqlTypeMatch) {
|
|
519
|
+
tokens.push({ text: sqlTypeMatch[0], type: 'macro' });
|
|
520
|
+
remaining = remaining.slice(sqlTypeMatch[0].length);
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Comprehensive SQL Clauses & Keywords
|
|
525
|
+
const sqlKwMatch = remaining.match(
|
|
526
|
+
/^(CREATE|ALTER|DROP|TRUNCATE|TABLE|DATABASE|SCHEMA|VIEW|INDEX|TRIGGER|FUNCTION|PROCEDURE|PRIMARY|FOREIGN|KEY|REFERENCES|CONSTRAINT|CHECK|DEFAULT|UNIQUE|NOT|NULL|CASCADE|RESTRICT|SELECT|DISTINCT|FROM|WHERE|AND|OR|IN|BETWEEN|LIKE|ILIKE|IS|EXISTS|HAVING|GROUP|ORDER|BY|ASC|DESC|LIMIT|OFFSET|FETCH|FIRST|NEXT|ROWS|ONLY|JOIN|INNER|LEFT|RIGHT|FULL|OUTER|CROSS|ON|USING|INSERT|INTO|VALUES|UPDATE|SET|DELETE|RETURNING|UNION|INTERSECT|EXCEPT|ALL|CASE|WHEN|THEN|ELSE|END|AS|BEGIN|COMMIT|ROLLBACK|TRANSACTION|SAVEPOINT|GRANT|REVOKE|WITH|RECURSIVE|OVER|PARTITION)\b/i
|
|
527
|
+
);
|
|
528
|
+
if (sqlKwMatch) {
|
|
529
|
+
tokens.push({ text: sqlKwMatch[0], type: 'keyword' });
|
|
530
|
+
remaining = remaining.slice(sqlKwMatch[0].length);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// 10e. GraphQL Variables, Directives & Scalars
|
|
536
|
+
if (isGraphQL) {
|
|
537
|
+
// GraphQL Variables ($id, $input)
|
|
538
|
+
const gqlVarMatch = remaining.match(/^(\$[\w]+)\b/);
|
|
539
|
+
if (gqlVarMatch) {
|
|
540
|
+
tokens.push({ text: gqlVarMatch[0], type: 'macro' });
|
|
541
|
+
remaining = remaining.slice(gqlVarMatch[0].length);
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Directives (@include, @skip, @deprecated, @specifiedBy)
|
|
546
|
+
const gqlDirMatch = remaining.match(/^(@(?:include|skip|deprecated|specifiedBy))\b/);
|
|
547
|
+
if (gqlDirMatch) {
|
|
548
|
+
tokens.push({ text: gqlDirMatch[0], type: 'decorator' });
|
|
549
|
+
remaining = remaining.slice(gqlDirMatch[0].length);
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Core Scalars
|
|
554
|
+
const gqlScalarMatch = remaining.match(/^(String|Int|Float|Boolean|ID)\b/);
|
|
555
|
+
if (gqlScalarMatch) {
|
|
556
|
+
tokens.push({ text: gqlScalarMatch[0], type: 'macro' });
|
|
557
|
+
remaining = remaining.slice(gqlScalarMatch[0].length);
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// GraphQL Keywords
|
|
562
|
+
const gqlKwMatch = remaining.match(
|
|
563
|
+
/^(query|mutation|subscription|fragment|on|type|input|interface|union|enum|scalar|schema|directive|extend)\b/
|
|
564
|
+
);
|
|
565
|
+
if (gqlKwMatch) {
|
|
566
|
+
tokens.push({ text: gqlKwMatch[0], type: 'keyword' });
|
|
567
|
+
remaining = remaining.slice(gqlKwMatch[0].length);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// 11. Bash / Shell Variables & CLI Flags
|
|
573
|
+
if (isBash) {
|
|
574
|
+
const bashVarMatch = remaining.match(/^(\$\{?[\w#?@*!$-]+\}?)/);
|
|
575
|
+
if (bashVarMatch) {
|
|
576
|
+
tokens.push({ text: bashVarMatch[0], type: 'macro' });
|
|
577
|
+
remaining = remaining.slice(bashVarMatch[0].length);
|
|
578
|
+
continue;
|
|
579
|
+
}
|
|
580
|
+
const bashFlagMatch = remaining.match(/^(--?[\w-]+)/);
|
|
581
|
+
if (bashFlagMatch) {
|
|
582
|
+
tokens.push({ text: bashFlagMatch[0], type: 'attr' });
|
|
583
|
+
remaining = remaining.slice(bashFlagMatch[0].length);
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// 12. Svelte 5 Native Runes & Template Logic Blocks
|
|
589
|
+
if (isSvelte) {
|
|
590
|
+
// Svelte 5 Runes ($state, $derived, $props, $effect, etc.)
|
|
591
|
+
const svelteRuneMatch = remaining.match(
|
|
592
|
+
/^(\$(?:state(?:\.raw|\.snapshot)?|derived(?:\.by)?|effect(?:\.pre|\.root)?|props|bindable|inspect(?:\.trace)?|host))\b/
|
|
593
|
+
);
|
|
594
|
+
if (svelteRuneMatch) {
|
|
595
|
+
tokens.push({ text: svelteRuneMatch[0], type: 'rune' });
|
|
596
|
+
remaining = remaining.slice(svelteRuneMatch[0].length);
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Svelte Control Flow & Snippets ({#if}, {#each}, {#snippet}, {@render}, {@html}, etc.)
|
|
601
|
+
const svelteBlockMatch = remaining.match(
|
|
602
|
+
/^(\{(?:#(?:if|each|await|snippet|key)|:(?:else\s+if|else|then|catch)|\/(?:if|each|await|snippet|key)|@(?:render|html|const|debug)))\b/
|
|
603
|
+
);
|
|
604
|
+
if (svelteBlockMatch) {
|
|
605
|
+
tokens.push({ text: svelteBlockMatch[0], type: 'directive' });
|
|
606
|
+
remaining = remaining.slice(svelteBlockMatch[0].length);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 13. HTML / Vue / Svelte / JSX Tags & Attributes
|
|
148
612
|
if (isVue || isSvelte || isHtml || isJsx) {
|
|
149
613
|
const tagMatch = remaining.match(/^(<\/?[\w.:-]+|\/>|>)/);
|
|
150
614
|
if (tagMatch) {
|
|
@@ -170,19 +634,19 @@
|
|
|
170
634
|
}
|
|
171
635
|
}
|
|
172
636
|
|
|
173
|
-
//
|
|
174
|
-
const
|
|
175
|
-
/^(
|
|
637
|
+
// 14. Standard Strings (Single & Double Quoted)
|
|
638
|
+
const strMatch = remaining.match(
|
|
639
|
+
/^("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/
|
|
176
640
|
);
|
|
177
|
-
if (
|
|
178
|
-
tokens.push({ text:
|
|
179
|
-
remaining = remaining.slice(
|
|
641
|
+
if (strMatch) {
|
|
642
|
+
tokens.push({ text: strMatch[0], type: 'string' });
|
|
643
|
+
remaining = remaining.slice(strMatch[0].length);
|
|
180
644
|
continue;
|
|
181
645
|
}
|
|
182
646
|
|
|
183
|
-
//
|
|
647
|
+
// 15. Keywords Across Languages (including ES2026 and TS6)
|
|
184
648
|
const kwMatch = remaining.match(
|
|
185
|
-
/^(import|export|from|default|const|let|var|function|return|async|await|class|interface|type|extends|implements|new|this|typeof|instanceof|if|else|switch|case|break|for|while|try|catch|finally|throw|as|in|of|true|false|null|undefined|fn|mut|struct|enum|impl|trait|pub|use|mod|crate|where|loop|unsafe|package|func|defer|go|chan|select|iota|def|self|yield|lambda|elif|except|with|None|True|False|pass|query|mutation|subscription|schema|scalar|fragment|directive|SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|GROUP|ORDER|BY|LIMIT|pnpm|npm|npx|bun|yarn|git|docker)\b/i
|
|
649
|
+
/^(import|export|from|default|const|let|var|function|return|async|await|class|interface|type|extends|implements|new|this|typeof|instanceof|if|else|switch|case|break|for|while|try|catch|finally|throw|as|in|of|true|false|null|undefined|fn|mut|struct|enum|impl|trait|pub|use|mod|crate|where|loop|unsafe|package|func|defer|go|chan|select|iota|def|self|yield|lambda|elif|except|with|None|True|False|pass|assert|raise|match|when|using|accessor|override|declare|namespace|asserts|is|del|global|nonlocal|query|mutation|subscription|schema|scalar|fragment|directive|SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|GROUP|ORDER|BY|LIMIT|pnpm|npm|npx|bun|yarn|git|docker|curl|wget|mkdir|echo|cat|rm|cp|mv|chmod|chown|sudo|cd|ls|pwd|grep|sed|awk)\b/i
|
|
186
650
|
);
|
|
187
651
|
if (kwMatch) {
|
|
188
652
|
tokens.push({ text: kwMatch[0], type: 'keyword' });
|
|
@@ -190,7 +654,7 @@
|
|
|
190
654
|
continue;
|
|
191
655
|
}
|
|
192
656
|
|
|
193
|
-
//
|
|
657
|
+
// 16. React Hooks / Generic Macro tokens
|
|
194
658
|
const macroMatch = remaining.match(/^(use[A-Z]\w+)\b/);
|
|
195
659
|
if (macroMatch) {
|
|
196
660
|
tokens.push({ text: macroMatch[0], type: 'macro' });
|
|
@@ -198,7 +662,7 @@
|
|
|
198
662
|
continue;
|
|
199
663
|
}
|
|
200
664
|
|
|
201
|
-
//
|
|
665
|
+
// 17. Function Invocations (funcName())
|
|
202
666
|
const fnMatch = remaining.match(/^(\$?\w+)(?=\s*\()/);
|
|
203
667
|
if (fnMatch) {
|
|
204
668
|
tokens.push({ text: fnMatch[0], type: 'function' });
|
|
@@ -206,15 +670,17 @@
|
|
|
206
670
|
continue;
|
|
207
671
|
}
|
|
208
672
|
|
|
209
|
-
//
|
|
210
|
-
const numMatch = remaining.match(
|
|
673
|
+
// 18. Numbers (integers, floats, scientific, BigInt, hex, binary, octal & CSS units)
|
|
674
|
+
const numMatch = remaining.match(
|
|
675
|
+
/^(?:0[xX][0-9a-fA-F_]+n?|0[bB][01_]+n?|0[oO][0-7_]+n?|\b\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?[\d_]+)?n?(?:px|rem|em|%|vh|vw|dvh|dvw|s|ms)?)\b/
|
|
676
|
+
);
|
|
211
677
|
if (numMatch) {
|
|
212
678
|
tokens.push({ text: numMatch[0], type: 'number' });
|
|
213
679
|
remaining = remaining.slice(numMatch[0].length);
|
|
214
680
|
continue;
|
|
215
681
|
}
|
|
216
682
|
|
|
217
|
-
//
|
|
683
|
+
// 19. Punctuation & Math Operators
|
|
218
684
|
const punctMatch = remaining.match(/^([{}()[\].,;:?!=<>+\-*/%&|^~_^\\]+)/);
|
|
219
685
|
if (punctMatch) {
|
|
220
686
|
tokens.push({ text: punctMatch[0], type: 'punctuation' });
|
|
@@ -222,7 +688,7 @@
|
|
|
222
688
|
continue;
|
|
223
689
|
}
|
|
224
690
|
|
|
225
|
-
//
|
|
691
|
+
// 20. Plain text / whitespace
|
|
226
692
|
const plainMatch = remaining.match(/^([\w$]+|\s+)/);
|
|
227
693
|
if (plainMatch) {
|
|
228
694
|
tokens.push({ text: plainMatch[0], type: 'plain' });
|
|
@@ -354,7 +820,7 @@
|
|
|
354
820
|
? 'text-neutral-800 dark:text-neutral-200'
|
|
355
821
|
: 'text-neutral-200'} {wrap ? 'whitespace-pre-wrap' : 'whitespace-pre'}"><code
|
|
356
822
|
class="language-{language}"
|
|
357
|
-
>{#each tokenizedLines as lineTokens, lineIdx}{@const lineNum =
|
|
823
|
+
>{#each tokenizedLines as lineTokens, lineIdx (lineIdx)}{@const lineNum =
|
|
358
824
|
lineIdx + 1}{@const isHighlighted = highlightLines.includes(lineNum)}<div
|
|
359
825
|
class="table-row {isHighlighted
|
|
360
826
|
? '-mx-4 block border-l-2 border-primary-500 bg-primary-500/10 px-4'
|
|
@@ -363,7 +829,7 @@
|
|
|
363
829
|
? 'text-neutral-400 dark:text-neutral-600'
|
|
364
830
|
: 'text-neutral-600 dark:text-neutral-500'}">{lineNum}</span
|
|
365
831
|
>{/if}<span class="table-cell"
|
|
366
|
-
>{#each lineTokens as token}{#if token.type === 'rune'}<span
|
|
832
|
+
>{#each lineTokens as token, tokenIdx (tokenIdx)}{#if token.type === 'rune'}<span
|
|
367
833
|
class="font-bold text-amber-500 dark:text-amber-400">{token.text}</span
|
|
368
834
|
>{:else if token.type === 'keyword'}<span class="font-semibold text-primary-500"
|
|
369
835
|
>{token.text}</span
|