diff --git a/KNOWN-GAPS.md b/KNOWN-GAPS.md
index 4860456..611bfd0 100644
--- a/KNOWN-GAPS.md
+++ b/KNOWN-GAPS.md
@@ -14,7 +14,7 @@ commits) so the ledger is deterministic and commit-trackable.
Regenerate: `node test/gap-ledger.ts --write` · verify up-to-date: `node test/gap-ledger.ts --check`.
-**0 gaps** across 7 grammars · 0 dropped.
+**0 gaps** across 6 grammars · 0 dropped.
_No gaps currently surface._ The generative check reports no valid-input flat-highlighter
divergence on the derived corpus. (This is the ledger MECHANISM; it lists what the check finds.)
diff --git a/README.md b/README.md
index cddff8c..658cbae 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,15 @@ Write a language's grammar **once**, as an executable definition. Monogram runs
- **TypeScript** ([`typescript.ts`](typescript.ts)) — mature: 100% valid-code coverage, 97.8% bidirectional vs `tsc`.
- **JavaScript** ([`javascript.ts`](javascript.ts)) — the standalone ECMAScript base TypeScript [builds on](#adding-a-language) (subset → superset); parses real-world JS, with less conformance-corpus depth than TS so far.
- **HTML** ([`html.ts`](html.ts)) — the engine reaching *past token streams into markup*; ~95 lines, validated against [`parse5`](https://github.com/inikulin/parse5).
-- **Vue** ([`vue.ts`](vue.ts)) — a dialect of `html.ts`: SFC blocks that embed Monogram's own TS/JS/CSS, plus directives and `{{ }}` interpolation.
+- **YAML** ([`yaml.ts`](yaml.ts)) — indentation-sensitive markup on the shared engine; validated against the maintained [RedCMD/YAML-Syntax-Highlighter](https://github.com/RedCMD/YAML-Syntax-Highlighter).
+
+## Used by
+
+Projects shipping Monogram-derived grammars:
+
+- [**vuejs/language-tools**](https://github.com/vuejs/language-tools) — the Vue TextMate grammars + VS Code language configuration ([vuejs/language-tools#6085](https://github.com/vuejs/language-tools/pull/6085)).
+
+Using Monogram in your project? Open a PR to add it here.
## Quick start
@@ -77,7 +85,6 @@ This matters because `tsc`'s *parser* is not the same thing as the language. It
| TSX | 96.7% · 65.7% | 95.6% vs 95.4% |
| HTML | 95.3% · 49.3% | 100.0% vs 98.8% |
| YAML | 100.0% · 73.9% | 100.0% vs 99.5% |
-| Vue | — | 98.0% vs 98.0% |
Measured against the *maintained* official grammar where it matters, not a dead bundle: JS/TS use Microsoft's maintained [TypeScript-TmLanguage](https://github.com/microsoft/TypeScript-TmLanguage); YAML uses the maintained [RedCMD/YAML-Syntax-Highlighter](https://github.com/RedCMD/YAML-Syntax-Highlighter) that VS Code switched to ([microsoft/vscode#232244](https://github.com/microsoft/vscode/pull/232244)); only HTML's baseline is the unmaintained [textmate/html.tmbundle](https://github.com/textmate/html.tmbundle) — the #203212 case Monogram targets.
@@ -88,7 +95,7 @@ Take the bugs reported against each *hand-written* official grammar and ask whet
-_Each hand-written **official** grammar vs Monogram's **derived** one, on the bugs filed against it: **TypeScript 26/26** (official 8/26) · **TSX 11/11** (official 5/11) · **HTML 20/20** (official 13/20) · **Vue 23/23** (official 18/23) · **YAML 8/8** (official 8/8). Per-issue detail below — auto-generated by `npm run bench:issues`._
+_Each hand-written **official** grammar vs Monogram's **derived** one, on the bugs filed against it: **TypeScript 26/26** (official 8/26) · **TSX 11/11** (official 5/11) · **HTML 20/20** (official 13/20) · **YAML 8/8** (official 8/8). Per-issue detail below — auto-generated by `npm run bench:issues`._
#### TypeScript
| issue | Monogram | official |
@@ -180,40 +187,6 @@ _Each hand-written **official** grammar vs Monogram's **derived** one, on the bu
-#### Vue
-| issue | Monogram | official |
-|---|:--:|:--:|
-| [#6007](https://github.com/vuejs/language-tools/issues/6007)/[#2096](https://github.com/vuejs/language-tools/issues/2096)/[#520](https://github.com/vuejs/language-tools/issues/520) — `as` type assertion in directive value | ✓ | · |
-| [#2060](https://github.com/vuejs/language-tools/issues/2060)-inline — `` const a = 1; `` (content on the close line) embeds + clean close | ✓ | · |
-| [#2060](https://github.com/vuejs/language-tools/issues/2060)-inline-adjacent — an unterminated union before a same-line `` ``, then a second ` `` | ✓ | ✓ |
-| [#3999](https://github.com/vuejs/language-tools/issues/3999) — a force-wrapped multi-line ``,
- ``,
- `\n {{ msg }}
\n `,
- `\n x
\n `,
- `\n x \n `,
- `\n \n `,
- `\n\n {{ n + 1 }}
\n `,
- `ok `,
- `\n `,
- `\n {{ greet(x) }} \n `,
- `\n {{ item.name }} \n `,
- ``,
- `\n\n {{ label }} \n `,
-];
-
-const corpus = [
- ...CORE.map((text, i) => ({ name: `core#${i}`, text })),
- ...vueIssueCases.map((c) => ({ name: `issue:${c.id}`, text: c.src })),
-];
-
-// ── tokenize via the faithful (injection-aware) harness; grade via the FROZEN table ──────────
-// Return the FULL scope CHAIN (not just the innermost) so grading is STACK-AWARE, identical to
-// scope-gap.ts's run(): a role correctly nested as an ancestor of a refinement is credited.
-type ScopeAt = (offset: number) => string[];
-async function lookupFor(which: 'mono' | 'off', src: string): Promise {
- const at = await scopeLookup(which, src); // offset → scopes[] (deepest last)
- return (offset: number) => at(offset);
-}
-
-const tally = { oCorrect: 0, oExact: 0, mCorrect: 0, mExact: 0, total: 0 };
-const perRole = new Map();
-const onlyMono: { text: string; role: RoleName; o: string; m: string }[] = [];
-const onlyOff: { text: string; role: RoleName; o: string; m: string }[] = [];
-const snip = { o: 0, m: 0, n: 0 };
-let nFiles = 0;
-
-for (const { text } of corpus) {
- let gold: GoldToken[], oAt: ScopeAt, mAt: ScopeAt;
- try {
- gold = vueOracle(text);
- oAt = await lookupFor('off', text);
- mAt = await lookupFor('mono', text);
- } catch { continue; }
- nFiles++;
- let okO = true, okM = true, gradedHere = 0;
- for (const t of gold) {
- const tier = ROLE_SPEC[t.role]?.tier;
- if (!tier || tier === 'lexical') continue; // lexical floor: excluded from the headline
- const so = oAt(t.start), sm = mAt(t.start); // full scope CHAINS
- const vo = gradeScopeStack(t.role, so), vm = gradeScopeStack(t.role, sm);
- const oc = isCorrect(vo), mc = isCorrect(vm);
- tally.total++; gradedHere++;
- if (oc) tally.oCorrect++; if (vo === 'exact') tally.oExact++;
- if (mc) tally.mCorrect++; if (vm === 'exact') tally.mExact++;
- const pr = perRole.get(t.role) ?? { n: 0, oC: 0, mC: 0 }; pr.n++; if (oc) pr.oC++; if (mc) pr.mC++; perRole.set(t.role, pr);
- if (!oc) okO = false; if (!mc) okM = false;
- const inner = (s: string[]) => s.length ? s[s.length - 1] : '(none)';
- if (mc && !oc && onlyMono.length < 40) onlyMono.push({ text: t.text, role: t.role, o: inner(so), m: inner(sm) });
- if (oc && !mc && onlyOff.length < 40) onlyOff.push({ text: t.text, role: t.role, o: inner(so), m: inner(sm) });
- }
- if (gradedHere) { snip.n++; if (okO) snip.o++; if (okM) snip.m++; }
-}
-
-const pct = (n: number, d = tally.total) => (d ? (100 * n / d).toFixed(1) : 'n/a');
-const gap = tally.total ? (100 * (tally.mCorrect - tally.oCorrect) / tally.total).toFixed(1) : 'n/a';
-console.log('='.repeat(78));
-console.log(' Scope-gap vs the PARSER oracle — Vue (vscode#203212)');
-console.log(' official: test/fixtures/vue-official/vue.tmLanguage.json monogram: vue.tmLanguage.json');
-console.log(' oracle: @vue/compiler-sfc split + parse5 (template) + tsc (script/expr)');
-console.log(' tokenized via vscode-tmlanguage-snapshot (injection-aware, vuejs/language-tools\' own tool)');
-console.log('='.repeat(78));
-console.log(` ${nFiles} files · ${tally.total} graded tokens (lexical-floor roles + directive names excluded)`);
-console.log(` OFFICIAL correct ${pct(tally.oCorrect)}% (exact ${pct(tally.oExact)}%)`);
-console.log(` MONOGRAM correct ${pct(tally.mCorrect)}% (exact ${pct(tally.mExact)}%)`);
-console.log(` ══ GAP (Monogram − official) = ${gap} pts ══`);
-console.log(` per-snippet all-tokens-correct: official ${pct(snip.o, snip.n)}% monogram ${pct(snip.m, snip.n)}% (n=${snip.n})`);
-
-const rows = [...perRole.entries()]
- .map(([role, r]) => ({ role, n: r.n, o: r.oC, m: r.mC, d: r.mC - r.oC }))
- .sort((a, b) => Math.abs(b.d) - Math.abs(a.d) || b.n - a.n);
-console.log(`\n per-role correctness (official→monogram correct / occurrences):`);
-for (const r of rows) console.log(` ${r.role.padEnd(16)} ${String(r.o).padStart(5)} →${String(r.m).padStart(5)} / ${r.n} ${r.d > 0 ? '+' : ''}${r.d || ''}`);
-
-if (onlyMono.length) {
- console.log(`\n only-Monogram-correct tokens (official wrong vs the parser) — ${onlyMono.length} shown:`);
- for (const x of onlyMono.slice(0, 12)) console.log(` «${x.text.slice(0, 18)}» ${x.role}: official «${x.o}» → monogram «${x.m}»`);
-}
-if (onlyOff.length) {
- console.log(`\n only-official-correct tokens (Monogram wrong) — ${onlyOff.length} shown:`);
- for (const x of onlyOff.slice(0, 12)) console.log(` «${x.text.slice(0, 18)}» ${x.role}: official «${x.o}» → monogram «${x.m}»`);
-}
-// Machine-readable summary (same shape as scope-gap.ts's ##SCOPEGAP## line) for any table generator.
-console.log('##SCOPEGAP## ' + JSON.stringify({
- name: 'Vue', official: 'vue.tmLanguage.json', tokens: tally.total,
- officialPct: tally.total ? (100 * tally.oCorrect) / tally.total : null,
- monogramPct: tally.total ? (100 * tally.mCorrect) / tally.total : null,
-}));
-console.log('\nDone.');
diff --git a/test/scope-roles.ts b/test/scope-roles.ts
index 3f0752f..882ecb6 100644
--- a/test/scope-roles.ts
+++ b/test/scope-roles.ts
@@ -507,8 +507,6 @@ if (import.meta.url === `file://${process.argv[1]}`) {
[R.litString, ['source.yaml', 'keyword.control.flow.block-scalar.yaml'], 'exact', 'block-scalar indicator as scalar literal'],
// HTML tag name correctly nested under an invalid.illegal overlay region.
[R.tagName, ['text.html', 'meta.tag.metadata.svg', 'entity.name.tag.svg', 'invalid.illegal.unrecognized-tag.html'], 'exact', 'svg tag name with an illegal overlay innermost'],
- // a Vue cast leak: the value `msg` correctly painted, deeper scope is just a meta wrapper.
- [R.valueRef, ['text.html.vue', 'source.ts', 'meta.cast.expr.ts', 'variable.other.readwrite.ts'], 'family', 'value under a cast meta wrapper'],
// THE GUARD: a value mis-painted as a generic — innermost is the type-name scope and the
// only matching ancestors are COARSE region markers (meta.type.parameters, source). Nothing
// role-bearing rescues it → still WRONG. (This is exactly #978/#859.)
diff --git a/test/vue-bench.ts b/test/vue-bench.ts
deleted file mode 100644
index b6b642a..0000000
--- a/test/vue-bench.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-bench.ts — Monogram's DERIVED Vue grammar vs the hand-written official one
-// (vuejs/language-tools: vue.tmLanguage.json + vue-directives.json + vue-interpolations.json),
-// graded by a NEUTRAL oracle (@vue/compiler-sfc for block structure + boundaries,
-// @vue/compiler-dom for directives + interpolations) — the same shape as the scope-gap benches
-// (both engines vs tsc) and html-bench (both vs parse5).
-//
-// Both grammars are tokenized through `vscode-tmlanguage-snapshot` — vuejs/language-tools'
-// OWN grammar-test tool (see test/vue-grammar-harness.ts) — which resolves grammars +
-// injections from a package.json `contributes`/`injectTo` descriptor exactly as VS Code
-// does, so the head-to-head is faithful to how the official grammar is actually tested.
-//
-// Fairness: BOTH grammars embed Monogram's OWN source.ts / source.js / text.html.basic, so
-// the script/template body tokenizes identically and only the VUE LAYER (block regions,
-// embed boundaries, directives, interpolation) differs.
-//
-// This is NOT a coverage race — Monogram's Vue is a focused core; the official covers far
-// more breadth (every lang=, modifiers, slots). The corpus is the SHARED CORE both target,
-// and we grade per-construct correctness on it. Official grammars are dev-only fixtures
-// (your own MIT work) under test/fixtures/vue-official; the bench skips if absent.
-//
-// Run: node test/vue-bench.ts
-// ─────────────────────────────────────────────────────────────────────────────
-import sfc from '@vue/compiler-sfc';
-import * as dom from '@vue/compiler-dom';
-import { scopeLookup, officialAvailable } from './vue-grammar-harness.ts';
-
-if (!officialAvailable) {
- console.log('⊘ Skipped: official Vue grammars not found under test/fixtures/vue-official.');
- console.log(' Fetch with: base=https://raw.githubusercontent.com/vuejs/language-tools/master/extensions/vscode/syntaxes');
- console.log(' curl -fsSL "$base/{vue.tmLanguage.json,vue-directives.json,vue-interpolations.json}" -O (into that dir)');
- process.exit(0);
-}
-
-const familyOf = (sc: string[]): string => {
- const s = sc.join(' ');
- if (s.includes('source.ts')) return 'ts';
- if (s.includes('source.js')) return 'js';
- if (s.includes('source.css')) return 'css';
- if (s.includes('text.html')) return 'html';
- return 'other';
-};
-
-// ── oracle facts (neutral: @vue) ──
-interface Fact { cat: string; offset: number; test: (sc: string[]) => boolean; label: string }
-function oracleFacts(src: string): Fact[] {
- const facts: Fact[] = [];
- const { descriptor } = sfc.parse(src);
- const scriptFam = (lang?: string) => (lang === 'ts' || lang === 'tsx' ? 'ts' : 'js');
- const addBlock = (block: any, fam: string, label: string) => {
- if (!block || block.loc.end.offset <= block.loc.start.offset) return;
- // Sample the FIRST non-whitespace char of the body — representative of the embed, and it
- // never lands on a nested interpolation/directive (which a midpoint could, giving 'ts').
- let off = block.loc.start.offset;
- while (off < block.loc.end.offset && /\s/.test(src[off])) off++;
- facts.push({ cat: 'block-embed', offset: off, test: sc => familyOf(sc) === fam, label });
- };
- addBlock(descriptor.template, 'html', 'template');
- addBlock(descriptor.script, scriptFam(descriptor.script?.lang), 'script' + (descriptor.script?.lang ? '/' + descriptor.script.lang : ''));
- addBlock(descriptor.scriptSetup, scriptFam(descriptor.scriptSetup?.lang), 'script-setup' + (descriptor.scriptSetup?.lang ? '/' + descriptor.scriptSetup.lang : ''));
- for (const st of descriptor.styles) addBlock(st, 'css', 'style' + (st.lang ? '/' + st.lang : ''));
- // embed boundary: a script/style CLOSE tag must NOT be inside its embed (the #1666 class)
- for (const m of src.matchAll(/<\/(script|style)\s*>/g)) {
- const nameOff = m.index! + 2; // first char of the close-tag name
- facts.push({ cat: 'embed-boundary', offset: nameOff, test: sc => { const f = familyOf(sc); return m[1] === 'style' ? f !== 'css' : (f !== 'ts' && f !== 'js'); }, label: `${m[1]}>` });
- }
- // directives + interpolations (neutral: @vue/compiler-dom over the template content)
- if (descriptor.template) {
- const base = descriptor.template.loc.start.offset;
- const mid = (l: any) => base + Math.floor((l.start.offset + l.end.offset) / 2);
- try {
- const walk = (n: any) => {
- if (n.type === 1) for (const p of n.props ?? []) {
- if (p.type === 7) {
- facts.push({ cat: 'directive-name', offset: base + p.loc.start.offset, label: 'v-' + p.name, test: sc => { const s = sc.join(' '); return s.includes('attribute-name') || s.includes('keyword') || s.includes('.vue'); } });
- if (p.exp?.loc) facts.push({ cat: 'directive-value', offset: mid(p.exp.loc), label: p.name + '=', test: sc => { const f = familyOf(sc); return f === 'ts' || f === 'js'; } });
- }
- }
- if (n.type === 5 && n.content?.loc) facts.push({ cat: 'interpolation', offset: mid(n.content.loc), label: 'interp', test: sc => { const f = familyOf(sc); return f === 'ts' || f === 'js'; } });
- for (const c of n.children ?? []) walk(c);
- };
- walk(dom.parse(descriptor.template.content));
- } catch { /* invalid template expression (e.g. the over-permissive showcase) — skipped */ }
- }
- return facts;
-}
-
-// ── corpus: the SHARED CORE both grammars target ──
-const corpus: string[] = [
- ``,
- ``,
- ``,
- ``,
- `\n {{ msg }}
\n `,
- `\n x
\n `,
- `\n x \n `,
- `\n \n `,
- `\n\n {{ n + 1 }}
\n `,
- `ok `,
- `\n `,
- `\n {{ greet(x) }} \n `,
- // harder cases — probe where a DERIVED grammar might fall short of the hand-written one
- `\n x \n `, // event modifiers
- `\n {{ item.name }} \n `, // destructure + member
- `\n {{ row.label }} \n `, // scoped slot
- `\n {{\n a + b\n }}
\n `, // multi-line interpolation
- ``, // generic call in script
-];
-
-// ── grade ──
-const cats = ['block-embed', 'embed-boundary', 'interpolation', 'directive-name', 'directive-value'];
-const tally: Record = {};
-for (const c of cats) tally[c] = { mono: 0, off: 0, n: 0 };
-const wins: string[] = [];
-for (const src of corpus) {
- const facts = oracleFacts(src);
- const mAt = await scopeLookup('mono', src), oAt = await scopeLookup('off', src);
- for (const f of facts) {
- const t = tally[f.cat]; if (!t) continue;
- const m = f.test(mAt(f.offset)), o = f.test(oAt(f.offset));
- t.n++; if (m) t.mono++; if (o) t.off++;
- if (m !== o) wins.push(` ${f.cat} ${f.label}: ${m ? 'Monogram ✓ / official ✗' : 'official ✓ / Monogram ✗'}`);
- }
-}
-
-// ── special showcases (Monogram's derived fixes) ──
-const overPermSrc = `\n {{ const z = 1 }}
\n `;
-const mConst = (await scopeLookup('mono', overPermSrc))(overPermSrc.indexOf('const') + 2).join(' ');
-const oConst = (await scopeLookup('off', overPermSrc))(overPermSrc.indexOf('const') + 2).join(' ');
-
-console.log('\n══════════════════════════════════════════════════════════════════════');
-console.log(' Monogram (derived) vs official vue.tmLanguage.json (hand-written)');
-console.log(' Graded by @vue/compiler-sfc + @vue/compiler-dom (neutral oracle).');
-console.log(' Tokenized via vscode-tmlanguage-snapshot (vuejs/language-tools\' own tool).');
-console.log('══════════════════════════════════════════════════════════════════════');
-console.log(' category Monogram official');
-let mAll = 0, oAll = 0, nAll = 0;
-for (const c of cats) {
- const t = tally[c]; if (!t.n) continue;
- mAll += t.mono; oAll += t.off; nAll += t.n;
- console.log(` ${c.padEnd(18)} ${(`${t.mono}/${t.n}`).padEnd(13)} ${t.off}/${t.n}`);
-}
-console.log(' ' + '─'.repeat(50));
-console.log(` ${'OVERALL'.padEnd(18)} ${(`${mAll}/${nAll} (${(100 * mAll / nAll).toFixed(1)}%)`).padEnd(13)} ${oAll}/${nAll} (${(100 * oAll / nAll).toFixed(1)}%)`);
-if (wins.length) { console.log('\n per-fact disagreements:'); for (const w of wins) console.log(w); }
-
-// How close are the two grammars OVERALL (beyond the oracle points)? Char-level family agreement.
-let same = 0, total = 0; const div: Record = {}; const divEx: Record = {};
-for (const src of corpus) {
- const mAt = await scopeLookup('mono', src), oAt = await scopeLookup('off', src);
- for (let i = 0; i < src.length; i++) {
- if (/\s/.test(src[i])) continue;
- const mf = familyOf(mAt(i)), of = familyOf(oAt(i));
- total++;
- if (mf === of) { same++; continue; }
- const k = `${mf}≠${of}`; div[k] = (div[k] ?? 0) + 1;
- (divEx[k] ??= []); if (divEx[k].length < 3) divEx[k].push(JSON.stringify(src.slice(Math.max(0, i - 5), i + 6)));
- }
-}
-console.log(`\n char-level family agreement (whole corpus): ${(100 * same / total).toFixed(1)}% (${same}/${total})`);
-for (const [k, v] of Object.entries(div).sort((a, b) => b[1] - a[1]).slice(0, 5))
- console.log(` divergence ${k} ×${v} — e.g. ${divEx[k].join(' ')}`);
-
-console.log('\n ── shared MECHANISMS (Monogram derives what the official hand-wrote) ──');
-console.log(` begin/while embed boundary (#1666): both use it — Monogram derives it, official hand-wrote it.`);
-console.log(` source.ts#expression interpolation embed: both use it — \`{{ const z = 1 }}\` →`);
-console.log(` Monogram: const ${mConst.includes('storage.type') ? 'is storage.type' : 'NOT a keyword ✓'}; official: const ${oConst.includes('storage.type') ? 'is storage.type' : 'NOT a keyword ✓'}`);
-console.log(` (the official's #vue-interpolations ALSO embeds source.ts#expression — Monogram DERIVES the same.)`);
-
-console.log('\n Honest reading:');
-console.log(' • This is the SHARED CORE. The official covers far more breadth (every lang= dialect,');
-console.log(' directive modifiers, pug/markdown, slot scoping) — not a coverage race.');
-console.log(' • On the neutral oracle facts the two grammars TIE. The char-level divergences are all');
-console.log(' the #6007/#5012 intra-line `as` case (e.g. `:value="msg as string"`): Monogram bounds');
-console.log(' the directive value with a capture-embed, so the closing `"` and everything after');
-console.log(' recover to HTML; the official begin/end region lets the cast\'s type eat the quote and');
-console.log(' leak TS across the rest of the tag. Here the DERIVED grammar is correct and the');
-console.log(' hand-written one is not — the one reported issue (#6007) the official still fails.');
-console.log(' • So: "derived MATCHES hand-written on the core, and is strictly more correct on `as`".');
-// Gate: on the shared core, the derived grammar must stay competitive with the hand-written one.
-if (mAll < oAll * 0.9) { console.log(`\n✗ Monogram (${mAll}) fell below 90% of official (${oAll}) on the shared core`); process.exit(1); }
-console.log(`\n✓ Derived Vue grammar is competitive with the hand-written official on the shared core.`);
diff --git a/test/vue-directives.ts b/test/vue-directives.ts
deleted file mode 100644
index e55f32b..0000000
--- a/test/vue-directives.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-directives.ts — gates Vue increment 2: the DERIVED injection grammar
-// (vue.directives.json / vue.interpolations.json) adds directives (v-for / v-if / :bind / @event /
-// #slot) and {{ }} interpolation ONTO the HTML scopes inside a . Because the
-// template reuses HTML wholesale, this is injection — exactly the official architecture.
-// Directive values and interpolation embed Monogram's OWN TS grammar (source.ts), so
-// Vue template expressions get Monogram's (more-correct) TS highlighting.
-//
-// Like a real editor's injectTo contribution, the injection grammar is loaded into the
-// registry and registered (getInjections) so it applies to the HTML scopes.
-//
-// Tokenized through vscode-tmlanguage-snapshot (vuejs/language-tools' own tool) — see
-// test/vue-grammar-harness.ts — the same engine every Vue bench now uses.
-//
-// Run: node test/vue-directives.ts
-// ─────────────────────────────────────────────────────────────────────────────
-import { tokenize } from './vue-grammar-harness.ts';
-
-const sfc = [
- '',
- ' ',
- ' ',
- ' {{ item.name + 1 }}',
- ' ',
- ' x
',
- ' ',
- ' ',
-].join('\n');
-const toks = await tokenize('mono', sfc);
-
-let pass = 0, fail = 0;
-const find = (text: string, pred: (s: string) => boolean) => toks.find(t => t.text === text && pred(t.scopes));
-function check(label: string, cond: boolean) {
- if (cond) pass++; else { fail++; console.log(`✗ ${label}`); }
-}
-
-// ── directives (injected onto the embedded HTML, inside ) ──
-check('v-for → keyword.control.loop.vue', !!find('v-for', s => s.includes('keyword.control.loop.vue')));
-check('v-if → keyword.control.conditional.vue', !!find('v-if', s => s.includes('keyword.control.conditional.vue')));
-check(': (v-bind shorthand) → punctuation.attribute-shorthand.bind', !!find(':', s => s.includes('punctuation.attribute-shorthand.bind')));
-check('@ (v-on shorthand) → punctuation.attribute-shorthand.event', !!find('@', s => s.includes('punctuation.attribute-shorthand.event')));
-
-// ── directive VALUES embed Monogram's TS ──
-check('v-for value "item in items" → TS (item is a TS variable)', !!find('item', s => s.includes('source.ts') && s.includes('variable')));
-check('v-for value: `in` → TS operator', !!find('in', s => s.includes('source.ts') && s.includes('keyword')));
-check('@click value "go(item)" → TS (go embedded)', !!find('go', s => s.includes('source.ts')));
-
-// ── {{ }} interpolation → delimiters + Monogram's TS expression ──
-check('{{ → interpolation.begin', !!find('{{', s => s.includes('punctuation.definition.interpolation.begin')));
-check('}} → interpolation.end', !!find('}}', s => s.includes('punctuation.definition.interpolation.end')));
-check('interpolation body → Monogram TS (1 → numeric)', !!find('1', s => s.includes('source.ts') && s.includes('constant.numeric')));
-
-// ── a plain HTML attribute (id="main") is NOT mis-embedded as TS — the injection's value
-// embed lives inside a directive region, so it only fires for directives ──
-check('plain attr value "main" stays HTML, not TS', !!find('main', s => s.includes('string') && !s.includes('source.ts')));
-
-console.log(`\nvue-directives: ${pass}/${pass + fail} checks pass`);
-if (fail > 0) { console.log('✗ Vue directives/interpolation FAILED'); process.exit(1); }
-console.log('✓ Vue directives + {{ }} inject onto the template HTML; values + interpolation are Monogram TS');
diff --git a/test/vue-dropin.ts b/test/vue-dropin.ts
deleted file mode 100644
index e0b447c..0000000
--- a/test/vue-dropin.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-dropin.ts — proves Monogram's Vue grammar is a true DROP-IN for vuejs/language-tools'
-// three Vue grammar files, by running it on VS Code's REAL HTML grammars (text.html.basic +
-// text.html.derivative) and real source.ts — the environment a published Vue extension sees.
-//
-// Why this is distinct from vue-grammar-harness.ts: that harness embeds MONOGRAM's own HTML
-// for fairness (isolating the Vue layer in the head-to-head). But Monogram's basic emits no
-// `meta.attribute`, so the official directive selector's excludes are no-ops there — the
-// official-HTML path is UNDER-tested. This test closes that gap: it wires Monogram's vue
-// grammar + the two thin-stub injections onto VS Code's actual derivative/basic/ts, with the
-// official `injectTo`, and asserts the real reported regression cases still hold. If VS Code
-// isn't installed (CI without it), it SKIPS — like html-bench / the scope-gap benches (dev-only).
-//
-// Run: node test/vue-dropin.ts
-// ─────────────────────────────────────────────────────────────────────────────
-import vsctm from 'vscode-textmate';
-import onig from 'vscode-oniguruma';
-import { readFileSync, existsSync } from 'node:fs';
-import { createRequire } from 'node:module';
-import { cases } from './vue-issue-cases.ts';
-
-const { INITIAL, Registry, parseRawGrammar } = vsctm;
-const require = createRequire(import.meta.url);
-const VSC = process.env.MONOGRAM_VSCODE_EXT ?? '/Applications/Visual Studio Code.app/Contents/Resources/app/extensions';
-const offHtml = `${VSC}/html/syntaxes/html.tmLanguage.json`;
-const offDerivative = `${VSC}/html/syntaxes/html-derivative.tmLanguage.json`;
-if (!existsSync(offHtml) || !existsSync(offDerivative)) {
- console.log('⊘ Skipped: VS Code HTML grammars not found (set MONOGRAM_VSCODE_EXT=/path/to/.../extensions). Dev-only, like html-bench.');
- process.exit(0);
-}
-const offTs = `${VSC}/typescript-basics/syntaxes/TypeScript.tmLanguage.json`;
-
-const wasmBin = readFileSync(require.resolve('vscode-oniguruma/release/onig.wasm'));
-await onig.loadWASM(wasmBin.buffer.slice(wasmBin.byteOffset, wasmBin.byteOffset + wasmBin.byteLength));
-const onigLib = Promise.resolve({ createOnigScanner: (p: string[]) => new onig.OnigScanner(p), createOnigString: (s: string) => new onig.OnigString(s) });
-const read = (p: string) => readFileSync(p, 'utf-8');
-const stub = (sn: string) => parseRawGrammar(JSON.stringify({ scopeName: sn, patterns: [{ match: '[^\\n]+', name: sn }] }), `${sn}.json`);
-
-// Monogram's Vue layer (main grammar + two thin-stub injections) on VS Code's REAL HTML + TS.
-const INJECT_TO = ['text.html.vue', 'text.html.markdown', 'text.html.derivative', 'text.pug'];
-const registry = new Registry({
- onigLib,
- loadGrammar: async (sn) => {
- if (sn === 'text.html.vue') return parseRawGrammar(read('vue.tmLanguage.json'), 'vue.json');
- if (sn === 'vue.directives') return parseRawGrammar(read('vue.directives.tmLanguage.json'), 'dir.json');
- if (sn === 'vue.interpolations') return parseRawGrammar(read('vue.interpolations.tmLanguage.json'), 'int.json');
- if (sn === 'text.html.basic') return parseRawGrammar(read(offHtml), 'html.json'); // VS Code's REAL HTML
- if (sn === 'text.html.derivative') return parseRawGrammar(read(offDerivative), 'der.json'); // VS Code's REAL derivative
- if (sn === 'source.ts') return existsSync(offTs) ? parseRawGrammar(read(offTs), 'ts.json') : parseRawGrammar(read('typescript.tmLanguage.json'), 'ts.json');
- if (sn === 'source.js') return parseRawGrammar(read('javascript.tmLanguage.json'), 'js.json');
- if (sn.startsWith('source.')) return stub(sn); // css dialects etc.
- return null;
- },
- getInjections: (sn) => {
- // Mirror VS Code's injectTo: each injection fires when one of the host grammars is active.
- const base = sn.split(' ')[0];
- return INJECT_TO.some(h => base === h || base.startsWith(h + '.')) ? ['vue.directives', 'vue.interpolations'] : undefined;
- },
-});
-await registry.loadGrammar('vue.directives');
-await registry.loadGrammar('vue.interpolations');
-const vue = (await registry.loadGrammar('text.html.vue'))!;
-
-function lookup(src: string): (offset: number) => string {
- const lines = src.split('\n'); const ls: number[] = []; let a = 0;
- for (const l of lines) { ls.push(a); a += l.length + 1; }
- const lt: any[][] = []; let st: any = INITIAL;
- for (const l of lines) { const r = vue.tokenizeLine(l, st); lt.push(r.tokens); st = r.ruleStack; }
- return (o: number) => { let li = 0; while (li + 1 < ls.length && ls[li + 1] <= o) li++; const c = o - ls[li]; for (const t of lt[li] ?? []) if (c >= t.startIndex && c < t.endIndex) return t.scopes.join(' '); return ''; };
-}
-const makeAt = (src: string) => { const lk = lookup(src); return (text: string, nth = 0) => { let i = -1; for (let k = 0; k <= nth; k++) i = src.indexOf(text, i + 1); return i < 0 ? '__NF__' : lk(i + Math.floor(text.length / 2)); }; };
-
-// EVERY reported case is a drop-in regression gate — run them ALL on the OFFICIAL host grammars,
-// so each is validated on BOTH host axes: vue-issues.ts runs the same cases on MONOGRAM's embedded
-// source.ts/html, this runs them on VS Code's REAL HTML + official source.ts (the published
-// environment). A case that passes on Monogram's host but fails here is a DROP-IN bug — e.g.
-// `generic="…"`, whose type-param value must tokenize under the OFFICIAL TS grammar's repo keys
-// (`#type`/`#comment`), not just Monogram's (`#type-inner`/`#blockcomment`). There are no `monoGap`
-// Vue cases (all reported bugs are solved); a future unsolvable one can't be a clean drop-in, so it
-// would (correctly) fail here and must be handled consciously rather than silently skipped.
-const skippedMonoGap = cases.filter((c) => c.monoGap);
-if (skippedMonoGap.length) console.log(` ⚠ ${skippedMonoGap.length} monoGap case(s) present — they are STILL run below (every case is a drop-in gate): ${skippedMonoGap.map(c => c.id).join(', ')}`);
-const dropinCases = cases;
-let pass = 0, fail = 0; const failures: string[] = [];
-for (const c of dropinCases) {
- const at = makeAt(c.src);
- const ok = c.checks.every(ch => ch.want(at(ch.at, ch.nth)));
- if (ok) pass++; else { fail++; failures.push(` ✗ ${c.id} ${c.title}`); }
-}
-
-console.log('\n══════════════════════════════════════════════════════════════════════');
-console.log(' Monogram Vue as a DROP-IN on VS Code\'s REAL HTML grammars (text.html.derivative');
-console.log(' + text.html.basic) + real source.ts — the published-extension environment.');
-console.log('══════════════════════════════════════════════════════════════════════');
-console.log(` reported regression cases: ${pass}/${dropinCases.length} pass on the OFFICIAL host (same cases vue-issues.ts runs on Monogram's host — every case validated on BOTH axes)`);
-for (const f of failures) console.log(f);
-if (fail > 0) { console.log('\n✗ Monogram Vue is NOT a clean drop-in on the official HTML (a case regressed)'); process.exit(1); }
-console.log(' ✓ directives fire on the official meta.tag, interpolation in text.html.derivative,');
-console.log(' and the #6007 `as`-cast still recovers — Monogram replaces the 3 official files.');
diff --git a/test/vue-embed-boundary.ts b/test/vue-embed-boundary.ts
deleted file mode 100644
index 654ae4f..0000000
--- a/test/vue-embed-boundary.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-embed-boundary.ts — the embed BOUNDARY tests (the hard cases the user flagged).
-// An embedded grammar (Monogram's TS) must not consume past the host's structural
-// boundary, even when its own region is open mid-construct.
-//
-// #1666 — `type Foo = 123` (no `;`) then ``. The TS `type` body region is
-// open, but `` is HTML's raw-text terminator and MUST end the embed.
-// GENERAL solution = a `begin/while` script region (re-checks per line, drops
-// the region + pops the open TS region at the `` line). GATED here.
-//
-// #5012 — `:value="msg as string"`. The closing `"` is an INTRA-LINE boundary a `while`
-// (line-granularity) can't enforce, and a begin/end embed lets the `as`-cast eat
-// the quote as a string-literal-type. SOLVED in pure TM: the value is CAPTURE-
-// EMBEDDED into a `([^"]*)` span, so the embedded grammar is clipped at the quote
-// (a capture's text range can't be crossed). GATED below.
-//
-// Tokenized through vscode-tmlanguage-snapshot (vuejs/language-tools' own tool) — see
-// test/vue-grammar-harness.ts — the same engine every Vue bench now uses.
-//
-// Run: node test/vue-embed-boundary.ts
-// ─────────────────────────────────────────────────────────────────────────────
-import { tokenize, type TextTok } from './vue-grammar-harness.ts';
-
-const find = (toks: TextTok[], text: string, pred: (s: string) => boolean) => toks.find(t => t.text === text && pred(t.scopes));
-
-let pass = 0, fail = 0;
-function check(label: string, cond: boolean) { if (cond) pass++; else { fail++; console.log(`✗ ${label}`); } }
-
-// ── #1666 (GATED): the embed must END at even with an open trailing type ──
-{
- const t = await tokenize('mono', '\n ');
- check('#1666: the trailing `type Foo = 123` highlights as TS', !!find(t, 'type', s => s.includes('source.ts') && s.includes('storage.type')));
- // the key fix: ends the embed → the following block is NOT swallowed into source.ts
- check('#1666: ends the embed — the following is NOT TS', !t.some(tk => tk.text === 'template' && tk.scopes.includes('source.ts')));
- check('#1666: the in the template is HTML, not TS', !t.some(tk => tk.text === 'b' && tk.scopes.includes('source.ts')));
-}
-
-// ── #5012 (GATED, FIXED): `:value="msg as string"` — the `as`-cast must NOT run its type
-// context past the closing `"` and swallow the rest of the tag. The directive value is
-// CAPTURE-EMBEDDED (a `([^"]*)` span), so the embedded grammar is clipped at the quote:
-// the cast stops, the `"` stays a string end, and `>ok ` recovers to HTML. Once thought
-// a pure-TM ceiling (semantic/Volar only); it isn't — capture-embed bounds it. ──
-{
- const t = await tokenize('mono', '\n ok \n \n');
- check('#5012: `msg as string` embeds as TS (the value)', !!find(t, 'as', s => s.includes('source.ts')));
- check('#5012 FIXED: the closing `"` is not eaten — `ok` after the value is HTML, not TS', !t.some(tk => tk.text === 'ok' && tk.scopes.includes('source.ts')));
- check('#5012 FIXED: `` after the value recovers to HTML', !!find(t, 'b', s => s.includes('entity.name.tag') && !s.includes('source.ts')));
- check('#5012: ');
- check('#3999: multi-line ');
- check('#3999: multi-line ends the embed (#1666); #5012 directive-value cast bounded by capture-embed');
diff --git a/test/vue-generic-dropin.ts b/test/vue-generic-dropin.ts
deleted file mode 100644
index 462e6ae..0000000
--- a/test/vue-generic-dropin.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-generic-dropin.ts — proves the DE-HACKED `generic="…"` attribute embed in Monogram's vue
-// grammar tokenizes correctly under BOTH hosts: Monogram's OWN source.ts AND VS Code's OFFICIAL
-// source.ts. The generic= value patterns now use the official PUBLIC repository keys
-// (`source.ts#comment`, `source.ts#type`, `source.ts#punctuation-comma`) + the literal variance /
-// `=` matches — exactly mirroring Volar's hand-written `vue-directives-generic-attr`. That only
-// works if those official key NAMES resolve in whichever source.ts is loaded:
-// • Monogram's source.ts — NATIVELY (typescript.ts's `canonicalRepoNames` 限制器 makes gen-tm emit
-// `#comment`/`#type`/`#punctuation-comma` as the real key names — one key each, not an alias).
-// • VS Code's source.ts — natively (they're its own keys).
-// This harness loads Monogram's vue grammar TWICE — once over each source.ts — and asserts the
-// type parameter, the `extends` constraint keyword, the comma separator, and a `/* */` comment in
-// the value all carry the right scope on BOTH. If they only worked on one host, the embed was
-// host-locked; passing on both proves the canonical names make Monogram's source.ts a true drop-in.
-//
-// Skips (exit 0) if VS Code's official TS grammar isn't installed — dev-only, like vue-dropin.
-// Run: node test/vue-generic-dropin.ts
-// ─────────────────────────────────────────────────────────────────────────────
-import vsctm from 'vscode-textmate';
-import onig from 'vscode-oniguruma';
-import { readFileSync, existsSync } from 'node:fs';
-import { createRequire } from 'node:module';
-
-const { INITIAL, Registry, parseRawGrammar } = vsctm;
-const require = createRequire(import.meta.url);
-const VSC = process.env.MONOGRAM_VSCODE_EXT ?? '/Applications/Visual Studio Code.app/Contents/Resources/app/extensions';
-const offTs = `${VSC}/typescript-basics/syntaxes/TypeScript.tmLanguage.json`;
-if (!existsSync(offTs)) {
- console.log('⊘ Skipped: VS Code official TS grammar not found (set MONOGRAM_VSCODE_EXT). Dev-only, like vue-dropin.');
- process.exit(0);
-}
-
-const wasmBin = readFileSync(require.resolve('vscode-oniguruma/release/onig.wasm'));
-await onig.loadWASM(wasmBin.buffer.slice(wasmBin.byteOffset, wasmBin.byteOffset + wasmBin.byteLength));
-const onigLib = Promise.resolve({ createOnigScanner: (p: string[]) => new onig.OnigScanner(p), createOnigString: (s: string) => new onig.OnigString(s) });
-const read = (p: string) => readFileSync(p, 'utf-8');
-const stub = (sn: string) => parseRawGrammar(JSON.stringify({ scopeName: sn, patterns: [{ match: '[^\\n]+', name: sn }] }), `${sn}.json`);
-
-// A registry hosting Monogram's vue grammar over a CHOSEN source.ts (Monogram's own, or VS Code's).
-function makeRegistry(tsPath: string) {
- return new Registry({
- onigLib,
- loadGrammar: async (sn) => {
- if (sn === 'text.html.vue') return parseRawGrammar(read('vue.tmLanguage.json'), 'vue.json');
- if (sn === 'text.html.basic') return parseRawGrammar(read(`${VSC}/html/syntaxes/html.tmLanguage.json`), 'html.json');
- if (sn === 'text.html.derivative') return parseRawGrammar(read(`${VSC}/html/syntaxes/html-derivative.tmLanguage.json`), 'der.json');
- if (sn === 'source.ts') return parseRawGrammar(read(tsPath), 'ts.json');
- if (sn === 'source.js') return parseRawGrammar(read('javascript.tmLanguage.json'), 'js.json');
- if (sn.startsWith('source.') || sn.startsWith('text.')) return stub(sn);
- return null;
- },
- });
-}
-
-// Tokenize `src` through the vue grammar and return offset → joined-scope lookup.
-async function lookupFor(tsPath: string, src: string): Promise<(offset: number) => string> {
- const reg = makeRegistry(tsPath);
- const vue = (await reg.loadGrammar('text.html.vue'))!;
- const lines = src.split('\n'); const ls: number[] = []; let a = 0;
- for (const l of lines) { ls.push(a); a += l.length + 1; }
- const lt: any[][] = []; let st: any = INITIAL;
- for (const l of lines) { const r = vue.tokenizeLine(l, st); lt.push(r.tokens); st = r.ruleStack; }
- return (o: number) => { let li = 0; while (li + 1 < ls.length && ls[li + 1] <= o) li++; const c = o - ls[li]; for (const t of lt[li] ?? []) if (c >= t.startIndex && c < t.endIndex) return t.scopes.join(' '); return ''; };
-}
-
-// A `',
-].join('\n');
-
-// Probe by the EXACT character offset of a construct in SRC (each construct below is unique in the
-// line, so indexOf is unambiguous). We check the scope STACK CONTAINS the expected leaf (not exact
-// equality) so incidental wrapper scopes (which differ between the two TS grammars) don't matter —
-// what matters is that the generic= value is tokenized AS TYPESCRIPT (the official keys resolved),
-// not dropped to a plain string.
-const checks: { find: string; want: string; desc: string }[] = [
- { find: 'T extends', want: 'entity.name.type', desc: 'type parameter `T` → entity.name.type' },
- { find: 'extends', want: 'storage.modifier.ts', desc: 'constraint keyword `extends` → storage.modifier.ts (the inlined variance match)' },
- { find: 'Base', want: 'entity.name.type', desc: 'constraint type `Base` → entity.name.type (via source.ts#type)' },
- { find: ', U', want: 'punctuation.separator.comma.ts', desc: 'separator `,` → punctuation.separator.comma.ts (via source.ts#punctuation-comma)' },
- { find: '/*c*/', want: 'comment.block', desc: 'inline `/*c*/` → comment scope (via source.ts#comment)' },
-];
-
-let pass = 0; const failures: string[] = [];
-for (const [label, tsPath] of [['Monogram source.ts', 'typescript.tmLanguage.json'] as const, ['official source.ts', offTs] as const]) {
- const lk = await lookupFor(tsPath, SRC);
- for (const ch of checks) {
- const got = lk(SRC.indexOf(ch.find)); // offset of the construct's FIRST char (the target token)
- if (got.includes(ch.want)) pass++;
- else failures.push(` ✗ [${label}] ${ch.desc}\n at ${JSON.stringify(ch.find)} got: ${got || '(empty)'}`);
- }
-}
-
-console.log('\n══════════════════════════════════════════════════════════════════════');
-console.log(' De-hacked Vue `generic="…"` — dual-host tokenization (Monogram + official source.ts)');
-console.log('══════════════════════════════════════════════════════════════════════');
-const total = checks.length * 2;
-console.log(` ${pass}/${total} scope checks pass across BOTH hosts (${checks.length} constructs × 2 source.ts hosts)`);
-for (const f of failures) console.log(f);
-if (failures.length) { console.log('\n✗ generic= does not tokenize identically on both hosts — the official keys do not resolve somewhere.'); process.exit(1); }
-console.log(' ✓ generic= uses ONLY official keys (source.ts#comment/#type/#punctuation-comma) +');
-console.log(' the literal variance/`=` matches, and lights up correctly on Monogram\'s source.ts');
-console.log(' (canonical native names) AND VS Code\'s official source.ts — a true repository-level drop-in.');
diff --git a/test/vue-grammar-harness.ts b/test/vue-grammar-harness.ts
deleted file mode 100644
index dc60f4a..0000000
--- a/test/vue-grammar-harness.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// vue-grammar-harness.ts — builds the Monogram and official Vue grammars through
-// vuejs/language-tools' OWN test tool, `vscode-tmlanguage-snapshot` (the engine behind
-// their extensions/vscode/tests/grammar.spec.ts). Instead of hand-wiring a vscode-textmate
-// Registry + getInjections, we hand the tool a package.json-shaped descriptor and let it
-// resolve grammars + injections from `contributes.grammars` / `injectTo` exactly the way
-// VS Code does. This makes the head-to-head FAITHFUL to how the official grammar is tested.
-//
-// Fairness (unchanged from the old harness): BOTH grammars embed Monogram's OWN
-// source.ts / source.js / text.html.basic, so the script/template body tokenizes
-// identically and only the VUE LAYER (block regions, embed boundaries, directives,
-// interpolation) differs. CSS dialects we don't grade get a one-scope stub.
-//
-// The tool only renders a snapshot STRING; we parse that back into per-line tokens so the
-// benches keep their precise offset→scope lookups. Shared by vue-issues.ts and vue-bench.ts.
-// ─────────────────────────────────────────────────────────────────────────────
-import { createGrammarSnapshot } from 'vscode-tmlanguage-snapshot';
-import { mkdtempSync, writeFileSync, existsSync } from 'node:fs';
-import { tmpdir } from 'node:os';
-import { join, relative, resolve } from 'node:path';
-
-const REPO = resolve(import.meta.dirname, '..');
-const FIX = join(REPO, 'test/fixtures/vue-official');
-export const officialAvailable = existsSync(join(FIX, 'vue.tmLanguage.json'));
-
-// One scratch dir for the .vue fixture we re-write per snippet + the CSS-dialect stubs.
-const work = mkdtempSync(join(tmpdir(), 'vue-harness-'));
-const stub = (sn: string) => {
- const p = join(work, `${sn}.json`);
- writeFileSync(p, JSON.stringify({ scopeName: sn, patterns: [{ match: '[^\\n]+', name: sn }] }));
- return p;
-};
-// Embedded grammars handed to BOTH grammars (identical → isolates the Vue layer). The CSS
-// dialects are stubbed (we don't pit them head-to-head; the stub keeps familyOf() === 'css').
-// text.html.derivative is Monogram's emitted thin alias of text.html.basic — the embedded-HTML
-// scope the template embeds and interpolation injects onto (both grammars get the same one, so
-// the official grammar, which targets text.html.derivative too, is tested faithfully).
-// source.tsx / source.js.jsx are Monogram's typescriptreact/javascriptreact grammars: BOTH Vue
-// grammars embed them for ` ``', src: `\n\n hi
${DONE}`,
- checks: [{ at: 'hi', want: htmlText, desc: ' ends the embed — template is HTML' }, { at: 'DONE', want: htmlText, desc: 'downstream recovers' }] },
- // SAME-LINE close (the #2060 minimal repro): content + `` `` share a line. The embed must
- // still highlight the content AS code AND keep the close clean tag punctuation — Monogram bounds the
- // pre-close content with a capture-embed so neither is lost. The official gets the content but LEAKS
- // the close (`/script>` mis-read as a `string.regexp`), the reported #2060 bug → off:false.
- { id: '#2060-inline', title: '`` const a = 1; `` (content on the close line) embeds + clean close', src: ``,
- checks: [{ at: 'const', want: embedded, desc: 'the const on the close line still embeds as TS (the embed is not dropped for that line)' },
- { at: '/script', want: isCloseTag, desc: 'the is clean tag punctuation, NOT swallowed into source.ts (the official leaks it as string.regexp.ts)' }] },
- // SAME-LINE close after an UNTERMINATED union, then an adjacent block. Monogram: 1st block\'s tail
- // embeds, the close is clean, the 2nd block recovers as code. The official leaks the close AND the
- // entire 2nd block into the 1st block\'s type context → off:false.
- { id: '#2060-inline-adjacent', title: "an unterminated union before a same-line `` ``, then a second `\n`,
- checks: [{ at: `| 'b'`, want: embedded, desc: 'the union tail before the same-line still embeds as TS' },
- { at: '/script', want: isCloseTag, desc: 'the first is clean tag punctuation, not leaked into source.ts' },
- { at: 'defineProps', want: embedded, desc: 'the second block recovers and embeds as TS (the official swallows it into the first block)' }] },
- // The force-wrapped (one-attr-per-line) start tag is #3999's actual trigger; the body is an
- // `interface`/`type` (TS-ONLY syntax) so the check pins the `ts` FAMILY, not merely "embedded".
- // A `want: embedded` here would still pass if the lang flipped source.ts→source.js (#3999's real
- // symptom), so we assert source.ts AND a TS-specific scope (`storage.type.interface.ts`) that a
- // source.js embed could never produce.
- { id: '#3999', title: 'a force-wrapped multi-line ``,
- checks: [{ at: 'interface', want: s => familyOf(s) === 'ts' && s.includes('storage.type.interface.ts'), desc: 'the `interface` keyword is TS-ONLY: it embeds as source.ts (`storage.type.interface.ts`) across the multi-line start tag — proving no source.ts→source.js family flip (#3999\'s symptom)' },
- { at: 'const', want: s => familyOf(s) === 'ts', desc: 'the rest of the body is still the ts family, not js' }] },
- // ── tag / interpolation edge cases ──
- { id: '#4769', title: 'tag name starting with `template`', src: `\n {{ y }} ${DONE}`,
- checks: [{ at: 'y', want: embedded, desc: 'interpolation inside a template-prefixed tag works' }, { at: 'DONE', want: htmlText, desc: 'downstream recovers' }] },
- { id: '#5701', title: '`{{` inside a `\n\n {{ real }}
${DONE}`,
- checks: [{ at: 'real', want: embedded, desc: 'the real interpolation still embeds as TS' }, { at: 'DONE', want: htmlText, desc: 'downstream recovers' }] },
- { id: '#6070', title: 'capitalized component then a ``,
- checks: [{ at: 'color', want: s => familyOf(s) === 'css', desc: '`), so every dialect's close rule shares one regex and only the first-
-// listed fires — a non-first dialect's CLOSE-LINE content (the pre-`` text) is then embedded
-// in the WRONG dialect. A bug is exactly: content that should be source.css.X carries some other
-// source.css.* instead.
-//
-// WHY THE EXISTING GATES MISSED IT (see issue #43 discussion): scope-gap-vue grades the Vue shell
-// (tags/directives/interpolation) against @vue/compiler-sfc+parse5+tsc — it has NO CSS oracle, so the
-// embedded dialect is structurally ungraded. This test adds that missing axis: an oracle that is the
-// grammar's DECLARED embed scope (not Monogram's parser, which raw-texts the body as a blob), and
-// DERIVED witnesses (each dialect × each structural position) rather than a thin corpus.
-//
-// CLOSED LOOP / no hardcoding: the dialects + their expected scopes come from the SAME grammar source
-// the emitter derives the rules from (`grammar.markup.rawText.embed.style`).
-//
-// Run: node test/vue-raw-style-embed-sites.ts
-import { tokenize } from './vue-grammar-harness.ts';
-import grammar from '../vue.ts';
-
-const style = (grammar as any).markup?.rawText?.embed?.style;
-if (!style) { console.error('vue grammar has no markup.rawText.embed.style'); process.exit(1); }
-
-// [langAttr | null (default), expectedScope]; closed-loop from the grammar's own embed map.
-const dialects: [string | null, string][] = [
- [null, style.default],
- ...Object.entries(style.lang as Record).map(([k, v]) => [k, v] as [string, string]),
-];
-
-// Structural positions. Each builds a `, find: 'midline' },
- // THE BUG: content on the SAME line as the close `` — the per-dialect close rule's capture.
- { pos: 'close-line ', src: `${open}\n.firstline { a: 1 }\n.closeline { b: 2 }`, find: 'closeline' },
- // single-line: open, content, and close all on one line.
- { pos: 'single-line ', src: `${open}.oneline { c: 3 }`, find: 'oneline' },
- ];
-}
-
-const cssScope = (chain: string) => chain.split(' ').find(s => s.startsWith('source.css') || s === 'source.sass' || s === 'source.stylus' || s === 'source.postcss') ?? '(none)';
-
-let cells = 0, wrong = 0;
-const fails: string[] = [];
-for (const [lang, expected] of dialects) {
- for (const w of witnesses(lang)) {
- cells++;
- const toks = await tokenize('mono', w.src);
- const t = toks.find(x => x.text.includes(w.find));
- const got = t ? cssScope(t.scopes) : '(token not found)';
- const ok = t !== undefined && t.scopes.split(' ').includes(expected);
- if (!ok) { wrong++; fails.push(`",
- {
- "token": "tag",
- "next": "@popall"
- }
- ],
- [
- "[^<]+",
- "source.css"
- ],
- [
- "<",
- "source.css"
- ]
- ]
- }
-}
diff --git a/vue.tmLanguage.json b/vue.tmLanguage.json
deleted file mode 100644
index d4b48dd..0000000
--- a/vue.tmLanguage.json
+++ /dev/null
@@ -1,3618 +0,0 @@
-{
- "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
- "name": "vue",
- "scopeName": "text.html.vue",
- "patterns": [
- {
- "include": "#comment"
- },
- {
- "include": "#entities"
- },
- {
- "include": "#block-md"
- },
- {
- "include": "#block-json"
- },
- {
- "include": "#block-jsonc"
- },
- {
- "include": "#block-json5"
- },
- {
- "include": "#block-yaml"
- },
- {
- "include": "#block-toml"
- },
- {
- "include": "#block-gql"
- },
- {
- "include": "#block-graphql"
- },
- {
- "include": "#raw-template-pug-inline"
- },
- {
- "include": "#raw-template-pug-inline-ml"
- },
- {
- "include": "#raw-template-pug"
- },
- {
- "include": "#raw-template-inline"
- },
- {
- "include": "#raw-template-inline-ml"
- },
- {
- "include": "#raw-template"
- },
- {
- "include": "#raw-template-ml"
- },
- {
- "include": "#raw-script-ts-inline"
- },
- {
- "include": "#raw-script-ts-inline-ml"
- },
- {
- "include": "#raw-script-ts"
- },
- {
- "include": "#raw-script-tsx-inline"
- },
- {
- "include": "#raw-script-tsx-inline-ml"
- },
- {
- "include": "#raw-script-tsx"
- },
- {
- "include": "#raw-script-jsx-inline"
- },
- {
- "include": "#raw-script-jsx-inline-ml"
- },
- {
- "include": "#raw-script-jsx"
- },
- {
- "include": "#raw-script-coffee-inline"
- },
- {
- "include": "#raw-script-coffee-inline-ml"
- },
- {
- "include": "#raw-script-coffee"
- },
- {
- "include": "#raw-script-inline"
- },
- {
- "include": "#raw-script-inline-ml"
- },
- {
- "include": "#raw-script"
- },
- {
- "include": "#raw-script-close"
- },
- {
- "include": "#raw-script-close-ml"
- },
- {
- "include": "#raw-script-ml"
- },
- {
- "include": "#raw-style-scss-inline"
- },
- {
- "include": "#raw-style-scss-inline-ml"
- },
- {
- "include": "#raw-style-scss"
- },
- {
- "include": "#raw-style-less-inline"
- },
- {
- "include": "#raw-style-less-inline-ml"
- },
- {
- "include": "#raw-style-less"
- },
- {
- "include": "#raw-style-stylus-inline"
- },
- {
- "include": "#raw-style-stylus-inline-ml"
- },
- {
- "include": "#raw-style-stylus"
- },
- {
- "include": "#raw-style-postcss-inline"
- },
- {
- "include": "#raw-style-postcss-inline-ml"
- },
- {
- "include": "#raw-style-postcss"
- },
- {
- "include": "#raw-style-sass-inline"
- },
- {
- "include": "#raw-style-sass-inline-ml"
- },
- {
- "include": "#raw-style-sass"
- },
- {
- "include": "#raw-style-inline"
- },
- {
- "include": "#raw-style-inline-ml"
- },
- {
- "include": "#raw-style"
- },
- {
- "include": "#raw-style-ml"
- },
- {
- "include": "#tag"
- }
- ],
- "repository": {
- "comment": {
- "name": "comment.block.html",
- "begin": "",
- "captures": {
- "0": {
- "name": "punctuation.definition.comment.vue"
- }
- }
- },
- "entities": {
- "patterns": [
- {
- "match": "(&)(#(?:[xX][0-9a-fA-F]+|[0-9]+))(;)",
- "captures": {
- "1": {
- "name": "punctuation.definition.entity.html"
- },
- "2": {
- "name": "constant.character.entity.html"
- },
- "3": {
- "name": "punctuation.definition.entity.html"
- }
- }
- },
- {
- "match": "(&)([a-zA-Z][a-zA-Z0-9]*)(;)",
- "captures": {
- "1": {
- "name": "punctuation.definition.entity.html"
- },
- "2": {
- "name": "constant.character.entity.named.html"
- },
- "3": {
- "name": "punctuation.definition.entity.html"
- }
- }
- }
- ]
- },
- "block-md": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?md\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "text.html.markdown",
- "patterns": [
- {
- "include": "text.html.markdown"
- }
- ]
- },
- "block-json": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?json\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.json",
- "patterns": [
- {
- "include": "source.json"
- }
- ]
- },
- "block-jsonc": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?jsonc\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.json.comments",
- "patterns": [
- {
- "include": "source.json.comments"
- }
- ]
- },
- "block-json5": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?json5\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.json5",
- "patterns": [
- {
- "include": "source.json5"
- }
- ]
- },
- "block-yaml": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?yaml\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.yaml",
- "patterns": [
- {
- "include": "source.yaml"
- }
- ]
- },
- "block-toml": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?toml\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.toml",
- "patterns": [
- {
- "include": "source.toml"
- }
- ]
- },
- "block-gql": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?gql\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.graphql",
- "patterns": [
- {
- "include": "source.graphql"
- }
- ]
- },
- "block-graphql": {
- "name": "meta.embedded.block.vue",
- "begin": "(<)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)\\b(?=[^>]*\\blang\\s*=\\s*[\"']?graphql\\b)([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "()(\\2)\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "contentName": "source.graphql",
- "patterns": [
- {
- "include": "source.graphql"
- }
- ]
- },
- "raw-template-pug-inline": {
- "name": "meta.template.vue",
- "match": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])pug\\4[^>]*)(>)(.*?)()([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "text.pug",
- "patterns": [
- {
- "include": "text.pug"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-template-pug-inline-ml": {
- "name": "meta.template.vue",
- "begin": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])pug\\4[^>]*)(>)(.*?)()([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "text.pug",
- "patterns": [
- {
- "include": "text.pug"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-template-pug": {
- "name": "meta.template.vue",
- "begin": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])pug\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.pug",
- "patterns": [
- {
- "include": "text.pug"
- }
- ]
- },
- "raw-template-inline": {
- "name": "meta.template.vue",
- "match": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*)(>)(.*?)()([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "text.html.derivative",
- "patterns": [
- {
- "include": "text.html.derivative"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- },
- "8": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-template-inline-ml": {
- "name": "meta.template.vue",
- "begin": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*)(>)(.*?)()([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "text.html.derivative",
- "patterns": [
- {
- "include": "text.html.derivative"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-template": {
- "name": "meta.template.vue",
- "begin": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.html.derivative",
- "patterns": [
- {
- "include": "text.html.derivative"
- }
- ]
- },
- "raw-template-ml": {
- "name": "meta.template.vue",
- "begin": "(<)([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\b(?![^>]*>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "()([Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee])\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "name": "meta.tag.vue",
- "begin": "\\G(?!\\blang\\s*=\\s*[\"']?(?:pug)\\b)",
- "end": "(?=\\blang\\s*=\\s*[\"']?(?:pug)\\b)|(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?pug\\b)",
- "end": "(?=[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "end": "(?=[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.pug",
- "patterns": [
- {
- "include": "text.pug"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.pug",
- "patterns": [
- {
- "include": "text.pug"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "end": "(?=[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.html.derivative",
- "patterns": [
- {
- "include": "text.html.derivative"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee](?:[\\s>]|$))",
- "contentName": "text.html.derivative",
- "patterns": [
- {
- "include": "text.html.derivative"
- }
- ]
- }
- ]
- },
- "raw-script-ts-inline": {
- "name": "meta.script.vue",
- "match": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])ts\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.ts",
- "patterns": [
- {
- "include": "source.ts"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-ts-inline-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])ts\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.ts",
- "patterns": [
- {
- "include": "source.ts"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-ts": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])ts\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.ts",
- "patterns": [
- {
- "include": "source.ts"
- }
- ]
- },
- "raw-script-tsx-inline": {
- "name": "meta.script.vue",
- "match": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])tsx\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.tsx",
- "patterns": [
- {
- "include": "source.tsx"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-tsx-inline-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])tsx\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.tsx",
- "patterns": [
- {
- "include": "source.tsx"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-tsx": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])tsx\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.tsx",
- "patterns": [
- {
- "include": "source.tsx"
- }
- ]
- },
- "raw-script-jsx-inline": {
- "name": "meta.script.vue",
- "match": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])jsx\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.js.jsx",
- "patterns": [
- {
- "include": "source.js.jsx"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-jsx-inline-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])jsx\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.js.jsx",
- "patterns": [
- {
- "include": "source.js.jsx"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-jsx": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])jsx\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js.jsx",
- "patterns": [
- {
- "include": "source.js.jsx"
- }
- ]
- },
- "raw-script-coffee-inline": {
- "name": "meta.script.vue",
- "match": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])coffee\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.coffee",
- "patterns": [
- {
- "include": "source.coffee"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-coffee-inline-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])coffee\\4[^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.coffee",
- "patterns": [
- {
- "include": "source.coffee"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-coffee": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*\\blang\\s*=\\s*([\"'])coffee\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.coffee",
- "patterns": [
- {
- "include": "source.coffee"
- }
- ]
- },
- "raw-script-inline": {
- "name": "meta.script.vue",
- "match": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- },
- "8": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-inline-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*)(>)(.*?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "raw-script-close": {
- "name": "meta.script.vue",
- "match": "^(\\s*)((?:(?!<[Ss][Cc][Rr][Ii][Pp][Tt]\\b).)+?)()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "captures": {
- "2": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "3": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "4": {
- "name": "entity.name.tag.vue"
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-close-ml": {
- "name": "meta.script.vue",
- "begin": "^(\\s*)((?:(?!<[Ss][Cc][Rr][Ii][Pp][Tt]\\b).)+?)()([Ss][Cc][Rr][Ii][Pp][Tt])(?=\\s*$)",
- "beginCaptures": {
- "2": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "3": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "4": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-script-ml": {
- "name": "meta.script.vue",
- "begin": "(<)([Ss][Cc][Rr][Ii][Pp][Tt])\\b(?![^>]*>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "()([Ss][Cc][Rr][Ii][Pp][Tt])\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "name": "meta.tag.vue",
- "begin": "\\G(?!\\blang\\s*=\\s*[\"']?(?:ts|tsx|jsx|coffee)\\b)",
- "end": "(?=\\blang\\s*=\\s*[\"']?(?:ts|tsx|jsx|coffee)\\b)|(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?ts\\b)",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.ts",
- "patterns": [
- {
- "include": "source.ts"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.ts",
- "patterns": [
- {
- "include": "source.ts"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?tsx\\b)",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.tsx",
- "patterns": [
- {
- "include": "source.tsx"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.tsx",
- "patterns": [
- {
- "include": "source.tsx"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?jsx\\b)",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js.jsx",
- "patterns": [
- {
- "include": "source.js.jsx"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js.jsx",
- "patterns": [
- {
- "include": "source.js.jsx"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?coffee\\b)",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.coffee",
- "patterns": [
- {
- "include": "source.coffee"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.coffee",
- "patterns": [
- {
- "include": "source.coffee"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "end": "(?=[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Cc][Rr][Ii][Pp][Tt](?:[\\s>]|$))",
- "contentName": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- }
- ]
- },
- "raw-style-scss-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])scss\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.css.scss",
- "patterns": [
- {
- "include": "source.css.scss"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-scss-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])scss\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.css.scss",
- "patterns": [
- {
- "include": "source.css.scss"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-scss": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])scss\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.scss",
- "patterns": [
- {
- "include": "source.css.scss"
- }
- ]
- },
- "raw-style-less-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])less\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.css.less",
- "patterns": [
- {
- "include": "source.css.less"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-less-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])less\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.css.less",
- "patterns": [
- {
- "include": "source.css.less"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-less": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])less\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.less",
- "patterns": [
- {
- "include": "source.css.less"
- }
- ]
- },
- "raw-style-stylus-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])stylus\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.stylus",
- "patterns": [
- {
- "include": "source.stylus"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-stylus-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])stylus\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.stylus",
- "patterns": [
- {
- "include": "source.stylus"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-stylus": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])stylus\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.stylus",
- "patterns": [
- {
- "include": "source.stylus"
- }
- ]
- },
- "raw-style-postcss-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])postcss\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.postcss",
- "patterns": [
- {
- "include": "source.postcss"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-postcss-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])postcss\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.postcss",
- "patterns": [
- {
- "include": "source.postcss"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-postcss": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])postcss\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.postcss",
- "patterns": [
- {
- "include": "source.postcss"
- }
- ]
- },
- "raw-style-sass-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])sass\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.sass",
- "patterns": [
- {
- "include": "source.sass"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- },
- "9": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-sass-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])sass\\4[^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "6": {
- "name": "source.sass",
- "patterns": [
- {
- "include": "source.sass"
- }
- ]
- },
- "7": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "8": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-sass": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*\\blang\\s*=\\s*([\"'])sass\\4[^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "5": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.sass",
- "patterns": [
- {
- "include": "source.sass"
- }
- ]
- },
- "raw-style-inline": {
- "name": "meta.style.vue",
- "match": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "captures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "source.css",
- "patterns": [
- {
- "include": "source.css"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- },
- "8": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style-inline-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*)(>)(.*?)()([Ss][Tt][Yy][Ll][Ee])(?=\\s*$)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "5": {
- "name": "source.css",
- "patterns": [
- {
- "include": "source.css"
- }
- ]
- },
- "6": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "7": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- }
- },
- "raw-style": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b([^>]*)(>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css",
- "patterns": [
- {
- "include": "source.css"
- }
- ]
- },
- "raw-style-ml": {
- "name": "meta.style.vue",
- "begin": "(<)([Ss][Tt][Yy][Ll][Ee])\\b(?![^>]*>)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "()([Ss][Tt][Yy][Ll][Ee])\\s*(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "entity.name.tag.vue"
- },
- "3": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "name": "meta.tag.vue",
- "begin": "\\G(?!\\blang\\s*=\\s*[\"']?(?:scss|less|stylus|postcss|sass)\\b)",
- "end": "(?=\\blang\\s*=\\s*[\"']?(?:scss|less|stylus|postcss|sass)\\b)|(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?scss\\b)",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.scss",
- "patterns": [
- {
- "include": "source.css.scss"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.scss",
- "patterns": [
- {
- "include": "source.css.scss"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?less\\b)",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.less",
- "patterns": [
- {
- "include": "source.css.less"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css.less",
- "patterns": [
- {
- "include": "source.css.less"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?stylus\\b)",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.stylus",
- "patterns": [
- {
- "include": "source.stylus"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.stylus",
- "patterns": [
- {
- "include": "source.stylus"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?postcss\\b)",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.postcss",
- "patterns": [
- {
- "include": "source.postcss"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.postcss",
- "patterns": [
- {
- "include": "source.postcss"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?=\\blang\\s*=\\s*[\"']?sass\\b)",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "patterns": [
- {
- "begin": "\\G",
- "end": "(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.sass",
- "patterns": [
- {
- "include": "source.sass"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.sass",
- "patterns": [
- {
- "include": "source.sass"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=>)(?=[^\\n]*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "end": "(?=[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css",
- "patterns": [
- {
- "include": "source.css"
- }
- ]
- },
- {
- "begin": "(?<=>)",
- "while": "^(?!.*[Ss][Tt][Yy][Ll][Ee](?:[\\s>]|$))",
- "contentName": "source.css",
- "patterns": [
- {
- "include": "source.css"
- }
- ]
- }
- ]
- },
- "tag": {
- "name": "meta.tag.vue",
- "begin": "(<)(/?)([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "2": {
- "name": "punctuation.definition.tag.begin.vue"
- },
- "3": {
- "name": "entity.name.tag.vue"
- }
- },
- "end": "(/?)(>)",
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.tag.end.vue"
- },
- "2": {
- "name": "punctuation.definition.tag.end.vue"
- }
- },
- "patterns": [
- {
- "include": "#attribute"
- }
- ]
- },
- "attribute": {
- "patterns": [
- {
- "begin": "(on[A-Za-z0-9_]+)(?![\\w:.-])",
- "beginCaptures": {
- "1": {
- "name": "entity.other.attribute-name.vue"
- }
- },
- "end": "(?=[\\s>/])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.vue"
- }
- },
- "contentName": "source.js",
- "patterns": [
- {
- "include": "source.js"
- }
- ]
- }
- ]
- },
- {
- "begin": "(style)(?![\\w:.-])",
- "beginCaptures": {
- "1": {
- "name": "entity.other.attribute-name.vue"
- }
- },
- "end": "(?=[\\s>/])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.css",
- "patterns": [
- {
- "include": "source.css#rule-list-innards"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.css",
- "patterns": [
- {
- "include": "source.css#rule-list-innards"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.vue"
- }
- },
- "contentName": "source.css",
- "patterns": [
- {
- "include": "source.css#rule-list-innards"
- }
- ]
- }
- ]
- },
- {
- "begin": "(generic)(?![\\w:.-])",
- "beginCaptures": {
- "1": {
- "name": "entity.other.attribute-name.vue"
- }
- },
- "end": "(?=[\\s>/])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.ts",
- "patterns": [
- {
- "include": "source.ts#comment"
- },
- {
- "name": "storage.modifier.ts",
- "match": "(?)"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- },
- "3": {
- "name": "source.ts",
- "patterns": [
- {
- "include": "source.ts#comment"
- },
- {
- "name": "storage.modifier.ts",
- "match": "(?)"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.vue"
- }
- },
- "contentName": "source.ts",
- "patterns": [
- {
- "include": "source.ts#comment"
- },
- {
- "name": "storage.modifier.ts",
- "match": "(?)"
- }
- ]
- }
- ]
- },
- {
- "match": "([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)(?=\\s*=)",
- "name": "entity.other.attribute-name.vue"
- },
- {
- "begin": "(=)\\s*",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.vue"
- }
- },
- "end": "(?=[\\s>])|(?<=[\"'])(?=/)",
- "patterns": [
- {
- "begin": "\"",
- "end": "\"",
- "name": "string.quoted.double.vue",
- "beginCaptures": {
- "0": {
- "name": "punctuation.definition.string.begin.vue"
- }
- },
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "begin": "'",
- "end": "'",
- "name": "string.quoted.single.vue",
- "beginCaptures": {
- "0": {
- "name": "punctuation.definition.string.begin.vue"
- }
- },
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.vue"
- }
- }
- },
- {
- "match": "[^\\s\"'<>=`]+",
- "name": "string.unquoted.vue"
- }
- ]
- },
- {
- "match": "([a-zA-Z][A-Za-z0-9_:.\\-\\p{L}\\p{Nl}\\p{Nd}\\p{Mn}\\p{Mc}\\p{Pc}]*)",
- "name": "entity.other.attribute-name.vue"
- }
- ]
- },
- "vue-interpolations": {
- "begin": "(\\{\\{)",
- "end": "(\\}\\})",
- "beginCaptures": {
- "1": {
- "name": "punctuation.definition.interpolation.begin.html.vue"
- }
- },
- "endCaptures": {
- "1": {
- "name": "punctuation.definition.interpolation.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "vue-directives": {
- "patterns": [
- {
- "begin": "(?<=[\\s<])(v-for)(?=[=\\s/>]|$)",
- "beginCaptures": {
- "1": {
- "name": "keyword.control.loop.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(v-if|v-else-if|v-else)(?=[=\\s/>]|$)",
- "beginCaptures": {
- "1": {
- "name": "keyword.control.conditional.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(:)(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?",
- "beginCaptures": {
- "1": {
- "name": "punctuation.attribute-shorthand.bind.html.vue"
- },
- "2": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "5": {
- "name": "entity.other.attribute-name.html.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(\\.)(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?",
- "beginCaptures": {
- "1": {
- "name": "punctuation.attribute-shorthand.bind.html.vue"
- },
- "2": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "5": {
- "name": "entity.other.attribute-name.html.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(@)(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?",
- "beginCaptures": {
- "1": {
- "name": "punctuation.attribute-shorthand.event.html.vue"
- },
- "2": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "5": {
- "name": "entity.other.attribute-name.html.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(#)(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?",
- "beginCaptures": {
- "1": {
- "name": "punctuation.attribute-shorthand.slot.html.vue"
- },
- "2": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "5": {
- "name": "entity.other.attribute-name.html.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- },
- {
- "begin": "(?<=[\\s<])(v-[\\w-]+)(?:(:)(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?)?",
- "beginCaptures": {
- "1": {
- "name": "entity.other.attribute-name.html.vue"
- },
- "2": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "3": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "4": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "5": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "6": {
- "name": "entity.other.attribute-name.html.vue"
- }
- },
- "end": "(?=[\\s/>])",
- "patterns": [
- {
- "match": "(=)\\s*(\")([^\"]*)(\")",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "match": "(=)\\s*(')([^']*)(')",
- "captures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- },
- "3": {
- "name": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- },
- "4": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- }
- },
- {
- "begin": "(=)\\s*([\"'])",
- "beginCaptures": {
- "1": {
- "name": "punctuation.separator.key-value.html.vue"
- },
- "2": {
- "name": "punctuation.definition.string.begin.html.vue"
- }
- },
- "end": "\\2",
- "endCaptures": {
- "0": {
- "name": "punctuation.definition.string.end.html.vue"
- }
- },
- "contentName": "source.ts.embedded.html.vue",
- "patterns": [
- {
- "include": "source.ts#expression"
- }
- ]
- }
- ]
- }
- ]
- }
- }
-}
diff --git a/vue.ts b/vue.ts
deleted file mode 100644
index 6032306..0000000
--- a/vue.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-// Vue Single-File Components — a markup language built by REUSING html.ts. A .vue file
-// is a set of top-level blocks (, ` mid-line (a `//` line comment, a string) and an
- // unterminated `type T =` must unwind at the close — so the body needs the `begin/while`
- // force-close (tmbundle#85, #5538/#2060). Style omits it: CSS is well-behaved, so it uses the
- // lookahead-end region that keeps a non-first DIALECT's close-line content in its dialect (#43).
- script: { default: 'source.js', lang: { ts: 'source.ts', tsx: 'source.tsx', jsx: 'source.js.jsx', coffee: 'source.coffee' }, forceClose: true },
- style: { default: 'source.css', lang: { scss: 'source.css.scss', less: 'source.css.less', stylus: 'source.stylus', postcss: 'source.postcss', sass: 'source.sass' } },
- },
- },
- // Custom-block embeds: ANY top-level block tag with `lang=""` embeds the mapped scope — the
- // Vue SFC custom-block convention (``, ``, ``).
- // Matches the hand-written grammar's generic `` catch-all. The common script/style/
- // template langs stay on the named rawText blocks above; these data langs (which have no named
- // block) are caught here on whatever tag carries them.
- customBlockEmbed: {
- md: 'text.html.markdown',
- json: 'source.json', jsonc: 'source.json.comments', json5: 'source.json5',
- yaml: 'source.yaml', toml: 'source.toml', gql: 'source.graphql', graphql: 'source.graphql',
- },
- // Directives + {{ }} interpolation, INJECTED onto the embedded HTML's scopes (Vue syntax
- // can't be baked into the reused HTML grammar — it injects on top). Emitted as TWO thin-stub
- // files (vue-directives.json / vue-interpolations.json) whose rules live in this grammar's
- // repository — the exact official topology, so they're byte-diffable against Volar's. The
- // selectors are the official ones (directives on the tag scope, interpolation on the
- // embedded-HTML/markdown/pug scopes); the generator appends `-source.ts.embedded.html.vue`
- // to each (the #5722 re-fire guard). Values + interpolation embed Monogram's OWN TS.
- inject: {
- exprEmbed: 'source.ts.embedded.html.vue',
- // `{{ }}` and directive values are EXPRESSIONS, not programs — embed the derived
- // expression-only sub-grammar so `{{ const x }}`/`{{ for(…) }}` don't mis-highlight
- // statement keywords (a nested block still re-enters the full grammar via $self).
- exprInclude: 'source.ts#expression',
- interpolation: {
- scopeName: 'vue.interpolations',
- repoKey: 'vue-interpolations',
- // Interpolation lives in TEXT content → inject onto the embedded-HTML-fragment scope
- // (+ markdown / pug hosts, like the official, so `{{ }}` lights in Vue-in-md/pug too).
- selector: [
- { scope: 'text.html.derivative', excludes: ['comment.block'] },
- { scope: 'text.html.markdown', excludes: ['comment.block'] },
- { scope: 'text.pug', excludes: ['comment', 'string.comment'] },
- ],
- open: '{{', close: '}}',
- beginScope: 'punctuation.definition.interpolation.begin.html.vue',
- endScope: 'punctuation.definition.interpolation.end.html.vue',
- },
- directives: {
- scopeName: 'vue.directives',
- repoKey: 'vue-directives',
- // Directives live in TAG-ATTRIBUTE position → inject onto the tag scope. The official's
- // per-clause excludes keep them from re-firing inside an attribute value / JSX / pug name.
- selector: [
- { scope: 'meta.tag', excludes: ['meta.attribute', 'meta.ng-binding', 'entity.name.tag.pug', 'attribute_value', 'source.tsx', 'source.js.jsx'] },
- { scope: 'meta.element', excludes: ['meta.attribute'] },
- ],
- control: [
- { match: 'v-for', scope: 'keyword.control.loop.vue' },
- { match: altPattern('v-if', 'v-else-if', 'v-else'), scope: 'keyword.control.conditional.vue' },
- ],
- shorthand: [
- { char: ':', scope: 'punctuation.attribute-shorthand.bind.html.vue' },
- // `.prop` is Vue's shorthand for `v-bind:prop.prop` — a bind shorthand, same scope as
- // `:` (vuejs/language-tools#3727). The directive arg (`prop`) is then parsed by the
- // shared arg-capture, so its value embeds like any other bind directive.
- { char: '.', scope: 'punctuation.attribute-shorthand.bind.html.vue' },
- { char: '@', scope: 'punctuation.attribute-shorthand.event.html.vue' },
- { char: '#', scope: 'punctuation.attribute-shorthand.slot.html.vue' },
- ],
- prefix: 'v-',
- nameScope: 'entity.other.attribute-name.html.vue',
- eqScope: 'punctuation.separator.key-value.html.vue',
- // The quotes around a directive value — string punctuation, matching the official.
- valueString: { begin: 'punctuation.definition.string.begin.html.vue', end: 'punctuation.definition.string.end.html.vue' },
- },
- },
- },
-});