refactor(arch): redesign the code structure
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/* Run only our generated local script in a minimal DOM, with no browser or network.
|
||||
* This checks event handlers and serializes the produced SVG for static inspection.
|
||||
* It is not a replacement for a native browser layout test.
|
||||
*/
|
||||
const fs=require('node:fs'),path=require('node:path'),vm=require('node:vm'),assert=require('node:assert');
|
||||
const rootDir=path.resolve(__dirname,'..');
|
||||
const source=fs.readFileSync(path.join(rootDir,'output/q1/question1_full.html'),'utf8');
|
||||
const script=source.match(/<script>([\s\S]*?)<\/script>/)[1];
|
||||
class Element {
|
||||
constructor(tag) {this.tag=tag;this.attrs={};this.children=[];this.style={};this.events={};this.value='';this.max='3';this.textContent='';}
|
||||
setAttribute(k,v){this.attrs[k]=String(v);}
|
||||
appendChild(x){this.children.push(x);return x;}
|
||||
replaceChildren(...x){this.children=x;this.textContent='';}
|
||||
addEventListener(k,f){this.events[k]=f;}
|
||||
add(o){this.children.push(o);}
|
||||
getBoundingClientRect(){return {width:width};}
|
||||
}
|
||||
const esc=s=>String(s).replace(/&/g,'&').replace(/</g,'<').replace(/"/g,'"');
|
||||
const palette={light:{'--foreground':'#24282e','--border':'#d9dfe5','--viz-series-1':'#146e9a','--viz-series-2':'#c6503a','--viz-series-3':'#198064'},dark:{'--foreground':'#eceff3','--border':'#424a55','--viz-series-1':'#6cc8ed','--viz-series-2':'#ff947d','--viz-series-3':'#64d6ac'}};
|
||||
function serialize(el,theme){
|
||||
if(el.tag==='text')Object.assign(el.attrs,{fill:palette[theme]['--foreground'],'font-size':12,'font-family':'Microsoft YaHei, sans-serif'});
|
||||
const attrs=Object.entries(el.attrs).map(([k,v])=>`${k}="${esc(String(v).replace(/var\(([^)]+)\)/g,(_,n)=>palette[theme][n]||n))}"`).join(' ');
|
||||
return `<${el.tag} ${attrs}>${esc(el.textContent)}${el.children.map(x=>serialize(x,theme)).join('')}</${el.tag}>`;
|
||||
}
|
||||
function text(el){return el.textContent+el.children.map(text).join(' ');}
|
||||
const elements={};
|
||||
for(const key of ['case','step','view','plot','step-label','stats','status','rows'])elements[key]=new Element(key==='plot'?'svg':'div');
|
||||
elements.view.value='region';
|
||||
const root=new Element('div');
|
||||
root.querySelector=s=>{const m=s.match(/data-q1="([^"]+)"/);assert(m&&elements[m[1]],'missing selector '+s);return elements[m[1]];};
|
||||
const document={getElementById:id=>{assert.equal(id,'q1-localization');return root;},createElement:tag=>new Element(tag),createElementNS:(_,tag)=>new Element(tag)};
|
||||
let width=736;
|
||||
vm.runInNewContext(script,{document,Option:function(label,value){this.label=label;this.value=String(value);},ResizeObserver:class{constructor(f){this.f=f;}observe(){}},Number,Math,String,Object,console},{timeout:5000});
|
||||
const output=path.join(rootDir,'output/q1/figures');fs.mkdirSync(output,{recursive:true});
|
||||
let checks=0;
|
||||
for(let i=0;i<elements.case.children.length;i++) {
|
||||
elements.case.value=String(i);elements.case.events.change();
|
||||
for(let n=1;n<=+elements.step.max;n++) {
|
||||
elements.step.value=String(n);elements.step.events.input();
|
||||
assert.equal(elements['step-label'].textContent,`${n} / ${elements.step.max}`);
|
||||
for(const v of ['global','region']) {
|
||||
elements.view.value=v;elements.view.events.change();
|
||||
const svg=serialize(elements.plot,'light');
|
||||
assert(!/NaN|undefined|Infinity/.test(svg));
|
||||
assert(svg.includes('data-axis="x"')&&svg.includes('data-axis="y"'));
|
||||
checks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(const w of [360,736])for(const theme of ['light','dark'])for(const index of [1,elements.case.children.length-1]) {
|
||||
width=w;elements.case.value=String(index);elements.case.events.change();
|
||||
elements.view.value='region';elements.view.events.change();
|
||||
const height=elements.plot.attrs.viewBox.split(' ')[3];
|
||||
const svg=serialize(elements.plot,theme).replace('<svg ',`<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${height}" `);
|
||||
const filename=(index===1?'counterexample':'practice')+`-${w}-${theme}.svg`;
|
||||
fs.writeFileSync(path.join(output,filename),svg,'utf8');
|
||||
}
|
||||
const report={interaction_states_checked:checks,missing_selectors:0,nonfinite_svg_values:0,browser_layout_verified:false,
|
||||
note:'Browser local-file navigation blocked by browser URL policy. Event handlers checked in minimal DOM; SVG statically inspected separately.'};
|
||||
fs.writeFileSync(path.join(rootDir,'output/q1/visualization_checks.json'),JSON.stringify(report,null,2));
|
||||
console.log(report);
|
||||
Reference in New Issue
Block a user