From ca590d6fed5a066dcf71804147ba8325bc91deb9 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 26 Jan 2018 15:14:48 -0800 Subject: [PATCH] Need allowJs to be true to use the json module resolution --- src/compiler/checker.ts | 2 +- src/compiler/commandLineParser.ts | 3 +- src/compiler/core.ts | 25 +++++++++----- src/compiler/moduleNameResolver.ts | 2 +- src/compiler/program.ts | 4 +-- src/harness/fourslash.ts | 3 +- src/services/jsTyping.ts | 4 +-- ...sFileCompilationWithMapFileAsJs.errors.txt | 4 +-- ...hMapFileAsJsWithInlineSourceMap.errors.txt | 4 +-- .../requireOfJsonFileWithoutAllowJs.js | 27 +++++++++++++++ .../requireOfJsonFileWithoutAllowJs.symbols | 24 ++++++++++++++ .../requireOfJsonFileWithoutAllowJs.types | 33 +++++++++++++++++++ tests/cases/compiler/requireOfJsonFile.ts | 1 + .../compiler/requireOfJsonFileWithAmd.ts | 1 + .../requireOfJsonFileWithEmptyObject.ts | 1 + ...uireOfJsonFileWithEmptyObjectWithErrors.ts | 1 + .../requireOfJsonFileWithNoContent.ts | 1 + .../requireOfJsonFileWithoutAllowJs.ts | 17 ++++++++++ 18 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 tests/baselines/reference/requireOfJsonFileWithoutAllowJs.js create mode 100644 tests/baselines/reference/requireOfJsonFileWithoutAllowJs.symbols create mode 100644 tests/baselines/reference/requireOfJsonFileWithoutAllowJs.types create mode 100644 tests/cases/compiler/requireOfJsonFileWithoutAllowJs.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b943135b006..249431aa97d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2084,7 +2084,7 @@ namespace ts { } // May be an untyped module. If so, ignore resolutionDiagnostic. - if (resolvedModule && !resolutionExtensionIsTypeScriptOrJson(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) { + if (resolvedModule && !extensionIsTypeScript(resolvedModule.extension) && resolutionDiagnostic === undefined || resolutionDiagnostic === Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type) { if (isForAugmentation) { const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented; error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName); diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 08378374c9b..a804b00f0b6 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -2037,7 +2037,8 @@ namespace ts { // Rather than requery this for each file and filespec, we query the supported extensions // once and store it on the expansion context. - const supportedExtensions = getSupportedExtensions(options, extraFileExtensions); + // When computing file names, do not include json files. Use only module resolution or explicit includes for them + const supportedExtensions = getSupportedExtensions(options, extraFileExtensions, /*excludeJson*/ true); // Literal files are always included verbatim. An "include" or "exclude" specification cannot // remove a literal file. diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 00a28dbbbcd..52358737dcf 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -2674,14 +2674,21 @@ namespace ts { export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray = [Extension.Dts, Extension.Ts, Extension.Tsx]; export const supportedJavascriptExtensions: ReadonlyArray = [Extension.Js, Extension.Jsx]; const allSupportedExtensions: ReadonlyArray = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions]; + let allSupportedExtensionsIncludingJson: ReadonlyArray | undefined; + function getAllSupportedExtensionsIncludingJson() { + return allSupportedExtensionsIncludingJson || (allSupportedExtensionsIncludingJson = [...allSupportedExtensions, Extension.Json]); + } - export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray): ReadonlyArray { + export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray, excludeJson?: boolean): ReadonlyArray { const needAllExtensions = options && options.allowJs; + const useJsonExtension = needAllExtensions && !excludeJson && getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeJs; if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) { - return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions; + return useJsonExtension ? + getAllSupportedExtensionsIncludingJson() : + needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions; } return deduplicate( - [...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)], + [...(useJsonExtension ? getAllSupportedExtensionsIncludingJson() : allSupportedExtensions), ...extraFileExtensions.map(e => e.extension)], equateStringsCaseSensitive, compareStringsCaseSensitive ); @@ -2691,6 +2698,10 @@ namespace ts { return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension)); } + export function hasJavaScriptOrJsonFileExtension(fileName: string) { + return hasJavaScriptFileExtension(fileName) || fileExtensionIs(fileName, Extension.Json); + } + export function hasTypeScriptFileExtension(fileName: string) { return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension)); } @@ -3091,10 +3102,6 @@ namespace ts { return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts; } - export function resolutionExtensionIsTypeScriptOrJson(ext: Extension) { - return extensionIsTypeScript(ext) || ext === Extension.Json; - } - /** * Gets the extension from a path. * Path must have a valid extension. @@ -3112,7 +3119,9 @@ namespace ts { } export function tryGetExtensionFromPath(path: string): Extension | undefined { - return find(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e)); + return find(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || + find(supportedJavascriptExtensions, e => fileExtensionIs(path, e)) || + (fileExtensionIs(path, Extension.Json) ? Extension.Json : undefined); } // Retrieves any string from the final "." onwards from a base file name. diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 30f310cac10..f1d97b68404 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -890,7 +890,7 @@ namespace ts { // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" - if (hasJavaScriptFileExtension(candidate) || fileExtensionIs(candidate, Extension.Json)) { + if (hasJavaScriptOrJsonFileExtension(candidate)) { const extensionless = removeFileExtension(candidate); if (state.traceEnabled) { const extension = candidate.substring(extensionless.length); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index b2ea3467916..7c7b480deff 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1975,7 +1975,7 @@ namespace ts { } const isFromNodeModulesSearch = resolution.isExternalLibraryImport; - const isJsFile = !resolutionExtensionIsTypeScriptOrJson(resolution.extension); + const isJsFile = !extensionIsTypeScript(resolution.extension); const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile; const resolvedFileName = resolution.resolvedFileName; @@ -2404,7 +2404,6 @@ namespace ts { switch (extension) { case Extension.Ts: case Extension.Dts: - case Extension.Json: // These are always allowed. return undefined; case Extension.Tsx: @@ -2412,6 +2411,7 @@ namespace ts { case Extension.Jsx: return needJsx() || needAllowJs(); case Extension.Js: + case Extension.Json: return needAllowJs(); } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7fdbbbc9640..1b849f36b3a 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -511,8 +511,9 @@ namespace FourSlash { } private getAllDiagnostics(): ts.Diagnostic[] { + const options = this.languageService.getProgram().getCompilerOptions(); return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => - ts.isAnySupportedFileExtension(fileName) ? this.getDiagnostics(fileName) : []); + ts.fileExtensionIsOneOf(fileName, ts.getSupportedExtensions(options)) ? this.getDiagnostics(fileName) : []); } public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) { diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index bd6c2e5cb9f..a32be9802c2 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -98,7 +98,7 @@ namespace ts.JsTyping { // Only infer typings for .js and .jsx files fileNames = mapDefined(fileNames, fileName => { const path = normalizePath(fileName); - if (hasJavaScriptFileExtension(path)) { + if (hasJavaScriptOrJsonFileExtension(path)) { return path; } }); @@ -193,7 +193,7 @@ namespace ts.JsTyping { */ function getTypingNamesFromSourceFileNames(fileNames: string[]) { const fromFileNames = mapDefined(fileNames, j => { - if (!hasJavaScriptFileExtension(j)) return undefined; + if (!hasJavaScriptOrJsonFileExtension(j)) return undefined; const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase())); const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName); diff --git a/tests/baselines/reference/jsFileCompilationWithMapFileAsJs.errors.txt b/tests/baselines/reference/jsFileCompilationWithMapFileAsJs.errors.txt index f9d88bd2727..5e0ff050c12 100644 --- a/tests/baselines/reference/jsFileCompilationWithMapFileAsJs.errors.txt +++ b/tests/baselines/reference/jsFileCompilationWithMapFileAsJs.errors.txt @@ -1,11 +1,11 @@ error TS5055: Cannot write file 'tests/cases/compiler/b.js' because it would overwrite input file. Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. -error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'. +error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'. !!! error TS5055: Cannot write file 'tests/cases/compiler/b.js' because it would overwrite input file. !!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. -!!! error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'. +!!! error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'. ==== tests/cases/compiler/a.ts (0 errors) ==== class c { } diff --git a/tests/baselines/reference/jsFileCompilationWithMapFileAsJsWithInlineSourceMap.errors.txt b/tests/baselines/reference/jsFileCompilationWithMapFileAsJsWithInlineSourceMap.errors.txt index f9d88bd2727..5e0ff050c12 100644 --- a/tests/baselines/reference/jsFileCompilationWithMapFileAsJsWithInlineSourceMap.errors.txt +++ b/tests/baselines/reference/jsFileCompilationWithMapFileAsJsWithInlineSourceMap.errors.txt @@ -1,11 +1,11 @@ error TS5055: Cannot write file 'tests/cases/compiler/b.js' because it would overwrite input file. Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. -error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'. +error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'. !!! error TS5055: Cannot write file 'tests/cases/compiler/b.js' because it would overwrite input file. !!! error TS5055: Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig. -!!! error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx'. +!!! error TS6054: File 'tests/cases/compiler/b.js.map' has unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.json'. ==== tests/cases/compiler/a.ts (0 errors) ==== class c { } diff --git a/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.js b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.js new file mode 100644 index 00000000000..ab52cbb1494 --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/requireOfJsonFileWithoutAllowJs.ts] //// + +//// [file1.ts] +import b1 = require('./b'); +let x = b1.a; +import b2 = require('./b.json'); +if (x) { + let b = b2.b; + x = (b1.b === b); +} + +//// [b.json] +{ + "a": true, + "b": "hello" +} + +//// [file1.js] +"use strict"; +exports.__esModule = true; +var b1 = require("./b"); +var x = b1.a; +var b2 = require("./b.json"); +if (x) { + var b = b2.b; + x = (b1.b === b); +} diff --git a/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.symbols b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.symbols new file mode 100644 index 00000000000..1729461ef07 --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.symbols @@ -0,0 +1,24 @@ +=== tests/cases/compiler/file1.ts === +import b1 = require('./b'); +>b1 : Symbol(b1, Decl(file1.ts, 0, 0)) + +let x = b1.a; +>x : Symbol(x, Decl(file1.ts, 1, 3)) +>b1 : Symbol(b1, Decl(file1.ts, 0, 0)) + +import b2 = require('./b.json'); +>b2 : Symbol(b2, Decl(file1.ts, 1, 13)) + +if (x) { +>x : Symbol(x, Decl(file1.ts, 1, 3)) + + let b = b2.b; +>b : Symbol(b, Decl(file1.ts, 4, 7)) +>b2 : Symbol(b2, Decl(file1.ts, 1, 13)) + + x = (b1.b === b); +>x : Symbol(x, Decl(file1.ts, 1, 3)) +>b1 : Symbol(b1, Decl(file1.ts, 0, 0)) +>b : Symbol(b, Decl(file1.ts, 4, 7)) +} + diff --git a/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.types b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.types new file mode 100644 index 00000000000..7984743550d --- /dev/null +++ b/tests/baselines/reference/requireOfJsonFileWithoutAllowJs.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/file1.ts === +import b1 = require('./b'); +>b1 : any + +let x = b1.a; +>x : any +>b1.a : any +>b1 : any +>a : any + +import b2 = require('./b.json'); +>b2 : any + +if (x) { +>x : any + + let b = b2.b; +>b : any +>b2.b : any +>b2 : any +>b : any + + x = (b1.b === b); +>x = (b1.b === b) : boolean +>x : any +>(b1.b === b) : boolean +>b1.b === b : boolean +>b1.b : any +>b1 : any +>b : any +>b : any +} + diff --git a/tests/cases/compiler/requireOfJsonFile.ts b/tests/cases/compiler/requireOfJsonFile.ts index d214bcda450..016c0795620 100644 --- a/tests/cases/compiler/requireOfJsonFile.ts +++ b/tests/cases/compiler/requireOfJsonFile.ts @@ -1,5 +1,6 @@ // @module: commonjs // @outdir: out/ +// @allowJs: true // @Filename: file1.ts import b1 = require('./b'); diff --git a/tests/cases/compiler/requireOfJsonFileWithAmd.ts b/tests/cases/compiler/requireOfJsonFileWithAmd.ts index 682874fe5c0..d37c9dd4f0e 100644 --- a/tests/cases/compiler/requireOfJsonFileWithAmd.ts +++ b/tests/cases/compiler/requireOfJsonFileWithAmd.ts @@ -1,5 +1,6 @@ // @module: amd // @outdir: out/ +// @allowJs: true // @Filename: file1.ts import b1 = require('./b'); diff --git a/tests/cases/compiler/requireOfJsonFileWithEmptyObject.ts b/tests/cases/compiler/requireOfJsonFileWithEmptyObject.ts index 4ec163b56e5..05f1d2d637c 100644 --- a/tests/cases/compiler/requireOfJsonFileWithEmptyObject.ts +++ b/tests/cases/compiler/requireOfJsonFileWithEmptyObject.ts @@ -1,5 +1,6 @@ // @module: commonjs // @outdir: out/ +// @allowJs: true // @Filename: file1.ts import b1 = require('./b'); diff --git a/tests/cases/compiler/requireOfJsonFileWithEmptyObjectWithErrors.ts b/tests/cases/compiler/requireOfJsonFileWithEmptyObjectWithErrors.ts index 4e1a21f938e..31ab0ea0a7c 100644 --- a/tests/cases/compiler/requireOfJsonFileWithEmptyObjectWithErrors.ts +++ b/tests/cases/compiler/requireOfJsonFileWithEmptyObjectWithErrors.ts @@ -1,5 +1,6 @@ // @module: commonjs // @outdir: out/ +// @allowJs: true // @Filename: file1.ts import b1 = require('./b'); diff --git a/tests/cases/compiler/requireOfJsonFileWithNoContent.ts b/tests/cases/compiler/requireOfJsonFileWithNoContent.ts index c0d94bb269a..4d3c63c6ffa 100644 --- a/tests/cases/compiler/requireOfJsonFileWithNoContent.ts +++ b/tests/cases/compiler/requireOfJsonFileWithNoContent.ts @@ -1,5 +1,6 @@ // @module: commonjs // @outdir: out/ +// @allowJs: true // @Filename: file1.ts import b1 = require('./b'); diff --git a/tests/cases/compiler/requireOfJsonFileWithoutAllowJs.ts b/tests/cases/compiler/requireOfJsonFileWithoutAllowJs.ts new file mode 100644 index 00000000000..d214bcda450 --- /dev/null +++ b/tests/cases/compiler/requireOfJsonFileWithoutAllowJs.ts @@ -0,0 +1,17 @@ +// @module: commonjs +// @outdir: out/ + +// @Filename: file1.ts +import b1 = require('./b'); +let x = b1.a; +import b2 = require('./b.json'); +if (x) { + let b = b2.b; + x = (b1.b === b); +} + +// @Filename: b.json +{ + "a": true, + "b": "hello" +} \ No newline at end of file