sicua
Version:
A tool for analyzing project structure and dependencies
132 lines (131 loc) • 4.55 kB
JavaScript
;
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;