@merlean/analyzer 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +11 -14
- package/lib/analyzer.js +77 -3
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -51,10 +51,11 @@ function printHelp() {
|
|
|
51
51
|
Merlean Analyzer - AI-powered codebase analysis
|
|
52
52
|
|
|
53
53
|
Usage:
|
|
54
|
+
npx @merlean/analyzer --name <name>
|
|
54
55
|
npx @merlean/analyzer <path> --name <name>
|
|
55
56
|
|
|
56
57
|
Arguments:
|
|
57
|
-
<path> Path to codebase
|
|
58
|
+
<path> Path to codebase (default: current directory)
|
|
58
59
|
|
|
59
60
|
Options:
|
|
60
61
|
--name, -n <name> Site name (required)
|
|
@@ -63,14 +64,14 @@ Options:
|
|
|
63
64
|
--help, -h Show this help
|
|
64
65
|
|
|
65
66
|
Examples:
|
|
66
|
-
# Analyze
|
|
67
|
-
npx @merlean/analyzer
|
|
67
|
+
# Analyze current directory
|
|
68
|
+
npx @merlean/analyzer --name "My App"
|
|
68
69
|
|
|
69
|
-
#
|
|
70
|
-
npx @merlean/analyzer ./my-app --name "My App"
|
|
70
|
+
# Analyze specific path
|
|
71
|
+
npx @merlean/analyzer ./my-app --name "My App"
|
|
71
72
|
|
|
72
|
-
#
|
|
73
|
-
npx @merlean/analyzer
|
|
73
|
+
# Use custom backend (for local dev)
|
|
74
|
+
npx @merlean/analyzer --name "My App" --backend http://localhost:3004
|
|
74
75
|
`);
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -80,18 +81,14 @@ async function main() {
|
|
|
80
81
|
const options = parseArgs();
|
|
81
82
|
|
|
82
83
|
// Validate required args
|
|
83
|
-
if (!options.path) {
|
|
84
|
-
console.error('❌ Error: Path to codebase is required');
|
|
85
|
-
console.log(' Run with --help for usage');
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
84
|
if (!options.name) {
|
|
90
85
|
console.error('❌ Error: --name is required');
|
|
86
|
+
console.log(' Run with --help for usage');
|
|
91
87
|
process.exit(1);
|
|
92
88
|
}
|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
// Default to current directory if no path provided
|
|
91
|
+
const codebasePath = path.resolve(options.path || '.');
|
|
95
92
|
|
|
96
93
|
if (!fs.existsSync(codebasePath)) {
|
|
97
94
|
console.error(`❌ Error: Path does not exist: ${codebasePath}`);
|
package/lib/analyzer.js
CHANGED
|
@@ -67,12 +67,19 @@ async function scanCodebase(codebasePath) {
|
|
|
67
67
|
const content = fs.readFileSync(file, 'utf-8');
|
|
68
68
|
const relativePath = path.relative(codebasePath, file);
|
|
69
69
|
|
|
70
|
-
//
|
|
71
|
-
|
|
70
|
+
// Smart extraction: if file is large, extract route-like patterns
|
|
71
|
+
let extractedContent;
|
|
72
|
+
if (content.length > 8000) {
|
|
73
|
+
// For large files, extract route definitions and API patterns
|
|
74
|
+
extractedContent = extractRoutePatterns(content, relativePath);
|
|
75
|
+
} else {
|
|
76
|
+
// For smaller files, include more content
|
|
77
|
+
extractedContent = content.slice(0, 8000);
|
|
78
|
+
}
|
|
72
79
|
|
|
73
80
|
fileContents.push({
|
|
74
81
|
path: relativePath,
|
|
75
|
-
content:
|
|
82
|
+
content: extractedContent
|
|
76
83
|
});
|
|
77
84
|
} catch (error) {
|
|
78
85
|
// Skip files that can't be read
|
|
@@ -82,6 +89,73 @@ async function scanCodebase(codebasePath) {
|
|
|
82
89
|
return fileContents;
|
|
83
90
|
}
|
|
84
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Extract route patterns from large files
|
|
94
|
+
*/
|
|
95
|
+
function extractRoutePatterns(content, filePath) {
|
|
96
|
+
const lines = content.split('\n');
|
|
97
|
+
const relevantLines = [];
|
|
98
|
+
|
|
99
|
+
// Patterns that indicate API routes/endpoints
|
|
100
|
+
const routePatterns = [
|
|
101
|
+
/app\.(get|post|put|patch|delete|use)\s*\(/i,
|
|
102
|
+
/router\.(get|post|put|patch|delete|use)\s*\(/i,
|
|
103
|
+
/Route::(get|post|put|patch|delete)\s*\(/i,
|
|
104
|
+
/@(Get|Post|Put|Patch|Delete|RequestMapping)/i,
|
|
105
|
+
/def\s+(get|post|put|patch|delete|index|create|update|destroy)/i,
|
|
106
|
+
/function\s+\w+\s*\(\s*(req|request)/i,
|
|
107
|
+
/fetch\s*\(/i,
|
|
108
|
+
/axios\./i,
|
|
109
|
+
/api['"]\s*:/i,
|
|
110
|
+
/endpoint/i,
|
|
111
|
+
/\/api\//i
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
let inRouteBlock = false;
|
|
115
|
+
let braceCount = 0;
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < lines.length; i++) {
|
|
118
|
+
const line = lines[i];
|
|
119
|
+
|
|
120
|
+
// Check if line matches any route pattern
|
|
121
|
+
const isRouteLine = routePatterns.some(pattern => pattern.test(line));
|
|
122
|
+
|
|
123
|
+
if (isRouteLine) {
|
|
124
|
+
// Include context: 2 lines before
|
|
125
|
+
for (let j = Math.max(0, i - 2); j < i; j++) {
|
|
126
|
+
if (!relevantLines.includes(lines[j])) {
|
|
127
|
+
relevantLines.push(`// Line ${j + 1}: ${lines[j]}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
relevantLines.push(`// Line ${i + 1}: ${line}`);
|
|
131
|
+
inRouteBlock = true;
|
|
132
|
+
braceCount = (line.match(/{/g) || []).length - (line.match(/}/g) || []).length;
|
|
133
|
+
} else if (inRouteBlock) {
|
|
134
|
+
// Continue capturing the route handler
|
|
135
|
+
relevantLines.push(line);
|
|
136
|
+
braceCount += (line.match(/{/g) || []).length - (line.match(/}/g) || []).length;
|
|
137
|
+
|
|
138
|
+
// End of route block
|
|
139
|
+
if (braceCount <= 0) {
|
|
140
|
+
inRouteBlock = false;
|
|
141
|
+
relevantLines.push('// ---');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Safety limit per block
|
|
145
|
+
if (relevantLines.length > 200) {
|
|
146
|
+
inRouteBlock = false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// If we found relevant lines, return them; otherwise return truncated content
|
|
152
|
+
if (relevantLines.length > 10) {
|
|
153
|
+
return `// Extracted route patterns from ${filePath} (${lines.length} lines total)\n\n${relevantLines.join('\n')}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return content.slice(0, 8000);
|
|
157
|
+
}
|
|
158
|
+
|
|
85
159
|
/**
|
|
86
160
|
* Prioritize files based on keywords in path/name
|
|
87
161
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@merlean/analyzer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "AI Bot codebase analyzer - generates site maps for AI assistant integration",
|
|
5
5
|
"keywords": ["ai", "bot", "analyzer", "claude", "anthropic", "widget"],
|
|
6
6
|
"author": "zmaren",
|