mirror of
https://github.com/denoland/deno.git
synced 2024-11-14 16:33:45 -05:00
124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
import { SEP, SEP_PATTERN } from "./constants.ts";
|
|
import { globrex } from "./globrex.ts";
|
|
import { join, normalize } from "./mod.ts";
|
|
import { assert } from "../testing/asserts.ts";
|
|
|
|
export interface GlobOptions {
|
|
extended?: boolean;
|
|
globstar?: boolean;
|
|
}
|
|
|
|
export interface GlobToRegExpOptions extends GlobOptions {
|
|
flags?: string;
|
|
}
|
|
|
|
/**
|
|
* Generate a regex based on glob pattern and options
|
|
* This was meant to be using the the `fs.walk` function
|
|
* but can be used anywhere else.
|
|
* Examples:
|
|
*
|
|
* Looking for all the `ts` files:
|
|
* walkSync(".", {
|
|
* match: [globToRegExp("*.ts")]
|
|
* })
|
|
*
|
|
* Looking for all the `.json` files in any subfolder:
|
|
* walkSync(".", {
|
|
* match: [globToRegExp(join("a", "**", "*.json"),{
|
|
* flags: "g",
|
|
* extended: true,
|
|
* globstar: true
|
|
* })]
|
|
* })
|
|
*
|
|
* @param glob - Glob pattern to be used
|
|
* @param options - Specific options for the glob pattern
|
|
* @returns A RegExp for the glob pattern
|
|
*/
|
|
export function globToRegExp(
|
|
glob: string,
|
|
{ extended = false, globstar = true }: GlobToRegExpOptions = {}
|
|
): RegExp {
|
|
const result = globrex(glob, {
|
|
extended,
|
|
globstar,
|
|
strict: false,
|
|
filepath: true
|
|
});
|
|
assert(result.path != null);
|
|
return result.path.regex;
|
|
}
|
|
|
|
/** Test whether the given string is a glob */
|
|
export function isGlob(str: string): boolean {
|
|
const chars: Record<string, string> = { "{": "}", "(": ")", "[": "]" };
|
|
/* eslint-disable-next-line max-len */
|
|
const regex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
|
|
|
|
if (str === "") {
|
|
return false;
|
|
}
|
|
|
|
let match: RegExpExecArray | null;
|
|
|
|
while ((match = regex.exec(str))) {
|
|
if (match[2]) return true;
|
|
let idx = match.index + match[0].length;
|
|
|
|
// if an open bracket/brace/paren is escaped,
|
|
// set the index to the next closing character
|
|
const open = match[1];
|
|
const close = open ? chars[open] : null;
|
|
if (open && close) {
|
|
const n = str.indexOf(close, idx);
|
|
if (n !== -1) {
|
|
idx = n + 1;
|
|
}
|
|
}
|
|
|
|
str = str.slice(idx);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Like normalize(), but doesn't collapse "**\/.." when `globstar` is true. */
|
|
export function normalizeGlob(
|
|
glob: string,
|
|
{ globstar = false }: GlobOptions = {}
|
|
): string {
|
|
if (!!glob.match(/\0/g)) {
|
|
throw new Error(`Glob contains invalid characters: "${glob}"`);
|
|
}
|
|
if (!globstar) {
|
|
return normalize(glob);
|
|
}
|
|
const s = SEP_PATTERN.source;
|
|
const badParentPattern = new RegExp(
|
|
`(?<=(${s}|^)\\*\\*${s})\\.\\.(?=${s}|$)`,
|
|
"g"
|
|
);
|
|
return normalize(glob.replace(badParentPattern, "\0")).replace(/\0/g, "..");
|
|
}
|
|
|
|
/** Like join(), but doesn't collapse "**\/.." when `globstar` is true. */
|
|
export function joinGlobs(
|
|
globs: string[],
|
|
{ extended = false, globstar = false }: GlobOptions = {}
|
|
): string {
|
|
if (!globstar || globs.length == 0) {
|
|
return join(...globs);
|
|
}
|
|
if (globs.length === 0) return ".";
|
|
let joined: string | undefined;
|
|
for (const glob of globs) {
|
|
const path = glob;
|
|
if (path.length > 0) {
|
|
if (!joined) joined = path;
|
|
else joined += `${SEP}${path}`;
|
|
}
|
|
}
|
|
if (!joined) return ".";
|
|
return normalizeGlob(joined, { extended, globstar });
|
|
}
|