Skip to content

Commit 6fd41c9

Browse files
committed
tests-galore
1 parent b6ad7fc commit 6fd41c9

File tree

17 files changed

+2867
-260
lines changed

17 files changed

+2867
-260
lines changed

src/commands/rg/file-types.ts

Lines changed: 140 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export interface FileType {
1414
* Built-in file type definitions
1515
* Use `rg --type-list` to see all types in real ripgrep
1616
*/
17-
export const FILE_TYPES: Record<string, FileType> = {
17+
const FILE_TYPES: Record<string, FileType> = {
1818
// Web languages
1919
js: { extensions: [".js", ".mjs", ".cjs", ".jsx"], globs: [] },
2020
ts: { extensions: [".ts", ".tsx", ".mts", ".cts"], globs: [] },
@@ -86,37 +86,157 @@ export const FILE_TYPES: Record<string, FileType> = {
8686
};
8787

8888
/**
89-
* Check if a filename matches any of the specified types
89+
* Mutable file type registry for runtime type modifications
90+
* Supports --type-add and --type-clear flags
9091
*/
91-
export function matchesType(filename: string, types: string[]): boolean {
92-
const lowerFilename = filename.toLowerCase();
92+
export class FileTypeRegistry {
93+
private types: Map<string, FileType>;
9394

94-
for (const typeName of types) {
95-
const fileType = FILE_TYPES[typeName];
96-
if (!fileType) continue;
95+
constructor() {
96+
// Clone default types
97+
this.types = new Map(
98+
Object.entries(FILE_TYPES).map(([name, type]) => [
99+
name,
100+
{ extensions: [...type.extensions], globs: [...type.globs] },
101+
]),
102+
);
103+
}
104+
105+
/**
106+
* Add a type definition
107+
* Format: "name:pattern" where pattern can be:
108+
* - "*.ext" - glob pattern
109+
* - "include:other" - include patterns from another type
110+
*/
111+
addType(spec: string): void {
112+
const colonIdx = spec.indexOf(":");
113+
if (colonIdx === -1) return;
114+
115+
const name = spec.slice(0, colonIdx);
116+
const pattern = spec.slice(colonIdx + 1);
97117

98-
// Check extensions
99-
for (const ext of fileType.extensions) {
100-
if (lowerFilename.endsWith(ext)) {
101-
return true;
118+
if (pattern.startsWith("include:")) {
119+
// Include patterns from another type
120+
const otherName = pattern.slice(8);
121+
const other = this.types.get(otherName);
122+
if (other) {
123+
const existing = this.types.get(name) || { extensions: [], globs: [] };
124+
existing.extensions.push(...other.extensions);
125+
existing.globs.push(...other.globs);
126+
this.types.set(name, existing);
102127
}
128+
} else {
129+
// Add glob pattern
130+
const existing = this.types.get(name) || { extensions: [], globs: [] };
131+
// If pattern is like "*.ext", add to extensions
132+
if (pattern.startsWith("*.") && !pattern.slice(2).includes("*")) {
133+
const ext = pattern.slice(1); // Keep the dot
134+
if (!existing.extensions.includes(ext)) {
135+
existing.extensions.push(ext);
136+
}
137+
} else {
138+
// Add as glob pattern
139+
if (!existing.globs.includes(pattern)) {
140+
existing.globs.push(pattern);
141+
}
142+
}
143+
this.types.set(name, existing);
144+
}
145+
}
146+
147+
/**
148+
* Clear all patterns from a type
149+
*/
150+
clearType(name: string): void {
151+
const existing = this.types.get(name);
152+
if (existing) {
153+
existing.extensions = [];
154+
existing.globs = [];
103155
}
156+
}
157+
158+
/**
159+
* Get a type by name
160+
*/
161+
getType(name: string): FileType | undefined {
162+
return this.types.get(name);
163+
}
164+
165+
/**
166+
* Get all type names
167+
*/
168+
getAllTypes(): Map<string, FileType> {
169+
return this.types;
170+
}
171+
172+
/**
173+
* Check if a filename matches any of the specified types
174+
*/
175+
matchesType(filename: string, typeNames: string[]): boolean {
176+
const lowerFilename = filename.toLowerCase();
177+
178+
for (const typeName of typeNames) {
179+
// Special case: 'all' matches any file with a recognized type
180+
if (typeName === "all") {
181+
if (this.matchesAnyType(filename)) {
182+
return true;
183+
}
184+
continue;
185+
}
186+
187+
const fileType = this.types.get(typeName);
188+
if (!fileType) continue;
104189

105-
// Check globs (simple exact match for now)
106-
for (const glob of fileType.globs) {
107-
if (glob.includes("*")) {
108-
// Simple glob matching
109-
const pattern = glob.replace(/\./g, "\\.").replace(/\*/g, ".*");
110-
if (new RegExp(`^${pattern}$`, "i").test(filename)) {
190+
// Check extensions
191+
for (const ext of fileType.extensions) {
192+
if (lowerFilename.endsWith(ext)) {
193+
return true;
194+
}
195+
}
196+
197+
// Check globs
198+
for (const glob of fileType.globs) {
199+
if (glob.includes("*")) {
200+
const pattern = glob.replace(/\./g, "\\.").replace(/\*/g, ".*");
201+
if (new RegExp(`^${pattern}$`, "i").test(filename)) {
202+
return true;
203+
}
204+
} else if (lowerFilename === glob.toLowerCase()) {
111205
return true;
112206
}
113-
} else if (lowerFilename === glob.toLowerCase()) {
114-
return true;
115207
}
116208
}
209+
210+
return false;
117211
}
118212

119-
return false;
213+
/**
214+
* Check if a filename matches any recognized type
215+
*/
216+
private matchesAnyType(filename: string): boolean {
217+
const lowerFilename = filename.toLowerCase();
218+
219+
for (const fileType of this.types.values()) {
220+
for (const ext of fileType.extensions) {
221+
if (lowerFilename.endsWith(ext)) {
222+
return true;
223+
}
224+
}
225+
226+
for (const glob of fileType.globs) {
227+
if (glob.includes("*")) {
228+
const pattern = glob.replace(/\./g, "\\.").replace(/\*/g, ".*");
229+
if (new RegExp(`^${pattern}$`, "i").test(filename)) {
230+
return true;
231+
}
232+
} else if (lowerFilename === glob.toLowerCase()) {
233+
return true;
234+
}
235+
}
236+
}
237+
238+
return false;
239+
}
120240
}
121241

122242
/**

0 commit comments

Comments
 (0)