UNPKG

sicua

Version:

A tool for analyzing project structure and dependencies

132 lines (131 loc) 4.55 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeVisitors = void 0; const typescript_1 = __importDefault(require("typescript")); class NodeVisitors { /** * Creates a visitor that collects nodes matching a predicate */ static createCollector(predicate) { return (root) => { const results = []; function visit(node) { if (predicate(node)) { results.push(node); } typescript_1.default.forEachChild(node, visit); } visit(root); return results; }; } /** * Creates a visitor that transforms nodes */ static createTransformer(predicate, transformer) { return (context) => { const visitor = (node) => { if (predicate(node)) { return transformer(node); } return typescript_1.default.visitEachChild(node, visitor, context); }; return (node) => { const result = typescript_1.default.visitNode(node, visitor); return result || node; // Ensure we always return a Node }; }; } /** * Creates a visitor that analyzes dependencies between nodes */ static createDependencyAnalyzer(sourceFile) { const dependencies = new Map(); const visit = (node) => { if (typescript_1.default.isIdentifier(node)) { const symbol = node.text; if (!dependencies.has(symbol)) { dependencies.set(symbol, new Set()); } // Find references in parent nodes let parent = node.parent; while (parent) { if (typescript_1.default.isIdentifier(parent)) { dependencies.get(symbol)?.add(parent.text); } parent = parent.parent; } } typescript_1.default.forEachChild(node, visit); }; return (root) => { visit(root); return dependencies; }; } /** * Creates a visitor that builds a control flow graph */ static createControlFlowAnalyzer(context) { const flows = new Map(); const addControlFlow = (from, to) => { if (!flows.has(from)) { flows.set(from, new Set()); } flows.get(from).add(to); }; const visit = (node) => { if (typescript_1.default.isIfStatement(node)) { addControlFlow(node, node.thenStatement); if (node.elseStatement) { addControlFlow(node, node.elseStatement); } } if (typescript_1.default.isWhileStatement(node) || typescript_1.default.isForStatement(node)) { addControlFlow(node, node.statement); } typescript_1.default.forEachChild(node, visit); }; return (root) => { visit(root); return flows; }; } /** * Helper to add control flow edges */ static addControlFlow(flows, from, to) { if (!flows.has(from)) { flows.set(from, new Set()); } flows.get(from).add(to); } /** * Creates a visitor that analyzes scopes */ static createScopeAnalyzer(context) { const scopes = new Map(); return (root) => { function visit(node) { if (typescript_1.default.isBlock(node) || typescript_1.default.isFunctionLike(node)) { const scope = new Set(); scopes.set(node, scope); // Collect declarations in this scope typescript_1.default.forEachChild(node, (child) => { if (typescript_1.default.isVariableDeclaration(child) && typescript_1.default.isIdentifier(child.name)) { scope.add(child.name.text); } }); } typescript_1.default.forEachChild(node, visit); } visit(root); return scopes; }; } } exports.NodeVisitors = NodeVisitors;