code-graph-generator
Version:
Generate Json Object of code that can be used to generate code-graphs for JavaScript/TypeScript/Range projects
241 lines • 8.63 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.toPosixPath = void 0;
exports.getStartLine = getStartLine;
exports.countLines = countLines;
exports.extractFunctionNames = extractFunctionNames;
exports.normalizePath = normalizePath;
exports.getCorrectCasePath = getCorrectCasePath;
exports.lightTraverse = lightTraverse;
exports.buildParentMap = buildParentMap;
exports.lightTraverseWithParents = lightTraverseWithParents;
// // src/utils/ast-utils.ts
/**
* Gets the starting line number of an AST node.
* @param node The AST node
* @returns The line number or 0 if not available
*/
function getStartLine(node) {
if (node?.loc?.start?.line) {
return node.loc.start.line;
}
return 0;
}
/**
* Counts the number of lines in a text.
* @param text The text to count lines in
* @returns The number of lines
*/
function countLines(text) {
if (!text)
return 0;
return text.split('\n').length;
}
/**
* Extracts function names from an AST node.
* @param node The AST node
* @returns Array of function names
*/
function extractFunctionNames(node) {
const names = [];
if (!node)
return names;
// Function declaration
if (node.type === 'FunctionDeclaration' && node.id?.name) {
names.push(node.id.name);
}
// Variable declarations with function expressions
if (node.type === 'VariableDeclaration') {
for (const declaration of node.declarations) {
if (declaration.init) {
if (declaration.init.type === 'FunctionExpression' ||
declaration.init.type === 'ArrowFunctionExpression') {
if (declaration.id?.name) {
names.push(declaration.id.name);
}
}
}
}
}
// Class methods
if (node.type === 'ClassDeclaration' && node.body?.body) {
for (const member of node.body.body) {
if (member.type === 'MethodDefinition' && member.key?.name) {
names.push(member.key.name);
}
}
}
return names;
}
/**
* Normalizes a file path to use forward slashes.
* @param filePath The file path to normalize
* @returns Normalized path with forward slashes
*/
function normalizePath(filePath) {
if (!filePath)
return '';
// Only normalize separators, preserve case
return filePath.replace(/\\/g, '/');
}
async function getCorrectCasePath(basePath, filePath) {
try {
const fs = await Promise.resolve().then(() => __importStar(require('fs/promises')));
const path = await Promise.resolve().then(() => __importStar(require('path')));
const normalizedPath = normalizePath(filePath);
// Try to find the correct case in the parent directory
const dir = path.dirname(path.join(basePath, normalizedPath));
const filename = path.basename(normalizedPath);
// Read the directory
const files = await fs.readdir(dir);
// Find the correct case
const correctName = files.find(f => f.toLowerCase() === filename.toLowerCase());
// If found, return with correct case
if (correctName) {
return normalizePath(path.join(path.dirname(normalizedPath), correctName));
}
// Fall back to the original
return normalizedPath;
}
catch (error) {
// If any error, just return the normalized path
return normalizePath(filePath);
}
}
// Legacy alias for normalizePath for backward compatibility
exports.toPosixPath = normalizePath;
/**
* Traverses an AST and calls visitor functions for specific node types.
* @param node The AST node to traverse
* @param visitors Object mapping node types to visitor functions
* @param visited Optional Set to prevent circular references
*/
function lightTraverse(node, visitors, visited = new Set()) {
if (!node || typeof node !== 'object' || visited.has(node))
return;
// Mark this node as visited to avoid circular references
visited.add(node);
try {
if (node.type && visitors[node.type]) {
visitors[node.type](node);
}
for (const key of Object.keys(node)) {
const child = node[key];
// Skip metadata properties
if (key === 'loc' || key === 'range' || key === 'parent')
continue;
if (Array.isArray(child)) {
for (const item of child) {
lightTraverse(item, visitors, visited);
}
}
else if (child && typeof child === 'object') {
lightTraverse(child, visitors, visited);
}
}
}
catch (error) {
console.error(`Error traversing node of type ${node.type}:`, error);
}
}
/**
* Builds a map of child nodes to their parent nodes.
* @param node The root AST node
* @param parent The parent node (null for root)
* @returns Map of nodes to their parents
*/
function buildParentMap(node, parent = null) {
const parentMap = new Map();
const visited = new Set();
const addParent = (childNode, parentNode) => {
if (!childNode || typeof childNode !== 'object' || visited.has(childNode))
return;
visited.add(childNode);
parentMap.set(childNode, parentNode);
for (const key in childNode) {
if (childNode.hasOwnProperty(key) &&
key !== 'loc' && key !== 'range' && key !== 'parent') {
const grandchild = childNode[key];
if (grandchild && typeof grandchild === 'object') {
if (Array.isArray(grandchild)) {
grandchild.forEach(item => addParent(item, childNode));
}
else {
addParent(grandchild, childNode);
}
}
}
}
};
addParent(node, parent);
return parentMap;
}
/**
* Traverses an AST with parent and grandparent context.
* @param ast The AST to traverse
* @param visitors Object mapping node types to visitor functions
*/
function lightTraverseWithParents(ast, visitors) {
const visited = new Set();
function visit(node, parent = null, grandparent = null) {
if (!node || typeof node !== 'object' || visited.has(node))
return;
visited.add(node);
try {
if (node.type && visitors[node.type]) {
visitors[node.type](node, parent, grandparent);
}
for (const key of Object.keys(node)) {
const child = node[key];
if (key === 'loc' || key === 'range')
continue;
if (Array.isArray(child)) {
for (const item of child) {
visit(item, node, parent);
}
}
else if (child && typeof child === 'object') {
visit(child, node, parent);
}
}
}
catch (error) {
console.error(`Error traversing node of type ${node.type} with parents:`, error);
}
}
visit(ast);
}
//# sourceMappingURL=ast-utils.js.map