@arborium/arborium 1.0.2 → 1.0.3

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 (40) hide show
  1. package/dist/arborium.iife.js +2 -2
  2. package/dist/arborium.iife.js.map +1 -1
  3. package/dist/arborium.js +1 -1
  4. package/dist/arborium.js.map +1 -1
  5. package/dist/iife.d.ts +1 -1
  6. package/dist/themes/alabaster.css +71 -68
  7. package/dist/themes/ayu-dark.css +69 -64
  8. package/dist/themes/ayu-light.css +69 -64
  9. package/dist/themes/base-docsrs.css +74 -0
  10. package/dist/themes/base.css +300 -0
  11. package/dist/themes/catppuccin-frappe.css +71 -68
  12. package/dist/themes/catppuccin-latte.css +71 -68
  13. package/dist/themes/catppuccin-macchiato.css +71 -68
  14. package/dist/themes/catppuccin-mocha.css +71 -68
  15. package/dist/themes/cobalt2.css +73 -68
  16. package/dist/themes/dayfox.css +71 -68
  17. package/dist/themes/desert256.css +93 -68
  18. package/dist/themes/docsrs-ayu.css +71 -68
  19. package/dist/themes/docsrs-dark.css +71 -68
  20. package/dist/themes/docsrs-light.css +71 -68
  21. package/dist/themes/dracula.css +71 -68
  22. package/dist/themes/ef-melissa-dark.css +73 -68
  23. package/dist/themes/github-dark.css +71 -68
  24. package/dist/themes/github-light.css +71 -68
  25. package/dist/themes/gruvbox-dark.css +71 -68
  26. package/dist/themes/gruvbox-light.css +71 -68
  27. package/dist/themes/kanagawa-dragon.css +71 -68
  28. package/dist/themes/light-owl.css +98 -68
  29. package/dist/themes/lucius-light.css +73 -68
  30. package/dist/themes/melange-dark.css +73 -68
  31. package/dist/themes/melange-light.css +73 -68
  32. package/dist/themes/monokai.css +71 -68
  33. package/dist/themes/nord.css +71 -68
  34. package/dist/themes/one-dark.css +71 -68
  35. package/dist/themes/rose-pine-moon.css +73 -68
  36. package/dist/themes/solarized-dark.css +73 -68
  37. package/dist/themes/solarized-light.css +73 -68
  38. package/dist/themes/tokyo-night.css +71 -68
  39. package/dist/themes/zenburn.css +71 -68
  40. package/package.json +3 -1
@@ -1,3 +1,3 @@
1
- var arborium=(function(y){"use strict";class I extends Error{constructor(e){super(e),this.name="WasiError"}}class S{write(e){return BigInt(0)}blockingWriteAndFlush(e){}blockingFlush(){}checkWrite(){return BigInt(1048576)}subscribe(){}}class R{read(e){return new Uint8Array(0)}blockingRead(e){return new Uint8Array(0)}subscribe(){}}function Q(){const t=new S,e=new S,s=new R,n={getEnvironment:()=>[],getArguments:()=>[]},r={exit:a=>{if(a.tag==="err")throw new I(`WASI exit with error: ${a.val}`)}},o={getStdin:()=>s},i={getStdout:()=>t},l={getStderr:()=>e},p={now:()=>{const a=Date.now();return{seconds:BigInt(Math.floor(a/1e3)),nanoseconds:a%1e3*1e6}},resolution:()=>({seconds:BigInt(0),nanoseconds:1e6})},w={Descriptor:class{},DirectoryEntryStream:class{},filesystemErrorCode:()=>null},m={getDirectories:()=>[]},c={Error:I},u={InputStream:R,OutputStream:S},g={getRandomBytes:a=>{const h=new Uint8Array(Number(a));return crypto.getRandomValues(h),h},getRandomU64:()=>{const a=new Uint8Array(8);return crypto.getRandomValues(a),new DataView(a.buffer).getBigUint64(0,!0)}};return{"wasi:cli/environment":n,"wasi:cli/exit":r,"wasi:cli/stdin":o,"wasi:cli/stdout":i,"wasi:cli/stderr":l,"wasi:clocks/wall-clock":p,"wasi:filesystem/types":w,"wasi:filesystem/preopens":m,"wasi:io/error":c,"wasi:io/streams":u,"wasi:random/random":g,"wasi:cli/environment@0.2.3":n,"wasi:cli/exit@0.2.3":r,"wasi:cli/stdin@0.2.3":o,"wasi:cli/stdout@0.2.3":i,"wasi:cli/stderr@0.2.3":l,"wasi:clocks/wall-clock@0.2.3":p,"wasi:filesystem/types@0.2.3":w,"wasi:filesystem/preopens@0.2.3":m,"wasi:io/error@0.2.3":c,"wasi:io/streams@0.2.3":u,"wasi:random/random@0.2.3":g}}const X={"arborium:grammar/types@0.1.0":{}},Z={manual:!1,theme:"tokyo-night",selector:"pre code",cdn:"jsdelivr",version:"1",pluginsUrl:"https://arborium.bearcove.eu/plugins.json",hostUrl:""};let v=null,k=null,f={...Z};const j=new Map;let $=null,E=new Set;async function tt(){if($)return;console.debug(`[arborium] Loading plugins manifest: ${f.pluginsUrl}`);const t=await fetch(f.pluginsUrl);if(!t.ok)throw new Error(`Failed to load plugins.json: ${t.status}`);$=await t.json(),E=new Set($.entries.map(e=>e.language)),console.debug(`[arborium] Available languages: ${Array.from(E).join(", ")}`)}async function U(t){const e=j.get(t);if(e)return console.debug(`[arborium] Grammar '${t}' found in cache`),e;await tt();const s=$?.entries.find(n=>n.language===t);if(!s)return console.debug(`[arborium] Grammar '${t}' not found in manifest`),null;try{const n=s.cdn_js,r=n.substring(0,n.lastIndexOf("/"));console.debug(`[arborium] Loading grammar '${t}' from ${n}`);const o=await import(n),i=async u=>{const g=`${r}/${u}`,a=await fetch(g);if(!a.ok)throw new Error(`Failed to fetch WASM ${u}: ${a.status}`);const h=await a.arrayBuffer();return WebAssembly.compile(h)},p={...Q(),...X},w=await o.instantiate(i,p),m=w.plugin||w["arborium:grammar/plugin@0.1.0"];if(!m)return console.error(`Grammar '${t}' missing plugin interface`),null;const c={languageId:t,injectionLanguages:m.injectionLanguages?.()??[],parse:u=>{const g=m.createSession();try{m.setText(g,u);const a=m.parse(g);if(a.tag==="err"){const gt=a.val;return console.error(`[arborium] Parse error: ${gt?.message}`),{spans:[],injections:[]}}const h=a.tag==="ok"?a.val:a;if(!h||typeof h!="object")return console.error("[arborium] Unexpected parse result:",a),{spans:[],injections:[]};const K=h;return{spans:K.spans||[],injections:K.injections||[]}}finally{m.freeSession(g)}}};return j.set(t,c),console.debug(`[arborium] Grammar '${t}' loaded successfully`),c}catch(n){return console.error(`[arborium] Failed to load grammar '${t}':`,n),null}}const C=new Map;let et=1;function st(){window.arboriumHost={isLanguageAvailable(t){return E.has(t)||j.has(t)},async loadGrammar(t){const e=await U(t);if(!e)return 0;for(const[n,r]of C)if(r===e)return n;const s=et++;return C.set(s,e),s},parse(t,e){const s=C.get(t);return s?s.parse(e):{spans:[],injections:[]}}}}function nt(){if(f.hostUrl)return f.hostUrl;const t=f.cdn,e=f.version;let s;t==="jsdelivr"?s="https://cdn.jsdelivr.net/npm":t==="unpkg"?s="https://unpkg.com":s=t;const n=e==="latest"?"":`@${e}`;return`${s}/@arborium/arborium${n}/dist`}async function rt(){return v||k||(k=(async()=>{st();const t=nt(),e=`${t}/arborium_host.js`,s=`${t}/arborium_host_bg.wasm`;console.debug(`[arborium] Loading host from ${e}`);try{const n=await import(e);return await n.default(s),v={highlight:n.highlight,isLanguageAvailable:n.isLanguageAvailable},console.debug("[arborium] Host loaded successfully"),v}catch(n){return console.error("[arborium] Failed to load host:",n),null}})(),k)}async function M(t,e,s){const n=await rt();if(n)try{return n.highlight(t,e)}catch(i){console.warn("Host highlight failed, falling back to JS:",i)}const r=await U(t);if(!r)return A(e);const o=r.parse(e);return P(e,o.spans)}async function W(t,e){const s=await U(t);return s?{languageId:()=>s.languageId,injectionLanguages:()=>s.injectionLanguages,highlight:async n=>{const r=s.parse(n);return P(n,r.spans)},parse:n=>s.parse(n),dispose:()=>{}}:null}function P(t,e){const s=[...e].sort((o,i)=>o.start-i.start);let n="",r=0;for(const o of s){if(o.start<r)continue;o.start>r&&(n+=A(t.slice(r,o.start)));const i=ot(o.capture),l=A(t.slice(o.start,o.end));i?n+=`<a-${i}>${l}</a-${i}>`:n+=l,r=o.end}return r<t.length&&(n+=A(t.slice(r))),n}function ot(t){return t.startsWith("keyword")||t==="include"||t==="conditional"?"k":t.startsWith("function")||t.startsWith("method")?"f":t.startsWith("string")||t==="character"?"s":t.startsWith("comment")?"c":t.startsWith("type")?"t":t.startsWith("variable")?"v":t.startsWith("number")||t==="float"?"n":t.startsWith("operator")?"o":t.startsWith("punctuation")?"p":t.startsWith("tag")?"tg":t.startsWith("attribute")?"at":null}function A(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function x(t){return t?{...f,...t}:{...f}}function B(t){f={...f,...t}}const it=[[/^#!.*\bpython[23]?\b/,"python"],[/^#!.*\bnode\b/,"javascript"],[/^#!.*\bdeno\b/,"typescript"],[/^#!.*\bbun\b/,"typescript"],[/^#!.*\bruby\b/,"ruby"],[/^#!.*\bperl\b/,"perl"],[/^#!.*\bphp\b/,"php"],[/^#!.*\bbash\b/,"bash"],[/^#!.*\bzsh\b/,"zsh"],[/^#!.*\bsh\b/,"bash"],[/^#!.*\blua\b/,"lua"],[/^#!.*\bawk\b/,"awk"]],at=[[/\b(fn|impl|trait|pub\s+fn|let\s+mut|&mut|->)\b/,"rust"],[/\b(func|package\s+\w+|import\s+\(|go\s+func|chan\s+\w+)\b/,"go"],[/\b(def\s+\w+\s*\(|import\s+\w+|from\s+\w+\s+import|class\s+\w+:)\b/,"python"],[/:\s*(string|number|boolean|void)\b|\binterface\s+\w+\s*\{/,"typescript"],[/\b(const|let|var)\s+\w+\s*=|function\s+\w+\s*\(|=>\s*\{/,"javascript"],[/\b(def\s+\w+|end\b|do\s*\|.*\||puts\s+|require\s+['"])\b/,"ruby"],[/\b(public\s+class|private\s+\w+|System\.out\.println)\b/,"java"],[/\b(#include\s*<|std::|template\s*<|nullptr|cout\s*<<)\b/,"cpp"],[/\b(#include\s*[<"]|printf\s*\(|int\s+main\s*\(|void\s+\w+\s*\()\b/,"c"],[/\b(namespace\s+\w+|using\s+System|public\s+static\s+void)\b/,"c-sharp"],[/<\?php|\$\w+\s*=/,"php"],[/\b(func\s+\w+|var\s+\w+:\s*\w+|let\s+\w+:\s*\w+|@objc)\b/,"swift"],[/\b(fun\s+\w+|val\s+\w+|var\s+\w+:|data\s+class)\b/,"kotlin"],[/\b(def\s+\w+|val\s+\w+|var\s+\w+|object\s+\w+|case\s+class)\b/,"scala"],[/\b(module\s+\w+|import\s+qualified|data\s+\w+\s*=|::\s*\w+\s*->)\b/,"haskell"],[/\b(defmodule\s+\w+|def\s+\w+|defp\s+\w+|\|>)\b/,"elixir"],[/\b(local\s+\w+\s*=|function\s+\w+\.\w+|require\s*\()\b/,"lua"],[/\b(SELECT\s+.*\s+FROM|INSERT\s+INTO|CREATE\s+TABLE|ALTER\s+TABLE)\b/i,"sql"],[/\b(if\s+\[\s*|then\b|fi\b|echo\s+["']|export\s+\w+=)\b/,"bash"],[/^\s*[\w-]+:\s*[\w\-"'[{]|^---\s*$/,"yaml"],[/^\s*\{[\s\S]*"[\w-]+":\s*/,"json"],[/^\s*\[[\w.-]+\]\s*$|^\s*\w+\s*=\s*["'\d\[]/,"toml"],[/<(!DOCTYPE|html|head|body|div|span|p|a\s)/i,"html"],[/^\s*[\w.#@][\w\s,#.:>+~-]*\{[^}]*\}|@media\s|@import\s/,"css"],[/^#{1,6}\s+\w|^\s*[-*+]\s+\w|^\s*\d+\.\s+\w|```\w*\n/,"markdown"],[/<\?xml|<[\w:-]+\s+xmlns/,"xml"],[/^FROM\s+\w+|^RUN\s+|^COPY\s+|^ENTRYPOINT\s+/m,"dockerfile"],[/\b(server\s*\{|location\s+[\/~]|proxy_pass\s+)\b/,"nginx"],[/\b(pub\s+fn|const\s+\w+\s*=|@import\(|comptime)\b/,"zig"]];function F(t){const e=t.split(`
2
- `)[0];for(const[s,n]of it)if(s.test(e))return n;for(const[s,n]of at)if(s.test(t))return n;return null}function H(t){const e=t.match(/\blanguage-(\w+)\b/);if(e)return e[1];const s=t.match(/\blang-(\w+)\b/);if(s)return s[1];const n=new Set(["rust","javascript","typescript","python","ruby","go","java","c","cpp","csharp","php","swift","kotlin","scala","haskell","elixir","lua","sql","bash","shell","yaml","json","toml","html","css","xml","markdown","dockerfile","nginx","zig","text","plaintext","console","sh"]);for(const r of t.split(/\s+/))if(n.has(r.toLowerCase()))return r.toLowerCase();return null}function L(t){const e={js:"javascript",ts:"typescript",py:"python",rb:"ruby",rs:"rust",sh:"bash",shell:"bash",yml:"yaml",cs:"c-sharp",csharp:"c-sharp","c++":"cpp","c#":"c-sharp","f#":"fsharp",dockerfile:"dockerfile",docker:"dockerfile",makefile:"make",plaintext:"text",plain:"text",txt:"text"},s=t.toLowerCase();return e[s]||s}const d=document.currentScript;function ct(){if(!d?.src)return new URLSearchParams;try{return new URL(d.src).searchParams}catch{return new URLSearchParams}}function lt(){if(!d)return{};const t={},e=ct();d.hasAttribute("data-manual")&&(t.manual=!0);const s=d.getAttribute("data-theme");s&&(t.theme=s);const n=d.getAttribute("data-selector");n&&(t.selector=n);const r=d.getAttribute("data-cdn");r&&(t.cdn=r);const o=d.getAttribute("data-version");o&&(t.version=o);const i=e.get("pluginsUrl");i&&(t.pluginsUrl=i);const l=e.get("hostUrl");return l&&(t.hostUrl=l),t}function N(){return document.documentElement.hasAttribute("data-docs-rs-theme")}function _(t){if(!t)return null;const e={light:"docsrs-light",dark:"docsrs-dark",ayu:"docsrs-ayu"};return e[t]?e[t]:null}function D(){if(N()){const s=_(document.documentElement.dataset.theme);if(s)return s;const n=_(document.documentElement.dataset.docsRsTheme);if(n)return n}const t=document.documentElement.dataset.theme;return t==="light"?"github-light":t==="dark"?"tokyo-night":window.matchMedia("(prefers-color-scheme: light)").matches?"github-light":"tokyo-night"}function b(){const t=window.Arborium||{},e=lt(),s={...t,...e};return s.theme||(s.theme=D()),B(s),x()}function ut(t){return Array.from(document.querySelectorAll(t))}function mt(t){const e=["hljs","highlighted","prism-code","shiki"];for(const r of e)if(t.classList.contains(r))return!0;const s=t.querySelectorAll("span[class]");return s.length>0&&Array.from(s).filter(o=>o.className&&o.className.length>0).length>=3||t.querySelectorAll("a").length>=2}function O(t){const e=t.getAttribute("data-lang");if(e)return L(e);const s=t.className,n=H(s);if(n)return L(n);const r=t.parentElement;if(r){const i=r.getAttribute("data-lang");if(i)return L(i);const l=H(r.className);if(l)return L(l)}const o=t.textContent||"";return F(o)}function q(t){const e=`arborium-theme-${t}`;if(document.getElementById(e))return;const s=b();let n;if(s.hostUrl)n=`${s.hostUrl}/themes/${t}.css`;else{const o=s.cdn,i=s.version;let l;o==="jsdelivr"?l="https://cdn.jsdelivr.net/npm":o==="unpkg"?l="https://unpkg.com":l=o;const p=i==="latest"?"":`@${i}`;n=`${l}/@arborium/arborium${p}/dist/themes/${t}.css`}console.debug(`[arborium] Loading theme: ${n}`);const r=document.createElement("link");r.id=e,r.rel="stylesheet",r.href=n,document.head.appendChild(r)}async function G(t,e,s){const n=t.textContent||"";if(n.trim())try{const r=await M(e,n,s);t.innerHTML=r,t.setAttribute("data-highlighted","true"),t.setAttribute("data-lang",e)}catch(r){console.warn(`[arborium] Failed to highlight ${e}:`,r)}}async function T(){const t=b();q(t.theme);const e=ut(t.selector);if(e.length===0)return;const s=new Map,n=[];for(const c of e){if(c.hasAttribute("data-highlighted")||mt(c))continue;const u=O(c);if(u){const g=s.get(u)||[];g.push(c),s.set(u,g)}else n.push(c)}const r=Array.from(s.keys()),o=r.map(c=>W(c).catch(u=>(console.warn(`[arborium] Failed to load grammar for ${c}:`,u),null))),i=await Promise.all(o),l=[];for(let c=0;c<r.length;c++){const u=r[c];if(!i[c])continue;const a=s.get(u)||[];for(const h of a)l.push(G(h,u,t))}await Promise.all(l);const p=e.length,w=e.filter(c=>c.hasAttribute("data-highlighted")).length,m=n.length;(w>0||m>0)&&console.debug(`[arborium] Highlighted ${w}/${p} blocks`+(m>0?` (${m} unknown language)`:""))}async function z(t){x({...b(),...t}),await T()}async function Y(t,e,s){const n=x({...b(),...s}),r=e||O(t);if(!r){console.warn("[arborium] Could not detect language for element");return}await G(t,r,n)}window.arborium={highlightAll:z,highlightElement:Y,loadGrammar:W,highlight:M,detectLanguage:F,config:b()};async function V(){const t=D();b().theme!==t&&(B({theme:t}),window.arborium.config=b(),q(t),console.debug(`[arborium] Theme changed to: ${t}`))}function J(){new MutationObserver(e=>{for(const s of e){const n=s.attributeName;if(n==="data-docs-rs-theme"||n==="data-theme"&&N()){V();break}}}).observe(document.documentElement,{attributes:!0}),window.matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>V())}return b().manual||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{T(),J()}):(T(),J())),y.highlightAll=z,y.highlightElement=Y,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"}),y})({});
1
+ var arborium=(function(v){"use strict";class R extends Error{constructor(e){super(e),this.name="WasiError"}}class E{write(e){return BigInt(0)}blockingWriteAndFlush(e){}blockingFlush(){}checkWrite(){return BigInt(1048576)}subscribe(){}}class B{read(e){return new Uint8Array(0)}blockingRead(e){return new Uint8Array(0)}subscribe(){}}function Z(){const t=new E,e=new E,s=new B,n={getEnvironment:()=>[],getArguments:()=>[]},r={exit:i=>{if(i.tag==="err")throw new R(`WASI exit with error: ${i.val}`)}},o={getStdin:()=>s},c={getStdout:()=>t},u={getStderr:()=>e},y={now:()=>{const i=Date.now();return{seconds:BigInt(Math.floor(i/1e3)),nanoseconds:i%1e3*1e6}},resolution:()=>({seconds:BigInt(0),nanoseconds:1e6})},p={Descriptor:class{},DirectoryEntryStream:class{},filesystemErrorCode:()=>null},m={getDirectories:()=>[]},a={Error:R},l={InputStream:B,OutputStream:E},g={getRandomBytes:i=>{const d=new Uint8Array(Number(i));return crypto.getRandomValues(d),d},getRandomU64:()=>{const i=new Uint8Array(8);return crypto.getRandomValues(i),new DataView(i.buffer).getBigUint64(0,!0)}};return{"wasi:cli/environment":n,"wasi:cli/exit":r,"wasi:cli/stdin":o,"wasi:cli/stdout":c,"wasi:cli/stderr":u,"wasi:clocks/wall-clock":y,"wasi:filesystem/types":p,"wasi:filesystem/preopens":m,"wasi:io/error":a,"wasi:io/streams":l,"wasi:random/random":g,"wasi:cli/environment@0.2.3":n,"wasi:cli/exit@0.2.3":r,"wasi:cli/stdin@0.2.3":o,"wasi:cli/stdout@0.2.3":c,"wasi:cli/stderr@0.2.3":u,"wasi:clocks/wall-clock@0.2.3":y,"wasi:filesystem/types@0.2.3":p,"wasi:filesystem/preopens@0.2.3":m,"wasi:io/error@0.2.3":a,"wasi:io/streams@0.2.3":l,"wasi:random/random@0.2.3":g}}const tt={"arborium:grammar/types@0.1.0":{}},et={manual:!1,theme:"one-dark",selector:"pre code",cdn:"jsdelivr",version:"1",pluginsUrl:"https://arborium.bearcove.eu/plugins.json",hostUrl:""};let k=null,$=null,f={...et};const j=new Map;let L=null,C=new Set;async function st(){if(L)return;console.debug(`[arborium] Loading plugins manifest: ${f.pluginsUrl}`);const t=await fetch(f.pluginsUrl);if(!t.ok)throw new Error(`Failed to load plugins.json: ${t.status}`);L=await t.json(),C=new Set(L.entries.map(e=>e.language)),console.debug(`[arborium] Available languages: ${Array.from(C).join(", ")}`)}async function U(t){const e=j.get(t);if(e)return console.debug(`[arborium] Grammar '${t}' found in cache`),e;await st();const s=L?.entries.find(n=>n.language===t);if(!s)return console.debug(`[arborium] Grammar '${t}' not found in manifest`),null;try{const n=s.cdn_js,r=n.substring(0,n.lastIndexOf("/"));console.debug(`[arborium] Loading grammar '${t}' from ${n}`);const o=await import(n),c=async l=>{const g=`${r}/${l}`,i=await fetch(g);if(!i.ok)throw new Error(`Failed to fetch WASM ${l}: ${i.status}`);const d=await i.arrayBuffer();return WebAssembly.compile(d)},y={...Z(),...tt},p=await o.instantiate(c,y),m=p.plugin||p["arborium:grammar/plugin@0.1.0"];if(!m)return console.error(`Grammar '${t}' missing plugin interface`),null;const a={languageId:t,injectionLanguages:m.injectionLanguages?.()??[],parse:l=>{const g=m.createSession();try{m.setText(g,l);const i=m.parse(g);if(i.tag==="err"){const ht=i.val;return console.error(`[arborium] Parse error: ${ht?.message}`),{spans:[],injections:[]}}const d=i.tag==="ok"?i.val:i;if(!d||typeof d!="object")return console.error("[arborium] Unexpected parse result:",i),{spans:[],injections:[]};const X=d;return{spans:X.spans||[],injections:X.injections||[]}}finally{m.freeSession(g)}}};return j.set(t,a),console.debug(`[arborium] Grammar '${t}' loaded successfully`),a}catch(n){return console.error(`[arborium] Failed to load grammar '${t}':`,n),null}}const T=new Map;let nt=1;function rt(){window.arboriumHost={isLanguageAvailable(t){return C.has(t)||j.has(t)},async loadGrammar(t){const e=await U(t);if(!e)return 0;for(const[n,r]of T)if(r===e)return n;const s=nt++;return T.set(s,e),s},parse(t,e){const s=T.get(t);return s?s.parse(e):{spans:[],injections:[]}}}}function ot(){if(f.hostUrl)return f.hostUrl;const t=f.cdn,e=f.version;let s;t==="jsdelivr"?s="https://cdn.jsdelivr.net/npm":t==="unpkg"?s="https://unpkg.com":s=t;const n=e==="latest"?"":`@${e}`;return`${s}/@arborium/arborium${n}/dist`}async function it(){return k||$||($=(async()=>{rt();const t=ot(),e=`${t}/arborium_host.js`,s=`${t}/arborium_host_bg.wasm`;console.debug(`[arborium] Loading host from ${e}`);try{const n=await import(e);return await n.default(s),k={highlight:n.highlight,isLanguageAvailable:n.isLanguageAvailable},console.debug("[arborium] Host loaded successfully"),k}catch(n){return console.error("[arborium] Failed to load host:",n),null}})(),$)}async function M(t,e,s){const n=await it();if(n)try{return n.highlight(t,e)}catch(c){console.warn("Host highlight failed, falling back to JS:",c)}const r=await U(t);if(!r)return S(e);const o=r.parse(e);return P(e,o.spans)}async function W(t,e){const s=await U(t);return s?{languageId:()=>s.languageId,injectionLanguages:()=>s.injectionLanguages,highlight:async n=>{const r=s.parse(n);return P(n,r.spans)},parse:n=>s.parse(n),dispose:()=>{}}:null}function P(t,e){const s=[...e].sort((o,c)=>o.start-c.start);let n="",r=0;for(const o of s){if(o.start<r)continue;o.start>r&&(n+=S(t.slice(r,o.start)));const c=at(o.capture),u=S(t.slice(o.start,o.end));c?n+=`<a-${c}>${u}</a-${c}>`:n+=u,r=o.end}return r<t.length&&(n+=S(t.slice(r))),n}function at(t){return t.startsWith("keyword")||t==="include"||t==="conditional"?"k":t.startsWith("function")||t.startsWith("method")?"f":t.startsWith("string")||t==="character"?"s":t.startsWith("comment")?"c":t.startsWith("type")?"t":t.startsWith("variable")?"v":t.startsWith("number")||t==="float"?"n":t.startsWith("operator")?"o":t.startsWith("punctuation")?"p":t.startsWith("tag")?"tg":t.startsWith("attribute")?"at":null}function S(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function x(t){return t?{...f,...t}:{...f}}function F(t){f={...f,...t}}const ct=[[/^#!.*\bpython[23]?\b/,"python"],[/^#!.*\bnode\b/,"javascript"],[/^#!.*\bdeno\b/,"typescript"],[/^#!.*\bbun\b/,"typescript"],[/^#!.*\bruby\b/,"ruby"],[/^#!.*\bperl\b/,"perl"],[/^#!.*\bphp\b/,"php"],[/^#!.*\bbash\b/,"bash"],[/^#!.*\bzsh\b/,"zsh"],[/^#!.*\bsh\b/,"bash"],[/^#!.*\blua\b/,"lua"],[/^#!.*\bawk\b/,"awk"]],lt=[[/\b(fn|impl|trait|pub\s+fn|let\s+mut|&mut|->)\b/,"rust"],[/\b(func|package\s+\w+|import\s+\(|go\s+func|chan\s+\w+)\b/,"go"],[/\b(def\s+\w+\s*\(|import\s+\w+|from\s+\w+\s+import|class\s+\w+:)\b/,"python"],[/:\s*(string|number|boolean|void)\b|\binterface\s+\w+\s*\{/,"typescript"],[/\b(const|let|var)\s+\w+\s*=|function\s+\w+\s*\(|=>\s*\{/,"javascript"],[/\b(def\s+\w+|end\b|do\s*\|.*\||puts\s+|require\s+['"])\b/,"ruby"],[/\b(public\s+class|private\s+\w+|System\.out\.println)\b/,"java"],[/\b(#include\s*<|std::|template\s*<|nullptr|cout\s*<<)\b/,"cpp"],[/\b(#include\s*[<"]|printf\s*\(|int\s+main\s*\(|void\s+\w+\s*\()\b/,"c"],[/\b(namespace\s+\w+|using\s+System|public\s+static\s+void)\b/,"c-sharp"],[/<\?php|\$\w+\s*=/,"php"],[/\b(func\s+\w+|var\s+\w+:\s*\w+|let\s+\w+:\s*\w+|@objc)\b/,"swift"],[/\b(fun\s+\w+|val\s+\w+|var\s+\w+:|data\s+class)\b/,"kotlin"],[/\b(def\s+\w+|val\s+\w+|var\s+\w+|object\s+\w+|case\s+class)\b/,"scala"],[/\b(module\s+\w+|import\s+qualified|data\s+\w+\s*=|::\s*\w+\s*->)\b/,"haskell"],[/\b(defmodule\s+\w+|def\s+\w+|defp\s+\w+|\|>)\b/,"elixir"],[/\b(local\s+\w+\s*=|function\s+\w+\.\w+|require\s*\()\b/,"lua"],[/\b(SELECT\s+.*\s+FROM|INSERT\s+INTO|CREATE\s+TABLE|ALTER\s+TABLE)\b/i,"sql"],[/\b(if\s+\[\s*|then\b|fi\b|echo\s+["']|export\s+\w+=)\b/,"bash"],[/^\s*[\w-]+:\s*[\w\-"'[{]|^---\s*$/,"yaml"],[/^\s*\{[\s\S]*"[\w-]+":\s*/,"json"],[/^\s*\[[\w.-]+\]\s*$|^\s*\w+\s*=\s*["'\d\[]/,"toml"],[/<(!DOCTYPE|html|head|body|div|span|p|a\s)/i,"html"],[/^\s*[\w.#@][\w\s,#.:>+~-]*\{[^}]*\}|@media\s|@import\s/,"css"],[/^#{1,6}\s+\w|^\s*[-*+]\s+\w|^\s*\d+\.\s+\w|```\w*\n/,"markdown"],[/<\?xml|<[\w:-]+\s+xmlns/,"xml"],[/^FROM\s+\w+|^RUN\s+|^COPY\s+|^ENTRYPOINT\s+/m,"dockerfile"],[/\b(server\s*\{|location\s+[\/~]|proxy_pass\s+)\b/,"nginx"],[/\b(pub\s+fn|const\s+\w+\s*=|@import\(|comptime)\b/,"zig"]];function H(t){const e=t.split(`
2
+ `)[0];for(const[s,n]of ct)if(s.test(e))return n;for(const[s,n]of lt)if(s.test(t))return n;return null}function N(t){const e=t.match(/\blanguage-(\w+)\b/);if(e)return e[1];const s=t.match(/\blang-(\w+)\b/);if(s)return s[1];const n=new Set(["rust","javascript","typescript","python","ruby","go","java","c","cpp","csharp","php","swift","kotlin","scala","haskell","elixir","lua","sql","bash","shell","yaml","json","toml","html","css","xml","markdown","dockerfile","nginx","zig","text","plaintext","console","sh"]);for(const r of t.split(/\s+/))if(n.has(r.toLowerCase()))return r.toLowerCase();return null}function A(t){const e={js:"javascript",ts:"typescript",py:"python",rb:"ruby",rs:"rust",sh:"bash",shell:"bash",yml:"yaml",cs:"c-sharp",csharp:"c-sharp","c++":"cpp","c#":"c-sharp","f#":"fsharp",dockerfile:"dockerfile",docker:"dockerfile",makefile:"make",plaintext:"text",plain:"text",txt:"text"},s=t.toLowerCase();return e[s]||s}const h=document.currentScript;function ut(){if(!h?.src)return new URLSearchParams;try{return new URL(h.src).searchParams}catch{return new URLSearchParams}}function mt(){if(!h)return{};const t={},e=ut();h.hasAttribute("data-manual")&&(t.manual=!0);const s=h.getAttribute("data-theme");s&&(t.theme=s);const n=h.getAttribute("data-selector");n&&(t.selector=n);const r=h.getAttribute("data-cdn");r&&(t.cdn=r);const o=h.getAttribute("data-version");o&&(t.version=o);const c=e.get("pluginsUrl");c&&(t.pluginsUrl=c);const u=e.get("hostUrl");return u&&(t.hostUrl=u),t}function _(){return document.documentElement.hasAttribute("data-docs-rs-theme")}function D(t){if(!t)return null;const e={light:"docsrs-light",dark:"docsrs-dark",ayu:"docsrs-ayu"};return e[t]?e[t]:null}function O(){if(_()){const s=D(document.documentElement.dataset.theme);if(s)return s;const n=D(document.documentElement.dataset.docsRsTheme);if(n)return n}const t=document.documentElement.dataset.theme;return t==="light"?"github-light":t==="dark"?"one-dark":window.matchMedia("(prefers-color-scheme: light)").matches?"github-light":"one-dark"}function b(){const t=window.Arborium||{},e=mt(),s={...t,...e};return s.theme||(s.theme=O()),F(s),x()}function gt(t){return Array.from(document.querySelectorAll(t))}function dt(t){const e=["hljs","highlighted","prism-code","shiki"];for(const r of e)if(t.classList.contains(r))return!0;const s=t.querySelectorAll("span[class]");return s.length>0&&Array.from(s).filter(o=>o.className&&o.className.length>0).length>=3||t.querySelectorAll("a").length>=2}function q(t){const e=t.getAttribute("data-lang");if(e)return A(e);const s=t.className,n=N(s);if(n)return A(n);const r=t.parentElement;if(r){const c=r.getAttribute("data-lang");if(c)return A(c);const u=N(r.className);if(u)return A(u)}const o=t.textContent||"";return H(o)}function G(){const t=b();if(t.hostUrl)return`${t.hostUrl}/themes`;const e=t.cdn,s=t.version;let n;e==="jsdelivr"?n="https://cdn.jsdelivr.net/npm":e==="unpkg"?n="https://unpkg.com":n=e;const r=s==="latest"?"":`@${s}`;return`${n}/@arborium/arborium${r}/dist/themes`}function ft(){const t="arborium-base";if(document.getElementById(t))return;const e=`${G()}/base-docsrs.css`;console.debug(`[arborium] Loading base CSS: ${e}`);const s=document.createElement("link");s.id=t,s.rel="stylesheet",s.href=e,document.head.appendChild(s)}let w=null;function z(t){if(w&&w!==t){const r=document.getElementById(`arborium-theme-${w}`);r&&(r.remove(),console.debug(`[arborium] Removed theme: ${w}`))}const e=`arborium-theme-${t}`;if(document.getElementById(e)){w=t;return}const s=`${G()}/${t}.css`;console.debug(`[arborium] Loading theme: ${s}`);const n=document.createElement("link");n.id=e,n.rel="stylesheet",n.href=s,document.head.appendChild(n),w=t}async function Y(t,e,s){const n=t.textContent||"";if(n.trim())try{const r=await M(e,n,s);t.innerHTML=r,t.setAttribute("data-highlighted","true"),t.setAttribute("data-lang",e)}catch(r){console.warn(`[arborium] Failed to highlight ${e}:`,r)}}async function I(){const t=b();ft(),z(t.theme);const e=gt(t.selector);if(e.length===0)return;const s=new Map,n=[];for(const a of e){if(a.hasAttribute("data-highlighted")||dt(a))continue;const l=q(a);if(l){const g=s.get(l)||[];g.push(a),s.set(l,g)}else n.push(a)}const r=Array.from(s.keys()),o=r.map(a=>W(a).catch(l=>(console.warn(`[arborium] Failed to load grammar for ${a}:`,l),null))),c=await Promise.all(o),u=[];for(let a=0;a<r.length;a++){const l=r[a];if(!c[a])continue;const i=s.get(l)||[];for(const d of i)u.push(Y(d,l,t))}await Promise.all(u);const y=e.length,p=e.filter(a=>a.hasAttribute("data-highlighted")).length,m=n.length;(p>0||m>0)&&console.debug(`[arborium] Highlighted ${p}/${y} blocks`+(m>0?` (${m} unknown language)`:""))}async function V(t){x({...b(),...t}),await I()}async function J(t,e,s){const n=x({...b(),...s}),r=e||q(t);if(!r){console.warn("[arborium] Could not detect language for element");return}await Y(t,r,n)}window.arborium={highlightAll:V,highlightElement:J,loadGrammar:W,highlight:M,detectLanguage:H,config:b()};async function K(){const t=O();b().theme!==t&&(F({theme:t}),window.arborium.config=b(),z(t),console.debug(`[arborium] Theme changed to: ${t}`))}function Q(){new MutationObserver(e=>{for(const s of e){const n=s.attributeName;if(n==="data-docs-rs-theme"||n==="data-theme"&&_()){K();break}}}).observe(document.documentElement,{attributes:!0}),window.matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>K())}return b().manual||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{I(),Q()}):(I(),Q())),v.highlightAll=V,v.highlightElement=J,Object.defineProperty(v,Symbol.toStringTag,{value:"Module"}),v})({});
3
3
  //# sourceMappingURL=arborium.iife.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"arborium.iife.js","sources":["../src/wasi-shims.ts","../src/loader.ts","../src/detect.ts","../src/iife.ts"],"sourcesContent":["/**\n * Minimal WASI shims for browser environment.\n * These provide stub implementations for WASI interfaces that\n * the grammar plugins require but don't actually use.\n */\n\n// Error type for WASI I/O\nclass WasiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WasiError';\n }\n}\n\n// Minimal stream implementation\nclass OutputStream {\n write(_contents: Uint8Array): bigint {\n // Silently discard output\n return BigInt(0);\n }\n\n blockingWriteAndFlush(_contents: Uint8Array): void {\n // No-op\n }\n\n blockingFlush(): void {\n // No-op\n }\n\n checkWrite(): bigint {\n return BigInt(1024 * 1024); // Allow large writes\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\nclass InputStream {\n read(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n blockingRead(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\n// Create the WASI import object expected by jco-generated modules\nexport function createWasiImports() {\n const stdout = new OutputStream();\n const stderr = new OutputStream();\n const stdin = new InputStream();\n\n // WASI interface implementations\n const environment = {\n getEnvironment: (): Array<[string, string]> => [],\n getArguments: (): string[] => [],\n };\n\n const exit = {\n exit: (status: { tag: string; val?: number }): void => {\n if (status.tag === 'err') {\n throw new WasiError(`WASI exit with error: ${status.val}`);\n }\n },\n };\n\n const stdinIface = { getStdin: () => stdin };\n const stdoutIface = { getStdout: () => stdout };\n const stderrIface = { getStderr: () => stderr };\n\n const wallClock = {\n now: (): { seconds: bigint; nanoseconds: number } => {\n const ms = Date.now();\n return {\n seconds: BigInt(Math.floor(ms / 1000)),\n nanoseconds: (ms % 1000) * 1_000_000,\n };\n },\n resolution: (): { seconds: bigint; nanoseconds: number } => {\n return { seconds: BigInt(0), nanoseconds: 1_000_000 };\n },\n };\n\n const filesystemTypes = {\n Descriptor: class {},\n DirectoryEntryStream: class {},\n filesystemErrorCode: () => null,\n };\n\n const preopens = {\n getDirectories: (): Array<[unknown, string]> => [],\n };\n\n const ioError = { Error: WasiError };\n const streams = { InputStream, OutputStream };\n\n const random = {\n getRandomBytes: (len: bigint): Uint8Array => {\n const bytes = new Uint8Array(Number(len));\n crypto.getRandomValues(bytes);\n return bytes;\n },\n getRandomU64: (): bigint => {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n const view = new DataView(bytes.buffer);\n return view.getBigUint64(0, true);\n },\n };\n\n // Return both versioned (@0.2.3) and unversioned imports for compatibility\n return {\n // Unversioned (used by published grammars)\n 'wasi:cli/environment': environment,\n 'wasi:cli/exit': exit,\n 'wasi:cli/stdin': stdinIface,\n 'wasi:cli/stdout': stdoutIface,\n 'wasi:cli/stderr': stderrIface,\n 'wasi:clocks/wall-clock': wallClock,\n 'wasi:filesystem/types': filesystemTypes,\n 'wasi:filesystem/preopens': preopens,\n 'wasi:io/error': ioError,\n 'wasi:io/streams': streams,\n 'wasi:random/random': random,\n\n // Versioned @0.2.3 (for newer builds)\n 'wasi:cli/environment@0.2.3': environment,\n 'wasi:cli/exit@0.2.3': exit,\n 'wasi:cli/stdin@0.2.3': stdinIface,\n 'wasi:cli/stdout@0.2.3': stdoutIface,\n 'wasi:cli/stderr@0.2.3': stderrIface,\n 'wasi:clocks/wall-clock@0.2.3': wallClock,\n 'wasi:filesystem/types@0.2.3': filesystemTypes,\n 'wasi:filesystem/preopens@0.2.3': preopens,\n 'wasi:io/error@0.2.3': ioError,\n 'wasi:io/streams@0.2.3': streams,\n 'wasi:random/random@0.2.3': random,\n };\n}\n\n// Grammar types import (the plugin exports these)\nexport const grammarTypesImport = {\n 'arborium:grammar/types@0.1.0': {\n // Types are just interfaces, nothing to export\n },\n};\n","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Fetch plugins.json from arborium.bearcove.eu to get grammar CDN URLs\n * 2. Load grammar WIT components on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport { createWasiImports, grammarTypesImport } from \"./wasi-shims.js\";\nimport type { ParseResult, ArboriumConfig, Grammar, Span, Injection } from \"./types.js\";\n\n// Default config\nexport const defaultConfig: Required<ArboriumConfig> = {\n manual: false,\n theme: \"tokyo-night\",\n selector: \"pre code\",\n cdn: \"jsdelivr\",\n version: \"1\", // Major version - allows patch/minor upgrades via CDN\n pluginsUrl: \"https://arborium.bearcove.eu/plugins.json\",\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// Plugin manifest from plugins.json\ninterface PluginEntry {\n language: string;\n package: string;\n version: string;\n cdn_js: string;\n cdn_wasm: string;\n local_js: string;\n local_wasm: string;\n}\n\ninterface PluginsManifest {\n dev_mode: boolean;\n generated_at: string;\n entries: PluginEntry[];\n}\n\nlet pluginsManifest: PluginsManifest | null = null;\n\n// Languages we know are available (from plugins.json)\nlet availableLanguages: Set<string> = new Set();\n\n/** WIT Result type as returned by jco-generated code */\ntype WitResult<T, E> = { tag: \"ok\"; val: T } | { tag: \"err\"; val: E };\n\n/** Plugin interface as exported by jco-generated WIT components */\ninterface JcoPlugin {\n languageId(): string;\n injectionLanguages(): string[];\n createSession(): number;\n freeSession(session: number): void;\n setText(session: number, text: string): void;\n parse(session: number): WitResult<ParseResult, { message: string }>;\n}\n\n/** A loaded grammar plugin (WIT component) */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n parse: (text: string) => ParseResult;\n}\n\n/** Load the plugins manifest */\nasync function loadPluginsManifest(): Promise<void> {\n if (pluginsManifest) return;\n\n console.debug(`[arborium] Loading plugins manifest: ${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 pluginsManifest = await response.json();\n\n // Populate available languages\n availableLanguages = new Set(pluginsManifest!.entries.map((e) => e.language));\n console.debug(`[arborium] Available languages: ${Array.from(availableLanguages).join(\", \")}`);\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 // Ensure manifest is loaded\n await loadPluginsManifest();\n\n // Find language entry\n const entry = pluginsManifest?.entries.find((e) => e.language === language);\n if (!entry) {\n console.debug(`[arborium] Grammar '${language}' not found in manifest`);\n return null;\n }\n\n try {\n // Always use CDN URLs for grammars (they're published packages)\n // hostUrl only affects the host module loading\n const jsUrl = entry.cdn_js;\n const baseUrl = jsUrl.substring(0, jsUrl.lastIndexOf(\"/\"));\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n // Dynamically import the JS module\n const module = await import(/* @vite-ignore */ jsUrl);\n\n // Create a getCoreModule function that fetches WASM files by path\n const getCoreModule = async (path: string): Promise<WebAssembly.Module> => {\n const wasmUrl = `${baseUrl}/${path}`;\n const response = await fetch(wasmUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch WASM ${path}: ${response.status}`);\n }\n const bytes = await response.arrayBuffer();\n return WebAssembly.compile(bytes);\n };\n\n // Create WASI imports\n const wasiImports = createWasiImports();\n const imports = {\n ...wasiImports,\n ...grammarTypesImport,\n };\n\n // Instantiate the jco-generated component\n const instance = await module.instantiate(getCoreModule, imports);\n\n // Get the plugin interface\n const jcoPlugin = (instance.plugin || instance[\"arborium:grammar/plugin@0.1.0\"]) as JcoPlugin;\n if (!jcoPlugin) {\n console.error(`Grammar '${language}' missing plugin interface`);\n return null;\n }\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages: jcoPlugin.injectionLanguages?.() ?? [],\n parse: (text: string) => {\n const session = jcoPlugin.createSession();\n try {\n jcoPlugin.setText(session, text);\n const result = jcoPlugin.parse(session);\n\n // Handle various result shapes from jco\n // Some versions return { tag: 'ok', val: ParseResult }\n // Others might return ParseResult directly\n if (result.tag === \"err\") {\n const err = result.val as { message?: string };\n console.error(`[arborium] Parse error: ${err?.message}`);\n return { spans: [], injections: [] };\n }\n\n // Extract the actual value - could be result.val or result itself\n const val = result.tag === \"ok\" ? result.val : result;\n if (!val || typeof val !== \"object\") {\n console.error(`[arborium] Unexpected parse result:`, result);\n return { spans: [], injections: [] };\n }\n\n // Access spans/injections with type coercion\n const parsed = val as { spans?: Span[]; injections?: Injection[] };\n return {\n spans: parsed.spans || [],\n injections: parsed.injections || [],\n };\n } finally {\n jcoPlugin.freeSession(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 availableLanguages.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 loadPluginsManifest();\n return availableLanguages.has(language);\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await loadPluginsManifest();\n return Array.from(availableLanguages);\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","/**\n * @arborium/arborium IIFE bundle\n *\n * Drop-in auto-highlighter that runs on page load.\n * Configuration via data attributes or window.Arborium object.\n */\n\nimport { loadGrammar, highlight, getConfig, setConfig, defaultConfig } from './loader.js';\nimport {\n detectLanguage,\n extractLanguageFromClass,\n normalizeLanguage,\n} from './detect.js';\nimport type { ArboriumConfig } from './types.js';\n\n// Capture current script immediately (before any async operations)\nconst currentScript = document.currentScript as HTMLScriptElement | null;\n\n/** Parse query parameters from script src URL */\nfunction getQueryParams(): URLSearchParams {\n if (!currentScript?.src) return new URLSearchParams();\n try {\n const url = new URL(currentScript.src);\n return url.searchParams;\n } catch {\n return new URLSearchParams();\n }\n}\n\n/** Parse configuration from script data attributes and query params */\nfunction getConfigFromScript(): Partial<ArboriumConfig> {\n if (!currentScript) return {};\n\n const config: Partial<ArboriumConfig> = {};\n const params = getQueryParams();\n\n // Data attributes\n if (currentScript.hasAttribute('data-manual')) {\n config.manual = true;\n }\n\n const theme = currentScript.getAttribute('data-theme');\n if (theme) config.theme = theme;\n\n const selector = currentScript.getAttribute('data-selector');\n if (selector) config.selector = selector;\n\n const cdn = currentScript.getAttribute('data-cdn');\n if (cdn) config.cdn = cdn;\n\n const version = currentScript.getAttribute('data-version');\n if (version) config.version = version;\n\n // Query parameters (for local testing)\n const pluginsUrl = params.get('pluginsUrl');\n if (pluginsUrl) config.pluginsUrl = pluginsUrl;\n\n const hostUrl = params.get('hostUrl');\n if (hostUrl) config.hostUrl = hostUrl;\n\n return config;\n}\n\n/** Detect if we're running on docs.rs */\nfunction isDocsRsEnvironment(): boolean {\n return document.documentElement.hasAttribute('data-docs-rs-theme');\n}\n\n/** Map docs.rs theme names to Arborium theme IDs */\nfunction mapDocsRsTheme(value?: string): string | null {\n if (!value) return null;\n\n const themeMap: Record<string, string> = {\n light: 'docsrs-light',\n dark: 'docsrs-dark',\n ayu: 'docsrs-ayu',\n };\n\n if (themeMap[value]) {\n return themeMap[value];\n }\n\n // Unknown theme value: return as-is or fallback to null\n return null;\n}\n\n/** Detect the current theme from docs.rs or environment */\nfunction getAutoTheme(): string {\n if (isDocsRsEnvironment()) {\n // Prefer the new docs.rs data-theme attribute, fall back to legacy one\n const docsRsTheme = mapDocsRsTheme(document.documentElement.dataset.theme);\n if (docsRsTheme) {\n return docsRsTheme;\n }\n\n const legacyDocsRsTheme = mapDocsRsTheme(\n document.documentElement.dataset.docsRsTheme\n );\n if (legacyDocsRsTheme) {\n return legacyDocsRsTheme;\n }\n }\n\n // Local rustdoc: data-theme toggles between light/dark but lacks docs.rs marker\n const rustdocTheme = document.documentElement.dataset.theme;\n if (rustdocTheme === 'light') {\n return 'github-light';\n }\n if (rustdocTheme === 'dark') {\n return 'tokyo-night';\n }\n\n // Fall back to system preference\n const isLight = window.matchMedia('(prefers-color-scheme: light)').matches;\n return isLight ? 'github-light' : 'tokyo-night';\n}\n\n/** Get merged configuration from all sources and apply to loader */\nfunction getMergedConfig(): Required<ArboriumConfig> {\n // Priority: data attributes > window.Arborium > auto-detect > defaults\n const windowConfig = window.Arborium || {};\n const scriptConfig = getConfigFromScript();\n const merged = { ...windowConfig, ...scriptConfig };\n\n // Auto-detect theme if not explicitly set\n if (!merged.theme) {\n merged.theme = getAutoTheme();\n }\n\n // Apply to loader so host loading uses correct URLs\n setConfig(merged);\n return getConfig();\n}\n\n/** Find all code blocks that need highlighting */\nfunction findCodeBlocks(selector: string): HTMLElement[] {\n return Array.from(document.querySelectorAll(selector));\n}\n\n/** Check if a code block already has syntax highlighting or semantic markup */\nfunction hasExistingHighlighting(block: HTMLElement): boolean {\n // Check for common highlighting library markers\n const highlightClasses = ['hljs', 'highlighted', 'prism-code', 'shiki'];\n for (const cls of highlightClasses) {\n if (block.classList.contains(cls)) return true;\n }\n\n // Check if there are spans with syntax highlighting classes inside\n // (highlight.js, prism, etc. use spans with classes)\n const spans = block.querySelectorAll('span[class]');\n if (spans.length > 0) {\n // If there are multiple spans with classes, likely already highlighted\n // Be conservative: even a few spans suggest existing highlighting\n const classedSpans = Array.from(spans).filter(\n (s) => s.className && s.className.length > 0\n );\n if (classedSpans.length >= 3) return true;\n }\n\n // Check for semantic markup (e.g., docs.rs uses <a> tags for type/function links)\n // If there are links inside the code, it has meaningful markup we shouldn't destroy\n const links = block.querySelectorAll('a');\n if (links.length >= 2) return true;\n\n return false;\n}\n\n/** Get the language for a code block */\nfunction getLanguageForBlock(block: HTMLElement): string | null {\n // Check data-lang attribute\n const dataLang = block.getAttribute('data-lang');\n if (dataLang) return normalizeLanguage(dataLang);\n\n // Check class=\"language-*\"\n const className = block.className;\n const classLang = extractLanguageFromClass(className);\n if (classLang) return normalizeLanguage(classLang);\n\n // Check parent element (often <pre> wraps <code>)\n const parent = block.parentElement;\n if (parent) {\n const parentDataLang = parent.getAttribute('data-lang');\n if (parentDataLang) return normalizeLanguage(parentDataLang);\n\n const parentClassLang = extractLanguageFromClass(parent.className);\n if (parentClassLang) return normalizeLanguage(parentClassLang);\n }\n\n // Try auto-detection\n const source = block.textContent || '';\n return detectLanguage(source);\n}\n\n/** Inject theme CSS if not already present */\nfunction injectThemeCSS(theme: string): void {\n const themeId = `arborium-theme-${theme}`;\n if (document.getElementById(themeId)) return;\n\n // Get the base URL for CSS\n const config = getMergedConfig();\n\n let cssUrl: string;\n if (config.hostUrl) {\n // Local mode - use hostUrl base\n cssUrl = `${config.hostUrl}/themes/${theme}.css`;\n } else {\n // CDN mode\n const cdn = config.cdn;\n const version = config.version;\n\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\n const versionSuffix = version === 'latest' ? '' : `@${version}`;\n cssUrl = `${baseUrl}/@arborium/arborium${versionSuffix}/dist/themes/${theme}.css`;\n }\n console.debug(`[arborium] Loading theme: ${cssUrl}`);\n\n const link = document.createElement('link');\n link.id = themeId;\n link.rel = 'stylesheet';\n link.href = cssUrl;\n document.head.appendChild(link);\n}\n\n/** Highlight a single code block */\nasync function highlightBlock(\n block: HTMLElement,\n language: string,\n config: ArboriumConfig\n): Promise<void> {\n const source = block.textContent || '';\n if (!source.trim()) return;\n\n try {\n const html = await highlight(language, source, config);\n block.innerHTML = html;\n block.setAttribute('data-highlighted', 'true');\n block.setAttribute('data-lang', language);\n } catch (err) {\n console.warn(`[arborium] Failed to highlight ${language}:`, err);\n // Don't modify the block on error\n }\n}\n\n/** Main auto-highlight function */\nasync function autoHighlight(): Promise<void> {\n const config = getMergedConfig();\n\n // Inject theme CSS\n injectThemeCSS(config.theme);\n\n // Find all code blocks\n const blocks = findCodeBlocks(config.selector);\n if (blocks.length === 0) return;\n\n // Group blocks by language\n const blocksByLanguage = new Map<string, HTMLElement[]>();\n const unknownBlocks: HTMLElement[] = [];\n\n for (const block of blocks) {\n // Skip already highlighted blocks\n if (block.hasAttribute('data-highlighted')) continue;\n\n // Skip blocks that appear to have existing syntax highlighting\n // (e.g., docs.rs uses spans with classes for highlighting)\n if (hasExistingHighlighting(block)) continue;\n\n const language = getLanguageForBlock(block);\n if (language) {\n const existing = blocksByLanguage.get(language) || [];\n existing.push(block);\n blocksByLanguage.set(language, existing);\n } else {\n unknownBlocks.push(block);\n }\n }\n\n // Load grammars in parallel for all detected languages\n const languages = Array.from(blocksByLanguage.keys());\n const loadPromises = languages.map((lang) =>\n loadGrammar(lang, config).catch((err) => {\n console.warn(`[arborium] Failed to load grammar for ${lang}:`, err);\n return null;\n })\n );\n\n // Wait for all grammars to load\n const grammars = await Promise.all(loadPromises);\n\n // Highlight blocks for each loaded grammar\n const highlightPromises: Promise<void>[] = [];\n\n for (let i = 0; i < languages.length; i++) {\n const language = languages[i];\n const grammar = grammars[i];\n if (!grammar) continue;\n\n const languageBlocks = blocksByLanguage.get(language) || [];\n for (const block of languageBlocks) {\n highlightPromises.push(highlightBlock(block, language, config));\n }\n }\n\n // Wait for all highlighting to complete\n await Promise.all(highlightPromises);\n\n // Log summary\n const total = blocks.length;\n const highlighted = blocks.filter((b) =>\n b.hasAttribute('data-highlighted')\n ).length;\n const skipped = unknownBlocks.length;\n\n if (highlighted > 0 || skipped > 0) {\n console.debug(\n `[arborium] Highlighted ${highlighted}/${total} blocks` +\n (skipped > 0 ? ` (${skipped} unknown language)` : '')\n );\n }\n}\n\n/** Public API for manual highlighting */\nexport async function highlightAll(config?: ArboriumConfig): Promise<void> {\n const mergedConfig = getConfig({ ...getMergedConfig(), ...config });\n await autoHighlight();\n}\n\n/** Public API for highlighting a specific element */\nexport async function highlightElement(\n element: HTMLElement,\n language?: string,\n config?: ArboriumConfig\n): Promise<void> {\n const mergedConfig = getConfig({ ...getMergedConfig(), ...config });\n const lang = language || getLanguageForBlock(element);\n\n if (!lang) {\n console.warn('[arborium] Could not detect language for element');\n return;\n }\n\n await highlightBlock(element, lang, mergedConfig);\n}\n\n// Expose public API on window\n(window as any).arborium = {\n highlightAll,\n highlightElement,\n loadGrammar,\n highlight,\n detectLanguage,\n config: getMergedConfig(),\n};\n\n/** Re-highlight all blocks when theme changes */\nasync function onThemeChange(): Promise<void> {\n const newTheme = getAutoTheme();\n const currentConfig = getMergedConfig();\n\n // Only re-highlight if theme actually changed and wasn't explicitly set\n if (currentConfig.theme !== newTheme) {\n // Update config\n setConfig({ theme: newTheme });\n (window as any).arborium.config = getMergedConfig();\n\n // Inject new theme CSS\n injectThemeCSS(newTheme);\n\n // No need to re-highlight - CSS handles the colors\n // The spans are already in place, just the theme CSS changes\n console.debug(`[arborium] Theme changed to: ${newTheme}`);\n }\n}\n\n/** Set up theme change watchers */\nfunction watchThemeChanges(): void {\n // Watch for docs.rs/rustdoc theme attribute changes\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n const attr = mutation.attributeName;\n if (\n attr === 'data-docs-rs-theme' ||\n (attr === 'data-theme' && isDocsRsEnvironment())\n ) {\n onThemeChange();\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n\n // Watch for system color scheme changes\n window\n .matchMedia('(prefers-color-scheme: light)')\n .addEventListener('change', () => onThemeChange());\n}\n\n// Auto-highlight on DOMContentLoaded (unless manual mode)\nconst config = getMergedConfig();\nif (!config.manual) {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n autoHighlight();\n watchThemeChanges();\n });\n } else {\n // DOM already loaded\n autoHighlight();\n watchThemeChanges();\n }\n}\n"],"names":["WasiError","message","OutputStream","_contents","InputStream","_len","createWasiImports","stdout","stderr","stdin","environment","exit","status","stdinIface","stdoutIface","stderrIface","wallClock","ms","filesystemTypes","preopens","ioError","streams","random","len","bytes","grammarTypesImport","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","pluginsManifest","availableLanguages","loadPluginsManifest","response","loadGrammarPlugin","language","cached","entry","e","jsUrl","baseUrl","module","getCoreModule","path","wasmUrl","imports","instance","jcoPlugin","plugin","text","session","result","err","val","parsed","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","cdn","version","versionSuffix","loadHost","hostUrl","highlight","source","_config","host","escapeHtml","spansToHtml","loadGrammar","spans","sorted","a","b","html","pos","span","tag","getTagForCapture","capture","getConfig","overrides","setConfig","newConfig","SHEBANG_PATTERNS","KEYWORD_FINGERPRINTS","detectLanguage","firstLine","pattern","extractLanguageFromClass","className","langMatch","shortMatch","knownLanguages","cls","normalizeLanguage","lang","aliases","lower","currentScript","getQueryParams","getConfigFromScript","params","theme","selector","pluginsUrl","isDocsRsEnvironment","mapDocsRsTheme","value","themeMap","getAutoTheme","docsRsTheme","legacyDocsRsTheme","rustdocTheme","getMergedConfig","windowConfig","scriptConfig","merged","findCodeBlocks","hasExistingHighlighting","block","highlightClasses","s","getLanguageForBlock","dataLang","classLang","parent","parentDataLang","parentClassLang","injectThemeCSS","themeId","cssUrl","link","highlightBlock","autoHighlight","blocks","blocksByLanguage","unknownBlocks","existing","languages","loadPromises","grammars","highlightPromises","i","languageBlocks","total","highlighted","skipped","highlightAll","highlightElement","element","mergedConfig","onThemeChange","newTheme","watchThemeChanges","mutations","mutation","attr"],"mappings":"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"}
1
+ {"version":3,"file":"arborium.iife.js","sources":["../src/wasi-shims.ts","../src/loader.ts","../src/detect.ts","../src/iife.ts"],"sourcesContent":["/**\n * Minimal WASI shims for browser environment.\n * These provide stub implementations for WASI interfaces that\n * the grammar plugins require but don't actually use.\n */\n\n// Error type for WASI I/O\nclass WasiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WasiError';\n }\n}\n\n// Minimal stream implementation\nclass OutputStream {\n write(_contents: Uint8Array): bigint {\n // Silently discard output\n return BigInt(0);\n }\n\n blockingWriteAndFlush(_contents: Uint8Array): void {\n // No-op\n }\n\n blockingFlush(): void {\n // No-op\n }\n\n checkWrite(): bigint {\n return BigInt(1024 * 1024); // Allow large writes\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\nclass InputStream {\n read(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n blockingRead(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\n// Create the WASI import object expected by jco-generated modules\nexport function createWasiImports() {\n const stdout = new OutputStream();\n const stderr = new OutputStream();\n const stdin = new InputStream();\n\n // WASI interface implementations\n const environment = {\n getEnvironment: (): Array<[string, string]> => [],\n getArguments: (): string[] => [],\n };\n\n const exit = {\n exit: (status: { tag: string; val?: number }): void => {\n if (status.tag === 'err') {\n throw new WasiError(`WASI exit with error: ${status.val}`);\n }\n },\n };\n\n const stdinIface = { getStdin: () => stdin };\n const stdoutIface = { getStdout: () => stdout };\n const stderrIface = { getStderr: () => stderr };\n\n const wallClock = {\n now: (): { seconds: bigint; nanoseconds: number } => {\n const ms = Date.now();\n return {\n seconds: BigInt(Math.floor(ms / 1000)),\n nanoseconds: (ms % 1000) * 1_000_000,\n };\n },\n resolution: (): { seconds: bigint; nanoseconds: number } => {\n return { seconds: BigInt(0), nanoseconds: 1_000_000 };\n },\n };\n\n const filesystemTypes = {\n Descriptor: class {},\n DirectoryEntryStream: class {},\n filesystemErrorCode: () => null,\n };\n\n const preopens = {\n getDirectories: (): Array<[unknown, string]> => [],\n };\n\n const ioError = { Error: WasiError };\n const streams = { InputStream, OutputStream };\n\n const random = {\n getRandomBytes: (len: bigint): Uint8Array => {\n const bytes = new Uint8Array(Number(len));\n crypto.getRandomValues(bytes);\n return bytes;\n },\n getRandomU64: (): bigint => {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n const view = new DataView(bytes.buffer);\n return view.getBigUint64(0, true);\n },\n };\n\n // Return both versioned (@0.2.3) and unversioned imports for compatibility\n return {\n // Unversioned (used by published grammars)\n 'wasi:cli/environment': environment,\n 'wasi:cli/exit': exit,\n 'wasi:cli/stdin': stdinIface,\n 'wasi:cli/stdout': stdoutIface,\n 'wasi:cli/stderr': stderrIface,\n 'wasi:clocks/wall-clock': wallClock,\n 'wasi:filesystem/types': filesystemTypes,\n 'wasi:filesystem/preopens': preopens,\n 'wasi:io/error': ioError,\n 'wasi:io/streams': streams,\n 'wasi:random/random': random,\n\n // Versioned @0.2.3 (for newer builds)\n 'wasi:cli/environment@0.2.3': environment,\n 'wasi:cli/exit@0.2.3': exit,\n 'wasi:cli/stdin@0.2.3': stdinIface,\n 'wasi:cli/stdout@0.2.3': stdoutIface,\n 'wasi:cli/stderr@0.2.3': stderrIface,\n 'wasi:clocks/wall-clock@0.2.3': wallClock,\n 'wasi:filesystem/types@0.2.3': filesystemTypes,\n 'wasi:filesystem/preopens@0.2.3': preopens,\n 'wasi:io/error@0.2.3': ioError,\n 'wasi:io/streams@0.2.3': streams,\n 'wasi:random/random@0.2.3': random,\n };\n}\n\n// Grammar types import (the plugin exports these)\nexport const grammarTypesImport = {\n 'arborium:grammar/types@0.1.0': {\n // Types are just interfaces, nothing to export\n },\n};\n","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Fetch plugins.json from arborium.bearcove.eu to get grammar CDN URLs\n * 2. Load grammar WIT components on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport { createWasiImports, grammarTypesImport } from \"./wasi-shims.js\";\nimport type { ParseResult, ArboriumConfig, Grammar, Span, Injection } from \"./types.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: \"https://arborium.bearcove.eu/plugins.json\",\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// Plugin manifest from plugins.json\ninterface PluginEntry {\n language: string;\n package: string;\n version: string;\n cdn_js: string;\n cdn_wasm: string;\n local_js: string;\n local_wasm: string;\n}\n\ninterface PluginsManifest {\n dev_mode: boolean;\n generated_at: string;\n entries: PluginEntry[];\n}\n\nlet pluginsManifest: PluginsManifest | null = null;\n\n// Languages we know are available (from plugins.json)\nlet availableLanguages: Set<string> = new Set();\n\n/** WIT Result type as returned by jco-generated code */\ntype WitResult<T, E> = { tag: \"ok\"; val: T } | { tag: \"err\"; val: E };\n\n/** Plugin interface as exported by jco-generated WIT components */\ninterface JcoPlugin {\n languageId(): string;\n injectionLanguages(): string[];\n createSession(): number;\n freeSession(session: number): void;\n setText(session: number, text: string): void;\n parse(session: number): WitResult<ParseResult, { message: string }>;\n}\n\n/** A loaded grammar plugin (WIT component) */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n parse: (text: string) => ParseResult;\n}\n\n/** Load the plugins manifest */\nasync function loadPluginsManifest(): Promise<void> {\n if (pluginsManifest) return;\n\n console.debug(`[arborium] Loading plugins manifest: ${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 pluginsManifest = await response.json();\n\n // Populate available languages\n availableLanguages = new Set(pluginsManifest!.entries.map((e) => e.language));\n console.debug(`[arborium] Available languages: ${Array.from(availableLanguages).join(\", \")}`);\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 // Ensure manifest is loaded\n await loadPluginsManifest();\n\n // Find language entry\n const entry = pluginsManifest?.entries.find((e) => e.language === language);\n if (!entry) {\n console.debug(`[arborium] Grammar '${language}' not found in manifest`);\n return null;\n }\n\n try {\n // Always use CDN URLs for grammars (they're published packages)\n // hostUrl only affects the host module loading\n const jsUrl = entry.cdn_js;\n const baseUrl = jsUrl.substring(0, jsUrl.lastIndexOf(\"/\"));\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n // Dynamically import the JS module\n const module = await import(/* @vite-ignore */ jsUrl);\n\n // Create a getCoreModule function that fetches WASM files by path\n const getCoreModule = async (path: string): Promise<WebAssembly.Module> => {\n const wasmUrl = `${baseUrl}/${path}`;\n const response = await fetch(wasmUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch WASM ${path}: ${response.status}`);\n }\n const bytes = await response.arrayBuffer();\n return WebAssembly.compile(bytes);\n };\n\n // Create WASI imports\n const wasiImports = createWasiImports();\n const imports = {\n ...wasiImports,\n ...grammarTypesImport,\n };\n\n // Instantiate the jco-generated component\n const instance = await module.instantiate(getCoreModule, imports);\n\n // Get the plugin interface\n const jcoPlugin = (instance.plugin || instance[\"arborium:grammar/plugin@0.1.0\"]) as JcoPlugin;\n if (!jcoPlugin) {\n console.error(`Grammar '${language}' missing plugin interface`);\n return null;\n }\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages: jcoPlugin.injectionLanguages?.() ?? [],\n parse: (text: string) => {\n const session = jcoPlugin.createSession();\n try {\n jcoPlugin.setText(session, text);\n const result = jcoPlugin.parse(session);\n\n // Handle various result shapes from jco\n // Some versions return { tag: 'ok', val: ParseResult }\n // Others might return ParseResult directly\n if (result.tag === \"err\") {\n const err = result.val as { message?: string };\n console.error(`[arborium] Parse error: ${err?.message}`);\n return { spans: [], injections: [] };\n }\n\n // Extract the actual value - could be result.val or result itself\n const val = result.tag === \"ok\" ? result.val : result;\n if (!val || typeof val !== \"object\") {\n console.error(`[arborium] Unexpected parse result:`, result);\n return { spans: [], injections: [] };\n }\n\n // Access spans/injections with type coercion\n const parsed = val as { spans?: Span[]; injections?: Injection[] };\n return {\n spans: parsed.spans || [],\n injections: parsed.injections || [],\n };\n } finally {\n jcoPlugin.freeSession(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 availableLanguages.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 loadPluginsManifest();\n return availableLanguages.has(language);\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await loadPluginsManifest();\n return Array.from(availableLanguages);\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","/**\n * @arborium/arborium IIFE bundle\n *\n * Drop-in auto-highlighter that runs on page load.\n * Configuration via data attributes or window.Arborium object.\n */\n\nimport { loadGrammar, highlight, getConfig, setConfig, defaultConfig } from \"./loader.js\";\nimport { detectLanguage, extractLanguageFromClass, normalizeLanguage } from \"./detect.js\";\nimport type { ArboriumConfig } from \"./types.js\";\n\n// Capture current script immediately (before any async operations)\nconst currentScript = document.currentScript as HTMLScriptElement | null;\n\n/** Parse query parameters from script src URL */\nfunction getQueryParams(): URLSearchParams {\n if (!currentScript?.src) return new URLSearchParams();\n try {\n const url = new URL(currentScript.src);\n return url.searchParams;\n } catch {\n return new URLSearchParams();\n }\n}\n\n/** Parse configuration from script data attributes and query params */\nfunction getConfigFromScript(): Partial<ArboriumConfig> {\n if (!currentScript) return {};\n\n const config: Partial<ArboriumConfig> = {};\n const params = getQueryParams();\n\n // Data attributes\n if (currentScript.hasAttribute(\"data-manual\")) {\n config.manual = true;\n }\n\n const theme = currentScript.getAttribute(\"data-theme\");\n if (theme) config.theme = theme;\n\n const selector = currentScript.getAttribute(\"data-selector\");\n if (selector) config.selector = selector;\n\n const cdn = currentScript.getAttribute(\"data-cdn\");\n if (cdn) config.cdn = cdn;\n\n const version = currentScript.getAttribute(\"data-version\");\n if (version) config.version = version;\n\n // Query parameters (for local testing)\n const pluginsUrl = params.get(\"pluginsUrl\");\n if (pluginsUrl) config.pluginsUrl = pluginsUrl;\n\n const hostUrl = params.get(\"hostUrl\");\n if (hostUrl) config.hostUrl = hostUrl;\n\n return config;\n}\n\n/** Detect if we're running on docs.rs */\nfunction isDocsRsEnvironment(): boolean {\n return document.documentElement.hasAttribute(\"data-docs-rs-theme\");\n}\n\n/** Map docs.rs theme names to Arborium theme IDs */\nfunction mapDocsRsTheme(value?: string): string | null {\n if (!value) return null;\n\n const themeMap: Record<string, string> = {\n light: \"docsrs-light\",\n dark: \"docsrs-dark\",\n ayu: \"docsrs-ayu\",\n };\n\n if (themeMap[value]) {\n return themeMap[value];\n }\n\n // Unknown theme value: return as-is or fallback to null\n return null;\n}\n\n/** Detect the current theme from docs.rs or environment */\nfunction getAutoTheme(): string {\n if (isDocsRsEnvironment()) {\n // Prefer the new docs.rs data-theme attribute, fall back to legacy one\n const docsRsTheme = mapDocsRsTheme(document.documentElement.dataset.theme);\n if (docsRsTheme) {\n return docsRsTheme;\n }\n\n const legacyDocsRsTheme = mapDocsRsTheme(document.documentElement.dataset.docsRsTheme);\n if (legacyDocsRsTheme) {\n return legacyDocsRsTheme;\n }\n }\n\n // Local rustdoc: data-theme toggles between light/dark but lacks docs.rs marker\n const rustdocTheme = document.documentElement.dataset.theme;\n if (rustdocTheme === \"light\") {\n return \"github-light\";\n }\n if (rustdocTheme === \"dark\") {\n return \"one-dark\";\n }\n\n // Fall back to system preference\n const isLight = window.matchMedia(\"(prefers-color-scheme: light)\").matches;\n return isLight ? \"github-light\" : \"one-dark\";\n}\n\n/** Get merged configuration from all sources and apply to loader */\nfunction getMergedConfig(): Required<ArboriumConfig> {\n // Priority: data attributes > window.Arborium > auto-detect > defaults\n const windowConfig = window.Arborium || {};\n const scriptConfig = getConfigFromScript();\n const merged = { ...windowConfig, ...scriptConfig };\n\n // Auto-detect theme if not explicitly set\n if (!merged.theme) {\n merged.theme = getAutoTheme();\n }\n\n // Apply to loader so host loading uses correct URLs\n setConfig(merged);\n return getConfig();\n}\n\n/** Find all code blocks that need highlighting */\nfunction findCodeBlocks(selector: string): HTMLElement[] {\n return Array.from(document.querySelectorAll(selector));\n}\n\n/** Check if a code block already has syntax highlighting or semantic markup */\nfunction hasExistingHighlighting(block: HTMLElement): boolean {\n // Check for common highlighting library markers\n const highlightClasses = [\"hljs\", \"highlighted\", \"prism-code\", \"shiki\"];\n for (const cls of highlightClasses) {\n if (block.classList.contains(cls)) return true;\n }\n\n // Check if there are spans with syntax highlighting classes inside\n // (highlight.js, prism, etc. use spans with classes)\n const spans = block.querySelectorAll(\"span[class]\");\n if (spans.length > 0) {\n // If there are multiple spans with classes, likely already highlighted\n // Be conservative: even a few spans suggest existing highlighting\n const classedSpans = Array.from(spans).filter((s) => s.className && s.className.length > 0);\n if (classedSpans.length >= 3) return true;\n }\n\n // Check for semantic markup (e.g., docs.rs uses <a> tags for type/function links)\n // If there are links inside the code, it has meaningful markup we shouldn't destroy\n const links = block.querySelectorAll(\"a\");\n if (links.length >= 2) return true;\n\n return false;\n}\n\n/** Get the language for a code block */\nfunction getLanguageForBlock(block: HTMLElement): string | null {\n // Check data-lang attribute\n const dataLang = block.getAttribute(\"data-lang\");\n if (dataLang) return normalizeLanguage(dataLang);\n\n // Check class=\"language-*\"\n const className = block.className;\n const classLang = extractLanguageFromClass(className);\n if (classLang) return normalizeLanguage(classLang);\n\n // Check parent element (often <pre> wraps <code>)\n const parent = block.parentElement;\n if (parent) {\n const parentDataLang = parent.getAttribute(\"data-lang\");\n if (parentDataLang) return normalizeLanguage(parentDataLang);\n\n const parentClassLang = extractLanguageFromClass(parent.className);\n if (parentClassLang) return normalizeLanguage(parentClassLang);\n }\n\n // Try auto-detection\n const source = block.textContent || \"\";\n return detectLanguage(source);\n}\n\n/** Get the CSS base URL */\nfunction getCssBaseUrl(): string {\n const config = getMergedConfig();\n\n if (config.hostUrl) {\n return `${config.hostUrl}/themes`;\n }\n\n const cdn = config.cdn;\n const version = config.version;\n\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\n const versionSuffix = version === \"latest\" ? \"\" : `@${version}`;\n return `${baseUrl}/@arborium/arborium${versionSuffix}/dist/themes`;\n}\n\n/** Inject base CSS (only once) */\nfunction injectBaseCSS(): void {\n const baseId = \"arborium-base\";\n if (document.getElementById(baseId)) return;\n\n const cssUrl = `${getCssBaseUrl()}/base-docsrs.css`;\n console.debug(`[arborium] Loading base CSS: ${cssUrl}`);\n\n const link = document.createElement(\"link\");\n link.id = baseId;\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n document.head.appendChild(link);\n}\n\n// Track currently loaded theme\nlet currentThemeId: string | null = null;\n\n/** Inject theme CSS, removing any previously loaded theme */\nfunction injectThemeCSS(theme: string): void {\n // Remove old theme if different\n if (currentThemeId && currentThemeId !== theme) {\n const oldLink = document.getElementById(`arborium-theme-${currentThemeId}`);\n if (oldLink) {\n oldLink.remove();\n console.debug(`[arborium] Removed theme: ${currentThemeId}`);\n }\n }\n\n const themeId = `arborium-theme-${theme}`;\n if (document.getElementById(themeId)) {\n currentThemeId = theme;\n return;\n }\n\n const cssUrl = `${getCssBaseUrl()}/${theme}.css`;\n console.debug(`[arborium] Loading theme: ${cssUrl}`);\n\n const link = document.createElement(\"link\");\n link.id = themeId;\n link.rel = \"stylesheet\";\n link.href = cssUrl;\n document.head.appendChild(link);\n\n currentThemeId = theme;\n}\n\n/** Highlight a single code block */\nasync function highlightBlock(\n block: HTMLElement,\n language: string,\n config: ArboriumConfig,\n): Promise<void> {\n const source = block.textContent || \"\";\n if (!source.trim()) return;\n\n try {\n const html = await highlight(language, source, config);\n block.innerHTML = html;\n block.setAttribute(\"data-highlighted\", \"true\");\n block.setAttribute(\"data-lang\", language);\n } catch (err) {\n console.warn(`[arborium] Failed to highlight ${language}:`, err);\n // Don't modify the block on error\n }\n}\n\n/** Main auto-highlight function */\nasync function autoHighlight(): Promise<void> {\n const config = getMergedConfig();\n\n // Inject base CSS (defines a-* selectors using variables)\n injectBaseCSS();\n\n // Inject theme CSS (defines the variables)\n injectThemeCSS(config.theme);\n\n // Find all code blocks\n const blocks = findCodeBlocks(config.selector);\n if (blocks.length === 0) return;\n\n // Group blocks by language\n const blocksByLanguage = new Map<string, HTMLElement[]>();\n const unknownBlocks: HTMLElement[] = [];\n\n for (const block of blocks) {\n // Skip already highlighted blocks\n if (block.hasAttribute(\"data-highlighted\")) continue;\n\n // Skip blocks that appear to have existing syntax highlighting\n // (e.g., docs.rs uses spans with classes for highlighting)\n if (hasExistingHighlighting(block)) continue;\n\n const language = getLanguageForBlock(block);\n if (language) {\n const existing = blocksByLanguage.get(language) || [];\n existing.push(block);\n blocksByLanguage.set(language, existing);\n } else {\n unknownBlocks.push(block);\n }\n }\n\n // Load grammars in parallel for all detected languages\n const languages = Array.from(blocksByLanguage.keys());\n const loadPromises = languages.map((lang) =>\n loadGrammar(lang, config).catch((err) => {\n console.warn(`[arborium] Failed to load grammar for ${lang}:`, err);\n return null;\n }),\n );\n\n // Wait for all grammars to load\n const grammars = await Promise.all(loadPromises);\n\n // Highlight blocks for each loaded grammar\n const highlightPromises: Promise<void>[] = [];\n\n for (let i = 0; i < languages.length; i++) {\n const language = languages[i];\n const grammar = grammars[i];\n if (!grammar) continue;\n\n const languageBlocks = blocksByLanguage.get(language) || [];\n for (const block of languageBlocks) {\n highlightPromises.push(highlightBlock(block, language, config));\n }\n }\n\n // Wait for all highlighting to complete\n await Promise.all(highlightPromises);\n\n // Log summary\n const total = blocks.length;\n const highlighted = blocks.filter((b) => b.hasAttribute(\"data-highlighted\")).length;\n const skipped = unknownBlocks.length;\n\n if (highlighted > 0 || skipped > 0) {\n console.debug(\n `[arborium] Highlighted ${highlighted}/${total} blocks` +\n (skipped > 0 ? ` (${skipped} unknown language)` : \"\"),\n );\n }\n}\n\n/** Public API for manual highlighting */\nexport async function highlightAll(config?: ArboriumConfig): Promise<void> {\n const mergedConfig = getConfig({ ...getMergedConfig(), ...config });\n await autoHighlight();\n}\n\n/** Public API for highlighting a specific element */\nexport async function highlightElement(\n element: HTMLElement,\n language?: string,\n config?: ArboriumConfig,\n): Promise<void> {\n const mergedConfig = getConfig({ ...getMergedConfig(), ...config });\n const lang = language || getLanguageForBlock(element);\n\n if (!lang) {\n console.warn(\"[arborium] Could not detect language for element\");\n return;\n }\n\n await highlightBlock(element, lang, mergedConfig);\n}\n\n// Expose public API on window\n(window as any).arborium = {\n highlightAll,\n highlightElement,\n loadGrammar,\n highlight,\n detectLanguage,\n config: getMergedConfig(),\n};\n\n/** Re-highlight all blocks when theme changes */\nasync function onThemeChange(): Promise<void> {\n const newTheme = getAutoTheme();\n const currentConfig = getMergedConfig();\n\n // Only re-highlight if theme actually changed and wasn't explicitly set\n if (currentConfig.theme !== newTheme) {\n // Update config\n setConfig({ theme: newTheme });\n (window as any).arborium.config = getMergedConfig();\n\n // Inject new theme CSS\n injectThemeCSS(newTheme);\n\n // No need to re-highlight - CSS handles the colors\n // The spans are already in place, just the theme CSS changes\n console.debug(`[arborium] Theme changed to: ${newTheme}`);\n }\n}\n\n/** Set up theme change watchers */\nfunction watchThemeChanges(): void {\n // Watch for docs.rs/rustdoc theme attribute changes\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n const attr = mutation.attributeName;\n if (attr === \"data-docs-rs-theme\" || (attr === \"data-theme\" && isDocsRsEnvironment())) {\n onThemeChange();\n break;\n }\n }\n });\n observer.observe(document.documentElement, { attributes: true });\n\n // Watch for system color scheme changes\n window\n .matchMedia(\"(prefers-color-scheme: light)\")\n .addEventListener(\"change\", () => onThemeChange());\n}\n\n// Auto-highlight on DOMContentLoaded (unless manual mode)\nconst config = getMergedConfig();\nif (!config.manual) {\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => {\n autoHighlight();\n watchThemeChanges();\n });\n } else {\n // DOM already loaded\n autoHighlight();\n watchThemeChanges();\n }\n}\n"],"names":["WasiError","message","OutputStream","_contents","InputStream","_len","createWasiImports","stdout","stderr","stdin","environment","exit","status","stdinIface","stdoutIface","stderrIface","wallClock","ms","filesystemTypes","preopens","ioError","streams","random","len","bytes","grammarTypesImport","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","pluginsManifest","availableLanguages","loadPluginsManifest","response","loadGrammarPlugin","language","cached","entry","e","jsUrl","baseUrl","module","getCoreModule","path","wasmUrl","imports","instance","jcoPlugin","plugin","text","session","result","err","val","parsed","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","cdn","version","versionSuffix","loadHost","hostUrl","highlight","source","_config","host","escapeHtml","spansToHtml","loadGrammar","spans","sorted","a","b","html","pos","span","tag","getTagForCapture","capture","getConfig","overrides","setConfig","newConfig","SHEBANG_PATTERNS","KEYWORD_FINGERPRINTS","detectLanguage","firstLine","pattern","extractLanguageFromClass","className","langMatch","shortMatch","knownLanguages","cls","normalizeLanguage","lang","aliases","lower","currentScript","getQueryParams","getConfigFromScript","params","theme","selector","pluginsUrl","isDocsRsEnvironment","mapDocsRsTheme","value","themeMap","getAutoTheme","docsRsTheme","legacyDocsRsTheme","rustdocTheme","getMergedConfig","windowConfig","scriptConfig","merged","findCodeBlocks","hasExistingHighlighting","block","highlightClasses","s","getLanguageForBlock","dataLang","classLang","parent","parentDataLang","parentClassLang","getCssBaseUrl","injectBaseCSS","baseId","cssUrl","link","currentThemeId","injectThemeCSS","oldLink","themeId","highlightBlock","autoHighlight","blocks","blocksByLanguage","unknownBlocks","existing","languages","loadPromises","grammars","highlightPromises","i","languageBlocks","total","highlighted","skipped","highlightAll","highlightElement","element","mergedConfig","onThemeChange","newTheme","watchThemeChanges","mutations","mutation","attr"],"mappings":"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"}
package/dist/arborium.js CHANGED
@@ -96,7 +96,7 @@ const T = {
96
96
  }
97
97
  }, R = {
98
98
  manual: !1,
99
- theme: "tokyo-night",
99
+ theme: "one-dark",
100
100
  selector: "pre code",
101
101
  cdn: "jsdelivr",
102
102
  version: "1",
@@ -1 +1 @@
1
- {"version":3,"file":"arborium.js","sources":["../src/wasi-shims.ts","../src/loader.ts","../src/detect.ts"],"sourcesContent":["/**\n * Minimal WASI shims for browser environment.\n * These provide stub implementations for WASI interfaces that\n * the grammar plugins require but don't actually use.\n */\n\n// Error type for WASI I/O\nclass WasiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WasiError';\n }\n}\n\n// Minimal stream implementation\nclass OutputStream {\n write(_contents: Uint8Array): bigint {\n // Silently discard output\n return BigInt(0);\n }\n\n blockingWriteAndFlush(_contents: Uint8Array): void {\n // No-op\n }\n\n blockingFlush(): void {\n // No-op\n }\n\n checkWrite(): bigint {\n return BigInt(1024 * 1024); // Allow large writes\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\nclass InputStream {\n read(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n blockingRead(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\n// Create the WASI import object expected by jco-generated modules\nexport function createWasiImports() {\n const stdout = new OutputStream();\n const stderr = new OutputStream();\n const stdin = new InputStream();\n\n // WASI interface implementations\n const environment = {\n getEnvironment: (): Array<[string, string]> => [],\n getArguments: (): string[] => [],\n };\n\n const exit = {\n exit: (status: { tag: string; val?: number }): void => {\n if (status.tag === 'err') {\n throw new WasiError(`WASI exit with error: ${status.val}`);\n }\n },\n };\n\n const stdinIface = { getStdin: () => stdin };\n const stdoutIface = { getStdout: () => stdout };\n const stderrIface = { getStderr: () => stderr };\n\n const wallClock = {\n now: (): { seconds: bigint; nanoseconds: number } => {\n const ms = Date.now();\n return {\n seconds: BigInt(Math.floor(ms / 1000)),\n nanoseconds: (ms % 1000) * 1_000_000,\n };\n },\n resolution: (): { seconds: bigint; nanoseconds: number } => {\n return { seconds: BigInt(0), nanoseconds: 1_000_000 };\n },\n };\n\n const filesystemTypes = {\n Descriptor: class {},\n DirectoryEntryStream: class {},\n filesystemErrorCode: () => null,\n };\n\n const preopens = {\n getDirectories: (): Array<[unknown, string]> => [],\n };\n\n const ioError = { Error: WasiError };\n const streams = { InputStream, OutputStream };\n\n const random = {\n getRandomBytes: (len: bigint): Uint8Array => {\n const bytes = new Uint8Array(Number(len));\n crypto.getRandomValues(bytes);\n return bytes;\n },\n getRandomU64: (): bigint => {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n const view = new DataView(bytes.buffer);\n return view.getBigUint64(0, true);\n },\n };\n\n // Return both versioned (@0.2.3) and unversioned imports for compatibility\n return {\n // Unversioned (used by published grammars)\n 'wasi:cli/environment': environment,\n 'wasi:cli/exit': exit,\n 'wasi:cli/stdin': stdinIface,\n 'wasi:cli/stdout': stdoutIface,\n 'wasi:cli/stderr': stderrIface,\n 'wasi:clocks/wall-clock': wallClock,\n 'wasi:filesystem/types': filesystemTypes,\n 'wasi:filesystem/preopens': preopens,\n 'wasi:io/error': ioError,\n 'wasi:io/streams': streams,\n 'wasi:random/random': random,\n\n // Versioned @0.2.3 (for newer builds)\n 'wasi:cli/environment@0.2.3': environment,\n 'wasi:cli/exit@0.2.3': exit,\n 'wasi:cli/stdin@0.2.3': stdinIface,\n 'wasi:cli/stdout@0.2.3': stdoutIface,\n 'wasi:cli/stderr@0.2.3': stderrIface,\n 'wasi:clocks/wall-clock@0.2.3': wallClock,\n 'wasi:filesystem/types@0.2.3': filesystemTypes,\n 'wasi:filesystem/preopens@0.2.3': preopens,\n 'wasi:io/error@0.2.3': ioError,\n 'wasi:io/streams@0.2.3': streams,\n 'wasi:random/random@0.2.3': random,\n };\n}\n\n// Grammar types import (the plugin exports these)\nexport const grammarTypesImport = {\n 'arborium:grammar/types@0.1.0': {\n // Types are just interfaces, nothing to export\n },\n};\n","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Fetch plugins.json from arborium.bearcove.eu to get grammar CDN URLs\n * 2. Load grammar WIT components on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport { createWasiImports, grammarTypesImport } from \"./wasi-shims.js\";\nimport type { ParseResult, ArboriumConfig, Grammar, Span, Injection } from \"./types.js\";\n\n// Default config\nexport const defaultConfig: Required<ArboriumConfig> = {\n manual: false,\n theme: \"tokyo-night\",\n selector: \"pre code\",\n cdn: \"jsdelivr\",\n version: \"1\", // Major version - allows patch/minor upgrades via CDN\n pluginsUrl: \"https://arborium.bearcove.eu/plugins.json\",\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// Plugin manifest from plugins.json\ninterface PluginEntry {\n language: string;\n package: string;\n version: string;\n cdn_js: string;\n cdn_wasm: string;\n local_js: string;\n local_wasm: string;\n}\n\ninterface PluginsManifest {\n dev_mode: boolean;\n generated_at: string;\n entries: PluginEntry[];\n}\n\nlet pluginsManifest: PluginsManifest | null = null;\n\n// Languages we know are available (from plugins.json)\nlet availableLanguages: Set<string> = new Set();\n\n/** WIT Result type as returned by jco-generated code */\ntype WitResult<T, E> = { tag: \"ok\"; val: T } | { tag: \"err\"; val: E };\n\n/** Plugin interface as exported by jco-generated WIT components */\ninterface JcoPlugin {\n languageId(): string;\n injectionLanguages(): string[];\n createSession(): number;\n freeSession(session: number): void;\n setText(session: number, text: string): void;\n parse(session: number): WitResult<ParseResult, { message: string }>;\n}\n\n/** A loaded grammar plugin (WIT component) */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n parse: (text: string) => ParseResult;\n}\n\n/** Load the plugins manifest */\nasync function loadPluginsManifest(): Promise<void> {\n if (pluginsManifest) return;\n\n console.debug(`[arborium] Loading plugins manifest: ${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 pluginsManifest = await response.json();\n\n // Populate available languages\n availableLanguages = new Set(pluginsManifest!.entries.map((e) => e.language));\n console.debug(`[arborium] Available languages: ${Array.from(availableLanguages).join(\", \")}`);\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 // Ensure manifest is loaded\n await loadPluginsManifest();\n\n // Find language entry\n const entry = pluginsManifest?.entries.find((e) => e.language === language);\n if (!entry) {\n console.debug(`[arborium] Grammar '${language}' not found in manifest`);\n return null;\n }\n\n try {\n // Always use CDN URLs for grammars (they're published packages)\n // hostUrl only affects the host module loading\n const jsUrl = entry.cdn_js;\n const baseUrl = jsUrl.substring(0, jsUrl.lastIndexOf(\"/\"));\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n // Dynamically import the JS module\n const module = await import(/* @vite-ignore */ jsUrl);\n\n // Create a getCoreModule function that fetches WASM files by path\n const getCoreModule = async (path: string): Promise<WebAssembly.Module> => {\n const wasmUrl = `${baseUrl}/${path}`;\n const response = await fetch(wasmUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch WASM ${path}: ${response.status}`);\n }\n const bytes = await response.arrayBuffer();\n return WebAssembly.compile(bytes);\n };\n\n // Create WASI imports\n const wasiImports = createWasiImports();\n const imports = {\n ...wasiImports,\n ...grammarTypesImport,\n };\n\n // Instantiate the jco-generated component\n const instance = await module.instantiate(getCoreModule, imports);\n\n // Get the plugin interface\n const jcoPlugin = (instance.plugin || instance[\"arborium:grammar/plugin@0.1.0\"]) as JcoPlugin;\n if (!jcoPlugin) {\n console.error(`Grammar '${language}' missing plugin interface`);\n return null;\n }\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages: jcoPlugin.injectionLanguages?.() ?? [],\n parse: (text: string) => {\n const session = jcoPlugin.createSession();\n try {\n jcoPlugin.setText(session, text);\n const result = jcoPlugin.parse(session);\n\n // Handle various result shapes from jco\n // Some versions return { tag: 'ok', val: ParseResult }\n // Others might return ParseResult directly\n if (result.tag === \"err\") {\n const err = result.val as { message?: string };\n console.error(`[arborium] Parse error: ${err?.message}`);\n return { spans: [], injections: [] };\n }\n\n // Extract the actual value - could be result.val or result itself\n const val = result.tag === \"ok\" ? result.val : result;\n if (!val || typeof val !== \"object\") {\n console.error(`[arborium] Unexpected parse result:`, result);\n return { spans: [], injections: [] };\n }\n\n // Access spans/injections with type coercion\n const parsed = val as { spans?: Span[]; injections?: Injection[] };\n return {\n spans: parsed.spans || [],\n injections: parsed.injections || [],\n };\n } finally {\n jcoPlugin.freeSession(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 availableLanguages.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 loadPluginsManifest();\n return availableLanguages.has(language);\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await loadPluginsManifest();\n return Array.from(availableLanguages);\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":["WasiError","message","OutputStream","_contents","InputStream","_len","createWasiImports","stdout","stderr","stdin","environment","exit","status","stdinIface","stdoutIface","stderrIface","wallClock","ms","filesystemTypes","preopens","ioError","streams","random","len","bytes","grammarTypesImport","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","pluginsManifest","availableLanguages","loadPluginsManifest","response","e","loadGrammarPlugin","language","cached","entry","jsUrl","baseUrl","module","getCoreModule","path","wasmUrl","imports","instance","jcoPlugin","plugin","text","session","result","err","val","parsed","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","cdn","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","knownLanguages","cls","normalizeLanguage","lang","aliases","lower"],"mappings":"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"}
1
+ {"version":3,"file":"arborium.js","sources":["../src/wasi-shims.ts","../src/loader.ts","../src/detect.ts"],"sourcesContent":["/**\n * Minimal WASI shims for browser environment.\n * These provide stub implementations for WASI interfaces that\n * the grammar plugins require but don't actually use.\n */\n\n// Error type for WASI I/O\nclass WasiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WasiError';\n }\n}\n\n// Minimal stream implementation\nclass OutputStream {\n write(_contents: Uint8Array): bigint {\n // Silently discard output\n return BigInt(0);\n }\n\n blockingWriteAndFlush(_contents: Uint8Array): void {\n // No-op\n }\n\n blockingFlush(): void {\n // No-op\n }\n\n checkWrite(): bigint {\n return BigInt(1024 * 1024); // Allow large writes\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\nclass InputStream {\n read(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n blockingRead(_len: bigint): Uint8Array {\n return new Uint8Array(0);\n }\n\n subscribe(): void {\n // No-op\n }\n}\n\n// Create the WASI import object expected by jco-generated modules\nexport function createWasiImports() {\n const stdout = new OutputStream();\n const stderr = new OutputStream();\n const stdin = new InputStream();\n\n // WASI interface implementations\n const environment = {\n getEnvironment: (): Array<[string, string]> => [],\n getArguments: (): string[] => [],\n };\n\n const exit = {\n exit: (status: { tag: string; val?: number }): void => {\n if (status.tag === 'err') {\n throw new WasiError(`WASI exit with error: ${status.val}`);\n }\n },\n };\n\n const stdinIface = { getStdin: () => stdin };\n const stdoutIface = { getStdout: () => stdout };\n const stderrIface = { getStderr: () => stderr };\n\n const wallClock = {\n now: (): { seconds: bigint; nanoseconds: number } => {\n const ms = Date.now();\n return {\n seconds: BigInt(Math.floor(ms / 1000)),\n nanoseconds: (ms % 1000) * 1_000_000,\n };\n },\n resolution: (): { seconds: bigint; nanoseconds: number } => {\n return { seconds: BigInt(0), nanoseconds: 1_000_000 };\n },\n };\n\n const filesystemTypes = {\n Descriptor: class {},\n DirectoryEntryStream: class {},\n filesystemErrorCode: () => null,\n };\n\n const preopens = {\n getDirectories: (): Array<[unknown, string]> => [],\n };\n\n const ioError = { Error: WasiError };\n const streams = { InputStream, OutputStream };\n\n const random = {\n getRandomBytes: (len: bigint): Uint8Array => {\n const bytes = new Uint8Array(Number(len));\n crypto.getRandomValues(bytes);\n return bytes;\n },\n getRandomU64: (): bigint => {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n const view = new DataView(bytes.buffer);\n return view.getBigUint64(0, true);\n },\n };\n\n // Return both versioned (@0.2.3) and unversioned imports for compatibility\n return {\n // Unversioned (used by published grammars)\n 'wasi:cli/environment': environment,\n 'wasi:cli/exit': exit,\n 'wasi:cli/stdin': stdinIface,\n 'wasi:cli/stdout': stdoutIface,\n 'wasi:cli/stderr': stderrIface,\n 'wasi:clocks/wall-clock': wallClock,\n 'wasi:filesystem/types': filesystemTypes,\n 'wasi:filesystem/preopens': preopens,\n 'wasi:io/error': ioError,\n 'wasi:io/streams': streams,\n 'wasi:random/random': random,\n\n // Versioned @0.2.3 (for newer builds)\n 'wasi:cli/environment@0.2.3': environment,\n 'wasi:cli/exit@0.2.3': exit,\n 'wasi:cli/stdin@0.2.3': stdinIface,\n 'wasi:cli/stdout@0.2.3': stdoutIface,\n 'wasi:cli/stderr@0.2.3': stderrIface,\n 'wasi:clocks/wall-clock@0.2.3': wallClock,\n 'wasi:filesystem/types@0.2.3': filesystemTypes,\n 'wasi:filesystem/preopens@0.2.3': preopens,\n 'wasi:io/error@0.2.3': ioError,\n 'wasi:io/streams@0.2.3': streams,\n 'wasi:random/random@0.2.3': random,\n };\n}\n\n// Grammar types import (the plugin exports these)\nexport const grammarTypesImport = {\n 'arborium:grammar/types@0.1.0': {\n // Types are just interfaces, nothing to export\n },\n};\n","/**\n * Arborium loader - loads grammar plugins and highlights code.\n *\n * Architecture:\n * 1. Fetch plugins.json from arborium.bearcove.eu to get grammar CDN URLs\n * 2. Load grammar WIT components on demand from @arborium/<lang> packages\n * 3. Parse and highlight using the grammar's tree-sitter parser\n */\n\nimport { createWasiImports, grammarTypesImport } from \"./wasi-shims.js\";\nimport type { ParseResult, ArboriumConfig, Grammar, Span, Injection } from \"./types.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: \"https://arborium.bearcove.eu/plugins.json\",\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// Plugin manifest from plugins.json\ninterface PluginEntry {\n language: string;\n package: string;\n version: string;\n cdn_js: string;\n cdn_wasm: string;\n local_js: string;\n local_wasm: string;\n}\n\ninterface PluginsManifest {\n dev_mode: boolean;\n generated_at: string;\n entries: PluginEntry[];\n}\n\nlet pluginsManifest: PluginsManifest | null = null;\n\n// Languages we know are available (from plugins.json)\nlet availableLanguages: Set<string> = new Set();\n\n/** WIT Result type as returned by jco-generated code */\ntype WitResult<T, E> = { tag: \"ok\"; val: T } | { tag: \"err\"; val: E };\n\n/** Plugin interface as exported by jco-generated WIT components */\ninterface JcoPlugin {\n languageId(): string;\n injectionLanguages(): string[];\n createSession(): number;\n freeSession(session: number): void;\n setText(session: number, text: string): void;\n parse(session: number): WitResult<ParseResult, { message: string }>;\n}\n\n/** A loaded grammar plugin (WIT component) */\ninterface GrammarPlugin {\n languageId: string;\n injectionLanguages: string[];\n parse: (text: string) => ParseResult;\n}\n\n/** Load the plugins manifest */\nasync function loadPluginsManifest(): Promise<void> {\n if (pluginsManifest) return;\n\n console.debug(`[arborium] Loading plugins manifest: ${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 pluginsManifest = await response.json();\n\n // Populate available languages\n availableLanguages = new Set(pluginsManifest!.entries.map((e) => e.language));\n console.debug(`[arborium] Available languages: ${Array.from(availableLanguages).join(\", \")}`);\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 // Ensure manifest is loaded\n await loadPluginsManifest();\n\n // Find language entry\n const entry = pluginsManifest?.entries.find((e) => e.language === language);\n if (!entry) {\n console.debug(`[arborium] Grammar '${language}' not found in manifest`);\n return null;\n }\n\n try {\n // Always use CDN URLs for grammars (they're published packages)\n // hostUrl only affects the host module loading\n const jsUrl = entry.cdn_js;\n const baseUrl = jsUrl.substring(0, jsUrl.lastIndexOf(\"/\"));\n\n console.debug(`[arborium] Loading grammar '${language}' from ${jsUrl}`);\n // Dynamically import the JS module\n const module = await import(/* @vite-ignore */ jsUrl);\n\n // Create a getCoreModule function that fetches WASM files by path\n const getCoreModule = async (path: string): Promise<WebAssembly.Module> => {\n const wasmUrl = `${baseUrl}/${path}`;\n const response = await fetch(wasmUrl);\n if (!response.ok) {\n throw new Error(`Failed to fetch WASM ${path}: ${response.status}`);\n }\n const bytes = await response.arrayBuffer();\n return WebAssembly.compile(bytes);\n };\n\n // Create WASI imports\n const wasiImports = createWasiImports();\n const imports = {\n ...wasiImports,\n ...grammarTypesImport,\n };\n\n // Instantiate the jco-generated component\n const instance = await module.instantiate(getCoreModule, imports);\n\n // Get the plugin interface\n const jcoPlugin = (instance.plugin || instance[\"arborium:grammar/plugin@0.1.0\"]) as JcoPlugin;\n if (!jcoPlugin) {\n console.error(`Grammar '${language}' missing plugin interface`);\n return null;\n }\n\n // Wrap as GrammarPlugin with session-based parsing\n const plugin: GrammarPlugin = {\n languageId: language,\n injectionLanguages: jcoPlugin.injectionLanguages?.() ?? [],\n parse: (text: string) => {\n const session = jcoPlugin.createSession();\n try {\n jcoPlugin.setText(session, text);\n const result = jcoPlugin.parse(session);\n\n // Handle various result shapes from jco\n // Some versions return { tag: 'ok', val: ParseResult }\n // Others might return ParseResult directly\n if (result.tag === \"err\") {\n const err = result.val as { message?: string };\n console.error(`[arborium] Parse error: ${err?.message}`);\n return { spans: [], injections: [] };\n }\n\n // Extract the actual value - could be result.val or result itself\n const val = result.tag === \"ok\" ? result.val : result;\n if (!val || typeof val !== \"object\") {\n console.error(`[arborium] Unexpected parse result:`, result);\n return { spans: [], injections: [] };\n }\n\n // Access spans/injections with type coercion\n const parsed = val as { spans?: Span[]; injections?: Injection[] };\n return {\n spans: parsed.spans || [],\n injections: parsed.injections || [],\n };\n } finally {\n jcoPlugin.freeSession(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 availableLanguages.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 loadPluginsManifest();\n return availableLanguages.has(language);\n}\n\n/** Get list of available languages */\nexport async function getAvailableLanguages(): Promise<string[]> {\n await loadPluginsManifest();\n return Array.from(availableLanguages);\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":["WasiError","message","OutputStream","_contents","InputStream","_len","createWasiImports","stdout","stderr","stdin","environment","exit","status","stdinIface","stdoutIface","stderrIface","wallClock","ms","filesystemTypes","preopens","ioError","streams","random","len","bytes","grammarTypesImport","defaultConfig","hostModule","hostLoadPromise","config","grammarCache","pluginsManifest","availableLanguages","loadPluginsManifest","response","e","loadGrammarPlugin","language","cached","entry","jsUrl","baseUrl","module","getCoreModule","path","wasmUrl","imports","instance","jcoPlugin","plugin","text","session","result","err","val","parsed","handleToPlugin","nextHandle","setupHostInterface","handle","p","getHostUrl","cdn","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","knownLanguages","cls","normalizeLanguage","lang","aliases","lower"],"mappings":"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"}