From e0c10d42095ab66fc669d22b6e43e8f4a0fb5de5 Mon Sep 17 00:00:00 2001 From: uhyo Date: Tue, 13 Aug 2024 22:07:48 +0900 Subject: [PATCH] refactor: split generate function (#49) * refactor: move interface emission to separate function * refactor: move replacement emission to new function --- build/logic/generate.ts | 212 +++++++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 88 deletions(-) diff --git a/build/logic/generate.ts b/build/logic/generate.ts index ea8d0b1..7a2227f 100644 --- a/build/logic/generate.ts +++ b/build/logic/generate.ts @@ -58,98 +58,22 @@ export function generate( consumedReplacements.add(name); if (!ts.isInterfaceDeclaration(statement)) { - // Find the replacement target of same kind. - const replacementTargetOfSameKind = replacementTarget.flatMap((target) => - target.type === "non-interface" ? [target] : [], + result += generateFullReplacement( + originalFile, + statement, + replacementTarget, + emitOriginalAsComment, ); - if (replacementTargetOfSameKind.length === 0) { - result += statement.getFullText(originalFile); - continue; - } - // Emit replaced statements - result += - replacementTargetOfSameKind - .map(({ statement, sourceFile }) => statement.getFullText(sourceFile)) - .join("") ?? ""; - if (emitOriginalAsComment) { - // Replaced statements are emitted as comments - // to make it easier to detect original lib changes - result += "\n" + commentOut(statement.getFullText(originalFile)) + "\n"; - } - continue; - } - const replaceInterfaces = replacementTarget.flatMap((target) => - target.type === "interface" ? [target] : [], - ); - if ( - replaceInterfaces.some( - (target) => - !isPartialReplacement( - statement, - originalFile, - target.originalStatement, - target.sourceFile, - ), - ) - ) { - // This needs to be a full replacement - for (const target of replaceInterfaces) { - result += target.originalStatement.getFullText(target.sourceFile); - } - if (emitOriginalAsComment) { - result += "\n" + commentOut(statement.getFullText(originalFile)) + "\n"; - } continue; } - const replaceInterfaceMembers = new Map< - string, - { - member: ts.TypeElement; - text: string; - }[] - >(); - for (const target of replacementTarget) { - if (target.type !== "interface") { - continue; - } - for (const [memberName, elements] of target.members) { - upsert(replaceInterfaceMembers, memberName, (members = []) => { - members.push(...elements); - return members; - }); - } - } - const emittedMembers = new Map(); - const memberList = statement.members.flatMap((mem) => { - const nameStr = mem.name?.getText(originalFile) ?? ""; - if (emittedMembers.has(nameStr)) { - emittedMembers.get(nameStr)?.push(mem); - return []; - } - const replacedMembers = replaceInterfaceMembers.get(nameStr); - if (replacedMembers !== undefined) { - emittedMembers.set(nameStr, [mem]); - return replacedMembers; - } - return [ - { - member: mem, - text: mem.getFullText(originalFile), - }, - ]; - }); - result += printInterface(printer, statement, memberList, originalFile); - - if (emitOriginalAsComment) { - result += "\n"; - for (const originalMems of emittedMembers.values()) { - for (const originalMem of originalMems) { - result += commentOut(originalMem.getFullText(originalFile)); - } - } - result += "\n"; - } + result += generateInterface( + printer, + originalFile, + statement, + replacementTarget, + emitOriginalAsComment, + ); } result += originalFile.text.slice(originalFile.endOfFileToken.pos); @@ -172,6 +96,118 @@ export function generate( return result; } +function generateFullReplacement( + originalFile: ts.SourceFile, + statement: ts.Statement, + replacementTarget: readonly ReplacementTarget[], + emitOriginalAsComment: boolean, +) { + // Find the replacement target of same kind. + const replacementTargetOfSameKind = replacementTarget.flatMap((target) => + target.type === "non-interface" ? [target] : [], + ); + if (replacementTargetOfSameKind.length === 0) { + return statement.getFullText(originalFile); + } + // Emit replaced statements + let result = + replacementTargetOfSameKind + .map(({ statement, sourceFile }) => statement.getFullText(sourceFile)) + .join("") ?? ""; + if (emitOriginalAsComment) { + // Replaced statements are emitted as comments + // to make it easier to detect original lib changes + result += "\n" + commentOut(statement.getFullText(originalFile)) + "\n"; + } + return result; +} + +function generateInterface( + printer: ts.Printer, + originalFile: ts.SourceFile, + statement: ts.InterfaceDeclaration, + replacementTarget: readonly ReplacementTarget[], + emitOriginalAsComment: boolean, +) { + const replaceInterfaces = replacementTarget.flatMap((target) => + target.type === "interface" ? [target] : [], + ); + if ( + replaceInterfaces.some( + (target) => + !isPartialReplacement( + statement, + originalFile, + target.originalStatement, + target.sourceFile, + ), + ) + ) { + // This needs to be a full replacement + let result = ""; + for (const target of replaceInterfaces) { + result += target.originalStatement.getFullText(target.sourceFile); + } + if (emitOriginalAsComment) { + result += "\n" + commentOut(statement.getFullText(originalFile)) + "\n"; + } + return result; + } + + const replaceInterfaceMembers = new Map< + string, + { + member: ts.TypeElement; + text: string; + }[] + >(); + for (const target of replacementTarget) { + if (target.type !== "interface") { + continue; + } + for (const [memberName, elements] of target.members) { + upsert(replaceInterfaceMembers, memberName, (members = []) => { + members.push(...elements); + return members; + }); + } + } + const emittedMembers = new Map(); + const memberList = statement.members.flatMap((mem) => { + const nameStr = mem.name?.getText(originalFile) ?? ""; + if (emittedMembers.has(nameStr)) { + emittedMembers.get(nameStr)?.push(mem); + return []; + } + const replacedMembers = replaceInterfaceMembers.get(nameStr); + if (replacedMembers !== undefined) { + emittedMembers.set(nameStr, [mem]); + return replacedMembers; + } + return [ + { + member: mem, + text: mem.getFullText(originalFile), + }, + ]; + }); + + let result = ""; + result += printInterface(printer, statement, memberList, originalFile); + + if (emitOriginalAsComment) { + result += "\n"; + for (const originalMems of emittedMembers.values()) { + for (const originalMem of originalMems) { + result += commentOut(originalMem.getFullText(originalFile)); + } + } + result += "\n"; + } + + return result; +} + type ReplacementTarget = ( | { type: "interface";