diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index c81b3b63244..a5cd7abc505 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -531,7 +531,7 @@ namespace ts { includeSpecs = ["**/*"]; } - return expandFiles(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors); + return matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors); } } @@ -589,14 +589,14 @@ namespace ts { * Expands an array of file specifications. * * @param fileNames The literal file names to include. - * @param includeSpecs The file specifications to expand. - * @param excludeSpecs The file specifications to exclude. + * @param include The wildcard file specifications to include. + * @param exclude The wildcard file specifications to exclude. * @param basePath The base path for any relative file specifications. * @param options Compiler options. * @param host The host used to resolve files and directories. * @param errors An array for diagnostic reporting. */ - export function expandFiles(fileNames: string[], includeSpecs: string[], excludeSpecs: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors?: Diagnostic[]): ExpandResult { + function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[]): ExpandResult { basePath = normalizePath(basePath); basePath = removeTrailingDirectorySeparator(basePath); @@ -615,11 +615,19 @@ namespace ts { // via wildcard, and to handle extension priority. const wildcardFileMap: Map = {}; + if (include) { + include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false); + } + + if (exclude) { + exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true); + } + // Wildcard directories (provided as part of a wildcard path) are stored in a // file map that marks whether it was a regular wildcard match (with a `*` or `?` token), // or a recursive directory. This information is used by filesystem watchers to monitor for // new entries in these paths. - const wildcardDirectories: Map = getWildcardDirectories(includeSpecs, basePath, host.useCaseSensitiveFileNames); + const wildcardDirectories: Map = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames); // Rather than requery this for each file and filespec, we query the supported extensions // once and store it on the expansion context. @@ -634,13 +642,8 @@ namespace ts { } } - if (includeSpecs) { - includeSpecs = validateSpecs(includeSpecs, errors, /*allowTrailingRecursion*/ false); - if (excludeSpecs) { - excludeSpecs = validateSpecs(excludeSpecs, errors, /*allowTrailingRecursion*/ true); - } - - for (const file of host.readDirectory(basePath, supportedExtensions, excludeSpecs, includeSpecs)) { + if (include && include.length > 0) { + for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include)) { // If we have already included a literal or wildcard path with a // higher priority extension, we should skip this file. // @@ -677,10 +680,10 @@ namespace ts { const validSpecs: string[] = []; for (const spec of specs) { if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { - errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec)); + errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec)); } else if (invalidMultipleRecursionPatterns.test(spec)) { - errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec)); + errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec)); } else { validSpecs.push(spec); @@ -696,7 +699,7 @@ namespace ts { /** * Gets directories in a set of include patterns that should be watched for changes. */ - function getWildcardDirectories(includes: string[], path: string, useCaseSensitiveFileNames: boolean) { + function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean) { // We watch a directory recursively if it contains a wildcard anywhere in a directory segment // of the pattern: // @@ -708,11 +711,16 @@ namespace ts { // // /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 excludeRegExp = getRegularExpressionForWildcard(exclude, path, "exclude", useCaseSensitiveFileNames); const wildcardDirectories: Map = {}; - if (includes !== undefined) { + if (include !== undefined) { const recursiveKeys: string[] = []; - for (const include of includes) { - const name = combinePaths(path, include); + for (const file of include) { + const name = combinePaths(path, file); + if (excludeRegExp && excludeRegExp.test(name)) { + continue; + } + const match = wildcardDirectoryPattern.exec(name); if (match) { const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase(); diff --git a/tests/cases/unittests/expandFiles.ts b/tests/cases/unittests/expandFiles.ts index 02065407e27..bbda14a2cfa 100644 --- a/tests/cases/unittests/expandFiles.ts +++ b/tests/cases/unittests/expandFiles.ts @@ -92,189 +92,376 @@ namespace ts { describe("expandFiles", () => { describe("with literal file list", () => { it("without exclusions", () => { - const fileNames = ["a.ts", "b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/b.ts"], + const json = { + files: [ + "a.ts", + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(fileNames, /*includeSpecs*/ undefined, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("missing files are still present", () => { - const fileNames = ["z.ts", "x.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/z.ts", "c:/dev/x.ts"], + const json = { + files: [ + "z.ts", + "x.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/z.ts", + "c:/dev/x.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(fileNames, /*includeSpecs*/ undefined, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("are not removed due to excludes", () => { - const fileNames = ["a.ts", "b.ts"]; - const excludeSpecs = ["b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/b.ts"], + const json = { + files: [ + "a.ts", + "b.ts" + ], + exclude: [ + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(fileNames, /*includeSpecs*/ undefined, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); }); describe("with literal include list", () => { it("without exclusions", () => { - const includeSpecs = ["a.ts", "b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/b.ts"], + const json = { + include: [ + "a.ts", + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with non .ts file extensions are excluded", () => { - const includeSpecs = ["a.js", "b.js"]; - const expected: ts.ExpandResult = { + const json = { + include: [ + "a.js", + "b.js" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], fileNames: [], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with missing files are excluded", () => { - const includeSpecs = ["z.ts", "x.ts"]; - const expected: ts.ExpandResult = { + const json = { + include: [ + "z.ts", + "x.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], fileNames: [], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with literal excludes", () => { - const includeSpecs = ["a.ts", "b.ts"]; - const excludeSpecs = ["b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts"], + const json = { + include: [ + "a.ts", + "b.ts" + ], + exclude: [ + "b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with wildcard excludes", () => { - const includeSpecs = ["a.ts", "b.ts", "z/a.ts", "z/abz.ts", "z/aba.ts", "x/b.ts"]; - const excludeSpecs = ["*.ts", "z/??z.ts", "*/b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/z/a.ts", "c:/dev/z/aba.ts"], + const json = { + include: [ + "a.ts", + "b.ts", + "z/a.ts", + "z/abz.ts", + "z/aba.ts", + "x/b.ts" + ], + exclude: [ + "*.ts", + "z/??z.ts", + "*/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/z/a.ts", + "c:/dev/z/aba.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with recursive excludes", () => { - const includeSpecs = ["a.ts", "b.ts", "x/a.ts", "x/b.ts", "x/y/a.ts", "x/y/b.ts"]; - const excludeSpecs = ["**/b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/x/a.ts", "c:/dev/x/y/a.ts"], + const json = { + include: [ + "a.ts", + "b.ts", + "x/a.ts", + "x/b.ts", + "x/y/a.ts", + "x/y/b.ts" + ], + exclude: [ + "**/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with case sensitive exclude", () => { - const includeSpecs = ["B.ts"]; - const excludeSpecs = ["**/b.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["/dev/B.ts"], + const json = { + include: [ + "B.ts" + ], + exclude: [ + "**/b.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/B.ts" + ], wildcardDirectories: {}, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, excludeSpecs, caseSensitiveBasePath, {}, caseSensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); assert.deepEqual(actual, expected); }); }); describe("with wildcard include list", () => { it("same named declarations are excluded", () => { - const includeSpecs = ["*.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/b.ts", "c:/dev/c.d.ts"], + const json = { + include: [ + "*.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts" + ], wildcardDirectories: { "c:/dev": ts.WatchDirectoryFlags.None }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("`*` matches only ts files", () => { - const includeSpecs = ["*"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/b.ts", "c:/dev/c.d.ts"], + const json = { + include: [ + "*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/b.ts", + "c:/dev/c.d.ts" + ], wildcardDirectories: { "c:/dev": ts.WatchDirectoryFlags.None }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("`?` matches only a single character", () => { - const includeSpecs = ["x/?.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/x/a.ts", "c:/dev/x/b.ts"], + const json = { + include: [ + "x/?.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/x/a.ts", + "c:/dev/x/b.ts" + ], wildcardDirectories: { "c:/dev/x": ts.WatchDirectoryFlags.None }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("with recursive directory", () => { - const includeSpecs = ["**/a.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts", "c:/dev/x/a.ts", "c:/dev/x/y/a.ts", "c:/dev/z/a.ts"], + const json = { + include: [ + "**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts", + "c:/dev/z/a.ts" + ], wildcardDirectories: { "c:/dev": ts.WatchDirectoryFlags.Recursive }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("case sensitive", () => { - const includeSpecs = ["**/A.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["/dev/A.ts"], + const json = { + include: [ + "**/A.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "/dev/A.ts" + ], wildcardDirectories: { "/dev": ts.WatchDirectoryFlags.Recursive }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseSensitiveBasePath, {}, caseSensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseSensitiveHost, caseSensitiveBasePath); assert.deepEqual(actual, expected); }); it("with missing files are excluded", () => { - const includeSpecs = ["*/z.ts"]; - const expected: ts.ExpandResult = { + const json = { + include: [ + "*/z.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], fileNames: [], wildcardDirectories: { "c:/dev": ts.WatchDirectoryFlags.Recursive }, }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("always include literal files", () => { - const fileNames = ["a.ts"]; - const includeSpecs = ["*/z.ts"]; - const excludeSpecs = ["**/a.ts"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/a.ts"], + const json = { + files: [ + "a.ts" + ], + include: [ + "*/z.ts" + ], + exclude: [ + "**/a.ts" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [ + "c:/dev/a.ts" + ], wildcardDirectories: { "c:/dev": ts.WatchDirectoryFlags.Recursive }, }; - const actual = ts.expandFiles(fileNames, includeSpecs, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("exclude folders", () => { - const includeSpecs = ["**/*"]; - const excludeSpecs = ["z", "x"]; - const expected: ts.ExpandResult = { + const json = { + include: [ + "**/*" + ], + exclude: [ + "z", + "x" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.ts", @@ -284,34 +471,66 @@ namespace ts { "c:/dev": ts.WatchDirectoryFlags.Recursive } }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, excludeSpecs, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("exclude .js files when allowJs=false", () => { - const includeSpecs = ["js/*"]; - const expected: ts.ExpandResult = { + const json = { + compilerOptions: { + allowJs: false + }, + include: [ + "js/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: false + }, + errors: [], fileNames: [], wildcardDirectories: { "c:/dev/js": ts.WatchDirectoryFlags.None } }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("include .js files when allowJs=true", () => { - const includeSpecs = ["js/*"]; - const expected: ts.ExpandResult = { - fileNames: ["c:/dev/js/a.js", "c:/dev/js/b.js"], + const json = { + compilerOptions: { + allowJs: true + }, + include: [ + "js/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: { + allowJs: true + }, + errors: [], + fileNames: [ + "c:/dev/js/a.js", + "c:/dev/js/b.js" + ], wildcardDirectories: { "c:/dev/js": ts.WatchDirectoryFlags.None } }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, { allowJs: true }, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); it("include paths outside of the project", () => { - const includeSpecs = ["*", "c:/ext/*"]; - const expected: ts.ExpandResult = { + const json = { + include: [ + "*", + "c:/ext/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.ts", @@ -323,20 +542,20 @@ namespace ts { "c:/ext": ts.WatchDirectoryFlags.None } }; - const actual = ts.expandFiles(/*fileNames*/ undefined, includeSpecs, /*excludeSpecs*/ undefined, caseInsensitiveBasePath, {}, caseInsensitiveHost); + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); assert.deepEqual(actual, expected); }); - }); - - describe("when called from parseJsonConfigFileContent", () => { it("with jsx=none, allowJs=false", () => { - const json: any = { - "compilerOptions": { - "jsx": "none", - "allowJs": false + const json = { + compilerOptions: { + allowJs: false } }; - const expected: ts.ExpandResult = { + const expected: ts.ParsedCommandLine = { + options: { + allowJs: false + }, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.tsx", @@ -347,17 +566,21 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual, expected); }); it("with jsx=preserve, allowJs=false", () => { - const json: any = { - "compilerOptions": { - "jsx": "preserve", - "allowJs": false + const json = { + compilerOptions: { + jsx: "preserve", + allowJs: false } }; - const expected: ts.ExpandResult = { + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.Preserve, + allowJs: false + }, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.tsx", @@ -368,17 +591,19 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual, expected); }); it("with jsx=none, allowJs=true", () => { - const json: any = { - "compilerOptions": { - "jsx": "none", - "allowJs": true + const json = { + compilerOptions: { + allowJs: true } }; - const expected: ts.ExpandResult = { + const expected: ts.ParsedCommandLine = { + options: { + allowJs: true + }, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.tsx", @@ -391,17 +616,21 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual, expected); }); it("with jsx=preserve, allowJs=true", () => { - const json: any = { - "compilerOptions": { - "jsx": "preserve", - "allowJs": true + const json = { + compilerOptions: { + jsx: "preserve", + allowJs: true } }; - const expected: ts.ExpandResult = { + const expected: ts.ParsedCommandLine = { + options: { + jsx: ts.JsxEmit.Preserve, + allowJs: true + }, + errors: [], fileNames: [ "c:/dev/a.ts", "c:/dev/b.tsx", @@ -414,8 +643,90 @@ namespace ts { } }; const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath); - assert.deepEqual(actual.fileNames, expected.fileNames); - assert.deepEqual(actual.wildcardDirectories, expected.wildcardDirectories); + assert.deepEqual(actual, expected); + }); + describe("with trailing recursive directory", () => { + it("in includes", () => { + const json = { + include: [ + "**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, "**") + ], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual, expected); + }); + it("in excludes", () => { + const json = { + include: [ + "**/*" + ], + exclude: [ + "**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual, expected); + }); + }); + describe("with multiple recursive directory patterns", () => { + it("in includes", () => { + const json = { + include: [ + "**/x/**/*" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**/*") + ], + fileNames: [], + wildcardDirectories: {} + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual, expected); + }); + it("in excludes", () => { + const json = { + include: [ + "**/a.ts" + ], + exclude: [ + "**/x/**" + ] + }; + const expected: ts.ParsedCommandLine = { + options: {}, + errors: [ + ts.createCompilerDiagnostic(ts.Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, "**/x/**") + ], + fileNames: [ + "c:/dev/a.ts", + "c:/dev/x/a.ts", + "c:/dev/x/y/a.ts", + "c:/dev/z/a.ts" + ], + wildcardDirectories: { + "c:/dev": ts.WatchDirectoryFlags.Recursive + } + }; + const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveHost, caseInsensitiveBasePath); + assert.deepEqual(actual, expected); + }); }); }); });