source-probe-helpers.mjs (3148B)
1 // Source edits and definition inspection through the mounted editor. 2 export const el=id=>document.getElementById(id); 3 const {editorFor}=await import(new URL('./probe-api.js',document.querySelector('script[type=module][src]').src)); 4 export const sourceEditor=editorFor(el('source-editor')); 5 globalThis.__sourceEditor=sourceEditor; 6 export const input=(id,value)=>{if(id==='source-editor'){sourceEditor.replaceSource(value,true);return;}el(id).value=value;el(id).dispatchEvent(new Event('input'));}; 7 export const change=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('change'));}; 8 export const pause=ms=>new Promise(r=>setTimeout(r,ms)); 9 export async function wait(check,label='page state'){ 10 for(let i=0;i<3600;i++){if(check())return;await pause(25);} 11 throw Error('Timeout '+label+' / '+el('status').textContent+' / '+el('compile-diagnostic').textContent+' / '+el('operation-diagnostic').textContent); 12 } 13 export const status=value=>wait(()=>el('status').textContent===value,value); 14 export const card=()=>document.querySelector('.definition-card'); 15 export const result=()=>card().querySelector('pre').textContent; 16 export const description=()=>card().querySelector('[role=status]').textContent; 17 export async function inspect(name,format='auto'){ 18 const title=card().querySelector('.definition-card-controls strong'); 19 if(card().hidden||title.textContent!==name||description().startsWith('Runtime stopped.')){ 20 let button=document.querySelector(`[aria-label="Inspect compiled definition ${name}"]`) 21 ??[...el('package-definition-list').querySelectorAll('button')].find(button=>button.textContent===name); 22 if(!button&&!sourceEditor.dom.hidden&&sourceEditor.revealDefinition(name)){await wait(()=>document.querySelector(`[aria-label="Inspect compiled definition ${name}"]`),'visible definition '+name);button=document.querySelector(`[aria-label="Inspect compiled definition ${name}"]`);} 23 if(!button)throw Error('Missing real definition '+name);button.click();await pause(0); 24 } 25 await wait(()=>!card().hidden&&!card().querySelector('select').disabled,'inspect '+name); 26 const select=card().querySelector('select'); 27 if(select.value!==format){select.value=format;select.dispatchEvent(new Event('change'));await pause(0);await wait(()=>!select.disabled,'interpret '+name);} 28 return result(); 29 } 30 export async function evaluateSource(expression,format='number'){ 31 const direct=/^[A-Za-z_][\w?]*$/.test(expression) && (document.querySelector(`[aria-label="Inspect compiled definition ${expression}"]`) 32 ??[...el('package-definition-list').querySelectorAll('button')].find(button=>button.textContent===expression)); 33 if(/^[A-Za-z_][\w?]*$/.test(expression)&&direct)return inspect(expression,format); 34 if(el('source-editor').hidden)throw Error('Test must import source-free functions explicitly, not synthesize an evaluator'); 35 const source=sourceEditor.getSource().replace(/\n-- browser probe binding\nprobeResult =[\s\S]*$/,''); 36 input('source-editor',source+'\n-- browser probe binding\nprobeResult = (\n'+expression.split('\n').map(line=>' '+line).join('\n')+'\n)'); 37 await status('Compiled');return inspect('probeResult',format); 38 }