@vanduo-oss/vd3-cbun 1.3.2 → 1.4.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.
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  VdCodeEditor: () => VdCodeEditor2,
26
26
  VdCodeEditorCore: () => VdCodeEditor,
27
27
  highlight: () => highlight,
28
+ renderTokensToHtml: () => renderTokensToHtml,
28
29
  tokenize: () => tokenize
29
30
  });
30
31
  module.exports = __toCommonJS(index_exports);
@@ -33,6 +34,26 @@ module.exports = __toCommonJS(index_exports);
33
34
  var import_vue = require("vue");
34
35
 
35
36
  // src/code-editor/tokenizer/scanner.js
37
+ function matchRule(source, i, rules) {
38
+ for (let r = 0; r < rules.length; r++) {
39
+ const rule = rules[r];
40
+ if (rule.when && !rule.when(source, i)) continue;
41
+ let value;
42
+ if (rule.consume) {
43
+ const got = rule.consume(source, i);
44
+ if (!got || !got.value || got.value.length === 0) continue;
45
+ value = got.value;
46
+ } else {
47
+ rule.re.lastIndex = i;
48
+ const m = rule.re.exec(source);
49
+ if (!m || m[0].length === 0) continue;
50
+ value = m[0];
51
+ }
52
+ const tokens = rule.expand ? rule.expand(value) : [{ type: rule.type, value }];
53
+ return { tokens, length: value.length, value };
54
+ }
55
+ return null;
56
+ }
36
57
  function scan(source, rules) {
37
58
  const tokens = [];
38
59
  const n = source.length;
@@ -45,26 +66,12 @@ function scan(source, rules) {
45
66
  plainStart = -1;
46
67
  };
47
68
  while (i < n) {
48
- let matched = false;
49
- for (let r = 0; r < rules.length; r++) {
50
- const rule = rules[r];
51
- rule.re.lastIndex = i;
52
- const m = rule.re.exec(source);
53
- if (m && m[0].length > 0) {
54
- flushPlain(i);
55
- const value = m[0];
56
- if (rule.expand) {
57
- const sub = rule.expand(value);
58
- for (let k = 0; k < sub.length; k++) tokens.push(sub[k]);
59
- } else {
60
- tokens.push({ type: rule.type, value });
61
- }
62
- i += value.length;
63
- matched = true;
64
- break;
65
- }
66
- }
67
- if (!matched) {
69
+ const hit = matchRule(source, i, rules);
70
+ if (hit) {
71
+ flushPlain(i);
72
+ for (let k = 0; k < hit.tokens.length; k++) tokens.push(hit.tokens[k]);
73
+ i += hit.length;
74
+ } else {
68
75
  if (plainStart === -1) plainStart = i;
69
76
  i++;
70
77
  }
@@ -196,14 +203,194 @@ var BUILTINS = [
196
203
  "NaN",
197
204
  "Infinity"
198
205
  ];
206
+ var REGEX_AFTER_KEYWORD = /* @__PURE__ */ new Set([
207
+ "return",
208
+ "throw",
209
+ "case",
210
+ "in",
211
+ "of",
212
+ "typeof",
213
+ "void",
214
+ "delete",
215
+ "new",
216
+ "else",
217
+ "do",
218
+ "yield",
219
+ "await",
220
+ "extends"
221
+ ]);
222
+ function isWs(c) {
223
+ return c === 32 || c === 9 || c === 10 || c === 13;
224
+ }
225
+ function isWord(c) {
226
+ return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 36 || c === 95;
227
+ }
228
+ function canStartRegex(source, i) {
229
+ let j = i - 1;
230
+ while (j >= 0 && isWs(source.charCodeAt(j))) j--;
231
+ if (j < 0) return true;
232
+ const c = source.charCodeAt(j);
233
+ if (c === 41 || c === 93) return false;
234
+ if ((c === 43 || c === 45) && j > 0 && source.charCodeAt(j - 1) === c) return false;
235
+ if (isWord(c)) {
236
+ let start = j;
237
+ while (start > 0 && isWord(source.charCodeAt(start - 1))) start--;
238
+ return REGEX_AFTER_KEYWORD.has(source.slice(start, j + 1));
239
+ }
240
+ return true;
241
+ }
242
+ function isRegexFlag(c) {
243
+ return c === 100 || c === 103 || c === 105 || c === 109 || c === 115 || c === 117 || c === 118 || c === 121;
244
+ }
245
+ function consumeRegex(source, i) {
246
+ const n = source.length;
247
+ let j = i + 1;
248
+ let inClass = false;
249
+ while (j < n) {
250
+ const c = source.charCodeAt(j);
251
+ if (c === 10) return null;
252
+ if (c === 92) {
253
+ j += 2;
254
+ continue;
255
+ }
256
+ if (inClass) {
257
+ if (c === 93) inClass = false;
258
+ j++;
259
+ continue;
260
+ }
261
+ if (c === 91) {
262
+ inClass = true;
263
+ j++;
264
+ continue;
265
+ }
266
+ if (c === 47) {
267
+ j++;
268
+ while (j < n && isRegexFlag(source.charCodeAt(j))) j++;
269
+ return { value: source.slice(i, j) };
270
+ }
271
+ j++;
272
+ }
273
+ return null;
274
+ }
275
+ function skipQuoted(s, i) {
276
+ const q = s.charCodeAt(i);
277
+ let j = i + 1;
278
+ const n = s.length;
279
+ while (j < n) {
280
+ const c = s.charCodeAt(j);
281
+ if (c === 92) {
282
+ j += 2;
283
+ continue;
284
+ }
285
+ if (c === q) return j + 1;
286
+ if (c === 10) return j;
287
+ j++;
288
+ }
289
+ return n;
290
+ }
291
+ function findTemplateInterpEnd(s, start) {
292
+ let depth = 1;
293
+ let i = start;
294
+ const n = s.length;
295
+ while (i < n && depth > 0) {
296
+ const c = s.charCodeAt(i);
297
+ if (c === 47 && s.charCodeAt(i + 1) === 47) {
298
+ const nl = s.indexOf("\n", i + 2);
299
+ if (nl < 0) return n;
300
+ i = nl;
301
+ continue;
302
+ }
303
+ if (c === 47 && s.charCodeAt(i + 1) === 42) {
304
+ const end = s.indexOf("*/", i + 2);
305
+ i = end < 0 ? n : end + 2;
306
+ continue;
307
+ }
308
+ if (c === 34 || c === 39) {
309
+ i = skipQuoted(s, i);
310
+ continue;
311
+ }
312
+ if (c === 96) {
313
+ i = skipTemplate(s, i);
314
+ continue;
315
+ }
316
+ if (c === 123) depth++;
317
+ else if (c === 125) {
318
+ depth--;
319
+ if (depth === 0) return i;
320
+ }
321
+ i++;
322
+ }
323
+ return n;
324
+ }
325
+ function skipTemplate(s, i) {
326
+ let j = i + 1;
327
+ const n = s.length;
328
+ while (j < n) {
329
+ const c = s.charCodeAt(j);
330
+ if (c === 92) {
331
+ j += 2;
332
+ continue;
333
+ }
334
+ if (c === 96) return j + 1;
335
+ if (c === 36 && s.charCodeAt(j + 1) === 123) {
336
+ const end = findTemplateInterpEnd(s, j + 2);
337
+ j = end < n && s.charCodeAt(end) === 125 ? end + 1 : end;
338
+ continue;
339
+ }
340
+ j++;
341
+ }
342
+ return n;
343
+ }
344
+ function expandTemplateLiteral(value, rules) {
345
+ const out = [];
346
+ const n = value.length;
347
+ let i = 1;
348
+ let strStart = 0;
349
+ const flushString = (end) => {
350
+ if (end > strStart) out.push({ type: "string", value: value.slice(strStart, end) });
351
+ };
352
+ while (i < n) {
353
+ const c = value.charCodeAt(i);
354
+ if (c === 92) {
355
+ i += i + 1 < n ? 2 : 1;
356
+ continue;
357
+ }
358
+ if (c === 96) {
359
+ flushString(i + 1);
360
+ return out;
361
+ }
362
+ if (c === 36 && i + 1 < n && value.charCodeAt(i + 1) === 123) {
363
+ flushString(i);
364
+ out.push({ type: "operator", value: "${" });
365
+ const innerStart = i + 2;
366
+ const innerEnd = findTemplateInterpEnd(value, innerStart);
367
+ const inner = value.slice(innerStart, innerEnd);
368
+ if (inner) {
369
+ const parts = scan(inner, rules);
370
+ for (let k = 0; k < parts.length; k++) out.push(parts[k]);
371
+ }
372
+ if (innerEnd < n && value.charCodeAt(innerEnd) === 125) {
373
+ out.push({ type: "punctuation", value: "}" });
374
+ i = innerEnd + 1;
375
+ } else {
376
+ i = innerEnd;
377
+ }
378
+ strStart = i;
379
+ continue;
380
+ }
381
+ i++;
382
+ }
383
+ flushString(n);
384
+ return out;
385
+ }
199
386
  function makeRules(keywords) {
200
- return [
387
+ const rules = [
201
388
  { type: "comment", re: /\/\/[^\n]*/y },
202
389
  { type: "comment", re: /\/\*[\s\S]*?(?:\*\/|$)/y },
203
390
  // unterminated -> comment to EOF
204
391
  { type: "string", re: /"(?:[^"\\\n]|\\.)*"?/y },
205
392
  { type: "string", re: /'(?:[^'\\\n]|\\.)*'?/y },
206
- { type: "string", re: /`(?:[^`\\]|\\.)*`?/y },
393
+ { expand: (value) => expandTemplateLiteral(value, rules), re: /`(?:[^`\\]|\\.)*`?/y },
207
394
  {
208
395
  type: "number",
209
396
  re: /0[xX][\da-fA-F_]+n?|0[bB][01_]+n?|0[oO][0-7_]+n?|(?:\d[\d_]*\.?[\d_]*|\.\d[\d_]*)(?:[eE][+-]?\d+)?n?/y
@@ -214,9 +401,15 @@ function makeRules(keywords) {
214
401
  { type: "builtin", re: wordRegex(BUILTINS) },
215
402
  { type: "function", re: /[A-Za-z_$][\w$]*(?=\s*\()/y },
216
403
  { type: "plain", re: /[A-Za-z_$][\w$]*/y },
404
+ {
405
+ type: "regex",
406
+ when: (source, i) => source.charCodeAt(i) === 47 && canStartRegex(source, i),
407
+ consume: consumeRegex
408
+ },
217
409
  { type: "operator", re: /\.{3}|=>|[+\-*/%=<>!&|^~?]+/y },
218
410
  { type: "punctuation", re: /[{}()[\];,.:]/y }
219
411
  ];
412
+ return rules;
220
413
  }
221
414
  var JS_RULES = makeRules(JS_KEYWORDS);
222
415
  var TS_RULES = makeRules(TS_KEYWORDS);
@@ -227,8 +420,304 @@ function tokenizeTypeScript(source) {
227
420
  return scan(source, TS_RULES);
228
421
  }
229
422
 
423
+ // src/code-editor/tokenizer/css.js
424
+ var PROPERTIES = [
425
+ "align-content",
426
+ "align-items",
427
+ "align-self",
428
+ "all",
429
+ "animation",
430
+ "animation-delay",
431
+ "animation-direction",
432
+ "animation-duration",
433
+ "animation-fill-mode",
434
+ "animation-iteration-count",
435
+ "animation-name",
436
+ "animation-play-state",
437
+ "animation-timing-function",
438
+ "appearance",
439
+ "aspect-ratio",
440
+ "backdrop-filter",
441
+ "backface-visibility",
442
+ "background",
443
+ "background-attachment",
444
+ "background-blend-mode",
445
+ "background-clip",
446
+ "background-color",
447
+ "background-image",
448
+ "background-origin",
449
+ "background-position",
450
+ "background-repeat",
451
+ "background-size",
452
+ "block-size",
453
+ "border",
454
+ "border-block",
455
+ "border-block-end",
456
+ "border-block-start",
457
+ "border-bottom",
458
+ "border-bottom-color",
459
+ "border-bottom-left-radius",
460
+ "border-bottom-right-radius",
461
+ "border-bottom-style",
462
+ "border-bottom-width",
463
+ "border-collapse",
464
+ "border-color",
465
+ "border-end-end-radius",
466
+ "border-end-start-radius",
467
+ "border-image",
468
+ "border-inline",
469
+ "border-inline-end",
470
+ "border-inline-start",
471
+ "border-left",
472
+ "border-left-color",
473
+ "border-left-style",
474
+ "border-left-width",
475
+ "border-radius",
476
+ "border-right",
477
+ "border-right-color",
478
+ "border-right-style",
479
+ "border-right-width",
480
+ "border-spacing",
481
+ "border-start-end-radius",
482
+ "border-start-start-radius",
483
+ "border-style",
484
+ "border-top",
485
+ "border-top-color",
486
+ "border-top-left-radius",
487
+ "border-top-right-radius",
488
+ "border-top-style",
489
+ "border-top-width",
490
+ "border-width",
491
+ "bottom",
492
+ "box-decoration-break",
493
+ "box-shadow",
494
+ "box-sizing",
495
+ "break-after",
496
+ "break-before",
497
+ "break-inside",
498
+ "caption-side",
499
+ "caret-color",
500
+ "clear",
501
+ "clip",
502
+ "clip-path",
503
+ "color",
504
+ "color-scheme",
505
+ "column-count",
506
+ "column-fill",
507
+ "column-gap",
508
+ "column-rule",
509
+ "column-span",
510
+ "column-width",
511
+ "columns",
512
+ "contain",
513
+ "container",
514
+ "content",
515
+ "counter-increment",
516
+ "counter-reset",
517
+ "cursor",
518
+ "direction",
519
+ "display",
520
+ "empty-cells",
521
+ "filter",
522
+ "flex",
523
+ "flex-basis",
524
+ "flex-direction",
525
+ "flex-flow",
526
+ "flex-grow",
527
+ "flex-shrink",
528
+ "flex-wrap",
529
+ "float",
530
+ "font",
531
+ "font-family",
532
+ "font-feature-settings",
533
+ "font-kerning",
534
+ "font-size",
535
+ "font-size-adjust",
536
+ "font-stretch",
537
+ "font-style",
538
+ "font-synthesis",
539
+ "font-variant",
540
+ "font-variation-settings",
541
+ "font-weight",
542
+ "gap",
543
+ "grid",
544
+ "grid-area",
545
+ "grid-auto-columns",
546
+ "grid-auto-flow",
547
+ "grid-auto-rows",
548
+ "grid-column",
549
+ "grid-column-end",
550
+ "grid-column-start",
551
+ "grid-row",
552
+ "grid-row-end",
553
+ "grid-row-start",
554
+ "grid-template",
555
+ "grid-template-areas",
556
+ "grid-template-columns",
557
+ "grid-template-rows",
558
+ "hanging-punctuation",
559
+ "height",
560
+ "hyphens",
561
+ "image-rendering",
562
+ "inline-size",
563
+ "inset",
564
+ "inset-block",
565
+ "inset-inline",
566
+ "isolation",
567
+ "justify-content",
568
+ "justify-items",
569
+ "justify-self",
570
+ "left",
571
+ "letter-spacing",
572
+ "line-break",
573
+ "line-clamp",
574
+ "line-height",
575
+ "list-style",
576
+ "list-style-image",
577
+ "list-style-position",
578
+ "list-style-type",
579
+ "margin",
580
+ "margin-block",
581
+ "margin-block-end",
582
+ "margin-block-start",
583
+ "margin-bottom",
584
+ "margin-inline",
585
+ "margin-inline-end",
586
+ "margin-inline-start",
587
+ "margin-left",
588
+ "margin-right",
589
+ "margin-top",
590
+ "mask",
591
+ "mask-image",
592
+ "max-block-size",
593
+ "max-height",
594
+ "max-inline-size",
595
+ "max-width",
596
+ "min-block-size",
597
+ "min-height",
598
+ "min-inline-size",
599
+ "min-width",
600
+ "mix-blend-mode",
601
+ "object-fit",
602
+ "object-position",
603
+ "offset",
604
+ "opacity",
605
+ "order",
606
+ "orphans",
607
+ "outline",
608
+ "outline-color",
609
+ "outline-offset",
610
+ "outline-style",
611
+ "outline-width",
612
+ "overflow",
613
+ "overflow-anchor",
614
+ "overflow-wrap",
615
+ "overflow-x",
616
+ "overflow-y",
617
+ "overscroll-behavior",
618
+ "padding",
619
+ "padding-block",
620
+ "padding-block-end",
621
+ "padding-block-start",
622
+ "padding-bottom",
623
+ "padding-inline",
624
+ "padding-inline-end",
625
+ "padding-inline-start",
626
+ "padding-left",
627
+ "padding-right",
628
+ "padding-top",
629
+ "page-break-after",
630
+ "page-break-before",
631
+ "page-break-inside",
632
+ "perspective",
633
+ "place-content",
634
+ "place-items",
635
+ "place-self",
636
+ "pointer-events",
637
+ "position",
638
+ "quotes",
639
+ "resize",
640
+ "right",
641
+ "rotate",
642
+ "row-gap",
643
+ "scale",
644
+ "scroll-behavior",
645
+ "scroll-margin",
646
+ "scroll-padding",
647
+ "scroll-snap-align",
648
+ "scroll-snap-type",
649
+ "shape-outside",
650
+ "tab-size",
651
+ "table-layout",
652
+ "text-align",
653
+ "text-align-last",
654
+ "text-decoration",
655
+ "text-decoration-color",
656
+ "text-decoration-line",
657
+ "text-decoration-style",
658
+ "text-decoration-thickness",
659
+ "text-emphasis",
660
+ "text-indent",
661
+ "text-overflow",
662
+ "text-rendering",
663
+ "text-shadow",
664
+ "text-transform",
665
+ "text-underline-offset",
666
+ "text-wrap",
667
+ "top",
668
+ "touch-action",
669
+ "transform",
670
+ "transform-origin",
671
+ "transition",
672
+ "transition-delay",
673
+ "transition-duration",
674
+ "transition-property",
675
+ "transition-timing-function",
676
+ "translate",
677
+ "unicode-bidi",
678
+ "user-select",
679
+ "vertical-align",
680
+ "visibility",
681
+ "white-space",
682
+ "widows",
683
+ "width",
684
+ "will-change",
685
+ "word-break",
686
+ "word-spacing",
687
+ "word-wrap",
688
+ "writing-mode",
689
+ "z-index"
690
+ ];
691
+ function cssPropRegex(names) {
692
+ const sorted = [...names].sort((a, b) => b.length - a.length);
693
+ return new RegExp("(?:" + sorted.join("|") + ")(?=\\s*:)", "y");
694
+ }
695
+ var RULES = [
696
+ { type: "comment", re: /\/\*[\s\S]*?(?:\*\/|$)/y },
697
+ // unterminated -> comment to EOF
698
+ { type: "string", re: /"(?:[^"\\\n]|\\.)*"?|'(?:[^'\\\n]|\\.)*'?/y },
699
+ { type: "meta", re: /@[a-zA-Z-]+/y },
700
+ { type: "keyword", re: /!important\b/y },
701
+ { type: "number", re: /#[0-9a-fA-F]{3,8}\b/y },
702
+ { type: "number", re: /-?(?:\d*\.\d+|\d+)(?:%|[a-zA-Z]{1,4})?/y },
703
+ { type: "property", re: /--[\w-]+/y },
704
+ { type: "property", re: cssPropRegex(PROPERTIES) },
705
+ { type: "attribute", re: /[.#][a-zA-Z_-][\w-]*/y },
706
+ { type: "meta", re: /::?[a-zA-Z_-][\w-]*/y },
707
+ { type: "function", re: /[-a-zA-Z][\w-]*(?=\()/y },
708
+ { type: "punctuation", re: /[{}()[\];:,]/y },
709
+ { type: "operator", re: /[>+~*]/y },
710
+ // Catch-all: consume an identifier/dash run (or whitespace) in one match so
711
+ // the greedy property/function look-ahead rules run once per run, not once
712
+ // per character (keeps scanning linear).
713
+ { type: "plain", re: /[-\w$]+|\s+/y }
714
+ ];
715
+ function tokenizeCss(source) {
716
+ return scan(source, RULES);
717
+ }
718
+
230
719
  // src/code-editor/tokenizer/html.js
231
- function expandTag(value) {
720
+ function expandTag(value, vue) {
232
721
  const out = [];
233
722
  const open = /^<\/?/.exec(value)[0];
234
723
  out.push({ type: "punctuation", value: open });
@@ -239,55 +728,186 @@ function expandTag(value) {
239
728
  rest = rest.slice(name[0].length);
240
729
  }
241
730
  if (rest) {
242
- const inner = scan(rest, [
731
+ const attrRules = vue ? [
732
+ { type: "string", re: /"[^"]*"?|'[^']*'?/y },
733
+ { type: "operator", re: /=/y },
734
+ { type: "punctuation", re: /\/?>/y },
735
+ { type: "meta", re: /(?:v-[\w:.@-]+|[@:][\w:.@-]*)/y },
736
+ { type: "attribute", re: /[a-zA-Z_][\w:.-]*/y }
737
+ ] : [
243
738
  { type: "string", re: /"[^"]*"?|'[^']*'?/y },
244
739
  { type: "operator", re: /=/y },
245
740
  { type: "punctuation", re: /\/?>/y },
246
741
  { type: "attribute", re: /[a-zA-Z_:@][\w:.-]*/y }
247
- ]);
742
+ ];
743
+ const inner = scanSlice(rest, attrRules);
248
744
  for (let i = 0; i < inner.length; i++) out.push(inner[i]);
249
745
  }
250
746
  return out;
251
747
  }
252
- var RULES = [
253
- { type: "comment", re: /<!--[\s\S]*?-->/y },
254
- { type: "meta", re: /<!\[CDATA\[[\s\S]*?\]\]>/y },
255
- { type: "meta", re: /<!DOCTYPE[^>]*>/iy },
256
- {
257
- expand: expandTag,
258
- re: /<\/?[a-zA-Z][\w:-]*(?:\s+[^\s/>"'=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s*\/?>/y
259
- },
260
- { expand: expandTag, re: /<\/?[a-zA-Z][\w:-]*/y },
261
- { type: "meta", re: /&[a-zA-Z][a-zA-Z0-9]*;|&#\d+;|&#x[0-9a-fA-F]+;/y }
262
- ];
748
+ function scanSlice(source, rules) {
749
+ const tokens = [];
750
+ const n = source.length;
751
+ let i = 0;
752
+ let plainStart = -1;
753
+ const flushPlain = (end) => {
754
+ if (plainStart !== -1 && end > plainStart) {
755
+ tokens.push({ type: "plain", value: source.slice(plainStart, end) });
756
+ }
757
+ plainStart = -1;
758
+ };
759
+ while (i < n) {
760
+ const hit = matchRule(source, i, rules);
761
+ if (hit) {
762
+ flushPlain(i);
763
+ for (let k = 0; k < hit.tokens.length; k++) tokens.push(hit.tokens[k]);
764
+ i += hit.length;
765
+ } else {
766
+ if (plainStart === -1) plainStart = i;
767
+ i++;
768
+ }
769
+ }
770
+ flushPlain(n);
771
+ return tokens;
772
+ }
773
+ function ieqChar(a, b) {
774
+ if (a === b) return true;
775
+ if (a >= 65 && a <= 90) return a + 32 === b;
776
+ if (b >= 65 && b <= 90) return b + 32 === a;
777
+ return false;
778
+ }
779
+ function findCloseTag(source, start, tagName) {
780
+ const n = source.length;
781
+ const tlen = tagName.length;
782
+ for (let i = start; i < n; i++) {
783
+ if (source.charCodeAt(i) !== 60) continue;
784
+ if (source.charCodeAt(i + 1) !== 47) continue;
785
+ let ok = true;
786
+ for (let k = 0; k < tlen; k++) {
787
+ if (!ieqChar(source.charCodeAt(i + 2 + k), tagName.charCodeAt(k))) {
788
+ ok = false;
789
+ break;
790
+ }
791
+ }
792
+ if (!ok) continue;
793
+ let j = i + 2 + tlen;
794
+ while (j < n) {
795
+ const c = source.charCodeAt(j);
796
+ if (c === 32 || c === 9 || c === 10 || c === 13) j++;
797
+ else break;
798
+ }
799
+ if (j < n && source.charCodeAt(j) === 62) return { start: i, end: j + 1 };
800
+ }
801
+ return null;
802
+ }
803
+ function embedInfo(tagValue) {
804
+ const open = /^<(script|style)\b/i.exec(tagValue);
805
+ if (!open) return null;
806
+ if (!tagValue.endsWith(">") || tagValue.endsWith("/>")) return null;
807
+ const tag = open[1].toLowerCase();
808
+ if (tag === "style") return { tag: "style", lang: "css" };
809
+ const lang = /\blang\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tagValue);
810
+ const id = (lang && (lang[1] || lang[2] || lang[3]) || "").toLowerCase();
811
+ if (id === "ts" || id === "tsx" || id === "typescript")
812
+ return { tag: "script", lang: "typescript" };
813
+ return { tag: "script", lang: "javascript" };
814
+ }
815
+ function tokenizeEmbed(source, lang) {
816
+ if (lang === "typescript") return tokenizeTypeScript(source);
817
+ if (lang === "css") return tokenizeCss(source);
818
+ return tokenizeJavaScript(source);
819
+ }
820
+ function expandMustache(value) {
821
+ const out = [{ type: "meta", value: "{{" }];
822
+ let inner = value.slice(2);
823
+ let close = "";
824
+ if (value.length >= 4 && inner.endsWith("}}")) {
825
+ close = "}}";
826
+ inner = inner.slice(0, -2);
827
+ }
828
+ if (inner) {
829
+ const parts = tokenizeJavaScript(inner);
830
+ for (let i = 0; i < parts.length; i++) out.push(parts[i]);
831
+ }
832
+ if (close) out.push({ type: "meta", value: close });
833
+ return out;
834
+ }
835
+ function makeMarkupRules(vue) {
836
+ const expand = (value) => expandTag(value, vue);
837
+ const rules = [
838
+ { type: "comment", re: /<!--[\s\S]*?-->/y },
839
+ { type: "meta", re: /<!\[CDATA\[[\s\S]*?\]\]>/y },
840
+ { type: "meta", re: /<!DOCTYPE[^>]*>/iy },
841
+ {
842
+ expand,
843
+ re: /<\/?[a-zA-Z][\w:-]*(?:\s+[^\s/>"'=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*\s*\/?>/y
844
+ },
845
+ { expand, re: /<\/?[a-zA-Z][\w:-]*/y },
846
+ { type: "meta", re: /&[a-zA-Z][a-zA-Z0-9]*;|&#\d+;|&#x[0-9a-fA-F]+;/y }
847
+ ];
848
+ if (vue) {
849
+ rules.splice(1, 0, { expand: expandMustache, re: /\{\{[\s\S]*?(?:\}\}|$)/y });
850
+ }
851
+ return rules;
852
+ }
853
+ var HTML_RULES = makeMarkupRules(false);
854
+ var VUE_RULES = makeMarkupRules(true);
855
+ function tokenizeMarkup(source, options) {
856
+ const vue = !!(options && options.vue);
857
+ const rules = vue ? VUE_RULES : HTML_RULES;
858
+ const tokens = [];
859
+ const n = source.length;
860
+ let i = 0;
861
+ let plainStart = -1;
862
+ const flushPlain = (end) => {
863
+ if (plainStart !== -1 && end > plainStart) {
864
+ tokens.push({ type: "plain", value: source.slice(plainStart, end) });
865
+ }
866
+ plainStart = -1;
867
+ };
868
+ while (i < n) {
869
+ const hit = matchRule(source, i, rules);
870
+ if (hit) {
871
+ flushPlain(i);
872
+ const embed = embedInfo(hit.value);
873
+ if (embed) {
874
+ for (let k = 0; k < hit.tokens.length; k++) tokens.push(hit.tokens[k]);
875
+ i += hit.length;
876
+ const close = findCloseTag(source, i, embed.tag);
877
+ const bodyEnd = close ? close.start : n;
878
+ const body = source.slice(i, bodyEnd);
879
+ if (body) {
880
+ const inner = tokenizeEmbed(body, embed.lang);
881
+ for (let k = 0; k < inner.length; k++) tokens.push(inner[k]);
882
+ }
883
+ if (close) {
884
+ const closeTokens = expandTag(source.slice(close.start, close.end), vue);
885
+ for (let k = 0; k < closeTokens.length; k++) tokens.push(closeTokens[k]);
886
+ i = close.end;
887
+ } else {
888
+ i = n;
889
+ }
890
+ continue;
891
+ }
892
+ for (let k = 0; k < hit.tokens.length; k++) tokens.push(hit.tokens[k]);
893
+ i += hit.length;
894
+ } else {
895
+ if (plainStart === -1) plainStart = i;
896
+ i++;
897
+ }
898
+ }
899
+ flushPlain(n);
900
+ return coalesce(tokens);
901
+ }
263
902
  function tokenizeHtml(source) {
264
- return scan(source, RULES);
903
+ return tokenizeMarkup(source, { vue: false });
265
904
  }
266
-
267
- // src/code-editor/tokenizer/css.js
268
- var RULES2 = [
269
- { type: "comment", re: /\/\*[\s\S]*?(?:\*\/|$)/y },
270
- // unterminated -> comment to EOF
271
- { type: "string", re: /"(?:[^"\\\n]|\\.)*"?|'(?:[^'\\\n]|\\.)*'?/y },
272
- { type: "meta", re: /@[a-zA-Z-]+/y },
273
- { type: "keyword", re: /!important\b/y },
274
- { type: "number", re: /#[0-9a-fA-F]{3,8}\b/y },
275
- { type: "number", re: /-?(?:\d*\.\d+|\d+)(?:%|[a-zA-Z]{1,4})?/y },
276
- { type: "property", re: /[-a-zA-Z]+(?=\s*:)/y },
277
- { type: "function", re: /[-a-zA-Z][\w-]*(?=\()/y },
278
- { type: "punctuation", re: /[{}()[\];:,]/y },
279
- { type: "operator", re: /[>+~*]/y },
280
- // Catch-all: consume an identifier/dash run (or whitespace) in one match so
281
- // the greedy property/function look-ahead rules run once per run, not once
282
- // per character (keeps scanning linear).
283
- { type: "plain", re: /[-\w$]+|\s+/y }
284
- ];
285
- function tokenizeCss(source) {
286
- return scan(source, RULES2);
905
+ function tokenizeVue(source) {
906
+ return tokenizeMarkup(source, { vue: true });
287
907
  }
288
908
 
289
909
  // src/code-editor/tokenizer/json.js
290
- var RULES3 = [
910
+ var RULES2 = [
291
911
  { type: "property", re: /"(?:[^"\\]|\\.)*"(?=\s*:)/y },
292
912
  { type: "string", re: /"(?:[^"\\]|\\.)*"?/y },
293
913
  { type: "number", re: /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/y },
@@ -296,11 +916,11 @@ var RULES3 = [
296
916
  { type: "punctuation", re: /[{}[\]:,]/y }
297
917
  ];
298
918
  function tokenizeJson(source) {
299
- return scan(source, RULES3);
919
+ return scan(source, RULES2);
300
920
  }
301
921
 
302
922
  // src/code-editor/tokenizer/markdown.js
303
- var RULES4 = [
923
+ var RULES3 = [
304
924
  { type: "string", re: /```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]*`/y },
305
925
  { type: "keyword", re: /^ {0,3}#{1,6} [^\n]*/my },
306
926
  { type: "comment", re: /^ {0,3}>[^\n]*/my },
@@ -311,7 +931,7 @@ var RULES4 = [
311
931
  { type: "meta", re: /\*[^*\n]+?\*|_[^_\n]+?_/y }
312
932
  ];
313
933
  function tokenizeMarkdown(source) {
314
- return scan(source, RULES4);
934
+ return scan(source, RULES3);
315
935
  }
316
936
 
317
937
  // src/code-editor/tokenizer/shell.js
@@ -393,7 +1013,7 @@ var BUILTINS2 = [
393
1013
  "tar",
394
1014
  "ssh"
395
1015
  ];
396
- var RULES5 = [
1016
+ var RULES4 = [
397
1017
  { type: "comment", re: /#[^\n]*/y },
398
1018
  { type: "string", re: /"(?:[^"\\]|\\.)*"?/y },
399
1019
  { type: "string", re: /'[^']*'?/y },
@@ -406,7 +1026,7 @@ var RULES5 = [
406
1026
  { type: "punctuation", re: /[(){}[\]]/y }
407
1027
  ];
408
1028
  function tokenizeShell(source) {
409
- return scan(source, RULES5);
1029
+ return scan(source, RULES4);
410
1030
  }
411
1031
 
412
1032
  // src/code-editor/tokenizer/python.js
@@ -489,7 +1109,7 @@ var BUILTINS3 = [
489
1109
  "AttributeError",
490
1110
  "RuntimeError"
491
1111
  ];
492
- var RULES6 = [
1112
+ var RULES5 = [
493
1113
  { type: "comment", re: /#[^\n]*/y },
494
1114
  {
495
1115
  type: "string",
@@ -512,7 +1132,7 @@ var RULES6 = [
512
1132
  { type: "plain", re: /\w+|\s+/y }
513
1133
  ];
514
1134
  function tokenizePython(source) {
515
- return scan(source, RULES6);
1135
+ return scan(source, RULES5);
516
1136
  }
517
1137
 
518
1138
  // src/code-editor/tokenizer/index.js
@@ -520,6 +1140,7 @@ var TOKENIZERS = {
520
1140
  javascript: tokenizeJavaScript,
521
1141
  typescript: tokenizeTypeScript,
522
1142
  html: tokenizeHtml,
1143
+ vue: tokenizeVue,
523
1144
  css: tokenizeCss,
524
1145
  json: tokenizeJson,
525
1146
  markdown: tokenizeMarkdown,
@@ -531,6 +1152,7 @@ var LANGUAGES = Object.freeze([
531
1152
  "javascript",
532
1153
  "typescript",
533
1154
  "html",
1155
+ "vue",
534
1156
  "css",
535
1157
  "json",
536
1158
  "markdown",
@@ -546,7 +1168,6 @@ var ALIASES = Object.freeze({
546
1168
  tsx: "typescript",
547
1169
  htm: "html",
548
1170
  xml: "html",
549
- vue: "html",
550
1171
  svg: "html",
551
1172
  sh: "shell",
552
1173
  bash: "shell",
@@ -600,9 +1221,12 @@ function renderTokensToHtml(tokens) {
600
1221
  }
601
1222
  return html;
602
1223
  }
603
- function highlight(source, language) {
1224
+ function highlight(source, language, options) {
604
1225
  const html = renderTokensToHtml(tokenize(source, language));
605
- return source.endsWith("\n") || source === "" ? html + "\n" : html;
1226
+ if (options && options.trailingNewline && (source.endsWith("\n") || source === "")) {
1227
+ return html + "\n";
1228
+ }
1229
+ return html;
606
1230
  }
607
1231
  function renderTokensToDom(tokens, doc) {
608
1232
  const frag = doc.createDocumentFragment();
@@ -756,7 +1380,7 @@ function handleBackspacePair(value, start, end) {
756
1380
  }
757
1381
 
758
1382
  // src/code-editor/core.js
759
- var VD_CODE_EDITOR_VERSION = "1.0.1";
1383
+ var VD_CODE_EDITOR_VERSION = "1.1.0";
760
1384
  var DEFAULTS = {
761
1385
  value: "",
762
1386
  language: "plaintext",