Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion gitnexus/src/config/ignore-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,65 @@ const IGNORED_FILES = new Set([



// User-defined ignore patterns loaded from .gitnexusignore
let userIgnorePatterns: string[] = [];
let userIgnoreLoaded = false;

/**
* Load .gitnexusignore from the repo root. Called once per analysis.
* Format: one pattern per line, # comments, blank lines ignored.
* Patterns are path prefixes (e.g., "app/engine/source/") or
* directory names (e.g., "workspace") matched against path segments.
*/
export const loadIgnoreFile = async (repoPath: string): Promise<void> => {
if (userIgnoreLoaded) return;
userIgnoreLoaded = true;

const fs = await import('fs/promises');
const path = await import('path');
const ignorePath = path.join(repoPath, '.gitnexusignore');

try {
const content = await fs.readFile(ignorePath, 'utf-8');
userIgnorePatterns = content
.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0 && !line.startsWith('#'));
} catch {
// No .gitnexusignore file — that's fine
userIgnorePatterns = [];
}
};

/** Reset loaded state (for testing or re-indexing) */
export const resetIgnoreFile = (): void => {
userIgnorePatterns = [];
userIgnoreLoaded = false;
};

export const shouldIgnorePath = (filePath: string): boolean => {
const normalizedPath = filePath.replace(/\\/g, '/');
const parts = normalizedPath.split('/');
const fileName = parts[parts.length - 1];
const fileNameLower = fileName.toLowerCase();

// Check if any path segment is in ignore list
// Check user-defined .gitnexusignore patterns first
for (const pattern of userIgnorePatterns) {
// Path prefix match: "app/engine/source/" matches "app/engine/source/foo.ts"
if (pattern.includes('/')) {
const cleanPattern = pattern.replace(/\/+$/, '');
if (normalizedPath.startsWith(cleanPattern + '/') || normalizedPath === cleanPattern) {
return true;
}
} else {
// Directory name match: "workspace" matches any path segment
if (parts.includes(pattern)) {
return true;
}
}
}

// Check if any path segment is in default ignore list
for (const part of parts) {
if (DEFAULT_IGNORE_LIST.has(part)) {
return true;
Expand Down
5 changes: 4 additions & 1 deletion gitnexus/src/core/ingestion/filesystem-walker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs/promises';
import path from 'path';
import { glob } from 'glob';
import { shouldIgnorePath } from '../../config/ignore-service.js';
import { shouldIgnorePath, loadIgnoreFile } from '../../config/ignore-service.js';

export interface FileEntry {
path: string;
Expand Down Expand Up @@ -32,6 +32,9 @@ export const walkRepositoryPaths = async (
repoPath: string,
onProgress?: (current: number, total: number, filePath: string) => void
): Promise<ScannedFile[]> => {
// Load .gitnexusignore before filtering
await loadIgnoreFile(repoPath);

const files = await glob('**/*', {
cwd: repoPath,
nodir: true,
Expand Down