From 0f10499245ec2fab8823f116caf34450b3a7385b Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 10 Oct 2026 04:58:27 +0800 Subject: [PATCH] refactor(javascript): share Babel child traversal --- .../javascript/javascriptSemanticReturns.ts | 14 ++----- .../javascript/javascriptSemanticTraversal.ts | 3 +- src/domain/referenceSourceImportParsing.ts | 42 ++++--------------- 3 files changed, 13 insertions(+), 46 deletions(-) diff --git a/src/domain/javascript/javascriptSemanticReturns.ts b/src/domain/javascript/javascriptSemanticReturns.ts index 95228ea3e..15b698a02 100644 --- a/src/domain/javascript/javascriptSemanticReturns.ts +++ b/src/domain/javascript/javascriptSemanticReturns.ts @@ -26,7 +26,10 @@ import { import { evaluateSemanticExpression } from "./javascriptSemanticValues.js"; import { range } from "./javascriptStaticAnalysisHelpers.js"; import { semanticReturnCoverage } from "./javascriptSemanticCoverage.js"; -import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js"; +import { + childNodes, + traverseJavaScriptAst, +} from "./javascriptSemanticTraversal.js"; interface ReturnExpression { readonly node: t.Node | null; @@ -145,15 +148,6 @@ const directReturnExpressions = (callable: t.Node): ReturnExpression[] => { return output; }; -const childNodes = (node: t.Node): t.Node[] => - (t.VISITOR_KEYS[node.type] ?? []).flatMap((key) => { - const value: unknown = Reflect.get(node, key); - if (t.isNode(value)) return [value]; - return Array.isArray(value) - ? value.filter((item): item is t.Node => t.isNode(item)) - : []; - }); - const callableIdsForBinding = ( binding: JavaScriptSemanticBindingState, state: JavaScriptSemanticAnalysisState, diff --git a/src/domain/javascript/javascriptSemanticTraversal.ts b/src/domain/javascript/javascriptSemanticTraversal.ts index 5eb311ac2..4719ce34d 100644 --- a/src/domain/javascript/javascriptSemanticTraversal.ts +++ b/src/domain/javascript/javascriptSemanticTraversal.ts @@ -50,7 +50,8 @@ interface TraversalFrame { nextIndex: number; } -const childNodes = (node: t.Node): t.Node[] => { +/** Return child Babel nodes in visitor-key order. */ +export const childNodes = (node: t.Node): t.Node[] => { const keys = t.VISITOR_KEYS[node.type]; if (keys === undefined) return []; const children: t.Node[] = []; diff --git a/src/domain/referenceSourceImportParsing.ts b/src/domain/referenceSourceImportParsing.ts index 1abfc6a51..3e0832ee4 100644 --- a/src/domain/referenceSourceImportParsing.ts +++ b/src/domain/referenceSourceImportParsing.ts @@ -6,6 +6,7 @@ import type { Node, StringLiteral, } from "@babel/types"; +import { traverseJavaScriptAst } from "./javascript/javascriptSemanticTraversal.js"; import { isCallExpression, isExportAllDeclaration, @@ -15,7 +16,6 @@ import { isImportDeclaration, isImportExpression, isMemberExpression, - isNode, isStringLiteral, isTSExternalModuleReference, isTSImportEqualsDeclaration, @@ -201,39 +201,6 @@ const isRequireCallee = (callee: Node | null | undefined): boolean => { return false; }; -const collectModuleExpressions = ( - node: unknown, - targets: Array, -): void => { - if (node === null || node === undefined) return; - if (typeof node !== "object") return; - if (Array.isArray(node)) { - for (const item of node) collectModuleExpressions(item, targets); - return; - } - if (!isNode(node)) return; - if (isCallExpression(node) || isImportExpression(node)) { - targets.push(node); - } - for (const value of Object.values(node)) { - if ( - value !== null && - value !== undefined && - typeof value === "object" && - !isSourceLocation(value) - ) { - collectModuleExpressions(value, targets); - } - } -}; - -const isSourceLocation = (value: unknown): boolean => - typeof value === "object" && - value !== null && - "start" in value && - "end" in value && - !("type" in value); - const extractRequireAndDynamicImports = ( body: readonly Node[], from_path: string, @@ -241,7 +208,12 @@ const extractRequireAndDynamicImports = ( ): void => { const expressions: Array = []; for (const statement of body) - collectModuleExpressions(statement, expressions); + traverseJavaScriptAst(statement, { + enter: (node) => { + if (isCallExpression(node) || isImportExpression(node)) + expressions.push(node); + }, + }); for (const call of expressions) { if (isImportExpression(call)) {