Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement expandGlob() #617

Merged
merged 20 commits into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename glob() to globToRegExp(), restructure glob related interfaces
  • Loading branch information
nayeemrmn committed Sep 28, 2019
commit b6af0a7a4d617ac467f6c77968485891da927b22
42 changes: 15 additions & 27 deletions fs/glob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@ import { WalkInfo, walk, walkSync } from "./walk.ts";
const { cwd } = Deno;

export interface GlobOptions {
// Allow ExtGlob features
extended?: boolean;
// When globstar is true, '/foo/**' is equivelant
// to '/foo/*' when globstar is false.
// Having globstar set to true is the same usage as
// using wildcards in bash
globstar?: boolean;
// be laissez faire about mutiple slashes
strict?: boolean;
// Parse as filepath for extra path related features
filepath?: boolean;
// Flag to use in the generated RegExp
}

export interface GlobToRegExpOptions extends GlobOptions {
flags?: string;
}

Expand All @@ -27,12 +21,12 @@ export interface GlobOptions {
*
* Looking for all the `ts` files:
* walkSync(".", {
* match: [glob("*.ts")]
* match: [globToRegExp("*.ts")]
* })
*
* Looking for all the `.json` files in any subfolder:
* walkSync(".", {
* match: [glob(join("a", "**", "*.json"),{
* match: [globToRegExp(join("a", "**", "*.json"),{
* flags: "g",
* extended: true,
* globstar: true
Expand All @@ -43,12 +37,12 @@ export interface GlobOptions {
* @param options - Specific options for the glob pattern
* @returns A RegExp for the glob pattern
*/
export function glob(glob: string, options: GlobOptions = {}): RegExp {
const result = globrex(glob, options);
if (options.filepath) {
return result.path!.regex;
}
return result.regex;
export function globToRegExp(
glob: string,
options: GlobToRegExpOptions = {}
): RegExp {
const result = globrex(glob, { ...options, filepath: true });
return result.path!.regex;
}

/** Test whether the given string is a glob */
Expand Down Expand Up @@ -103,17 +97,14 @@ export async function* expandGlob(
includeDirs = true,
extended = false,
globstar = false,
strict = false,
filepath = true,
flags = ""
strict = false
}: ExpandGlobOptions = {}
): AsyncIterableIterator<WalkInfo> {
const absoluteGlob = isAbsolute(globString)
? globString
: join(root, globString);
const globOptions = { extended, globstar, strict, filepath, flags };
yield* walk(root, {
match: [glob(absoluteGlob, globOptions)],
match: [globToRegExp(absoluteGlob, { extended, globstar, strict })],
includeDirs
});
}
Expand All @@ -127,17 +118,14 @@ export function* expandGlobSync(
includeDirs = true,
extended = false,
globstar = false,
strict = false,
filepath = true,
flags = ""
strict = false
}: ExpandGlobOptions = {}
): IterableIterator<WalkInfo> {
const absoluteGlob = isAbsolute(globString)
? globString
: join(root, globString);
const globOptions = { extended, globstar, strict, filepath, flags };
yield* walkSync(root, {
match: [glob(absoluteGlob, globOptions)],
match: [globToRegExp(absoluteGlob, { extended, globstar, strict })],
includeDirs
});
}
38 changes: 18 additions & 20 deletions fs/glob_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isWindows } from "./path/constants.ts";
import {
ExpandGlobOptions,
expandGlob,
glob,
globToRegExp,
isGlob,
expandGlobSync
} from "./glob.ts";
Expand All @@ -17,37 +17,37 @@ import { touch, walkArray } from "./walk_test.ts";
test({
name: "glob: glob to regex",
fn(): void {
assertEquals(glob("unicorn.*") instanceof RegExp, true);
assertEquals(glob("unicorn.*").test("poney.ts"), false);
assertEquals(glob("unicorn.*").test("unicorn.py"), true);
assertEquals(glob("*.ts").test("poney.ts"), true);
assertEquals(glob("*.ts").test("unicorn.js"), false);
assertEquals(globToRegExp("unicorn.*") instanceof RegExp, true);
assertEquals(globToRegExp("unicorn.*").test("poney.ts"), false);
assertEquals(globToRegExp("unicorn.*").test("unicorn.py"), true);
assertEquals(globToRegExp("*.ts").test("poney.ts"), true);
assertEquals(globToRegExp("*.ts").test("unicorn.js"), false);
assertEquals(
glob(join("unicorn", "**", "cathedral.ts")).test(
globToRegExp(join("unicorn", "**", "cathedral.ts")).test(
join("unicorn", "in", "the", "cathedral.ts")
),
true
);
assertEquals(
glob(join("unicorn", "**", "cathedral.ts")).test(
globToRegExp(join("unicorn", "**", "cathedral.ts")).test(
join("unicorn", "in", "the", "kitchen.ts")
),
false
);
assertEquals(
glob(join("unicorn", "**", "bathroom.*")).test(
globToRegExp(join("unicorn", "**", "bathroom.*")).test(
join("unicorn", "sleeping", "in", "bathroom.py")
),
true
);
assertEquals(
glob(join("unicorn", "!(sleeping)", "bathroom.ts"), {
globToRegExp(join("unicorn", "!(sleeping)", "bathroom.ts"), {
extended: true
}).test(join("unicorn", "flying", "bathroom.ts")),
true
);
assertEquals(
glob(join("unicorn", "(!sleeping)", "bathroom.ts"), {
globToRegExp(join("unicorn", "(!sleeping)", "bathroom.ts"), {
extended: true
}).test(join("unicorn", "sleeping", "bathroom.ts")),
false
Expand All @@ -61,7 +61,7 @@ testWalk(
await touch(d + "/a/x.ts");
},
async function globInWalk(): Promise<void> {
const arr = await walkArray(".", { match: [glob("*.ts")] });
const arr = await walkArray(".", { match: [globToRegExp("*.ts")] });
assertEquals(arr.length, 1);
assertEquals(arr[0], "a/x.ts");
}
Expand All @@ -76,7 +76,7 @@ testWalk(
await touch(d + "/b/z.js");
},
async function globInWalkWildcardFiles(): Promise<void> {
const arr = await walkArray(".", { match: [glob("*.ts")] });
const arr = await walkArray(".", { match: [globToRegExp("*.ts")] });
assertEquals(arr.length, 2);
assertEquals(arr[0], "a/x.ts");
assertEquals(arr[1], "b/z.ts");
Expand All @@ -92,7 +92,7 @@ testWalk(
async function globInWalkFolderWildcard(): Promise<void> {
const arr = await walkArray(".", {
match: [
glob(join("a", "**", "*.ts"), {
globToRegExp(join("a", "**", "*.ts"), {
flags: "g",
globstar: true
})
Expand All @@ -116,7 +116,7 @@ testWalk(
async function globInWalkFolderExtended(): Promise<void> {
const arr = await walkArray(".", {
match: [
glob(join("a", "+(raptor|deno)", "*.ts"), {
globToRegExp(join("a", "+(raptor|deno)", "*.ts"), {
flags: "g",
extended: true
})
Expand All @@ -136,7 +136,7 @@ testWalk(
},
async function globInWalkWildcardExtension(): Promise<void> {
const arr = await walkArray(".", {
match: [glob("x.*", { flags: "g", globstar: true })]
match: [globToRegExp("x.*", { flags: "g", globstar: true })]
});
assertEquals(arr.length, 2);
assertEquals(arr[0], "x.js");
Expand Down Expand Up @@ -288,14 +288,12 @@ function urlToFilePath(url: URL): string {
return url.pathname.slice(url.protocol == "file:" && isWindows ? 1 : 0);
}

const EG_OPTIONS = {
const EG_OPTIONS: ExpandGlobOptions = {
root: urlToFilePath(new URL(join("testdata", "glob"), import.meta.url)),
includeDirs: true,
extended: false,
globstar: false,
strict: false,
filepath: false,
flags: ""
strict: false
};

test(async function expandGlobExt(): Promise<void> {
Expand Down
20 changes: 17 additions & 3 deletions fs/globrex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// MIT License
// Copyright (c) 2018 Terkel Gjervig Nielsen

import { GlobOptions } from "./glob.ts";

const isWin = Deno.build.os === "win";
const SEP = isWin ? `(\\\\+|\\/)` : `\\/`;
const SEP_ESC = isWin ? `\\\\` : `/`;
Expand All @@ -13,6 +11,22 @@ const WILDCARD = `([^${SEP_ESC}/]*)`;
const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}/]*(?:${SEP_ESC}|\/|$))*)`;
const WILDCARD_SEGMENT = `([^${SEP_ESC}/]*)`;

export interface GlobrexOptions {
// Allow ExtGlob features
extended?: boolean;
// When globstar is true, '/foo/**' is equivelant
// to '/foo/*' when globstar is false.
// Having globstar set to true is the same usage as
// using wildcards in bash
globstar?: boolean;
// be laissez faire about mutiple slashes
strict?: boolean;
// Parse as filepath for extra path related features
filepath?: boolean;
// Flag to use in the generated RegExp
flags?: string;
}

export interface GlobrexResult {
regex: RegExp;
path?: {
Expand Down Expand Up @@ -41,7 +55,7 @@ export function globrex(
strict = false,
filepath = false,
flags = ""
}: GlobOptions = {}
}: GlobrexOptions = {}
): GlobrexResult {
let regex = "";
let segment = "";
Expand Down
17 changes: 12 additions & 5 deletions prettier/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
// This script formats the given source files. If the files are omitted, it
// formats the all files in the repository.
import { ExpandGlobOptions, expandGlob, glob } from "../fs/glob.ts";
import { isAbsolute, join } from "../fs/path/mod.ts";
import { WalkInfo } from "../fs/walk.ts";
import { parse } from "../flags/mod.ts";
import {
ExpandGlobOptions,
WalkInfo,
expandGlob,
globToRegExp
} from "../fs/mod.ts";
import { isAbsolute, join } from "../fs/path/mod.ts";
import { prettier, prettierPlugins } from "./prettier.ts";
const { args, cwd, exit, readAll, readFile, stdin, stdout, writeFile } = Deno;

Expand Down Expand Up @@ -308,14 +312,17 @@ async function* getTargetFiles(
root,
extended: true,
globstar: true,
filepath: true
strict: false
};

// TODO: We use the `g` flag here to support path prefixes when specifying
// excludes. Replace with a solution that does this more correctly.
const excludePathPatterns = exclude.map(
(s: string): RegExp =>
glob(isAbsolute(s) ? s : join(root, s), { ...expandGlobOpts, flags: "g" })
globToRegExp(isAbsolute(s) ? s : join(root, s), {
...expandGlobOpts,
flags: "g"
})
);
const shouldInclude = ({ filename }: WalkInfo): boolean =>
!excludePathPatterns.some((p: RegExp): boolean => !!filename.match(p));
Expand Down
14 changes: 11 additions & 3 deletions testing/runner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#!/usr/bin/env -S deno -A
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { parse } from "../flags/mod.ts";
import { WalkInfo, expandGlob, glob, ExpandGlobOptions } from "../fs/mod.ts";
import {
ExpandGlobOptions,
WalkInfo,
expandGlob,
globToRegExp
} from "../fs/mod.ts";
import { isWindows } from "../fs/path/constants.ts";
import { isAbsolute, join } from "../fs/path/mod.ts";
import { RunTestsOptions, runTests } from "./mod.ts";
Expand Down Expand Up @@ -76,14 +81,17 @@ export async function* findTestModules(
root,
extended: true,
globstar: true,
filepath: true
strict: false
};

// TODO: We use the `g` flag here to support path prefixes when specifying
// excludes. Replace with a solution that does this more correctly.
const excludePathPatterns = excludePaths.map(
(s: string): RegExp =>
glob(isAbsolute(s) ? s : join(root, s), { ...expandGlobOpts, flags: "g" })
globToRegExp(isAbsolute(s) ? s : join(root, s), {
...expandGlobOpts,
flags: "g"
})
);
const excludeUrlPatterns = excludeUrls.map(
(url: string): RegExp => RegExp(url)
Expand Down