basic-examples-probe.mjs (6219B)
1 import {evaluateSource,inspect} from './source-probe-helpers.mjs'; 2 const el=id=>document.getElementById(id),delay=ms=>new Promise(r=>setTimeout(r,ms)); 3 const assert=(ok,message)=>{if(!ok)throw Error(message);}; 4 const input=(id,value)=>{if(id==='source-editor'){globalThis.__sourceEditor.replaceSource(value,true);return;}el(id).value=value;el(id).dispatchEvent(new Event('input'));}; 5 const change=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('change'));}; 6 async function status(want){for(let i=0;i<4500;i++){if(el('status').textContent===want)return;await delay(20);}throw Error(want+': '+el('status').textContent+' / '+el('compile-diagnostic').textContent+' / '+el('operation-diagnostic').textContent);} 7 export async function run(control,backend='haskell-wasm'){ 8 await status('Ready'); 9 const groups=[...el('program-picker').querySelectorAll('optgroup')]; 10 assert(groups.map(g=>g.label).join('|')==='Basic Examples|Practical Examples|Language & Runtime Explorations','Purposeful selector groups'); 11 const basics=['names-values','arithmetic','functions','lists','transform-list','choices']; 12 assert([...groups[0].children].map(o=>o.value).join('|')===basics.map(n=>'demo:'+n).join('|'),'Basic progression'); 13 assert(groups[2].firstElementChild.value==='demo:language-reference','Reference leads explorations'); 14 assert(![...el('program-picker').options].some(o=>o.value==='demo:intro'||o.value==='package:intro'),'Start Here retired from selector'); 15 assert(el('program-picker').value==='demo:names-values'&&!el('expression-editor'),'Beginner arrival is source-first'); 16 assert(document.querySelector('.definition-card').hidden,'Arrival waits for explicit inspection'); 17 const base=new URL('../',document.querySelector('script[type=module][src]').src); 18 const releases=(await(await fetch(new URL('packages.json',base))).json()).releases; 19 assert(![...el('program-picker').options].some(o=>o.value.startsWith('package:')),'Libraries are discovered in the explorer, not a giant selector list'); 20 assert(el('add-import').textContent==='Explore libraries…','Prominent library explorer'); 21 const select=async name=>{change('program-picker','demo:'+name);await status('Ready');}; 22 const evaluate=async(expression,output,expected)=>assert(await evaluateSource(expression,output)===expected,expression+' expected '+expected); 23 const defaults=[['greeting','string','Hello, world!'],['total','number','12'],['sixDoubled','number','12'],['itemCount','number','3'],['total','number','24'],['emptyBasket','string','Your basket is empty.']]; 24 for(let i=0;i<basics.length;i++){ 25 await select(basics[i]);const original=globalThis.__sourceEditor.getSource(); 26 assert(await inspect(...defaults[i].slice(0,2))===defaults[i][2],'Published lesson result '+basics[i]); 27 if(i===0)assert(await inspect('greetAndAnswer','values')==='["Hello, world!" 42]','Intro list is published and inspectable'); 28 if(i===2){assert(await inspect('nineDoubled','number')==='18','Second function call');assert(await inspect('area','number')==='28','Two-parameter function');} 29 if(i===4){assert(await inspect('doubled','values')==='[4 8 12]','Mapped list');assert(await inspect('numbers','values')==='[2 4 6]','Original list preserved');} 30 if(i===5){assert(await inspect('oneItem','string')==='You have one item.','Specific match');assert(await inspect('fullBasket','string')==='You have several items.','Fallback match');} 31 if(!el('restore-source').hidden){el('restore-source').click();await status('Ready');} 32 if(i===0){input('source-editor',original.replace('answer = 42','answer = 7'));await status('Compiled');await evaluate('answer','number','7');} 33 if(i===1){input('source-editor',original.replace('add 5 7','add 8 9'));await status('Compiled');await evaluate('total','number','17');} 34 if(i===2){input('source-editor',original.replace('mul number 2','mul number 3').replace(/\bdouble\b/g,'triple'));await status('Compiled');await evaluate('sixDoubled','number','18');await evaluate('nineDoubled','number','27');} 35 if(i===3){input('source-editor',original.replace('numbers = [2 4 6]','numbers = [2 4 6 8]'));await status('Compiled');await evaluate('itemCount','number','4');await evaluate('total','number','20');input('source-editor',original.replace('numbers = [2 4 6]','numbers = []'));await status('Compiled');await evaluate('itemCount','number','0');await evaluate('total','number','0');} 36 if(i===4){input('source-editor',original.replace('mul number 2','mul number 3'));await status('Compiled');await evaluate('total','number','36');} 37 if(i===5){input('source-editor',original.replace('message _ =','message 2 = "You have two items."\nmessage _ ='));await status('Compiled');await evaluate('message 2','string','You have two items.');await evaluate('message 4','string','You have several items.');} 38 el('restore-source').click();await status('Ready');assert(globalThis.__sourceEditor.getSource()===original,'Restore '+basics[i]); 39 } 40 await select('language-reference'); 41 const catalogue=await(await fetch(new URL('catalogue.json',base))).json(); 42 const reference=catalogue.find(d=>d.id==='language-reference'); 43 assert(await inspect('leaf','tricu')==='t','Published reference root without compilation'); 44 await evaluate('describe (t t)','string','true');await evaluate('describe "hi"','string','greeting');await evaluate('firstOr 99 []','number','99'); 45 input('source-editor',reference.source+'\n-- my reference notes');await status('Compiled');await evaluate('sequenced 9','number','9'); 46 // A retired example's immutable publication still loads through its old share link. 47 const old=releases.find(r=>r.name==='intro'&&r.version==='0.2.0'); 48 location.hash=new URLSearchParams({bundle:old.hash,demo:'intro',export:'answer'}).toString();await delay(50);await status('Ready'); 49 assert(el('program-picker').value==='hash','Retired link remains a direct bundle selection');await evaluate('answer','number','42'); 50 await select('names-values'); 51 return {userAgent:navigator.userAgent,checks:['beginner default; grouped selector; library exploration separated from example selection; all six lesson defaults and exercises; restoration; published reference root; editable reference; retained historical link'],backend}; 52 }