@live-codes/odin-wasm 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- var odinWasm=(()=>{var W=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var gt=Object.getOwnPropertyNames;var St=Object.prototype.hasOwnProperty;var mt=(t,e)=>{for(var n in e)W(t,n,{get:e[n],enumerable:!0})},wt=(t,e,n,c)=>{if(e&&typeof e=="object"||typeof e=="function")for(let f of gt(e))!St.call(t,f)&&f!==n&&W(t,f,{get:()=>e[f],enumerable:!(c=pt(e,f))||c.enumerable});return t};var _t=t=>wt(W({},"__esModule",{value:!0}),t);var Yt={};mt(Yt,{TARGETS:()=>Lt,createCompiler:()=>Bt});var V=Object.freeze({"odin.wasm":Object.freeze({bytes:3763439,sha256:"5044e383aa2415927cd518a4d3e6fdbcc6c99154ac90d212e154f18c092deef3"}),"odin-src.pack.gz":Object.freeze({bytes:2502169,sha256:"567b1c0c1b50d3e557d119927ade3373dda91364acae3302f2cf01950a8dd8f9"})});var zt=Object.freeze(Object.keys(V)),Ut="baseUrl is required here. The assets that ship in this package can only be read where there is a filesystem, and a browser cannot reach a file inside an npm package \u2014 copy them somewhere your page can fetch with `npx --package @live-codes/odin-wasm odin-wasm-copy-assets <dir>` and pass that directory as baseUrl.";function tt(t,e){if(t.baseUrl!=null&&t.baseUrl!=="")return yt(t);if(!e)throw new Error(Ut);return At(e)}function yt(t){let e=Ct(t.baseUrl);return{kind:"hosted",key:`hosted\0${e}`,description:e,baseUrl:e,async readAsset(n,c){let f=new URL(n,e),E=await fetch(f);if(!E.ok)throw new Error(`Failed to load the runtime asset ${f}: ${E.status}`);return et(n,await Tt(E,c))}}}function At(t){return{kind:"packaged",key:`packaged\0${t.root.href}`,description:`the assets packaged with this library (${t.root.href})`,async readAsset(e){let n;try{n=await t.readFile(e)}catch(c){throw new Error(`Failed to read the packaged asset ${e} from ${t.root.href}: ${c.message}`,{cause:c})}return et(e,n)}}}function Ct(t){let e;try{e=t instanceof URL?t:new URL(t,globalThis.document?.baseURI)}catch(n){throw new Error(`baseUrl must be an absolute http(s) URL, or relative to the page in a browser: ${n.message}`,{cause:n})}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`baseUrl must be an absolute http(s) URL, or relative to the page in a browser: got "${t}"`);return e.href.endsWith("/")?e.href:`${e.href}/`}async function Tt(t,e){if(!e||!t.body)return new Uint8Array(await t.arrayBuffer());let n=Number(t.headers.get("content-length"))||0,c=t.body.getReader(),f=[],E=0;for(e(0,n);;){let{done:d,value:S}=await c.read();if(d)break;f.push(S),E+=S.length,e(E,n)}let w=new Uint8Array(E),g=0;for(let d of f)w.set(d,g),g+=d.length;return w}async function et(t,e){let n=V[t];if(!n)throw new Error(`No pinned receipt for the runtime asset ${t}`);if(e.byteLength!==n.bytes)throw new Error(`The runtime asset ${t} is ${e.byteLength} bytes, expected ${n.bytes}`);let c=await bt(e);if(c!==n.sha256)throw new Error(`The runtime asset ${t} failed SHA-256 verification: expected ${n.sha256}, got ${c}`);return e}async function bt(t){let e=globalThis.crypto?.subtle;if(!e)throw new Error("Verifying the runtime assets needs crypto.subtle: a secure context in the browser, or Node 20 and later.");let n=await e.digest("SHA-256",t);return[...new Uint8Array(n)].map(c=>c.toString(16).padStart(2,"0")).join("")}async function rt(t){if(typeof DecompressionStream!="function")throw new Error("Inflating the standard library pack needs DecompressionStream");let e=new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"));return new Uint8Array(await new Response(e).arrayBuffer())}var N=class extends Error{constructor(e){super(`WASI process exited with code ${e}`),this.code=e}},O=t=>{let e=[];for(let n of String(t).split("/"))if(!(n===""||n===".")){if(n===".."){e.pop();continue}e.push(n)}return e.join("/")},H=t=>{let e=t.lastIndexOf("/");return e<0?"":t.slice(0,e)},Y=new TextEncoder,xt=new TextDecoder,$=class{constructor(){this.files=new Map,this.dirs=new Set([""])}mkdirAll(e){let n=O(e)===""?[]:O(e).split("/"),c="";for(let f of n)c=c===""?f:`${c}/${f}`,this.dirs.add(c)}writeFile(e,n){let c=O(e);this.mkdirAll(H(c));let f=n instanceof Uint8Array?n:new Uint8Array(n);this.files.set(c,{data:f,size:f.length})}readFile(e){let n=this.files.get(O(e));return n?n.data.subarray(0,n.size):null}exists(e){let n=O(e);return this.files.has(n)||this.dirs.has(n)}listDir(e){let n=O(e),c=n===""?"":`${n}/`,f=[];for(let E of this.dirs)E!==""&&E.startsWith(c)&&E.indexOf("/",c.length)<0&&E!==n&&f.push({name:E.slice(c.length),isDir:!0});for(let E of this.files.keys())E.startsWith(c)&&E.indexOf("/",c.length)<0&&f.push({name:E.slice(c.length),isDir:!1});return f.sort((E,w)=>E.name<w.name?-1:E.name>w.name?1:0),f}},kt=t=>t instanceof Uint8Array?t:new Uint8Array(t),X=(t,e={})=>{let n=e.args??[],c=e.env??[],f=e.stdout??(()=>{}),E=e.stderr??(()=>{}),w=kt(Y.encode(e.stdin??"")),g=0,d=new Map,S=4;d.set(0,{kind:"stdin"}),d.set(1,{kind:"stdout"}),d.set(2,{kind:"stderr"}),d.set(3,{kind:"dir",path:""});let _=["","",""],l=null,h=()=>new Uint8Array(l.buffer),u=()=>new DataView(l.buffer),y=(r,o)=>xt.decode(h().subarray(r,r+o)),k=(r,o)=>{let s=_[r]+o,i=s.lastIndexOf(`
2
- `);i>=0&&((r===1?f:E)(s.slice(0,i+1)),s=s.slice(i+1)),_[r]=s},R=()=>{for(let r of[1,2])_[r]!==""&&((r===1?f:E)(_[r]),_[r]="")},A=(r,o,s)=>{let i=u();i.setBigUint64(r+0,0n,!0),i.setBigUint64(r+8,0n,!0),i.setUint8(r+16,o),i.setBigUint64(r+24,1n,!0),i.setBigUint64(r+32,BigInt(s),!0),i.setBigUint64(r+40,0n,!0),i.setBigUint64(r+48,0n,!0),i.setBigUint64(r+56,0n,!0)},z=(r,o)=>{if(t.dirs.has(r))return A(o,3,0),0;let s=t.files.get(r);return s?(A(o,4,s.size),0):44},D=(r,o)=>{if(o<=r.data.length)return;let s=Math.max(r.data.length*2,4096);for(;s<o;)s*=2;let i=new Uint8Array(s);i.set(r.data.subarray(0,r.size)),r.data=i},G=(r,o,s,i)=>{let a=u(),p=h(),m=0;for(let C=0;C<s;C++){let T=a.getUint32(o+C*8,!0),U=a.getUint32(o+C*8+4,!0),b=Math.max(0,Math.min(U,r.size-i));if(p.set(r.data.subarray(i,i+b),T),i+=b,m+=b,b<U)break}return m},Q=(r,o,s,i)=>{let a=u(),p=h(),m=0;for(let C=0;C<s;C++){let T=a.getUint32(o+C*8,!0),U=a.getUint32(o+C*8+4,!0);D(r,i+U),r.data.set(p.subarray(T,T+U),i),i+=U,r.size=Math.max(r.size,i),m+=U}return m},Z=(r,o,s)=>{let i=u(),a=h(),p=s;for(let m=0;m<r.length;m++){let C=Y.encode(r[m]);i.setUint32(o+m*4,p,!0),a.set(C,p),a[p+C.length]=0,p+=C.length+1}return 0},L=(r,o,s)=>{let i=d.get(r);if(!i||i.kind!=="dir")return null;let a=y(o,s);return O(a.startsWith("/")?a:`${i.path}/${a}`)};return{imports:{args_sizes_get(r,o){let s=u();return s.setUint32(r,n.length,!0),s.setUint32(o,n.reduce((i,a)=>i+Y.encode(a).length+1,0),!0),0},args_get(r,o){return Z(n,r,o)},environ_sizes_get(r,o){let s=u();return s.setUint32(r,c.length,!0),s.setUint32(o,c.reduce((i,a)=>i+Y.encode(a).length+1,0),!0),0},environ_get(r,o){return Z(c,r,o)},clock_res_get(r,o){return u().setBigUint64(o,1000n,!0),0},clock_time_get(r,o,s){let i=r===0?BigInt(Date.now())*1000000n:BigInt(Math.round((globalThis.performance?.now()??Date.now())*1e3))*1000n;return u().setBigUint64(s,i,!0),0},fd_close(r){return d.has(r)?(r>3&&d.delete(r),0):8},fd_fdstat_get(r,o){let s=d.get(r);if(!s)return 8;let i=u(),a=s.kind==="dir"?3:s.kind==="file"?4:2;return i.setUint8(o,a),i.setUint16(o+2,0,!0),i.setBigUint64(o+8,0xffffffffffffffffn,!0),i.setBigUint64(o+16,0xffffffffffffffffn,!0),0},fd_filestat_get(r,o){let s=d.get(r);return s?(s.kind==="dir"?A(o,3,0):s.kind==="file"?A(o,4,s.file.size):A(o,2,0),0):8},fd_filestat_set_size(r,o){let s=d.get(r);if(!s||s.kind!=="file")return 8;let i=Number(o);return D(s.file,i),i>s.file.size&&s.file.data.fill(0,s.file.size,i),s.file.size=i,0},fd_prestat_get(r,o){if(r!==3)return 8;let s=u();return s.setUint8(o,0),s.setUint32(o+4,1,!0),0},fd_prestat_dir_name(r,o,s){return r!==3?8:(s>=1&&(h()[o]=47),0)},fd_read(r,o,s,i){let a=d.get(r);if(!a)return 8;if(a.kind==="stdin"){let m=G({data:w,size:w.length},o,s,g);return g+=m,u().setUint32(i,m,!0),0}if(a.kind!=="file")return 8;let p=G(a.file,o,s,a.offset);return a.offset+=p,u().setUint32(i,p,!0),0},fd_pread(r,o,s,i,a){let p=d.get(r);if(!p||p.kind!=="file")return 8;let m=G(p.file,o,s,Number(i));return u().setUint32(a,m,!0),0},fd_write(r,o,s,i){let a=d.get(r);if(!a)return 8;if(a.kind==="stdout"||a.kind==="stderr"){let m=u(),C=0;for(let T=0;T<s;T++){let U=m.getUint32(o+T*8,!0),b=m.getUint32(o+T*8+4,!0);k(r,y(U,b)),C+=b}return m.setUint32(i,C,!0),0}if(a.kind!=="file")return 8;let p=Q(a.file,o,s,a.offset);return a.offset+=p,u().setUint32(i,p,!0),0},fd_pwrite(r,o,s,i,a){let p=d.get(r);if(!p||p.kind!=="file")return 8;let m=Q(p.file,o,s,Number(i));return u().setUint32(a,m,!0),0},fd_seek(r,o,s,i){let a=d.get(r);if(!a||a.kind!=="file")return 8;let p=Number(o),m=0;if(s===1)m=a.offset;else if(s===2)m=a.file.size;else if(s!==0)return 28;return m+p<0?28:(a.offset=m+p,u().setBigUint64(i,BigInt(a.offset),!0),0)},fd_readdir(r,o,s,i,a){let p=d.get(r);if(!p||p.kind!=="dir")return 8;p.entries||(p.entries=t.listDir(p.path));let m=u(),C=h(),T=0;for(let U=Number(i);U<p.entries.length;U++){let b=p.entries[U],x=Y.encode(b.name),F=new Uint8Array(24+x.length),I=new DataView(F.buffer);I.setBigUint64(0,BigInt(U+1),!0),I.setBigUint64(8,BigInt(U+1),!0),I.setUint32(16,x.length,!0),I.setUint8(20,b.isDir?3:4),F.set(x,24);let j=Math.min(F.length,s-T);if(C.set(F.subarray(0,j),o+T),T+=j,j<F.length)break}return m.setUint32(a,T,!0),0},path_create_directory(r,o,s){let i=L(r,o,s);return i===null?8:t.exists(i)?20:t.dirs.has(H(i))?(t.dirs.add(i),0):44},path_filestat_get(r,o,s,i,a){let p=L(r,s,i);return p===null?8:z(p,a)},path_open(r,o,s,i,a,p,m,C,T){let U=L(r,s,i);if(U===null)return 8;let b=u();if(t.dirs.has(U)){if(a&4&&a&1)return 20;let I=S++;return d.set(I,{kind:"dir",path:U}),b.setUint32(T,I,!0),0}if(a&2)return t.files.has(U)?54:44;let x=t.files.get(U);if(x){if(a&4&&a&1)return 20;a&8&&(x.data=new Uint8Array(0),x.size=0)}else{if(!(a&1)||!t.dirs.has(H(U)))return 44;x={data:new Uint8Array(0),size:0},t.files.set(U,x)}let F=S++;return d.set(F,{kind:"file",path:U,file:x,offset:C&1?x.size:0}),b.setUint32(T,F,!0),0},path_remove_directory(r,o,s){let i=L(r,o,s);return i===null?8:t.dirs.has(i)?t.listDir(i).length>0?55:(t.dirs.delete(i),0):t.files.has(i)?54:44},path_unlink_file(r,o,s){let i=L(r,o,s);return i===null?8:t.files.has(i)?(t.files.delete(i),0):t.dirs.has(i)?31:44},fd_sync(){return 0},fd_datasync(){return 0},fd_advise(){return 0},fd_tell(r,o){let s=d.get(r);return!s||s.kind!=="file"?8:(u().setBigUint64(o,BigInt(s.offset),!0),0)},fd_renumber(r,o){return!d.has(r)||!d.has(o)?8:(d.set(o,d.get(r)),d.delete(r),0)},fd_allocate:()=>52,fd_fdstat_set_flags:()=>52,fd_fdstat_set_rights:()=>52,fd_filestat_set_times:()=>52,path_filestat_set_times:()=>52,path_link:()=>52,path_readlink:()=>52,path_rename:()=>52,path_symlink:()=>52,proc_raise:()=>52,sock_accept:()=>52,sock_recv:()=>52,sock_send:()=>52,sock_shutdown:()=>52,proc_exit(r){throw new N(r)},random_get(r,o){return globalThis.crypto.getRandomValues(h().subarray(r,r+o)),0},sched_yield(){return 0},poll_oneoff(){return 52}},setMemory(r){l=r},flush:R}},q=(t,e)=>{let n=new WebAssembly.Instance(t,{wasi_snapshot_preview1:e.imports});e.setMemory(n.exports.memory);let c=0;try{n.exports._start()}catch(f){if(f instanceof N)c=f.code;else throw e.flush(),f}return e.flush(),c};var B=class extends Error{constructor(e){super(`The program exited (code ${e}).`),this.name="JsExit",this.code=e}},Ft=new TextEncoder,It=new TextDecoder,nt=t=>new Proxy(t,{get:(e,n)=>typeof n=="string"&&!(n in e)?()=>0:e[n]});function st({input:t="",args:e=[],stdout:n=()=>{},stderr:c=()=>{}}={}){let f=typeof t=="string"?Ft.encode(t):new Uint8Array(t),E=0,w=null,g=()=>new Uint8Array(w.buffer),d=(l,h)=>It.decode(g().subarray(l,l+h)),S=new Proxy({},{get:(l,h)=>typeof h=="string"?()=>0:void 0}),_={write(l,h,u){let y=d(h,u);(l===2?c:n)(y)},read(l,h,u){if(l!==0)return 0;let y=Math.max(0,Math.min(u,f.length-E));return y>0&&(g().set(f.subarray(E,E+y),h),E+=y),y},trap(){throw new B(1)},abort(){throw new B(1)},alert(){},evaluate(l,h){let u=d(l,h);(0,globalThis.eval)(u)},open(){},time_now:()=>BigInt(Date.now()),tick_now:()=>globalThis.performance?.now?.()??Date.now(),time_sleep(){},sqrt:Math.sqrt,sin:Math.sin,cos:Math.cos,pow:Math.pow,fmuladd:(l,h,u)=>l*h+u,ln:Math.log,exp:Math.exp,ldexp:(l,h)=>l*2**h,rand_bytes(l,h){g().set(globalThis.crypto.getRandomValues(new Uint8Array(h)),l)}};return{imports:{env:nt({}),odin_env:nt(_),odin_dom:S,webgl:S,webgl2:S},setMemory(l){w=l},args:e}}var J="/odin",it="/out/main.wasm",v=["wasi_wasm32","js_wasm32"],Ot=new TextEncoder,ot=()=>{let t=[],e=[],n=[];return{stdout:c=>{t.push(c),n.push(c)},stderr:c=>{e.push(c),n.push(c)},stdoutText:()=>t.join(""),stderrText:()=>e.join(""),outputText:()=>n.join("")}},Rt=t=>t.split(`
3
- `).map(e=>e.trimEnd()).filter(e=>e.trim()!=="");function ct({compilerModule:t,libraryEntries:e}){let n=()=>{let g=new $;for(let[d,S]of e)g.writeFile(`${J}/${d}`,S);return g.mkdirAll(`${J}/vendor`),g},c=({code:g,target:d,compileArgs:S,fileName:_})=>{let l=n();l.writeFile(`/src/${_}`,Ot.encode(g)),l.mkdirAll("/out");let h=[],u=[],y=["odin","build","/src",`-out:${it}`,"-backend:wasm",`-target:${d}`,...S],k=1,R="";try{k=q(t,X(l,{args:y,env:[`ODIN_ROOT=${J}`],stdout:A=>h.push(A),stderr:A=>u.push(A)}))}catch(A){R=A?.message??String(A)}return{exitCode:k,artifact:k===0?l.readFile(it):null,diagnostics:Rt(h.join("")+u.join("")),crash:R}},f=(g,{input:d,args:S})=>{let _=ot(),l=0;try{l=q(new WebAssembly.Module(g.slice()),X(new $,{args:["main.wasm",...S],stdin:d,stdout:_.stdout,stderr:_.stderr}))}catch(h){h instanceof N?l=h.code:(_.stderr(`The program trapped: ${h?.message??h}
4
- `),l=1)}return{exitCode:l,...at(_)}},E=async(g,{input:d,args:S})=>{let _=ot(),l=st({input:d,args:["main.wasm",...S],stdout:_.stdout,stderr:_.stderr}),h=0;try{let{instance:u}=await WebAssembly.instantiate(g.slice(),l.imports);l.setMemory(u.exports.memory),u.exports._start&&u.exports._start(),u.exports._end&&u.exports._end()}catch(u){u instanceof B?h=u.code:(_.stderr(`The program trapped: ${u?.message??u}
5
- `),h=1)}return{exitCode:h,...at(_)}};return{compileAndRun:async({code:g,input:d="",target:S,args:_=[],compileArgs:l=[],fileName:h="main.odin"})=>{let u=M(),y=c({code:g,target:S,compileArgs:[...l],fileName:h}),k=Math.round(M()-u);if(y.artifact===null||y.artifact.length===0)return{stdout:"",stderr:"",output:"",errors:y.crash?[y.crash]:y.diagnostics.length>0?y.diagnostics:[`The compiler produced no module (exit code ${y.exitCode}).`],exitCode:null,compileMs:k,runMs:null};let R=M(),A;try{A=S==="js_wasm32"?await E(y.artifact,{input:d,args:_}):f(y.artifact,{input:d,args:_})}catch(D){A={exitCode:1,stdout:"",stderr:`The program could not run: ${D?.message??D}
6
- `,output:""},A.output=A.stderr}let z=Math.round(M()-R);return{stdout:A.stdout,stderr:A.stderr,output:A.output,errors:[],exitCode:A.exitCode,compileMs:k,runMs:z}}}}var at=t=>({stdout:t.stdoutText(),stderr:t.stderrText(),output:t.outputText()}),M=()=>globalThis.performance?.now?.()??Date.now();var dt="ODINPOC1";function ut(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);if(new TextDecoder().decode(e.subarray(0,8))!==dt)throw new Error(`The standard library pack is not a ${dt} container.`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),c=new TextDecoder,f=n.getUint32(8,!0),E=[],w=12;for(let g=0;g<f;g++){let d=n.getUint32(w,!0);w+=4;let S=c.decode(e.subarray(w,w+d));w+=d;let _=n.getUint32(w,!0);w+=4,E.push([S,e.subarray(w,w+_)]),w+=_}return E}var P=new Map;async function Dt(t,e){let n=g=>(d,S)=>e?.({name:g,loaded:d,total:S}),c=await t.readAsset("odin.wasm",n("odin.wasm")),f=await t.readAsset("odin-src.pack.gz",n("odin-src.pack.gz")),E=await WebAssembly.compile(c),w=ut(await rt(f));return ct({compilerModule:E,libraryEntries:w})}function lt(t,e){let n=P.get(t.key);return n===void 0&&(n={key:t.key,refs:0,promise:Dt(t,e)},P.set(t.key,n),n.promise.catch(()=>P.delete(t.key))),n.refs+=1,n}function K(t){t.refs-=1,t.refs<=0&&P.delete(t.key)}var Nt={wasi:"wasi_wasm32","wasi-wasm32":"wasi_wasm32",js:"js_wasm32","js-wasm32":"js_wasm32"};function ft(t,e){let n=t??e;if(n==null)return"wasi_wasm32";let c=Nt[n]??n;if(!v.includes(c))throw new Error(`Unknown target "${n}". Expected one of ${v.join(", ")}.`);return c}function Et({packaged:t}){async function e(n={}){let c=ft(n.target),f=tt(n,t),E=lt(f,n.onProgress),w;try{w=await E.promise}catch(S){throw K(E),S}let g={target:c,args:n.args??[],compileArgs:n.compileArgs??[],fileName:n.fileName??"main.odin"},d=!1;return{get target(){return g.target},get targets(){return[...v]},async run(S,_,l={}){if(d)throw new Error("This compiler has been disposed.");if(typeof S!="string")throw new Error("run() needs the program source as its first argument.");return w.compileAndRun({code:S,input:_??"",target:ft(l.target,g.target),args:l.args??g.args,compileArgs:[...g.compileArgs,...l.compileArgs??[]],fileName:l.fileName??g.fileName})},dispose(){d||(d=!0,K(E))}}}return{createCompiler:e,TARGETS:v}}var ht=Et({packaged:null}),Bt=ht.createCompiler,{TARGETS:Lt}=ht;return _t(Yt);})();
1
+ var odinWasm=(()=>{var W=Object.defineProperty;var gt=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var St=Object.prototype.hasOwnProperty;var wt=(t,e)=>{for(var n in e)W(t,n,{get:e[n],enumerable:!0})},_t=(t,e,n,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let f of mt(e))!St.call(t,f)&&f!==n&&W(t,f,{get:()=>e[f],enumerable:!(a=gt(e,f))||a.enumerable});return t};var yt=t=>_t(W({},"__esModule",{value:!0}),t);var $t={};wt($t,{TARGETS:()=>Yt,createCompiler:()=>Lt});var V=Object.freeze({"odin.wasm":Object.freeze({bytes:3763439,sha256:"5044e383aa2415927cd518a4d3e6fdbcc6c99154ac90d212e154f18c092deef3"}),"odin-src.pack.gz":Object.freeze({bytes:2502169,sha256:"567b1c0c1b50d3e557d119927ade3373dda91364acae3302f2cf01950a8dd8f9"}),"odin.js":Object.freeze({bytes:72772,sha256:"e918ba1614af23f02299976122d5edf4c994873ce4c6cdab621d42f3e9cb9733"})});var Gt=Object.freeze(Object.keys(V)),Ut="baseUrl is required here. The assets that ship in this package can only be read where there is a filesystem, and a browser cannot reach a file inside an npm package \u2014 copy them somewhere your page can fetch with `npx --package @live-codes/odin-wasm odin-wasm-copy-assets <dir>` and pass that directory as baseUrl.";function et(t,e){if(t.baseUrl!=null&&t.baseUrl!=="")return At(t);if(!e)throw new Error(Ut);return Ct(e)}function At(t){let e=Tt(t.baseUrl);return{kind:"hosted",key:`hosted\0${e}`,description:e,baseUrl:e,async readAsset(n,a){let f=new URL(n,e),h=await fetch(f);if(!h.ok)throw new Error(`Failed to load the runtime asset ${f}: ${h.status}`);return rt(n,await bt(h,a))}}}function Ct(t){return{kind:"packaged",key:`packaged\0${t.root.href}`,description:`the assets packaged with this library (${t.root.href})`,async readAsset(e){let n;try{n=await t.readFile(e)}catch(a){throw new Error(`Failed to read the packaged asset ${e} from ${t.root.href}: ${a.message}`,{cause:a})}return rt(e,n)}}}function Tt(t){let e;try{e=t instanceof URL?t:new URL(t,globalThis.document?.baseURI)}catch(n){throw new Error(`baseUrl must be an absolute http(s) URL, or relative to the page in a browser: ${n.message}`,{cause:n})}if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Error(`baseUrl must be an absolute http(s) URL, or relative to the page in a browser: got "${t}"`);return e.href.endsWith("/")?e.href:`${e.href}/`}async function bt(t,e){if(!e||!t.body)return new Uint8Array(await t.arrayBuffer());let n=Number(t.headers.get("content-length"))||0,a=t.body.getReader(),f=[],h=0;for(e(0,n);;){let{done:c,value:g}=await a.read();if(c)break;f.push(g),h+=g.length,e(h,n)}let m=new Uint8Array(h),y=0;for(let c of f)m.set(c,y),y+=c.length;return m}async function rt(t,e){let n=V[t];if(!n)throw new Error(`No pinned receipt for the runtime asset ${t}`);if(e.byteLength!==n.bytes)throw new Error(`The runtime asset ${t} is ${e.byteLength} bytes, expected ${n.bytes}`);let a=await xt(e);if(a!==n.sha256)throw new Error(`The runtime asset ${t} failed SHA-256 verification: expected ${n.sha256}, got ${a}`);return e}async function xt(t){let e=globalThis.crypto?.subtle;if(!e)throw new Error("Verifying the runtime assets needs crypto.subtle: a secure context in the browser, or Node 20 and later.");let n=await e.digest("SHA-256",t);return[...new Uint8Array(n)].map(a=>a.toString(16).padStart(2,"0")).join("")}async function nt(t){if(typeof DecompressionStream!="function")throw new Error("Inflating the standard library pack needs DecompressionStream");let e=new Blob([t]).stream().pipeThrough(new DecompressionStream("gzip"));return new Uint8Array(await new Response(e).arrayBuffer())}var B=class extends Error{constructor(e){super(`WASI process exited with code ${e}`),this.code=e}},R=t=>{let e=[];for(let n of String(t).split("/"))if(!(n===""||n===".")){if(n===".."){e.pop();continue}e.push(n)}return e.join("/")},H=t=>{let e=t.lastIndexOf("/");return e<0?"":t.slice(0,e)},M=new TextEncoder,kt=new TextDecoder,v=class{constructor(){this.files=new Map,this.dirs=new Set([""])}mkdirAll(e){let n=R(e)===""?[]:R(e).split("/"),a="";for(let f of n)a=a===""?f:`${a}/${f}`,this.dirs.add(a)}writeFile(e,n){let a=R(e);this.mkdirAll(H(a));let f=n instanceof Uint8Array?n:new Uint8Array(n);this.files.set(a,{data:f,size:f.length})}readFile(e){let n=this.files.get(R(e));return n?n.data.subarray(0,n.size):null}exists(e){let n=R(e);return this.files.has(n)||this.dirs.has(n)}listDir(e){let n=R(e),a=n===""?"":`${n}/`,f=[];for(let h of this.dirs)h!==""&&h.startsWith(a)&&h.indexOf("/",a.length)<0&&h!==n&&f.push({name:h.slice(a.length),isDir:!0});for(let h of this.files.keys())h.startsWith(a)&&h.indexOf("/",a.length)<0&&f.push({name:h.slice(a.length),isDir:!1});return f.sort((h,m)=>h.name<m.name?-1:h.name>m.name?1:0),f}},Ft=t=>t instanceof Uint8Array?t:new Uint8Array(t),X=(t,e={})=>{let n=e.args??[],a=e.env??[],f=e.stdout??(()=>{}),h=e.stderr??(()=>{}),m=Ft(M.encode(e.stdin??"")),y=0,c=new Map,g=4;c.set(0,{kind:"stdin"}),c.set(1,{kind:"stdout"}),c.set(2,{kind:"stderr"}),c.set(3,{kind:"dir",path:""});let S=["","",""],u=null,E=()=>new Uint8Array(u.buffer),l=()=>new DataView(u.buffer),_=(r,o)=>kt.decode(E().subarray(r,r+o)),F=(r,o)=>{let s=S[r]+o,i=s.lastIndexOf(`
2
+ `);i>=0&&((r===1?f:h)(s.slice(0,i+1)),s=s.slice(i+1)),S[r]=s},O=()=>{for(let r of[1,2])S[r]!==""&&((r===1?f:h)(S[r]),S[r]="")},k=(r,o,s)=>{let i=l();i.setBigUint64(r+0,0n,!0),i.setBigUint64(r+8,0n,!0),i.setUint8(r+16,o),i.setBigUint64(r+24,1n,!0),i.setBigUint64(r+32,BigInt(s),!0),i.setBigUint64(r+40,0n,!0),i.setBigUint64(r+48,0n,!0),i.setBigUint64(r+56,0n,!0)},C=(r,o)=>{if(t.dirs.has(r))return k(o,3,0),0;let s=t.files.get(r);return s?(k(o,4,s.size),0):44},P=(r,o)=>{if(o<=r.data.length)return;let s=Math.max(r.data.length*2,4096);for(;s<o;)s*=2;let i=new Uint8Array(s);i.set(r.data.subarray(0,r.size)),r.data=i},D=(r,o,s,i)=>{let d=l(),p=E(),w=0;for(let A=0;A<s;A++){let T=d.getUint32(o+A*8,!0),U=d.getUint32(o+A*8+4,!0),b=Math.max(0,Math.min(U,r.size-i));if(p.set(r.data.subarray(i,i+b),T),i+=b,w+=b,b<U)break}return w},Z=(r,o,s,i)=>{let d=l(),p=E(),w=0;for(let A=0;A<s;A++){let T=d.getUint32(o+A*8,!0),U=d.getUint32(o+A*8+4,!0);P(r,i+U),r.data.set(p.subarray(T,T+U),i),i+=U,r.size=Math.max(r.size,i),w+=U}return w},tt=(r,o,s)=>{let i=l(),d=E(),p=s;for(let w=0;w<r.length;w++){let A=M.encode(r[w]);i.setUint32(o+w*4,p,!0),d.set(A,p),d[p+A.length]=0,p+=A.length+1}return 0},$=(r,o,s)=>{let i=c.get(r);if(!i||i.kind!=="dir")return null;let d=_(o,s);return R(d.startsWith("/")?d:`${i.path}/${d}`)};return{imports:{args_sizes_get(r,o){let s=l();return s.setUint32(r,n.length,!0),s.setUint32(o,n.reduce((i,d)=>i+M.encode(d).length+1,0),!0),0},args_get(r,o){return tt(n,r,o)},environ_sizes_get(r,o){let s=l();return s.setUint32(r,a.length,!0),s.setUint32(o,a.reduce((i,d)=>i+M.encode(d).length+1,0),!0),0},environ_get(r,o){return tt(a,r,o)},clock_res_get(r,o){return l().setBigUint64(o,1000n,!0),0},clock_time_get(r,o,s){let i=r===0?BigInt(Date.now())*1000000n:BigInt(Math.round((globalThis.performance?.now()??Date.now())*1e3))*1000n;return l().setBigUint64(s,i,!0),0},fd_close(r){return c.has(r)?(r>3&&c.delete(r),0):8},fd_fdstat_get(r,o){let s=c.get(r);if(!s)return 8;let i=l(),d=s.kind==="dir"?3:s.kind==="file"?4:2;return i.setUint8(o,d),i.setUint16(o+2,0,!0),i.setBigUint64(o+8,0xffffffffffffffffn,!0),i.setBigUint64(o+16,0xffffffffffffffffn,!0),0},fd_filestat_get(r,o){let s=c.get(r);return s?(s.kind==="dir"?k(o,3,0):s.kind==="file"?k(o,4,s.file.size):k(o,2,0),0):8},fd_filestat_set_size(r,o){let s=c.get(r);if(!s||s.kind!=="file")return 8;let i=Number(o);return P(s.file,i),i>s.file.size&&s.file.data.fill(0,s.file.size,i),s.file.size=i,0},fd_prestat_get(r,o){if(r!==3)return 8;let s=l();return s.setUint8(o,0),s.setUint32(o+4,1,!0),0},fd_prestat_dir_name(r,o,s){return r!==3?8:(s>=1&&(E()[o]=47),0)},fd_read(r,o,s,i){let d=c.get(r);if(!d)return 8;if(d.kind==="stdin"){let w=D({data:m,size:m.length},o,s,y);return y+=w,l().setUint32(i,w,!0),0}if(d.kind!=="file")return 8;let p=D(d.file,o,s,d.offset);return d.offset+=p,l().setUint32(i,p,!0),0},fd_pread(r,o,s,i,d){let p=c.get(r);if(!p||p.kind!=="file")return 8;let w=D(p.file,o,s,Number(i));return l().setUint32(d,w,!0),0},fd_write(r,o,s,i){let d=c.get(r);if(!d)return 8;if(d.kind==="stdout"||d.kind==="stderr"){let w=l(),A=0;for(let T=0;T<s;T++){let U=w.getUint32(o+T*8,!0),b=w.getUint32(o+T*8+4,!0);F(r,_(U,b)),A+=b}return w.setUint32(i,A,!0),0}if(d.kind!=="file")return 8;let p=Z(d.file,o,s,d.offset);return d.offset+=p,l().setUint32(i,p,!0),0},fd_pwrite(r,o,s,i,d){let p=c.get(r);if(!p||p.kind!=="file")return 8;let w=Z(p.file,o,s,Number(i));return l().setUint32(d,w,!0),0},fd_seek(r,o,s,i){let d=c.get(r);if(!d||d.kind!=="file")return 8;let p=Number(o),w=0;if(s===1)w=d.offset;else if(s===2)w=d.file.size;else if(s!==0)return 28;return w+p<0?28:(d.offset=w+p,l().setBigUint64(i,BigInt(d.offset),!0),0)},fd_readdir(r,o,s,i,d){let p=c.get(r);if(!p||p.kind!=="dir")return 8;p.entries||(p.entries=t.listDir(p.path));let w=l(),A=E(),T=0;for(let U=Number(i);U<p.entries.length;U++){let b=p.entries[U],x=M.encode(b.name),I=new Uint8Array(24+x.length),N=new DataView(I.buffer);N.setBigUint64(0,BigInt(U+1),!0),N.setBigUint64(8,BigInt(U+1),!0),N.setUint32(16,x.length,!0),N.setUint8(20,b.isDir?3:4),I.set(x,24);let j=Math.min(I.length,s-T);if(A.set(I.subarray(0,j),o+T),T+=j,j<I.length)break}return w.setUint32(d,T,!0),0},path_create_directory(r,o,s){let i=$(r,o,s);return i===null?8:t.exists(i)?20:t.dirs.has(H(i))?(t.dirs.add(i),0):44},path_filestat_get(r,o,s,i,d){let p=$(r,s,i);return p===null?8:C(p,d)},path_open(r,o,s,i,d,p,w,A,T){let U=$(r,s,i);if(U===null)return 8;let b=l();if(t.dirs.has(U)){if(d&4&&d&1)return 20;let N=g++;return c.set(N,{kind:"dir",path:U}),b.setUint32(T,N,!0),0}if(d&2)return t.files.has(U)?54:44;let x=t.files.get(U);if(x){if(d&4&&d&1)return 20;d&8&&(x.data=new Uint8Array(0),x.size=0)}else{if(!(d&1)||!t.dirs.has(H(U)))return 44;x={data:new Uint8Array(0),size:0},t.files.set(U,x)}let I=g++;return c.set(I,{kind:"file",path:U,file:x,offset:A&1?x.size:0}),b.setUint32(T,I,!0),0},path_remove_directory(r,o,s){let i=$(r,o,s);return i===null?8:t.dirs.has(i)?t.listDir(i).length>0?55:(t.dirs.delete(i),0):t.files.has(i)?54:44},path_unlink_file(r,o,s){let i=$(r,o,s);return i===null?8:t.files.has(i)?(t.files.delete(i),0):t.dirs.has(i)?31:44},fd_sync(){return 0},fd_datasync(){return 0},fd_advise(){return 0},fd_tell(r,o){let s=c.get(r);return!s||s.kind!=="file"?8:(l().setBigUint64(o,BigInt(s.offset),!0),0)},fd_renumber(r,o){return!c.has(r)||!c.has(o)?8:(c.set(o,c.get(r)),c.delete(r),0)},fd_allocate:()=>52,fd_fdstat_set_flags:()=>52,fd_fdstat_set_rights:()=>52,fd_filestat_set_times:()=>52,path_filestat_set_times:()=>52,path_link:()=>52,path_readlink:()=>52,path_rename:()=>52,path_symlink:()=>52,proc_raise:()=>52,sock_accept:()=>52,sock_recv:()=>52,sock_send:()=>52,sock_shutdown:()=>52,proc_exit(r){throw new B(r)},random_get(r,o){return globalThis.crypto.getRandomValues(E().subarray(r,r+o)),0},sched_yield(){return 0},poll_oneoff(){return 52}},setMemory(r){u=r},flush:O}},q=(t,e)=>{let n=new WebAssembly.Instance(t,{wasi_snapshot_preview1:e.imports});e.setMemory(n.exports.memory);let a=0;try{n.exports._start()}catch(f){if(f instanceof B)a=f.code;else throw e.flush(),f}return e.flush(),a};var L=class extends Error{constructor(e){super(`The program exited (code ${e}).`),this.name="JsExit",this.code=e}},Ot=new TextEncoder,It=new TextDecoder,st=t=>new Proxy(t,{get:(e,n)=>typeof n=="string"&&!(n in e)?()=>0:e[n]});function it({input:t="",args:e=[],stdout:n=()=>{},stderr:a=()=>{}}={}){let f=typeof t=="string"?Ot.encode(t):new Uint8Array(t),h=0,m=null,y=()=>new Uint8Array(m.buffer),c=(u,E)=>It.decode(y().subarray(u,u+E)),g=new Proxy({},{get:(u,E)=>typeof E=="string"?()=>0:void 0}),S={write(u,E,l){let _=c(E,l);(u===2?a:n)(_)},read(u,E,l){if(u!==0)return 0;let _=Math.max(0,Math.min(l,f.length-h));return _>0&&(y().set(f.subarray(h,h+_),E),h+=_),_},trap(){throw new L(1)},abort(){throw new L(1)},alert(){},evaluate(u,E){let l=c(u,E);(0,globalThis.eval)(l)},open(){},time_now:()=>BigInt(Date.now()),tick_now:()=>globalThis.performance?.now?.()??Date.now(),time_sleep(){},sqrt:Math.sqrt,sin:Math.sin,cos:Math.cos,pow:Math.pow,fmuladd:(u,E,l)=>u*E+l,ln:Math.log,exp:Math.exp,ldexp:(u,E)=>u*2**E,rand_bytes(u,E){y().set(globalThis.crypto.getRandomValues(new Uint8Array(E)),u)}};return{imports:{env:st({}),odin_env:st(S),odin_dom:g,webgl:g,webgl2:g},setMemory(u){m=u},args:e}}var J="/odin",ot="/out/main.wasm",z=["wasi_wasm32","js_wasm32"],Nt=new TextEncoder,at=()=>{let t=[],e=[],n=[];return{stdout:a=>{t.push(a),n.push(a)},stderr:a=>{e.push(a),n.push(a)},stdoutText:()=>t.join(""),stderrText:()=>e.join(""),outputText:()=>n.join("")}},Rt=t=>t.split(`
3
+ `).map(e=>e.trimEnd()).filter(e=>e.trim()!==""),ct=t=>t.crash?[t.crash]:t.diagnostics.length>0?t.diagnostics:[`The compiler produced no module (exit code ${t.exitCode}).`];function lt({compilerModule:t,libraryEntries:e}){let n=()=>{let c=new v;for(let[g,S]of e)c.writeFile(`${J}/${g}`,S);return c.mkdirAll(`${J}/vendor`),c},a=({code:c,target:g,compileArgs:S,fileName:u})=>{let E=n();E.writeFile(`/src/${u}`,Nt.encode(c)),E.mkdirAll("/out");let l=[],_=[],F=["odin","build","/src",`-out:${ot}`,"-backend:wasm",`-target:${g}`,...S],O=1,k="";try{O=q(t,X(E,{args:F,env:[`ODIN_ROOT=${J}`],stdout:C=>l.push(C),stderr:C=>_.push(C)}))}catch(C){k=C?.message??String(C)}return{exitCode:O,artifact:O===0?E.readFile(ot):null,diagnostics:Rt(l.join("")+_.join("")),crash:k}},f=({code:c,target:g,compileArgs:S=[],fileName:u="main.odin"})=>{let E=Y(),l=a({code:c,target:g,compileArgs:[...S],fileName:u}),_=Math.round(Y()-E);return l.artifact===null||l.artifact.length===0?{ok:!1,wasm:null,errors:ct(l),compileMs:_}:{ok:!0,wasm:l.artifact,errors:[],compileMs:_}},h=(c,{input:g,args:S})=>{let u=at(),E=0;try{E=q(new WebAssembly.Module(c.slice()),X(new v,{args:["main.wasm",...S],stdin:g,stdout:u.stdout,stderr:u.stderr}))}catch(l){l instanceof B?E=l.code:(u.stderr(`The program trapped: ${l?.message??l}
4
+ `),E=1)}return{exitCode:E,...dt(u)}},m=async(c,{input:g,args:S})=>{let u=at(),E=it({input:g,args:["main.wasm",...S],stdout:u.stdout,stderr:u.stderr}),l=0;try{let{instance:_}=await WebAssembly.instantiate(c.slice(),E.imports);E.setMemory(_.exports.memory),_.exports._start&&_.exports._start(),_.exports._end&&_.exports._end()}catch(_){_ instanceof L?l=_.code:(u.stderr(`The program trapped: ${_?.message??_}
5
+ `),l=1)}return{exitCode:l,...dt(u)}};return{compileAndRun:async({code:c,input:g="",target:S,args:u=[],compileArgs:E=[],fileName:l="main.odin"})=>{let _=Y(),F=a({code:c,target:S,compileArgs:[...E],fileName:l}),O=Math.round(Y()-_);if(F.artifact===null||F.artifact.length===0)return{stdout:"",stderr:"",output:"",errors:ct(F),exitCode:null,compileMs:O,runMs:null};let k=Y(),C;try{C=S==="js_wasm32"?await m(F.artifact,{input:g,args:u}):h(F.artifact,{input:g,args:u})}catch(D){C={exitCode:1,stdout:"",stderr:`The program could not run: ${D?.message??D}
6
+ `,output:""},C.output=C.stderr}let P=Math.round(Y()-k);return{stdout:C.stdout,stderr:C.stderr,output:C.output,errors:[],exitCode:C.exitCode,compileMs:O,runMs:P}},compileOnly:f}}var dt=t=>({stdout:t.stdoutText(),stderr:t.stderrText(),output:t.outputText()}),Y=()=>globalThis.performance?.now?.()??Date.now();var ut="ODINPOC1";function ft(t){let e=t instanceof Uint8Array?t:new Uint8Array(t);if(new TextDecoder().decode(e.subarray(0,8))!==ut)throw new Error(`The standard library pack is not a ${ut} container.`);let n=new DataView(e.buffer,e.byteOffset,e.byteLength),a=new TextDecoder,f=n.getUint32(8,!0),h=[],m=12;for(let y=0;y<f;y++){let c=n.getUint32(m,!0);m+=4;let g=a.decode(e.subarray(m,m+c));m+=c;let S=n.getUint32(m,!0);m+=4,h.push([g,e.subarray(m,m+S)]),m+=S}return h}var G=new Map;async function Dt(t,e){let n=y=>(c,g)=>e?.({name:y,loaded:c,total:g}),a=await t.readAsset("odin.wasm",n("odin.wasm")),f=await t.readAsset("odin-src.pack.gz",n("odin-src.pack.gz")),h=await WebAssembly.compile(a),m=ft(await nt(f));return lt({compilerModule:h,libraryEntries:m})}function Et(t,e){let n=G.get(t.key);return n===void 0&&(n={key:t.key,refs:0,promise:Dt(t,e)},G.set(t.key,n),n.promise.catch(()=>G.delete(t.key))),n.refs+=1,n}function K(t){t.refs-=1,t.refs<=0&&G.delete(t.key)}var Bt={wasi:"wasi_wasm32","wasi-wasm32":"wasi_wasm32",js:"js_wasm32","js-wasm32":"js_wasm32"};function Q(t,e){let n=t??e;if(n==null)return"wasi_wasm32";let a=Bt[n]??n;if(!z.includes(a))throw new Error(`Unknown target "${n}". Expected one of ${z.join(", ")}.`);return a}function ht({packaged:t}){async function e(n={}){let a=Q(n.target),f=et(n,t),h=Et(f,n.onProgress),m;try{m=await h.promise}catch(g){throw K(h),g}let y={target:a,args:n.args??[],compileArgs:n.compileArgs??[],fileName:n.fileName??"main.odin"},c=!1;return{get target(){return y.target},get targets(){return[...z]},async run(g,S,u={}){if(c)throw new Error("This compiler has been disposed.");if(typeof g!="string")throw new Error("run() needs the program source as its first argument.");return m.compileAndRun({code:g,input:S??"",target:Q(u.target,y.target),args:u.args??y.args,compileArgs:[...y.compileArgs,...u.compileArgs??[]],fileName:u.fileName??y.fileName})},async compile(g,S={}){if(c)throw new Error("This compiler has been disposed.");if(typeof g!="string")throw new Error("compile() needs the program source as its first argument.");return m.compileOnly({code:g,target:Q(S.target,y.target),compileArgs:[...y.compileArgs,...S.compileArgs??[]],fileName:S.fileName??y.fileName})},dispose(){c||(c=!0,K(h))}}}return{createCompiler:e,TARGETS:z}}var pt=ht({packaged:null}),Lt=pt.createCompiler,{TARGETS:Yt}=pt;return yt($t);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-codes/odin-wasm",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Run Odin in the browser with one API, on the Odin compiler compiled to WebAssembly",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,17 +11,25 @@ import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises';
11
11
  import { createHash } from 'node:crypto';
12
12
 
13
13
  const ROOT_ASSETS = new URL('../../../assets/', import.meta.url);
14
+ const PUBLIC = new URL('../../../public/', import.meta.url);
14
15
  const PACKAGE_ASSETS = new URL('../assets/', import.meta.url);
15
16
  const RECEIPTS = new URL('../src/asset-receipts.js', import.meta.url);
16
17
 
17
- // Loaded in this order, and the order is the load order.
18
- const ASSET_NAMES = ['odin.wasm', 'odin-src.pack.gz'];
18
+ // What ships in assets/, in the order the package loads it, and where each comes from.
19
+ const ASSETS = [
20
+ ['odin.wasm', new URL('odin.wasm', ROOT_ASSETS)],
21
+ ['odin-src.pack.gz', new URL('odin-src.pack.gz', ROOT_ASSETS)],
22
+ // Odin's own JS runtime, which is what a js_wasm32 program runs on when it needs the DOM — a
23
+ // worker has no `document`, so the host instantiates on the page. The repository vendors it for
24
+ // its own page; this is the same file.
25
+ ['odin.js', new URL('odin.js', PUBLIC)],
26
+ ];
19
27
 
20
28
  await mkdir(PACKAGE_ASSETS, { recursive: true });
21
29
 
22
30
  const receipts = [];
23
- for (const name of ASSET_NAMES) {
24
- await copyFile(new URL(name, ROOT_ASSETS), new URL(name, PACKAGE_ASSETS));
31
+ for (const [name, from] of ASSETS) {
32
+ await copyFile(from, new URL(name, PACKAGE_ASSETS));
25
33
  const bytes = await readFile(new URL(name, PACKAGE_ASSETS));
26
34
  receipts.push({
27
35
  name,
package/src/api.js CHANGED
@@ -104,6 +104,29 @@ export function createApi({ packaged }) {
104
104
  });
105
105
  },
106
106
 
107
+ /**
108
+ * Compile without running, for a host that runs the module itself.
109
+ *
110
+ * A page that needs the DOM cannot use `run`: a worker has no `document`, so the module has to
111
+ * be instantiated on the page with Odin's own JS runtime. This hands back the module for that.
112
+ *
113
+ * @param {string} code - the Odin source.
114
+ * @param {object} [options] - per-call `target`, `compileArgs`, `fileName`.
115
+ * @returns {Promise<{ok: boolean, wasm: Uint8Array|null, errors: string[], compileMs: number}>}
116
+ */
117
+ async compile(code, options = {}) {
118
+ if (disposed) throw new Error('This compiler has been disposed.');
119
+ if (typeof code !== 'string') {
120
+ throw new Error('compile() needs the program source as its first argument.');
121
+ }
122
+ return engine.compileOnly({
123
+ code,
124
+ target: resolveTarget(options.target, defaults.target),
125
+ compileArgs: [...defaults.compileArgs, ...(options.compileArgs ?? [])],
126
+ fileName: options.fileName ?? defaults.fileName,
127
+ });
128
+ },
129
+
107
130
  /** Drop this compiler's hold on the shared engine. Further runs throw. */
108
131
  dispose() {
109
132
  if (disposed) return;
@@ -8,5 +8,6 @@
8
8
 
9
9
  export const ASSET_RECEIPTS = Object.freeze({
10
10
  'odin.wasm': Object.freeze({ bytes: 3763439, sha256: '5044e383aa2415927cd518a4d3e6fdbcc6c99154ac90d212e154f18c092deef3' }),
11
- 'odin-src.pack.gz': Object.freeze({ bytes: 2502169, sha256: '567b1c0c1b50d3e557d119927ade3373dda91364acae3302f2cf01950a8dd8f9' })
11
+ 'odin-src.pack.gz': Object.freeze({ bytes: 2502169, sha256: '567b1c0c1b50d3e557d119927ade3373dda91364acae3302f2cf01950a8dd8f9' }),
12
+ 'odin.js': Object.freeze({ bytes: 72772, sha256: 'e918ba1614af23f02299976122d5edf4c994873ce4c6cdab621d42f3e9cb9733' })
12
13
  });
package/src/engine.js CHANGED
@@ -44,6 +44,14 @@ const diagnosticLines = (text) =>
44
44
  .map((line) => line.trimEnd())
45
45
  .filter((line) => line.trim() !== '');
46
46
 
47
+ /** Why a compile produced no module, as the lines a caller reads. */
48
+ const compileFailure = (compiled) =>
49
+ compiled.crash
50
+ ? [compiled.crash]
51
+ : compiled.diagnostics.length > 0
52
+ ? compiled.diagnostics
53
+ : [`The compiler produced no module (exit code ${compiled.exitCode}).`];
54
+
47
55
  /**
48
56
  * @param {object} assets
49
57
  * @param {WebAssembly.Module} assets.compilerModule - the Odin compiler
@@ -99,6 +107,25 @@ export function createEngine({ compilerModule, libraryEntries }) {
99
107
  };
100
108
  };
101
109
 
110
+ /**
111
+ * Compile only, returning the module for the caller to run.
112
+ *
113
+ * A page that needs the DOM has to instantiate the program on the main thread — a worker has no
114
+ * `document`, and Odin's JS runtime is written for the page — so the caller takes the module
115
+ * instead of an output string.
116
+ *
117
+ * @returns {{ok: boolean, wasm: Uint8Array|null, errors: string[], compileMs: number}}
118
+ */
119
+ const compileOnly = ({ code, target, compileArgs = [], fileName = 'main.odin' }) => {
120
+ const started = now();
121
+ const compiled = compile({ code, target, compileArgs: [...compileArgs], fileName });
122
+ const compileMs = Math.round(now() - started);
123
+ if (compiled.artifact === null || compiled.artifact.length === 0) {
124
+ return { ok: false, wasm: null, errors: compileFailure(compiled), compileMs };
125
+ }
126
+ return { ok: true, wasm: compiled.artifact, errors: [], compileMs };
127
+ };
128
+
102
129
  const runWasiTarget = (artifact, { input, args }) => {
103
130
  const captured = capture();
104
131
  let exitCode = 0;
@@ -155,12 +182,7 @@ export function createEngine({ compilerModule, libraryEntries }) {
155
182
  const compileMs = Math.round(now() - compileStarted);
156
183
 
157
184
  if (compiled.artifact === null || compiled.artifact.length === 0) {
158
- const errors = compiled.crash
159
- ? [compiled.crash]
160
- : compiled.diagnostics.length > 0
161
- ? compiled.diagnostics
162
- : [`The compiler produced no module (exit code ${compiled.exitCode}).`];
163
- return { stdout: '', stderr: '', output: '', errors, exitCode: null, compileMs, runMs: null };
185
+ return { stdout: '', stderr: '', output: '', errors: compileFailure(compiled), exitCode: null, compileMs, runMs: null };
164
186
  }
165
187
 
166
188
  const runStarted = now();
@@ -186,7 +208,7 @@ export function createEngine({ compilerModule, libraryEntries }) {
186
208
  };
187
209
  };
188
210
 
189
- return { compileAndRun };
211
+ return { compileAndRun, compileOnly };
190
212
  }
191
213
 
192
214
  const capturedText = (captured) => ({