Skip to content

Commit 53bcc8e

Browse files
authored
Merge pull request #1395 from quarto-dev/bugfix/exc-glob
Smart glob handling incorrectly ignoring `!`
2 parents cfb7d4c + 3fde385 commit 53bcc8e

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

src/core/path.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,28 @@ export function resolveGlobs(
189189
const excludeGlobs: string[] = [];
190190

191191
// deal with implicit ** syntax and ability to escape negation (!)
192-
const asFullGlob = (glob: string) => {
193-
const preventSmartGlobs = options?.mode === "strict" ||
194-
(options?.mode === "auto" && !isGlob(glob));
192+
const asFullGlob = (glob: string, preferSmart?: boolean) => {
193+
const useSmartGlobs = () => {
194+
if (options?.mode === "strict") {
195+
return false;
196+
} else if (options?.mode === "always") {
197+
return true;
198+
} else {
199+
if (preferSmart) {
200+
return true;
201+
} else {
202+
return isGlob(glob);
203+
}
204+
}
205+
};
206+
const smartGlob = useSmartGlobs();
195207

196208
// handle negation
197209
if (glob.startsWith("\\!")) {
198210
glob = glob.slice(1);
199211
}
200212
// ending w/ a slash means everything in the dir
201-
if (!preventSmartGlobs) {
213+
if (smartGlob) {
202214
if (glob.endsWith("/")) {
203215
glob = glob + "**/*";
204216
} else {
@@ -215,7 +227,7 @@ export function resolveGlobs(
215227
}
216228

217229
if (!glob.startsWith("/")) {
218-
if (!preventSmartGlobs) {
230+
if (smartGlob) {
219231
return "**/" + glob;
220232
} else {
221233
return glob;
@@ -228,7 +240,9 @@ export function resolveGlobs(
228240
// divide globs into include and exclude
229241
for (const glob of globs) {
230242
if (glob.startsWith("!")) {
231-
excludeGlobs.push(asFullGlob(glob.slice(1)));
243+
// We should always force smart globs in the event
244+
// of excludes since these would normally qualify
245+
excludeGlobs.push(asFullGlob(glob.slice(1), true));
232246
} else {
233247
includeGlobs.push(asFullGlob(glob));
234248
}

tests/unit/glob.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* glob.test.ts
3+
*
4+
* Copyright (C) 2020 by RStudio, PBC
5+
*
6+
*/
7+
import { assert, assertEquals } from "testing/asserts.ts";
8+
import { filterPaths } from "../../src/core/path.ts";
9+
import { unitTest } from "../test.ts";
10+
11+
unitTest(
12+
"globs",
13+
//deno-lint-ignore require-await
14+
async () => {
15+
const paths = [
16+
"/test.qmd",
17+
"/test2.qmd",
18+
"/test3.qmd",
19+
"/folder/test.qmd",
20+
"/folder/test2.qmd",
21+
"/folder/test.txt",
22+
];
23+
24+
const globDescs = [
25+
{ globs: ["*.qmd"], includes: 5, excludes: 0 },
26+
{ globs: ["**"], includes: 6, excludes: 0 },
27+
{ globs: ["*.qmd", "!folder"], includes: 5, excludes: 0 },
28+
{ globs: ["*.qmd", "!folder/"], includes: 5, excludes: 3 },
29+
{ globs: ["test*.*", "!folder/"], includes: 6, excludes: 3 },
30+
{ globs: ["test*.*", "!*.txt"], includes: 6, excludes: 1 },
31+
{ globs: ["folder/*.txt"], includes: 1, excludes: 0 },
32+
{ globs: ["folder/*.*", "!*.txt"], includes: 3, excludes: 1 },
33+
{ globs: ["folder/**"], includes: 3, excludes: 0 },
34+
{ globs: ["test2.*", "!folder/"], includes: 2, excludes: 3 },
35+
];
36+
for (const globDesc of globDescs) {
37+
const filtered = filterPaths("/", paths, globDesc.globs);
38+
assert(
39+
filtered.include.length === globDesc.includes,
40+
`Globs [${
41+
globDesc.globs.join(",")
42+
}] result in the wrong number of 'includes' matches.`,
43+
);
44+
assert(
45+
filtered.exclude.length === globDesc.excludes,
46+
`Globs [${
47+
globDesc.globs.join(",")
48+
}] result in the wrong number of 'excludes' matches.`,
49+
);
50+
}
51+
},
52+
);

0 commit comments

Comments
 (0)