UNPKG

@paulohenriquevn/m2js

Version:

Transform TypeScript/JavaScript code into LLM-friendly Markdown summaries + Smart Dead Code Detection + Graph-Deep Diff Analysis. Extract exported functions, classes, and JSDoc comments for better AI context with 60%+ token reduction. Intelligent dead cod

400 lines 13.3 kB
"use strict"; /** * Usage Pattern Analyzer for M2JS * Extracts usage examples and patterns from code */ 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; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.analyzeUsagePatterns = analyzeUsagePatterns; /* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ const parser_1 = require("@babel/parser"); const traverse_1 = __importDefault(require("@babel/traverse")); const t = __importStar(require("@babel/types")); const fs_1 = require("fs"); /** * Analyzes usage patterns from parsed files */ function analyzeUsagePatterns(parsedFiles, projectPath) { const examples = []; const patterns = []; const errorHandling = []; const commonFlows = []; // Analyze each file for usage patterns parsedFiles.forEach(parsedFile => { try { const fileContent = (0, fs_1.readFileSync)(parsedFile.filePath, 'utf8'); const usage = extractUsageFromFile(fileContent, parsedFile); examples.push(...usage.examples); patterns.push(...usage.patterns); errorHandling.push(...usage.errorHandling); commonFlows.push(...usage.flows); } catch (error) { // Skip files that can't be read } }); // Also look for test files const testExamples = extractFromTestFiles(projectPath, parsedFiles); examples.push(...testExamples); return { examples: deduplicateExamples(examples).slice(0, 10), patterns: consolidatePatterns(patterns).slice(0, 8), errorHandling: deduplicateStrings(errorHandling).slice(0, 5), commonFlows: deduplicateStrings(commonFlows).slice(0, 5), }; } /** * Extracts usage patterns from a single file */ function extractUsageFromFile(content, parsedFile) { const examples = []; const patterns = []; const errorHandling = []; const flows = []; try { const ast = (0, parser_1.parse)(content, { sourceType: 'module', plugins: ['typescript', 'jsx', 'decorators-legacy'], }); (0, traverse_1.default)(ast, { // Extract function calls as usage examples CallExpression(nodePath) { const callee = nodePath.node.callee; if (t.isIdentifier(callee)) { const functionName = callee.name; // Check if this function is exported from our parsed files const isOurFunction = parsedFile.functions.some(f => f.name === functionName); if (isOurFunction) { const example = generateUsageExample(nodePath, functionName); if (example) { examples.push(example); } } } // Check for method calls on our classes if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) { const methodName = callee.property.name; const objectName = t.isIdentifier(callee.object) ? callee.object.name : ''; const isOurMethod = parsedFile.classes.some(cls => cls.methods.some(method => method.name === methodName)); if (isOurMethod) { const example = generateMethodUsageExample(nodePath, objectName, methodName); if (example) { examples.push(example); } } } }, // Extract error handling patterns TryStatement(nodePath) { const errorPattern = extractErrorHandlingPattern(nodePath); if (errorPattern) { errorHandling.push(errorPattern); } }, // Extract common patterns like validation flows IfStatement(nodePath) { const pattern = extractValidationPattern(nodePath); if (pattern) { patterns.push(pattern); } }, // Extract workflow patterns from sequential function calls ExpressionStatement(nodePath) { const flow = extractWorkflowPattern(nodePath); if (flow) { flows.push(flow); } }, }); } catch (error) { // Skip files with parsing errors } return { examples, patterns, errorHandling, flows }; } /** * Generates usage example from function call */ function generateUsageExample(nodePath, functionName) { try { const args = nodePath.node.arguments; const code = generateCodeFromNode(nodePath.node); if (!code || code.length > 200) return null; const category = categorizeFunction(functionName); const description = generateExampleDescription(functionName, args); return { function: functionName, example: code, description, category, }; } catch { return null; } } /** * Generates usage example from method call */ function generateMethodUsageExample(nodePath, objectName, methodName) { try { const code = generateCodeFromNode(nodePath.node); if (!code || code.length > 200) return null; const category = categorizeFunction(methodName); const description = `Call ${methodName}() on ${objectName} instance`; return { function: `${objectName}.${methodName}`, example: code, description, category, }; } catch { return null; } } /** * Categorizes function based on name patterns */ function categorizeFunction(name) { const lowerName = name.toLowerCase(); if (lowerName.includes('create') || lowerName.includes('new') || lowerName.includes('build')) { return 'creation'; } if (lowerName.includes('validate') || lowerName.includes('check') || lowerName.includes('verify')) { return 'validation'; } if (lowerName.includes('transform') || lowerName.includes('convert') || lowerName.includes('format')) { return 'transformation'; } if (lowerName.includes('get') || lowerName.includes('find') || lowerName.includes('search') || lowerName.includes('query')) { return 'query'; } return 'business-logic'; } /** * Generates description for usage example */ function generateExampleDescription(functionName, args) { const argCount = args.length; const action = functionName .replace(/([A-Z])/g, ' $1') .toLowerCase() .trim(); if (argCount === 0) { return `Call ${action} with no parameters`; } else if (argCount === 1) { return `Call ${action} with single parameter`; } else { return `Call ${action} with ${argCount} parameters`; } } /** * Extracts error handling patterns */ function extractErrorHandlingPattern(nodePath) { try { const tryBlock = nodePath.node.block; const catchClause = nodePath.node.handler; if (!catchClause) return null; const pattern = `try { /* ${getBlockDescription(tryBlock)} */ } catch (${catchClause.param?.name || 'error'}) { /* ${getBlockDescription(catchClause.body)} */ }`; return pattern.length < 150 ? pattern : null; } catch { return null; } } /** * Extracts validation patterns from if statements */ function extractValidationPattern(nodePath) { try { const test = nodePath.node.test; if (t.isCallExpression(test) && t.isIdentifier(test.callee)) { const functionName = test.callee.name; if (functionName.includes('validate') || functionName.includes('check')) { return { pattern: 'Validation Guard', description: `Check ${functionName}() before proceeding`, frequency: 1, examples: [generateCodeFromNode(nodePath.node)], }; } } return null; } catch { return null; } } /** * Extracts workflow patterns */ function extractWorkflowPattern(nodePath) { try { const expression = nodePath.node.expression; if (t.isAwaitExpression(expression) && t.isCallExpression(expression.argument)) { const call = expression.argument; if (t.isIdentifier(call.callee)) { return `await ${call.callee.name}()`; } } return null; } catch { return null; } } /** * Gets description of a code block */ function getBlockDescription(block) { if (!block || !block.body) return 'code block'; const statementCount = block.body.length; if (statementCount === 0) return 'empty block'; if (statementCount === 1) return 'single statement'; return `${statementCount} statements`; } /** * Generates code string from AST node (simplified) */ function generateCodeFromNode(node) { try { // This is a simplified code generation // In a real implementation, you'd use babel-generator if (t.isCallExpression(node)) { const callee = t.isIdentifier(node.callee) ? node.callee.name : 'function'; const argCount = node.arguments.length; if (argCount === 0) { return `${callee}()`; } else if (argCount === 1) { return `${callee}(param)`; } else { return `${callee}(${Array(argCount).fill('param').join(', ')})`; } } return 'code_example'; } catch { return 'code_example'; } } /** * Extracts examples from test files */ function extractFromTestFiles(_projectPath, _parsedFiles) { const examples = []; // Look for common test file patterns // const testPatterns = [ // '**/*.test.ts', // '**/*.test.js', // '**/*.spec.ts', // '**/*.spec.js', // '**/tests/**/*.ts', // '**/tests/**/*.js' // ]; // This is a simplified implementation // In practice, you'd use a proper glob library to find test files return examples; } /** * Removes duplicate examples */ function deduplicateExamples(examples) { const seen = new Set(); return examples.filter(example => { const key = `${example.function}-${example.example}`; if (seen.has(key)) return false; seen.add(key); return true; }); } /** * Consolidates similar patterns */ function consolidatePatterns(patterns) { const patternMap = new Map(); patterns.forEach(pattern => { const existing = patternMap.get(pattern.pattern); if (existing) { existing.frequency += pattern.frequency; existing.examples.push(...pattern.examples); } else { patternMap.set(pattern.pattern, { ...pattern }); } }); return Array.from(patternMap.values()).sort((a, b) => b.frequency - a.frequency); } /** * Removes duplicate strings */ function deduplicateStrings(strings) { return Array.from(new Set(strings)); } //# sourceMappingURL=usage-pattern-analyzer.js.map