userpravah
Version:
UserPravah is an extensible, framework-agnostic tool for analyzing user flows and navigation patterns in web applications. It supports multiple frameworks (Angular, React) and output formats (DOT/Graphviz, JSON) with a plugin-based architecture for easy e
135 lines (133 loc) ⢠5.55 kB
JavaScript
import * as path from 'path';
import { MainAnalyzer } from './main-analyzer.js';
import { AngularAdapter } from './analyzers/angular/angular-adapter.js';
import { DotOutputFormatter } from './formatters/dot-formatter.js';
import { BasicPatternCollector } from './core/pattern-collector.interface.js';
function parseArgs(args) {
const cliArgs = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
switch (arg) {
case '-p':
case '--project':
cliArgs.projectPath = args[++i];
break;
case '-f':
case '--framework':
cliArgs.framework = args[++i];
break;
case '-o':
case '--format':
cliArgs.format = args[++i];
break;
case '-d':
case '--dir':
cliArgs.outputDir = args[++i];
break;
case '--show-patterns':
cliArgs.showPatterns = true;
break;
case '-h':
case '--help':
cliArgs.help = true;
break;
}
}
return cliArgs;
}
function printHelp() {
console.log(`
Usage: angular-flow-analyzer [options]
Options:
-p, --project <path> Path to the Angular project (required)
-f, --framework <name> Framework to analyze (default: "angular")
-o, --format <type> Output format (default: "dot")
-d, --dir <path> Output directory (default: ".")
--show-patterns Display discovered coding patterns after analysis
-h, --help Show this help message
`);
}
async function run() {
const rawArgs = process.argv.slice(2);
const args = parseArgs(rawArgs);
if (args.help || rawArgs.length === 0) {
printHelp();
process.exit(0);
}
const projectPath = args.projectPath;
if (!projectPath) {
console.error('ā Error: Project path (-p, --project) is required.');
printHelp();
process.exit(1);
}
const frameworkName = args.framework || 'angular';
const outputFormat = args.format || 'dot';
const outputDirectory = args.outputDir || '.'; // Default to current directory
console.log(`š ļø Analyzer starting with options:`);
console.log(` Project Path: ${path.resolve(projectPath)}`);
console.log(` Framework: ${frameworkName}`);
console.log(` Output Format: ${outputFormat}`);
console.log(` Output Directory: ${path.resolve(outputDirectory)}`);
if (args.showPatterns)
console.log(` Show Patterns: true`);
try {
// Instantiate the pattern collector (can be shared)
const patternCollector = new BasicPatternCollector();
// Instantiate adapters and formatters
// The AngularAdapter constructor now takes projectPath and an optional patternCollector
const angularAdapter = new AngularAdapter(path.resolve(projectPath), patternCollector);
// Add other adapters here as they are developed, e.g.:
// const reactAdapter = new ReactAdapter(path.resolve(projectPath), patternCollector);
const dotFormatter = new DotOutputFormatter();
// Add other formatters here:
// const jsonFormatter = new JsonOutputFormatter();
const mainAnalyzer = new MainAnalyzer([angularAdapter], // Pass all available adapters
[dotFormatter], // Pass all available formatters
patternCollector // Pass the central pattern collector
);
await mainAnalyzer.analyzeAndGenerateOutput(path.resolve(projectPath), frameworkName, outputFormat, path.resolve(outputDirectory));
if (args.showPatterns) {
console.log("\nš Discovered Coding Patterns:");
const allPatterns = mainAnalyzer.getCollectedPatterns();
if (allPatterns.length === 0) {
console.log(" No specific patterns were collected during this analysis.");
}
else {
// Group patterns by type for better readability
const patternsByType = {};
allPatterns.forEach(p => {
if (!patternsByType[p.type])
patternsByType[p.type] = [];
patternsByType[p.type].push(p);
});
for (const type in patternsByType) {
console.log(`
Type: ${type} (${patternsByType[type].length} occurrences)`);
patternsByType[type].forEach(pattern => {
let detailsString = JSON.stringify(pattern.details);
if (detailsString && detailsString.length > 100) {
detailsString = detailsString.substring(0, 97) + '...';
}
console.log(` - File: ${pattern.file}${pattern.lineNumber ? ':' + pattern.lineNumber : ''}`);
if (pattern.details)
console.log(` Details: ${detailsString}`);
});
}
}
}
}
catch (error) {
console.error('\nā Fatal Error during analysis execution:');
if (error.stack) {
console.error(error.stack);
}
else {
console.error(error);
}
process.exit(1);
}
}
// Remove the old AngularFlowAnalyzer class definition and its direct execution
// The run() function will be the new entry point.
run();