Merge pull request #13024 from Microsoft/package_json_unsupported_extension

Skip files from package.json "main" or "types" if they have an unsupported extension.
This commit is contained in:
Mohamed Hegazy 2016-12-20 15:44:37 -08:00 committed by GitHub
commit 328a5ef2ba
12 changed files with 169 additions and 16 deletions

View file

@ -2685,6 +2685,10 @@
"category": "Message",
"code": 6080
},
"File '{0}' has an unsupported extension, so skipping it.": {
"category": "Message",
"code": 6081
},
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
"category": "Error",
"code": 6082

View file

@ -47,11 +47,6 @@ namespace ts {
return resolved.path;
}
/** Create Resolved from a file with unknown extension. */
function resolvedFromAnyFile(path: string): Resolved | undefined {
return { path, extension: extensionFromPath(path) };
}
/** Adds `isExernalLibraryImport` to a Resolved to get a ResolvedModule. */
function resolvedModuleFromResolved({ path, extension }: Resolved, isExternalLibraryImport: boolean): ResolvedModuleFull {
return { resolvedFileName: path, extension, isExternalLibraryImport };
@ -71,7 +66,8 @@ namespace ts {
traceEnabled: boolean;
}
function tryReadTypesSection(extensions: Extensions, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
function tryReadPackageJsonMainOrTypes(extensions: Extensions, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
const jsonContent = readJson(packageJsonPath, state.host);
switch (extensions) {
@ -714,18 +710,21 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
const typesFile = tryReadTypesSection(extensions, packageJsonPath, candidate, state);
if (typesFile) {
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host);
const mainOrTypesFile = tryReadPackageJsonMainOrTypes(extensions, packageJsonPath, candidate, state);
if (mainOrTypesFile) {
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(mainOrTypesFile), state.host);
// A package.json "typings" may specify an exact filename, or may choose to omit an extension.
const fromFile = tryFile(typesFile, failedLookupLocations, onlyRecordFailures, state);
if (fromFile) {
// Note: this would allow a package.json to specify a ".js" file as typings. Maybe that should be forbidden.
return resolvedFromAnyFile(fromFile);
const fromExactFile = tryFile(mainOrTypesFile, failedLookupLocations, onlyRecordFailures, state);
if (fromExactFile) {
const resolved = fromExactFile && resolvedIfExtensionMatches(extensions, fromExactFile);
if (resolved) {
return resolved;
}
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromExactFile);
}
const x = tryAddingExtensions(typesFile, Extensions.TypeScript, failedLookupLocations, onlyRecordFailures, state);
if (x) {
return x;
const resolved = tryAddingExtensions(mainOrTypesFile, Extensions.TypeScript, failedLookupLocations, onlyRecordFailures, state);
if (resolved) {
return resolved;
}
}
else {
@ -745,6 +744,24 @@ namespace ts {
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
}
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
const extension = tryGetExtensionFromPath(path);
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
}
/** True if `extension` is one of the supported `extensions`. */
function extensionIsOk(extensions: Extensions, extension: Extension): boolean {
switch (extensions) {
case Extensions.JavaScript:
return extension === Extension.Js || extension === Extension.Jsx;
case Extensions.TypeScript:
return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Dts;
case Extensions.DtsOnly:
return extension === Extension.Dts;
}
}
function pathToPackageJson(directory: string): string {
return combinePaths(directory, "package.json");
}

View file

@ -0,0 +1,17 @@
//// [tests/cases/compiler/moduleResolutionWithExtensions_unexpected.ts] ////
//// [normalize.css]
// This tests that a package.json "main" with an unexpected extension is ignored.
This file is not read.
//// [package.json]
{ "main": "normalize.css" }
//// [a.ts]
import "normalize.css";
//// [a.js]
"use strict";
require("normalize.css");

View file

@ -0,0 +1,4 @@
=== /a.ts ===
import "normalize.css";
No type information for this code.
No type information for this code.

View file

@ -0,0 +1,29 @@
[
"======== Resolving module 'normalize.css' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module 'normalize.css' from 'node_modules' folder.",
"File '/node_modules/normalize.css.ts' does not exist.",
"File '/node_modules/normalize.css.tsx' does not exist.",
"File '/node_modules/normalize.css.d.ts' does not exist.",
"Found 'package.json' at '/node_modules/normalize.css/package.json'.",
"'package.json' does not have a 'types' or 'main' field.",
"File '/node_modules/normalize.css/index.ts' does not exist.",
"File '/node_modules/normalize.css/index.tsx' does not exist.",
"File '/node_modules/normalize.css/index.d.ts' does not exist.",
"File '/node_modules/@types/normalize.css.d.ts' does not exist.",
"File '/node_modules/@types/normalize.css/package.json' does not exist.",
"File '/node_modules/@types/normalize.css/index.d.ts' does not exist.",
"Loading module 'normalize.css' from 'node_modules' folder.",
"File '/node_modules/normalize.css.js' does not exist.",
"File '/node_modules/normalize.css.jsx' does not exist.",
"Found 'package.json' at '/node_modules/normalize.css/package.json'.",
"No types specified in 'package.json', so returning 'main' value of 'normalize.css'",
"File '/node_modules/normalize.css/normalize.css' exist - use it as a name resolution result.",
"File '/node_modules/normalize.css/normalize.css' has an unsupported extension, so skipping it.",
"File '/node_modules/normalize.css/normalize.css.ts' does not exist.",
"File '/node_modules/normalize.css/normalize.css.tsx' does not exist.",
"File '/node_modules/normalize.css/normalize.css.d.ts' does not exist.",
"File '/node_modules/normalize.css/index.js' does not exist.",
"File '/node_modules/normalize.css/index.jsx' does not exist.",
"======== Module name 'normalize.css' was not resolved. ========"
]

View file

@ -0,0 +1,4 @@
=== /a.ts ===
import "normalize.css";
No type information for this code.
No type information for this code.

View file

@ -0,0 +1,17 @@
//// [tests/cases/compiler/moduleResolutionWithExtensions_unexpected2.ts] ////
//// [foo.js]
// This tests that a package.json "types" with an unexpected extension is ignored.
This file is not read.
//// [package.json]
{ "types": "foo.js" }
//// [a.ts]
import "foo";
//// [a.js]
"use strict";
require("foo");

View file

@ -0,0 +1,4 @@
=== /a.ts ===
import "foo";
No type information for this code.
No type information for this code.

View file

@ -0,0 +1,29 @@
[
"======== Resolving module 'foo' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module 'foo' from 'node_modules' folder.",
"File '/node_modules/foo.ts' does not exist.",
"File '/node_modules/foo.tsx' does not exist.",
"File '/node_modules/foo.d.ts' does not exist.",
"Found 'package.json' at '/node_modules/foo/package.json'.",
"'package.json' has 'types' field 'foo.js' that references '/node_modules/foo/foo.js'.",
"File '/node_modules/foo/foo.js' exist - use it as a name resolution result.",
"File '/node_modules/foo/foo.js' has an unsupported extension, so skipping it.",
"File '/node_modules/foo/foo.js.ts' does not exist.",
"File '/node_modules/foo/foo.js.tsx' does not exist.",
"File '/node_modules/foo/foo.js.d.ts' does not exist.",
"File '/node_modules/foo/index.ts' does not exist.",
"File '/node_modules/foo/index.tsx' does not exist.",
"File '/node_modules/foo/index.d.ts' does not exist.",
"File '/node_modules/@types/foo.d.ts' does not exist.",
"File '/node_modules/@types/foo/package.json' does not exist.",
"File '/node_modules/@types/foo/index.d.ts' does not exist.",
"Loading module 'foo' from 'node_modules' folder.",
"File '/node_modules/foo.js' does not exist.",
"File '/node_modules/foo.jsx' does not exist.",
"Found 'package.json' at '/node_modules/foo/package.json'.",
"'package.json' does not have a 'types' or 'main' field.",
"File '/node_modules/foo/index.js' does not exist.",
"File '/node_modules/foo/index.jsx' does not exist.",
"======== Module name 'foo' was not resolved. ========"
]

View file

@ -0,0 +1,4 @@
=== /a.ts ===
import "foo";
No type information for this code.
No type information for this code.

View file

@ -0,0 +1,12 @@
// @noImplicitReferences: true
// @traceResolution: true
// This tests that a package.json "main" with an unexpected extension is ignored.
// @Filename: /node_modules/normalize.css/normalize.css
This file is not read.
// @Filename: /node_modules/normalize.css/package.json
{ "main": "normalize.css" }
// @Filename: /a.ts
import "normalize.css";

View file

@ -0,0 +1,12 @@
// @noImplicitReferences: true
// @traceResolution: true
// This tests that a package.json "types" with an unexpected extension is ignored.
// @Filename: /node_modules/foo/foo.js
This file is not read.
// @Filename: /node_modules/foo/package.json
{ "types": "foo.js" }
// @Filename: /a.ts
import "foo";