Merge pull request #4744 from Microsoft/Port-4738

Ports PR-4738 into release-1.6
This commit is contained in:
Vladimir Matveev 2015-09-11 10:20:55 -07:00
commit fa7a59fdcf
28 changed files with 347 additions and 144 deletions

View file

@ -976,8 +976,8 @@ namespace ts {
}
}
let fileName = getResolvedModuleFileName(getSourceFile(location), moduleReferenceLiteral.text);
let sourceFile = fileName && host.getSourceFile(fileName);
let resolvedModule = getResolvedModule(getSourceFile(location), moduleReferenceLiteral.text);
let sourceFile = resolvedModule && host.getSourceFile(resolvedModule.resolvedFileName);
if (sourceFile) {
if (sourceFile.symbol) {
return sourceFile.symbol;

View file

@ -427,6 +427,8 @@ namespace ts {
Cannot_emit_namespaced_JSX_elements_in_React: { code: 2650, category: DiagnosticCategory.Error, key: "Cannot emit namespaced JSX elements in React" },
A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums: { code: 2651, category: DiagnosticCategory.Error, key: "A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums." },
Merged_declaration_0_cannot_include_a_default_export_declaration_Consider_adding_a_separate_export_default_0_declaration_instead: { code: 2652, category: DiagnosticCategory.Error, key: "Merged declaration '{0}' cannot include a default export declaration. Consider adding a separate 'export default {0}' declaration instead." },
Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition: { code: 2654, category: DiagnosticCategory.Error, key: "Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition." },
Exported_external_package_typings_can_only_be_in_d_ts_files_Please_contact_the_package_author_to_update_the_package_definition: { code: 2655, category: DiagnosticCategory.Error, key: "Exported external package typings can only be in '.d.ts' files. Please contact the package author to update the package definition." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

View file

@ -1697,6 +1697,14 @@
"category": "Error",
"code": 2652
},
"Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.": {
"category": "Error",
"code": 2654
},
"Exported external package typings can only be in '.d.ts' files. Please contact the package author to update the package definition.": {
"category": "Error",
"code": 2655
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000

View file

@ -36,7 +36,7 @@ namespace ts {
return normalizePath(referencedFileName);
}
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
let moduleResolution = compilerOptions.moduleResolution !== undefined
? compilerOptions.moduleResolution
: compilerOptions.module === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic;
@ -47,7 +47,7 @@ namespace ts {
}
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModule {
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
let containingDirectory = getDirectoryPath(containingFile);
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
@ -56,11 +56,13 @@ namespace ts {
let resolvedFileName = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
if (resolvedFileName) {
return { resolvedFileName, failedLookupLocations };
return { resolvedModule: { resolvedFileName }, failedLookupLocations };
}
resolvedFileName = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ false, failedLookupLocations, host);
return { resolvedFileName, failedLookupLocations };
return resolvedFileName
? { resolvedModule: { resolvedFileName }, failedLookupLocations }
: { resolvedModule: undefined, failedLookupLocations };
}
else {
return loadModuleFromNodeModules(moduleName, containingDirectory, host);
@ -117,7 +119,7 @@ namespace ts {
return loadNodeModuleFromFile(combinePaths(candidate, "index"), loadOnlyDts, failedLookupLocation, host);
}
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModule {
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
let failedLookupLocations: string[] = [];
directory = normalizeSlashes(directory);
while (true) {
@ -127,12 +129,12 @@ namespace ts {
let candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
let result = loadNodeModuleFromFile(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
if (result) {
return { resolvedFileName: result, failedLookupLocations };
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
}
result = loadNodeModuleFromDirectory(candidate, /* loadOnlyDts */ true, failedLookupLocations, host);
if (result) {
return { resolvedFileName: result, failedLookupLocations };
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
}
}
@ -144,47 +146,19 @@ namespace ts {
directory = parentPath;
}
return { resolvedFileName: undefined, failedLookupLocations };
}
export function baseUrlModuleNameResolver(moduleName: string, containingFile: string, baseUrl: string, host: ModuleResolutionHost): ResolvedModule {
Debug.assert(baseUrl !== undefined);
let normalizedModuleName = normalizeSlashes(moduleName);
let basePart = useBaseUrl(moduleName) ? baseUrl : getDirectoryPath(containingFile);
let candidate = normalizePath(combinePaths(basePart, moduleName));
let failedLookupLocations: string[] = [];
return forEach(supportedExtensions, ext => tryLoadFile(candidate + ext)) || { resolvedFileName: undefined, failedLookupLocations };
function tryLoadFile(location: string): ResolvedModule {
if (host.fileExists(location)) {
return { resolvedFileName: location, failedLookupLocations };
}
else {
failedLookupLocations.push(location);
return undefined;
}
}
return { resolvedModule: undefined, failedLookupLocations };
}
function nameStartsWithDotSlashOrDotDotSlash(name: string) {
let i = name.lastIndexOf("./", 1);
return i === 0 || (i === 1 && name.charCodeAt(0) === CharacterCodes.dot);
}
function useBaseUrl(moduleName: string): boolean {
// path is not rooted
// module name does not start with './' or '../'
return getRootLength(moduleName) === 0 && !nameStartsWithDotSlashOrDotDotSlash(moduleName);
}
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
// module names that contain '!' are used to reference resources and are not resolved to actual files on disk
if (moduleName.indexOf('!') != -1) {
return { resolvedFileName: undefined, failedLookupLocations: [] };
return { resolvedModule: undefined, failedLookupLocations: [] };
}
let searchPath = getDirectoryPath(containingFile);
@ -222,7 +196,9 @@ namespace ts {
searchPath = parentPath;
}
return { resolvedFileName: referencedSourceFile, failedLookupLocations };
return referencedSourceFile
? { resolvedModule: { resolvedFileName: referencedSourceFile }, failedLookupLocations }
: { resolvedModule: undefined, failedLookupLocations };
}
/* @internal */
@ -372,9 +348,9 @@ namespace ts {
host = host || createCompilerHost(options);
const resolveModuleNamesWorker =
host.resolveModuleNames ||
((moduleNames, containingFile) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedFileName));
const resolveModuleNamesWorker = host.resolveModuleNames
? ((moduleNames: string[], containingFile: string) => host.resolveModuleNames(moduleNames, containingFile))
: ((moduleNames: string[], containingFile: string) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedModule));
let filesByName = createFileMap<SourceFile>(fileName => host.getCanonicalFileName(fileName));
@ -494,10 +470,17 @@ namespace ts {
let resolutions = resolveModuleNamesWorker(moduleNames, newSourceFile.fileName);
// ensure that module resolution results are still correct
for (let i = 0; i < moduleNames.length; ++i) {
let oldResolution = getResolvedModuleFileName(oldSourceFile, moduleNames[i]);
if (oldResolution !== resolutions[i]) {
let newResolution = resolutions[i];
let oldResolution = getResolvedModule(oldSourceFile, moduleNames[i]);
let resolutionChanged = oldResolution
? !newResolution ||
oldResolution.resolvedFileName !== newResolution.resolvedFileName ||
!!oldResolution.isExternalLibraryImport !== !!newResolution.isExternalLibraryImport
: newResolution;
if (resolutionChanged) {
return false;
}
}
}
}
// pass the cache of module resolutions from the old source file
@ -874,9 +857,23 @@ namespace ts {
let resolutions = resolveModuleNamesWorker(moduleNames, file.fileName);
for (let i = 0; i < file.imports.length; ++i) {
let resolution = resolutions[i];
setResolvedModuleName(file, moduleNames[i], resolution);
setResolvedModule(file, moduleNames[i], resolution);
if (resolution && !options.noResolve) {
findModuleSourceFile(resolution, file.imports[i]);
const importedFile = findModuleSourceFile(resolution.resolvedFileName, file.imports[i]);
if (importedFile && resolution.isExternalLibraryImport) {
if (!isExternalModule(importedFile)) {
let start = getTokenPosOfNode(file.imports[i], file)
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.File_0_is_not_a_module, importedFile.fileName));
}
else if (!fileExtensionIs(importedFile.fileName, ".d.ts")) {
let start = getTokenPosOfNode(file.imports[i], file)
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_can_only_be_in_d_ts_files_Please_contact_the_package_author_to_update_the_package_definition));
}
else if (importedFile.referencedFiles.length) {
let firstRef = importedFile.referencedFiles[0];
fileProcessingDiagnostics.add(createFileDiagnostic(importedFile, firstRef.pos, firstRef.end - firstRef.pos, Diagnostics.Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition));
}
}
}
}
}

View file

@ -1284,7 +1284,7 @@ namespace ts {
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
// It is used to resolve module names in the checker.
// Content of this fiels should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<string>;
/* @internal */ resolvedModules: Map<ResolvedModule>;
/* @internal */ imports: LiteralExpression[];
}
@ -2283,11 +2283,20 @@ namespace ts {
export interface ResolvedModule {
resolvedFileName: string;
/*
* Denotes if 'resolvedFileName' is isExternalLibraryImport and thus should be proper external module:
* - be a .d.ts file
* - use top level imports\exports
* - don't use tripleslash references
*/
isExternalLibraryImport?: boolean;
}
export interface ResolvedModuleWithFailedLookupLocations {
resolvedModule: ResolvedModule;
failedLookupLocations: string[];
}
export type ModuleNameResolver = (moduleName: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => ResolvedModule;
export interface CompilerHost extends ModuleResolutionHost {
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
getCancellationToken?(): CancellationToken;
@ -2305,7 +2314,7 @@ namespace ts {
* If resolveModuleNames is implemented then implementation for members from ModuleResolutionHost can be just
* 'throw new Error("NotImplemented")'
*/
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
}
export interface TextSpan {

View file

@ -99,20 +99,20 @@ namespace ts {
return true;
}
export function hasResolvedModuleName(sourceFile: SourceFile, moduleNameText: string): boolean {
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
return sourceFile.resolvedModules && hasProperty(sourceFile.resolvedModules, moduleNameText);
}
export function getResolvedModuleFileName(sourceFile: SourceFile, moduleNameText: string): string {
return hasResolvedModuleName(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
}
export function setResolvedModuleName(sourceFile: SourceFile, moduleNameText: string, resolvedFileName: string): void {
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = {};
}
sourceFile.resolvedModules[moduleNameText] = resolvedFileName;
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
}
// Returns true if this node contains a parse error anywhere underneath it.

View file

@ -225,8 +225,8 @@ module Harness.LanguageService {
let imports: ts.Map<string> = {};
for (let module of preprocessInfo.importedFiles) {
let resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost);
if (resolutionInfo.resolvedFileName) {
imports[module.fileName] = resolutionInfo.resolvedFileName;
if (resolutionInfo.resolvedModule) {
imports[module.fileName] = resolutionInfo.resolvedModule.resolvedFileName;
}
}
return JSON.stringify(imports);

View file

@ -79,7 +79,7 @@ namespace ts.server {
}
}
interface TimestampedResolvedModule extends ResolvedModule {
interface TimestampedResolvedModule extends ResolvedModuleWithFailedLookupLocations {
lastCheckTime: number;
}
@ -99,11 +99,11 @@ namespace ts.server {
}
}
resolveModuleNames(moduleNames: string[], containingFile: string): string[] {
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModule[] {
let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile);
let newResolutions: Map<TimestampedResolvedModule> = {};
let resolvedFileNames: string[] = [];
let resolvedModules: ResolvedModule[] = [];
let compilerOptions = this.getCompilationSettings();
@ -119,25 +119,25 @@ namespace ts.server {
else {
resolution = <TimestampedResolvedModule>resolveModuleName(moduleName, containingFile, compilerOptions, this.moduleResolutionHost);
resolution.lastCheckTime = Date.now();
newResolutions[moduleName] = resolution;
newResolutions[moduleName] = resolution;
}
}
ts.Debug.assert(resolution !== undefined);
resolvedFileNames.push(resolution.resolvedFileName);
resolvedModules.push(resolution.resolvedModule);
}
// replace old results with a new one
this.resolvedModuleNames.set(containingFile, newResolutions);
return resolvedFileNames;
return resolvedModules;
function moduleResolutionIsValid(resolution: TimestampedResolvedModule): boolean {
if (!resolution) {
return false;
}
if (resolution.resolvedFileName) {
if (resolution.resolvedModule) {
// TODO: consider checking failedLookupLocations
// TODO: use lastCheckTime to track expiration for module name resolution
return true;

View file

@ -802,7 +802,7 @@ namespace ts {
public languageVariant: LanguageVariant;
public identifiers: Map<string>;
public nameTable: Map<string>;
public resolvedModules: Map<string>;
public resolvedModules: Map<ResolvedModule>;
public imports: LiteralExpression[];
private namedDeclarations: Map<Declaration[]>;
@ -1022,7 +1022,7 @@ namespace ts {
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
* host specific questions using 'getScriptSnapshot'.
*/
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
}
//

View file

@ -273,7 +273,7 @@ namespace ts {
private loggingEnabled = false;
private tracingEnabled = false;
public resolveModuleNames: (moduleName: string[], containingFile: string) => string[];
public resolveModuleNames: (moduleName: string[], containingFile: string) => ResolvedModule[];
constructor(private shimHost: LanguageServiceShimHost) {
// if shimHost is a COM object then property check will become method call with no arguments.
@ -281,7 +281,10 @@ namespace ts {
if ("getModuleResolutionsForFile" in this.shimHost) {
this.resolveModuleNames = (moduleNames: string[], containingFile: string) => {
let resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
return map(moduleNames, name => lookUp(resolutionsInFile, name));
return map(moduleNames, name => {
const result = lookUp(resolutionsInFile, name);
return result ? { resolvedFileName: result } : undefined;
});
};
}
}
@ -942,7 +945,11 @@ namespace ts {
public resolveModuleName(fileName: string, moduleName: string, compilerOptionsJson: string): string {
return this.forwardJSONCall(`resolveModuleName('${fileName}')`, () => {
let compilerOptions = <CompilerOptions>JSON.parse(compilerOptionsJson);
return resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host);
const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host);
return {
resolvedFileName: result.resolvedModule ? result.resolvedModule.resolvedFileName: undefined,
failedLookupLocations: result.failedLookupLocations
};
});
}

View file

@ -0,0 +1,17 @@
//// [tests/cases/compiler/nodeResolution4.ts] ////
//// [ref.ts]
var x = 1;
//// [a.ts]
/// <reference path="ref.ts"/>
export var y;
//// [b.ts]
import y = require("./a");
//// [ref.js]
var x = 1;
//// [a.js]
//// [b.js]

View file

@ -0,0 +1,14 @@
=== tests/cases/compiler/b.ts ===
import y = require("./a");
>y : Symbol(y, Decl(b.ts, 0, 0))
=== tests/cases/compiler/ref.ts ===
var x = 1;
>x : Symbol(x, Decl(ref.ts, 1, 3))
=== tests/cases/compiler/a.ts ===
/// <reference path="ref.ts"/>
export var y;
>y : Symbol(y, Decl(a.ts, 1, 10))

View file

@ -0,0 +1,15 @@
=== tests/cases/compiler/b.ts ===
import y = require("./a");
>y : typeof y
=== tests/cases/compiler/ref.ts ===
var x = 1;
>x : number
>1 : number
=== tests/cases/compiler/a.ts ===
/// <reference path="ref.ts"/>
export var y;
>y : any

View file

@ -0,0 +1,14 @@
tests/cases/compiler/b.ts(1,20): error TS2306: File 'tests/cases/compiler/node_modules/a.d.ts' is not a module.
==== tests/cases/compiler/b.ts (1 errors) ====
import y = require("a");
~~~
!!! error TS2306: File 'a.d.ts' is not a module.
==== tests/cases/compiler/node_modules/a.d.ts (0 errors) ====
declare module "a" {
var x: number;
}

View file

@ -0,0 +1,13 @@
//// [tests/cases/compiler/nodeResolution5.ts] ////
//// [a.d.ts]
declare module "a" {
var x: number;
}
//// [b.ts]
import y = require("a");
//// [b.js]

View file

@ -0,0 +1,17 @@
tests/cases/compiler/node_modules/a.d.ts(1,1): error TS2654: Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.
==== tests/cases/compiler/b.ts (0 errors) ====
import y = require("a");
==== tests/cases/compiler/node_modules/ref.ts (0 errors) ====
var x = 1;
==== tests/cases/compiler/node_modules/a.d.ts (1 errors) ====
/// <reference path="ref.ts"/>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2654: Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.
export declare var y;

View file

@ -0,0 +1,18 @@
//// [tests/cases/compiler/nodeResolution6.ts] ////
//// [ref.ts]
var x = 1;
//// [a.d.ts]
/// <reference path="ref.ts"/>
export declare var y;
//// [b.ts]
import y = require("a");
//// [ref.js]
var x = 1;
//// [b.js]

View file

@ -0,0 +1,14 @@
tests/cases/compiler/b.ts(1,20): error TS2306: File 'tests/cases/compiler/node_modules/a/index.d.ts' is not a module.
==== tests/cases/compiler/b.ts (1 errors) ====
import y = require("a");
~~~
!!! error TS2306: File 'index.d.ts' is not a module.
==== tests/cases/compiler/node_modules/a/index.d.ts (0 errors) ====
declare module "a" {
var x: number;
}

View file

@ -0,0 +1,13 @@
//// [tests/cases/compiler/nodeResolution7.ts] ////
//// [index.d.ts]
declare module "a" {
var x: number;
}
//// [b.ts]
import y = require("a");
//// [b.js]

View file

@ -0,0 +1,16 @@
tests/cases/compiler/node_modules/a/index.d.ts(1,1): error TS2654: Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.
==== tests/cases/compiler/b.ts (0 errors) ====
import y = require("a");
==== tests/cases/compiler/node_modules/a/ref.ts (0 errors) ====
var x = 1;
==== tests/cases/compiler/node_modules/a/index.d.ts (1 errors) ====
/// <reference path="ref.ts"/>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2654: Exported external package typings file cannot contain tripleslash references. Please contact the package author to update the package definition.
export declare var y;

View file

@ -0,0 +1,17 @@
//// [tests/cases/compiler/nodeResolution8.ts] ////
//// [ref.ts]
var x = 1;
//// [index.d.ts]
/// <reference path="ref.ts"/>
export declare var y;
//// [b.ts]
import y = require("a");
//// [ref.js]
var x = 1;
//// [b.js]

View file

@ -0,0 +1,12 @@
// @module: commonjs
// @moduleResolution: node
// @filename: ref.ts
var x = 1;
// @filename: a.ts
/// <reference path="ref.ts"/>
export var y;
// @filename: b.ts
import y = require("./a");

View file

@ -0,0 +1,10 @@
// @module: commonjs
// @moduleResolution: node
// @filename: node_modules/a.d.ts
declare module "a" {
var x: number;
}
// @filename: b.ts
import y = require("a");

View file

@ -0,0 +1,13 @@
// @module: commonjs
// @moduleResolution: node
// @filename: node_modules/ref.ts
var x = 1;
// @filename: node_modules/a.d.ts
/// <reference path="ref.ts"/>
export declare var y;
// @filename: b.ts
import y = require("a");

View file

@ -0,0 +1,10 @@
// @module: commonjs
// @moduleResolution: node
// @filename: node_modules/a/index.d.ts
declare module "a" {
var x: number;
}
// @filename: b.ts
import y = require("a");

View file

@ -0,0 +1,13 @@
// @module: commonjs
// @moduleResolution: node
// @filename: node_modules/a/ref.ts
var x = 1;
// @filename: node_modules/a/index.d.ts
/// <reference path="ref.ts"/>
export declare var y;
// @filename: b.ts
import y = require("a");

View file

@ -40,8 +40,9 @@ module ts {
let containingFile = { name: containingFileName }
let moduleFile = { name: moduleFileNameNoExt + ext }
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.resolvedFileName, moduleFile.name);
assert.equal(!!resolution.resolvedModule.isExternalLibraryImport, false);
let failedLookupLocations: string[] = [];
let dir = getDirectoryPath(containingFileName);
for (let e of supportedExtensions) {
@ -78,7 +79,8 @@ module ts {
let packageJson = { name: packageJsonFileName, content: JSON.stringify({ "typings": fieldRef }) };
let moduleFile = { name: moduleFileName };
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, packageJson, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.resolvedFileName, moduleFile.name);
assert.equal(!!resolution.resolvedModule.isExternalLibraryImport, false);
// expect three failed lookup location - attempt to load module as file with all supported extensions
assert.equal(resolution.failedLookupLocations.length, 3);
}
@ -95,7 +97,8 @@ module ts {
let packageJson = {name: "/a/b/foo/package.json", content: JSON.stringify({main: "/c/d"})};
let indexFile = { name: "/a/b/foo/index.d.ts" };
let resolution = nodeModuleNameResolver("./foo", containingFile.name, createModuleResolutionHost(containingFile, packageJson, indexFile));
assert.equal(resolution.resolvedFileName, indexFile.name);
assert.equal(resolution.resolvedModule.resolvedFileName, indexFile.name);
assert.equal(!!resolution.resolvedModule.isExternalLibraryImport, false);
assert.deepEqual(resolution.failedLookupLocations, [
"/a/b/foo.ts",
"/a/b/foo.tsx",
@ -111,7 +114,7 @@ module ts {
let containingFile = { name: "/a/b/c/d/e.ts" };
let moduleFile = { name: "/a/b/node_modules/foo.ts" };
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, undefined);
assert.equal(resolution.resolvedModule, undefined);
assert.deepEqual(resolution.failedLookupLocations, [
"/a/b/c/d/node_modules/foo.d.ts",
"/a/b/c/d/node_modules/foo/package.json",
@ -135,14 +138,16 @@ module ts {
let containingFile = { name: "/a/b/c/d/e.ts" };
let moduleFile = { name: "/a/b/node_modules/foo.d.ts" };
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.isExternalLibraryImport, true);
});
it("load module as directory", () => {
let containingFile = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
let moduleFile = { name: "/a/node_modules/foo/index.d.ts" };
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.resolvedFileName, moduleFile.name);
assert.equal(resolution.resolvedModule.isExternalLibraryImport, true);
assert.deepEqual(resolution.failedLookupLocations, [
"/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts",
"/a/node_modules/b/c/node_modules/d/node_modules/foo/package.json",
@ -158,64 +163,4 @@ module ts {
]);
});
});
describe("BaseUrl mode", () => {
it ("load module as relative url", () => {
function test(containingFileName: string, moduleFileName: string, moduleName: string): void {
let containingFile = {name: containingFileName };
let moduleFile = { name: moduleFileName };
let resolution = baseUrlModuleNameResolver(moduleName, containingFile.name, "<some-value>", createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
let expectedFailedLookupLocations: string[] = [];
let moduleNameHasExt = forEach(supportedExtensions, e => fileExtensionIs(moduleName, e));
if (!moduleNameHasExt) {
let dir = getDirectoryPath(containingFileName);
// add candidates with extensions that precede extension of the actual module name file in the list of supportd extensions
for (let ext of supportedExtensions) {
let hasExtension = ext !== ".ts"
? fileExtensionIs(moduleFileName, ext)
: fileExtensionIs(moduleFileName, ".ts") && !fileExtensionIs(moduleFileName, ".d.ts");
if (hasExtension) {
break;
}
else {
expectedFailedLookupLocations.push(normalizePath(combinePaths(dir, moduleName + ext)));
}
}
}
assert.deepEqual(resolution.failedLookupLocations, expectedFailedLookupLocations)
}
test("/a/b/c/d.ts", "/foo.ts", "/foo");
test("/a/b/c/d.ts", "/foo.d.ts", "/foo");
test("/a/b/c/d.ts", "/foo.tsx", "/foo");
test("/a/b/c/d.ts", "/a/b/c/foo.ts", "./foo");
test("/a/b/c/d.ts", "/a/b/c/foo.d.ts", "./foo");
test("/a/b/c/d.ts", "/a/b/c/foo.tsx", "./foo");
test("/a/b/c/d.ts", "/a/b/foo.ts", "../foo");
test("/a/b/c/d.ts", "/a/b/foo.d.ts", "../foo");
test("/a/b/c/d.ts", "/a/b/foo.tsx", "../foo");
});
it ("load module using base url", () => {
function test(containingFileName: string, moduleFileName: string, moduleName: string, baseUrl: string): void {
let containingFile = { name: containingFileName };
let moduleFile = { name: moduleFileName };
let resolution = baseUrlModuleNameResolver(moduleName, containingFileName, baseUrl, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
}
test("/a/base/c/d.ts", "/a/base/c/d/e.ts", "c/d/e", "/a/base");
test("/a/base/c/d.ts", "/a/base/c/d/e.d.ts", "c/d/e", "/a/base");
test("/a/base/c/d.ts", "/a/base/c/d/e.tsx", "c/d/e", "/a/base");
});
});
}

View file

@ -160,7 +160,7 @@ module ts {
return size;
}
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<string>): void {
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule>): void {
let file = program.getSourceFile(fileName);
assert.isTrue(file !== undefined, `cannot find file ${fileName}`);
if (expectedContent === undefined) {
@ -175,7 +175,16 @@ module ts {
for (let id in expectedContent) {
if (hasProperty(expectedContent, id)) {
assert.isTrue(hasProperty(file.resolvedModules, id), `expected ${id} to be found in resolved modules`);
assert.isTrue(expectedContent[id] === file.resolvedModules[id], `expected '${expectedContent[id]}' to be equal to '${file.resolvedModules[id]}'`);
if (expectedContent[id]) {
const expected = expectedContent[id];
const actual = file.resolvedModules[id];
assert.isTrue(actual !== undefined);
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'shouldBeProperExternalModule': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
}
else {
assert.isTrue(file.resolvedModules[id] === undefined);
}
}
}
}
@ -237,7 +246,7 @@ module ts {
var options: CompilerOptions = { target };
var program_1 = newProgram(files, ["a.ts"], options);
checkResolvedModulesCache(program_1, "a.ts", { "b": "b.ts" });
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "b.ts", undefined);
var program_2 = updateProgram(program_1, ["a.ts"], options, files => {
@ -246,7 +255,7 @@ module ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedModulesCache(program_1, "a.ts", { "b": "b.ts" });
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "b.ts", undefined);
// imports has changed - program is not reused
@ -263,7 +272,7 @@ module ts {
files[0].text = files[0].text.updateImportsAndExports(newImports);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedModulesCache(program_4, "a.ts", { "b": "b.ts", "c": undefined });
checkResolvedModulesCache(program_4, "a.ts", { "b": { resolvedFileName: "b.ts" }, "c": undefined });
});
})
}