ide-probe.mjs (5080B)
1 import {syntaxProbe} from './syntax-probe.mjs'; 2 import {el,input,change,status,wait,inspect,result,description,card,evaluateSource} from './source-probe-helpers.mjs'; 3 const assert=(condition,message)=>{if(!condition)throw Error(message);}; 4 export async function run(control,backend='haskell-wasm'){ 5 const phase=name=>fetch(control+'/phase',{method:'POST',body:JSON.stringify({name:'ide: '+name})}); 6 await status('Ready');await syntaxProbe();await status('Ready'); 7 assert(!el('runtime-backend'),'No runtime selector'); 8 for(const path of ['worker.js','compiler-worker.js','conformance/worker.js','conformance/compiler-worker.js'])assert((await fetch(new URL('./'+path,document.querySelector('script[type=module][src]').src))).status===404,'JS conformance Workers not shipped'); 9 assert(!el('expression-editor')&&card().hidden,'Arrival is source-first and does not inspect automatically'); 10 el('settings-toggle').click();assert(!el('settings-panel').hidden,'Settings opens');el('settings-close').click();assert(document.activeElement===el('settings-toggle'),'Settings returns focus'); 11 change('program-picker','demo:language-reference');await status('Ready'); 12 for(const [format,want] of [['tricu','t'],['triangle','△'],['dag','tree △\ntree\n'],['ternary','0']])assert(await inspect('leaf',format)===want,'Direct definition '+format); 13 for(const [format,want] of [['tricu','(t t t)'],['triangle','(△ △ △)'],['ternary','200']])assert(await evaluateSource('identity (t t t)',format)===want,'Source-authored application '+format); 14 let copied,blob,download;const clipboard=Object.getOwnPropertyDescriptor(navigator,'clipboard'); 15 Object.defineProperty(navigator,'clipboard',{configurable:true,value:{writeText:async value=>{copied=value;}}}); 16 const createURL=URL.createObjectURL,click=HTMLAnchorElement.prototype.click; 17 URL.createObjectURL=value=>{blob=value;return createURL(value);};HTMLAnchorElement.prototype.click=function(){download=this.download;}; 18 try{ 19 await phase('complete text download'); 20 await evaluateSource(JSON.stringify('a'.repeat(600)),'tricu');assert(result().length===16384&&description().includes('Preview: first 16,384'),'Bounded preview is explicit'); 21 card().querySelector('.definition-actions button').click();await wait(()=>copied!==undefined,'complete copy');assert(copied.length>16384&&copied.startsWith(result()),'Copy has complete tree source'); 22 card().querySelectorAll('.definition-actions button')[1].click();assert(download==='probeResult.tri'&&await blob.text()===copied,'Download matches complete copy'); 23 // Package export uses original DAG records and does not normalize functions. 24 change('program-picker','demo:language-reference');await status('Ready');change('stored-definition','leaf');change('stored-format','tricu');blob=undefined; 25 el('stored-download').click();await wait(()=>!!blob&&el('status').textContent==='Ready','stored export');assert(download==='leaf.tri'&&await blob.text()==='t','Stored-record tree export'); 26 const expectedHash=el('bundle-hash').value;blob=undefined;el('download-bundle').click();await wait(()=>!!blob&&/Downloaded original/.test(el('bundle-download-status').textContent),'verified original bundle'); 27 const digest=[...new Uint8Array(await crypto.subtle.digest('SHA-256',await blob.arrayBuffer()))].map(n=>n.toString(16).padStart(2,'0')).join('');assert(digest===expectedHash&&download===expectedHash+'.arboricx','Immutable authenticated bundle bytes'); 28 }finally{URL.createObjectURL=createURL;HTMLAnchorElement.prototype.click=click;if(clipboard)Object.defineProperty(navigator,'clipboard',clipboard);else delete navigator.clipboard;} 29 el('reload-package').click();await status('Ready'); 30 await phase('shared DAG'); 31 const bindings=['x0 = t t t'];for(let i=1;i<=28;i++)bindings.push(`x${i} = t x${i-1} x${i-1}`); 32 const expression='let\n '+bindings.join('\n ')+'\n in x28'; 33 assert((await evaluateSource(expression,'dag')).length<20000,'DAG preserves exponential sharing'); 34 await phase('expanded tree refusal'); 35 await inspect('probeResult','tricu');assert(/Expanded tree exceeds 32 MiB/.test(description()),'Refuse oversized expansion before constructing output'); 36 assert([...card().querySelectorAll('.definition-actions button')].every(button=>button.disabled),'Partial result never downloadable'); 37 assert(await evaluateSource('identity 52')==='52','Rendering error preserves definitions'); 38 input('bundle-hash','not-a-hash');el('program-hash').requestSubmit();assert(el('status').textContent==='Stopped'&&card().hidden,'Invalid replacement cannot retain old output'); 39 change('program-picker','demo:language-reference');await status('Ready'); 40 await phase('live revisions and IO'); 41 const live=await(await import('/live-ux-probe.mjs')).run(control,backend); 42 change('program-picker','demo:language-reference');await status('Ready'); 43 return {userAgent:navigator.userAgent,checks:[...live.checks,'source-first workspace; native settings; t/triangle/DAG/ternary; complete inline Copy/Download; expansion refusal; non-evaluating stored export; immutable bundle download']}; 44 }