diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 686af79a6cca0..50399fd5c38e7 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1008,9 +1008,7 @@ namespace ts { function convertTypingOptionsFromJsonWorker(jsonOptions: any, basePath: string, errors: Diagnostic[], configFileName?: string): TypingOptions { - const options: TypingOptions = getBaseFileName(configFileName) === "jsconfig.json" - ? { enableAutoDiscovery: true, include: [], exclude: [] } - : { enableAutoDiscovery: false, include: [], exclude: [] }; + const options: TypingOptions = { enableAutoDiscovery: getBaseFileName(configFileName) === "jsconfig.json", include: [], exclude: [] }; convertOptionsFromJson(typingOptionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_typing_option_0, errors); return options; } @@ -1263,12 +1261,13 @@ namespace ts { /** * Gets directories in a set of include patterns that should be watched for changes. */ - function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean) { + function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean): Map { // We watch a directory recursively if it contains a wildcard anywhere in a directory segment // of the pattern: // // /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively // /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added + // /a/b - Watch /a/b recursively to catch changes to anything in any recursive subfoler // // We watch a directory without recursion if it contains a wildcard in the file segment of // the pattern: @@ -1281,15 +1280,14 @@ namespace ts { if (include !== undefined) { const recursiveKeys: string[] = []; for (const file of include) { - const name = normalizePath(combinePaths(path, file)); - if (excludeRegex && excludeRegex.test(name)) { + const spec = normalizePath(combinePaths(path, file)); + if (excludeRegex && excludeRegex.test(spec)) { continue; } - const match = wildcardDirectoryPattern.exec(name); + const match = getWildcardDirectoryFromSpec(spec, useCaseSensitiveFileNames); if (match) { - const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase(); - const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None; + const { key, flags } = match; const existingFlags = wildcardDirectories[key]; if (existingFlags === undefined || existingFlags < flags) { wildcardDirectories[key] = flags; @@ -1313,6 +1311,20 @@ namespace ts { return wildcardDirectories; } + function getWildcardDirectoryFromSpec(spec: string, useCaseSensitiveFileNames: boolean): { key: string, flags: WatchDirectoryFlags } | undefined { + const match = wildcardDirectoryPattern.exec(spec); + if (match) { + return { + key: useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase(), + flags: watchRecursivePattern.test(spec) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None + }; + } + if (isImplicitGlob(spec)) { + return { key: spec, flags: WatchDirectoryFlags.Recursive }; + } + return undefined; + } + /** * Determines whether a literal or wildcard file has already been included that has a higher * extension priority. diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 395ddb4057434..6df6658ea23bb 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1231,7 +1231,7 @@ namespace ts { */ export function getDirectoryPath(path: Path): Path; export function getDirectoryPath(path: string): string; - export function getDirectoryPath(path: string): any { + export function getDirectoryPath(path: string): string { return path.substr(0, Math.max(getRootLength(path), path.lastIndexOf(directorySeparator))); } @@ -1491,6 +1491,10 @@ namespace ts { return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos; } + export function hasExtension(fileName: string): boolean { + return getBaseFileName(fileName).indexOf(".") >= 0; + } + export function fileExtensionIs(path: string, extension: string): boolean { return path.length > extension.length && endsWith(path, extension); } @@ -1525,7 +1529,7 @@ namespace ts { return undefined; } - const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther; + const replaceWildcardCharacter = usage === "files" ? replaceWildCardCharacterFiles : replaceWildCardCharacterOther; const singleAsteriskRegexFragment = usage === "files" ? singleAsteriskRegexFragmentFiles : singleAsteriskRegexFragmentOther; /** @@ -1536,81 +1540,105 @@ namespace ts { let pattern = ""; let hasWrittenSubpattern = false; - spec: for (const spec of specs) { + for (const spec of specs) { if (!spec) { continue; } - let subpattern = ""; - let hasRecursiveDirectoryWildcard = false; - let hasWrittenComponent = false; - const components = getNormalizedPathComponents(spec, basePath); - if (usage !== "exclude" && components[components.length - 1] === "**") { - continue spec; + const subPattern = getSubPatternFromSpec(spec, basePath, usage, singleAsteriskRegexFragment, doubleAsteriskRegexFragment, replaceWildcardCharacter); + if (subPattern === undefined) { + continue; } - // getNormalizedPathComponents includes the separator for the root component. - // We need to remove to create our regex correctly. - components[0] = removeTrailingDirectorySeparator(components[0]); + if (hasWrittenSubpattern) { + pattern += "|"; + } - let optionalCount = 0; - for (let component of components) { - if (component === "**") { - if (hasRecursiveDirectoryWildcard) { - continue spec; - } + pattern += "(" + subPattern + ")"; + hasWrittenSubpattern = true; + } - subpattern += doubleAsteriskRegexFragment; - hasRecursiveDirectoryWildcard = true; - hasWrittenComponent = true; - } - else { - if (usage === "directories") { - subpattern += "("; - optionalCount++; - } + if (!pattern) { + return undefined; + } - if (hasWrittenComponent) { - subpattern += directorySeparator; - } + // If excluding, match "foo/bar/baz...", but if including, only allow "foo". + const terminator = usage === "exclude" ? "($|/)" : "$"; + return `^(${pattern})${terminator}`; + } - if (usage !== "exclude") { - // The * and ? wildcards should not match directories or files that start with . if they - // appear first in a component. Dotted directories and files can be included explicitly - // like so: **/.*/.* - if (component.charCodeAt(0) === CharacterCodes.asterisk) { - subpattern += "([^./]" + singleAsteriskRegexFragment + ")?"; - component = component.substr(1); - } - else if (component.charCodeAt(0) === CharacterCodes.question) { - subpattern += "[^./]"; - component = component.substr(1); - } - } + /** + * An "includes" path "foo" is implicitly a glob "foo/** /*" (without the space) if its last component has no extension, + * and does not contain any glob characters itself. + */ + export function isImplicitGlob(lastPathComponent: string): boolean { + return !/[.*?]/.test(lastPathComponent); + } + + function getSubPatternFromSpec(spec: string, basePath: string, usage: "files" | "directories" | "exclude", singleAsteriskRegexFragment: string, doubleAsteriskRegexFragment: string, replaceWildcardCharacter: (match: string) => string): string | undefined { + let subpattern = ""; + let hasRecursiveDirectoryWildcard = false; + let hasWrittenComponent = false; + const components = getNormalizedPathComponents(spec, basePath); + const lastComponent = lastOrUndefined(components); + if (usage !== "exclude" && lastComponent === "**") { + return undefined; + } + + // getNormalizedPathComponents includes the separator for the root component. + // We need to remove to create our regex correctly. + components[0] = removeTrailingDirectorySeparator(components[0]); - subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter); - hasWrittenComponent = true; + if (isImplicitGlob(lastComponent)) { + components.push("**", "*"); + } + + let optionalCount = 0; + for (let component of components) { + if (component === "**") { + if (hasRecursiveDirectoryWildcard) { + return undefined; } - } - while (optionalCount > 0) { - subpattern += ")?"; - optionalCount--; + subpattern += doubleAsteriskRegexFragment; + hasRecursiveDirectoryWildcard = true; } + else { + if (usage === "directories") { + subpattern += "("; + optionalCount++; + } - if (hasWrittenSubpattern) { - pattern += "|"; + if (hasWrittenComponent) { + subpattern += directorySeparator; + } + + if (usage !== "exclude") { + // The * and ? wildcards should not match directories or files that start with . if they + // appear first in a component. Dotted directories and files can be included explicitly + // like so: **/.*/.* + if (component.charCodeAt(0) === CharacterCodes.asterisk) { + subpattern += "([^./]" + singleAsteriskRegexFragment + ")?"; + component = component.substr(1); + } + else if (component.charCodeAt(0) === CharacterCodes.question) { + subpattern += "[^./]"; + component = component.substr(1); + } + } + + subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter); } - pattern += "(" + subpattern + ")"; - hasWrittenSubpattern = true; + hasWrittenComponent = true; } - if (!pattern) { - return undefined; + while (optionalCount > 0) { + subpattern += ")?"; + optionalCount--; } - return "^(" + pattern + (usage === "exclude" ? ")($|/)" : ")$"); + return subpattern; } function replaceWildCardCharacterFiles(match: string) { @@ -1697,6 +1725,7 @@ namespace ts { function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) { // Storage for our results in the form of literal paths (e.g. the paths as written by the user). const basePaths: string[] = [path]; + if (includes) { // Storage for literal base paths amongst the include patterns. const includeBasePaths: string[] = []; @@ -1704,14 +1733,8 @@ namespace ts { // We also need to check the relative paths by converting them to absolute and normalizing // in case they escape the base path (e.g "..\somedirectory") const absolute: string = isRootedDiskPath(include) ? include : normalizePath(combinePaths(path, include)); - - const wildcardOffset = indexOfAnyCharCode(absolute, wildcardCharCodes); - const includeBasePath = wildcardOffset < 0 - ? removeTrailingDirectorySeparator(getDirectoryPath(absolute)) - : absolute.substring(0, absolute.lastIndexOf(directorySeparator, wildcardOffset)); - // Append the literal and canonical candidate base paths. - includeBasePaths.push(includeBasePath); + includeBasePaths.push(getIncludeBasePath(absolute)); } // Sort the offsets array using either the literal or canonical path representations. @@ -1719,21 +1742,27 @@ namespace ts { // Iterate over each include base path and include unique base paths that are not a // subpath of an existing base path - include: for (let i = 0; i < includeBasePaths.length; i++) { - const includeBasePath = includeBasePaths[i]; - for (let j = 0; j < basePaths.length; j++) { - if (containsPath(basePaths[j], includeBasePath, path, !useCaseSensitiveFileNames)) { - continue include; - } + for (const includeBasePath of includeBasePaths) { + if (ts.every(basePaths, basePath => !containsPath(basePath, includeBasePath, path, !useCaseSensitiveFileNames))) { + basePaths.push(includeBasePath); } - - basePaths.push(includeBasePath); } } return basePaths; } + function getIncludeBasePath(absolute: string): string { + const wildcardOffset = indexOfAnyCharCode(absolute, wildcardCharCodes); + if (wildcardOffset < 0) { + // No "*" or "?" in the path + return !hasExtension(absolute) + ? absolute + : removeTrailingDirectorySeparator(getDirectoryPath(absolute)); + } + return absolute.substring(0, absolute.lastIndexOf(directorySeparator, wildcardOffset)); + } + export function ensureScriptKind(fileName: string, scriptKind?: ScriptKind): ScriptKind { // Using scriptKind as a condition handles both: // - 'scriptKind' is unspecified and thus it is `undefined` diff --git a/src/compiler/program.ts b/src/compiler/program.ts index a9c64f3ecbe3a..2bc31c706137a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -971,10 +971,6 @@ namespace ts { return sortAndDeduplicateDiagnostics(allDiagnostics); } - function hasExtension(fileName: string): boolean { - return getBaseFileName(fileName).indexOf(".") >= 0; - } - function processRootFile(fileName: string, isDefaultLib: boolean) { processSourceFile(normalizePath(fileName), isDefaultLib); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f9ec3e9f268cc..14da212951e26 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3092,6 +3092,7 @@ namespace ts { Pretty, } + /** Either a parsed command line or a parsed tsconfig.json */ export interface ParsedCommandLine { options: CompilerOptions; typingOptions?: TypingOptions; diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index 79e9668d073c7..b514ac142c50b 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -91,6 +91,12 @@ namespace ts { const defaultExcludes = ["node_modules", "bower_components", "jspm_packages"]; + function assertParsed(actual: ts.ParsedCommandLine, expected: ts.ParsedCommandLine): void { + assert.deepEqual(actual.fileNames, expected.fileNames); + assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual.errors, expected.errors); + } + describe("matchFiles", () => { describe("with literal file list", () => { it("without exclusions", () => { @@ -110,9 +116,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("missing files are still present", () => { const json = { @@ -131,9 +135,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("are not removed due to excludes", () => { const json = { @@ -155,9 +157,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); }); @@ -179,9 +179,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with non .ts file extensions are excluded", () => { const json = { @@ -200,9 +198,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with missing files are excluded", () => { const json = { @@ -221,9 +217,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with literal excludes", () => { const json = { @@ -244,9 +238,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with wildcard excludes", () => { const json = { @@ -274,9 +266,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with recursive excludes", () => { const json = { @@ -303,9 +293,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with case sensitive exclude", () => { const json = { @@ -325,9 +313,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and no exclusions", () => { const json = { @@ -349,9 +335,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and exclusions", () => { const json = { @@ -378,9 +362,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and empty exclude", () => { const json = { @@ -406,9 +388,7 @@ namespace ts { wildcardDirectories: {}, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); }); @@ -432,9 +412,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("`*` matches only ts files", () => { const json = { @@ -455,9 +433,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("`?` matches only a single character", () => { const json = { @@ -477,9 +453,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with recursive directory", () => { const json = { @@ -501,9 +475,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with multiple recursive directories", () => { const json = { @@ -527,9 +499,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("case sensitive", () => { const json = { @@ -548,9 +518,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with missing files are excluded", () => { const json = { @@ -570,9 +538,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("always include literal files", () => { const json = { @@ -597,9 +563,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("exclude folders", () => { const json = { @@ -624,9 +588,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and no exclusions", () => { const json = { @@ -645,9 +607,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and exclusions", () => { const json = { @@ -671,9 +631,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with common package folders and empty exclude", () => { const json = { @@ -696,9 +654,7 @@ namespace ts { }, }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveCommonFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("exclude .js files when allowJs=false", () => { const json = { @@ -723,9 +679,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("include .js files when allowJs=true", () => { const json = { @@ -750,9 +704,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("include explicitly listed .min.js files when allowJs=true", () => { const json = { @@ -777,9 +729,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("include paths outside of the project", () => { const json = { @@ -803,9 +753,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("include paths outside of the project using relative paths", () => { const json = { @@ -828,9 +776,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("exclude paths outside of the project using relative paths", () => { const json = { @@ -851,9 +797,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("include files with .. in their name", () => { const json = { @@ -873,9 +817,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("exclude files with .. in their name", () => { const json = { @@ -897,9 +839,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with jsx=none, allowJs=false", () => { const json = { @@ -922,9 +862,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with jsx=preserve, allowJs=false", () => { const json = { @@ -949,9 +887,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with jsx=none, allowJs=true", () => { const json = { @@ -976,9 +912,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with jsx=preserve, allowJs=true", () => { const json = { @@ -1005,9 +939,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("exclude .min.js files using wildcards", () => { const json = { @@ -1034,9 +966,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); describe("with trailing recursive directory", () => { it("in includes", () => { @@ -1056,9 +986,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("in excludes", () => { const json = { @@ -1079,9 +1007,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); }); describe("with multiple recursive directory patterns", () => { @@ -1102,9 +1028,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("in excludes", () => { const json = { @@ -1131,9 +1055,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); }); @@ -1155,9 +1077,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("in includes after a subdirectory", () => { @@ -1177,9 +1097,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("in excludes immediately after", () => { @@ -1207,9 +1125,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("in excludes after a subdirectory", () => { @@ -1237,9 +1153,25 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); + }); + }); + + describe("with implicit globbification", () => { + it("Expands 'z' to 'z/**/*'", () => { + const json = { + include: ["z"] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ "a.ts", "aba.ts", "abz.ts", "b.ts", "bba.ts", "bbz.ts" ].map(x => `c:/dev/z/${x}`), + wildcardDirectories: { + "c:/dev/z": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assertParsed(actual, expected); }); }); }); @@ -1264,9 +1196,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); describe("that are explicitly included", () => { it("without wildcards", () => { @@ -1286,9 +1216,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with recursive wildcards that match directories", () => { const json = { @@ -1310,9 +1238,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with recursive wildcards that match nothing", () => { const json = { @@ -1334,9 +1260,7 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); it("with wildcard excludes that implicitly exclude dotted files", () => { const json = { @@ -1357,9 +1281,7 @@ namespace ts { wildcardDirectories: {} }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveDottedFoldersHost, caseInsensitiveBasePath, undefined, caseInsensitiveTsconfigPath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); - assert.deepEqual(actual.errors, expected.errors); + assertParsed(actual, expected); }); }); });