diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index da0ea4aee56..a0f91e3d0e9 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1906,21 +1906,6 @@ namespace ts { */ const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/; - /** - * Tests for a path with multiple recursive directory wildcards. - * Matches **\** and **\a\**, but not **\a**b. - * - * NOTE: used \ in place of / above to avoid issues with multiline comments. - * - * Breakdown: - * (^|\/) # matches either the beginning of the string or a directory separator. - * \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator. - * (.*\/)? # optionally matches any number of characters followed by a directory separator. - * \*\* # matches a recursive directory wildcard "**" - * ($|\/) # matches either the end of the string or a directory separator. - */ - const invalidMultipleRecursionPatterns = /(^|\/)\*\*\/(.*\/)?\*\*($|\/)/; - /** * Tests for a path where .. appears after a recursive directory wildcard. * Matches **\..\*, **\a\..\*, and **\.., but not ..\**\* @@ -2115,9 +2100,6 @@ namespace ts { if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { return Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0; } - else if (invalidMultipleRecursionPatterns.test(spec)) { - return Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0; - } else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) { return Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 0b82a3967dd..a79a3751db6 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2376,7 +2376,6 @@ namespace ts { function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", { singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter }: WildcardMatcher): string | undefined { let subpattern = ""; - let hasRecursiveDirectoryWildcard = false; let hasWrittenComponent = false; const components = getNormalizedPathComponents(spec, basePath); const lastComponent = lastOrUndefined(components); @@ -2395,12 +2394,7 @@ namespace ts { let optionalCount = 0; for (let component of components) { if (component === "**") { - if (hasRecursiveDirectoryWildcard) { - return undefined; - } - subpattern += doubleAsteriskRegexFragment; - hasRecursiveDirectoryWildcard = true; } else { if (usage === "directories") { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 2cb068f0efb..336def7ea52 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2623,10 +2623,6 @@ "category": "Error", "code": 5010 }, - "File specification cannot contain multiple recursive directory wildcards ('**'): '{0}'.": { - "category": "Error", - "code": 5011 - }, "Cannot read file '{0}': {1}.": { "category": "Error", "code": 5012 diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index f2c2369ef37..17a0db04fdf 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -50,6 +50,7 @@ namespace ts { "/dev/x/b.ts", "/dev/x/y/a.ts", "/dev/x/y/b.ts", + "/dev/q/a/c/b/d.ts", "/dev/js/a.js", "/dev/js/b.js", ]); @@ -1171,13 +1172,17 @@ namespace ts { }; const expected: ts.ParsedCommandLine = { options: {}, - errors: [ - createDiagnosticForConfigFile(json, 12, 11, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*"), - ts.createCompilerDiagnostic(ts.Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2, - caseInsensitiveTsconfigPath, JSON.stringify(json.include), "[]") + errors: [], + fileNames: [ + "c:/dev/x/a.ts", + "c:/dev/x/aa.ts", + "c:/dev/x/b.ts", + "c:/dev/x/y/a.ts", + "c:/dev/x/y/b.ts", ], - fileNames: [], - wildcardDirectories: {} + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } }; validateMatches(expected, json, caseInsensitiveHost, caseInsensitiveBasePath, /*existingOptions*/ undefined, caseInsensitiveTsconfigPath); }); @@ -1192,13 +1197,9 @@ namespace ts { }; const expected: ts.ParsedCommandLine = { options: {}, - errors: [ - createDiagnosticForConfigFile(json, 34, 9, ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**") - ], + errors: [], fileNames: [ "c:/dev/a.ts", - "c:/dev/x/a.ts", - "c:/dev/x/y/a.ts", "c:/dev/z/a.ts" ], wildcardDirectories: { @@ -1426,5 +1427,60 @@ namespace ts { }); }); }); + + describe("exclude or include patterns which start with **", () => { + it("can exclude dirs whose pattern starts with **", () => { + const json = { + exclude: [ + "**/x" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/A.ts", + "/dev/B.ts", + "/dev/a.ts", + "/dev/b.ts", + "/dev/c.d.ts", + "/dev/q/a/c/b/d.ts", + "/dev/z/a.ts", + "/dev/z/aba.ts", + "/dev/z/abz.ts", + "/dev/z/b.ts", + "/dev/z/bba.ts", + "/dev/z/bbz.ts", + ], + wildcardDirectories: { + "/dev": ts.WatchDirectoryFlags.Recursive + } + }; + validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath); + }); + it("can include dirs whose pattern starts with **", () => { + const json = { + include: [ + "**/x", + "**/a/**/b" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/x/a.ts", + "/dev/x/b.ts", + "/dev/x/y/a.ts", + "/dev/x/y/b.ts", + "/dev/q/a/c/b/d.ts", + ], + wildcardDirectories: { + "/dev": ts.WatchDirectoryFlags.Recursive + } + }; + validateMatches(expected, json, caseSensitiveHost, caseSensitiveBasePath); + }); + }); }); }