import fs from 'node:fs';import path from 'node:path';import vm from 'node:vm';import {fileURLToPath}from'node:url';
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');const singleMode=process.argv.includes('--single-mode'),scope=process.argv.includes('--core')?'core':'all';let serial=0;const nodes=new Map(),styles=new Map(),messages=[];let reactions=0;
class N{constructor(type){this.type=type;this.id=String(++serial);this.children=[];this.width=100;this.height=100;this.x=0;this.y=0;this.name='';this.fills=[];nodes.set(this.id,this);}appendChild(n){if(n.parent)n.parent.children=n.parent.children.filter(x=>x!==n);n.parent=this;this.children.push(n);}resize(w,h){if(!Number.isFinite(w)||!Number.isFinite(h)||w<=0||h<=0)throw new Error('Invalid resize '+w+' '+h);this.width=w;this.height=h;}setPluginData(){}setExplicitVariableModeForCollection(){}findOne(fn){for(const c of this.children){if(fn(c))return c;const m=c.findOne(fn);if(m)return m;}return null;}addComponentProperty(name,type,value){this.properties||={};const key=name+'#'+this.id;this.properties[key]={type,value};return key;}createInstance(){const copy=(source)=>{const n=new N(source.type);for(const [k,v]of Object.entries(source))if(!['id','children','parent'].includes(k))n[k]=structuredClone(v);for(const c of source.children)n.appendChild(copy(c));return n;};const n=copy(this);n.type='INSTANCE';return n;}setProperties(props){for(const [key,v]of Object.entries(props)){const label=this.findOne(n=>n.componentPropertyReferences?.characters===key);if(!label)throw new Error('Unbound label property '+key);label.characters=v;}}async setTextStyleIdAsync(id){if(!styles.has(id))throw new Error('Unknown text style');}async setReactionsAsync(r){const page=n=>{while(n&&n.type!=='PAGE')n=n.parent;return n;};for(const x of r)for(const a of x.actions||[]){const target=nodes.get(a.destinationId);if(!target)throw new Error('Missing prototype target');if(page(target)!==page(this))throw new Error('Cross-page prototype '+this.name);}reactions+=r.length;}}
const doc=new N('DOCUMENT');const figma={showUI(){},ui:{postMessage(m){messages.push(m)}},variables:{createVariableCollection(name){const v={id:String(++serial),name,defaultModeId:'light',renameMode(){},addMode(){if(singleMode)throw new Error('Limited to 1 mode only');return'dark'}};return v;},createVariable(name,col,type){if(typeof col!=='object')throw new Error('Collection object required');return{id:String(++serial),name,type,setValueForMode(){}};},setBoundVariableForPaint(p,k,v){return{...p,boundVariables:{[k]:{type:'VARIABLE_ALIAS',id:v.id}}};}},createPage(){const n=new N('PAGE');doc.appendChild(n);return n;},async setCurrentPageAsync(p){this.currentPage=p;},createFrame(){return new N('FRAME');},createComponent(){return new N('COMPONENT');},createRectangle(){return new N('RECTANGLE');},createEllipse(){return new N('ELLIPSE');},createText(){return new N('TEXT');},createNodeFromSvg(svg){if(!svg.includes('<path'))throw new Error('Invalid SVG');return new N('FRAME');},async loadFontAsync(n){if(!n.family||!n.style)throw new Error('Font malformed');},createTextStyle(){const s={id:String(++serial)};styles.set(s.id,s);return s;},createPaintStyle(){return{id:String(++serial)};},viewport:{scrollAndZoomIntoView(){}},commitUndo(){},notify(){}};
const context={figma,__html__:'',console,setTimeout,clearTimeout};vm.createContext(context);vm.runInContext(fs.readFileSync(path.join(root,'figma-importer/code.js'),'utf8'),context);await figma.ui.onmessage({type:'build',scope});const error=messages.find(x=>x.type==='error');if(error)throw new Error(error.text);const done=messages.find(x=>x.type==='done');if(!done)throw new Error('Importer did not finish');const pages=doc.children.map(p=>({name:p.name,topLevelFrames:p.children.filter(n=>n.type==='FRAME').length,components:p.children.filter(n=>n.type==='COMPONENT').length}));const report={scope,singleMode,verification:'Local Figma API contract simulation; not a live Figma editor import',pages,textStyles:styles.size,prototypeReactions:reactions,completion:done.text,errors:[]};fs.writeFileSync(path.join(root,'qa/importer'+(scope==='core'?'-core':'')+(singleMode?'-single-mode':'')+'-report.json'),JSON.stringify(report,null,2));console.log(JSON.stringify(report,null,2));
