Only resolve symlinks in node_modules

This commit is contained in:
Andy Hanson 2016-11-03 06:09:47 -07:00
parent 2eca0af91b
commit b6727ea582
35 changed files with 423 additions and 69 deletions

View file

@ -548,7 +548,7 @@ namespace ts {
const result = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
if (result) {
const { resolved, isExternalLibraryImport } = result;
return createResolvedModuleWithFailedLookupLocations(resolved && resolvedWithRealpath(resolved, host, traceEnabled), isExternalLibraryImport, failedLookupLocations);
return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations);
}
return { resolvedModule: undefined, failedLookupLocations };
@ -563,7 +563,8 @@ namespace ts {
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
}
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, /*checkOneLevel*/ false);
return resolved && { resolved, isExternalLibraryImport: true };
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
return resolved && { resolved: resolvedWithRealpath(resolved, host, traceEnabled), isExternalLibraryImport: true };
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));

View file

@ -958,28 +958,38 @@ namespace Harness {
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
const realPathMap: ts.FileMap<string> = ts.createFileMap<string>();
const fileMap: ts.FileMap<() => ts.SourceFile> = ts.createFileMap<() => ts.SourceFile>();
/** Maps a symlink name to a realpath. Used only for exposing `realpath`. */
const realPathMap = ts.createFileMap<string>();
/**
* Maps a file name to a source file.
* This will have a different SourceFile for every symlink pointing to that file;
* if the program resolves realpaths then symlink entries will be ignored.
*/
const fileMap = ts.createFileMap<ts.SourceFile>();
for (const file of inputFiles) {
if (file.content !== undefined) {
const fileName = ts.normalizePath(file.unitName);
const path = ts.toPath(file.unitName, currentDirectory, getCanonicalFileName);
if (file.fileOptions && file.fileOptions["symlink"]) {
const link = file.fileOptions["symlink"];
const linkPath = ts.toPath(link, currentDirectory, getCanonicalFileName);
realPathMap.set(linkPath, fileName);
fileMap.set(path, (): ts.SourceFile => { throw new Error("Symlinks should always be resolved to a realpath first"); });
const links = file.fileOptions["symlink"].split(",");
for (const link of links) {
const linkPath = ts.toPath(link, currentDirectory, getCanonicalFileName);
realPathMap.set(linkPath, fileName);
// Create a different SourceFile for every symlink.
const sourceFile = createSourceFileAndAssertInvariants(linkPath, file.content, scriptTarget);
fileMap.set(linkPath, sourceFile);
}
}
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
fileMap.set(path, () => sourceFile);
fileMap.set(path, sourceFile);
}
}
function getSourceFile(fileName: string) {
fileName = ts.normalizePath(fileName);
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
if (fileMap.contains(path)) {
return fileMap.get(path)();
const fromFileMap = fileMap.get(toPath(fileName));
if (fromFileMap) {
return fromFileMap;
}
else if (fileName === fourslashFileName) {
const tsFn = "tests/cases/fourslash/" + fourslashFileName;
@ -998,6 +1008,9 @@ namespace Harness {
newLineKind === ts.NewLineKind.LineFeed ? lineFeed :
Harness.IO.newLine();
function toPath(fileName: string): ts.Path {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
return {
getCurrentDirectory: () => currentDirectory,
@ -1007,24 +1020,19 @@ namespace Harness {
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => newLine,
fileExists: fileName => {
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
return fileMap.contains(path) || (realPathMap && realPathMap.contains(path));
fileExists: fileName => fileMap.contains(toPath(fileName)),
readFile: (fileName: string): string => fileMap.get(toPath(fileName)).getText(),
realpath: (fileName: string): ts.Path => {
const path = toPath(fileName);
return (realPathMap.get(path) as ts.Path) || path;
},
readFile: (fileName: string): string => {
return fileMap.get(ts.toPath(fileName, currentDirectory, getCanonicalFileName))().getText();
},
realpath: realPathMap && ((f: string) => {
const path = ts.toPath(f, currentDirectory, getCanonicalFileName);
return realPathMap.get(path) || path;
}),
directoryExists: dir => {
let path = ts.toPath(dir, currentDirectory, getCanonicalFileName);
// Strip trailing /, which may exist if the path is a drive root
if (path[path.length - 1] === "/") {
path = <ts.Path>path.substr(0, path.length - 1);
}
return mapHasFileInDirectory(path, fileMap) || mapHasFileInDirectory(path, realPathMap);
return mapHasFileInDirectory(path, fileMap);
},
getDirectories: d => {
const path = ts.toPath(d, currentDirectory, getCanonicalFileName);

View file

@ -3,26 +3,22 @@
"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'. ========"
]

View file

@ -3,7 +3,6 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/a'.",
"File '/src/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/a.ts', result '/src/a.ts'",
"======== Module name './a' was successfully resolved to '/src/a.ts'. ========",
"======== Resolving module './a.js' from '/src/d.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -13,7 +12,6 @@
"File '/src/a.js.d.ts' does not exist.",
"File name '/src/a.js' has a '.js' extension - stripping it",
"File '/src/a.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/a.ts', result '/src/a.ts'",
"======== Module name './a.js' was successfully resolved to '/src/a.ts'. ========",
"======== Resolving module './jquery.js' from '/src/jquery_user_1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -25,6 +23,5 @@
"File '/src/jquery.ts' does not exist.",
"File '/src/jquery.tsx' does not exist.",
"File '/src/jquery.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/jquery.d.ts', result '/src/jquery.d.ts'",
"======== Module name './jquery.js' was successfully resolved to '/src/jquery.d.ts'. ========"
]

View file

@ -4,7 +4,6 @@
"Loading module as file / folder, candidate module location '/tsx'.",
"File '/tsx.ts' does not exist.",
"File '/tsx.tsx' exist - use it as a name resolution result.",
"Resolving real path for '/tsx.tsx', result '/tsx.tsx'",
"======== Module name './tsx' was successfully resolved to '/tsx.tsx'. ========",
"======== Resolving module './jsx' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -19,7 +18,6 @@
"Loading module as file / folder, candidate module location '/jsx'.",
"File '/jsx.js' does not exist.",
"File '/jsx.jsx' exist - use it as a name resolution result.",
"Resolving real path for '/jsx.jsx', result '/jsx.jsx'",
"======== Module name './jsx' was successfully resolved to '/jsx.jsx'. ========",
"======== Resolving module './js' from '/a.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -33,6 +31,5 @@
"File '/js/index.d.ts' does not exist.",
"Loading module as file / folder, candidate module location '/js'.",
"File '/js.js' exist - use it as a name resolution result.",
"Resolving real path for '/js.js', result '/js.js'",
"======== Module name './js' was successfully resolved to '/js.js'. ========"
]

View file

@ -12,6 +12,5 @@
"Loading module as file / folder, candidate module location '/jsx'.",
"File '/jsx.js' does not exist.",
"File '/jsx.jsx' exist - use it as a name resolution result.",
"Resolving real path for '/jsx.jsx', result '/jsx.jsx'",
"======== Module name './jsx' was successfully resolved to '/jsx.jsx'. ========"
]

View file

@ -12,6 +12,5 @@
"Loading module as file / folder, candidate module location '/jsx'.",
"File '/jsx.js' does not exist.",
"File '/jsx.jsx' exist - use it as a name resolution result.",
"Resolving real path for '/jsx.jsx', result '/jsx.jsx'",
"======== Module name './jsx' was successfully resolved to '/jsx.jsx'. ========"
]

View file

@ -7,6 +7,5 @@
"File '/b.d.ts' does not exist.",
"File '/b/package.json' does not exist.",
"File '/b/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/b/index.ts', result '/b/index.ts'",
"======== Module name './b' was successfully resolved to '/b/index.ts'. ========"
]

View file

@ -1,6 +1,8 @@
//// [tests/cases/compiler/moduleResolutionWithSymlinks.ts] ////
//// [index.ts]
// When symlinked files are in node_modules, they are resolved with realpath;
// so a linked file does not create a duplicate SourceFile of the real one.
export class MyClass { private x: number; }
@ -15,9 +17,31 @@ import { MyClass2 } from "./library-b";
let x: MyClass;
let y: MyClass2;
x = y;
y = x;
y = x;
/*
# To reproduce in a real project:
mkdir src; cd src
mkdir library-a
echo 'export class MyClass { private x: number; }' > library-a/index.ts
mkdir library-b; cd library-b
echo 'import {MyClass} from "library-a"; export { MyClass as MyClass2 }' > index.ts
mkdir node_modules; cd node_modules
ln -s ../../library-a library-a # Linux
# Windows: open command prompt as administrator and run: mklink /D library-a ..\..\library-a
cd ../.. # back to src
echo 'import { MyClass } from "./library-a"; import { MyClass2 } from "./library-b"; let x: MyClass; let y: MyClass2; x = y; y = x;' > app.ts
tsc app.ts # Should write to library-a/index.js, library-b/index.js, and app.js
*/
//// [index.js]
//// [/src/library-a/index.js]
// When symlinked files are in node_modules, they are resolved with realpath;
// so a linked file does not create a duplicate SourceFile of the real one.
"use strict";
var MyClass = (function () {
function MyClass() {
@ -25,13 +49,31 @@ var MyClass = (function () {
return MyClass;
}());
exports.MyClass = MyClass;
//// [index.js]
//// [/src/library-b/index.js]
"use strict";
var library_a_1 = require("library-a");
exports.MyClass2 = library_a_1.MyClass;
//// [app.js]
//// [/src/app.js]
"use strict";
var x;
var y;
x = y;
y = x;
/*
# To reproduce in a real project:
mkdir src; cd src
mkdir library-a
echo 'export class MyClass { private x: number; }' > library-a/index.ts
mkdir library-b; cd library-b
echo 'import {MyClass} from "library-a"; export { MyClass as MyClass2 }' > index.ts
mkdir node_modules; cd node_modules
ln -s ../../library-a library-a # Linux
# Windows: open command prompt as administrator and run: mklink /D library-a ..\..\library-a
cd ../.. # back to src
echo 'import { MyClass } from "./library-a"; import { MyClass2 } from "./library-b"; let x: MyClass; let y: MyClass2; x = y; y = x;' > app.ts
tsc app.ts # Should write to library-a/index.js, library-b/index.js, and app.js
*/

View file

@ -21,11 +21,32 @@ y = x;
>y : Symbol(y, Decl(app.ts, 4, 3))
>x : Symbol(x, Decl(app.ts, 3, 3))
/*
# To reproduce in a real project:
mkdir src; cd src
mkdir library-a
echo 'export class MyClass { private x: number; }' > library-a/index.ts
mkdir library-b; cd library-b
echo 'import {MyClass} from "library-a"; export { MyClass as MyClass2 }' > index.ts
mkdir node_modules; cd node_modules
ln -s ../../library-a library-a # Linux
# Windows: open command prompt as administrator and run: mklink /D library-a ..\..\library-a
cd ../.. # back to src
echo 'import { MyClass } from "./library-a"; import { MyClass2 } from "./library-b"; let x: MyClass; let y: MyClass2; x = y; y = x;' > app.ts
tsc app.ts # Should write to library-a/index.js, library-b/index.js, and app.js
*/
=== /src/library-a/index.ts ===
// When symlinked files are in node_modules, they are resolved with realpath;
// so a linked file does not create a duplicate SourceFile of the real one.
export class MyClass { private x: number; }
>MyClass : Symbol(MyClass, Decl(index.ts, 0, 0))
>x : Symbol(MyClass.x, Decl(index.ts, 1, 22))
>x : Symbol(MyClass.x, Decl(index.ts, 3, 22))
=== /src/library-b/index.ts ===
import {MyClass} from "library-a";

View file

@ -7,7 +7,6 @@
"File '/src/library-a.d.ts' does not exist.",
"File '/src/library-a/package.json' does not exist.",
"File '/src/library-a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/library-a/index.ts', result '/src/library-a/index.ts'",
"======== Module name './library-a' was successfully resolved to '/src/library-a/index.ts'. ========",
"======== Resolving module './library-b' from '/src/app.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -17,7 +16,6 @@
"File '/src/library-b.d.ts' does not exist.",
"File '/src/library-b/package.json' does not exist.",
"File '/src/library-b/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/library-b/index.ts', result '/src/library-b/index.ts'",
"======== Module name './library-b' was successfully resolved to '/src/library-b/index.ts'. ========",
"======== Resolving module 'library-a' from '/src/library-b/index.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",

View file

@ -23,7 +23,28 @@ y = x;
>y : MyClass
>x : MyClass
/*
# To reproduce in a real project:
mkdir src; cd src
mkdir library-a
echo 'export class MyClass { private x: number; }' > library-a/index.ts
mkdir library-b; cd library-b
echo 'import {MyClass} from "library-a"; export { MyClass as MyClass2 }' > index.ts
mkdir node_modules; cd node_modules
ln -s ../../library-a library-a # Linux
# Windows: open command prompt as administrator and run: mklink /D library-a ..\..\library-a
cd ../.. # back to src
echo 'import { MyClass } from "./library-a"; import { MyClass2 } from "./library-b"; let x: MyClass; let y: MyClass2; x = y; y = x;' > app.ts
tsc app.ts # Should write to library-a/index.js, library-b/index.js, and app.js
*/
=== /src/library-a/index.ts ===
// When symlinked files are in node_modules, they are resolved with realpath;
// so a linked file does not create a duplicate SourceFile of the real one.
export class MyClass { private x: number; }
>MyClass : MyClass

View file

@ -0,0 +1,32 @@
//// [tests/cases/compiler/moduleResolutionWithSymlinks_notInNodeModules.ts] ////
//// [abc.ts]
// When symlinked files are not in node_modules, realpath is not used.
// A symlink file acts like the real thing. So, 2 symlinks act like 2 different files.
// See GH#10364.
export const x = 0;
//// [app.ts]
import { x } from "./shared/abc";
import { x as x2 } from "./shared2/abc";
x + x2;
//// [/src/bin/shared/abc.js]
// When symlinked files are not in node_modules, realpath is not used.
// A symlink file acts like the real thing. So, 2 symlinks act like 2 different files.
// See GH#10364.
"use strict";
exports.x = 0;
//// [/src/bin/shared2/abc.js]
// When symlinked files are not in node_modules, realpath is not used.
// A symlink file acts like the real thing. So, 2 symlinks act like 2 different files.
// See GH#10364.
"use strict";
exports.x = 0;
//// [/src/bin/app.js]
"use strict";
var abc_1 = require("./shared/abc");
var abc_2 = require("./shared2/abc");
abc_1.x + abc_2.x;

View file

@ -0,0 +1,12 @@
=== /src/app.ts ===
import { x } from "./shared/abc";
>x : Symbol(x, Decl(app.ts, 0, 8))
import { x as x2 } from "./shared2/abc";
>x : Symbol(x2, Decl(app.ts, 1, 8))
>x2 : Symbol(x2, Decl(app.ts, 1, 8))
x + x2;
>x : Symbol(x, Decl(app.ts, 0, 8))
>x2 : Symbol(x2, Decl(app.ts, 1, 8))

View file

@ -0,0 +1,12 @@
[
"======== Resolving module './shared/abc' from '/src/app.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/shared/abc'.",
"File '/src/shared/abc.ts' exist - use it as a name resolution result.",
"======== Module name './shared/abc' was successfully resolved to '/src/shared/abc.ts'. ========",
"======== Resolving module './shared2/abc' from '/src/app.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/shared2/abc'.",
"File '/src/shared2/abc.ts' exist - use it as a name resolution result.",
"======== Module name './shared2/abc' was successfully resolved to '/src/shared2/abc.ts'. ========"
]

View file

@ -0,0 +1,13 @@
=== /src/app.ts ===
import { x } from "./shared/abc";
>x : 0
import { x as x2 } from "./shared2/abc";
>x : 0
>x2 : 0
x + x2;
>x + x2 : number
>x : 0
>x2 : 0

View file

@ -0,0 +1,40 @@
//// [tests/cases/compiler/moduleResolutionWithSymlinks_withOutDir.ts] ////
//// [index.ts]
// Same as moduleResolutionWithSymlinks.ts, but with outDir
export class MyClass { private x: number; }
//// [index.ts]
import {MyClass} from "library-a";
export { MyClass as MyClass2 }
//// [app.ts]
import { MyClass } from "./library-a";
import { MyClass2 } from "./library-b";
let x: MyClass;
let y: MyClass2;
x = y;
y = x;
//// [/src/bin/library-a/index.js]
// Same as moduleResolutionWithSymlinks.ts, but with outDir
"use strict";
var MyClass = (function () {
function MyClass() {
}
return MyClass;
}());
exports.MyClass = MyClass;
//// [/src/bin/library-b/index.js]
"use strict";
var library_a_1 = require("library-a");
exports.MyClass2 = library_a_1.MyClass;
//// [/src/bin/app.js]
"use strict";
var x;
var y;
x = y;
y = x;

View file

@ -0,0 +1,38 @@
=== /src/app.ts ===
import { MyClass } from "./library-a";
>MyClass : Symbol(MyClass, Decl(app.ts, 0, 8))
import { MyClass2 } from "./library-b";
>MyClass2 : Symbol(MyClass2, Decl(app.ts, 1, 8))
let x: MyClass;
>x : Symbol(x, Decl(app.ts, 3, 3))
>MyClass : Symbol(MyClass, Decl(app.ts, 0, 8))
let y: MyClass2;
>y : Symbol(y, Decl(app.ts, 4, 3))
>MyClass2 : Symbol(MyClass2, Decl(app.ts, 1, 8))
x = y;
>x : Symbol(x, Decl(app.ts, 3, 3))
>y : Symbol(y, Decl(app.ts, 4, 3))
y = x;
>y : Symbol(y, Decl(app.ts, 4, 3))
>x : Symbol(x, Decl(app.ts, 3, 3))
=== /src/library-a/index.ts ===
// Same as moduleResolutionWithSymlinks.ts, but with outDir
export class MyClass { private x: number; }
>MyClass : Symbol(MyClass, Decl(index.ts, 0, 0))
>x : Symbol(MyClass.x, Decl(index.ts, 2, 22))
=== /src/library-b/index.ts ===
import {MyClass} from "library-a";
>MyClass : Symbol(MyClass, Decl(index.ts, 0, 8))
export { MyClass as MyClass2 }
>MyClass : Symbol(MyClass2, Decl(index.ts, 1, 8))
>MyClass2 : Symbol(MyClass2, Decl(index.ts, 1, 8))

View file

@ -0,0 +1,30 @@
[
"======== Resolving module './library-a' from '/src/app.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/library-a'.",
"File '/src/library-a.ts' does not exist.",
"File '/src/library-a.tsx' does not exist.",
"File '/src/library-a.d.ts' does not exist.",
"File '/src/library-a/package.json' does not exist.",
"File '/src/library-a/index.ts' exist - use it as a name resolution result.",
"======== Module name './library-a' was successfully resolved to '/src/library-a/index.ts'. ========",
"======== Resolving module './library-b' from '/src/app.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/src/library-b'.",
"File '/src/library-b.ts' does not exist.",
"File '/src/library-b.tsx' does not exist.",
"File '/src/library-b.d.ts' does not exist.",
"File '/src/library-b/package.json' does not exist.",
"File '/src/library-b/index.ts' exist - use it as a name resolution result.",
"======== Module name './library-b' was successfully resolved to '/src/library-b/index.ts'. ========",
"======== Resolving module 'library-a' from '/src/library-b/index.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module 'library-a' from 'node_modules' folder.",
"File '/src/library-b/node_modules/library-a.ts' does not exist.",
"File '/src/library-b/node_modules/library-a.tsx' does not exist.",
"File '/src/library-b/node_modules/library-a.d.ts' does not exist.",
"File '/src/library-b/node_modules/library-a/package.json' does not exist.",
"File '/src/library-b/node_modules/library-a/index.ts' exist - use it as a name resolution result.",
"Resolving real path for '/src/library-b/node_modules/library-a/index.ts', result '/src/library-a/index.ts'",
"======== Module name 'library-a' was successfully resolved to '/src/library-a/index.ts'. ========"
]

View file

@ -0,0 +1,40 @@
=== /src/app.ts ===
import { MyClass } from "./library-a";
>MyClass : typeof MyClass
import { MyClass2 } from "./library-b";
>MyClass2 : typeof MyClass
let x: MyClass;
>x : MyClass
>MyClass : MyClass
let y: MyClass2;
>y : MyClass
>MyClass2 : MyClass
x = y;
>x = y : MyClass
>x : MyClass
>y : MyClass
y = x;
>y = x : MyClass
>y : MyClass
>x : MyClass
=== /src/library-a/index.ts ===
// Same as moduleResolutionWithSymlinks.ts, but with outDir
export class MyClass { private x: number; }
>MyClass : MyClass
>x : number
=== /src/library-b/index.ts ===
import {MyClass} from "library-a";
>MyClass : typeof MyClass
export { MyClass as MyClass2 }
>MyClass : typeof MyClass
>MyClass2 : typeof MyClass

View file

@ -5,13 +5,11 @@
"Resolving module name 'folder2/file2' relative to base url 'c:/root' - 'c:/root/folder2/file2'.",
"Loading module as file / folder, candidate module location 'c:/root/folder2/file2'.",
"File 'c:/root/folder2/file2.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/folder2/file2.ts', result 'c:/root/folder2/file2.ts'",
"======== Module name 'folder2/file2' was successfully resolved to 'c:/root/folder2/file2.ts'. ========",
"======== Resolving module './file3' from 'c:/root/folder2/file2.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location 'c:/root/folder2/file3'.",
"File 'c:/root/folder2/file3.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/folder2/file3.ts', result 'c:/root/folder2/file3.ts'",
"======== Module name './file3' was successfully resolved to 'c:/root/folder2/file3.ts'. ========",
"======== Resolving module 'file4' from 'c:/root/folder2/file2.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",

View file

@ -5,13 +5,11 @@
"Resolving module name 'folder2/file2' relative to base url 'c:/root' - 'c:/root/folder2/file2'.",
"Loading module as file / folder, candidate module location 'c:/root/folder2/file2'.",
"File 'c:/root/folder2/file2.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/folder2/file2.ts', result 'c:/root/folder2/file2.ts'",
"======== Module name 'folder2/file2' was successfully resolved to 'c:/root/folder2/file2.ts'. ========",
"======== Resolving module './file3' from 'c:/root/folder2/file2.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",
"Loading module as file / folder, candidate module location 'c:/root/folder2/file3'.",
"File 'c:/root/folder2/file3.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/folder2/file3.ts', result 'c:/root/folder2/file3.ts'",
"======== Module name './file3' was successfully resolved to 'c:/root/folder2/file3.ts'. ========",
"======== Resolving module 'file4' from 'c:/root/folder2/file2.ts'. ========",
"Explicitly specified module resolution kind: 'NodeJs'.",

View file

@ -7,7 +7,6 @@
"Trying substitution '*', candidate module location: 'folder2/file1'.",
"Loading module as file / folder, candidate module location 'c:/root/folder2/file1'.",
"File 'c:/root/folder2/file1.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/folder2/file1.ts', result 'c:/root/folder2/file1.ts'",
"======== Module name 'folder2/file1' was successfully resolved to 'c:/root/folder2/file1.ts'. ========",
"======== Resolving module 'folder3/file2' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -26,7 +25,6 @@
"Trying substitution 'generated/*', candidate module location: 'generated/folder3/file2'.",
"Loading module as file / folder, candidate module location 'c:/root/generated/folder3/file2'.",
"File 'c:/root/generated/folder3/file2.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/generated/folder3/file2.ts', result 'c:/root/generated/folder3/file2.ts'",
"======== Module name 'folder3/file2' was successfully resolved to 'c:/root/generated/folder3/file2.ts'. ========",
"======== Resolving module 'components/file3' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -42,7 +40,6 @@
"File 'c:/root/shared/components/file3/index.ts' does not exist.",
"File 'c:/root/shared/components/file3/index.tsx' does not exist.",
"File 'c:/root/shared/components/file3/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/shared/components/file3/index.d.ts', result 'c:/root/shared/components/file3/index.d.ts'",
"======== Module name 'components/file3' was successfully resolved to 'c:/root/shared/components/file3/index.d.ts'. ========",
"======== Resolving module 'file4' from 'c:/root/folder1/file1.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",

View file

@ -18,7 +18,6 @@
"Loading 'project/file3' from the root dir 'c:/root/generated/src', candidate location 'c:/root/generated/src/project/file3'",
"Loading module as file / folder, candidate module location 'c:/root/generated/src/project/file3'.",
"File 'c:/root/generated/src/project/file3.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/generated/src/project/file3.ts', result 'c:/root/generated/src/project/file3.ts'",
"======== Module name './project/file3' was successfully resolved to 'c:/root/generated/src/project/file3.ts'. ========",
"======== Resolving module '../file2' from 'c:/root/generated/src/project/file3.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -45,6 +44,5 @@
"File 'c:/root/src/file2/index.ts' does not exist.",
"File 'c:/root/src/file2/index.tsx' does not exist.",
"File 'c:/root/src/file2/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/src/file2/index.d.ts', result 'c:/root/src/file2/index.d.ts'",
"======== Module name '../file2' was successfully resolved to 'c:/root/src/file2/index.d.ts'. ========"
]

View file

@ -18,7 +18,6 @@
"Loading 'project/file2' from the root dir 'c:/root/generated/src', candidate location 'c:/root/generated/src/project/file2'",
"Loading module as file / folder, candidate module location 'c:/root/generated/src/project/file2'.",
"File 'c:/root/generated/src/project/file2.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/generated/src/project/file2.ts', result 'c:/root/generated/src/project/file2.ts'",
"======== 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'.",
@ -100,7 +99,6 @@
"File 'c:/shared/module1/index.ts' does not exist.",
"File 'c:/shared/module1/index.tsx' does not exist.",
"File 'c:/shared/module1/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/shared/module1/index.d.ts', result 'c:/shared/module1/index.d.ts'",
"======== 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'.",
@ -110,7 +108,6 @@
"Trying substitution 'generated/src/templates/*', candidate module location: 'generated/src/templates/module2'.",
"Loading module as file / folder, candidate module location 'c:/root/generated/src/templates/module2'.",
"File 'c:/root/generated/src/templates/module2.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/generated/src/templates/module2.ts', result 'c:/root/generated/src/templates/module2.ts'",
"======== Module name 'templates/module2' was successfully resolved to 'c:/root/generated/src/templates/module2.ts'. ========",
"======== Resolving module '../file3' from 'c:/root/generated/src/project/file2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
@ -137,6 +134,5 @@
"File 'c:/root/src/file3/index.ts' does not exist.",
"File 'c:/root/src/file3/index.tsx' does not exist.",
"File 'c:/root/src/file3/index.d.ts' exist - use it as a name resolution result.",
"Resolving real path for 'c:/root/src/file3/index.d.ts', result 'c:/root/src/file3/index.d.ts'",
"======== Module name '../file3' was successfully resolved to 'c:/root/src/file3/index.d.ts'. ========"
]

View file

@ -10,7 +10,6 @@
"File '/ref.ts' does not exist.",
"File '/ref.tsx' does not exist.",
"File '/ref.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/ref.d.ts', result '/ref.d.ts'",
"======== Module name './ref' was successfully resolved to '/ref.d.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -3,7 +3,6 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/mod1'.",
"File '/mod1.ts' exist - use it as a name resolution result.",
"Resolving real path for '/mod1.ts', result '/mod1.ts'",
"======== Module name './mod1' was successfully resolved to '/mod1.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -3,13 +3,11 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/main'.",
"File '/main.ts' exist - use it as a name resolution result.",
"Resolving real path for '/main.ts', result '/main.ts'",
"======== Module name './main' was successfully resolved to '/main.ts'. ========",
"======== Resolving module './mod1' from '/mod2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/mod1'.",
"File '/mod1.ts' exist - use it as a name resolution result.",
"Resolving real path for '/mod1.ts', result '/mod1.ts'",
"======== Module name './mod1' was successfully resolved to '/mod1.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/mod1.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",
@ -20,7 +18,6 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/main'.",
"File '/main.ts' exist - use it as a name resolution result.",
"Resolving real path for '/main.ts', result '/main.ts'",
"======== Module name './main' was successfully resolved to '/main.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -10,7 +10,6 @@
"File '/ref.ts' does not exist.",
"File '/ref.tsx' does not exist.",
"File '/ref.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/ref.d.ts', result '/ref.d.ts'",
"======== Module name './ref' was successfully resolved to '/ref.d.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -10,7 +10,6 @@
"File '/ref.ts' does not exist.",
"File '/ref.tsx' does not exist.",
"File '/ref.d.ts' exist - use it as a name resolution result.",
"Resolving real path for '/ref.d.ts', result '/ref.d.ts'",
"======== Module name './ref' was successfully resolved to '/ref.d.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -3,7 +3,6 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/mod1'.",
"File '/mod1.ts' exist - use it as a name resolution result.",
"Resolving real path for '/mod1.ts', result '/mod1.ts'",
"======== Module name './mod1' was successfully resolved to '/mod1.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -3,13 +3,11 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/main'.",
"File '/main.ts' exist - use it as a name resolution result.",
"Resolving real path for '/main.ts', result '/main.ts'",
"======== Module name './main' was successfully resolved to '/main.ts'. ========",
"======== Resolving module './mod1' from '/mod2.ts'. ========",
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/mod1'.",
"File '/mod1.ts' exist - use it as a name resolution result.",
"Resolving real path for '/mod1.ts', result '/mod1.ts'",
"======== Module name './mod1' was successfully resolved to '/mod1.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/mod1.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",
@ -20,7 +18,6 @@
"Module resolution kind is not specified, using 'NodeJs'.",
"Loading module as file / folder, candidate module location '/main'.",
"File '/main.ts' exist - use it as a name resolution result.",
"Resolving real path for '/main.ts', result '/main.ts'",
"======== Module name './main' was successfully resolved to '/main.ts'. ========",
"======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========",
"Resolving with primary search path '/types'",

View file

@ -1,6 +1,8 @@
// @module: commonjs
// When symlinked files are in node_modules, they are resolved with realpath;
// so a linked file does not create a duplicate SourceFile of the real one.
// @noImplicitReferences: true
// @traceResolution: true
// @fullEmitPaths: true
// @filename: /src/library-a/index.ts
// @symlink: /src/library-b/node_modules/library-a/index.ts
@ -17,4 +19,23 @@ import { MyClass2 } from "./library-b";
let x: MyClass;
let y: MyClass2;
x = y;
y = x;
y = x;
/*
# To reproduce in a real project:
mkdir src; cd src
mkdir library-a
echo 'export class MyClass { private x: number; }' > library-a/index.ts
mkdir library-b; cd library-b
echo 'import {MyClass} from "library-a"; export { MyClass as MyClass2 }' > index.ts
mkdir node_modules; cd node_modules
ln -s ../../library-a library-a # Linux
# Windows: open command prompt as administrator and run: mklink /D library-a ..\..\library-a
cd ../.. # back to src
echo 'import { MyClass } from "./library-a"; import { MyClass2 } from "./library-b"; let x: MyClass; let y: MyClass2; x = y; y = x;' > app.ts
tsc app.ts # Should write to library-a/index.js, library-b/index.js, and app.js
*/

View file

@ -0,0 +1,40 @@
// When symlinked files are not in node_modules, realpath is not used.
// A symlink file acts like the real thing. So, 2 symlinks act like 2 different files.
// See GH#10364.
// @noImplicitReferences: true
// @traceResolution: true
// @fullEmitPaths: true
// @filename: /shared/abc.ts
// @symlink: /src/shared/abc.ts,/src/shared2/abc.ts
export const x = 0;
// @filename: /src/app.ts
import { x } from "./shared/abc";
import { x as x2 } from "./shared2/abc";
x + x2;
// @filename: /src/tsconfig.json
{
"compilerOptions": {
"outDir": "bin"
}
}
/*
# To reproduce in a real project:
mkdir shared
echo 'export const x = 0;' > shared/abc.ts
mkdir src; cd src
echo 'import { x } from "./shared/abc"; import { x as x2 } from "./shared2/abc"; x + x2;' > app.ts
ln -s ../shared ./shared; ln -s ../shared ./shared2 # Linux
# Windows: Open command prompt as administrator and run: `mklink /D shared ..\shared; mklink /D shared2 ..\shared`
echo '{ "compilerOptions": { "outDir": "bin" } }' > tsconfig.json
node ../../../../TypeScript/built/local/tsc.js
# Should create `bin/app.js`, `bin/shared/abc.js`, and `bin/shared2/abc.js`
*/

View file

@ -0,0 +1,22 @@
// Same as moduleResolutionWithSymlinks.ts, but with outDir
// @noImplicitReferences: true
// @traceResolution: true
// @fullEmitPaths: true
// @outDir: /src/bin
// @filename: /src/library-a/index.ts
// @symlink: /src/library-b/node_modules/library-a/index.ts
export class MyClass { private x: number; }
// @filename: /src/library-b/index.ts
import {MyClass} from "library-a";
export { MyClass as MyClass2 }
// @filename: /src/app.ts
import { MyClass } from "./library-a";
import { MyClass2 } from "./library-b";
let x: MyClass;
let y: MyClass2;
x = y;
y = x;