UNPKG

opnet-transform-web

Version:

OP_NET AssemblyScript transformer

92 lines (91 loc) 3.87 kB
import OPNetTransformer, { SimpleParser, logger } from './OPNetTransformer.js'; import parserTypeScript from 'prettier/parser-typescript'; import prettier from 'prettier/standalone'; import prettierPluginEstree from 'prettier/plugins/estree'; export default class OpnetWebTransformer extends OPNetTransformer { virtualFs = new Map(); readFile(filename, baseDir) { return this.virtualFs.get(`${baseDir}/${filename}`) ?? null; } writeFile(filename, contents, baseDir) { this.virtualFs.set(`${baseDir}/${filename}`, contents.toString()); return; } listFiles(dirname, baseDir) { const files = []; for (const [key] of this.virtualFs.entries()) { if (key.startsWith(`${baseDir}/${dirname}`)) { files.push(key.replace(`${baseDir}/`, '')); } } return files.length > 0 ? files : null; } async afterParse(parser) { // 1) Parse AST for (const source of parser.sources) { if (source.isLibrary || source.internalPath.startsWith('~lib/')) { continue; } for (const stmt of source.statements) { this.visitStatement(stmt); } } // 2) Build ABI per class const abiMap = this.buildAbiPerClass(); // 4) Write one JSON + .d.ts per class for (const [className, abiObj] of abiMap.entries()) { if (abiObj.functions.length === 0) continue; // JSON const filePath = `abis/${className}.abi.json`; this.writeFile(filePath, JSON.stringify(abiObj, null, 4), '.'); logger.success(`ABI generated to ${filePath}`); // DTS const dtsPath = `abis/${className}.d.ts`; const dtsContents = this.buildDtsForClass(className, abiObj); const formattedDts = await prettier.format(dtsContents, { plugins: [parserTypeScript, prettierPluginEstree], parser: 'typescript', printWidth: 100, trailingComma: 'all', tabWidth: 4, semi: true, singleQuote: true, quoteProps: 'as-needed', bracketSpacing: true, bracketSameLine: true, arrowParens: 'always', singleAttributePerLine: true, }); this.writeFile(dtsPath, formattedDts, '.'); logger.success(`Type definitions generated to ${dtsPath}`); } // 5) Inject/overwrite `execute` in each relevant class for (const [className, methods] of this.methodsByClass.entries()) { if (!methods.length) continue; logger.info(`Injecting 'execute' in class ${className}...`); const classDecl = this.classDeclarations.get(className); if (!classDecl) { logger.warn(`ClassDeclaration not found for ${className}`); continue; } const methodText = this.buildExecuteMethod(className, methods); const newMember = SimpleParser.parseClassMember(methodText, classDecl); // Overwrite if it exists const existingIndex = classDecl.members.findIndex((member) => { return (member.kind === 58 /* NodeKind.MethodDeclaration */ && member.name.text === 'execute'); }); if (existingIndex !== -1) { logger.info(`Overwriting existing 'execute' in class ${className}`); classDecl.members[existingIndex] = newMember; } else { classDecl.members.push(newMember); } } // 6) Check for "unused" events and log warnings this.checkUnusedEvents(); } }