@arborium/arborium 1.2.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +113 -0
  2. package/dist/arborium.iife.js +2 -2
  3. package/dist/arborium.iife.js.map +1 -1
  4. package/dist/arborium.js +122 -98
  5. package/dist/arborium.js.map +1 -1
  6. package/dist/arborium_host.js +39 -9
  7. package/dist/arborium_host_bg.wasm +0 -0
  8. package/dist/index.d.ts +2 -1
  9. package/dist/plugins-manifest.d.ts +2 -0
  10. package/dist/themes/alabaster.css +1 -0
  11. package/dist/themes/ayu-dark.css +1 -0
  12. package/dist/themes/ayu-light.css +1 -0
  13. package/dist/themes/base-rustdoc.css +69 -426
  14. package/dist/themes/base.css +0 -8
  15. package/dist/themes/catppuccin-frappe.css +1 -0
  16. package/dist/themes/catppuccin-latte.css +1 -0
  17. package/dist/themes/catppuccin-macchiato.css +1 -0
  18. package/dist/themes/catppuccin-mocha.css +1 -0
  19. package/dist/themes/cobalt2.css +1 -0
  20. package/dist/themes/dayfox.css +1 -0
  21. package/dist/themes/desert256.css +1 -0
  22. package/dist/themes/dracula.css +1 -0
  23. package/dist/themes/ef-melissa-dark.css +1 -0
  24. package/dist/themes/github-dark.css +1 -0
  25. package/dist/themes/github-light.css +1 -0
  26. package/dist/themes/gruvbox-dark.css +1 -0
  27. package/dist/themes/gruvbox-light.css +1 -0
  28. package/dist/themes/kanagawa-dragon.css +1 -0
  29. package/dist/themes/light-owl.css +1 -0
  30. package/dist/themes/lucius-light.css +1 -0
  31. package/dist/themes/melange-dark.css +1 -0
  32. package/dist/themes/melange-light.css +1 -0
  33. package/dist/themes/monokai.css +1 -0
  34. package/dist/themes/nord.css +1 -0
  35. package/dist/themes/one-dark.css +1 -0
  36. package/dist/themes/rose-pine-moon.css +1 -0
  37. package/dist/themes/rustdoc-ayu.css +68 -67
  38. package/dist/themes/rustdoc-dark.css +68 -67
  39. package/dist/themes/rustdoc-light.css +68 -67
  40. package/dist/themes/solarized-dark.css +1 -0
  41. package/dist/themes/solarized-light.css +1 -0
  42. package/dist/themes/tokyo-night.css +1 -0
  43. package/dist/themes/zenburn.css +1 -0
  44. package/dist/types.d.ts +38 -1
  45. package/package.json +1 -1
package/dist/arborium.js CHANGED
@@ -1,4 +1,4 @@
1
- const x = [
1
+ const x = "2.1.0", $ = [
2
2
  "ada",
3
3
  "agda",
4
4
  "asciidoc",
@@ -100,60 +100,61 @@ const x = [
100
100
  theme: "one-dark",
101
101
  selector: "pre code",
102
102
  cdn: "jsdelivr",
103
- version: "1",
104
- // Major version - allows patch/minor upgrades via CDN
103
+ version: x,
104
+ // Precise version from manifest
105
105
  pluginsUrl: "",
106
106
  // Empty means use bundled manifest
107
107
  hostUrl: ""
108
108
  // Empty means use CDN based on version
109
109
  };
110
- let p = null, b = null, i = { ...L };
111
- const g = /* @__PURE__ */ new Map(), j = new Set(x);
112
- let l = null, f = null;
113
- async function $() {
114
- if (i.pluginsUrl)
115
- return f || (f = (async () => {
116
- console.debug(`[arborium] Loading local plugins manifest from: ${i.pluginsUrl}`);
117
- const s = await fetch(i.pluginsUrl);
110
+ let p = null, f = null, o = { ...L };
111
+ const g = /* @__PURE__ */ new Map(), j = new Set($);
112
+ let l = null, b = null;
113
+ async function _() {
114
+ if (o.pluginsUrl)
115
+ return b || (b = (async () => {
116
+ console.debug(`[arborium] Loading local plugins manifest from: ${o.pluginsUrl}`);
117
+ const s = await fetch(o.pluginsUrl);
118
118
  if (!s.ok)
119
119
  throw new Error(`Failed to load plugins.json: ${s.status}`);
120
120
  l = await s.json(), console.debug(`[arborium] Loaded local manifest with ${l?.entries.length} entries`);
121
- })(), f);
121
+ })(), b);
122
122
  }
123
123
  function U(s) {
124
124
  if (l) {
125
- const n = l.entries.find((e) => e.language === s);
126
- if (n)
127
- return n.local_js.substring(0, n.local_js.lastIndexOf("/"));
125
+ const a = l.entries.find((r) => r.language === s);
126
+ if (a)
127
+ return a.local_js.substring(0, a.local_js.lastIndexOf("/"));
128
128
  }
129
- const r = i.cdn;
130
- let t;
131
- return r === "jsdelivr" ? t = "https://cdn.jsdelivr.net/npm" : r === "unpkg" ? t = "https://unpkg.com" : t = r, `${t}/@arborium/${s}@1`;
129
+ const e = o.cdn, t = o.version;
130
+ let n;
131
+ return e === "jsdelivr" ? n = "https://cdn.jsdelivr.net/npm" : e === "unpkg" ? n = "https://unpkg.com" : n = e, `${n}/@arborium/${s}@${t}`;
132
132
  }
133
133
  async function w(s) {
134
- const r = g.get(s);
135
- if (r)
136
- return console.debug(`[arborium] Grammar '${s}' found in cache`), r;
137
- if (await $(), !j.has(s) && !l?.entries.some((t) => t.language === s))
134
+ const e = g.get(s);
135
+ if (e)
136
+ return console.debug(`[arborium] Grammar '${s}' found in cache`), e;
137
+ if (await _(), !j.has(s) && !l?.entries.some((t) => t.language === s))
138
138
  return console.debug(`[arborium] Grammar '${s}' not available`), null;
139
139
  try {
140
- const t = U(s), n = `${t}/grammar.js`, e = `${t}/grammar_bg.wasm`;
140
+ const t = U(s), n = `${t}/grammar.js`, a = `${t}/grammar_bg.wasm`;
141
141
  console.debug(`[arborium] Loading grammar '${s}' from ${n}`);
142
- const a = await import(
142
+ const r = await import(
143
143
  /* @vite-ignore */
144
144
  n
145
145
  );
146
- await a.default(e);
147
- const o = a.language_id();
148
- o !== s && console.warn(`[arborium] Language ID mismatch: expected '${s}', got '${o}'`);
149
- const c = a.injection_languages(), y = {
146
+ await r.default(a);
147
+ const i = r.language_id();
148
+ i !== s && console.warn(`[arborium] Language ID mismatch: expected '${s}', got '${i}'`);
149
+ const c = r.injection_languages(), y = {
150
150
  languageId: s,
151
151
  injectionLanguages: c,
152
+ module: r,
152
153
  parse: (k) => {
153
- const m = a.create_session();
154
+ const m = r.create_session();
154
155
  try {
155
- a.set_text(m, k);
156
- const u = a.parse(m);
156
+ r.set_text(m, k);
157
+ const u = r.parse(m);
157
158
  return {
158
159
  spans: u.spans || [],
159
160
  injections: u.injections || []
@@ -161,7 +162,7 @@ async function w(s) {
161
162
  } catch (u) {
162
163
  return console.error("[arborium] Parse error:", u), { spans: [], injections: [] };
163
164
  } finally {
164
- a.free_session(m);
165
+ r.free_session(m);
165
166
  }
166
167
  }
167
168
  };
@@ -172,7 +173,7 @@ async function w(s) {
172
173
  }
173
174
  const d = /* @__PURE__ */ new Map();
174
175
  let T = 1;
175
- function _() {
176
+ function E() {
176
177
  window.arboriumHost = {
177
178
  /** Check if a language is available (sync) */
178
179
  isLanguageAvailable(s) {
@@ -180,38 +181,38 @@ function _() {
180
181
  },
181
182
  /** Load a grammar and return a handle (async) */
182
183
  async loadGrammar(s) {
183
- const r = await w(s);
184
- if (!r) return 0;
185
- for (const [n, e] of d)
186
- if (e === r) return n;
184
+ const e = await w(s);
185
+ if (!e) return 0;
186
+ for (const [n, a] of d)
187
+ if (a === e) return n;
187
188
  const t = T++;
188
- return d.set(t, r), t;
189
+ return d.set(t, e), t;
189
190
  },
190
191
  /** Parse text using a grammar handle (sync) */
191
- parse(s, r) {
192
+ parse(s, e) {
192
193
  const t = d.get(s);
193
- return t ? t.parse(r) : { spans: [], injections: [] };
194
+ return t ? t.parse(e) : { spans: [], injections: [] };
194
195
  }
195
196
  };
196
197
  }
197
- function E() {
198
- if (i.hostUrl)
199
- return i.hostUrl;
200
- const s = i.cdn, r = i.version;
198
+ function S() {
199
+ if (o.hostUrl)
200
+ return o.hostUrl;
201
+ const s = o.cdn, e = o.version;
201
202
  let t;
202
203
  s === "jsdelivr" ? t = "https://cdn.jsdelivr.net/npm" : s === "unpkg" ? t = "https://unpkg.com" : t = s;
203
- const n = r === "latest" ? "" : `@${r}`;
204
+ const n = e === "latest" ? "" : `@${e}`;
204
205
  return `${t}/@arborium/arborium${n}/dist`;
205
206
  }
206
207
  async function W() {
207
- return p || b || (b = (async () => {
208
- _();
209
- const s = E(), r = `${s}/arborium_host.js`, t = `${s}/arborium_host_bg.wasm`;
210
- console.debug(`[arborium] Loading host from ${r}`);
208
+ return p || f || (f = (async () => {
209
+ E();
210
+ const s = S(), e = `${s}/arborium_host.js`, t = `${s}/arborium_host_bg.wasm`;
211
+ console.debug(`[arborium] Loading host from ${e}`);
211
212
  try {
212
213
  const n = await import(
213
214
  /* @vite-ignore */
214
- r
215
+ e
215
216
  );
216
217
  return await n.default(t), p = {
217
218
  highlight: n.highlight,
@@ -220,46 +221,67 @@ async function W() {
220
221
  } catch (n) {
221
222
  return console.error("[arborium] Failed to load host:", n), null;
222
223
  }
223
- })(), b);
224
+ })(), f);
224
225
  }
225
- async function q(s, r, t) {
226
+ async function R(s, e, t) {
226
227
  const n = await W();
227
228
  if (n)
228
229
  try {
229
- return n.highlight(s, r);
230
- } catch (o) {
231
- console.warn("Host highlight failed, falling back to JS:", o);
230
+ return n.highlight(s, e);
231
+ } catch (i) {
232
+ console.warn("Host highlight failed, falling back to JS:", i);
232
233
  }
233
- const e = await w(s);
234
- if (!e)
235
- return h(r);
236
- const a = e.parse(r);
237
- return v(r, a.spans);
234
+ const a = await w(s);
235
+ if (!a)
236
+ return h(e);
237
+ const r = a.parse(e);
238
+ return v(e, r.spans);
238
239
  }
239
- async function R(s, r) {
240
+ async function H(s, e) {
240
241
  const t = await w(s);
241
- return t ? {
242
+ if (!t) return null;
243
+ const { module: n } = t;
244
+ return {
242
245
  languageId: () => t.languageId,
243
246
  injectionLanguages: () => t.injectionLanguages,
244
- highlight: async (n) => {
245
- const e = t.parse(n);
246
- return v(n, e.spans);
247
+ highlight: async (a) => {
248
+ const r = t.parse(a);
249
+ return v(a, r.spans);
250
+ },
251
+ parse: (a) => t.parse(a),
252
+ createSession: () => {
253
+ const a = n.create_session();
254
+ return {
255
+ setText: (r) => n.set_text(a, r),
256
+ parse: () => {
257
+ try {
258
+ const r = n.parse(a);
259
+ return {
260
+ spans: r.spans || [],
261
+ injections: r.injections || []
262
+ };
263
+ } catch (r) {
264
+ return console.error("[arborium] Session parse error:", r), { spans: [], injections: [] };
265
+ }
266
+ },
267
+ cancel: () => n.cancel(a),
268
+ free: () => n.free_session(a)
269
+ };
247
270
  },
248
- parse: (n) => t.parse(n),
249
271
  dispose: () => {
250
272
  }
251
- } : null;
273
+ };
252
274
  }
253
- function v(s, r) {
254
- const t = [...r].sort((a, o) => a.start - o.start);
255
- let n = "", e = 0;
256
- for (const a of t) {
257
- if (a.start < e) continue;
258
- a.start > e && (n += h(s.slice(e, a.start)));
259
- const o = C(a.capture), c = h(s.slice(a.start, a.end));
260
- o ? n += `<a-${o}>${c}</a-${o}>` : n += c, e = a.end;
275
+ function v(s, e) {
276
+ const t = [...e].sort((r, i) => r.start - i.start);
277
+ let n = "", a = 0;
278
+ for (const r of t) {
279
+ if (r.start < a) continue;
280
+ r.start > a && (n += h(s.slice(a, r.start)));
281
+ const i = C(r.capture), c = h(s.slice(r.start, r.end));
282
+ i ? n += `<a-${i}>${c}</a-${i}>` : n += c, a = r.end;
261
283
  }
262
- return e < s.length && (n += h(s.slice(e))), n;
284
+ return a < s.length && (n += h(s.slice(a))), n;
263
285
  }
264
286
  function C(s) {
265
287
  return s.startsWith("keyword") || s === "include" || s === "conditional" ? "k" : s.startsWith("function") || s.startsWith("method") ? "f" : s.startsWith("string") || s === "character" ? "s" : s.startsWith("comment") ? "c" : s.startsWith("type") ? "t" : s.startsWith("variable") ? "v" : s.startsWith("number") || s === "float" ? "n" : s.startsWith("operator") ? "o" : s.startsWith("punctuation") ? "p" : s.startsWith("tag") ? "tg" : s.startsWith("attribute") ? "at" : null;
@@ -267,8 +289,8 @@ function C(s) {
267
289
  function h(s) {
268
290
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
269
291
  }
270
- function H(s) {
271
- return s ? { ...i, ...s } : { ...i };
292
+ function M(s) {
293
+ return s ? { ...o, ...s } : { ...o };
272
294
  }
273
295
  const I = [
274
296
  [/^#!.*\bpython[23]?\b/, "python"],
@@ -283,7 +305,7 @@ const I = [
283
305
  [/^#!.*\bsh\b/, "bash"],
284
306
  [/^#!.*\blua\b/, "lua"],
285
307
  [/^#!.*\bawk\b/, "awk"]
286
- ], S = [
308
+ ], q = [
287
309
  // Rust - distinctive keywords
288
310
  [/\b(fn|impl|trait|pub\s+fn|let\s+mut|&mut|->)\b/, "rust"],
289
311
  // Go - distinctive keywords
@@ -343,20 +365,20 @@ const I = [
343
365
  // Zig
344
366
  [/\b(pub\s+fn|const\s+\w+\s*=|@import\(|comptime)\b/, "zig"]
345
367
  ];
346
- function M(s) {
347
- const r = s.split(`
368
+ function P(s) {
369
+ const e = s.split(`
348
370
  `)[0];
349
371
  for (const [t, n] of I)
350
- if (t.test(r))
372
+ if (t.test(e))
351
373
  return n;
352
- for (const [t, n] of S)
374
+ for (const [t, n] of q)
353
375
  if (t.test(s))
354
376
  return n;
355
377
  return null;
356
378
  }
357
- function P(s) {
358
- const r = s.match(/\blanguage-(\w+)\b/);
359
- if (r) return r[1];
379
+ function A(s) {
380
+ const e = s.match(/\blanguage-(\w+)\b/);
381
+ if (e) return e[1];
360
382
  const t = s.match(/\blang-(\w+)\b/);
361
383
  if (t) return t[1];
362
384
  const n = /* @__PURE__ */ new Set([
@@ -395,13 +417,13 @@ function P(s) {
395
417
  "console",
396
418
  "sh"
397
419
  ]);
398
- for (const e of s.split(/\s+/))
399
- if (n.has(e.toLowerCase()))
400
- return e.toLowerCase();
420
+ for (const a of s.split(/\s+/))
421
+ if (n.has(a.toLowerCase()))
422
+ return a.toLowerCase();
401
423
  return null;
402
424
  }
403
- function A(s) {
404
- const r = {
425
+ function G(s) {
426
+ const e = {
405
427
  js: "javascript",
406
428
  ts: "typescript",
407
429
  py: "python",
@@ -422,15 +444,17 @@ function A(s) {
422
444
  plain: "text",
423
445
  txt: "text"
424
446
  }, t = s.toLowerCase();
425
- return r[t] || t;
447
+ return e[t] || t;
426
448
  }
427
449
  export {
428
- M as detectLanguage,
429
- P as extractLanguageFromClass,
430
- H as getConfig,
431
- q as highlight,
432
- R as loadGrammar,
433
- A as normalizeLanguage,
450
+ $ as availableLanguages,
451
+ P as detectLanguage,
452
+ A as extractLanguageFromClass,
453
+ M as getConfig,
454
+ R as highlight,
455
+ H as loadGrammar,
456
+ G as normalizeLanguage,
457
+ x as pluginVersion,
434
458
  v as spansToHtml
435
459
  };
436
460
  //# sourceMappingURL=arborium.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"arborium.js","sources":["../src/plugins-manifest.ts","../src/loader.ts","../src/detect.ts"],"sourcesContent":["// AUTO-GENERATED by `cargo xtask gen-manifest` - DO NOT EDIT\n\n/** All available languages */\nexport const availableLanguages: string[] = [\n \"ada\",\n \"agda\",\n \"asciidoc\",\n \"asm\",\n \"awk\",\n \"bash\",\n \"batch\",\n \"c\",\n \"c-sharp\",\n \"caddy\",\n \"capnp\",\n \"clojure\",\n \"cmake\",\n \"commonlisp\",\n \"cpp\",\n \"css\",\n \"d\",\n \"dart\",\n \"devicetree\",\n \"diff\",\n \"dockerfile\",\n \"dot\",\n \"elisp\",\n \"elixir\",\n \"elm\",\n \"erlang\",\n \"fish\",\n \"fsharp\",\n \"gleam\",\n \"glsl\",\n \"go\",\n \"graphql\",\n \"haskell\",\n \"hcl\",\n \"hlsl\",\n \"html\",\n \"idris\",\n \"ini\",\n \"java\",\n \"javascript\",\n \"jinja2\",\n \"jq\",\n \"json\",\n \"julia\",\n \"kdl\",\n \"kotlin\",\n \"lean\",\n \"lua\",\n \"markdown\",\n \"matlab\",\n \"meson\",\n \"nginx\",\n \"ninja\",\n \"nix\",\n \"objc\",\n \"ocaml\",\n \"perl\",\n \"php\",\n \"postscript\",\n \"powershell\",\n \"prolog\",\n \"python\",\n \"query\",\n \"r\",\n \"rescript\",\n \"ron\",\n \"ruby\",\n \"rust\",\n \"scala\",\n \"scheme\",\n \"scss\",\n \"sparql\",\n \"sql\",\n \"ssh-config\",\n \"starlark\",\n \"svelte\",\n \"swift\",\n \"textproto\",\n \"thrift\",\n \"tlaplus\",\n \"toml\",\n \"tsx\",\n \"typescript\",\n \"typst\",\n \"uiua\",\n \"vb\",\n \"verilog\",\n \"vhdl\",\n \"vim\",\n \"vue\",\n \"x86asm\",\n \"xml\",\n \"yaml\",\n \"yuri\",\n \"zig\",\n \"zsh\",\n];","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Grammar registry is bundled at build time (no network request needed in production)\n * - Can be overridden via pluginsUrl config for local development\n * 2. Load grammar wasm-bindgen modules on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport type { ParseResult, ArboriumConfig, Grammar, Span, Injection } from \"./types.js\";\nimport { availableLanguages } from \"./plugins-manifest.js\";\n\n// Default config\nexport const defaultConfig: Required<ArboriumConfig> = {\n manual: false,\n theme: \"one-dark\",\n selector: \"pre code\",\n cdn: \"jsdelivr\",\n version: \"1\", // Major version - allows patch/minor upgrades via CDN\n pluginsUrl: \"\", // Empty means use bundled manifest\n hostUrl: \"\", // Empty means use CDN based on version\n};\n\n// Rust host module (loaded on demand)\ninterface HostModule {\n highlight: (language: string, source: string) => string;\n isLanguageAvailable: (language: string) => boolean;\n}\nlet hostModule: HostModule | null = null;\nlet hostLoadPromise: Promise<HostModule | null> | null = null;\n\n// Merged config\nlet config: Required<ArboriumConfig> = { ...defaultConfig };\n\n// Grammar plugins cache\nconst grammarCache = new Map<string, GrammarPlugin>();\n\n// Languages we know are available (bundled at build time)\nconst knownLanguages: Set<string> = new Set(availableLanguages);\n\n// For local development: can override with pluginsUrl to load from dev server\ninterface LocalManifest {\n entries: Array<{\n language: string;\n local_js: string;\n local_wasm: string;\n }>;\n}\nlet localManifest: LocalManifest | null = null;\nlet localManifestPromise: Promise<void> | null = null;\n\n/** Load local manifest if pluginsUrl is configured (for dev server) */\nasync function ensureLocalManifest(): Promise<void> {\n if (!config.pluginsUrl) {\n return;\n }\n\n if (localManifestPromise) {\n return localManifestPromise;\n }\n\n localManifestPromise = (async () => {\n console.debug(`[arborium] Loading local plugins manifest from: ${config.pluginsUrl}`);\n const response = await fetch(config.pluginsUrl);\n if (!response.ok) {\n throw new Error(`Failed to load plugins.json: ${response.status}`);\n }\n localManifest = await response.json();\n console.debug(`[arborium] Loaded local manifest with ${localManifest?.entries.length} entries`);\n })();\n\n return localManifestPromise;\n}\n\n/** Get the CDN base URL for a grammar */\nfunction getGrammarBaseUrl(language: string): string {\n // If we have a local manifest (dev mode), use the local path\n if (localManifest) {\n const entry = localManifest.entries.find((e) => e.language === language);\n if (entry) {\n // Extract base URL from local_js path (e.g., \"/langs/group-hazel/python/npm/grammar.js\" -> \"/langs/group-hazel/python/npm\")\n return entry.local_js.substring(0, entry.local_js.lastIndexOf(\"/\"));\n }\n }\n\n // Production: derive from language name using @1 (major version)\n const cdn = config.cdn;\n let baseUrl: string;\n if (cdn === \"jsdelivr\") {\n baseUrl = \"https://cdn.jsdelivr.net/npm\";\n } else if (cdn === \"unpkg\") {\n baseUrl = \"https://unpkg.com\";\n } else {\n baseUrl = cdn;\n }\n return `${baseUrl}/@arborium/${language}@1`;\n}\n\n/** wasm-bindgen plugin module interface */\ninterface WasmBindgenPlugin {\n default: (wasmUrl: string) => Promise<void>;\n language_id: () => string;\n injection_languages: () => string[];\n create_session: () => number;\n free_session: (session: number) => void;\n set_text: (session: number, text: string) => void;\n parse: (session: number) => ParseResult;\n cancel: (session: number) => void;\n}\n\n/** A loaded grammar plugin */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n parse: (text: string) => ParseResult;\n}\n\n/** Load a grammar plugin */\nasync function loadGrammarPlugin(language: string): Promise<GrammarPlugin | null> {\n // Check cache\n const cached = grammarCache.get(language);\n if (cached) {\n console.debug(`[arborium] Grammar '${language}' found in cache`);\n return cached;\n }\n\n // Load local manifest if in dev mode\n await ensureLocalManifest();\n\n // Check if language is known\n if (\n !knownLanguages.has(language) &&\n !localManifest?.entries.some((e) => e.language === language)\n ) {\n console.debug(`[arborium] Grammar '${language}' not available`);\n return null;\n }\n\n try {\n const baseUrl = getGrammarBaseUrl(language);\n const jsUrl = `${baseUrl}/grammar.js`;\n const wasmUrl = `${baseUrl}/grammar_bg.wasm`;\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n\n // Dynamically import the wasm-bindgen generated JS module\n const module = (await import(/* @vite-ignore */ jsUrl)) as WasmBindgenPlugin;\n\n // Initialize the WASM module\n await module.default(wasmUrl);\n\n // Verify it loaded correctly\n const loadedId = module.language_id();\n if (loadedId !== language) {\n console.warn(`[arborium] Language ID mismatch: expected '${language}', got '${loadedId}'`);\n }\n\n // Get injection languages\n const injectionLanguages = module.injection_languages();\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages,\n parse: (text: string) => {\n const session = module.create_session();\n try {\n module.set_text(session, text);\n // wasm-bindgen returns ParseResult directly (or throws on error)\n const result = module.parse(session);\n return {\n spans: result.spans || [],\n injections: result.injections || [],\n };\n } catch (e) {\n console.error(`[arborium] Parse error:`, e);\n return { spans: [], injections: [] };\n } finally {\n module.free_session(session);\n }\n },\n };\n\n grammarCache.set(language, plugin);\n console.debug(`[arborium] Grammar '${language}' loaded successfully`);\n return plugin;\n } catch (e) {\n console.error(`[arborium] Failed to load grammar '${language}':`, e);\n return null;\n }\n}\n\n// Handle to plugin mapping for the host interface\nconst handleToPlugin = new Map<number, GrammarPlugin>();\nlet nextHandle = 1;\n\n/** Setup window.arboriumHost for the Rust host to call into */\nfunction setupHostInterface(): void {\n (window as any).arboriumHost = {\n /** Check if a language is available (sync) */\n isLanguageAvailable(language: string): boolean {\n return knownLanguages.has(language) || grammarCache.has(language);\n },\n\n /** Load a grammar and return a handle (async) */\n async loadGrammar(language: string): Promise<number> {\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) return 0; // 0 = not found\n\n // Check if we already have a handle\n for (const [handle, p] of handleToPlugin) {\n if (p === plugin) return handle;\n }\n\n // Create new handle\n const handle = nextHandle++;\n handleToPlugin.set(handle, plugin);\n return handle;\n },\n\n /** Parse text using a grammar handle (sync) */\n parse(handle: number, text: string): ParseResult {\n const plugin = handleToPlugin.get(handle);\n if (!plugin) return { spans: [], injections: [] };\n return plugin.parse(text);\n },\n };\n}\n\n/** Get the host URL based on config */\nfunction getHostUrl(): string {\n if (config.hostUrl) {\n return config.hostUrl;\n }\n // Use CDN\n const cdn = config.cdn;\n const version = config.version;\n let baseUrl: string;\n if (cdn === \"jsdelivr\") {\n baseUrl = \"https://cdn.jsdelivr.net/npm\";\n } else if (cdn === \"unpkg\") {\n baseUrl = \"https://unpkg.com\";\n } else {\n baseUrl = cdn;\n }\n const versionSuffix = version === \"latest\" ? \"\" : `@${version}`;\n return `${baseUrl}/@arborium/arborium${versionSuffix}/dist`;\n}\n\n/** Load the Rust host module */\nasync function loadHost(): Promise<HostModule | null> {\n if (hostModule) return hostModule;\n if (hostLoadPromise) return hostLoadPromise;\n\n hostLoadPromise = (async () => {\n // Setup the interface the host imports\n setupHostInterface();\n\n const hostUrl = getHostUrl();\n const jsUrl = `${hostUrl}/arborium_host.js`;\n const wasmUrl = `${hostUrl}/arborium_host_bg.wasm`;\n\n console.debug(`[arborium] Loading host from ${jsUrl}`);\n try {\n const module = await import(/* @vite-ignore */ jsUrl);\n await module.default(wasmUrl);\n\n hostModule = {\n highlight: module.highlight,\n isLanguageAvailable: module.isLanguageAvailable,\n };\n console.debug(`[arborium] Host loaded successfully`);\n return hostModule;\n } catch (e) {\n console.error(\"[arborium] Failed to load host:\", e);\n return null;\n }\n })();\n\n return hostLoadPromise;\n}\n\n/** Highlight source code */\nexport async function highlight(\n language: string,\n source: string,\n _config?: ArboriumConfig,\n): Promise<string> {\n // Try to use the Rust host (handles injections properly)\n const host = await loadHost();\n if (host) {\n try {\n return host.highlight(language, source);\n } catch (e) {\n console.warn(\"Host highlight failed, falling back to JS:\", e);\n }\n }\n\n // Fallback to JS-only highlighting (no injection support)\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) {\n return escapeHtml(source);\n }\n\n const result = plugin.parse(source);\n return spansToHtml(source, result.spans);\n}\n\n/** Load a grammar for direct use */\nexport async function loadGrammar(\n language: string,\n _config?: ArboriumConfig,\n): Promise<Grammar | null> {\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) return null;\n\n return {\n languageId: () => plugin.languageId,\n injectionLanguages: () => plugin.injectionLanguages,\n highlight: async (source: string) => {\n const result = plugin.parse(source);\n return spansToHtml(source, result.spans);\n },\n parse: (source: string) => plugin.parse(source),\n dispose: () => {\n // No-op for now, plugins are cached\n },\n };\n}\n\n/** Convert spans to HTML */\nexport function spansToHtml(source: string, spans: Span[]): string {\n // Sort spans by start position\n const sorted = [...spans].sort((a, b) => a.start - b.start);\n\n let html = \"\";\n let pos = 0;\n\n for (const span of sorted) {\n // Skip overlapping spans\n if (span.start < pos) continue;\n\n // Add text before span\n if (span.start > pos) {\n html += escapeHtml(source.slice(pos, span.start));\n }\n\n // Get tag for capture\n const tag = getTagForCapture(span.capture);\n const text = escapeHtml(source.slice(span.start, span.end));\n\n if (tag) {\n html += `<a-${tag}>${text}</a-${tag}>`;\n } else {\n html += text;\n }\n\n pos = span.end;\n }\n\n // Add remaining text\n if (pos < source.length) {\n html += escapeHtml(source.slice(pos));\n }\n\n return html;\n}\n\n/** Get the short tag for a capture name */\nfunction getTagForCapture(capture: string): string | null {\n if (capture.startsWith(\"keyword\") || capture === \"include\" || capture === \"conditional\") {\n return \"k\";\n }\n if (capture.startsWith(\"function\") || capture.startsWith(\"method\")) {\n return \"f\";\n }\n if (capture.startsWith(\"string\") || capture === \"character\") {\n return \"s\";\n }\n if (capture.startsWith(\"comment\")) {\n return \"c\";\n }\n if (capture.startsWith(\"type\")) {\n return \"t\";\n }\n if (capture.startsWith(\"variable\")) {\n return \"v\";\n }\n if (capture.startsWith(\"number\") || capture === \"float\") {\n return \"n\";\n }\n if (capture.startsWith(\"operator\")) {\n return \"o\";\n }\n if (capture.startsWith(\"punctuation\")) {\n return \"p\";\n }\n if (capture.startsWith(\"tag\")) {\n return \"tg\";\n }\n if (capture.startsWith(\"attribute\")) {\n return \"at\";\n }\n return null;\n}\n\n/** Escape HTML special characters */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n/** Get current config, optionally merging with overrides */\nexport function getConfig(overrides?: Partial<ArboriumConfig>): Required<ArboriumConfig> {\n if (overrides) {\n return { ...config, ...overrides };\n }\n return { ...config };\n}\n\n/** Set/merge config */\nexport function setConfig(newConfig: Partial<ArboriumConfig>): void {\n config = { ...config, ...newConfig };\n}\n\n/** Check if a language is available */\nexport async function isLanguageAvailable(language: string): Promise<boolean> {\n await ensureLocalManifest();\n return (\n knownLanguages.has(language) ||\n (localManifest?.entries.some((e) => e.language === language) ?? false)\n );\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await ensureLocalManifest();\n // In dev mode, use local manifest if available\n if (localManifest) {\n return localManifest.entries.map((e) => e.language);\n }\n return Array.from(knownLanguages);\n}\n","/**\n * Simple language detection heuristics.\n * Not meant to be comprehensive - just catches common cases.\n */\n\n/** Shebang patterns */\nconst SHEBANG_PATTERNS: Array<[RegExp, string]> = [\n [/^#!.*\\bpython[23]?\\b/, 'python'],\n [/^#!.*\\bnode\\b/, 'javascript'],\n [/^#!.*\\bdeno\\b/, 'typescript'],\n [/^#!.*\\bbun\\b/, 'typescript'],\n [/^#!.*\\bruby\\b/, 'ruby'],\n [/^#!.*\\bperl\\b/, 'perl'],\n [/^#!.*\\bphp\\b/, 'php'],\n [/^#!.*\\bbash\\b/, 'bash'],\n [/^#!.*\\bzsh\\b/, 'zsh'],\n [/^#!.*\\bsh\\b/, 'bash'],\n [/^#!.*\\blua\\b/, 'lua'],\n [/^#!.*\\bawk\\b/, 'awk'],\n];\n\n/** Keyword fingerprints - first few unique keywords that identify a language */\nconst KEYWORD_FINGERPRINTS: Array<[RegExp, string]> = [\n // Rust - distinctive keywords\n [/\\b(fn|impl|trait|pub\\s+fn|let\\s+mut|&mut|->)\\b/, 'rust'],\n\n // Go - distinctive keywords\n [/\\b(func|package\\s+\\w+|import\\s+\\(|go\\s+func|chan\\s+\\w+)\\b/, 'go'],\n\n // Python - distinctive patterns\n [/\\b(def\\s+\\w+\\s*\\(|import\\s+\\w+|from\\s+\\w+\\s+import|class\\s+\\w+:)\\b/, 'python'],\n\n // TypeScript - distinctive type annotations\n [/:\\s*(string|number|boolean|void)\\b|\\binterface\\s+\\w+\\s*\\{/, 'typescript'],\n\n // JavaScript - distinctive patterns (after TS check)\n [/\\b(const|let|var)\\s+\\w+\\s*=|function\\s+\\w+\\s*\\(|=>\\s*\\{/, 'javascript'],\n\n // Ruby - distinctive keywords\n [/\\b(def\\s+\\w+|end\\b|do\\s*\\|.*\\||puts\\s+|require\\s+['\"])\\b/, 'ruby'],\n\n // Java - distinctive patterns\n [/\\b(public\\s+class|private\\s+\\w+|System\\.out\\.println)\\b/, 'java'],\n\n // C++ - distinctive patterns\n [/\\b(#include\\s*<|std::|template\\s*<|nullptr|cout\\s*<<)\\b/, 'cpp'],\n\n // C - distinctive patterns (after C++ check)\n [/\\b(#include\\s*[<\"]|printf\\s*\\(|int\\s+main\\s*\\(|void\\s+\\w+\\s*\\()\\b/, 'c'],\n\n // C# - distinctive patterns\n [/\\b(namespace\\s+\\w+|using\\s+System|public\\s+static\\s+void)\\b/, 'c-sharp'],\n\n // PHP - distinctive patterns\n [/<\\?php|\\$\\w+\\s*=/, 'php'],\n\n // Swift - distinctive patterns\n [/\\b(func\\s+\\w+|var\\s+\\w+:\\s*\\w+|let\\s+\\w+:\\s*\\w+|@objc)\\b/, 'swift'],\n\n // Kotlin - distinctive patterns\n [/\\b(fun\\s+\\w+|val\\s+\\w+|var\\s+\\w+:|data\\s+class)\\b/, 'kotlin'],\n\n // Scala - distinctive patterns\n [/\\b(def\\s+\\w+|val\\s+\\w+|var\\s+\\w+|object\\s+\\w+|case\\s+class)\\b/, 'scala'],\n\n // Haskell - distinctive patterns\n [/\\b(module\\s+\\w+|import\\s+qualified|data\\s+\\w+\\s*=|::\\s*\\w+\\s*->)\\b/, 'haskell'],\n\n // Elixir - distinctive patterns\n [/\\b(defmodule\\s+\\w+|def\\s+\\w+|defp\\s+\\w+|\\|>)\\b/, 'elixir'],\n\n // Lua - distinctive patterns\n [/\\b(local\\s+\\w+\\s*=|function\\s+\\w+\\.\\w+|require\\s*\\()\\b/, 'lua'],\n\n // SQL - distinctive patterns\n [/\\b(SELECT\\s+.*\\s+FROM|INSERT\\s+INTO|CREATE\\s+TABLE|ALTER\\s+TABLE)\\b/i, 'sql'],\n\n // Shell/Bash - distinctive patterns\n [/\\b(if\\s+\\[\\s*|then\\b|fi\\b|echo\\s+[\"']|export\\s+\\w+=)\\b/, 'bash'],\n\n // YAML - distinctive patterns\n [/^\\s*[\\w-]+:\\s*[\\w\\-\"'[{]|^---\\s*$/, 'yaml'],\n\n // JSON - distinctive patterns\n [/^\\s*\\{[\\s\\S]*\"[\\w-]+\":\\s*/, 'json'],\n\n // TOML - distinctive patterns\n [/^\\s*\\[[\\w.-]+\\]\\s*$|^\\s*\\w+\\s*=\\s*[\"'\\d\\[]/, 'toml'],\n\n // HTML - distinctive patterns\n [/<(!DOCTYPE|html|head|body|div|span|p|a\\s)/i, 'html'],\n\n // CSS - distinctive patterns\n [/^\\s*[\\w.#@][\\w\\s,#.:>+~-]*\\{[^}]*\\}|@media\\s|@import\\s/, 'css'],\n\n // Markdown - distinctive patterns\n [/^#{1,6}\\s+\\w|^\\s*[-*+]\\s+\\w|^\\s*\\d+\\.\\s+\\w|```\\w*\\n/, 'markdown'],\n\n // XML - distinctive patterns\n [/<\\?xml|<[\\w:-]+\\s+xmlns/, 'xml'],\n\n // Dockerfile\n [/^FROM\\s+\\w+|^RUN\\s+|^COPY\\s+|^ENTRYPOINT\\s+/m, 'dockerfile'],\n\n // Nginx config\n [/\\b(server\\s*\\{|location\\s+[\\/~]|proxy_pass\\s+)\\b/, 'nginx'],\n\n // Zig\n [/\\b(pub\\s+fn|const\\s+\\w+\\s*=|@import\\(|comptime)\\b/, 'zig'],\n];\n\n/**\n * Detect the language of a code snippet.\n * Returns null if detection fails.\n */\nexport function detectLanguage(source: string): string | null {\n // Check shebang first (most reliable)\n const firstLine = source.split('\\n')[0];\n for (const [pattern, language] of SHEBANG_PATTERNS) {\n if (pattern.test(firstLine)) {\n return language;\n }\n }\n\n // Check keyword fingerprints\n for (const [pattern, language] of KEYWORD_FINGERPRINTS) {\n if (pattern.test(source)) {\n return language;\n }\n }\n\n return null;\n}\n\n/**\n * Extract language from class name.\n * Supports multiple patterns:\n * - \"language-rust\" -> \"rust\" (standard)\n * - \"lang-rust\" -> \"rust\" (common alternative)\n * - \"rust\" -> \"rust\" (docs.rs style, bare language name)\n */\nexport function extractLanguageFromClass(className: string): string | null {\n // Try \"language-*\" pattern first (most specific)\n const langMatch = className.match(/\\blanguage-(\\w+)\\b/);\n if (langMatch) return langMatch[1];\n\n // Try \"lang-*\" pattern\n const shortMatch = className.match(/\\blang-(\\w+)\\b/);\n if (shortMatch) return shortMatch[1];\n\n // Try bare language names (for docs.rs compatibility)\n // Only match known language names to avoid false positives\n const knownLanguages = new Set([\n 'rust', 'javascript', 'typescript', 'python', 'ruby', 'go', 'java',\n 'c', 'cpp', 'csharp', 'php', 'swift', 'kotlin', 'scala', 'haskell',\n 'elixir', 'lua', 'sql', 'bash', 'shell', 'yaml', 'json', 'toml',\n 'html', 'css', 'xml', 'markdown', 'dockerfile', 'nginx', 'zig',\n 'text', 'plaintext', 'console', 'sh',\n ]);\n\n for (const cls of className.split(/\\s+/)) {\n if (knownLanguages.has(cls.toLowerCase())) {\n return cls.toLowerCase();\n }\n }\n\n return null;\n}\n\n/**\n * Normalize language identifier (handle aliases)\n */\nexport function normalizeLanguage(lang: string): string {\n const aliases: Record<string, string> = {\n js: 'javascript',\n ts: 'typescript',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n sh: 'bash',\n shell: 'bash',\n yml: 'yaml',\n cs: 'c-sharp',\n csharp: 'c-sharp',\n 'c++': 'cpp',\n 'c#': 'c-sharp',\n 'f#': 'fsharp',\n dockerfile: 'dockerfile',\n docker: 'dockerfile',\n makefile: 'make',\n plaintext: 'text',\n plain: 'text',\n txt: 'text',\n };\n\n const lower = lang.toLowerCase();\n return aliases[lower] || lower;\n}\n"],"names":["availableLanguages","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","knownLanguages","localManifest","localManifestPromise","ensureLocalManifest","response","getGrammarBaseUrl","language","entry","cdn","baseUrl","loadGrammarPlugin","cached","e","jsUrl","wasmUrl","module","loadedId","injectionLanguages","plugin","text","session","result","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","version","versionSuffix","loadHost","hostUrl","highlight","source","_config","host","escapeHtml","spansToHtml","loadGrammar","spans","sorted","b","html","pos","span","tag","getTagForCapture","capture","getConfig","overrides","SHEBANG_PATTERNS","KEYWORD_FINGERPRINTS","detectLanguage","firstLine","pattern","extractLanguageFromClass","className","langMatch","shortMatch","cls","normalizeLanguage","lang","aliases","lower"],"mappings":"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"}
1
+ {"version":3,"file":"arborium.js","sources":["../src/plugins-manifest.ts","../src/loader.ts","../src/detect.ts"],"sourcesContent":["// AUTO-GENERATED by `cargo xtask gen-manifest` - DO NOT EDIT\n\n/** Version of plugin packages (all @arborium/* packages share this version) */\nexport const pluginVersion = \"2.1.0\";\n\n/** All available languages */\nexport const availableLanguages: string[] = [\n \"ada\",\n \"agda\",\n \"asciidoc\",\n \"asm\",\n \"awk\",\n \"bash\",\n \"batch\",\n \"c\",\n \"c-sharp\",\n \"caddy\",\n \"capnp\",\n \"clojure\",\n \"cmake\",\n \"commonlisp\",\n \"cpp\",\n \"css\",\n \"d\",\n \"dart\",\n \"devicetree\",\n \"diff\",\n \"dockerfile\",\n \"dot\",\n \"elisp\",\n \"elixir\",\n \"elm\",\n \"erlang\",\n \"fish\",\n \"fsharp\",\n \"gleam\",\n \"glsl\",\n \"go\",\n \"graphql\",\n \"haskell\",\n \"hcl\",\n \"hlsl\",\n \"html\",\n \"idris\",\n \"ini\",\n \"java\",\n \"javascript\",\n \"jinja2\",\n \"jq\",\n \"json\",\n \"julia\",\n \"kdl\",\n \"kotlin\",\n \"lean\",\n \"lua\",\n \"markdown\",\n \"matlab\",\n \"meson\",\n \"nginx\",\n \"ninja\",\n \"nix\",\n \"objc\",\n \"ocaml\",\n \"perl\",\n \"php\",\n \"postscript\",\n \"powershell\",\n \"prolog\",\n \"python\",\n \"query\",\n \"r\",\n \"rescript\",\n \"ron\",\n \"ruby\",\n \"rust\",\n \"scala\",\n \"scheme\",\n \"scss\",\n \"sparql\",\n \"sql\",\n \"ssh-config\",\n \"starlark\",\n \"svelte\",\n \"swift\",\n \"textproto\",\n \"thrift\",\n \"tlaplus\",\n \"toml\",\n \"tsx\",\n \"typescript\",\n \"typst\",\n \"uiua\",\n \"vb\",\n \"verilog\",\n \"vhdl\",\n \"vim\",\n \"vue\",\n \"x86asm\",\n \"xml\",\n \"yaml\",\n \"yuri\",\n \"zig\",\n \"zsh\",\n];","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Grammar registry is bundled at build time (no network request needed in production)\n * - Can be overridden via pluginsUrl config for local development\n * 2. Load grammar wasm-bindgen modules on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport type { ParseResult, ArboriumConfig, Grammar, Session, Span, Injection } from \"./types.js\";\nimport { availableLanguages, pluginVersion } from \"./plugins-manifest.js\";\n\n// Default config\nexport const defaultConfig: Required<ArboriumConfig> = {\n manual: false,\n theme: \"one-dark\",\n selector: \"pre code\",\n cdn: \"jsdelivr\",\n version: pluginVersion, // Precise version from manifest\n pluginsUrl: \"\", // Empty means use bundled manifest\n hostUrl: \"\", // Empty means use CDN based on version\n};\n\n// Rust host module (loaded on demand)\ninterface HostModule {\n highlight: (language: string, source: string) => string;\n isLanguageAvailable: (language: string) => boolean;\n}\nlet hostModule: HostModule | null = null;\nlet hostLoadPromise: Promise<HostModule | null> | null = null;\n\n// Merged config\nlet config: Required<ArboriumConfig> = { ...defaultConfig };\n\n// Grammar plugins cache\nconst grammarCache = new Map<string, GrammarPlugin>();\n\n// Languages we know are available (bundled at build time)\nconst knownLanguages: Set<string> = new Set(availableLanguages);\n\n// For local development: can override with pluginsUrl to load from dev server\ninterface LocalManifest {\n entries: Array<{\n language: string;\n local_js: string;\n local_wasm: string;\n }>;\n}\nlet localManifest: LocalManifest | null = null;\nlet localManifestPromise: Promise<void> | null = null;\n\n/** Load local manifest if pluginsUrl is configured (for dev server) */\nasync function ensureLocalManifest(): Promise<void> {\n if (!config.pluginsUrl) {\n return;\n }\n\n if (localManifestPromise) {\n return localManifestPromise;\n }\n\n localManifestPromise = (async () => {\n console.debug(`[arborium] Loading local plugins manifest from: ${config.pluginsUrl}`);\n const response = await fetch(config.pluginsUrl);\n if (!response.ok) {\n throw new Error(`Failed to load plugins.json: ${response.status}`);\n }\n localManifest = await response.json();\n console.debug(`[arborium] Loaded local manifest with ${localManifest?.entries.length} entries`);\n })();\n\n return localManifestPromise;\n}\n\n/** Get the CDN base URL for a grammar */\nfunction getGrammarBaseUrl(language: string): string {\n // If we have a local manifest (dev mode), use the local path\n if (localManifest) {\n const entry = localManifest.entries.find((e) => e.language === language);\n if (entry) {\n // Extract base URL from local_js path (e.g., \"/langs/group-hazel/python/npm/grammar.js\" -> \"/langs/group-hazel/python/npm\")\n return entry.local_js.substring(0, entry.local_js.lastIndexOf(\"/\"));\n }\n }\n\n // Production: derive from language name using precise version\n const cdn = config.cdn;\n const version = config.version;\n let baseUrl: string;\n if (cdn === \"jsdelivr\") {\n baseUrl = \"https://cdn.jsdelivr.net/npm\";\n } else if (cdn === \"unpkg\") {\n baseUrl = \"https://unpkg.com\";\n } else {\n baseUrl = cdn;\n }\n return `${baseUrl}/@arborium/${language}@${version}`;\n}\n\n/** wasm-bindgen plugin module interface */\ninterface WasmBindgenPlugin {\n default: (wasmUrl: string) => Promise<void>;\n language_id: () => string;\n injection_languages: () => string[];\n create_session: () => number;\n free_session: (session: number) => void;\n set_text: (session: number, text: string) => void;\n parse: (session: number) => ParseResult;\n cancel: (session: number) => void;\n}\n\n/** A loaded grammar plugin */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n module: WasmBindgenPlugin;\n parse: (text: string) => ParseResult;\n}\n\n/** Load a grammar plugin */\nasync function loadGrammarPlugin(language: string): Promise<GrammarPlugin | null> {\n // Check cache\n const cached = grammarCache.get(language);\n if (cached) {\n console.debug(`[arborium] Grammar '${language}' found in cache`);\n return cached;\n }\n\n // Load local manifest if in dev mode\n await ensureLocalManifest();\n\n // Check if language is known\n if (\n !knownLanguages.has(language) &&\n !localManifest?.entries.some((e) => e.language === language)\n ) {\n console.debug(`[arborium] Grammar '${language}' not available`);\n return null;\n }\n\n try {\n const baseUrl = getGrammarBaseUrl(language);\n const jsUrl = `${baseUrl}/grammar.js`;\n const wasmUrl = `${baseUrl}/grammar_bg.wasm`;\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n\n // Dynamically import the wasm-bindgen generated JS module\n const module = (await import(/* @vite-ignore */ jsUrl)) as WasmBindgenPlugin;\n\n // Initialize the WASM module\n await module.default(wasmUrl);\n\n // Verify it loaded correctly\n const loadedId = module.language_id();\n if (loadedId !== language) {\n console.warn(`[arborium] Language ID mismatch: expected '${language}', got '${loadedId}'`);\n }\n\n // Get injection languages\n const injectionLanguages = module.injection_languages();\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages,\n module,\n parse: (text: string) => {\n const session = module.create_session();\n try {\n module.set_text(session, text);\n // wasm-bindgen returns ParseResult directly (or throws on error)\n const result = module.parse(session);\n return {\n spans: result.spans || [],\n injections: result.injections || [],\n };\n } catch (e) {\n console.error(`[arborium] Parse error:`, e);\n return { spans: [], injections: [] };\n } finally {\n module.free_session(session);\n }\n },\n };\n\n grammarCache.set(language, plugin);\n console.debug(`[arborium] Grammar '${language}' loaded successfully`);\n return plugin;\n } catch (e) {\n console.error(`[arborium] Failed to load grammar '${language}':`, e);\n return null;\n }\n}\n\n// Handle to plugin mapping for the host interface\nconst handleToPlugin = new Map<number, GrammarPlugin>();\nlet nextHandle = 1;\n\n/** Setup window.arboriumHost for the Rust host to call into */\nfunction setupHostInterface(): void {\n (window as any).arboriumHost = {\n /** Check if a language is available (sync) */\n isLanguageAvailable(language: string): boolean {\n return knownLanguages.has(language) || grammarCache.has(language);\n },\n\n /** Load a grammar and return a handle (async) */\n async loadGrammar(language: string): Promise<number> {\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) return 0; // 0 = not found\n\n // Check if we already have a handle\n for (const [handle, p] of handleToPlugin) {\n if (p === plugin) return handle;\n }\n\n // Create new handle\n const handle = nextHandle++;\n handleToPlugin.set(handle, plugin);\n return handle;\n },\n\n /** Parse text using a grammar handle (sync) */\n parse(handle: number, text: string): ParseResult {\n const plugin = handleToPlugin.get(handle);\n if (!plugin) return { spans: [], injections: [] };\n return plugin.parse(text);\n },\n };\n}\n\n/** Get the host URL based on config */\nfunction getHostUrl(): string {\n if (config.hostUrl) {\n return config.hostUrl;\n }\n // Use CDN\n const cdn = config.cdn;\n const version = config.version;\n let baseUrl: string;\n if (cdn === \"jsdelivr\") {\n baseUrl = \"https://cdn.jsdelivr.net/npm\";\n } else if (cdn === \"unpkg\") {\n baseUrl = \"https://unpkg.com\";\n } else {\n baseUrl = cdn;\n }\n const versionSuffix = version === \"latest\" ? \"\" : `@${version}`;\n return `${baseUrl}/@arborium/arborium${versionSuffix}/dist`;\n}\n\n/** Load the Rust host module */\nasync function loadHost(): Promise<HostModule | null> {\n if (hostModule) return hostModule;\n if (hostLoadPromise) return hostLoadPromise;\n\n hostLoadPromise = (async () => {\n // Setup the interface the host imports\n setupHostInterface();\n\n const hostUrl = getHostUrl();\n const jsUrl = `${hostUrl}/arborium_host.js`;\n const wasmUrl = `${hostUrl}/arborium_host_bg.wasm`;\n\n console.debug(`[arborium] Loading host from ${jsUrl}`);\n try {\n const module = await import(/* @vite-ignore */ jsUrl);\n await module.default(wasmUrl);\n\n hostModule = {\n highlight: module.highlight,\n isLanguageAvailable: module.isLanguageAvailable,\n };\n console.debug(`[arborium] Host loaded successfully`);\n return hostModule;\n } catch (e) {\n console.error(\"[arborium] Failed to load host:\", e);\n return null;\n }\n })();\n\n return hostLoadPromise;\n}\n\n/** Highlight source code */\nexport async function highlight(\n language: string,\n source: string,\n _config?: ArboriumConfig,\n): Promise<string> {\n // Try to use the Rust host (handles injections properly)\n const host = await loadHost();\n if (host) {\n try {\n return host.highlight(language, source);\n } catch (e) {\n console.warn(\"Host highlight failed, falling back to JS:\", e);\n }\n }\n\n // Fallback to JS-only highlighting (no injection support)\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) {\n return escapeHtml(source);\n }\n\n const result = plugin.parse(source);\n return spansToHtml(source, result.spans);\n}\n\n/** Load a grammar for direct use */\nexport async function loadGrammar(\n language: string,\n _config?: ArboriumConfig,\n): Promise<Grammar | null> {\n const plugin = await loadGrammarPlugin(language);\n if (!plugin) return null;\n\n const { module } = plugin;\n\n return {\n languageId: () => plugin.languageId,\n injectionLanguages: () => plugin.injectionLanguages,\n highlight: async (source: string) => {\n const result = plugin.parse(source);\n return spansToHtml(source, result.spans);\n },\n parse: (source: string) => plugin.parse(source),\n createSession: (): Session => {\n const handle = module.create_session();\n return {\n setText: (text: string) => module.set_text(handle, text),\n parse: () => {\n try {\n const result = module.parse(handle);\n return {\n spans: result.spans || [],\n injections: result.injections || [],\n };\n } catch (e) {\n console.error(`[arborium] Session parse error:`, e);\n return { spans: [], injections: [] };\n }\n },\n cancel: () => module.cancel(handle),\n free: () => module.free_session(handle),\n };\n },\n dispose: () => {\n // No-op for now, plugins are cached\n },\n };\n}\n\n/** Convert spans to HTML */\nexport function spansToHtml(source: string, spans: Span[]): string {\n // Sort spans by start position\n const sorted = [...spans].sort((a, b) => a.start - b.start);\n\n let html = \"\";\n let pos = 0;\n\n for (const span of sorted) {\n // Skip overlapping spans\n if (span.start < pos) continue;\n\n // Add text before span\n if (span.start > pos) {\n html += escapeHtml(source.slice(pos, span.start));\n }\n\n // Get tag for capture\n const tag = getTagForCapture(span.capture);\n const text = escapeHtml(source.slice(span.start, span.end));\n\n if (tag) {\n html += `<a-${tag}>${text}</a-${tag}>`;\n } else {\n html += text;\n }\n\n pos = span.end;\n }\n\n // Add remaining text\n if (pos < source.length) {\n html += escapeHtml(source.slice(pos));\n }\n\n return html;\n}\n\n/** Get the short tag for a capture name */\nfunction getTagForCapture(capture: string): string | null {\n if (capture.startsWith(\"keyword\") || capture === \"include\" || capture === \"conditional\") {\n return \"k\";\n }\n if (capture.startsWith(\"function\") || capture.startsWith(\"method\")) {\n return \"f\";\n }\n if (capture.startsWith(\"string\") || capture === \"character\") {\n return \"s\";\n }\n if (capture.startsWith(\"comment\")) {\n return \"c\";\n }\n if (capture.startsWith(\"type\")) {\n return \"t\";\n }\n if (capture.startsWith(\"variable\")) {\n return \"v\";\n }\n if (capture.startsWith(\"number\") || capture === \"float\") {\n return \"n\";\n }\n if (capture.startsWith(\"operator\")) {\n return \"o\";\n }\n if (capture.startsWith(\"punctuation\")) {\n return \"p\";\n }\n if (capture.startsWith(\"tag\")) {\n return \"tg\";\n }\n if (capture.startsWith(\"attribute\")) {\n return \"at\";\n }\n return null;\n}\n\n/** Escape HTML special characters */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n/** Get current config, optionally merging with overrides */\nexport function getConfig(overrides?: Partial<ArboriumConfig>): Required<ArboriumConfig> {\n if (overrides) {\n return { ...config, ...overrides };\n }\n return { ...config };\n}\n\n/** Set/merge config */\nexport function setConfig(newConfig: Partial<ArboriumConfig>): void {\n config = { ...config, ...newConfig };\n}\n\n/** Check if a language is available */\nexport async function isLanguageAvailable(language: string): Promise<boolean> {\n await ensureLocalManifest();\n return (\n knownLanguages.has(language) ||\n (localManifest?.entries.some((e) => e.language === language) ?? false)\n );\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await ensureLocalManifest();\n // In dev mode, use local manifest if available\n if (localManifest) {\n return localManifest.entries.map((e) => e.language);\n }\n return Array.from(knownLanguages);\n}\n","/**\n * Simple language detection heuristics.\n * Not meant to be comprehensive - just catches common cases.\n */\n\n/** Shebang patterns */\nconst SHEBANG_PATTERNS: Array<[RegExp, string]> = [\n [/^#!.*\\bpython[23]?\\b/, 'python'],\n [/^#!.*\\bnode\\b/, 'javascript'],\n [/^#!.*\\bdeno\\b/, 'typescript'],\n [/^#!.*\\bbun\\b/, 'typescript'],\n [/^#!.*\\bruby\\b/, 'ruby'],\n [/^#!.*\\bperl\\b/, 'perl'],\n [/^#!.*\\bphp\\b/, 'php'],\n [/^#!.*\\bbash\\b/, 'bash'],\n [/^#!.*\\bzsh\\b/, 'zsh'],\n [/^#!.*\\bsh\\b/, 'bash'],\n [/^#!.*\\blua\\b/, 'lua'],\n [/^#!.*\\bawk\\b/, 'awk'],\n];\n\n/** Keyword fingerprints - first few unique keywords that identify a language */\nconst KEYWORD_FINGERPRINTS: Array<[RegExp, string]> = [\n // Rust - distinctive keywords\n [/\\b(fn|impl|trait|pub\\s+fn|let\\s+mut|&mut|->)\\b/, 'rust'],\n\n // Go - distinctive keywords\n [/\\b(func|package\\s+\\w+|import\\s+\\(|go\\s+func|chan\\s+\\w+)\\b/, 'go'],\n\n // Python - distinctive patterns\n [/\\b(def\\s+\\w+\\s*\\(|import\\s+\\w+|from\\s+\\w+\\s+import|class\\s+\\w+:)\\b/, 'python'],\n\n // TypeScript - distinctive type annotations\n [/:\\s*(string|number|boolean|void)\\b|\\binterface\\s+\\w+\\s*\\{/, 'typescript'],\n\n // JavaScript - distinctive patterns (after TS check)\n [/\\b(const|let|var)\\s+\\w+\\s*=|function\\s+\\w+\\s*\\(|=>\\s*\\{/, 'javascript'],\n\n // Ruby - distinctive keywords\n [/\\b(def\\s+\\w+|end\\b|do\\s*\\|.*\\||puts\\s+|require\\s+['\"])\\b/, 'ruby'],\n\n // Java - distinctive patterns\n [/\\b(public\\s+class|private\\s+\\w+|System\\.out\\.println)\\b/, 'java'],\n\n // C++ - distinctive patterns\n [/\\b(#include\\s*<|std::|template\\s*<|nullptr|cout\\s*<<)\\b/, 'cpp'],\n\n // C - distinctive patterns (after C++ check)\n [/\\b(#include\\s*[<\"]|printf\\s*\\(|int\\s+main\\s*\\(|void\\s+\\w+\\s*\\()\\b/, 'c'],\n\n // C# - distinctive patterns\n [/\\b(namespace\\s+\\w+|using\\s+System|public\\s+static\\s+void)\\b/, 'c-sharp'],\n\n // PHP - distinctive patterns\n [/<\\?php|\\$\\w+\\s*=/, 'php'],\n\n // Swift - distinctive patterns\n [/\\b(func\\s+\\w+|var\\s+\\w+:\\s*\\w+|let\\s+\\w+:\\s*\\w+|@objc)\\b/, 'swift'],\n\n // Kotlin - distinctive patterns\n [/\\b(fun\\s+\\w+|val\\s+\\w+|var\\s+\\w+:|data\\s+class)\\b/, 'kotlin'],\n\n // Scala - distinctive patterns\n [/\\b(def\\s+\\w+|val\\s+\\w+|var\\s+\\w+|object\\s+\\w+|case\\s+class)\\b/, 'scala'],\n\n // Haskell - distinctive patterns\n [/\\b(module\\s+\\w+|import\\s+qualified|data\\s+\\w+\\s*=|::\\s*\\w+\\s*->)\\b/, 'haskell'],\n\n // Elixir - distinctive patterns\n [/\\b(defmodule\\s+\\w+|def\\s+\\w+|defp\\s+\\w+|\\|>)\\b/, 'elixir'],\n\n // Lua - distinctive patterns\n [/\\b(local\\s+\\w+\\s*=|function\\s+\\w+\\.\\w+|require\\s*\\()\\b/, 'lua'],\n\n // SQL - distinctive patterns\n [/\\b(SELECT\\s+.*\\s+FROM|INSERT\\s+INTO|CREATE\\s+TABLE|ALTER\\s+TABLE)\\b/i, 'sql'],\n\n // Shell/Bash - distinctive patterns\n [/\\b(if\\s+\\[\\s*|then\\b|fi\\b|echo\\s+[\"']|export\\s+\\w+=)\\b/, 'bash'],\n\n // YAML - distinctive patterns\n [/^\\s*[\\w-]+:\\s*[\\w\\-\"'[{]|^---\\s*$/, 'yaml'],\n\n // JSON - distinctive patterns\n [/^\\s*\\{[\\s\\S]*\"[\\w-]+\":\\s*/, 'json'],\n\n // TOML - distinctive patterns\n [/^\\s*\\[[\\w.-]+\\]\\s*$|^\\s*\\w+\\s*=\\s*[\"'\\d\\[]/, 'toml'],\n\n // HTML - distinctive patterns\n [/<(!DOCTYPE|html|head|body|div|span|p|a\\s)/i, 'html'],\n\n // CSS - distinctive patterns\n [/^\\s*[\\w.#@][\\w\\s,#.:>+~-]*\\{[^}]*\\}|@media\\s|@import\\s/, 'css'],\n\n // Markdown - distinctive patterns\n [/^#{1,6}\\s+\\w|^\\s*[-*+]\\s+\\w|^\\s*\\d+\\.\\s+\\w|```\\w*\\n/, 'markdown'],\n\n // XML - distinctive patterns\n [/<\\?xml|<[\\w:-]+\\s+xmlns/, 'xml'],\n\n // Dockerfile\n [/^FROM\\s+\\w+|^RUN\\s+|^COPY\\s+|^ENTRYPOINT\\s+/m, 'dockerfile'],\n\n // Nginx config\n [/\\b(server\\s*\\{|location\\s+[\\/~]|proxy_pass\\s+)\\b/, 'nginx'],\n\n // Zig\n [/\\b(pub\\s+fn|const\\s+\\w+\\s*=|@import\\(|comptime)\\b/, 'zig'],\n];\n\n/**\n * Detect the language of a code snippet.\n * Returns null if detection fails.\n */\nexport function detectLanguage(source: string): string | null {\n // Check shebang first (most reliable)\n const firstLine = source.split('\\n')[0];\n for (const [pattern, language] of SHEBANG_PATTERNS) {\n if (pattern.test(firstLine)) {\n return language;\n }\n }\n\n // Check keyword fingerprints\n for (const [pattern, language] of KEYWORD_FINGERPRINTS) {\n if (pattern.test(source)) {\n return language;\n }\n }\n\n return null;\n}\n\n/**\n * Extract language from class name.\n * Supports multiple patterns:\n * - \"language-rust\" -> \"rust\" (standard)\n * - \"lang-rust\" -> \"rust\" (common alternative)\n * - \"rust\" -> \"rust\" (docs.rs style, bare language name)\n */\nexport function extractLanguageFromClass(className: string): string | null {\n // Try \"language-*\" pattern first (most specific)\n const langMatch = className.match(/\\blanguage-(\\w+)\\b/);\n if (langMatch) return langMatch[1];\n\n // Try \"lang-*\" pattern\n const shortMatch = className.match(/\\blang-(\\w+)\\b/);\n if (shortMatch) return shortMatch[1];\n\n // Try bare language names (for docs.rs compatibility)\n // Only match known language names to avoid false positives\n const knownLanguages = new Set([\n 'rust', 'javascript', 'typescript', 'python', 'ruby', 'go', 'java',\n 'c', 'cpp', 'csharp', 'php', 'swift', 'kotlin', 'scala', 'haskell',\n 'elixir', 'lua', 'sql', 'bash', 'shell', 'yaml', 'json', 'toml',\n 'html', 'css', 'xml', 'markdown', 'dockerfile', 'nginx', 'zig',\n 'text', 'plaintext', 'console', 'sh',\n ]);\n\n for (const cls of className.split(/\\s+/)) {\n if (knownLanguages.has(cls.toLowerCase())) {\n return cls.toLowerCase();\n }\n }\n\n return null;\n}\n\n/**\n * Normalize language identifier (handle aliases)\n */\nexport function normalizeLanguage(lang: string): string {\n const aliases: Record<string, string> = {\n js: 'javascript',\n ts: 'typescript',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n sh: 'bash',\n shell: 'bash',\n yml: 'yaml',\n cs: 'c-sharp',\n csharp: 'c-sharp',\n 'c++': 'cpp',\n 'c#': 'c-sharp',\n 'f#': 'fsharp',\n dockerfile: 'dockerfile',\n docker: 'dockerfile',\n makefile: 'make',\n plaintext: 'text',\n plain: 'text',\n txt: 'text',\n };\n\n const lower = lang.toLowerCase();\n return aliases[lower] || lower;\n}\n"],"names":["pluginVersion","availableLanguages","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","knownLanguages","localManifest","localManifestPromise","ensureLocalManifest","response","getGrammarBaseUrl","language","entry","e","cdn","version","baseUrl","loadGrammarPlugin","cached","jsUrl","wasmUrl","module","loadedId","injectionLanguages","plugin","text","session","result","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","versionSuffix","loadHost","hostUrl","highlight","source","_config","host","escapeHtml","spansToHtml","loadGrammar","spans","sorted","a","b","html","pos","span","tag","getTagForCapture","capture","getConfig","overrides","SHEBANG_PATTERNS","KEYWORD_FINGERPRINTS","detectLanguage","firstLine","pattern","extractLanguageFromClass","className","langMatch","shortMatch","cls","normalizeLanguage","lang","aliases","lower"],"mappings":"AAGO,MAAMA,IAAgB,SAGhBC,IAA+B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GCzFaC,IAA0C;AAAA,EACrD,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL,SAASF;AAAA;AAAA,EACT,YAAY;AAAA;AAAA,EACZ,SAAS;AAAA;AACX;AAOA,IAAIG,IAAgC,MAChCC,IAAqD,MAGrDC,IAAmC,EAAE,GAAGH,EAAA;AAG5C,MAAMI,wBAAmB,IAAA,GAGnBC,IAA8B,IAAI,IAAIN,CAAkB;AAU9D,IAAIO,IAAsC,MACtCC,IAA6C;AAGjD,eAAeC,IAAqC;AAClD,MAAKL,EAAO;AAIZ,WAAII,MAIJA,KAAwB,YAAY;AAClC,cAAQ,MAAM,mDAAmDJ,EAAO,UAAU,EAAE;AACpF,YAAMM,IAAW,MAAM,MAAMN,EAAO,UAAU;AAC9C,UAAI,CAACM,EAAS;AACZ,cAAM,IAAI,MAAM,gCAAgCA,EAAS,MAAM,EAAE;AAEnE,MAAAH,IAAgB,MAAMG,EAAS,KAAA,GAC/B,QAAQ,MAAM,yCAAyCH,GAAe,QAAQ,MAAM,UAAU;AAAA,IAChG,GAAA,GAEOC;AACT;AAGA,SAASG,EAAkBC,GAA0B;AAEnD,MAAIL,GAAe;AACjB,UAAMM,IAAQN,EAAc,QAAQ,KAAK,CAACO,MAAMA,EAAE,aAAaF,CAAQ;AACvE,QAAIC;AAEF,aAAOA,EAAM,SAAS,UAAU,GAAGA,EAAM,SAAS,YAAY,GAAG,CAAC;AAAA,EAEtE;AAGA,QAAME,IAAMX,EAAO,KACbY,IAAUZ,EAAO;AACvB,MAAIa;AACJ,SAAIF,MAAQ,aACVE,IAAU,iCACDF,MAAQ,UACjBE,IAAU,sBAEVA,IAAUF,GAEL,GAAGE,CAAO,cAAcL,CAAQ,IAAII,CAAO;AACpD;AAuBA,eAAeE,EAAkBN,GAAiD;AAEhF,QAAMO,IAASd,EAAa,IAAIO,CAAQ;AACxC,MAAIO;AACF,mBAAQ,MAAM,uBAAuBP,CAAQ,kBAAkB,GACxDO;AAOT,MAHA,MAAMV,EAAA,GAIJ,CAACH,EAAe,IAAIM,CAAQ,KAC5B,CAACL,GAAe,QAAQ,KAAK,CAACO,MAAMA,EAAE,aAAaF,CAAQ;AAE3D,mBAAQ,MAAM,uBAAuBA,CAAQ,iBAAiB,GACvD;AAGT,MAAI;AACF,UAAMK,IAAUN,EAAkBC,CAAQ,GACpCQ,IAAQ,GAAGH,CAAO,eAClBI,IAAU,GAAGJ,CAAO;AAE1B,YAAQ,MAAM,+BAA+BL,CAAQ,UAAUQ,CAAK,EAAE;AAGtE,UAAME,IAAU,MAAM;AAAA;AAAA,MAA0BF;AAAA;AAGhD,UAAME,EAAO,QAAQD,CAAO;AAG5B,UAAME,IAAWD,EAAO,YAAA;AACxB,IAAIC,MAAaX,KACf,QAAQ,KAAK,8CAA8CA,CAAQ,WAAWW,CAAQ,GAAG;AAI3F,UAAMC,IAAqBF,EAAO,oBAAA,GAG5BG,IAAwB;AAAA,MAC5B,YAAYb;AAAA,MACZ,oBAAAY;AAAA,MACA,QAAAF;AAAA,MACA,OAAO,CAACI,MAAiB;AACvB,cAAMC,IAAUL,EAAO,eAAA;AACvB,YAAI;AACF,UAAAA,EAAO,SAASK,GAASD,CAAI;AAE7B,gBAAME,IAASN,EAAO,MAAMK,CAAO;AACnC,iBAAO;AAAA,YACL,OAAOC,EAAO,SAAS,CAAA;AAAA,YACvB,YAAYA,EAAO,cAAc,CAAA;AAAA,UAAC;AAAA,QAEtC,SAASd,GAAG;AACV,yBAAQ,MAAM,2BAA2BA,CAAC,GACnC,EAAE,OAAO,IAAI,YAAY,CAAA,EAAC;AAAA,QACnC,UAAA;AACE,UAAAQ,EAAO,aAAaK,CAAO;AAAA,QAC7B;AAAA,MACF;AAAA,IAAA;AAGF,WAAAtB,EAAa,IAAIO,GAAUa,CAAM,GACjC,QAAQ,MAAM,uBAAuBb,CAAQ,uBAAuB,GAC7Da;AAAA,EACT,SAASX,GAAG;AACV,mBAAQ,MAAM,sCAAsCF,CAAQ,MAAME,CAAC,GAC5D;AAAA,EACT;AACF;AAGA,MAAMe,wBAAqB,IAAA;AAC3B,IAAIC,IAAa;AAGjB,SAASC,IAA2B;AACjC,SAAe,eAAe;AAAA;AAAA,IAE7B,oBAAoBnB,GAA2B;AAC7C,aAAON,EAAe,IAAIM,CAAQ,KAAKP,EAAa,IAAIO,CAAQ;AAAA,IAClE;AAAA;AAAA,IAGA,MAAM,YAAYA,GAAmC;AACnD,YAAMa,IAAS,MAAMP,EAAkBN,CAAQ;AAC/C,UAAI,CAACa,EAAQ,QAAO;AAGpB,iBAAW,CAACO,GAAQC,CAAC,KAAKJ;AACxB,YAAII,MAAMR,EAAQ,QAAOO;AAI3B,YAAMA,IAASF;AACf,aAAAD,EAAe,IAAIG,GAAQP,CAAM,GAC1BO;AAAA,IACT;AAAA;AAAA,IAGA,MAAMA,GAAgBN,GAA2B;AAC/C,YAAMD,IAASI,EAAe,IAAIG,CAAM;AACxC,aAAKP,IACEA,EAAO,MAAMC,CAAI,IADJ,EAAE,OAAO,CAAA,GAAI,YAAY,GAAC;AAAA,IAEhD;AAAA,EAAA;AAEJ;AAGA,SAASQ,IAAqB;AAC5B,MAAI9B,EAAO;AACT,WAAOA,EAAO;AAGhB,QAAMW,IAAMX,EAAO,KACbY,IAAUZ,EAAO;AACvB,MAAIa;AACJ,EAAIF,MAAQ,aACVE,IAAU,iCACDF,MAAQ,UACjBE,IAAU,sBAEVA,IAAUF;AAEZ,QAAMoB,IAAgBnB,MAAY,WAAW,KAAK,IAAIA,CAAO;AAC7D,SAAO,GAAGC,CAAO,sBAAsBkB,CAAa;AACtD;AAGA,eAAeC,IAAuC;AACpD,SAAIlC,KACAC,MAEJA,KAAmB,YAAY;AAE7B,IAAA4B,EAAA;AAEA,UAAMM,IAAUH,EAAA,GACVd,IAAQ,GAAGiB,CAAO,qBAClBhB,IAAU,GAAGgB,CAAO;AAE1B,YAAQ,MAAM,gCAAgCjB,CAAK,EAAE;AACrD,QAAI;AACF,YAAME,IAAS,MAAM;AAAA;AAAA,QAA0BF;AAAA;AAC/C,mBAAME,EAAO,QAAQD,CAAO,GAE5BnB,IAAa;AAAA,QACX,WAAWoB,EAAO;AAAA,QAClB,qBAAqBA,EAAO;AAAA,MAAA,GAE9B,QAAQ,MAAM,qCAAqC,GAC5CpB;AAAA,IACT,SAASY,GAAG;AACV,qBAAQ,MAAM,mCAAmCA,CAAC,GAC3C;AAAA,IACT;AAAA,EACF,GAAA,GAEOX;AACT;AAGA,eAAsBmC,EACpB1B,GACA2B,GACAC,GACiB;AAEjB,QAAMC,IAAO,MAAML,EAAA;AACnB,MAAIK;AACF,QAAI;AACF,aAAOA,EAAK,UAAU7B,GAAU2B,CAAM;AAAA,IACxC,SAASzB,GAAG;AACV,cAAQ,KAAK,8CAA8CA,CAAC;AAAA,IAC9D;AAIF,QAAMW,IAAS,MAAMP,EAAkBN,CAAQ;AAC/C,MAAI,CAACa;AACH,WAAOiB,EAAWH,CAAM;AAG1B,QAAMX,IAASH,EAAO,MAAMc,CAAM;AAClC,SAAOI,EAAYJ,GAAQX,EAAO,KAAK;AACzC;AAGA,eAAsBgB,EACpBhC,GACA4B,GACyB;AACzB,QAAMf,IAAS,MAAMP,EAAkBN,CAAQ;AAC/C,MAAI,CAACa,EAAQ,QAAO;AAEpB,QAAM,EAAE,QAAAH,MAAWG;AAEnB,SAAO;AAAA,IACL,YAAY,MAAMA,EAAO;AAAA,IACzB,oBAAoB,MAAMA,EAAO;AAAA,IACjC,WAAW,OAAOc,MAAmB;AACnC,YAAMX,IAASH,EAAO,MAAMc,CAAM;AAClC,aAAOI,EAAYJ,GAAQX,EAAO,KAAK;AAAA,IACzC;AAAA,IACA,OAAO,CAACW,MAAmBd,EAAO,MAAMc,CAAM;AAAA,IAC9C,eAAe,MAAe;AAC5B,YAAMP,IAASV,EAAO,eAAA;AACtB,aAAO;AAAA,QACL,SAAS,CAACI,MAAiBJ,EAAO,SAASU,GAAQN,CAAI;AAAA,QACvD,OAAO,MAAM;AACX,cAAI;AACF,kBAAME,IAASN,EAAO,MAAMU,CAAM;AAClC,mBAAO;AAAA,cACL,OAAOJ,EAAO,SAAS,CAAA;AAAA,cACvB,YAAYA,EAAO,cAAc,CAAA;AAAA,YAAC;AAAA,UAEtC,SAASd,GAAG;AACV,2BAAQ,MAAM,mCAAmCA,CAAC,GAC3C,EAAE,OAAO,IAAI,YAAY,CAAA,EAAC;AAAA,UACnC;AAAA,QACF;AAAA,QACA,QAAQ,MAAMQ,EAAO,OAAOU,CAAM;AAAA,QAClC,MAAM,MAAMV,EAAO,aAAaU,CAAM;AAAA,MAAA;AAAA,IAE1C;AAAA,IACA,SAAS,MAAM;AAAA,IAEf;AAAA,EAAA;AAEJ;AAGO,SAASW,EAAYJ,GAAgBM,GAAuB;AAEjE,QAAMC,IAAS,CAAC,GAAGD,CAAK,EAAE,KAAK,CAACE,GAAGC,MAAMD,EAAE,QAAQC,EAAE,KAAK;AAE1D,MAAIC,IAAO,IACPC,IAAM;AAEV,aAAWC,KAAQL,GAAQ;AAEzB,QAAIK,EAAK,QAAQD,EAAK;AAGtB,IAAIC,EAAK,QAAQD,MACfD,KAAQP,EAAWH,EAAO,MAAMW,GAAKC,EAAK,KAAK,CAAC;AAIlD,UAAMC,IAAMC,EAAiBF,EAAK,OAAO,GACnCzB,IAAOgB,EAAWH,EAAO,MAAMY,EAAK,OAAOA,EAAK,GAAG,CAAC;AAE1D,IAAIC,IACFH,KAAQ,MAAMG,CAAG,IAAI1B,CAAI,OAAO0B,CAAG,MAEnCH,KAAQvB,GAGVwB,IAAMC,EAAK;AAAA,EACb;AAGA,SAAID,IAAMX,EAAO,WACfU,KAAQP,EAAWH,EAAO,MAAMW,CAAG,CAAC,IAG/BD;AACT;AAGA,SAASI,EAAiBC,GAAgC;AACxD,SAAIA,EAAQ,WAAW,SAAS,KAAKA,MAAY,aAAaA,MAAY,gBACjE,MAELA,EAAQ,WAAW,UAAU,KAAKA,EAAQ,WAAW,QAAQ,IACxD,MAELA,EAAQ,WAAW,QAAQ,KAAKA,MAAY,cACvC,MAELA,EAAQ,WAAW,SAAS,IACvB,MAELA,EAAQ,WAAW,MAAM,IACpB,MAELA,EAAQ,WAAW,UAAU,IACxB,MAELA,EAAQ,WAAW,QAAQ,KAAKA,MAAY,UACvC,MAELA,EAAQ,WAAW,UAAU,IACxB,MAELA,EAAQ,WAAW,aAAa,IAC3B,MAELA,EAAQ,WAAW,KAAK,IACnB,OAELA,EAAQ,WAAW,WAAW,IACzB,OAEF;AACT;AAGA,SAASZ,EAAWhB,GAAsB;AACxC,SAAOA,EACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ;AAC3B;AAGO,SAAS6B,EAAUC,GAA+D;AACvF,SAAIA,IACK,EAAE,GAAGpD,GAAQ,GAAGoD,EAAA,IAElB,EAAE,GAAGpD,EAAA;AACd;ACzbA,MAAMqD,IAA4C;AAAA,EAChD,CAAC,wBAAwB,QAAQ;AAAA,EACjC,CAAC,iBAAiB,YAAY;AAAA,EAC9B,CAAC,iBAAiB,YAAY;AAAA,EAC9B,CAAC,gBAAgB,YAAY;AAAA,EAC7B,CAAC,iBAAiB,MAAM;AAAA,EACxB,CAAC,iBAAiB,MAAM;AAAA,EACxB,CAAC,gBAAgB,KAAK;AAAA,EACtB,CAAC,iBAAiB,MAAM;AAAA,EACxB,CAAC,gBAAgB,KAAK;AAAA,EACtB,CAAC,eAAe,MAAM;AAAA,EACtB,CAAC,gBAAgB,KAAK;AAAA,EACtB,CAAC,gBAAgB,KAAK;AACxB,GAGMC,IAAgD;AAAA;AAAA,EAEpD,CAAC,kDAAkD,MAAM;AAAA;AAAA,EAGzD,CAAC,6DAA6D,IAAI;AAAA;AAAA,EAGlE,CAAC,sEAAsE,QAAQ;AAAA;AAAA,EAG/E,CAAC,6DAA6D,YAAY;AAAA;AAAA,EAG1E,CAAC,2DAA2D,YAAY;AAAA;AAAA,EAGxE,CAAC,4DAA4D,MAAM;AAAA;AAAA,EAGnE,CAAC,2DAA2D,MAAM;AAAA;AAAA,EAGlE,CAAC,2DAA2D,KAAK;AAAA;AAAA,EAGjE,CAAC,qEAAqE,GAAG;AAAA;AAAA,EAGzE,CAAC,+DAA+D,SAAS;AAAA;AAAA,EAGzE,CAAC,oBAAoB,KAAK;AAAA;AAAA,EAG1B,CAAC,4DAA4D,OAAO;AAAA;AAAA,EAGpE,CAAC,qDAAqD,QAAQ;AAAA;AAAA,EAG9D,CAAC,iEAAiE,OAAO;AAAA;AAAA,EAGzE,CAAC,sEAAsE,SAAS;AAAA;AAAA,EAGhF,CAAC,kDAAkD,QAAQ;AAAA;AAAA,EAG3D,CAAC,0DAA0D,KAAK;AAAA;AAAA,EAGhE,CAAC,wEAAwE,KAAK;AAAA;AAAA,EAG9E,CAAC,0DAA0D,MAAM;AAAA;AAAA,EAGjE,CAAC,qCAAqC,MAAM;AAAA;AAAA,EAG5C,CAAC,6BAA6B,MAAM;AAAA;AAAA,EAGpC,CAAC,8CAA8C,MAAM;AAAA;AAAA,EAGrD,CAAC,8CAA8C,MAAM;AAAA;AAAA,EAGrD,CAAC,0DAA0D,KAAK;AAAA;AAAA,EAGhE,CAAC,uDAAuD,UAAU;AAAA;AAAA,EAGlE,CAAC,2BAA2B,KAAK;AAAA;AAAA,EAGjC,CAAC,gDAAgD,YAAY;AAAA;AAAA,EAG7D,CAAC,oDAAoD,OAAO;AAAA;AAAA,EAG5D,CAAC,qDAAqD,KAAK;AAC7D;AAMO,SAASC,EAAepB,GAA+B;AAE5D,QAAMqB,IAAYrB,EAAO,MAAM;AAAA,CAAI,EAAE,CAAC;AACtC,aAAW,CAACsB,GAASjD,CAAQ,KAAK6C;AAChC,QAAII,EAAQ,KAAKD,CAAS;AACxB,aAAOhD;AAKX,aAAW,CAACiD,GAASjD,CAAQ,KAAK8C;AAChC,QAAIG,EAAQ,KAAKtB,CAAM;AACrB,aAAO3B;AAIX,SAAO;AACT;AASO,SAASkD,EAAyBC,GAAkC;AAEzE,QAAMC,IAAYD,EAAU,MAAM,oBAAoB;AACtD,MAAIC,EAAW,QAAOA,EAAU,CAAC;AAGjC,QAAMC,IAAaF,EAAU,MAAM,gBAAgB;AACnD,MAAIE,EAAY,QAAOA,EAAW,CAAC;AAInC,QAAM3D,wBAAqB,IAAI;AAAA,IAC7B;AAAA,IAAQ;AAAA,IAAc;AAAA,IAAc;AAAA,IAAU;AAAA,IAAQ;AAAA,IAAM;AAAA,IAC5D;AAAA,IAAK;AAAA,IAAO;AAAA,IAAU;AAAA,IAAO;AAAA,IAAS;AAAA,IAAU;AAAA,IAAS;AAAA,IACzD;AAAA,IAAU;AAAA,IAAO;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAQ;AAAA,IACzD;AAAA,IAAQ;AAAA,IAAO;AAAA,IAAO;AAAA,IAAY;AAAA,IAAc;AAAA,IAAS;AAAA,IACzD;AAAA,IAAQ;AAAA,IAAa;AAAA,IAAW;AAAA,EAAA,CACjC;AAED,aAAW4D,KAAOH,EAAU,MAAM,KAAK;AACrC,QAAIzD,EAAe,IAAI4D,EAAI,YAAA,CAAa;AACtC,aAAOA,EAAI,YAAA;AAIf,SAAO;AACT;AAKO,SAASC,EAAkBC,GAAsB;AACtD,QAAMC,IAAkC;AAAA,IACtC,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,IACP,KAAK;AAAA,EAAA,GAGDC,IAAQF,EAAK,YAAA;AACnB,SAAOC,EAAQC,CAAK,KAAKA;AAC3B;"}
@@ -144,12 +144,12 @@ if (!('encodeInto' in cachedTextEncoder)) {
144
144
 
145
145
  let WASM_VECTOR_LEN = 0;
146
146
 
147
- function wasm_bindgen__convert__closures_____invoke__hdf270ce0da308ff1(arg0, arg1, arg2) {
148
- wasm.wasm_bindgen__convert__closures_____invoke__hdf270ce0da308ff1(arg0, arg1, arg2);
147
+ function wasm_bindgen__convert__closures_____invoke__h6709295d3f31b919(arg0, arg1, arg2) {
148
+ wasm.wasm_bindgen__convert__closures_____invoke__h6709295d3f31b919(arg0, arg1, arg2);
149
149
  }
150
150
 
151
- function wasm_bindgen__convert__closures_____invoke__h089a09d160a6520b(arg0, arg1, arg2, arg3) {
152
- wasm.wasm_bindgen__convert__closures_____invoke__h089a09d160a6520b(arg0, arg1, arg2, arg3);
151
+ function wasm_bindgen__convert__closures_____invoke__h18c7f9ef50dd6692(arg0, arg1, arg2, arg3) {
152
+ wasm.wasm_bindgen__convert__closures_____invoke__h18c7f9ef50dd6692(arg0, arg1, arg2, arg3);
153
153
  }
154
154
 
155
155
  const HighlightConfigFinalization = (typeof FinalizationRegistry === 'undefined')
@@ -176,12 +176,42 @@ export class HighlightConfig {
176
176
  setMaxInjectionDepth(depth) {
177
177
  wasm.highlightconfig_setMaxInjectionDepth(this.__wbg_ptr, depth);
178
178
  }
179
+ /**
180
+ * Set HTML format to class names: `<span class="keyword">`, etc.
181
+ */
182
+ setHtmlFormatClassNames() {
183
+ wasm.highlightconfig_setHtmlFormatClassNames(this.__wbg_ptr);
184
+ }
185
+ /**
186
+ * Set HTML format to custom elements (default): `<a-k>`, `<a-f>`, etc.
187
+ */
188
+ setHtmlFormatCustomElements() {
189
+ wasm.highlightconfig_setHtmlFormatCustomElements(this.__wbg_ptr);
190
+ }
191
+ /**
192
+ * Set HTML format to class names with custom prefix.
193
+ * @param {string} prefix
194
+ */
195
+ setHtmlFormatClassNamesWithPrefix(prefix) {
196
+ const ptr0 = passStringToWasm0(prefix, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
197
+ const len0 = WASM_VECTOR_LEN;
198
+ wasm.highlightconfig_setHtmlFormatClassNamesWithPrefix(this.__wbg_ptr, ptr0, len0);
199
+ }
179
200
  constructor() {
180
201
  const ret = wasm.highlightconfig_new();
181
202
  this.__wbg_ptr = ret >>> 0;
182
203
  HighlightConfigFinalization.register(this, this.__wbg_ptr, this);
183
204
  return this;
184
205
  }
206
+ /**
207
+ * Set HTML format to custom elements with custom prefix.
208
+ * @param {string} prefix
209
+ */
210
+ setHtmlFormatCustomElementsWithPrefix(prefix) {
211
+ const ptr0 = passStringToWasm0(prefix, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
212
+ const len0 = WASM_VECTOR_LEN;
213
+ wasm.highlightconfig_setHtmlFormatCustomElementsWithPrefix(this.__wbg_ptr, ptr0, len0);
214
+ }
185
215
  }
186
216
  if (Symbol.dispose) HighlightConfig.prototype[Symbol.dispose] = HighlightConfig.prototype.free;
187
217
 
@@ -325,7 +355,7 @@ function __wbg_get_imports() {
325
355
  const ret = Reflect.get(arg0, arg1);
326
356
  return ret;
327
357
  }, arguments) };
328
- imports.wbg.__wbg_isLanguageAvailable_34dd470608352293 = function(arg0, arg1) {
358
+ imports.wbg.__wbg_isLanguageAvailable_bebeb3f045eb460a = function(arg0, arg1) {
329
359
  const ret = arboriumHost.isLanguageAvailable(getStringFromWasm0(arg0, arg1));
330
360
  return ret;
331
361
  };
@@ -333,7 +363,7 @@ function __wbg_get_imports() {
333
363
  const ret = arg0.length;
334
364
  return ret;
335
365
  };
336
- imports.wbg.__wbg_loadGrammar_3b1f0071cede0f25 = function() { return handleError(function (arg0, arg1) {
366
+ imports.wbg.__wbg_loadGrammar_09d7adef1b251231 = function() { return handleError(function (arg0, arg1) {
337
367
  const ret = arboriumHost.loadGrammar(getStringFromWasm0(arg0, arg1));
338
368
  return ret;
339
369
  }, arguments) };
@@ -344,7 +374,7 @@ function __wbg_get_imports() {
344
374
  const a = state0.a;
345
375
  state0.a = 0;
346
376
  try {
347
- return wasm_bindgen__convert__closures_____invoke__h089a09d160a6520b(a, state0.b, arg0, arg1);
377
+ return wasm_bindgen__convert__closures_____invoke__h18c7f9ef50dd6692(a, state0.b, arg0, arg1);
348
378
  } finally {
349
379
  state0.a = a;
350
380
  }
@@ -359,7 +389,7 @@ function __wbg_get_imports() {
359
389
  const ret = new Function(getStringFromWasm0(arg0, arg1));
360
390
  return ret;
361
391
  };
362
- imports.wbg.__wbg_parse_4dfd6e8a8b8e03d3 = function(arg0, arg1, arg2) {
392
+ imports.wbg.__wbg_parse_9d9d59c234d6c63c = function(arg0, arg1, arg2) {
363
393
  const ret = arboriumHost.parse(arg0 >>> 0, getStringFromWasm0(arg1, arg2));
364
394
  return ret;
365
395
  };
@@ -405,7 +435,7 @@ function __wbg_get_imports() {
405
435
  };
406
436
  imports.wbg.__wbindgen_cast_3b1a32895b770b74 = function(arg0, arg1) {
407
437
  // Cast intrinsic for `Closure(Closure { dtor_idx: 10, function: Function { arguments: [Externref], shim_idx: 11, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
408
- const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__hd7b7e163837b9c9e, wasm_bindgen__convert__closures_____invoke__hdf270ce0da308ff1);
438
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__hb099e2ae98169675, wasm_bindgen__convert__closures_____invoke__h6709295d3f31b919);
409
439
  return ret;
410
440
  };
411
441
  imports.wbg.__wbindgen_init_externref_table = function() {
Binary file
package/dist/index.d.ts CHANGED
@@ -5,4 +5,5 @@
5
5
  */
6
6
  export { loadGrammar, highlight, spansToHtml, getConfig } from './loader.js';
7
7
  export { detectLanguage, extractLanguageFromClass, normalizeLanguage } from './detect.js';
8
- export type { Grammar, Span, Injection, ParseResult, ArboriumConfig, } from './types.js';
8
+ export { pluginVersion, availableLanguages } from './plugins-manifest.js';
9
+ export type { Grammar, Session, Span, Injection, ParseResult, ArboriumConfig, } from './types.js';