Skip to content

Commit 14d7a44

Browse files
committed
Merge branch 'master' into add-isIntersectionConstituent-to-relation-key
2 parents 2e0b451 + dbef230 commit 14d7a44

21 files changed

+367
-43
lines changed

src/compiler/checker.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -23436,7 +23436,7 @@ namespace ts {
2343623436
// the declared number of type parameters, the call has an incorrect arity.
2343723437
const numTypeParameters = length(signature.typeParameters);
2343823438
const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters);
23439-
return !typeArguments ||
23439+
return !some(typeArguments) ||
2344023440
(typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
2344123441
}
2344223442

@@ -24196,7 +24196,7 @@ namespace ts {
2419624196

2419724197
if (isSingleNonGenericCandidate) {
2419824198
const candidate = candidates[0];
24199-
if (typeArguments || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
24199+
if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
2420024200
return undefined;
2420124201
}
2420224202
if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
@@ -24217,7 +24217,7 @@ namespace ts {
2421724217

2421824218
if (candidate.typeParameters) {
2421924219
let typeArgumentTypes: Type[] | undefined;
24220-
if (typeArguments) {
24220+
if (some(typeArguments)) {
2422124221
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
2422224222
if (!typeArgumentTypes) {
2422324223
candidateForTypeArgumentError = candidate;

src/compiler/program.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -2271,7 +2271,19 @@ namespace ts {
22712271
// Get source file from normalized fileName
22722272
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
22732273
if (useSourceOfProjectReferenceRedirect) {
2274-
const source = getSourceOfProjectReferenceRedirect(fileName);
2274+
let source = getSourceOfProjectReferenceRedirect(fileName);
2275+
// If preserveSymlinks is true, module resolution wont jump the symlink
2276+
// but the resolved real path may be the .d.ts from project reference
2277+
// Note:: Currently we try the real path only if the
2278+
// file is from node_modules to avoid having to run real path on all file paths
2279+
if (!source &&
2280+
host.realpath &&
2281+
options.preserveSymlinks &&
2282+
isDeclarationFileName(fileName) &&
2283+
stringContains(fileName, nodeModulesPathPart)) {
2284+
const realPath = host.realpath(fileName);
2285+
if (realPath !== fileName) source = getSourceOfProjectReferenceRedirect(realPath);
2286+
}
22752287
if (source) {
22762288
const file = isString(source) ?
22772289
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, packageId) :

src/compiler/transformers/ts.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -2452,7 +2452,12 @@ namespace ts {
24522452
*
24532453
* @param node The module declaration node.
24542454
*/
2455-
function shouldEmitModuleDeclaration(node: ModuleDeclaration) {
2455+
function shouldEmitModuleDeclaration(nodeIn: ModuleDeclaration) {
2456+
const node = getParseTreeNode(nodeIn, isModuleDeclaration);
2457+
if (!node) {
2458+
// If we can't find a parse tree node, assume the node is instantiated.
2459+
return true;
2460+
}
24562461
return isInstantiatedModule(node, !!compilerOptions.preserveConstEnums || !!compilerOptions.isolatedModules);
24572462
}
24582463

src/server/project.ts

+112-16
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ namespace ts.server {
258258
private compilerOptions: CompilerOptions,
259259
public compileOnSaveEnabled: boolean,
260260
directoryStructureHost: DirectoryStructureHost,
261-
currentDirectory: string | undefined) {
261+
currentDirectory: string | undefined,
262+
customRealpath?: (s: string) => string) {
262263
this.directoryStructureHost = directoryStructureHost;
263264
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || "");
264265
this.getCanonicalFileName = this.projectService.toCanonicalFileName;
@@ -286,7 +287,7 @@ namespace ts.server {
286287
}
287288

288289
if (host.realpath) {
289-
this.realpath = path => host.realpath!(path);
290+
this.realpath = customRealpath || (path => host.realpath!(path));
290291
}
291292

292293
// Use the current directory as resolution root only if the project created using current directory string
@@ -1660,6 +1661,12 @@ namespace ts.server {
16601661
}
16611662
}
16621663

1664+
/*@internal*/
1665+
interface SymlinkedDirectory {
1666+
real: string;
1667+
realPath: Path;
1668+
}
1669+
16631670
/**
16641671
* If a file is opened, the server will look for a tsconfig (or jsconfig)
16651672
* and if successfull create a ConfiguredProject for it.
@@ -1673,6 +1680,8 @@ namespace ts.server {
16731680
readonly canonicalConfigFilePath: NormalizedPath;
16741681
private projectReferenceCallbacks: ResolvedProjectReferenceCallbacks | undefined;
16751682
private mapOfDeclarationDirectories: Map<true> | undefined;
1683+
private symlinkedDirectories: Map<SymlinkedDirectory | false> | undefined;
1684+
private symlinkedFiles: Map<string> | undefined;
16761685

16771686
/* @internal */
16781687
pendingReload: ConfigFileProgramReloadLevel | undefined;
@@ -1714,7 +1723,9 @@ namespace ts.server {
17141723
/*compilerOptions*/ {},
17151724
/*compileOnSaveEnabled*/ false,
17161725
cachedDirectoryStructureHost,
1717-
getDirectoryPath(configFileName));
1726+
getDirectoryPath(configFileName),
1727+
projectService.host.realpath && (s => this.getRealpath(s))
1728+
);
17181729
this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName));
17191730
}
17201731

@@ -1727,18 +1738,34 @@ namespace ts.server {
17271738
useSourceOfProjectReferenceRedirect = () => !!this.languageServiceEnabled &&
17281739
!this.getCompilerOptions().disableSourceOfProjectReferenceRedirect;
17291740

1741+
private fileExistsIfProjectReferenceDts(file: string) {
1742+
const source = this.projectReferenceCallbacks!.getSourceOfProjectReferenceRedirect(file);
1743+
return source !== undefined ?
1744+
isString(source) ? super.fileExists(source) : true :
1745+
undefined;
1746+
}
1747+
17301748
/**
17311749
* This implementation of fileExists checks if the file being requested is
17321750
* .d.ts file for the referenced Project.
17331751
* If it is it returns true irrespective of whether that file exists on host
17341752
*/
17351753
fileExists(file: string): boolean {
1754+
if (super.fileExists(file)) return true;
1755+
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false;
1756+
if (!isDeclarationFileName(file)) return false;
1757+
17361758
// Project references go to source file instead of .d.ts file
1737-
if (this.useSourceOfProjectReferenceRedirect() && this.projectReferenceCallbacks) {
1738-
const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file);
1739-
if (source) return isString(source) ? super.fileExists(source) : true;
1740-
}
1741-
return super.fileExists(file);
1759+
return this.fileOrDirectoryExistsUsingSource(file, /*isFile*/ true);
1760+
}
1761+
1762+
private directoryExistsIfProjectReferenceDeclDir(dir: string) {
1763+
const dirPath = this.toPath(dir);
1764+
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
1765+
return forEachKey(
1766+
this.mapOfDeclarationDirectories!,
1767+
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
1768+
);
17421769
}
17431770

17441771
/**
@@ -1747,14 +1774,17 @@ namespace ts.server {
17471774
* If it is it returns true irrespective of whether that directory exists on host
17481775
*/
17491776
directoryExists(path: string): boolean {
1750-
if (super.directoryExists(path)) return true;
1777+
if (super.directoryExists(path)) {
1778+
this.handleDirectoryCouldBeSymlink(path);
1779+
return true;
1780+
}
17511781
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false;
17521782

17531783
if (!this.mapOfDeclarationDirectories) {
17541784
this.mapOfDeclarationDirectories = createMap();
17551785
this.projectReferenceCallbacks.forEachResolvedProjectReference(ref => {
17561786
if (!ref) return;
1757-
const out = ref.commandLine.options.outFile || ref.commandLine.options.outDir;
1787+
const out = ref.commandLine.options.outFile || ref.commandLine.options.out;
17581788
if (out) {
17591789
this.mapOfDeclarationDirectories!.set(getDirectoryPath(this.toPath(out)), true);
17601790
}
@@ -1767,12 +1797,74 @@ namespace ts.server {
17671797
}
17681798
});
17691799
}
1770-
const dirPath = this.toPath(path);
1771-
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
1772-
return !!forEachKey(
1773-
this.mapOfDeclarationDirectories,
1774-
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
1775-
);
1800+
1801+
return this.fileOrDirectoryExistsUsingSource(path, /*isFile*/ false);
1802+
}
1803+
1804+
private realpathIfSymlinkedProjectReferenceDts(s: string): string | undefined {
1805+
return this.symlinkedFiles && this.symlinkedFiles.get(this.toPath(s));
1806+
}
1807+
1808+
private getRealpath(s: string): string {
1809+
return this.realpathIfSymlinkedProjectReferenceDts(s) ||
1810+
this.projectService.host.realpath!(s);
1811+
}
1812+
1813+
private handleDirectoryCouldBeSymlink(directory: string) {
1814+
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return;
1815+
1816+
// Because we already watch node_modules, handle symlinks in there
1817+
if (!this.realpath || !stringContains(directory, nodeModulesPathPart)) return;
1818+
if (!this.symlinkedDirectories) this.symlinkedDirectories = createMap();
1819+
const directoryPath = ensureTrailingDirectorySeparator(this.toPath(directory));
1820+
if (this.symlinkedDirectories.has(directoryPath)) return;
1821+
1822+
const real = this.projectService.host.realpath!(directory);
1823+
let realPath: Path;
1824+
if (real === directory ||
1825+
(realPath = ensureTrailingDirectorySeparator(this.toPath(real))) === directoryPath) {
1826+
// not symlinked
1827+
this.symlinkedDirectories.set(directoryPath, false);
1828+
return;
1829+
}
1830+
1831+
this.symlinkedDirectories.set(directoryPath, {
1832+
real: ensureTrailingDirectorySeparator(real),
1833+
realPath
1834+
});
1835+
}
1836+
1837+
private fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean {
1838+
const fileOrDirectoryExistsUsingSource = isFile ?
1839+
(file: string) => this.fileExistsIfProjectReferenceDts(file) :
1840+
(dir: string) => this.directoryExistsIfProjectReferenceDeclDir(dir);
1841+
// Check current directory or file
1842+
const result = fileOrDirectoryExistsUsingSource(fileOrDirectory);
1843+
if (result !== undefined) return result;
1844+
1845+
if (!this.symlinkedDirectories) return false;
1846+
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
1847+
if (!stringContains(fileOrDirectoryPath, nodeModulesPathPart)) return false;
1848+
if (isFile && this.symlinkedFiles && this.symlinkedFiles.has(fileOrDirectoryPath)) return true;
1849+
1850+
// If it contains node_modules check if its one of the symlinked path we know of
1851+
return firstDefinedIterator(
1852+
this.symlinkedDirectories.entries(),
1853+
([directoryPath, symlinkedDirectory]) => {
1854+
if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined;
1855+
const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath));
1856+
if (isFile && result) {
1857+
if (!this.symlinkedFiles) this.symlinkedFiles = createMap();
1858+
// Store the real path for the file'
1859+
const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, this.currentDirectory);
1860+
this.symlinkedFiles.set(
1861+
fileOrDirectoryPath,
1862+
`${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`
1863+
);
1864+
}
1865+
return result;
1866+
}
1867+
) || false;
17761868
}
17771869

17781870
/**
@@ -1785,6 +1877,8 @@ namespace ts.server {
17851877
this.pendingReload = ConfigFileProgramReloadLevel.None;
17861878
this.projectReferenceCallbacks = undefined;
17871879
this.mapOfDeclarationDirectories = undefined;
1880+
this.symlinkedDirectories = undefined;
1881+
this.symlinkedFiles = undefined;
17881882
let result: boolean;
17891883
switch (reloadLevel) {
17901884
case ConfigFileProgramReloadLevel.Partial:
@@ -1917,6 +2011,8 @@ namespace ts.server {
19172011
this.configFileSpecs = undefined;
19182012
this.projectReferenceCallbacks = undefined;
19192013
this.mapOfDeclarationDirectories = undefined;
2014+
this.symlinkedDirectories = undefined;
2015+
this.symlinkedFiles = undefined;
19202016
super.close();
19212017
}
19222018

src/services/formatting/smartIndenter.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,9 @@ namespace ts.formatting {
326326
export function argumentStartsOnSameLineAsPreviousArgument(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean {
327327
if (isCallOrNewExpression(parent)) {
328328
if (!parent.arguments) return false;
329-
330-
const currentNode = Debug.assertDefined(find(parent.arguments, arg => arg.pos === child.pos));
329+
const currentNode = find(parent.arguments, arg => arg.pos === child.pos);
330+
// If it's not one of the arguments, don't look past this
331+
if (!currentNode) return false;
331332
const currentIndex = parent.arguments.indexOf(currentNode);
332333
if (currentIndex === 0) return false; // Can't look at previous node if first
333334

src/testRunner/unittests/transform.ts

+29
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,35 @@ namespace Foo {
447447
}).outputText;
448448
});
449449

450+
testBaseline("transformUpdateModuleMember", () => {
451+
return transpileModule(`
452+
module MyModule {
453+
const myVariable = 1;
454+
function foo(param: string) {}
455+
}
456+
`, {
457+
transformers: {
458+
before: [renameVariable],
459+
},
460+
compilerOptions: {
461+
target: ScriptTarget.ES2015,
462+
newLine: NewLineKind.CarriageReturnLineFeed,
463+
}
464+
}).outputText;
465+
466+
function renameVariable(context: TransformationContext) {
467+
return (sourceFile: SourceFile): SourceFile => {
468+
return visitNode(sourceFile, rootTransform, isSourceFile);
469+
};
470+
function rootTransform<T extends Node>(node: T): Node {
471+
if (isVariableDeclaration(node)) {
472+
return updateVariableDeclaration(node, createIdentifier("newName"), /* type */ undefined, node.initializer);
473+
}
474+
return visitEachChild(node, rootTransform, context);
475+
}
476+
}
477+
});
478+
450479
// https://github.com/Microsoft/TypeScript/issues/24709
451480
testBaseline("issue24709", () => {
452481
const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true);

0 commit comments

Comments
 (0)