Look for package.json::main when resolving JS targets

This commit is contained in:
Mohamed Hegazy
2016-12-21 15:03:37 -08:00
parent e7668b0954
commit 051edacf26
10 changed files with 163 additions and 22 deletions

View File

@@ -1,4 +1,4 @@
/// <reference path="core.ts" />
/// <reference path="core.ts" />
/// <reference path="diagnosticInformationMap.generated.ts" />
namespace ts {
@@ -726,6 +726,13 @@ namespace ts {
if (resolved) {
return resolved;
}
if (extensions === Extensions.JavaScript) {
const resolved = tryAddingExtensions(mainOrTypesFile, Extensions.JavaScript, failedLookupLocations, onlyRecordFailures, state);
if (resolved) {
return resolved;
}
}
}
else {
if (state.traceEnabled) {

View File

@@ -1,4 +1,4 @@
/// <reference path="..\harness.ts" />
/// <reference path="..\harness.ts" />
namespace ts {
export function checkResolvedModule(expected: ResolvedModuleFull, actual: ResolvedModuleFull): boolean {
@@ -408,7 +408,7 @@ export = C;
"/a/b/c.ts": `/// <reference path="d.ts"/>`,
"/a/b/d.ts": "var x"
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "/a/b/d.ts"], []);
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "/a/b/d.ts"], []);
});
it("should fail when two files used in program differ only in casing (tripleslash references)", () => {
@@ -416,7 +416,7 @@ export = C;
"/a/b/c.ts": `/// <reference path="D.ts"/>`,
"/a/b/d.ts": "var x"
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports)", () => {
@@ -424,7 +424,7 @@ export = C;
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/d.ts": "export var x"
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports, relative module names)", () => {
@@ -432,7 +432,7 @@ export = C;
"moduleA.ts": `import {x} from "./ModuleB"`,
"moduleB.ts": "export var x"
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts"], [1149]);
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts"], [1149]);
});
it("should fail when two files exist on disk that differs only in casing", () => {
@@ -441,7 +441,7 @@ export = C;
"/a/b/D.ts": "export var x",
"/a/b/d.ts": "export var y"
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ true, ["c.ts", "d.ts"], [1149]);
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ true, ["c.ts", "d.ts"], [1149]);
});
it("should fail when module name in 'require' calls has inconsistent casing", () => {
@@ -450,7 +450,7 @@ export = C;
"moduleB.ts": `import a = require("./moduleC")`,
"moduleC.ts": "export var x"
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts", "moduleC.ts"], [1149, 1149]);
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts", "moduleC.ts"], [1149, 1149]);
});
it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => {
@@ -463,7 +463,7 @@ import a = require("./moduleA");
import b = require("./moduleB");
`
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]);
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]);
});
it("should not fail when module names in 'require' calls has consistent casing and current directory has uppercase chars", () => {
const files = createMap({
@@ -475,7 +475,7 @@ import a = require("./moduleA");
import b = require("./moduleB");
`
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []);
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []);
});
});
@@ -490,7 +490,7 @@ import b = require("./moduleB");
const file2: File = { name: "/root/folder2/file2.ts" };
const file3: File = { name: "/root/folder2/file3.ts" };
const host = createModuleResolutionHost(hasDirectoryExists, file1, file2, file3);
for (const moduleResolution of [ ModuleResolutionKind.NodeJs, ModuleResolutionKind.Classic ]) {
for (const moduleResolution of [ModuleResolutionKind.NodeJs, ModuleResolutionKind.Classic]) {
const options: CompilerOptions = { moduleResolution, baseUrl: "/root" };
{
const result = resolveModuleName("folder2/file2", file1.name, options, host);
@@ -703,7 +703,7 @@ import b = require("./moduleB");
}
});
it ("classic + baseUrl + path mappings", () => {
it("classic + baseUrl + path mappings", () => {
// classic mode does not use directoryExists
test(/*hasDirectoryExists*/ false);
@@ -762,7 +762,7 @@ import b = require("./moduleB");
}
});
it ("node + rootDirs", () => {
it("node + rootDirs", () => {
test(/*hasDirectoryExists*/ false);
test(/*hasDirectoryExists*/ true);
@@ -835,7 +835,7 @@ import b = require("./moduleB");
}
});
it ("classic + rootDirs", () => {
it("classic + rootDirs", () => {
test(/*hasDirectoryExists*/ false);
function test(hasDirectoryExists: boolean) {
@@ -889,7 +889,7 @@ import b = require("./moduleB");
}
});
it ("nested node module", () => {
it("nested node module", () => {
test(/*hasDirectoryExists*/ false);
test(/*hasDirectoryExists*/ true);
@@ -902,9 +902,9 @@ import b = require("./moduleB");
moduleResolution: ModuleResolutionKind.NodeJs,
baseUrl: "/root",
paths: {
"libs/guid": [ "src/libs/guid" ]
"libs/guid": ["src/libs/guid"]
}
};
};
const result = resolveModuleName("libs/guid", app.name, options, host);
checkResolvedModuleWithFailedLookupLocations(result, createResolvedModule(libsTypings.name), [
// first try to load module as file
@@ -1020,7 +1020,7 @@ import b = require("./moduleB");
const names = map(files, f => f.name);
const sourceFiles = arrayToMap(map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES2015)), f => f.fileName);
const compilerHost: CompilerHost = {
fileExists : fileName => fileName in sourceFiles,
fileExists: fileName => fileName in sourceFiles,
getSourceFile: fileName => sourceFiles[fileName],
getDefaultLibFileName: () => "lib.d.ts",
writeFile: notImplemented,
@@ -1042,7 +1042,7 @@ import b = require("./moduleB");
assert.equal(diagnostics1[0].messageText, diagnostics2[0].messageText, "expected one diagnostic");
});
it ("Modules in the same .d.ts file are preferred to external files", () => {
it("Modules in the same .d.ts file are preferred to external files", () => {
const f = {
name: "/a/b/c/c/app.d.ts",
content: `
@@ -1056,7 +1056,7 @@ import b = require("./moduleB");
};
const file = createSourceFile(f.name, f.content, ScriptTarget.ES2015);
const compilerHost: CompilerHost = {
fileExists : fileName => fileName === file.fileName,
fileExists: fileName => fileName === file.fileName,
getSourceFile: fileName => fileName === file.fileName ? file : undefined,
getDefaultLibFileName: () => "lib.d.ts",
writeFile: notImplemented,
@@ -1074,7 +1074,7 @@ import b = require("./moduleB");
createProgram([f.name], {}, compilerHost);
});
it ("Modules in .ts file are not checked in the same file", () => {
it("Modules in .ts file are not checked in the same file", () => {
const f = {
name: "/a/b/c/c/app.ts",
content: `
@@ -1088,7 +1088,7 @@ import b = require("./moduleB");
};
const file = createSourceFile(f.name, f.content, ScriptTarget.ES2015);
const compilerHost: CompilerHost = {
fileExists : fileName => fileName === file.fileName,
fileExists: fileName => fileName === file.fileName,
getSourceFile: fileName => fileName === file.fileName ? file : undefined,
getDefaultLibFileName: () => "lib.d.ts",
writeFile: notImplemented,
@@ -1105,5 +1105,31 @@ import b = require("./moduleB");
};
createProgram([f.name], {}, compilerHost);
});
it("Module name as directory - load js from 'main'", () => {
test(/*hasDirectoryExists*/ false);
test(/*hasDirectoryExists*/ true);
function test(hasDirectoryExists: boolean) {
const containingFile = { name: "/a/b.ts" };
const packageJson = { name: "/a/c/package.json", content: JSON.stringify({ main: "d/e" }) };
const indexFile = { name: "/a/c/d/e.js" };
const resolution = nodeModuleNameResolver("./c", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, indexFile));
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(indexFile.name), [
"/a/c.ts",
"/a/c.tsx",
"/a/c.d.ts",
"/a/c/index.ts",
"/a/c/index.tsx",
"/a/c/index.d.ts",
"/a/c.js",
"/a/c.jsx",
"/a/c/d/e",
"/a/c/d/e.ts",
"/a/c/d/e.tsx",
"/a/c/d/e.d.ts",
]);
}
});
});
}

View File

@@ -23,6 +23,8 @@
"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/normalize.css.js' does not exist.",
"File '/node_modules/normalize.css/normalize.css.jsx' 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,22 @@
//// [tests/cases/conformance/moduleResolution/untypedModuleImport_MainInPackageJson.ts] ////
//// [foo.js]
// This tests that importing from a JS file globally works in an untyped way.
// (Assuming we don't have `--noImplicitAny` or `--allowJs`.)
This file is not processed.
//// [package.json]
{
"main": "lib/foo"
}
//// [a.ts]
import * as foo from "foo";
foo.bar();
//// [a.js]
"use strict";
var foo = require("foo");
foo.bar();

View File

@@ -0,0 +1,7 @@
=== /a.ts ===
import * as foo from "foo";
>foo : Symbol(foo, Decl(a.ts, 0, 6))
foo.bar();
>foo : Symbol(foo, Decl(a.ts, 0, 6))

View File

@@ -0,0 +1,10 @@
=== /a.ts ===
import * as foo from "foo";
>foo : any
foo.bar();
>foo.bar() : any
>foo.bar : any
>foo : any
>bar : any

View File

@@ -0,0 +1,18 @@
/a.ts(1,22): error TS7016: Could not find a declaration file for module 'foo'. '/node_modules/foo/lib/foo.js' implicitly has an 'any' type.
==== /a.ts (1 errors) ====
import * as foo from "foo";
~~~~~
!!! error TS7016: Could not find a declaration file for module 'foo'. '/node_modules/foo/lib/foo.js' implicitly has an 'any' type.
==== /node_modules/foo/lib/foo.js (0 errors) ====
// This tests that `--noImplicitAny` disables untyped modules.
This file is not processed.
==== /node_modules/foo/package.json (0 errors) ====
{
"main": "lib/foo"
}

View File

@@ -0,0 +1,18 @@
//// [tests/cases/conformance/moduleResolution/untypedModuleImport_noImplicitAny2.ts] ////
//// [foo.js]
// This tests that `--noImplicitAny` disables untyped modules.
This file is not processed.
//// [package.json]
{
"main": "lib/foo"
}
//// [a.ts]
import * as foo from "foo";
//// [a.js]
"use strict";

View File

@@ -0,0 +1,16 @@
// @noImplicitReferences: true
// @currentDirectory: /
// This tests that importing from a JS file globally works in an untyped way.
// (Assuming we don't have `--noImplicitAny` or `--allowJs`.)
// @filename: /node_modules/foo/lib/foo.js
This file is not processed.
// @filename: /node_modules/foo/package.json
{
"main": "lib/foo"
}
// @filename: /a.ts
import * as foo from "foo";
foo.bar();

View File

@@ -0,0 +1,15 @@
// @noImplicitReferences: true
// @currentDirectory: /
// @noImplicitAny: true
// This tests that `--noImplicitAny` disables untyped modules.
// @filename: /node_modules/foo/lib/foo.js
This file is not processed.
// @filename: /node_modules/foo/package.json
{
"main": "lib/foo"
}
// @filename: /a.ts
import * as foo from "foo";