UNPKG

@vibe-dev-kit/cli

Version:

Advanced Command-line toolkit that analyzes your codebase and deploys project-aware rules, memories, commands and agents to any AI coding assistant - VDK is the world's first Vibe Development Kit

258 lines (229 loc) 7.67 kB
/** * javascript.js * * Analyzer for JavaScript code to detect naming conventions, * patterns, and commonly used libraries or frameworks. */ import * as acorn from 'acorn'; /** * Analyzes JavaScript code to detect naming conventions and patterns * @param {string} content - JavaScript code content * @param {string} filePath - Path to the file * @returns {Object} Analysis results */ export async function analyzeJavaScript(content, filePath) { const analysis = { variables: [], functions: [], classes: [], components: [], patterns: [], }; try { // Parse the JavaScript file to AST const ast = acorn.parse(content, { ecmaVersion: 'latest', sourceType: 'module', locations: true, }); // Visit each node in the AST visitNodes(ast, { VariableDeclarator(node) { if (node.id && node.id.name) { analysis.variables.push(node.id.name); } // Detect React components (capital-named variables with JSX) if ( node.id && node.id.name && node.id.name[0] === node.id.name[0].toUpperCase() && node.init && (isReactFunctionComponent(node.init) || isReactClassComponent(node)) ) { analysis.components.push(node.id.name); analysis.patterns.push('React Component'); } }, FunctionDeclaration(node) { if (node.id && node.id.name) { analysis.functions.push(node.id.name); // Detect React components (capital-named functions) if (node.id.name[0] === node.id.name[0].toUpperCase() && isReactFunctionComponent(node)) { analysis.components.push(node.id.name); analysis.patterns.push('React Component'); } } }, ClassDeclaration(node) { if (node.id && node.id.name) { analysis.classes.push(node.id.name); // Detect React class components if (isReactClassComponent(node)) { analysis.components.push(node.id.name); analysis.patterns.push('React Class Component'); } } }, ImportDeclaration(node) { // Detect import patterns if (node.source && node.source.value) { const importPath = node.source.value; // Check for common libraries/frameworks if (importPath === 'react') { analysis.patterns.push('React'); } else if (importPath === 'react-dom') { analysis.patterns.push('React DOM'); } else if (importPath === 'react-router' || importPath === 'react-router-dom') { analysis.patterns.push('React Router'); } else if (importPath === 'redux' || importPath === '@reduxjs/toolkit') { analysis.patterns.push('Redux'); } else if (importPath.startsWith('next')) { analysis.patterns.push('Next.js'); } else if (importPath.startsWith('@nestjs')) { analysis.patterns.push('NestJS'); } else if (importPath === 'express') { analysis.patterns.push('Express'); } else if (importPath.startsWith('@angular')) { analysis.patterns.push('Angular'); } else if (importPath === 'vue') { analysis.patterns.push('Vue.js'); } } }, ObjectExpression(node) { // Detect use of object methods and property types let objectMethodCount = 0; let objectPropertyCount = 0; for (const prop of node.properties) { if (prop.type === 'Property') { objectPropertyCount++; } else if ( prop.type === 'ObjectMethod' || (prop.value && prop.value.type === 'FunctionExpression') ) { objectMethodCount++; } } // If object has several methods, it might be a module pattern if (objectMethodCount > 3 && objectPropertyCount > 0) { analysis.patterns.push('Module Pattern'); } }, ArrowFunctionExpression(node) { // Look for higher-order functions and functional patterns if (node.body && node.body.type === 'ArrowFunctionExpression') { analysis.patterns.push('Higher-order Function'); } // Detect React components (JSX returns) if (isReactFunctionComponent(node)) { analysis.patterns.push('Arrow Function Component'); } }, }); // Deduplicate patterns analysis.patterns = [...new Set(analysis.patterns)]; // Deduplicate names analysis.variables = [...new Set(analysis.variables)]; analysis.functions = [...new Set(analysis.functions)]; analysis.classes = [...new Set(analysis.classes)]; analysis.components = [...new Set(analysis.components)]; return analysis; } catch (error) { // If there's a parsing error, return an empty analysis console.error(`Error analyzing JavaScript file: ${filePath}`); console.error(error.message); return analysis; } } /** * Visits each node in the Abstract Syntax Tree * @param {Object} ast - The AST to visit * @param {Object} visitors - Object with visitor functions */ function visitNodes(ast, visitors) { function visit(node) { if (!node) return; // Call appropriate visitor if exists if (node.type && visitors[node.type]) { visitors[node.type](node); } // Recursively visit children for (const key in node) { if (node[key] && typeof node[key] === 'object') { if (Array.isArray(node[key])) { node[key].forEach((child) => { if (child && typeof child === 'object') { visit(child); } }); } else { visit(node[key]); } } } } visit(ast); } /** * Checks if a node is likely a React function component * @param {Object} node - AST node to check * @returns {boolean} True if likely a React component */ function isReactFunctionComponent(node) { return isJSXReturningFunction(node); } /** * Checks if a node is likely a React class component * @param {Object} node - AST node to check * @returns {boolean} True if likely a React class component */ function isReactClassComponent(node) { // Check for class extends React.Component or Component if (node.superClass) { if (node.superClass.name === 'Component') { return true; } if ( node.superClass.object && node.superClass.object.name === 'React' && node.superClass.property && node.superClass.property.name === 'Component' ) { return true; } } // Or check for render() method that returns JSX if (node.body && node.body.body) { const renderMethod = node.body.body.find( (n) => n.type === 'MethodDefinition' && n.key && n.key.name === 'render' ); if (renderMethod) { return true; } } return false; } /** * Checks if a function returns JSX * @param {Object} node - AST node to check * @returns {boolean} True if the function returns JSX */ function isJSXReturningFunction(node) { if (!node) return false; // Check if return statement contains JSX if (node.body) { if (node.body.type === 'JSXElement' || node.body.type === 'JSXFragment') { return true; } if (node.body.body) { const returnStatement = node.body.body.find((n) => n.type === 'ReturnStatement'); if (returnStatement && returnStatement.argument) { return ( returnStatement.argument.type === 'JSXElement' || returnStatement.argument.type === 'JSXFragment' ); } } } return false; }