Skip to content

Commit 995b9f7

Browse files
committed
feat(git): refine sparse pattern cone mode
1 parent d5d3bb2 commit 995b9f7

1 file changed

Lines changed: 46 additions & 15 deletions

File tree

src/git/fetch-source.ts

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -289,28 +289,59 @@ const patternHasGlob = (pattern: string) =>
289289
const normalizeSparsePatterns = (include?: string[]) =>
290290
(include ?? []).map((pattern) => pattern.replace(/\\/g, "/")).filter(Boolean);
291291

292+
const isDirectoryLiteral = (pattern: string) => {
293+
if (pattern.endsWith("/")) {
294+
return true;
295+
}
296+
const base = pattern.split("/").pop() ?? "";
297+
return !base.includes(".");
298+
};
299+
300+
const toNoConePattern = (pattern: string) => {
301+
if (!patternHasGlob(pattern) && isDirectoryLiteral(pattern)) {
302+
return pattern.endsWith("/") ? pattern : `${pattern}/`;
303+
}
304+
return pattern;
305+
};
306+
292307
const resolveSparseSpec = (include?: string[]) => {
293308
const normalized = normalizeSparsePatterns(include);
294309
if (normalized.length === 0) {
295310
return { enabled: false, mode: "cone" as const, patterns: [] as string[] };
296311
}
297-
const hasDoubleStar = normalized.some((pattern) => pattern.includes("**"));
298-
const hasLiteral = normalized.some((pattern) => !patternHasGlob(pattern));
299-
if (hasDoubleStar || hasLiteral) {
300-
return { enabled: true, mode: "no-cone" as const, patterns: normalized };
312+
const conePaths: string[] = [];
313+
let coneEligible = true;
314+
for (const pattern of normalized) {
315+
if (pattern.includes("**")) {
316+
coneEligible = false;
317+
break;
318+
}
319+
if (!patternHasGlob(pattern)) {
320+
if (isDirectoryLiteral(pattern)) {
321+
conePaths.push(pattern.replace(/\/+$/, ""));
322+
continue;
323+
}
324+
coneEligible = false;
325+
break;
326+
}
327+
const globIndex = pattern.search(/[*?[]/);
328+
const base = globIndex === -1 ? pattern : pattern.slice(0, globIndex);
329+
const trimmed = base.replace(/\/+$/, "");
330+
if (!trimmed) {
331+
coneEligible = false;
332+
break;
333+
}
334+
conePaths.push(trimmed);
301335
}
302-
const paths = normalized.map((pattern) => {
303-
const starIndex = pattern.indexOf("*");
304-
const base = starIndex === -1 ? pattern : pattern.slice(0, starIndex);
305-
return base.replace(/\/+$|\/$/, "");
306-
});
307-
const uniquePaths = Array.from(
308-
new Set(paths.filter((value) => value.length > 0)),
309-
);
310-
if (uniquePaths.length === 0) {
311-
return { enabled: true, mode: "no-cone" as const, patterns: normalized };
336+
const uniquePaths = Array.from(new Set(conePaths.filter(Boolean)));
337+
if (coneEligible && uniquePaths.length > 0) {
338+
return { enabled: true, mode: "cone" as const, patterns: uniquePaths };
312339
}
313-
return { enabled: true, mode: "cone" as const, patterns: uniquePaths };
340+
return {
341+
enabled: true,
342+
mode: "no-cone" as const,
343+
patterns: normalized.map(toNoConePattern),
344+
};
314345
};
315346

316347
const cloneRepo = async (params: FetchParams, outDir: string) => {

0 commit comments

Comments
 (0)