diff --git a/ts2panda/src/base/util.ts b/ts2panda/src/base/util.ts index 2453424609fe347aa7ef928b26c18ecd710bbb7c..62dc971fd1440313cdd2f70d33e1f6834d3f7489 100644 --- a/ts2panda/src/base/util.ts +++ b/ts2panda/src/base/util.ts @@ -420,4 +420,83 @@ export function getRecordName(node: ts.SourceFile): string { export function getLiteralKey(node: ts.SourceFile, idx:number): string { return `${getRecordName(node)}_${idx}`; -} \ No newline at end of file +} + +let generatedVarId = 0; +let nodeIdNameMap = new Map(); + +function generateUniqueName(): string { + if (generatedVarId < 26) { // #a ~ #z + // @ts-ignore + return "#" + String.fromCharCode(97 /* a */ + generatedVarId); + } + // @ts-ignore + return "#" + (generatedVarId - 26); +} + +/** + * Gets the node from which a name should be generated, from tsc logic + */ +function getNodeForGeneratedName( + // @ts-ignore + name: ts.GeneratedIdentifier) { + const autoGenerateId = name.autoGenerateId; + let node = name as ts.Node; + // @ts-ignore + let original = node.original; + while (original) { + node = original; + + // if "node" is a different generated name (having a different "autoGenerateId"), use it and stop traversing. + if (ts.isIdentifier(node) + // @ts-ignore + && !!(node.autoGenerateFlags! & ts.GeneratedIdentifierFlags.Node) + // @ts-ignore + && node.autoGenerateId !== autoGenerateId) { + break; + } + // @ts-ignore + original = node.original; + } + + // otherwise, return the original node for the source; + return node; +} + +function generateNameCached(node: ts.Node) { + // @ts-ignore + const nodeId = ts.getNodeId(node); + if (nodeIdNameMap.get(nodeId)) { + return nodeIdNameMap.get(nodeId); + } + let generatedName = generateUniqueName(); + nodeIdNameMap.set(nodeId, generatedName); + return generatedName; +} + +export function makeNameForGeneratedNode(node: ts.Node) { + node.forEachChild(childNode => { + switch (childNode.kind) { + case ts.SyntaxKind.Identifier: { + // @ts-ignore + if (ts.isGeneratedIdentifier(childNode) && (childNode).escapedText == "") { + // @ts-ignore + if ((childNode.autoGenerateFlags & ts.GeneratedIdentifierFlags.KindMask) === + // @ts-ignore + ts.GeneratedIdentifierFlags.Node) { + // @ts-ignore + let originalNode = getNodeForGeneratedName(childNode); + // @ts-ignore + (childNode).escapedText = generateNameCached(originalNode); + } else { + // @ts-ignore + (childNode).escapedText = generateUniqueName(); + } + generatedVarId++; + } + break; + } + } + makeNameForGeneratedNode(childNode); + }); +} diff --git a/ts2panda/src/index.ts b/ts2panda/src/index.ts index 41c8d54f0ad35a8cc97f6937bd29ae79afd4279d..d16ef717ae3b0ae8c14e7c29d0e75e7ff1d3ff5c 100644 --- a/ts2panda/src/index.ts +++ b/ts2panda/src/index.ts @@ -34,7 +34,8 @@ import { transformCommonjsModule, getRecordName, getOutputBinName, - terminateWritePipe + terminateWritePipe, + makeNameForGeneratedNode } from "./base/util"; function checkIsGlobalDeclaration(sourceFile: ts.SourceFile) { @@ -135,7 +136,7 @@ function main(fileNames: string[], options: ts.CompilerOptions, cmdArgsSet?: Map return node; } } - makeAutoGeneratedNodeName(node); + makeNameForGeneratedNode(node); if (ts.getEmitHelpers(node)) { let newStatements = []; ts.getEmitHelpers(node)?.forEach( @@ -227,29 +228,7 @@ function transformSourcefilesList(parsed: ts.ParsedCommandLine | undefined) { main(files, parsed.options, cmdArgsSet); } -let generatedVarId = 0; -function makeAutoGeneratedNodeName(node: ts.Node) { - node.forEachChild(childNode => { - switch (childNode.kind) { - case ts.SyntaxKind.Identifier: { - // @ts-ignore - if (ts.isGeneratedIdentifier(childNode) && (childNode).escapedText == "") { - if (generatedVarId < 26) { // #a ~ #z - // @ts-ignore - (childNode).escapedText = "#" + String.fromCharCode(97 /* a */ + generatedVarId); - } else { - // @ts-ignore - (childNode).escapedText = "#" + (generatedVarId - 26); - } - generatedVarId++; - } - break; - } - } - makeAutoGeneratedNodeName(childNode); - }); -} function getDtsFiles(libDir: string): string[] { let dtsFiles:string[] = []; @@ -411,7 +390,7 @@ function compileWatchExpression(jsFileName: string, errorMsgFileName: string, op // @ts-ignore (ctx: ts.TransformationContext) => { return (node: ts.SourceFile) => { - makeAutoGeneratedNodeName(node); + makeNameForGeneratedNode(node); if (ts.getEmitHelpers(node)) { let newStatements = []; ts.getEmitHelpers(node)?.forEach(