@parseme/cli 0.0.3 → 0.0.5
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 +182 -187
- package/dist/cli/cli.js +144 -0
- package/dist/{analyzers → core/analyzers}/ast-analyzer.d.ts +1 -1
- package/dist/{analyzers → core/analyzers}/ast-analyzer.js +14 -27
- package/dist/core/analyzers/framework-detector.d.ts +7 -0
- package/dist/core/analyzers/framework-detector.js +165 -0
- package/dist/{analyzers → core/analyzers}/pattern-detector.d.ts +2 -5
- package/dist/{analyzers → core/analyzers}/pattern-detector.js +134 -49
- package/dist/{analyzers → core/analyzers}/project-analyzer.d.ts +2 -0
- package/dist/{analyzers → core/analyzers}/project-analyzer.js +12 -9
- package/dist/core/config.d.ts +19 -0
- package/dist/{config.js → core/config.js} +79 -91
- package/dist/{builders → core}/context-builder.d.ts +4 -11
- package/dist/core/context-builder.js +225 -0
- package/dist/{generator.d.ts → core/generator.d.ts} +0 -3
- package/dist/{generator.js → core/generator.js} +12 -17
- package/dist/core/types/analyzer-types.d.ts +38 -0
- package/dist/core/types/analyzer-types.js +2 -0
- package/dist/core/types/config-types.d.ts +36 -0
- package/dist/core/types/config-types.js +2 -0
- package/dist/core/types/generator-types.d.ts +6 -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/dist/utils/file-collector.d.ts +23 -0
- package/dist/utils/file-collector.js +61 -0
- package/dist/utils/file-filter.d.ts +30 -0
- package/dist/utils/file-filter.js +99 -0
- package/dist/{analyzers/git-analyzer.d.ts → utils/git.d.ts} +1 -4
- package/dist/{analyzers/git-analyzer.js → utils/git.js} +0 -4
- package/dist/{prompt.d.ts → utils/prompt.d.ts} +0 -1
- package/dist/{prompt.js → utils/prompt.js} +0 -9
- package/package.json +12 -8
- package/dist/analyzers/framework-detector.d.ts +0 -12
- package/dist/analyzers/framework-detector.js +0 -180
- package/dist/builders/context-builder.js +0 -386
- package/dist/cli.js +0 -145
- package/dist/config.d.ts +0 -44
- package/dist/types.d.ts +0 -84
- package/dist/types.js +0 -2
- /package/dist/{cli.d.ts → cli/cli.d.ts} +0 -0
|
@@ -2,10 +2,10 @@ import { mkdir, writeFile } from 'fs/promises';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { ASTAnalyzer } from './analyzers/ast-analyzer.js';
|
|
4
4
|
import { FrameworkDetector } from './analyzers/framework-detector.js';
|
|
5
|
-
import { GitAnalyzer } from './analyzers/git-analyzer.js';
|
|
6
5
|
import { ProjectAnalyzer } from './analyzers/project-analyzer.js';
|
|
7
|
-
import { ContextBuilder } from './builders/context-builder.js';
|
|
8
6
|
import { ParsemeConfig } from './config.js';
|
|
7
|
+
import { ContextBuilder } from './context-builder.js';
|
|
8
|
+
import { GitAnalyzer } from '../utils/git.js';
|
|
9
9
|
export class ParsemeGenerator {
|
|
10
10
|
config;
|
|
11
11
|
projectAnalyzer;
|
|
@@ -17,36 +17,31 @@ 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
|
|
35
27
|
const projectInfo = await this.projectAnalyzer.analyze(configData.rootDir);
|
|
36
|
-
// Step 2:
|
|
37
|
-
projectInfo.framework = await this.frameworkDetector.detect(projectInfo);
|
|
38
|
-
// Step 3: Analyze all relevant files with AST
|
|
28
|
+
// Step 2: Analyze all relevant files with AST
|
|
39
29
|
const fileAnalyses = await this.astAnalyzer.analyzeProject(configData.rootDir);
|
|
40
|
-
// Step
|
|
30
|
+
// Step 3: Detect frameworks from dependencies
|
|
31
|
+
projectInfo.frameworks = await this.frameworkDetector.detect(projectInfo);
|
|
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,38 @@
|
|
|
1
|
+
import type { ServiceInfo, ModelInfo, ConfigInfo, MiddlewareInfo, UtilityInfo, EndpointInfo } from '../analyzers/pattern-detector.js';
|
|
2
|
+
export type { ServiceInfo, ModelInfo, ConfigInfo, MiddlewareInfo, UtilityInfo, EndpointInfo };
|
|
3
|
+
export interface FileAnalysis {
|
|
4
|
+
path: string;
|
|
5
|
+
type: 'route' | 'middleware' | 'model' | 'service' | 'utility' | 'config' | 'test' | 'component';
|
|
6
|
+
exports: string[];
|
|
7
|
+
imports: string[];
|
|
8
|
+
functions: string[];
|
|
9
|
+
classes: string[];
|
|
10
|
+
routes?: EndpointInfo[];
|
|
11
|
+
components?: ComponentInfo[];
|
|
12
|
+
services?: ServiceInfo[];
|
|
13
|
+
models?: ModelInfo[];
|
|
14
|
+
configs?: ConfigInfo[];
|
|
15
|
+
middleware?: MiddlewareInfo[];
|
|
16
|
+
utilities?: UtilityInfo[];
|
|
17
|
+
}
|
|
18
|
+
export interface RouteInfo {
|
|
19
|
+
method: string;
|
|
20
|
+
path: string;
|
|
21
|
+
handler: string;
|
|
22
|
+
middleware?: string[];
|
|
23
|
+
file: string;
|
|
24
|
+
line: number;
|
|
25
|
+
}
|
|
26
|
+
export interface ComponentInfo {
|
|
27
|
+
name: string;
|
|
28
|
+
file: string;
|
|
29
|
+
line: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GitInfo {
|
|
32
|
+
branch: string;
|
|
33
|
+
lastCommit: string;
|
|
34
|
+
changedFiles: string[];
|
|
35
|
+
status: 'clean' | 'dirty';
|
|
36
|
+
origin?: string;
|
|
37
|
+
diffStat?: string;
|
|
38
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface GeneratorOptions {
|
|
2
|
+
rootDir?: string;
|
|
3
|
+
includeGitInfo?: boolean;
|
|
4
|
+
useGitForFiles?: boolean;
|
|
5
|
+
maxDepth?: number;
|
|
6
|
+
excludePatterns?: string[];
|
|
7
|
+
analyzeFileTypes?: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface ParsemeConfigFile extends GeneratorOptions {
|
|
10
|
+
outputPath?: string;
|
|
11
|
+
contextDir?: string;
|
|
12
|
+
rootDir?: string;
|
|
13
|
+
analyzeFileTypes?: string[];
|
|
14
|
+
excludePatterns?: string[];
|
|
15
|
+
maxDepth?: number;
|
|
16
|
+
includeGitInfo?: boolean;
|
|
17
|
+
useGitForFiles?: boolean;
|
|
18
|
+
readmeSuggestion?: boolean;
|
|
19
|
+
sections?: {
|
|
20
|
+
overview?: boolean;
|
|
21
|
+
architecture?: boolean;
|
|
22
|
+
routes?: boolean;
|
|
23
|
+
dependencies?: boolean;
|
|
24
|
+
git?: boolean;
|
|
25
|
+
fileStructure?: boolean;
|
|
26
|
+
};
|
|
27
|
+
style?: {
|
|
28
|
+
includeLineNumbers?: boolean;
|
|
29
|
+
includeFileStats?: boolean;
|
|
30
|
+
groupByType?: boolean;
|
|
31
|
+
sortOrder?: 'alphabetical' | 'type' | 'size';
|
|
32
|
+
};
|
|
33
|
+
limits?: {
|
|
34
|
+
maxFilesPerContext?: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -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
|
+
frameworks?: 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';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ParsemeConfig } from '../core/config.js';
|
|
2
|
+
export interface FileCollectionOptions {
|
|
3
|
+
fileTypes?: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface FileCollectionResult {
|
|
6
|
+
files: string[];
|
|
7
|
+
totalFound: number;
|
|
8
|
+
excluded: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class FileCollector {
|
|
11
|
+
private readonly fileFilter;
|
|
12
|
+
private readonly config;
|
|
13
|
+
constructor(config: ParsemeConfig);
|
|
14
|
+
getFiles(rootDir: string, options?: FileCollectionOptions): Promise<FileCollectionResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Get all project files (no file type filtering, for files.md)
|
|
17
|
+
*/
|
|
18
|
+
getAllProjectFiles(rootDir: string): Promise<FileCollectionResult>;
|
|
19
|
+
/**
|
|
20
|
+
* Get code files for AST analysis (filtered by file types, for structure.json)
|
|
21
|
+
*/
|
|
22
|
+
getCodeFiles(rootDir: string, fileTypes?: string[]): Promise<FileCollectionResult>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FileFilterService } from './file-filter.js';
|
|
2
|
+
export class FileCollector {
|
|
3
|
+
fileFilter;
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = config;
|
|
7
|
+
const configData = this.config.get();
|
|
8
|
+
this.fileFilter = new FileFilterService(configData.excludePatterns, configData.useGitForFiles ?? true);
|
|
9
|
+
}
|
|
10
|
+
async getFiles(rootDir, options = {}) {
|
|
11
|
+
const configData = this.config.get();
|
|
12
|
+
const { fileTypes } = options;
|
|
13
|
+
// Get all filtered files (respects git ignore + custom excludePatterns)
|
|
14
|
+
const allFiles = await this.fileFilter.getFilteredFiles(rootDir);
|
|
15
|
+
// Filter by file types if specified
|
|
16
|
+
let filteredFiles = allFiles;
|
|
17
|
+
if (fileTypes && fileTypes.length > 0) {
|
|
18
|
+
const extensionSet = new Set(fileTypes.map((ext) => (ext.startsWith('.') ? ext : `.${ext}`)));
|
|
19
|
+
filteredFiles = allFiles.filter((file) => {
|
|
20
|
+
const ext = file.substring(file.lastIndexOf('.'));
|
|
21
|
+
return extensionSet.has(ext);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
// Apply limits
|
|
25
|
+
let finalFiles = filteredFiles;
|
|
26
|
+
let excluded = 0;
|
|
27
|
+
if (configData.limits?.maxFilesPerContext) {
|
|
28
|
+
const limit = configData.limits.maxFilesPerContext;
|
|
29
|
+
if (filteredFiles.length > limit) {
|
|
30
|
+
finalFiles = filteredFiles.slice(0, limit);
|
|
31
|
+
excluded = filteredFiles.length - limit;
|
|
32
|
+
// Show warning when files are excluded
|
|
33
|
+
const fileTypeDesc = fileTypes ? `${fileTypes.join(', ')} files` : 'files';
|
|
34
|
+
console.warn(`⚠️ File limit reached: ${excluded} ${fileTypeDesc} excluded.`);
|
|
35
|
+
console.warn(` Processed: ${limit}/${filteredFiles.length} files`);
|
|
36
|
+
console.warn(` To process more files, increase 'limits.maxFilesPerContext' in your config file.`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
files: finalFiles,
|
|
41
|
+
totalFound: filteredFiles.length,
|
|
42
|
+
excluded,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get all project files (no file type filtering, for files.md)
|
|
47
|
+
*/
|
|
48
|
+
async getAllProjectFiles(rootDir) {
|
|
49
|
+
return this.getFiles(rootDir);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get code files for AST analysis (filtered by file types, for structure.json)
|
|
53
|
+
*/
|
|
54
|
+
async getCodeFiles(rootDir, fileTypes) {
|
|
55
|
+
const configData = this.config.get();
|
|
56
|
+
const defaultFileTypes = configData.analyzeFileTypes || ['ts', 'tsx', 'js', 'jsx'];
|
|
57
|
+
return this.getFiles(rootDir, {
|
|
58
|
+
fileTypes: fileTypes || defaultFileTypes,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare class FileFilterService {
|
|
2
|
+
private readonly excludePatterns;
|
|
3
|
+
private readonly useGitForFiles;
|
|
4
|
+
private readonly ig;
|
|
5
|
+
constructor(excludePatterns?: string[], useGitForFiles?: boolean);
|
|
6
|
+
/**
|
|
7
|
+
* Get all files that should be analyzed, respecting:
|
|
8
|
+
* 1. Git-tracked files (respects all .gitignore files automatically)
|
|
9
|
+
* 2. All files (if non-git repo) - respects only custom excludePatterns
|
|
10
|
+
* 3. Custom excludePatterns from config (always applied)
|
|
11
|
+
*/
|
|
12
|
+
getFilteredFiles(rootDir: string, fileExtensions?: string[]): Promise<string[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Check if the directory is a git repository
|
|
15
|
+
*/
|
|
16
|
+
private isGitRepository;
|
|
17
|
+
/**
|
|
18
|
+
* Get all tracked files from git
|
|
19
|
+
* This respects all .gitignore files in the repository (parent, current, and child dirs)
|
|
20
|
+
*/
|
|
21
|
+
private getGitTrackedFiles;
|
|
22
|
+
/**
|
|
23
|
+
* Get all files recursively (fallback for non-git repos)
|
|
24
|
+
*/
|
|
25
|
+
private getAllFilesRecursive;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a specific file should be filtered out
|
|
28
|
+
*/
|
|
29
|
+
shouldIgnore(filePath: string): boolean;
|
|
30
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { readdir, stat } from 'fs/promises';
|
|
3
|
+
import { join, relative } from 'path';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
export class FileFilterService {
|
|
8
|
+
excludePatterns;
|
|
9
|
+
useGitForFiles;
|
|
10
|
+
ig;
|
|
11
|
+
constructor(excludePatterns = [], useGitForFiles = true) {
|
|
12
|
+
this.excludePatterns = excludePatterns;
|
|
13
|
+
this.useGitForFiles = useGitForFiles;
|
|
14
|
+
this.ig = ignore();
|
|
15
|
+
this.ig.add(excludePatterns);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get all files that should be analyzed, respecting:
|
|
19
|
+
* 1. Git-tracked files (respects all .gitignore files automatically)
|
|
20
|
+
* 2. All files (if non-git repo) - respects only custom excludePatterns
|
|
21
|
+
* 3. Custom excludePatterns from config (always applied)
|
|
22
|
+
*/
|
|
23
|
+
async getFilteredFiles(rootDir, fileExtensions) {
|
|
24
|
+
try {
|
|
25
|
+
let files;
|
|
26
|
+
// Try to get git-tracked files first (only if useGitForFiles is enabled)
|
|
27
|
+
const isGitRepo = this.useGitForFiles && (await this.isGitRepository(rootDir));
|
|
28
|
+
if (isGitRepo) {
|
|
29
|
+
files = await this.getGitTrackedFiles(rootDir);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Fallback: get all files recursively
|
|
33
|
+
files = await this.getAllFilesRecursive(rootDir, rootDir);
|
|
34
|
+
}
|
|
35
|
+
// Apply custom exclude patterns
|
|
36
|
+
const filteredFiles = files.filter((file) => !this.ig.ignores(file));
|
|
37
|
+
// Optionally filter by file extensions
|
|
38
|
+
if (fileExtensions && fileExtensions.length > 0) {
|
|
39
|
+
const extensionSet = new Set(fileExtensions.map((ext) => (ext.startsWith('.') ? ext : `.${ext}`)));
|
|
40
|
+
return filteredFiles.filter((file) => {
|
|
41
|
+
const ext = file.substring(file.lastIndexOf('.'));
|
|
42
|
+
return extensionSet.has(ext);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return filteredFiles;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw new Error(`Failed to get filtered files: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if the directory is a git repository
|
|
53
|
+
*/
|
|
54
|
+
async isGitRepository(rootDir) {
|
|
55
|
+
try {
|
|
56
|
+
await execAsync('git rev-parse --git-dir', { cwd: rootDir });
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get all tracked files from git
|
|
65
|
+
* This respects all .gitignore files in the repository (parent, current, and child dirs)
|
|
66
|
+
*/
|
|
67
|
+
async getGitTrackedFiles(rootDir) {
|
|
68
|
+
const { stdout } = await execAsync('git ls-files', { cwd: rootDir });
|
|
69
|
+
return stdout
|
|
70
|
+
.split('\n')
|
|
71
|
+
.map((line) => line.trim())
|
|
72
|
+
.filter((line) => line);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get all files recursively (fallback for non-git repos)
|
|
76
|
+
*/
|
|
77
|
+
async getAllFilesRecursive(dir, rootDir) {
|
|
78
|
+
const entries = await readdir(dir);
|
|
79
|
+
const files = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
const fullPath = join(dir, entry);
|
|
82
|
+
const relativePath = relative(rootDir, fullPath);
|
|
83
|
+
const stats = await stat(fullPath);
|
|
84
|
+
if (stats.isFile()) {
|
|
85
|
+
files.push(relativePath);
|
|
86
|
+
}
|
|
87
|
+
else if (stats.isDirectory() && !entry.startsWith('.')) {
|
|
88
|
+
files.push(...(await this.getAllFilesRecursive(fullPath, rootDir)));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return files;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if a specific file should be filtered out
|
|
95
|
+
*/
|
|
96
|
+
shouldIgnore(filePath) {
|
|
97
|
+
return this.ig.ignores(filePath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { GitInfo } from '../types.js';
|
|
1
|
+
import type { GitInfo } from '../core/types.js';
|
|
3
2
|
export declare class GitAnalyzer {
|
|
4
|
-
private readonly config;
|
|
5
|
-
constructor(config: ParsemeConfig);
|
|
6
3
|
analyze(rootDir: string): Promise<GitInfo | null>;
|
|
7
4
|
private getCurrentBranch;
|
|
8
5
|
private getLastCommit;
|
|
@@ -2,10 +2,6 @@ import { exec } from 'child_process';
|
|
|
2
2
|
import { promisify } from 'util';
|
|
3
3
|
const execAsync = promisify(exec);
|
|
4
4
|
export class GitAnalyzer {
|
|
5
|
-
config;
|
|
6
|
-
constructor(config) {
|
|
7
|
-
this.config = config;
|
|
8
|
-
}
|
|
9
5
|
async analyze(rootDir) {
|
|
10
6
|
try {
|
|
11
7
|
// Check if this is a git repository
|
|
@@ -31,12 +31,3 @@ export async function prompt(options) {
|
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
export async function confirmPrompt(message, defaultValue = true) {
|
|
35
|
-
const answer = await prompt({
|
|
36
|
-
message,
|
|
37
|
-
defaultValue: defaultValue ? 'y' : 'n',
|
|
38
|
-
choices: ['y', 'n', 'yes', 'no'],
|
|
39
|
-
});
|
|
40
|
-
const normalized = answer.toLowerCase();
|
|
41
|
-
return normalized === 'y' || normalized === 'yes';
|
|
42
|
-
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parseme/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
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,16 @@
|
|
|
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",
|
|
28
|
-
"
|
|
29
|
-
"test:
|
|
30
|
-
"
|
|
31
|
-
"test:
|
|
32
|
-
"
|
|
27
|
+
"test": "node --test --experimental-test-coverage 'tests/**/*.test.ts'",
|
|
28
|
+
"pretest:unit": "npm run build",
|
|
29
|
+
"test:unit": "node --test 'tests/unit/**/*.test.ts'",
|
|
30
|
+
"pretest:integration": "npm run build",
|
|
31
|
+
"test:integration": "node --test 'tests/integration/**/*.test.ts'",
|
|
32
|
+
"test:watch": "node --test --watch 'tests/**/*.test.ts'",
|
|
33
|
+
"pretest:coverage": "npm run build",
|
|
34
|
+
"test:coverage": "node --test --experimental-test-coverage 'tests/unit/**/*.test.ts' 'tests/integration/**/*.test.ts'",
|
|
35
|
+
"test:setup:e2e": "npm run -C ../e2e setup",
|
|
36
|
+
"test:e2e": "npm run -C ../e2e test",
|
|
33
37
|
"clean": "rm -rf dist"
|
|
34
38
|
},
|
|
35
39
|
"keywords": [
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ParsemeConfig } from '../config.js';
|
|
2
|
-
import type { ProjectInfo, FrameworkInfo } from '../types.js';
|
|
3
|
-
export declare class FrameworkDetector {
|
|
4
|
-
private readonly config;
|
|
5
|
-
constructor(config: ParsemeConfig);
|
|
6
|
-
detect(projectInfo: ProjectInfo): Promise<FrameworkInfo>;
|
|
7
|
-
private detectExpress;
|
|
8
|
-
private detectFastify;
|
|
9
|
-
private detectNestJS;
|
|
10
|
-
private detectKoa;
|
|
11
|
-
private detectHapi;
|
|
12
|
-
}
|