Skip to content

Commit

Permalink
Merge pull request #337 from matheuscoelhomalta/fix/support-parenthes…
Browse files Browse the repository at this point in the history
…es-in-paths

Fix/support parentheses in paths
  • Loading branch information
yamadashy authored Feb 7, 2025
2 parents b6dc403 + 86de7c1 commit 091df27
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/core/file/fileSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ const isGitWorktreeRef = async (gitPath: string): Promise<boolean> => {
}
};

/**
* Escapes special characters in glob patterns to handle paths with parentheses.
* Example: "src/(categories)" -> "src/\\(categories\\)"
*/
export const escapeGlobPattern = (pattern: string): string => {
// First escape backslashes
const escapedBackslashes = pattern.replace(/\\/g, '\\\\');
// Then escape special characters
return escapedBackslashes.replace(/[()[\]{}]/g, '\\$&');
};

// Get all file paths considering the config
export const searchFiles = async (rootDir: string, config: RepomixConfigMerged): Promise<FileSearchResult> => {
// First check directory permissions
Expand All @@ -69,7 +80,8 @@ export const searchFiles = async (rootDir: string, config: RepomixConfigMerged):
throw new Error(`Cannot access directory ${rootDir}: ${permissionCheck.error?.message}`);
}

const includePatterns = config.include.length > 0 ? config.include : ['**/*'];
const includePatterns =
config.include.length > 0 ? config.include.map((pattern) => escapeGlobPattern(pattern)) : ['**/*'];

try {
const [ignorePatterns, ignoreFilePatterns] = await Promise.all([
Expand Down
47 changes: 47 additions & 0 deletions tests/core/file/fileSearch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { globby } from 'globby';
import { minimatch } from 'minimatch';
import { beforeEach, describe, expect, test, vi } from 'vitest';
import {
escapeGlobPattern,
getIgnoreFilePatterns,
getIgnorePatterns,
parseIgnoreContent,
Expand Down Expand Up @@ -342,4 +343,50 @@ node_modules
expect(result.filePaths).toEqual(['file1.js', 'file2.js']);
});
});

describe('escapeGlobPattern', () => {
test('should escape parentheses in pattern', () => {
const pattern = 'src/(categories)/**/*.ts';
expect(escapeGlobPattern(pattern)).toBe('src/\\(categories\\)/**/*.ts');
});

test('should escape multiple types of brackets', () => {
const pattern = 'src/(auth)/[id]/{slug}/**/*.ts';
expect(escapeGlobPattern(pattern)).toBe('src/\\(auth\\)/\\[id\\]/\\{slug\\}/**/*.ts');
});

test('should handle nested brackets', () => {
const pattern = 'src/(auth)/([id])/**/*.ts';
expect(escapeGlobPattern(pattern)).toBe('src/\\(auth\\)/\\(\\[id\\]\\)/**/*.ts');
});

test('should handle empty string', () => {
expect(escapeGlobPattern('')).toBe('');
});

test('should not modify patterns without special characters', () => {
const pattern = 'src/components/**/*.ts';
expect(escapeGlobPattern(pattern)).toBe(pattern);
});

test('should handle multiple occurrences of the same bracket type', () => {
const pattern = 'src/(auth)/(settings)/**/*.ts';
expect(escapeGlobPattern(pattern)).toBe('src/\\(auth\\)/\\(settings\\)/**/*.ts');
});
});

test('should escape backslashes in pattern', () => {
const pattern = 'src\\temp\\(categories)';
expect(escapeGlobPattern(pattern)).toBe('src\\\\temp\\\\\\(categories\\)');
});

test('should handle patterns with already escaped special characters', () => {
const pattern = 'src\\\\(categories)';
expect(escapeGlobPattern(pattern)).toBe('src\\\\\\\\\\(categories\\)');
});

test('should handle patterns with mixed backslashes and special characters', () => {
const pattern = 'src\\temp\\[id]\\{slug}';
expect(escapeGlobPattern(pattern)).toBe('src\\\\temp\\\\\\[id\\]\\\\\\{slug\\}');
});
});

0 comments on commit 091df27

Please sign in to comment.