@parseme/cli 0.0.4 → 0.0.6

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.
@@ -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,4 +1,4 @@
1
- import type { GitInfo } from '../types.js';
1
+ import type { GitInfo } from '../core/types.js';
2
2
  export declare class GitAnalyzer {
3
3
  analyze(rootDir: string): Promise<GitInfo | null>;
4
4
  private getCurrentBranch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parseme/cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
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",
@@ -24,11 +24,14 @@
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
- "test:unit": "node --test tests/unit/**/*.test.ts",
29
- "test:integration": "node --test tests/integration/**/*.test.ts",
30
- "test:watch": "node --test --watch tests/**/*.test.ts",
31
- "test:coverage": "node --test --experimental-test-coverage tests/**/*.test.ts",
27
+ "test": "node --test 'tests/**/*.test.ts'",
28
+ "pretest": "npm run build",
29
+ "test:unit": "node --test 'tests/unit/**/*.test.ts'",
30
+ "test:integration": "node --test 'tests/integration/**/*.test.ts'",
31
+ "test:watch": "node --test --watch 'tests/**/*.test.ts'",
32
+ "test:coverage": "node --test --experimental-test-coverage 'tests/unit/**/*.test.ts' 'tests/integration/**/*.test.ts'",
33
+ "test:setup:e2e": "npm run -C ../e2e setup",
34
+ "test:e2e": "npm run -C ../e2e test",
32
35
  "clean": "rm -rf dist"
33
36
  },
34
37
  "keywords": [
File without changes
File without changes