agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
101 lines (88 loc) • 3.68 kB
JavaScript
/**
* @file Extract semantic blocks from JavaScript code using AST
* @description Single responsibility: Main orchestrator for AST-based code block extraction
*/
const { parseAST } = require('../../../utils/astHelpers');
const walk = require('acorn-walk');
const createBlockFromNode = require('./createBlockFromNode');
const isReactComponent = require('./isReactComponent');
const extractFallbackBlocks = require('./extractFallbackBlocks');
/**
* Extract semantic blocks from JavaScript code using AST
* @param {string} content - File content
* @param {string} filePath - File path for context
* @returns {Array} Array of semantic code blocks
*/
function extractSemanticBlocks(content, filePath) {
const blocks = [];
try {
// Parse with loose mode to handle various JS patterns
const ast = parseAST(content, {
allowImportExportEverywhere: true,
allowAwaitOutsideFunction: true,
locations: true,
ranges: true
});
// Extract different types of semantic blocks
walk.simple(ast, {
// Regular functions
FunctionDeclaration(node) {
blocks.push(createBlockFromNode(node, content, 'function', filePath));
},
// Arrow functions and function expressions assigned to variables
VariableDeclarator(node) {
if (node.init && (node.init.type === 'FunctionExpression' ||
node.init.type === 'ArrowFunctionExpression')) {
blocks.push(createBlockFromNode(node, content, 'function', filePath));
}
// Object methods pattern: const obj = { method() {} }
else if (node.init && node.init.type === 'ObjectExpression') {
node.init.properties.forEach(prop => {
if (prop.value && (prop.value.type === 'FunctionExpression' ||
prop.value.type === 'ArrowFunctionExpression')) {
blocks.push(createBlockFromNode(prop, content, 'method', filePath));
}
});
}
},
// Class declarations
ClassDeclaration(node) {
blocks.push(createBlockFromNode(node, content, 'class', filePath));
// Extract class methods separately for granular analysis
node.body.body.forEach(method => {
if (method.type === 'MethodDefinition') {
blocks.push(createBlockFromNode(method, content, 'classMethod', filePath));
}
});
},
// Object methods: obj.method = function() {}
AssignmentExpression(node) {
if (node.right && (node.right.type === 'FunctionExpression' ||
node.right.type === 'ArrowFunctionExpression')) {
blocks.push(createBlockFromNode(node, content, 'function', filePath));
}
},
// Export statements with functions
ExportNamedDeclaration(node) {
if (node.declaration) {
if (node.declaration.type === 'FunctionDeclaration') {
blocks.push(createBlockFromNode(node.declaration, content, 'function', filePath));
} else if (node.declaration.type === 'ClassDeclaration') {
blocks.push(createBlockFromNode(node.declaration, content, 'class', filePath));
}
}
},
// React components (functional)
CallExpression(node) {
if (isReactComponent(node)) {
blocks.push(createBlockFromNode(node, content, 'reactComponent', filePath));
}
}
});
} catch (error) {
// If AST parsing fails, fall back to regex-based extraction for specific patterns
blocks.push(...extractFallbackBlocks(content, filePath));
}
return blocks;
}
module.exports = extractSemanticBlocks;