Repository navigation
Expand file tree
/
Copy pathast.cjs
More file actions
27 lines (27 loc) · 3.28 KB
/
Copy pathast.cjs
File metadata and controls
27 lines (27 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';
const oxc=require('oxc-parser');
const key=n=>n?.type==='Identifier'?n.name:n?.type==='Literal'?n.value:undefined;
const property=(n,k)=>n?.properties?.find(p=>p.type==='Property'&&!p.computed&&key(p.key)===k);
function walk(root,visitor){const pending=[root];while(pending.length){const node=pending.pop();if(!node||typeof node.type!=='string')continue;visitor.enter?.(node);visitor[node.type]?.(node);const keys=oxc.visitorKeys[node.type]||[];for(let k=keys.length-1;k>=0;k--){const child=node[keys[k]];if(Array.isArray(child)){for(let i=child.length-1;i>=0;i--)if(child[i])pending.push(child[i]);}else if(child)pending.push(child);}}}
function parseProgram(source){const result=oxc.parseSync('zcode.cjs',source);if(result.errors.length)throw new Error(result.errors.map(e=>e.message).join('\n'));return result.program;}
function checkSyntax(source){const result=oxc.parseSync('zcode.cjs',source,oxc.rawTransferSupported()?{experimentalLazy:true}:undefined);try{if(result.errors.length)throw new Error(result.errors.map(e=>e.message).join('\n'));}finally{result.dispose?.();}}
function extractFunctions(source,wanted){
const spans=new Map(),labels=new Map();
const declaration=n=>{if(n.type!=='FunctionDeclaration'||!n.id)return;const name=n.id.name;const list=spans.get(name)||[];list.push({start:n.start,end:n.end});spans.set(name,list);};
const call=n=>{const a=n.arguments;if(a.length!==2)return;const arg=a[0],label=a[1];if(!['Identifier','IdentifierReference'].includes(arg.type)||!['Literal','StringLiteral'].includes(label.type)||!wanted.has(label.value))return;const list=labels.get(label.value)||[];list.push(arg.name);labels.set(label.value,list);};
if(oxc.rawTransferSupported()){
const parsed=oxc.parseSync('zcode.cjs',source,{experimentalLazy:true});
try{if(parsed.errors.length)throw new Error(parsed.errors.map(e=>e.message).join('\n'));parsed.visit(new (oxc.experimentalGetLazyVisitor())({Function:declaration,CallExpression:call}));}finally{parsed.dispose();}
}else{walk(parseProgram(source),{FunctionDeclaration:declaration,CallExpression:call});}
const declarations=new Map();
for(const label of wanted){const names=labels.get(label);if(names?.length!==1)throw new Error(`Cannot uniquely resolve ${label}`);const ranges=spans.get(names[0]);if(ranges?.length!==1)throw new Error(`Cannot uniquely resolve declaration ${names[0]}`);const range=ranges[0];const node=parseProgram(source.slice(range.start,range.end)).body[0];walk(node,{enter(n){n.start+=range.start;n.end+=range.start;}});declarations.set(names[0],node);}
return {labels,declarations};
}
function renamedSource(source,mapping){
if(!oxc.rawTransferSupported())throw new Error('Low-memory rename validation requires raw transfer support');
const parsed=oxc.parseSync('zcode.cjs',source,{experimentalLazy:true}),edits=[];
const identifier=n=>{if(mapping.has(n.name))edits.push({start:n.start,end:n.end,text:mapping.get(n.name)});};
try{parsed.visit(new (oxc.experimentalGetLazyVisitor())({IdentifierReference:identifier,BindingIdentifier:identifier}));}finally{parsed.dispose();}
edits.sort((a,b)=>b.start-a.start);let result=source;for(const e of edits)result=result.slice(0,e.start)+e.text+result.slice(e.end);return {source:result,edits:edits.length};
}
module.exports={parseProgram,checkSyntax,walk,key,property,extractFunctions,renamedSource};