Skip to content

Commit

Permalink
Merge pull request microsoft#10510 from Microsoft/import_directory
Browse files Browse the repository at this point in the history
An import ending in "/" is always an import of a directory.
  • Loading branch information
Andy committed Sep 14, 2016
2 parents a690ba2 + 0f51bdb commit 42515c7
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 40 deletions.
17 changes: 15 additions & 2 deletions src/compiler/core.ts
Expand Up @@ -1044,7 +1044,8 @@ namespace ts {
return 0;
}

export let directorySeparator = "/";
export const directorySeparator = "/";
const directorySeparatorCharCode = CharacterCodes.slash;
function getNormalizedParts(normalizedSlashedPath: string, rootLength: number) {
const parts = normalizedSlashedPath.substr(rootLength).split(directorySeparator);
const normalized: string[] = [];
Expand All @@ -1069,8 +1070,20 @@ namespace ts {
export function normalizePath(path: string): string {
path = normalizeSlashes(path);
const rootLength = getRootLength(path);
const root = path.substr(0, rootLength);
const normalized = getNormalizedParts(path, rootLength);
return path.substr(0, rootLength) + normalized.join(directorySeparator);
if (normalized.length) {
const joinedParts = root + normalized.join(directorySeparator);
return pathEndsWithDirectorySeparator(path) ? joinedParts + directorySeparator : joinedParts;
}
else {
return root;
}
}

/** A path ending with '/' refers to a directory only, never a file. */
export function pathEndsWithDirectorySeparator(path: string): boolean {
return path.charCodeAt(path.length - 1) === directorySeparatorCharCode;
}

export function getDirectoryPath(path: Path): Path;
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/program.ts
Expand Up @@ -670,7 +670,7 @@ namespace ts {
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0, candidate);
}

const resolvedFileName = loadModuleFromFile(candidate, supportedExtensions, failedLookupLocations, onlyRecordFailures, state);
const resolvedFileName = !pathEndsWithDirectorySeparator(candidate) && loadModuleFromFile(candidate, supportedExtensions, failedLookupLocations, onlyRecordFailures, state);

return resolvedFileName || loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, onlyRecordFailures, state);
}
Expand Down
@@ -1,4 +1,4 @@
//// [tests/cases/compiler/relativeModuleWithoutSlash.ts] ////
//// [tests/cases/compiler/importWithTrailingSlash.ts] ////

//// [a.ts]

Expand All @@ -11,13 +11,13 @@ export default { aIndex: 0 };
import a from ".";
import aIndex from "./";
a.a;
aIndex.a; //aIndex.aIndex; See GH#9690
aIndex.aIndex;

//// [test.ts]
import a from "..";
import aIndex from "../";
a.a;
aIndex.a; //aIndex.aIndex;
aIndex.aIndex;


//// [a.js]
Expand All @@ -33,10 +33,10 @@ exports["default"] = { aIndex: 0 };
var _1 = require(".");
var _2 = require("./");
_1["default"].a;
_2["default"].a; //aIndex.aIndex; See GH#9690
_2["default"].aIndex;
//// [test.js]
"use strict";
var __1 = require("..");
var _1 = require("../");
__1["default"].a;
_1["default"].a; //aIndex.aIndex;
_1["default"].aIndex;
Expand Up @@ -7,10 +7,11 @@
"======== Module name '.' was successfully resolved to '/a.ts'. ========",
"======== Resolving module './' from '/a/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a'.",
"File '/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a.ts', result '/a.ts'",
"======== Module name './' was successfully resolved to '/a.ts'. ========",
"Loading module as file / folder, candidate module location '/a/'.",
"File '/a/package.json' does not exist.",
"File '/a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a/index.ts', result '/a/index.ts'",
"======== Module name './' was successfully resolved to '/a/index.ts'. ========",
"======== Resolving module '..' from '/a/b/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a'.",
Expand All @@ -19,8 +20,9 @@
"======== Module name '..' was successfully resolved to '/a.ts'. ========",
"======== Resolving module '../' from '/a/b/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a'.",
"File '/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a.ts', result '/a.ts'",
"======== Module name '../' was successfully resolved to '/a.ts'. ========"
"Loading module as file / folder, candidate module location '/a/'.",
"File '/a/package.json' does not exist.",
"File '/a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a/index.ts', result '/a/index.ts'",
"======== Module name '../' was successfully resolved to '/a/index.ts'. ========"
]
Expand Up @@ -19,10 +19,10 @@ a.a;
>a : Symbol(a, Decl(test.ts, 0, 6))
>a : Symbol(a, Decl(a.ts, 1, 16))

aIndex.a; //aIndex.aIndex; See GH#9690
>aIndex.a : Symbol(a, Decl(a.ts, 1, 16))
aIndex.aIndex;
>aIndex.aIndex : Symbol(aIndex, Decl(index.ts, 0, 16))
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
>a : Symbol(a, Decl(a.ts, 1, 16))
>aIndex : Symbol(aIndex, Decl(index.ts, 0, 16))

=== /a/b/test.ts ===
import a from "..";
Expand All @@ -36,8 +36,8 @@ a.a;
>a : Symbol(a, Decl(test.ts, 0, 6))
>a : Symbol(a, Decl(a.ts, 1, 16))

aIndex.a; //aIndex.aIndex;
>aIndex.a : Symbol(a, Decl(a.ts, 1, 16))
aIndex.aIndex;
>aIndex.aIndex : Symbol(aIndex, Decl(index.ts, 0, 16))
>aIndex : Symbol(aIndex, Decl(test.ts, 1, 6))
>a : Symbol(a, Decl(a.ts, 1, 16))
>aIndex : Symbol(aIndex, Decl(index.ts, 0, 16))

28 changes: 28 additions & 0 deletions tests/baselines/reference/importWithTrailingSlash.trace.json
@@ -0,0 +1,28 @@
[
"======== Resolving module '.' from '/a/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a'.",
"File '/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a.ts', result '/a.ts'",
"======== Module name '.' was successfully resolved to '/a.ts'. ========",
"======== Resolving module './' from '/a/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a/'.",
"File '/a/package.json' does not exist.",
"File '/a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a/index.ts', result '/a/index.ts'",
"======== Module name './' was successfully resolved to '/a/index.ts'. ========",
"======== Resolving module '..' from '/a/b/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a'.",
"File '/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a.ts', result '/a.ts'",
"======== Module name '..' was successfully resolved to '/a.ts'. ========",
"======== Resolving module '../' from '/a/b/test.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/a/'.",
"File '/a/package.json' does not exist.",
"File '/a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/a/index.ts', result '/a/index.ts'",
"======== Module name '../' was successfully resolved to '/a/index.ts'. ========"
]
Expand Up @@ -16,32 +16,32 @@ import a from ".";
>a : { a: number; }

import aIndex from "./";
>aIndex : { a: number; }
>aIndex : { aIndex: number; }

a.a;
>a.a : number
>a : { a: number; }
>a : number

aIndex.a; //aIndex.aIndex; See GH#9690
>aIndex.a : number
>aIndex : { a: number; }
>a : number
aIndex.aIndex;
>aIndex.aIndex : number
>aIndex : { aIndex: number; }
>aIndex : number

=== /a/b/test.ts ===
import a from "..";
>a : { a: number; }

import aIndex from "../";
>aIndex : { a: number; }
>aIndex : { aIndex: number; }

a.a;
>a.a : number
>a : { a: number; }
>a : number

aIndex.a; //aIndex.aIndex;
>aIndex.a : number
>aIndex : { a: number; }
>a : number
aIndex.aIndex;
>aIndex.aIndex : number
>aIndex : { aIndex: number; }
>aIndex : number

@@ -0,0 +1,9 @@
/a.ts(2,17): error TS2307: Cannot find module './foo/'.


==== /a.ts (1 errors) ====

import foo from "./foo/";
~~~~~~~~
!!! error TS2307: Cannot find module './foo/'.

@@ -0,0 +1,7 @@
//// [a.ts]

import foo from "./foo/";


//// [a.js]
"use strict";
@@ -0,0 +1,10 @@
[
"======== Resolving module './foo/' from '/a.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location '/foo/'.",
"File '/foo/package.json' does not exist.",
"File '/foo/index.ts' does not exist.",
"File '/foo/index.tsx' does not exist.",
"File '/foo/index.d.ts' does not exist.",
"======== Module name './foo/' was not resolved. ========"
]
Expand Up @@ -14,7 +14,7 @@
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'module3'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'",
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
"Module name 'module3', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module3'.",
Expand All @@ -32,7 +32,7 @@
"======== Module name 'module3' was successfully resolved to 'c:/module3.d.ts'. ========",
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'module1'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'",
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
"Module name 'module1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module1'.",
Expand All @@ -44,7 +44,7 @@
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1.d.ts'. ========",
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'Classic'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'templates/module2'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'",
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
"Module name 'templates/module2', matched pattern 'templates/*'.",
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",
Expand Down
Expand Up @@ -22,7 +22,7 @@
"======== Module name './project/file2' was successfully resolved to 'c:/root/generated/src/project/file2.ts'. ========",
"======== Resolving module 'module3' from 'c:/root/src/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'module3'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module3'",
"'paths' option is specified, looking for a pattern to match module name 'module3'.",
"Module name 'module3', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module3'.",
Expand Down Expand Up @@ -79,7 +79,7 @@
"======== Module name 'module3' was successfully resolved to 'c:/node_modules/module3.d.ts'. ========",
"======== Resolving module 'module1' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'module1'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'module1'",
"'paths' option is specified, looking for a pattern to match module name 'module1'.",
"Module name 'module1', matched pattern '*'.",
"Trying substitution '*', candidate module location: 'module1'.",
Expand All @@ -104,7 +104,7 @@
"======== Module name 'module1' was successfully resolved to 'c:/shared/module1/index.d.ts'. ========",
"======== Resolving module 'templates/module2' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"'baseUrl' option is set to 'c:/root', using this value to resolve non-relative module name 'templates/module2'",
"'baseUrl' option is set to 'c:/root/', using this value to resolve non-relative module name 'templates/module2'",
"'paths' option is specified, looking for a pattern to match module name 'templates/module2'.",
"Module name 'templates/module2', matched pattern 'templates/*'.",
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",
Expand Down
Expand Up @@ -11,10 +11,10 @@ export default { aIndex: 0 };
import a from ".";
import aIndex from "./";
a.a;
aIndex.a; //aIndex.aIndex; See GH#9690
aIndex.aIndex;

// @Filename: /a/b/test.ts
import a from "..";
import aIndex from "../";
a.a;
aIndex.a; //aIndex.aIndex;
aIndex.aIndex;
5 changes: 5 additions & 0 deletions tests/cases/compiler/importWithTrailingSlash_noResolve.ts
@@ -0,0 +1,5 @@
// @traceResolution: true
// @moduleResolution: node

// @Filename: /a.ts
import foo from "./foo/";

0 comments on commit 42515c7

Please sign in to comment.