tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

import-picker-probe.mjs (8373B)


      1 const assert=(ok,message)=>{if(!ok)throw Error(message);};
      2 const el=id=>document.getElementById(id),delay=ms=>new Promise(r=>setTimeout(r,ms));
      3 const input=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('input'));};
      4 const change=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('change'));};
      5 async function wait(fn,label){for(let i=0;i<4500;i++){if(fn())return;await delay(20);}throw Error('Timeout '+label+' / '+el('status').textContent+' / '+el('import-status').textContent);}
      6 const status=value=>wait(()=>el('status').textContent===value,value);
      7 export async function run(control,backend='haskell-wasm'){
      8  const base=new URL('../',document.querySelector('script[type=module][src]').src);
      9  const {createRuntimeSession}=(await import(new URL('dist/probe-api.js',base))).runtimeSession;
     10  const catalogue=await(await fetch(new URL('reference/libraries.json',base))).json();
     11  const lib=name=>catalogue.releases.find(r=>r.name==='tricu-lib-'+name&&r.version==='0.1.0');
     12  const math=lib('native-math');
     13  // Static references and independently specified examples can be consumed without
     14  // a page session or a JavaScript module catalogue.
     15  const llms=await(await fetch(new URL('llms.txt',location.href))).text();
     16  assert(llms.includes('reference/getting-started.md'),'Agent entrypoint points into this release');
     17  for(const [,path]of llms.matchAll(/\]\((\.\/[^)]+)\)/g))assert((await fetch(new URL(path,location.href))).ok,'Readable static reference '+path);
     18  const examples=await(await fetch(new URL('reference/examples.json',base))).json();
     19  const host={before:async()=>{},after:()=>{},write:()=>{},read:async()=>'',running:()=>{}};
     20  const session=await createRuntimeSession(backend,true);
     21  try{
     22   for(const example of examples){
     23    let terminal='';await session.compile(example.source,'empty');
     24    const result=await session.runExpression(example.expression,example.output,example.mode,{...host,write:text=>{terminal+=text;}});
     25    assert(result.value===example.expected,'Documented result '+example.id+': '+JSON.stringify(result));
     26    assert(terminal===example.terminal,'Documented terminal '+example.id);
     27   }
     28   await session.compile('!export answer\nanswer = 42','empty');
     29   const stage=await session.inspectModule(`-- 🐕\n!import ${math.manifest} as N\n!export answer\nanswer = 1`);
     30   assert(stage.imports[0][0]===math.manifest&&stage.imports[0][1]==='N','Native header response');
     31   assert((await session.runExpression('answer','number','pure',host)).value==='42','Inspection preserves compiled scope');
     32   let rejected=false;try{await session.inspectModule(`!import ${math.manifest} as\n!export answer\nanswer=1`);}catch{rejected=true;}
     33   assert(rejected,'Malformed header rejected');
     34   assert((await session.runExpression('answer','number','pure',host)).value==='42','Failed inspection preserves compiled scope');
     35  }finally{session.dispose();}
     36  await status('Ready');change('runtime-backend',backend);await status('Ready');
     37  document.querySelector('[data-compiler-example=module]').click();await status('Compiled');
     38  const original='-- preserve this comment 🐕\n!export answer\nanswer = 42';
     39  input('source-editor',original);await status('Compiled');
     40  const open=async()=>{el('add-import').click();await wait(()=>el('import-results').querySelector('button'),'library list');assert(el('import-dialog').open,'Modal open');};
     41  const select=async()=>{input('import-search','remainder');await wait(()=>el('import-results').querySelector(`[data-manifest="${math.manifest}"]`),'search export');el('import-results').querySelector(`[data-manifest="${math.manifest}"]`).click();};
     42  await open();await select();
     43  assert(el('import-title').textContent==='native-math','Search reaches native math');
     44  assert(el('import-preview').textContent===`!import ${math.manifest} as N`,'Exact full manifest preview');
     45  assert(el('import-version').value==='0.1.0','Newest version initially selected');
     46  assert(el('import-version').options.length===2,'History available in details');
     47  assert(el('import-usage').textContent.includes('multiply')&&el('import-example').textContent.includes('Expected result: 42'),'Calling conventions and tested example available inline');
     48  input('import-alias','Numbers');change('import-version','0.0.9');await wait(()=>!el('insert-import').disabled,'historical release check');
     49  assert(el('import-version').value==='0.0.9'&&el('import-preview').textContent.endsWith('as Numbers'),'History preserves chosen namespace');
     50  change('import-version','0.1.0');input('import-alias','N');
     51  await wait(()=>!el('insert-import').disabled,'candidate compiled');
     52  el('insert-import').click();
     53  assert(!el('import-dialog').open,'Insertion closes dialog');
     54  assert(el('source-editor').value===`!import ${math.manifest} as N\n`+original,'Insertion preserves all original source');
     55  assert(el('source-editor').selectionStart===0&&el('source-editor').selectionEnd===(`!import ${math.manifest} as N\n`).length,'Inserted line selected');
     56  await status('Compiled');
     57  input('expression-editor','N.add answer 8');change('output-type','number');el('run').click();await status('Finished');assert(el('result').textContent==='50','Inserted namespace usable');
     58  // Undo is one native textarea edit; compilation does not replace the editor.
     59  el('source-editor').focus();assert(document.execCommand('undo'),'Undo available');
     60  assert(el('source-editor').value===original,'One undo restores exact original source');await status('Compiled');
     61  await open();await select();await wait(()=>!el('insert-import').disabled,'reinsert checked');el('insert-import').click();await status('Compiled');
     62  const inserted=el('source-editor').value;
     63  await open();await select();await wait(()=>!el('insert-import').disabled,'existing import');
     64  assert(el('import-status').textContent.includes('Already imported as N'),'Existing namespace shown');el('insert-import').click();
     65  assert(el('source-editor').value===inserted,'Jump does not edit');
     66  // Alias conflict is based on the native header; a failed check leaves the editor intact.
     67  await open();input('import-search','conversions');el('import-results').querySelector('button').click();input('import-alias','N');
     68  await wait(()=>el('import-status').textContent.includes('already used'),'namespace conflict');assert(el('insert-import').disabled,'Conflict blocks insert');el('import-cancel').click();
     69  assert(el('source-editor').value===inserted,'Cancellation preserves source');
     70  input('source-editor','!export answer\nanswer = (');await status('Compilation failed');
     71  await open();await select();await wait(()=>el('import-status').textContent.includes('copy the import'),'malformed source fallback');assert(el('insert-import').disabled,'Malformed source blocks insertion');el('import-cancel').click();
     72  input('source-editor',original);await status('Compiled');
     73  await open();await select();el('import-cancel').click();await delay(400);assert(!el('import-dialog').open,'Check cancelled');assert(el('source-editor').value===original,'Cancellation is an edit-free operation');
     74  // Local filenames are text and their validated interfaces are searchable.
     75  const bytes=await(await fetch('/_arboricx/bundle/hash/'+math.hash)).arrayBuffer();
     76  const files=new DataTransfer();files.items.add(new File([bytes],'<svg onload=bad>.arboricx'));el('local-module-file').files=files.files;el('local-module-file').dispatchEvent(new Event('change'));
     77  await wait(()=>el('local-module-list').children.length===1&&!el('local-module-file').disabled,'local validation');await status('Compiled');
     78  await open();input('import-search','<svg');assert(!el('import-results').querySelector('svg'),'Filename is text');el('import-results').querySelector('button').click();
     79  assert(el('import-version').hidden,'Local file has no invented version');await wait(()=>!el('insert-import').disabled,'local import check');el('insert-import').click();await status('Compiled');
     80  input('expression-editor','Local.add 5 6');el('run').click();await status('Finished');assert(el('result').textContent==='11','Local library from unified picker');
     81  return {userAgent:navigator.userAgent,checks:['static agent references; complete published interfaces; general documented examples; native read-only header inspection; export search; exact imports; undo; existing import jump; namespace conflicts; malformed source copy fallback; cancellation; local-file discovery'],backend};
     82 }