Skip to content

Commit

Permalink
Do not merge file patterns into a single regular expression
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelMitchell-at committed Feb 3, 2025
1 parent 739d729 commit 24a558c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 49 deletions.
36 changes: 18 additions & 18 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ import {
getNormalizedAbsolutePath,
getOwnKeys,
getRegexFromPattern,
getRegularExpressionForWildcard,
getRegularExpressionsForWildcards,
getRelativePathFromFile,
getSpellingSuggestion,
Expand Down Expand Up @@ -2689,16 +2688,17 @@ function filterSameAsDefaultInclude(specs: readonly string[] | undefined) {
function matchesSpecs(path: string, includeSpecs: readonly string[] | undefined, excludeSpecs: readonly string[] | undefined, host: ConvertToTSConfigHost): (path: string) => boolean {
if (!includeSpecs) return returnTrue;
const patterns = getFileMatcherPatterns(path, excludeSpecs, includeSpecs, host.useCaseSensitiveFileNames, host.getCurrentDirectory());
const excludeRe = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, host.useCaseSensitiveFileNames);
const includeRe = patterns.includeFilePattern && getRegexFromPattern(patterns.includeFilePattern, host.useCaseSensitiveFileNames);
if (includeRe) {
if (excludeRe) {
return path => !(includeRe.test(path) && !excludeRe.test(path));
const excludeRegexes = patterns.excludePatterns && patterns.excludePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames));
const includeRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames));
if (includeRegexes) {
if (excludeRegexes) {
return path => !(includeRegexes.some(regex => regex.test(path)) && !excludeRegexes.some(regex => regex.test(path)));
}
return path => !includeRe.test(path);
return path => !includeRegexes.some(regex => regex.test(path));
}
if (excludeRe) {
return path => excludeRe.test(path);

if (excludeRegexes) {
return path => excludeRegexes.some(regex => regex.test(path));
}
return returnTrue;
}
Expand Down Expand Up @@ -3931,7 +3931,7 @@ export function getFileNamesFromConfigSpecs(
// Valid only if *.json specified
if (!jsonOnlyIncludeRegexes) {
const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json));
const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`);
const includeFilePatterns = getRegularExpressionsForWildcards(includes, basePath, "files");
jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray;
}
const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file));
Expand Down Expand Up @@ -4032,11 +4032,11 @@ export function matchesExcludeWorker(
currentDirectory: string,
basePath?: string,
): boolean {
const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude");
const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames);
if (!excludeRegex) return false;
if (excludeRegex.test(pathToCheck)) return true;
return !hasExtension(pathToCheck) && excludeRegex.test(ensureTrailingDirectorySeparator(pathToCheck));
const excludePatterns = getRegularExpressionsForWildcards(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude");
const excludeRegexes = excludePatterns && excludePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));
if (!excludeRegexes) return false;
if (excludeRegexes.some(regex => regex.test(pathToCheck))) return true;
return !hasExtension(pathToCheck) && excludeRegexes.some(regex => regex.test(ensureTrailingDirectorySeparator(pathToCheck)));
}

function validateSpecs(specs: readonly string[], errors: Diagnostic[], disallowTrailingRecursion: boolean, jsonSourceFile: TsConfigSourceFile | undefined, specKey: string): readonly string[] {
Expand Down Expand Up @@ -4081,15 +4081,15 @@ function getWildcardDirectories({ validatedIncludeSpecs: include, validatedExclu
//
// /a/b/* - Watch /a/b directly to catch any new file
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, basePath, "exclude");
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
const rawExcludeRegexes = getRegularExpressionsForWildcards(exclude, basePath, "exclude");
const excludeRegexes = rawExcludeRegexes && rawExcludeRegexes.map(regex => new RegExp(regex, useCaseSensitiveFileNames ? "" : "i"));
const wildcardDirectories: MapLike<WatchDirectoryFlags> = {};
const wildCardKeyToPath = new Map<CanonicalKey, string>();
if (include !== undefined) {
const recursiveKeys: CanonicalKey[] = [];
for (const file of include) {
const spec = normalizePath(combinePaths(basePath, file));
if (excludeRegex && excludeRegex.test(spec)) {
if (some(excludeRegexes, excludeRegex => excludeRegex.test(spec))) {
continue;
}

Expand Down
42 changes: 13 additions & 29 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@ import {
LogicalOperator,
LogicalOrCoalescingAssignmentOperator,
mangleScopedPackageName,
map,
mapDefined,
MapLike,
MemberName,
Expand Down Expand Up @@ -9552,26 +9551,15 @@ const wildcardMatchers = {
exclude: excludeMatcher,
};

/** @internal */
export function getRegularExpressionForWildcard(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string | undefined {
const patterns = getRegularExpressionsForWildcards(specs, basePath, usage);
if (!patterns || !patterns.length) {
return undefined;
}

const pattern = patterns.map(pattern => `(${pattern})`).join("|");
// If excluding, match "foo/bar/baz...", but if including, only allow "foo".
const terminator = usage === "exclude" ? "($|/)" : "$";
return `^(${pattern})${terminator}`;
}

/** @internal */
export function getRegularExpressionsForWildcards(specs: readonly string[] | undefined, basePath: string, usage: "files" | "directories" | "exclude"): readonly string[] | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}

return flatMap(specs, spec => spec && getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage]));
// If excluding, match "foo/bar/baz...", but if including, only allow "foo".
const terminator = usage === "exclude" ? "($|/)" : "$";
return flatMap(specs, spec => spec && `^${getSubPatternFromSpec(spec, basePath, usage, wildcardMatchers[usage])}${terminator}`);
}

/**
Expand Down Expand Up @@ -9684,12 +9672,9 @@ export interface FileSystemEntries {

/** @internal */
export interface FileMatcherPatterns {
/** One pattern for each "include" spec. */
includeFilePatterns: readonly string[] | undefined;
/** One pattern matching one of any of the "include" specs. */
includeFilePattern: string | undefined;
includeDirectoryPattern: string | undefined;
excludePattern: string | undefined;
includeDirectoryPatterns: readonly string[] | undefined;
excludePatterns: readonly string[] | undefined;
basePaths: readonly string[];
}

Expand All @@ -9704,10 +9689,9 @@ export function getFileMatcherPatterns(path: string, excludes: readonly string[]
const absolutePath = combinePaths(currentDirectory, path);

return {
includeFilePatterns: map(getRegularExpressionsForWildcards(includes, absolutePath, "files"), pattern => `^${pattern}$`),
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
includeFilePatterns: getRegularExpressionsForWildcards(includes, absolutePath, "files"),
includeDirectoryPatterns: getRegularExpressionsForWildcards(includes, absolutePath, "directories"),
excludePatterns: getRegularExpressionsForWildcards(excludes, absolutePath, "exclude"),
basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames),
};
}
Expand All @@ -9729,8 +9713,8 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);

const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));
const includeDirectoryRegex = patterns.includeDirectoryPattern && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames);
const excludeRegex = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames);
const includeDirectoryRegexes = patterns.includeDirectoryPatterns && patterns.includeDirectoryPatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));
const excludeRegexes = patterns.excludePatterns && patterns.excludePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));

// Associate an array of results with each include regex. This keeps results in order of the "include" order.
// If there are no "includes", then just put everything in results[0].
Expand All @@ -9753,7 +9737,7 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
if (excludeRegex && excludeRegex.test(absoluteName)) continue;
if (excludeRegexes && excludeRegexes.some(regex => regex.test(absoluteName))) continue;
if (!includeFileRegexes) {
results[0].push(name);
}
Expand All @@ -9776,8 +9760,8 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (
(!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))
(!includeDirectoryRegexes || includeDirectoryRegexes.some(regex => regex.test(absoluteName))) &&
(!excludeRegexes || !excludeRegexes.some(regex => regex.test(absoluteName)))
) {
visitDirectory(name, absoluteName, depth);
}
Expand Down
5 changes: 3 additions & 2 deletions src/services/getEditsForFileRename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,11 @@ function updateTsconfigFiles(program: Program, changeTracker: textChanges.Change
const includes = mapDefined(property.initializer.elements, e => isStringLiteral(e) ? e.text : undefined);
if (includes.length === 0) return;
const matchers = getFileMatcherPatterns(configDir, /*excludes*/ [], includes, useCaseSensitiveFileNames, currentDirectory);
const includeRegexes = Debug.checkDefined(matchers.includeFilePatterns).map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));
// If there isn't some include for this, add a new one.
if (
getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(oldFileOrDirPath) &&
!getRegexFromPattern(Debug.checkDefined(matchers.includeFilePattern), useCaseSensitiveFileNames).test(newFileOrDirPath)
includeRegexes.some(regex => regex.test(oldFileOrDirPath)) &&
!includeRegexes.some(regex => regex.test(newFileOrDirPath))
) {
changeTracker.insertNodeAfter(configFile, last(property.initializer.elements), factory.createStringLiteral(relativePath(newFileOrDirPath)));
}
Expand Down

0 comments on commit 24a558c

Please sign in to comment.