mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-15 03:23:08 -06:00
use CompilerHost.realpath to resolve actual location for symlinks
This commit is contained in:
parent
166f95c677
commit
2b5bbfee60
@ -2752,6 +2752,10 @@
|
||||
"category": "Error",
|
||||
"code": 6129
|
||||
},
|
||||
"Resolving real path for '{0}', result '{1}'": {
|
||||
"category": "Message",
|
||||
"code": 6130
|
||||
},
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
"code": 7005
|
||||
|
||||
@ -570,22 +570,29 @@ namespace ts {
|
||||
let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings(moduleName, containingDirectory, nodeLoadModuleByRelativeName,
|
||||
failedLookupLocations, supportedExtensions, state);
|
||||
|
||||
if (resolvedFileName) {
|
||||
return createResolvedModule(resolvedFileName, /*isExternalLibraryImport*/false, failedLookupLocations);
|
||||
let isExternalLibraryImport = false;
|
||||
if (!resolvedFileName) {
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
|
||||
}
|
||||
resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state);
|
||||
isExternalLibraryImport = resolvedFileName !== undefined;
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
resolvedFileName = nodeLoadModuleByRelativeName(candidate, supportedExtensions, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
}
|
||||
|
||||
let isExternalLibraryImport = false;
|
||||
if (moduleHasNonRelativeName(moduleName)) {
|
||||
if (resolvedFileName && host.realpath) {
|
||||
const originalFileName = resolvedFileName;
|
||||
resolvedFileName = normalizePath(host.realpath(resolvedFileName));
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
|
||||
trace(host, Diagnostics.Resolving_real_path_for_0_result_1, originalFileName, resolvedFileName);
|
||||
}
|
||||
resolvedFileName = loadModuleFromNodeModules(moduleName, containingDirectory, failedLookupLocations, state);
|
||||
isExternalLibraryImport = resolvedFileName !== undefined;
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
resolvedFileName = nodeLoadModuleByRelativeName(candidate, supportedExtensions, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
}
|
||||
|
||||
return createResolvedModule(resolvedFileName, isExternalLibraryImport, failedLookupLocations);
|
||||
}
|
||||
|
||||
@ -873,6 +880,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const newLine = getNewLineCharacter(options);
|
||||
const realpath = sys.realpath && ((path: string) => sys.realpath(path));
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
@ -886,7 +894,8 @@ namespace ts {
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
trace: (s: string) => sys.write(s + newLine),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName)
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName),
|
||||
realpath
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ namespace ts {
|
||||
createHash?(data: string): string;
|
||||
getMemoryUsage?(): number;
|
||||
exit(exitCode?: number): void;
|
||||
realpath?(path: string): string;
|
||||
}
|
||||
|
||||
export interface FileWatcher {
|
||||
@ -73,6 +74,7 @@ namespace ts {
|
||||
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
|
||||
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
|
||||
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
|
||||
realpath(path: string): string;
|
||||
};
|
||||
|
||||
export var sys: System = (function () {
|
||||
@ -527,12 +529,15 @@ namespace ts {
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
process.exit(exitCode);
|
||||
},
|
||||
realpath(path: string): string {
|
||||
return _fs.realpathSync(path);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getChakraSystem(): System {
|
||||
|
||||
const realpath = ChakraHost.realpath && ((path: string) => ChakraHost.realpath(path));
|
||||
return {
|
||||
newLine: ChakraHost.newLine || "\r\n",
|
||||
args: ChakraHost.args,
|
||||
@ -558,6 +563,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => ChakraHost.currentDirectory,
|
||||
readDirectory: ChakraHost.readDirectory,
|
||||
exit: ChakraHost.quit,
|
||||
realpath
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -2779,6 +2779,7 @@ namespace ts {
|
||||
readFile(fileName: string): string;
|
||||
trace?(s: string): void;
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
realpath?(path: string): string;
|
||||
}
|
||||
|
||||
export interface ResolvedModule {
|
||||
|
||||
@ -89,16 +89,16 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
otherFiles = [];
|
||||
|
||||
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
|
||||
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content });
|
||||
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content, fileOptions: lastUnit.fileOptions });
|
||||
units.forEach(unit => {
|
||||
if (unit.name !== lastUnit.name) {
|
||||
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content });
|
||||
otherFiles.push({ unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions });
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
toBeCompiled = units.map(unit => {
|
||||
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content };
|
||||
return { unitName: this.makeUnitName(unit.name, rootDir), content: unit.content, fileOptions: unit.fileOptions };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -855,13 +855,23 @@ namespace Harness {
|
||||
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
|
||||
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
|
||||
const fileMap: ts.FileMap<ts.SourceFile> = ts.createFileMap<ts.SourceFile>();
|
||||
let realPathMap: ts.FileMap<string>;
|
||||
const fileMap: ts.FileMap<() => ts.SourceFile> = ts.createFileMap<() => ts.SourceFile>();
|
||||
for (const file of inputFiles) {
|
||||
if (file.content !== undefined) {
|
||||
const fileName = ts.normalizePath(file.unitName);
|
||||
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
|
||||
const path = ts.toPath(file.unitName, currentDirectory, getCanonicalFileName);
|
||||
fileMap.set(path, sourceFile);
|
||||
if (file.fileOptions && file.fileOptions["symlink"]) {
|
||||
const link = file.fileOptions["symlink"];
|
||||
const linkPath = ts.toPath(link, currentDirectory, getCanonicalFileName);
|
||||
if (!realPathMap) {
|
||||
realPathMap = ts.createFileMap<string>();
|
||||
}
|
||||
realPathMap.set(linkPath, fileName);
|
||||
fileMap.set(path, (): ts.SourceFile => { throw new Error("Symlinks should always be resolved to a realpath first"); });
|
||||
}
|
||||
const sourceFile = createSourceFileAndAssertInvariants(fileName, file.content, scriptTarget);
|
||||
fileMap.set(path, ts.memoize(() => sourceFile));
|
||||
}
|
||||
}
|
||||
|
||||
@ -869,7 +879,7 @@ namespace Harness {
|
||||
fileName = ts.normalizePath(fileName);
|
||||
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
if (fileMap.contains(path)) {
|
||||
return fileMap.get(path);
|
||||
return fileMap.get(path)();
|
||||
}
|
||||
else if (fileName === fourslashFileName) {
|
||||
const tsFn = "tests/cases/fourslash/" + fourslashFileName;
|
||||
@ -898,11 +908,16 @@ namespace Harness {
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => {
|
||||
return fileMap.contains(ts.toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
const path = ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
return fileMap.contains(path) || (realPathMap && realPathMap.contains(path));
|
||||
},
|
||||
readFile: (fileName: string): string => {
|
||||
return fileMap.get(ts.toPath(fileName, currentDirectory, getCanonicalFileName)).getText();
|
||||
}
|
||||
return fileMap.get(ts.toPath(fileName, currentDirectory, getCanonicalFileName))().getText();
|
||||
},
|
||||
realpath: realPathMap && ((f: string) => {
|
||||
const path = ts.toPath(f, currentDirectory, getCanonicalFileName);
|
||||
return realPathMap.contains(path) ? realPathMap.get(path) : path;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
@ -923,7 +938,8 @@ namespace Harness {
|
||||
{ name: "libFiles", type: "string" },
|
||||
{ name: "noErrorTruncation", type: "boolean" },
|
||||
{ name: "suppressOutputPathCheck", type: "boolean" },
|
||||
{ name: "noImplicitReferences", type: "boolean" }
|
||||
{ name: "noImplicitReferences", type: "boolean" },
|
||||
{ name: "symlink", type: "string" }
|
||||
];
|
||||
|
||||
let optionsIndex: ts.Map<ts.CommandLineOption>;
|
||||
@ -978,6 +994,7 @@ namespace Harness {
|
||||
export interface TestFile {
|
||||
unitName: string;
|
||||
content: string;
|
||||
fileOptions?: any;
|
||||
}
|
||||
|
||||
export interface CompilationOutput {
|
||||
@ -1415,10 +1432,8 @@ namespace Harness {
|
||||
// Comment line, check for global/file @options and record them
|
||||
optionRegex.lastIndex = 0;
|
||||
const metaDataName = testMetaData[1].toLowerCase();
|
||||
if (metaDataName === "filename") {
|
||||
currentFileOptions[testMetaData[1]] = testMetaData[2];
|
||||
}
|
||||
else {
|
||||
currentFileOptions[testMetaData[1]] = testMetaData[2];
|
||||
if (metaDataName !== "filename") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -431,11 +431,15 @@ namespace ts {
|
||||
export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResolutionHost {
|
||||
|
||||
public directoryExists: (directoryName: string) => boolean;
|
||||
public realpath: (path: string) => string;
|
||||
|
||||
constructor(private shimHost: CoreServicesShimHost) {
|
||||
if ("directoryExists" in this.shimHost) {
|
||||
this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName);
|
||||
}
|
||||
if ("realpath" in this.shimHost) {
|
||||
this.realpath = path => this.shimHost.realpath(path);
|
||||
}
|
||||
}
|
||||
|
||||
public readDirectory(rootDir: string, extension: string, exclude: string[], depth?: number): string[] {
|
||||
|
||||
37
tests/baselines/reference/moduleResolutionWithSymlinks.js
Normal file
37
tests/baselines/reference/moduleResolutionWithSymlinks.js
Normal file
@ -0,0 +1,37 @@
|
||||
//// [tests/cases/compiler/moduleResolutionWithSymlinks.ts] ////
|
||||
|
||||
//// [index.ts]
|
||||
|
||||
export class MyClass{}
|
||||
|
||||
//// [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;
|
||||
|
||||
//// [index.js]
|
||||
"use strict";
|
||||
var MyClass = (function () {
|
||||
function MyClass() {
|
||||
}
|
||||
return MyClass;
|
||||
}());
|
||||
exports.MyClass = MyClass;
|
||||
//// [index.js]
|
||||
"use strict";
|
||||
var library_a_1 = require("library-a");
|
||||
exports.MyClass2 = library_a_1.MyClass;
|
||||
//// [app.js]
|
||||
"use strict";
|
||||
var x;
|
||||
var y;
|
||||
x = y;
|
||||
y = x;
|
||||
@ -0,0 +1,36 @@
|
||||
=== /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 ===
|
||||
|
||||
export class MyClass{}
|
||||
>MyClass : Symbol(MyClass, Decl(index.ts, 0, 0))
|
||||
|
||||
=== /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))
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
[
|
||||
"======== 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.",
|
||||
"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'.",
|
||||
"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.",
|
||||
"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'.",
|
||||
"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'. ========"
|
||||
]
|
||||
38
tests/baselines/reference/moduleResolutionWithSymlinks.types
Normal file
38
tests/baselines/reference/moduleResolutionWithSymlinks.types
Normal file
@ -0,0 +1,38 @@
|
||||
=== /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 ===
|
||||
|
||||
export class MyClass{}
|
||||
>MyClass : MyClass
|
||||
|
||||
=== /src/library-b/index.ts ===
|
||||
import {MyClass} from "library-a";
|
||||
>MyClass : typeof MyClass
|
||||
|
||||
export { MyClass as MyClass2 }
|
||||
>MyClass : typeof MyClass
|
||||
>MyClass2 : typeof MyClass
|
||||
|
||||
20
tests/cases/compiler/moduleResolutionWithSymlinks.ts
Normal file
20
tests/cases/compiler/moduleResolutionWithSymlinks.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// @module: commonjs
|
||||
// @noImplicitReferences: true
|
||||
// @traceResolution: true
|
||||
|
||||
// @filename: /src/library-a/index.ts
|
||||
// @symlink: /src/library-b/node_modules/library-a/index.ts
|
||||
export class MyClass{}
|
||||
|
||||
// @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;
|
||||
Loading…
x
Reference in New Issue
Block a user