yaxa-svelte 2.0.4 → 2.2.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 (65) hide show
  1. package/README.md +38 -3
  2. package/dist/components/blocks/FAQ.svelte.d.ts +1 -1
  3. package/dist/components/blocks/FeatureGrid.svelte.d.ts +1 -1
  4. package/dist/components/blocks/Testimonials.svelte.d.ts +1 -1
  5. package/dist/components/elements/Avatar.svelte.d.ts +7 -25
  6. package/dist/components/elements/Badge.svelte.d.ts +15 -57
  7. package/dist/components/elements/Button.svelte.d.ts +19 -77
  8. package/dist/components/elements/Carousel.svelte.d.ts +2 -54
  9. package/dist/components/elements/CodeBlock.svelte +237 -8
  10. package/dist/components/elements/CodeBlock.test.js +227 -0
  11. package/dist/components/elements/CodeDiff.svelte +14 -0
  12. package/dist/components/elements/CodeDiff.test.js +16 -0
  13. package/dist/components/elements/EmptyState.svelte.d.ts +6 -26
  14. package/dist/components/elements/Icon.svelte.d.ts +6 -22
  15. package/dist/components/elements/Kbd.svelte.d.ts +5 -19
  16. package/dist/components/elements/Progress.svelte.d.ts +9 -35
  17. package/dist/components/elements/Skeleton.svelte.d.ts +8 -32
  18. package/dist/components/elements/Terminal.svelte.d.ts +1 -1
  19. package/dist/components/elements/Timeline.svelte.d.ts +4 -16
  20. package/dist/components/elements/Tree.svelte.d.ts +3 -13
  21. package/dist/components/elements/VirtualList.svelte.d.ts +3 -13
  22. package/dist/components/forms/Combobox.svelte.d.ts +7 -29
  23. package/dist/components/forms/Input.svelte.d.ts +9 -35
  24. package/dist/components/forms/MultiSelect.svelte.d.ts +7 -29
  25. package/dist/components/forms/NumberInput.svelte.d.ts +7 -29
  26. package/dist/components/forms/Select.svelte.d.ts +7 -29
  27. package/dist/components/forms/Switch.svelte.d.ts +8 -32
  28. package/dist/components/forms/Textarea.svelte.d.ts +11 -45
  29. package/dist/components/layout/Card.svelte.d.ts +10 -42
  30. package/dist/components/layout/Container.svelte.d.ts +7 -25
  31. package/dist/components/layout/DashboardShell.svelte.d.ts +1 -31
  32. package/dist/components/layout/ResizablePanels.svelte.d.ts +1 -35
  33. package/dist/components/navigation/CommandPalette.dom.test.d.ts +1 -0
  34. package/dist/components/navigation/CommandPalette.dom.test.js +76 -0
  35. package/dist/components/navigation/Stepper.svelte.d.ts +3 -13
  36. package/dist/components/overlays/Alert.svelte.d.ts +5 -19
  37. package/dist/components/overlays/Drawer.svelte.d.ts +3 -13
  38. package/dist/components/overlays/Modal.svelte.d.ts +6 -22
  39. package/dist/components/overlays/NotificationCenter.svelte.d.ts +1 -1
  40. package/dist/components/overlays/Slideover.svelte.d.ts +5 -19
  41. package/dist/components/overlays/Toast.svelte.d.ts +12 -44
  42. package/dist/components/saas/OrgSwitcher.svelte.d.ts +1 -1
  43. package/dist/components/saas/PasskeyUI.svelte.d.ts +1 -1
  44. package/dist/server/endpoint/endpoint.test.d.ts +1 -0
  45. package/dist/server/endpoint/endpoint.test.js +364 -0
  46. package/dist/server/endpoint/guards.d.ts +52 -0
  47. package/dist/server/endpoint/guards.js +137 -0
  48. package/dist/server/endpoint/index.d.ts +14 -0
  49. package/dist/server/endpoint/index.js +238 -0
  50. package/dist/server/endpoint/problem.d.ts +26 -0
  51. package/dist/server/endpoint/problem.js +62 -0
  52. package/dist/server/endpoint/types.d.ts +144 -0
  53. package/dist/server/endpoint/types.js +1 -0
  54. package/dist/server/endpoint/validate.d.ts +21 -0
  55. package/dist/server/endpoint/validate.js +128 -0
  56. package/dist/server/index.d.ts +2 -0
  57. package/dist/server/index.js +2 -0
  58. package/dist/server/polar/index.d.ts +2 -1
  59. package/dist/server/polar/index.js +9 -8
  60. package/dist/server/polar/webhook.js +14 -11
  61. package/dist/server/polar/webhook.test.js +81 -0
  62. package/dist/testing/index.d.ts +2 -0
  63. package/dist/testing/index.js +12 -1
  64. package/dist/utils/cn.d.ts +2 -2
  65. package/package.json +11 -13
@@ -46,10 +46,15 @@
46
46
  const isSvelte = ['svelte', 'svelte5', 'sv'].includes(lang);
47
47
  const isHtml = ['html', 'xml', 'svg'].includes(lang);
48
48
  const isPython = ['python', 'py'].includes(lang);
49
- const isSql = lang === 'sql';
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);
50
53
  const isBash = ['bash', 'sh', 'zsh', 'shell'].includes(lang);
51
54
  const isJson = ['json', 'jsonc', 'json5'].includes(lang);
52
55
  const isCss = ['css', 'scss', 'postcss', 'tailwind', 'tailwindcss'].includes(lang);
56
+ const isYaml = ['yaml', 'yml'].includes(lang);
57
+ const isToml = ['toml', 'cargo'].includes(lang);
53
58
 
54
59
  let multilineState:
55
60
  | null
@@ -179,7 +184,7 @@
179
184
 
180
185
  if (
181
186
  (!isLatex && remaining.startsWith('//')) ||
182
- ((isPython || isBash || lang === 'env' || lang === 'yaml' || lang === 'yml') &&
187
+ ((isPython || isBash || lang === 'env' || isYaml || isToml || isGraphQL) &&
183
188
  remaining.startsWith('#')) ||
184
189
  (isLatex && remaining.startsWith('%')) ||
185
190
  (isSql && remaining.startsWith('--'))
@@ -188,8 +193,8 @@
188
193
  break;
189
194
  }
190
195
 
191
- // 2. Python Triple-Quoted Strings (Docstrings)
192
- if (isPython && (remaining.startsWith('"""') || remaining.startsWith("'''"))) {
196
+ // 2. Python & TOML Triple-Quoted Strings (Docstrings / Multiline)
197
+ if ((isPython || isToml) && (remaining.startsWith('"""') || remaining.startsWith("'''"))) {
193
198
  const delim = remaining.startsWith('"""') ? '"""' : "'''";
194
199
  const closeIdx = remaining.indexOf(delim, 3);
195
200
  if (closeIdx !== -1) {
@@ -228,6 +233,110 @@
228
233
  }
229
234
  }
230
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
+
231
340
  // 5. CSS & Tailwind CSS v4 At-Rules, Variables & Colors
232
341
  if (isCss) {
233
342
  // Tailwind v4 & CSS At-rules (@theme, @utility, @source, @plugin, @import, @custom-variant, etc.)
@@ -316,10 +425,10 @@
316
425
  }
317
426
  }
318
427
 
319
- // 9. Python Built-in Types (int, str, dict, list, bool, etc.)
428
+ // 9. Python Built-in Types & Modern Typing Constructs (Python 3.0 to 3.13+)
320
429
  if (isPython) {
321
430
  const pyTypeMatch = remaining.match(
322
- /^(str|int|float|bool|dict|list|tuple|set|bytes|Any|Optional|Union|Callable|Literal)\b/
431
+ /^(str|int|float|bool|dict|list|tuple|set|bytes|Any|Optional|Union|Callable|Literal|TypeIs|TypeGuard|Self)\b/
323
432
  );
324
433
  if (pyTypeMatch) {
325
434
  tokens.push({ text: pyTypeMatch[0], type: 'macro' });
@@ -340,6 +449,126 @@
340
449
  }
341
450
  }
342
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
+
343
572
  // 11. Bash / Shell Variables & CLI Flags
344
573
  if (isBash) {
345
574
  const bashVarMatch = remaining.match(/^(\$\{?[\w#?@*!$-]+\}?)/);
@@ -591,7 +820,7 @@
591
820
  ? 'text-neutral-800 dark:text-neutral-200'
592
821
  : 'text-neutral-200'} {wrap ? 'whitespace-pre-wrap' : 'whitespace-pre'}"><code
593
822
  class="language-{language}"
594
- >{#each tokenizedLines as lineTokens, lineIdx}{@const lineNum =
823
+ >{#each tokenizedLines as lineTokens, lineIdx (lineIdx)}{@const lineNum =
595
824
  lineIdx + 1}{@const isHighlighted = highlightLines.includes(lineNum)}<div
596
825
  class="table-row {isHighlighted
597
826
  ? '-mx-4 block border-l-2 border-primary-500 bg-primary-500/10 px-4'
@@ -600,7 +829,7 @@
600
829
  ? 'text-neutral-400 dark:text-neutral-600'
601
830
  : 'text-neutral-600 dark:text-neutral-500'}">{lineNum}</span
602
831
  >{/if}<span class="table-cell"
603
- >{#each lineTokens as token}{#if token.type === 'rune'}<span
832
+ >{#each lineTokens as token, tokenIdx (tokenIdx)}{#if token.type === 'rune'}<span
604
833
  class="font-bold text-amber-500 dark:text-amber-400">{token.text}</span
605
834
  >{:else if token.type === 'keyword'}<span class="font-semibold text-primary-500"
606
835
  >{token.text}</span
@@ -48,6 +48,36 @@ describe('tokenizeCode', () => {
48
48
  const line4 = tokens[4].map((t) => ({ text: t.text, type: t.type }));
49
49
  expect(line4).toContainEqual({ text: 'assert', type: 'keyword' });
50
50
  });
51
+ it('tokenizes Python 3.13+ syntax: type parameters, TypeIs narrowing, match/case and decorators', () => {
52
+ const pyCode = `type Point[T = int] = tuple[T, T]
53
+ @deprecated
54
+ def is_str(val: object) -> TypeIs[str]:
55
+ match val:
56
+ case str():
57
+ return True
58
+ case _:
59
+ return False`;
60
+ const tokens = tokenizeCode(pyCode, 'python');
61
+ expect(tokens).toHaveLength(8);
62
+ // Line 0: type Point[T = int] = tuple[T, T]
63
+ const line0 = tokens[0].map((t) => ({ text: t.text, type: t.type }));
64
+ expect(line0).toContainEqual({ text: 'type', type: 'keyword' });
65
+ expect(line0).toContainEqual({ text: 'int', type: 'macro' });
66
+ expect(line0).toContainEqual({ text: 'tuple', type: 'macro' });
67
+ // Line 1: @deprecated
68
+ const line1 = tokens[1].map((t) => ({ text: t.text, type: t.type }));
69
+ expect(line1).toContainEqual({ text: '@deprecated', type: 'decorator' });
70
+ // Line 2: def is_str(val: object) -> TypeIs[str]:
71
+ const line2 = tokens[2].map((t) => ({ text: t.text, type: t.type }));
72
+ expect(line2).toContainEqual({ text: 'def', type: 'keyword' });
73
+ expect(line2).toContainEqual({ text: 'TypeIs', type: 'macro' });
74
+ expect(line2).toContainEqual({ text: 'str', type: 'macro' });
75
+ // Line 3 & 4: match / case
76
+ const line3 = tokens[3].map((t) => ({ text: t.text, type: t.type }));
77
+ expect(line3).toContainEqual({ text: 'match', type: 'keyword' });
78
+ const line4 = tokens[4].map((t) => ({ text: t.text, type: t.type }));
79
+ expect(line4).toContainEqual({ text: 'case', type: 'keyword' });
80
+ });
51
81
  it('tokenizes tailwind css v4 at-rules, variables and hex colors', () => {
52
82
  const cssCode = `@theme {
53
83
  --color-primary-500: #ff3e00;
@@ -150,4 +180,201 @@ type TaskResult = Awaited<Promise<Record<string, unknown>>>;`;
150
180
  const line11 = tokens[11].map((t) => ({ text: t.text, type: t.type }));
151
181
  expect(line11).toContainEqual({ text: 'Awaited', type: 'macro' });
152
182
  });
183
+ it('tokenizes YAML keys, anchors, aliases, tags, booleans and document markers', () => {
184
+ const yamlCode = `---
185
+ # App configuration
186
+ name: "yaxa-app"
187
+ version: 2.1
188
+ enabled: true
189
+ maintenance: off
190
+ defaults: &base_config
191
+ timeout: 30
192
+ production: *base_config
193
+ tag_demo: !custom_tag
194
+ created_at: 2026-10-27`;
195
+ const tokens = tokenizeCode(yamlCode, 'yaml');
196
+ expect(tokens).toHaveLength(11);
197
+ // Line 0: ---
198
+ expect(tokens[0][0]).toEqual({ text: '---', type: 'punctuation' });
199
+ // Line 1: # App configuration
200
+ expect(tokens[1][0]).toEqual({ text: '# App configuration', type: 'comment' });
201
+ // Line 2: name: "yaxa-app"
202
+ const line2 = tokens[2].map((t) => ({ text: t.text, type: t.type }));
203
+ expect(line2).toContainEqual({ text: 'name', type: 'attr' });
204
+ expect(line2).toContainEqual({ text: '"yaxa-app"', type: 'string' });
205
+ // Line 4: enabled: true
206
+ const line4 = tokens[4].map((t) => ({ text: t.text, type: t.type }));
207
+ expect(line4).toContainEqual({ text: 'enabled', type: 'attr' });
208
+ expect(line4).toContainEqual({ text: 'true', type: 'keyword' });
209
+ // Line 5: maintenance: off
210
+ const line5 = tokens[5].map((t) => ({ text: t.text, type: t.type }));
211
+ expect(line5).toContainEqual({ text: 'maintenance', type: 'attr' });
212
+ expect(line5).toContainEqual({ text: 'off', type: 'keyword' });
213
+ // Line 6: defaults: &base_config
214
+ const line6 = tokens[6].map((t) => ({ text: t.text, type: t.type }));
215
+ expect(line6).toContainEqual({ text: 'defaults', type: 'attr' });
216
+ expect(line6).toContainEqual({ text: '&base_config', type: 'macro' });
217
+ // Line 8: production: *base_config
218
+ const line8 = tokens[8].map((t) => ({ text: t.text, type: t.type }));
219
+ expect(line8).toContainEqual({ text: 'production', type: 'attr' });
220
+ expect(line8).toContainEqual({ text: '*base_config', type: 'macro' });
221
+ // Line 9: tag_demo: !custom_tag
222
+ const line9 = tokens[9].map((t) => ({ text: t.text, type: t.type }));
223
+ expect(line9).toContainEqual({ text: 'tag_demo', type: 'attr' });
224
+ expect(line9).toContainEqual({ text: '!custom_tag', type: 'directive' });
225
+ // Line 10: created_at: 2026-10-27
226
+ const line10 = tokens[10].map((t) => ({ text: t.text, type: t.type }));
227
+ expect(line10).toContainEqual({ text: 'created_at', type: 'attr' });
228
+ expect(line10).toContainEqual({ text: '2026-10-27', type: 'number' });
229
+ });
230
+ it('tokenizes TOML table headers, keys, dates, and multiline strings', () => {
231
+ const tomlCode = `[server]
232
+ port = 8080
233
+ enabled = true
234
+ started = 1979-05-27T07:32:00Z
235
+ bio = """
236
+ Hello World
237
+ Multilined
238
+ """`;
239
+ const tokens = tokenizeCode(tomlCode, 'toml');
240
+ expect(tokens).toHaveLength(8);
241
+ // Line 0: [server]
242
+ expect(tokens[0][0]).toEqual({ text: '[server]', type: 'directive' });
243
+ // Line 1: port = 8080
244
+ const line1 = tokens[1].map((t) => ({ text: t.text, type: t.type }));
245
+ expect(line1).toContainEqual({ text: 'port', type: 'attr' });
246
+ expect(line1).toContainEqual({ text: '8080', type: 'number' });
247
+ // Line 2: enabled = true
248
+ const line2 = tokens[2].map((t) => ({ text: t.text, type: t.type }));
249
+ expect(line2).toContainEqual({ text: 'enabled', type: 'attr' });
250
+ expect(line2).toContainEqual({ text: 'true', type: 'keyword' });
251
+ // Line 3: started = 1979-05-27T07:32:00Z
252
+ const line3 = tokens[3].map((t) => ({ text: t.text, type: t.type }));
253
+ expect(line3).toContainEqual({ text: 'started', type: 'attr' });
254
+ expect(line3).toContainEqual({ text: '1979-05-27T07:32:00Z', type: 'number' });
255
+ // Multiline string across lines 4, 5, 6, 7
256
+ expect(tokens[4].some((t) => t.type === 'string')).toBe(true);
257
+ expect(tokens[5][0].type).toBe('string');
258
+ expect(tokens[6][0].type).toBe('string');
259
+ expect(tokens[7].some((t) => t.type === 'string')).toBe(true);
260
+ });
261
+ it('tokenizes Rust attributes, macros, lifetimes, and standard types to Tier 1 standard', () => {
262
+ const rustCode = `#[derive(Debug, Clone)]
263
+ pub fn process<'a>(name: &'a str) -> Option<String> {
264
+ let items: Vec<i32> = vec![1, 2, 3];
265
+ println!("Processed: {}", name);
266
+ Some(name.to_string())
267
+ }`;
268
+ const tokens = tokenizeCode(rustCode, 'rust');
269
+ expect(tokens).toHaveLength(6);
270
+ // Line 0: #[derive(Debug, Clone)]
271
+ expect(tokens[0][0].type).toBe('decorator');
272
+ // Line 1: pub fn process<'a>(name: &'a str) -> Option<String>
273
+ const line1 = tokens[1].map((t) => ({ text: t.text, type: t.type }));
274
+ expect(line1).toContainEqual({ text: 'pub', type: 'keyword' });
275
+ expect(line1).toContainEqual({ text: 'fn', type: 'keyword' });
276
+ expect(line1).toContainEqual({ text: "'a", type: 'macro' });
277
+ expect(line1).toContainEqual({ text: 'str', type: 'macro' });
278
+ expect(line1).toContainEqual({ text: 'Option', type: 'macro' });
279
+ expect(line1).toContainEqual({ text: 'String', type: 'macro' });
280
+ // Line 2: let items: Vec<i32> = vec![1, 2, 3];
281
+ const line2 = tokens[2].map((t) => ({ text: t.text, type: t.type }));
282
+ expect(line2).toContainEqual({ text: 'Vec', type: 'macro' });
283
+ expect(line2).toContainEqual({ text: 'i32', type: 'macro' });
284
+ expect(line2).toContainEqual({ text: 'vec!', type: 'macro' });
285
+ // Line 3: println!("...")
286
+ const line3 = tokens[3].map((t) => ({ text: t.text, type: t.type }));
287
+ expect(line3).toContainEqual({ text: 'println!', type: 'macro' });
288
+ // Line 4: Some(...)
289
+ const line4 = tokens[4].map((t) => ({ text: t.text, type: t.type }));
290
+ expect(line4).toContainEqual({ text: 'Some', type: 'macro' });
291
+ });
292
+ it('tokenizes Go built-in functions and primitive types to Tier 1 standard', () => {
293
+ const goCode = `package main
294
+ func NewBuffer(size int) (error, any) {
295
+ buf := make([]byte, size)
296
+ println(len(buf))
297
+ return nil, buf
298
+ }`;
299
+ const tokens = tokenizeCode(goCode, 'go');
300
+ expect(tokens).toHaveLength(6);
301
+ // Line 0: package main
302
+ expect(tokens[0].some((t) => t.text === 'package' && t.type === 'keyword')).toBe(true);
303
+ // Line 1: func NewBuffer(size int) (error, any)
304
+ const line1 = tokens[1].map((t) => ({ text: t.text, type: t.type }));
305
+ expect(line1).toContainEqual({ text: 'func', type: 'keyword' });
306
+ expect(line1).toContainEqual({ text: 'int', type: 'macro' });
307
+ expect(line1).toContainEqual({ text: 'error', type: 'macro' });
308
+ expect(line1).toContainEqual({ text: 'any', type: 'macro' });
309
+ // Line 2: make([]byte)
310
+ const line2 = tokens[2].map((t) => ({ text: t.text, type: t.type }));
311
+ expect(line2).toContainEqual({ text: 'make', type: 'function' });
312
+ expect(line2).toContainEqual({ text: 'byte', type: 'macro' });
313
+ // Line 3: len(buf)
314
+ const line3 = tokens[3].map((t) => ({ text: t.text, type: t.type }));
315
+ expect(line3).toContainEqual({ text: 'len', type: 'function' });
316
+ });
317
+ it('tokenizes SQL DDL, constraints, clauses, and data types to Tier 1 standard', () => {
318
+ const sqlCode = `CREATE TABLE users (
319
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
320
+ email VARCHAR(255) NOT NULL UNIQUE,
321
+ metadata JSONB,
322
+ created_at TIMESTAMPTZ DEFAULT NOW()
323
+ );
324
+ SELECT id, email FROM users WHERE id IS NOT NULL ORDER BY created_at DESC LIMIT 10;`;
325
+ const tokens = tokenizeCode(sqlCode, 'sql');
326
+ expect(tokens).toHaveLength(7);
327
+ // Line 0: CREATE TABLE users (
328
+ const line0 = tokens[0].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
329
+ expect(line0).toContainEqual({ text: 'CREATE', type: 'keyword' });
330
+ expect(line0).toContainEqual({ text: 'TABLE', type: 'keyword' });
331
+ // Line 1: id UUID PRIMARY KEY DEFAULT ...
332
+ const line1 = tokens[1].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
333
+ expect(line1).toContainEqual({ text: 'UUID', type: 'macro' });
334
+ expect(line1).toContainEqual({ text: 'PRIMARY', type: 'keyword' });
335
+ expect(line1).toContainEqual({ text: 'KEY', type: 'keyword' });
336
+ expect(line1).toContainEqual({ text: 'DEFAULT', type: 'keyword' });
337
+ // Line 2: VARCHAR
338
+ const line2 = tokens[2].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
339
+ expect(line2).toContainEqual({ text: 'VARCHAR', type: 'macro' });
340
+ expect(line2).toContainEqual({ text: 'NOT', type: 'keyword' });
341
+ expect(line2).toContainEqual({ text: 'NULL', type: 'keyword' });
342
+ expect(line2).toContainEqual({ text: 'UNIQUE', type: 'keyword' });
343
+ // Line 3: JSONB
344
+ const line3 = tokens[3].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
345
+ expect(line3).toContainEqual({ text: 'JSONB', type: 'macro' });
346
+ // Line 4: TIMESTAMPTZ
347
+ const line4 = tokens[4].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
348
+ expect(line4).toContainEqual({ text: 'TIMESTAMPTZ', type: 'macro' });
349
+ // Line 6: SELECT query
350
+ const line6 = tokens[6].map((t) => ({ text: t.text.toUpperCase(), type: t.type }));
351
+ expect(line6).toContainEqual({ text: 'SELECT', type: 'keyword' });
352
+ expect(line6).toContainEqual({ text: 'FROM', type: 'keyword' });
353
+ expect(line6).toContainEqual({ text: 'WHERE', type: 'keyword' });
354
+ expect(line6).toContainEqual({ text: 'ORDER', type: 'keyword' });
355
+ expect(line6).toContainEqual({ text: 'BY', type: 'keyword' });
356
+ expect(line6).toContainEqual({ text: 'DESC', type: 'keyword' });
357
+ expect(line6).toContainEqual({ text: 'LIMIT', type: 'keyword' });
358
+ });
359
+ it('tokenizes GraphQL queries, variables, directives, and scalar types to Tier 1 standard', () => {
360
+ const gqlCode = `query GetUser($userId: ID!, $withDetails: Boolean = true) {
361
+ user(id: $userId) {
362
+ id
363
+ name
364
+ email @include(if: $withDetails)
365
+ }
366
+ }`;
367
+ const tokens = tokenizeCode(gqlCode, 'graphql');
368
+ expect(tokens).toHaveLength(7);
369
+ // Line 0: query GetUser($userId: ID!, $withDetails: Boolean = true)
370
+ const line0 = tokens[0].map((t) => ({ text: t.text, type: t.type }));
371
+ expect(line0).toContainEqual({ text: 'query', type: 'keyword' });
372
+ expect(line0).toContainEqual({ text: '$userId', type: 'macro' });
373
+ expect(line0).toContainEqual({ text: 'ID', type: 'macro' });
374
+ expect(line0).toContainEqual({ text: '$withDetails', type: 'macro' });
375
+ expect(line0).toContainEqual({ text: 'Boolean', type: 'macro' });
376
+ // Line 4: email @include(if: $withDetails)
377
+ const line4 = tokens[4].map((t) => ({ text: t.text, type: t.type }));
378
+ expect(line4).toContainEqual({ text: '@include', type: 'decorator' });
379
+ });
153
380
  });
@@ -318,6 +318,8 @@
318
318
  >{token.text}</span
319
319
  >{:else if token.type === 'macro'}<span
320
320
  class="font-semibold text-indigo-600 dark:text-indigo-400">{token.text}</span
321
+ >{:else if token.type === 'decorator'}<span
322
+ class="text-purple-600 dark:text-purple-400">{token.text}</span
321
323
  >{:else if token.type === 'number'}<span
322
324
  class="text-purple-600 dark:text-purple-400">{token.text}</span
323
325
  >{:else if token.type === 'punctuation'}<span
@@ -378,6 +380,12 @@
378
380
  <span class="text-amber-600 dark:text-amber-300">{token.text}</span>
379
381
  {:else if token.type === 'function'}
380
382
  <span class="text-sky-600 dark:text-sky-400">{token.text}</span>
383
+ {:else if token.type === 'macro'}
384
+ <span class="font-semibold text-indigo-600 dark:text-indigo-400"
385
+ >{token.text}</span
386
+ >
387
+ {:else if token.type === 'decorator'}
388
+ <span class="text-purple-600 dark:text-purple-400">{token.text}</span>
381
389
  {:else if token.type === 'number'}
382
390
  <span class="text-purple-600 dark:text-purple-400">{token.text}</span>
383
391
  {:else if token.type === 'punctuation'}
@@ -437,6 +445,12 @@
437
445
  <span class="text-amber-600 dark:text-amber-300">{token.text}</span>
438
446
  {:else if token.type === 'function'}
439
447
  <span class="text-sky-600 dark:text-sky-400">{token.text}</span>
448
+ {:else if token.type === 'macro'}
449
+ <span class="font-semibold text-indigo-600 dark:text-indigo-400"
450
+ >{token.text}</span
451
+ >
452
+ {:else if token.type === 'decorator'}
453
+ <span class="text-purple-600 dark:text-purple-400">{token.text}</span>
440
454
  {:else if token.type === 'number'}
441
455
  <span class="text-purple-600 dark:text-purple-400">{token.text}</span>
442
456
  {:else if token.type === 'punctuation'}
@@ -49,4 +49,20 @@ describe('CodeDiff Component & Diff Algorithm', () => {
49
49
  expect(target.textContent).toContain('Greeting.svelte');
50
50
  cleanup();
51
51
  });
52
+ it('should highlight modern Python 3.13 and macro tokens in diff view', () => {
53
+ const original = `def check(val: object):\n return False`;
54
+ const modified = `@deprecated\ndef check(val: object) -> TypeIs[str]:\n return True`;
55
+ const { target, cleanup } = renderComponent(CodeDiff, {
56
+ original,
57
+ modified,
58
+ filename: 'validator.py',
59
+ language: 'python',
60
+ viewMode: 'unified'
61
+ });
62
+ expect(target.textContent).toContain('@deprecated');
63
+ expect(target.textContent).toContain('TypeIs');
64
+ expect(target.textContent).toContain('+3');
65
+ expect(target.textContent).toContain('-2');
66
+ cleanup();
67
+ });
52
68
  });
@@ -3,35 +3,15 @@ import type { Snippet } from 'svelte';
3
3
  import type { IconSource } from './Icon.svelte';
4
4
  export declare const emptyStateVariants: import("tailwind-variants").TVReturnType<{
5
5
  size: {
6
- sm: "py-6 px-4 gap-2";
7
- md: "py-10 px-6 gap-3";
8
- lg: "py-16 px-8 gap-4";
6
+ sm: string;
7
+ md: string;
8
+ lg: string;
9
9
  };
10
10
  bordered: {
11
- true: "border border-dashed border-neutral-300 dark:border-neutral-800";
12
- false: "border-0";
11
+ true: string;
12
+ false: string;
13
13
  };
14
- }, undefined, "flex flex-col items-center justify-center text-center p-8 rounded-2xl bg-white dark:bg-neutral-900/50", {
15
- size: {
16
- sm: "py-6 px-4 gap-2";
17
- md: "py-10 px-6 gap-3";
18
- lg: "py-16 px-8 gap-4";
19
- };
20
- bordered: {
21
- true: "border border-dashed border-neutral-300 dark:border-neutral-800";
22
- false: "border-0";
23
- };
24
- }, undefined, import("tailwind-variants").TVReturnTypeLike<{
25
- size: {
26
- sm: "py-6 px-4 gap-2";
27
- md: "py-10 px-6 gap-3";
28
- lg: "py-16 px-8 gap-4";
29
- };
30
- bordered: {
31
- true: "border border-dashed border-neutral-300 dark:border-neutral-800";
32
- false: "border-0";
33
- };
34
- }, undefined>>;
14
+ }, undefined, "flex flex-col items-center justify-center text-center p-8 rounded-2xl bg-white dark:bg-neutral-900/50", undefined, undefined, undefined>;
35
15
  export type EmptyStateProps = VariantProps<typeof emptyStateVariants> & {
36
16
  title?: string;
37
17
  description?: string;