@parseme/cli 0.0.3 → 0.0.4
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/README.md +163 -156
- package/dist/{cli.js → cli/cli.js} +59 -49
- package/dist/{prompt.d.ts → cli/prompt.d.ts} +0 -1
- package/dist/{prompt.js → cli/prompt.js} +0 -9
- package/dist/{analyzers → core/analyzers}/ast-analyzer.js +7 -6
- package/dist/{analyzers → core/analyzers}/framework-detector.d.ts +0 -3
- package/dist/{analyzers → core/analyzers}/framework-detector.js +0 -4
- package/dist/{analyzers → core/analyzers}/git-analyzer.d.ts +0 -3
- package/dist/{analyzers → core/analyzers}/git-analyzer.js +0 -4
- package/dist/{analyzers → core/analyzers}/pattern-detector.d.ts +0 -3
- package/dist/{analyzers → core/analyzers}/pattern-detector.js +52 -47
- package/dist/{analyzers → core/analyzers}/project-analyzer.d.ts +2 -0
- package/dist/{analyzers → core/analyzers}/project-analyzer.js +19 -5
- package/dist/core/config.d.ts +20 -0
- package/dist/{config.js → core/config.js} +80 -68
- package/dist/{builders → core}/context-builder.d.ts +3 -8
- package/dist/{builders → core}/context-builder.js +7 -84
- package/dist/{generator.d.ts → core/generator.d.ts} +0 -3
- package/dist/{generator.js → core/generator.js} +8 -13
- package/dist/core/types/analyzer-types.d.ts +39 -0
- package/dist/core/types/analyzer-types.js +2 -0
- package/dist/{config.d.ts → core/types/config-types.d.ts} +8 -15
- package/dist/core/types/config-types.js +2 -0
- package/dist/core/types/generator-types.d.ts +8 -0
- package/dist/core/types/generator-types.js +2 -0
- package/dist/core/types/index.d.ts +4 -0
- package/dist/core/types/index.js +5 -0
- package/dist/core/types/project-types.d.ts +30 -0
- package/dist/core/types/project-types.js +2 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.js +2 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +2 -2
- package/package.json +3 -4
- package/dist/types.d.ts +0 -84
- package/dist/types.js +0 -2
- /package/dist/{cli.d.ts → cli/cli.d.ts} +0 -0
- /package/dist/{analyzers → core/analyzers}/ast-analyzer.d.ts +0 -0
|
@@ -3,28 +3,35 @@ import { readFile, writeFile } from 'fs/promises';
|
|
|
3
3
|
import { join, extname } from 'path';
|
|
4
4
|
export class ParsemeConfig {
|
|
5
5
|
config;
|
|
6
|
+
userConfig;
|
|
6
7
|
constructor(config = {}) {
|
|
8
|
+
this.userConfig = { ...config }; // Store original user config
|
|
7
9
|
this.config = this.mergeWithDefaults(config);
|
|
8
10
|
}
|
|
9
|
-
static async fromFileWithOptions(configPath, cliOptions = {}) {
|
|
10
|
-
const configFromFile = await ParsemeConfig.fromFile(configPath);
|
|
11
|
+
static async fromFileWithOptions(configPath, cliOptions = {}, options = { showWarnings: true }) {
|
|
12
|
+
const configFromFile = await ParsemeConfig.fromFile(configPath, options);
|
|
11
13
|
const mergedConfig = {
|
|
12
14
|
...configFromFile.get(),
|
|
13
15
|
...cliOptions, // CLI options take priority
|
|
14
16
|
};
|
|
15
17
|
return new ParsemeConfig(mergedConfig);
|
|
16
18
|
}
|
|
17
|
-
static async fromFile(configPath
|
|
19
|
+
static async fromFile(configPath, options = {
|
|
20
|
+
showWarnings: true,
|
|
21
|
+
throwOnNotFound: false,
|
|
22
|
+
}) {
|
|
18
23
|
const defaultPaths = [
|
|
19
|
-
'parseme.config.ts',
|
|
20
|
-
'parseme.config.js',
|
|
21
24
|
'parseme.config.json',
|
|
22
|
-
'.parsemerc.ts',
|
|
23
|
-
'.parsemerc.js',
|
|
24
25
|
'.parsemerc.json',
|
|
25
26
|
'.parsemerc',
|
|
27
|
+
'parseme.config.ts',
|
|
28
|
+
'.parsemerc.ts',
|
|
29
|
+
'parseme.config.js',
|
|
30
|
+
'.parsemerc.js',
|
|
26
31
|
];
|
|
27
32
|
const paths = configPath ? [configPath] : defaultPaths;
|
|
33
|
+
let tsWarning = null;
|
|
34
|
+
let configLoadError = null;
|
|
28
35
|
for (const path of paths) {
|
|
29
36
|
try {
|
|
30
37
|
const ext = extname(path);
|
|
@@ -32,17 +39,18 @@ export class ParsemeConfig {
|
|
|
32
39
|
// Dynamic import for JS/TS config files
|
|
33
40
|
const fullPath = path.startsWith('/') ? path : join(process.cwd(), path);
|
|
34
41
|
if (ext === '.ts') {
|
|
35
|
-
// For TypeScript files,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
// For TypeScript files, check if file exists first
|
|
43
|
+
if (existsSync(fullPath)) {
|
|
44
|
+
try {
|
|
45
|
+
const module = await import(fullPath);
|
|
46
|
+
const config = module.default || module;
|
|
47
|
+
return new ParsemeConfig(config);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// File exists but can't be loaded - save warning
|
|
51
|
+
tsWarning = path;
|
|
52
|
+
configLoadError = { path, error: error };
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
}
|
|
48
56
|
else {
|
|
@@ -54,20 +62,56 @@ export class ParsemeConfig {
|
|
|
54
62
|
}
|
|
55
63
|
else {
|
|
56
64
|
// JSON config files
|
|
57
|
-
const
|
|
65
|
+
const fullPath = path.startsWith('/') ? path : join(process.cwd(), path);
|
|
66
|
+
const content = await readFile(fullPath, 'utf-8');
|
|
58
67
|
const config = JSON.parse(content);
|
|
59
68
|
return new ParsemeConfig(config);
|
|
60
69
|
}
|
|
61
70
|
}
|
|
62
|
-
catch {
|
|
71
|
+
catch (error) {
|
|
72
|
+
// If file exists, save the error
|
|
73
|
+
const fullPath = path.startsWith('/') ? path : join(process.cwd(), path);
|
|
74
|
+
if (existsSync(fullPath)) {
|
|
75
|
+
configLoadError = { path, error: error };
|
|
76
|
+
}
|
|
63
77
|
// Continue to next path
|
|
64
78
|
}
|
|
65
79
|
}
|
|
80
|
+
// Handle case when config file was found but couldn't be loaded
|
|
81
|
+
if (configLoadError) {
|
|
82
|
+
const { path, error } = configLoadError;
|
|
83
|
+
if (options.throwOnNotFound) {
|
|
84
|
+
throw new Error(`Configuration file "${path}" found but failed to load: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
if (options.showWarnings) {
|
|
87
|
+
console.warn(`Configuration file "${path}" found but failed to load: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Handle case when no config found at all
|
|
92
|
+
if (options.throwOnNotFound) {
|
|
93
|
+
throw new Error('No configuration file found. Run "parseme init" to create one.');
|
|
94
|
+
}
|
|
95
|
+
if (options.showWarnings) {
|
|
96
|
+
console.warn('No configuration file found. Run "parseme init" to create one.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (tsWarning && !configLoadError && options.showWarnings) {
|
|
100
|
+
console.warn(`Could not load TypeScript config file: ${tsWarning}`);
|
|
101
|
+
console.warn(`Consider using a .js config file or ensure tsx/ts-node is available`);
|
|
102
|
+
}
|
|
66
103
|
// Return default config if no file found
|
|
67
104
|
return new ParsemeConfig();
|
|
68
105
|
}
|
|
69
106
|
mergeWithDefaults(config) {
|
|
70
107
|
const rootDir = config.rootDir || process.cwd();
|
|
108
|
+
const supportedFileTypes = ['ts', 'tsx', 'js', 'jsx'];
|
|
109
|
+
// Validate analyzeFileTypes
|
|
110
|
+
const fileTypes = config.analyzeFileTypes || ['ts', 'tsx', 'js', 'jsx'];
|
|
111
|
+
const invalidTypes = fileTypes.filter((type) => !supportedFileTypes.includes(type));
|
|
112
|
+
if (invalidTypes.length > 0) {
|
|
113
|
+
throw new Error(`Invalid file types: ${invalidTypes.join(', ')}. Supported types are: ${supportedFileTypes.join(', ')}`);
|
|
114
|
+
}
|
|
71
115
|
return {
|
|
72
116
|
// Output
|
|
73
117
|
outputPath: config.outputPath || 'PARSEME.md',
|
|
@@ -76,17 +120,7 @@ export class ParsemeConfig {
|
|
|
76
120
|
rootDir,
|
|
77
121
|
maxDepth: config.maxDepth || 10,
|
|
78
122
|
excludePatterns: this.mergeExcludePatterns(config.excludePatterns, rootDir),
|
|
79
|
-
|
|
80
|
-
'src/**/*.ts',
|
|
81
|
-
'src/**/*.js',
|
|
82
|
-
'src/**/*.tsx',
|
|
83
|
-
'src/**/*.jsx',
|
|
84
|
-
'lib/**/*.ts',
|
|
85
|
-
'lib/**/*.js',
|
|
86
|
-
'package.json',
|
|
87
|
-
'tsconfig.json',
|
|
88
|
-
'README.md',
|
|
89
|
-
],
|
|
123
|
+
analyzeFileTypes: fileTypes,
|
|
90
124
|
// Git
|
|
91
125
|
includeGitInfo: config.includeGitInfo ?? true,
|
|
92
126
|
// Sections
|
|
@@ -132,47 +166,36 @@ export class ParsemeConfig {
|
|
|
132
166
|
await writeFile(path, configContent);
|
|
133
167
|
}
|
|
134
168
|
else {
|
|
135
|
-
// Generate JSON config file
|
|
136
|
-
await writeFile(path, JSON.stringify(this.
|
|
169
|
+
// Generate JSON config file - only save user config, not defaults
|
|
170
|
+
await writeFile(path, JSON.stringify(this.userConfig, null, 2));
|
|
137
171
|
}
|
|
138
172
|
}
|
|
139
173
|
generateJSConfig() {
|
|
174
|
+
// Only export user-specified config, not defaults
|
|
140
175
|
return `/** @type {import('parseme').ParsemeConfigFile} */
|
|
141
|
-
|
|
176
|
+
const config = ${JSON.stringify(this.userConfig, null, 2)};
|
|
177
|
+
|
|
178
|
+
export default config;
|
|
142
179
|
`;
|
|
143
180
|
}
|
|
144
181
|
generateTSConfig() {
|
|
182
|
+
// Only export user-specified config, not defaults
|
|
145
183
|
return `import type { ParsemeConfigFile } from 'parseme';
|
|
146
184
|
|
|
147
|
-
const config: ParsemeConfigFile = ${JSON.stringify(this.
|
|
185
|
+
const config: ParsemeConfigFile = ${JSON.stringify(this.userConfig, null, 2)};
|
|
148
186
|
|
|
149
187
|
export default config;
|
|
150
188
|
`;
|
|
151
189
|
}
|
|
152
190
|
mergeExcludePatterns(configPatterns, rootDir) {
|
|
153
|
-
|
|
154
|
-
'node_modules/**',
|
|
155
|
-
'dist/**',
|
|
156
|
-
'build/**',
|
|
157
|
-
'coverage/**',
|
|
158
|
-
'.git/**',
|
|
159
|
-
'**/*.log',
|
|
160
|
-
'**/*.tmp',
|
|
161
|
-
'**/.DS_Store',
|
|
162
|
-
'**/.*',
|
|
163
|
-
];
|
|
164
|
-
// Priority: Config patterns > .gitignore patterns > Default patterns
|
|
165
|
-
if (configPatterns) {
|
|
166
|
-
return configPatterns;
|
|
167
|
-
}
|
|
168
|
-
// Try to read .gitignore patterns
|
|
191
|
+
// Always read .gitignore patterns
|
|
169
192
|
const gitignorePatterns = this.readGitignorePatterns(rootDir);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
193
|
+
// Merge gitignore patterns with config patterns, they are added to gitignore patterns, not replacing them
|
|
194
|
+
const excludePatterns = [...gitignorePatterns];
|
|
195
|
+
if (configPatterns) {
|
|
196
|
+
excludePatterns.push(...configPatterns);
|
|
174
197
|
}
|
|
175
|
-
return
|
|
198
|
+
return excludePatterns;
|
|
176
199
|
}
|
|
177
200
|
readGitignorePatterns(rootDir) {
|
|
178
201
|
try {
|
|
@@ -184,18 +207,7 @@ export default config;
|
|
|
184
207
|
return gitignoreContent
|
|
185
208
|
.split('\n')
|
|
186
209
|
.map((line) => line.trim())
|
|
187
|
-
.filter((line) => line && !line.startsWith('#'))
|
|
188
|
-
.map((pattern) => {
|
|
189
|
-
// Convert gitignore patterns to glob patterns
|
|
190
|
-
if (pattern.endsWith('/')) {
|
|
191
|
-
return pattern + '**';
|
|
192
|
-
}
|
|
193
|
-
if (!pattern.includes('/') && !pattern.includes('*')) {
|
|
194
|
-
// Convert simple names to match directory patterns
|
|
195
|
-
return pattern + '/**';
|
|
196
|
-
}
|
|
197
|
-
return pattern;
|
|
198
|
-
});
|
|
210
|
+
.filter((line) => line && !line.startsWith('#'));
|
|
199
211
|
}
|
|
200
212
|
catch {
|
|
201
213
|
return [];
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ParsemeConfig } from '
|
|
2
|
-
import type { ContextOutput, ProjectInfo, FileAnalysis, GitInfo, GeneratorOptions } from '
|
|
1
|
+
import type { ParsemeConfig } from './config.js';
|
|
2
|
+
import type { ContextOutput, ProjectInfo, FileAnalysis, GitInfo, GeneratorOptions } from './types.js';
|
|
3
3
|
interface BuildContext {
|
|
4
4
|
projectInfo: ProjectInfo;
|
|
5
5
|
fileAnalyses: FileAnalysis[];
|
|
6
|
+
allFiles: string[];
|
|
6
7
|
gitInfo?: GitInfo | null;
|
|
7
8
|
options: GeneratorOptions;
|
|
8
9
|
contextDir?: string;
|
|
@@ -18,13 +19,7 @@ export declare class ContextBuilder {
|
|
|
18
19
|
private buildMultiFile;
|
|
19
20
|
private buildHeader;
|
|
20
21
|
private buildProjectOverview;
|
|
21
|
-
private buildFrameworkSection;
|
|
22
|
-
private buildArchitectureSection;
|
|
23
|
-
private buildRoutesSection;
|
|
24
|
-
private buildFileStructureSection;
|
|
25
|
-
private buildDependenciesSection;
|
|
26
22
|
private buildGitSection;
|
|
27
|
-
private buildFooter;
|
|
28
23
|
private buildSummarySection;
|
|
29
24
|
private buildFilesList;
|
|
30
25
|
private buildDetailedStructure;
|
|
@@ -109,7 +109,6 @@ export class ContextBuilder {
|
|
|
109
109
|
const contextFiles = {
|
|
110
110
|
structure: '',
|
|
111
111
|
routes: '',
|
|
112
|
-
dependencies: '',
|
|
113
112
|
};
|
|
114
113
|
// Helper function to merge split files into contextFiles
|
|
115
114
|
const mergeSplitFiles = (result, baseName) => {
|
|
@@ -123,8 +122,8 @@ export class ContextBuilder {
|
|
|
123
122
|
});
|
|
124
123
|
}
|
|
125
124
|
};
|
|
126
|
-
// Files list (markdown)
|
|
127
|
-
contextFiles.files = this.buildFilesList(
|
|
125
|
+
// Files list (markdown) - all files in project, not just analyzed ones
|
|
126
|
+
contextFiles.files = this.buildFilesList(context.allFiles);
|
|
128
127
|
// Detailed structure (JSON with AST)
|
|
129
128
|
const structureResult = this.buildDetailedStructure(limitedFileAnalyses);
|
|
130
129
|
mergeSplitFiles(structureResult, 'structure');
|
|
@@ -134,15 +133,6 @@ export class ContextBuilder {
|
|
|
134
133
|
const routesResult = this.buildDetailedRoutes(routes, limitedFileAnalyses);
|
|
135
134
|
mergeSplitFiles(routesResult, 'api-endpoints');
|
|
136
135
|
}
|
|
137
|
-
// Dependencies
|
|
138
|
-
const dependenciesResult = this.buildDetailedDependencies(projectInfo);
|
|
139
|
-
mergeSplitFiles(dependenciesResult, 'dependencies');
|
|
140
|
-
// Framework details
|
|
141
|
-
if (projectInfo.framework &&
|
|
142
|
-
projectInfo.framework.name &&
|
|
143
|
-
projectInfo.framework.name !== 'unknown') {
|
|
144
|
-
contextFiles.framework = this.buildDetailedFramework(projectInfo.framework);
|
|
145
|
-
}
|
|
146
136
|
// Git information
|
|
147
137
|
if (gitInfo) {
|
|
148
138
|
contextFiles.gitDiff = this.buildDetailedGit(gitInfo);
|
|
@@ -194,68 +184,6 @@ Auto-generated project summary optimized for AI coding agents. This file provide
|
|
|
194
184
|
}
|
|
195
185
|
return content;
|
|
196
186
|
}
|
|
197
|
-
buildFrameworkSection(framework) {
|
|
198
|
-
if (!framework) {
|
|
199
|
-
return '';
|
|
200
|
-
}
|
|
201
|
-
const features = framework.features.length > 0 ? `\n- **Features**: ${framework.features.join(', ')}` : '';
|
|
202
|
-
return `## Framework: ${framework.name}
|
|
203
|
-
|
|
204
|
-
- **Version**: ${framework.version || 'Unknown'}${features}`;
|
|
205
|
-
}
|
|
206
|
-
buildArchitectureSection(fileAnalyses) {
|
|
207
|
-
const typeGroups = fileAnalyses.reduce((acc, file) => {
|
|
208
|
-
if (!acc[file.type]) {
|
|
209
|
-
acc[file.type] = [];
|
|
210
|
-
}
|
|
211
|
-
acc[file.type].push(file);
|
|
212
|
-
return acc;
|
|
213
|
-
}, {});
|
|
214
|
-
const archLines = Object.entries(typeGroups)
|
|
215
|
-
.map(([type, files]) => `- **${type}**: ${files.length} files`)
|
|
216
|
-
.join('\n');
|
|
217
|
-
return `## Architecture Overview
|
|
218
|
-
|
|
219
|
-
${archLines}`;
|
|
220
|
-
}
|
|
221
|
-
buildRoutesSection(routes, _fileAnalyses) {
|
|
222
|
-
const routesByMethod = routes.reduce((acc, route) => {
|
|
223
|
-
if (!acc[route.method]) {
|
|
224
|
-
acc[route.method] = [];
|
|
225
|
-
}
|
|
226
|
-
acc[route.method].push(route);
|
|
227
|
-
return acc;
|
|
228
|
-
}, {});
|
|
229
|
-
const routeLines = Object.entries(routesByMethod)
|
|
230
|
-
.map(([method, methodRoutes]) => {
|
|
231
|
-
const routeList = methodRoutes
|
|
232
|
-
.map((route) => ` - \`${route.path}\` → ${route.handler}`)
|
|
233
|
-
.join('\n');
|
|
234
|
-
return `- **${method}**:\n${routeList}`;
|
|
235
|
-
})
|
|
236
|
-
.join('\n');
|
|
237
|
-
return `## API Endpoints
|
|
238
|
-
|
|
239
|
-
${routeLines}`;
|
|
240
|
-
}
|
|
241
|
-
buildFileStructureSection(fileAnalyses) {
|
|
242
|
-
const structure = fileAnalyses.map((file) => `- \`${file.path}\` (${file.type})`).join('\n');
|
|
243
|
-
return `## File Structure
|
|
244
|
-
|
|
245
|
-
${structure}`;
|
|
246
|
-
}
|
|
247
|
-
buildDependenciesSection(projectInfo) {
|
|
248
|
-
const deps = Object.keys(projectInfo.dependencies);
|
|
249
|
-
const devDeps = Object.keys(projectInfo.devDependencies);
|
|
250
|
-
let content = '## Dependencies\n\n';
|
|
251
|
-
if (deps.length > 0) {
|
|
252
|
-
content += `**Production**: ${deps.join(', ')}\n\n`;
|
|
253
|
-
}
|
|
254
|
-
if (devDeps.length > 0) {
|
|
255
|
-
content += `**Development**: ${devDeps.join(', ')}`;
|
|
256
|
-
}
|
|
257
|
-
return content;
|
|
258
|
-
}
|
|
259
187
|
buildGitSection(gitInfo) {
|
|
260
188
|
return `## Git Information
|
|
261
189
|
|
|
@@ -271,12 +199,7 @@ Git diff statistics from the time of generation are available at \`parseme-conte
|
|
|
271
199
|
\`\`\`bash
|
|
272
200
|
git diff --stat
|
|
273
201
|
\`\`\`
|
|
274
|
-
Compare the output with the baseline in \`parseme-context/gitDiff.
|
|
275
|
-
}
|
|
276
|
-
buildFooter() {
|
|
277
|
-
return `---
|
|
278
|
-
|
|
279
|
-
*Generated by PARSEME v1.0.0 on ${new Date().toISOString().split('T')[0]}*`;
|
|
202
|
+
Compare the output with the baseline in \`parseme-context/gitDiff.md\` to detect any modifications.`;
|
|
280
203
|
}
|
|
281
204
|
buildSummarySection(context, linkPath) {
|
|
282
205
|
const { fileAnalyses } = context;
|
|
@@ -293,11 +216,11 @@ A comprehensive list of all discovered API endpoints is available at \`${linkPat
|
|
|
293
216
|
}
|
|
294
217
|
return content;
|
|
295
218
|
}
|
|
296
|
-
buildFilesList(
|
|
219
|
+
buildFilesList(allFiles) {
|
|
297
220
|
let content = `# Project Files\n\n`;
|
|
298
|
-
content += `This is a complete list of all
|
|
299
|
-
|
|
300
|
-
content += `- ${file
|
|
221
|
+
content += `This is a complete list of all files in the project (excluding files matching exclude patterns).\n\n`;
|
|
222
|
+
allFiles.forEach((file) => {
|
|
223
|
+
content += `- ${file}\n`;
|
|
301
224
|
});
|
|
302
225
|
return content;
|
|
303
226
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type ParsemeConfigFile } from './config.js';
|
|
2
1
|
import type { ContextOutput, GeneratorOptions } from './types.js';
|
|
3
2
|
export declare class ParsemeGenerator {
|
|
4
3
|
private readonly config;
|
|
@@ -8,8 +7,6 @@ export declare class ParsemeGenerator {
|
|
|
8
7
|
private readonly gitAnalyzer;
|
|
9
8
|
private readonly contextBuilder;
|
|
10
9
|
constructor(options?: GeneratorOptions);
|
|
11
|
-
static fromConfig(configPath?: string): Promise<ParsemeGenerator>;
|
|
12
|
-
static fromConfigWithOptions(configPath?: string, cliOptions?: Partial<ParsemeConfigFile>): Promise<ParsemeGenerator>;
|
|
13
10
|
generate(outputPath?: string): Promise<ContextOutput>;
|
|
14
11
|
generateToFile(outputPath?: string, contextDir?: string): Promise<void>;
|
|
15
12
|
}
|
|
@@ -4,8 +4,8 @@ import { ASTAnalyzer } from './analyzers/ast-analyzer.js';
|
|
|
4
4
|
import { FrameworkDetector } from './analyzers/framework-detector.js';
|
|
5
5
|
import { GitAnalyzer } from './analyzers/git-analyzer.js';
|
|
6
6
|
import { ProjectAnalyzer } from './analyzers/project-analyzer.js';
|
|
7
|
-
import { ContextBuilder } from './builders/context-builder.js';
|
|
8
7
|
import { ParsemeConfig } from './config.js';
|
|
8
|
+
import { ContextBuilder } from './context-builder.js';
|
|
9
9
|
export class ParsemeGenerator {
|
|
10
10
|
config;
|
|
11
11
|
projectAnalyzer;
|
|
@@ -17,18 +17,10 @@ export class ParsemeGenerator {
|
|
|
17
17
|
this.config = new ParsemeConfig(options);
|
|
18
18
|
this.projectAnalyzer = new ProjectAnalyzer(this.config);
|
|
19
19
|
this.astAnalyzer = new ASTAnalyzer(this.config);
|
|
20
|
-
this.frameworkDetector = new FrameworkDetector(
|
|
21
|
-
this.gitAnalyzer = new GitAnalyzer(
|
|
20
|
+
this.frameworkDetector = new FrameworkDetector();
|
|
21
|
+
this.gitAnalyzer = new GitAnalyzer();
|
|
22
22
|
this.contextBuilder = new ContextBuilder(this.config);
|
|
23
23
|
}
|
|
24
|
-
static async fromConfig(configPath) {
|
|
25
|
-
const config = await ParsemeConfig.fromFile(configPath);
|
|
26
|
-
return new ParsemeGenerator(config.get());
|
|
27
|
-
}
|
|
28
|
-
static async fromConfigWithOptions(configPath, cliOptions = {}) {
|
|
29
|
-
const config = await ParsemeConfig.fromFileWithOptions(configPath, cliOptions);
|
|
30
|
-
return new ParsemeGenerator(config.get());
|
|
31
|
-
}
|
|
32
24
|
async generate(outputPath) {
|
|
33
25
|
const configData = this.config.get();
|
|
34
26
|
// Step 1: Analyze the project structure and metadata
|
|
@@ -37,16 +29,19 @@ export class ParsemeGenerator {
|
|
|
37
29
|
projectInfo.framework = await this.frameworkDetector.detect(projectInfo);
|
|
38
30
|
// Step 3: Analyze all relevant files with AST
|
|
39
31
|
const fileAnalyses = await this.astAnalyzer.analyzeProject(configData.rootDir);
|
|
40
|
-
// Step 4: Get
|
|
32
|
+
// Step 4: Get all project files (for file list output)
|
|
33
|
+
const allFiles = await this.projectAnalyzer.getAllProjectFiles(configData.rootDir);
|
|
34
|
+
// Step 5: Get git information if enabled
|
|
41
35
|
const gitInfo = configData.includeGitInfo
|
|
42
36
|
? await this.gitAnalyzer.analyze(configData.rootDir)
|
|
43
37
|
: null;
|
|
44
38
|
// Calculate final output path for link generation
|
|
45
39
|
const finalOutputPath = outputPath || configData.outputPath || join(configData.rootDir, 'PARSEME.md');
|
|
46
|
-
// Step
|
|
40
|
+
// Step 6: Build the context output
|
|
47
41
|
return this.contextBuilder.build({
|
|
48
42
|
projectInfo,
|
|
49
43
|
fileAnalyses,
|
|
44
|
+
allFiles,
|
|
50
45
|
gitInfo,
|
|
51
46
|
options: configData,
|
|
52
47
|
contextDir: configData.contextDir,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ServiceInfo, ModelInfo, ConfigInfo, MiddlewareInfo, UtilityInfo } from '../analyzers/pattern-detector.js';
|
|
2
|
+
export type { ServiceInfo, ModelInfo, ConfigInfo, MiddlewareInfo, UtilityInfo };
|
|
3
|
+
export interface FileAnalysis {
|
|
4
|
+
path: string;
|
|
5
|
+
type: 'route' | 'middleware' | 'model' | 'service' | 'utility' | 'config' | 'test' | 'component';
|
|
6
|
+
framework?: string;
|
|
7
|
+
exports: string[];
|
|
8
|
+
imports: string[];
|
|
9
|
+
functions: string[];
|
|
10
|
+
classes: string[];
|
|
11
|
+
routes?: RouteInfo[];
|
|
12
|
+
components?: ComponentInfo[];
|
|
13
|
+
services?: ServiceInfo[];
|
|
14
|
+
models?: ModelInfo[];
|
|
15
|
+
configs?: ConfigInfo[];
|
|
16
|
+
middleware?: MiddlewareInfo[];
|
|
17
|
+
utilities?: UtilityInfo[];
|
|
18
|
+
}
|
|
19
|
+
export interface RouteInfo {
|
|
20
|
+
method: string;
|
|
21
|
+
path: string;
|
|
22
|
+
handler: string;
|
|
23
|
+
middleware?: string[];
|
|
24
|
+
file: string;
|
|
25
|
+
line: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ComponentInfo {
|
|
28
|
+
name: string;
|
|
29
|
+
file: string;
|
|
30
|
+
line: number;
|
|
31
|
+
}
|
|
32
|
+
export interface GitInfo {
|
|
33
|
+
branch: string;
|
|
34
|
+
lastCommit: string;
|
|
35
|
+
changedFiles: string[];
|
|
36
|
+
status: 'clean' | 'dirty';
|
|
37
|
+
origin?: string;
|
|
38
|
+
diffStat?: string;
|
|
39
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
export interface GeneratorOptions {
|
|
2
|
+
rootDir?: string;
|
|
3
|
+
includeGitInfo?: boolean;
|
|
4
|
+
maxDepth?: number;
|
|
5
|
+
excludePatterns?: string[];
|
|
6
|
+
analyzeFileTypes?: string[];
|
|
7
|
+
}
|
|
2
8
|
export interface ParsemeConfigFile extends GeneratorOptions {
|
|
3
9
|
outputPath?: string;
|
|
4
10
|
contextDir?: string;
|
|
5
11
|
rootDir?: string;
|
|
6
|
-
|
|
12
|
+
analyzeFileTypes?: string[];
|
|
7
13
|
excludePatterns?: string[];
|
|
8
14
|
maxDepth?: number;
|
|
9
15
|
includeGitInfo?: boolean;
|
|
@@ -29,16 +35,3 @@ export interface ParsemeConfigFile extends GeneratorOptions {
|
|
|
29
35
|
truncateStrategy?: 'truncate' | 'split' | 'summarize';
|
|
30
36
|
};
|
|
31
37
|
}
|
|
32
|
-
export declare class ParsemeConfig {
|
|
33
|
-
private readonly config;
|
|
34
|
-
constructor(config?: Partial<ParsemeConfigFile>);
|
|
35
|
-
static fromFileWithOptions(configPath?: string, cliOptions?: Partial<ParsemeConfigFile>): Promise<ParsemeConfig>;
|
|
36
|
-
static fromFile(configPath?: string): Promise<ParsemeConfig>;
|
|
37
|
-
private mergeWithDefaults;
|
|
38
|
-
get(): ParsemeConfigFile;
|
|
39
|
-
save(path?: string): Promise<void>;
|
|
40
|
-
private generateJSConfig;
|
|
41
|
-
private generateTSConfig;
|
|
42
|
-
private mergeExcludePatterns;
|
|
43
|
-
private readGitignorePatterns;
|
|
44
|
-
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RouteInfo, ComponentInfo } from './analyzer-types.js';
|
|
2
|
+
export interface ProjectInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
type: 'typescript' | 'javascript' | 'mixed';
|
|
7
|
+
category: ProjectCategory;
|
|
8
|
+
packageManager: 'unknown' | 'npm' | 'yarn' | 'pnpm' | 'bun';
|
|
9
|
+
framework?: FrameworkInfo;
|
|
10
|
+
buildTool?: BuildToolInfo;
|
|
11
|
+
dependencies: Record<string, string>;
|
|
12
|
+
devDependencies: Record<string, string>;
|
|
13
|
+
scripts?: Record<string, string>;
|
|
14
|
+
entryPoints?: string[];
|
|
15
|
+
outputTargets?: string[];
|
|
16
|
+
}
|
|
17
|
+
export type ProjectCategory = 'backend-api' | 'frontend-web' | 'frontend-mobile' | 'npm-package' | 'monorepo' | 'cli-tool' | 'desktop-app' | 'fullstack' | 'unknown';
|
|
18
|
+
export interface FrameworkInfo {
|
|
19
|
+
name: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
features: string[];
|
|
22
|
+
routes?: RouteInfo[];
|
|
23
|
+
components?: ComponentInfo[];
|
|
24
|
+
}
|
|
25
|
+
export interface BuildToolInfo {
|
|
26
|
+
name: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
configFiles: string[];
|
|
29
|
+
features: string[];
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './types/index.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { ParsemeGenerator } from './generator.js';
|
|
2
|
-
export { ParsemeConfig } from './config.js';
|
|
3
|
-
export type { GeneratorOptions, ContextOutput, ProjectInfo, FrameworkInfo, RouteInfo, FileAnalysis, GitInfo, } from './types.js';
|
|
4
|
-
export type { ParsemeConfigFile } from './config.js';
|
|
1
|
+
export { ParsemeGenerator } from './core/generator.js';
|
|
2
|
+
export { ParsemeConfig } from './core/config.js';
|
|
3
|
+
export type { GeneratorOptions, ContextOutput, ProjectInfo, FrameworkInfo, RouteInfo, FileAnalysis, GitInfo, ParsemeConfigFile, } from './core/types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Main exports for the parseme package
|
|
2
|
-
export { ParsemeGenerator } from './generator.js';
|
|
3
|
-
export { ParsemeConfig } from './config.js';
|
|
2
|
+
export { ParsemeGenerator } from './core/generator.js';
|
|
3
|
+
export { ParsemeConfig } from './core/config.js';
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parseme/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Adds a PARSEME.md file—a README.md for AI agents—to your project, providing context and structure for automated tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"parseme": "dist/cli.js"
|
|
9
|
+
"parseme": "dist/cli/cli.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
@@ -24,12 +24,11 @@
|
|
|
24
24
|
"format:check": "prettier . --ignore-unknown --check",
|
|
25
25
|
"lint": "eslint --config ./eslint.config.js --fix",
|
|
26
26
|
"lint:check": "eslint --config ./eslint.config.js --no-fix --max-warnings 0",
|
|
27
|
-
"test": "node --test --experimental-test-coverage tests/**/*.test.ts",
|
|
27
|
+
"test": "node --test --experimental-test-coverage 'tests/**/*.test.ts'",
|
|
28
28
|
"test:unit": "node --test tests/unit/**/*.test.ts",
|
|
29
29
|
"test:integration": "node --test tests/integration/**/*.test.ts",
|
|
30
30
|
"test:watch": "node --test --watch tests/**/*.test.ts",
|
|
31
31
|
"test:coverage": "node --test --experimental-test-coverage tests/**/*.test.ts",
|
|
32
|
-
"prepare": "npm run build",
|
|
33
32
|
"clean": "rm -rf dist"
|
|
34
33
|
},
|
|
35
34
|
"keywords": [
|