added tests

This commit is contained in:
Vladimir Matveev
2015-08-18 13:36:08 -07:00
parent 1cb5280971
commit 049a5fba07
2 changed files with 98 additions and 61 deletions

View File

@@ -37,13 +37,13 @@ namespace ts {
export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
switch(compilerOptions.moduleResolution) {
case ModuleResolutionKind.NodeJs: return nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host);
case ModuleResolutionKind.BaseUrl: return baseUrlModuleNameResolver(moduleName, containingFile, compilerOptions, host);
case ModuleResolutionKind.NodeJs: return nodeModuleNameResolver(moduleName, containingFile, host);
case ModuleResolutionKind.BaseUrl: return baseUrlModuleNameResolver(moduleName, containingFile, compilerOptions.baseUrl, host);
default: return legacyNameResolver(moduleName, containingFile, compilerOptions, host);
}
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
export function nodeModuleNameResolver(moduleName: string, containingFile: string, host: ModuleResolutionHost): ResolvedModule {
let containingDirectory = getDirectoryPath(containingFile);
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
@@ -132,30 +132,34 @@ namespace ts {
return { resolvedFileName: undefined, failedLookupLocations };
}
export function baseUrlModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModule {
Debug.assert(compilerOptions.baseUrl !== undefined, "baseUrl is mandatory when using this module resolution strategy");
export function baseUrlModuleNameResolver(moduleName: string, containingFile: string, baseUrl: string, host: ModuleResolutionHost): ResolvedModule {
Debug.assert(baseUrl !== undefined);
let normalizedModuleName = normalizeSlashes(moduleName);
// treat module name as url that is relative to containing file if
let basePart = useBaseUrl(moduleName) ? compilerOptions.baseUrl : getDirectoryPath(containingFile);
let normalizedModuleName = normalizeSlashes(moduleName);
let basePart = useBaseUrl(moduleName) ? baseUrl : getDirectoryPath(containingFile);
let candidate = normalizePath(combinePaths(basePart, moduleName));
let failedLookupLocations: string[] = [];
// first - try to load file as is
let result = tryLoadFile(candidate);
if (result) {
return result;
}
// then try all supported extension
for(let ext of supportedExtensions) {
let result = tryLoadFile(candidate + ext);
let hasSupportedExtension = forEach(supportedExtensions, ext => fileExtensionIs(candidate, ext));
if (hasSupportedExtension) {
// module name already has extension - use it as is
let result = tryLoadFile(candidate);
if (result) {
return result;
}
}
else {
// module name does not have extension - try every supported extension
for(let ext of supportedExtensions) {
let result = tryLoadFile(candidate + ext);
if (result) {
return result;
}
}
}
return { resolvedFileName: undefined, failedLookupLocations };
function tryLoadFile(location: string): ResolvedModule {

View File

@@ -44,42 +44,38 @@ module ts {
return !path && <File>fse;
}
}
}
function isDirectory(fse: Directory | File): boolean {
return (<Directory>fse).children !== undefined;
}
function createDirectory(name: string): Directory {
return { name, children: {} }
}
function makeFS(files: File[]): Directory {
// create root
let {dir} = splitPath(files[0].name);
let root: Directory = createDirectory(dir);
for(let f of files) {
addFile(f.name, f.content, root);
function isDirectory(fse: Directory | File): boolean {
return (<Directory>fse).children !== undefined;
}
function addFile(path: string, content: string, parent: Directory) {
Debug.assert(parent !== undefined);
function makeFS(files: File[]): Directory {
// create root
let {dir} = splitPath(files[0].name);
let root: Directory = { name: dir, children: {} };
let {dir, rel} = splitPath(path);
if (rel) {
let d = parent.children[dir] || (parent.children[dir] = createDirectory(dir));
Debug.assert(isDirectory(d))
addFile(rel, content, <Directory>d);
for(let f of files) {
addFile(f.name, f.content, root);
}
else {
parent.children[dir] = <File>{ name: dir, content };
function addFile(path: string, content: string, parent: Directory) {
Debug.assert(parent !== undefined);
let {dir, rel} = splitPath(path);
if (rel) {
let d = parent.children[dir] || (parent.children[dir] = { name: dir, children: {} });
Debug.assert(isDirectory(d))
addFile(rel, content, <Directory>d);
}
else {
parent.children[dir] = <File>{ name: dir, content };
}
}
return root;
}
return root;
}
function splitPath(path: string): { dir: string; rel: string } {
let index = path.indexOf(directorySeparator);
return index === -1
@@ -87,8 +83,6 @@ module ts {
: { dir: path.substr(0, index), rel: path.substr(index + 1) };
}
let opts: CompilerOptions = { moduleResolution: ModuleResolutionKind.NodeJs };
describe("Node module resolution - relative paths", () => {
function testLoadAsFile(containingFileName: string, moduleFileNameNoExt: string, moduleName: string): void {
@@ -97,7 +91,7 @@ module ts {
let containingFile = { name: containingFileName, content: ""}
let moduleFile = { name: moduleFileNameNoExt + ".d.ts", content: "var x;"}
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, opts, createModuleResolutionHost(containingFile, moduleFile));
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.isTrue(resolution.failedLookupLocations.length === 0);
@@ -107,7 +101,7 @@ module ts {
let containingFile = { name: containingFileName, content: ""}
let moduleFile = { name: moduleFileNameNoExt + ".ts", content: "var x;"}
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, opts, createModuleResolutionHost(containingFile, moduleFile));
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, undefined);
assert.equal(resolution.failedLookupLocations.length, 3);
@@ -130,12 +124,16 @@ module ts {
it("module name that starts with '/' script extension resolved as relative file name", () => {
testLoadAsFile("/foo/bar/baz.ts", "/foo", "/foo");
});
it("module name that starts with 'c:/' script extension resolved as relative file name", () => {
testLoadAsFile("c:/foo/bar/baz.ts", "c:/foo", "c:/foo");
});
function testLoadingFromPackageJson(containingFileName: string, packageJsonFileName: string, fieldName: string, fieldRef: string, moduleFileName: string, moduleName: string): void {
let containingFile = { name: containingFileName };
let packageJson = { name: packageJsonFileName, content: JSON.stringify({ [fieldName]: fieldRef }) };
let moduleFile = { name: moduleFileName };
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, opts, createModuleResolutionHost(containingFile, packageJson, moduleFile));
let resolution = nodeModuleNameResolver(moduleName, containingFile.name, createModuleResolutionHost(containingFile, packageJson, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
// expect one failed lookup location - attempt to load module as file
assert.equal(resolution.failedLookupLocations.length, 1);
@@ -145,19 +143,21 @@ module ts {
testLoadingFromPackageJson("/a/b/c/d.ts", "/a/b/c/bar/package.json", "typings", "c/d/e.d.ts", "/a/b/c/bar/c/d/e.d.ts", "./bar");
testLoadingFromPackageJson("/a/b/c/d.ts", "/a/bar/package.json", "typings", "e.d.ts", "/a/bar/e.d.ts", "../../bar");
testLoadingFromPackageJson("/a/b/c/d.ts", "/bar/package.json", "typings", "e.d.ts", "/bar/e.d.ts", "/bar");
testLoadingFromPackageJson("c:/a/b/c/d.ts", "c:/bar/package.json", "typings", "e.d.ts", "c:/bar/e.d.ts", "c:/bar");
});
it("module name as directory - load from main", () => {
testLoadingFromPackageJson("/a/b/c/d.ts", "/a/b/c/bar/package.json", "main", "c/d/e.d.ts", "/a/b/c/bar/c/d/e.d.ts", "./bar");
testLoadingFromPackageJson("/a/b/c/d.ts", "/a/bar/package.json", "main", "e.d.ts", "/a/bar/e.d.ts", "../../bar");
testLoadingFromPackageJson("/a/b/c/d.ts", "/bar/package.json", "main", "e.d.ts", "/bar/e.d.ts", "/bar");
testLoadingFromPackageJson("c:/a/b/c/d.ts", "c:/bar/package.json", "main", "e.d.ts", "c:/bar/e.d.ts", "c:/bar");
});
it ("module name as directory - load index.d.ts", () => {
let containingFile = {name: "/a/b/c.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, opts, createModuleResolutionHost(containingFile, packageJson, indexFile));
let resolution = nodeModuleNameResolver("./foo", containingFile.name, createModuleResolutionHost(containingFile, packageJson, indexFile));
assert.equal(resolution.resolvedFileName, indexFile.name);
// expect 2 failed lookup locations:
assert.deepEqual(resolution.failedLookupLocations, [
@@ -171,7 +171,7 @@ module ts {
it("load module as file - ts files not loaded", () => {
let containingFile = { name: "/a/b/c/d/e.ts" };
let moduleFile = { name: "/a/b/node_modules/foo.ts" };
let resolution = nodeModuleNameResolver("foo", containingFile.name, opts, createModuleResolutionHost(containingFile, moduleFile));
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, undefined);
assert.deepEqual(resolution.failedLookupLocations, [
"/a/b/c/d/node_modules/foo.d.ts",
@@ -195,14 +195,14 @@ module ts {
it("load module as file", () => {
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, opts, createModuleResolutionHost(containingFile, moduleFile));
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
});
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, opts, createModuleResolutionHost(containingFile, moduleFile));
let resolution = nodeModuleNameResolver("foo", containingFile.name, createModuleResolutionHost(containingFile, moduleFile));
assert.equal(resolution.resolvedFileName, moduleFile.name);
assert.deepEqual(resolution.failedLookupLocations, [
"/a/node_modules/b/c/node_modules/d/node_modules/foo.d.ts",
@@ -221,16 +221,36 @@ module ts {
});
describe("BaseUrl mode", () => {
function getCompilerOptions(baseUrl: string): CompilerOptions {
return { baseUrl, moduleResolution: ModuleResolutionKind.BaseUrl };
}
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, getCompilerOptions("<some-value>"), createModuleResolutionHost(containingFile, moduleFile));
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.ts");
@@ -250,5 +270,18 @@ module ts {
test("/a/b/c/d.ts", "/a/b/c/foo.tsx", "foo.tsx");
test("/a/b/c/d.ts", "/a/b/c/foo.d.ts", "foo.d.ts");
});
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");
});
});
}