UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

217 lines (211 loc) 8.47 kB
/** * @file Core AST manipulation utilities for JavaScript code analysis * @description Single responsibility: Provide fundamental AST operations across AgentSqripts analyzers * * This utility module provides essential Abstract Syntax Tree (AST) operations including * robust parsing, node traversal, function extraction, and type checking. It serves as * the foundation for all AST-based analysis in the platform, handling JavaScript parsing * complexity while providing a simple, consistent interface. * * Design rationale: * - Acorn parser provides fast, standards-compliant JavaScript parsing * - Graceful error handling enables analysis to continue with partial results * - Simple traversal utilities abstract away AST complexity * - Type-safe node operations prevent runtime errors in analyzers */ const acorn = require('acorn'); const walk = require('acorn-walk'); /** * Parse JavaScript content into AST with comprehensive error handling * * Technical function: Converts JavaScript source code into traversable AST structure * * Implementation rationale: * - Latest ECMAScript version support enables modern JavaScript analysis * - Module source type handles both ES6 modules and CommonJS patterns * - allowReturnOutsideFunction accommodates real-world code variations * - Silent error handling prevents analysis pipeline failures * * Parser configuration strategy: * - ecmaVersion: 'latest' supports newest JavaScript features * - sourceType: 'module' handles import/export statements * - allowReturnOutsideFunction: Tolerates non-strict code patterns * - Options spread enables specialized parser configuration * * Error handling approach: * - Null return enables graceful degradation in analyzers * - Silent errors prevent console noise during batch analysis * - Partial analysis possible when some files fail to parse * - Error patterns indicate syntax issues without breaking workflow * * AST parsing challenges: * - Syntax errors in real-world codebases * - Mixed module systems (ES6 + CommonJS) * - Non-standard JavaScript extensions (JSX, TypeScript) * - Dynamic code generation and eval patterns * * Performance considerations: * - Acorn is optimized for parsing speed over error recovery * - Single-pass parsing suitable for static analysis workflows * - Memory usage scales linearly with source code size * - Consider streaming parsers for extremely large files * * @param {string} content - JavaScript source code to parse into AST * @param {Object} options - Additional parser options to override defaults * @returns {Object|null} Parsed AST object, or null if parsing fails * @example * const ast = parseAST('function hello() { return "world"; }'); * if (ast) { * // Process AST successfully * } else { * // Handle parsing failure gracefully * } */ function parseAST(content, options = {}) { try { return acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'module', allowReturnOutsideFunction: true, ...options }); } catch (error) { // Silently handle parse errors return null; } } /** * Collect all AST nodes of specific type with efficient traversal * * Technical function: Type-specific node collection using optimized AST walker * * Implementation rationale: * - acorn-walk provides efficient tree traversal without manual recursion * - Dynamic property access enables type-based node filtering * - Array accumulation maintains discovery order for analysis * - Simple interface abstracts traversal complexity from analyzers * * Traversal optimization: * - walk.simple() optimized for single-purpose node collection * - No unnecessary node visits for uninteresting types * - Early termination possible with custom walker extensions * - Memory-efficient accumulation without intermediate structures * * Node type applications: * - Variable declarations: Identify data flow patterns * - Function calls: Map dependency relationships * - Import statements: Analyze module dependencies * - Loop constructs: Detect performance patterns * * Collection strategy: * - Dynamic object key enables runtime type specification * - Array push maintains temporal order of node discovery * - Shallow copy of nodes enables safe post-processing * - No filtering applied - pure collection for flexibility * * @param {Object} ast - Root AST node to traverse for node collection * @param {string} nodeType - AST node type to collect (e.g., 'FunctionDeclaration') * @returns {Array<Object>} Array of collected AST nodes of specified type * @example * const functions = collectNodes(ast, 'FunctionDeclaration'); * const loops = collectNodes(ast, 'ForStatement'); * const imports = collectNodes(ast, 'ImportDeclaration'); */ function collectNodes(ast, nodeType) { const nodes = []; walk.simple(ast, { [nodeType]: (node) => nodes.push(node) }); return nodes; } /** * Extract all function definitions with comprehensive function type support * * Technical function: Specialized function node collection covering all JavaScript function forms * * Implementation rationale: * - Multiple function types require comprehensive collection strategy * - Single traversal more efficient than multiple type-specific calls * - Function analysis foundational for complexity and dependency analysis * - Unified collection simplifies function-based analysis workflows * * Function type coverage: * - FunctionDeclaration: Traditional named functions * - FunctionExpression: Anonymous and named function expressions * - ArrowFunctionExpression: ES6 arrow functions * - Method definitions and class methods handled by broader analysis * * Function analysis applications: * - Cyclomatic complexity calculation * - Function size and parameter analysis * - Call graph construction for dependency mapping * - Performance hotspot identification * * Collection completeness: * - Covers all standard JavaScript function forms * - Handles nested functions and closures * - Maintains function hierarchy through AST structure * - Enables both flat and hierarchical function analysis * * @param {Object} ast - Root AST node to extract functions from * @returns {Array<Object>} Array of all function nodes found in AST * @example * const functions = extractFunctions(ast); * functions.forEach(fn => { * console.log(`Function: ${fn.id?.name || 'anonymous'}`); * console.log(`Parameters: ${fn.params.length}`); * }); */ function extractFunctions(ast) { const functions = []; walk.simple(ast, { FunctionDeclaration: (node) => functions.push(node), FunctionExpression: (node) => functions.push(node), ArrowFunctionExpression: (node) => functions.push(node) }); return functions; } /** * Type-safe AST node checking with multiple type support * * Technical function: Robust node type validation with flexible input handling * * Implementation rationale: * - Null-safe checking prevents runtime errors on malformed ASTs * - Multiple type support enables flexible node classification * - Array normalization provides consistent interface * - Type checking foundational for safe AST analysis * * Type checking strategy: * - Single type passed as string for simple checks * - Multiple types passed as array for union type checking * - Array.includes() provides O(n) lookup sufficient for small type sets * - Null checking prevents errors on undefined/null nodes * * Node type safety: * - Prevents accessing properties on undefined nodes * - Enables confident type-based property access * - Supports conditional processing based on node types * - Foundational for building type-safe AST analyzers * * @param {Object} node - AST node to check type of (may be null/undefined) * @param {string|Array<string>} types - Single type or array of types to check against * @returns {boolean} True if node exists and matches any of the specified types * @example * if (isNodeType(node, 'FunctionDeclaration')) { * // Safe to access function-specific properties * } * if (isNodeType(node, ['CallExpression', 'NewExpression'])) { * // Handle both call types * } */ function isNodeType(node, types) { const typeArray = Array.isArray(types) ? types : [types]; return node && typeArray.includes(node.type); } module.exports = { parseAST, collectNodes, extractFunctions, isNodeType };