Skip to content

Commit

Permalink
Merge branch 'master' into add-isIntersectionConstituent-to-relation-key
Browse files Browse the repository at this point in the history
  • Loading branch information
sandersn committed Oct 29, 2019
2 parents 2e0b451 + dbef230 commit 14d7a44
Show file tree
Hide file tree
Showing 21 changed files with 367 additions and 43 deletions.
6 changes: 3 additions & 3 deletions src/compiler/checker.ts
Expand Up @@ -23436,7 +23436,7 @@ namespace ts {
// the declared number of type parameters, the call has an incorrect arity.
const numTypeParameters = length(signature.typeParameters);
const minTypeArgumentCount = getMinTypeArgumentCount(signature.typeParameters);
return !typeArguments ||
return !some(typeArguments) ||
(typeArguments.length >= minTypeArgumentCount && typeArguments.length <= numTypeParameters);
}

Expand Down Expand Up @@ -24196,7 +24196,7 @@ namespace ts {

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

if (candidate.typeParameters) {
let typeArgumentTypes: Type[] | undefined;
if (typeArguments) {
if (some(typeArguments)) {
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
if (!typeArgumentTypes) {
candidateForTypeArgumentError = candidate;
Expand Down
14 changes: 13 additions & 1 deletion src/compiler/program.ts
Expand Up @@ -2271,7 +2271,19 @@ namespace ts {
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
if (useSourceOfProjectReferenceRedirect) {
const source = getSourceOfProjectReferenceRedirect(fileName);
let source = getSourceOfProjectReferenceRedirect(fileName);
// If preserveSymlinks is true, module resolution wont jump the symlink
// but the resolved real path may be the .d.ts from project reference
// Note:: Currently we try the real path only if the
// file is from node_modules to avoid having to run real path on all file paths
if (!source &&
host.realpath &&
options.preserveSymlinks &&
isDeclarationFileName(fileName) &&
stringContains(fileName, nodeModulesPathPart)) {
const realPath = host.realpath(fileName);
if (realPath !== fileName) source = getSourceOfProjectReferenceRedirect(realPath);
}
if (source) {
const file = isString(source) ?
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, packageId) :
Expand Down
7 changes: 6 additions & 1 deletion src/compiler/transformers/ts.ts
Expand Up @@ -2452,7 +2452,12 @@ namespace ts {
*
* @param node The module declaration node.
*/
function shouldEmitModuleDeclaration(node: ModuleDeclaration) {
function shouldEmitModuleDeclaration(nodeIn: ModuleDeclaration) {
const node = getParseTreeNode(nodeIn, isModuleDeclaration);
if (!node) {
// If we can't find a parse tree node, assume the node is instantiated.
return true;
}
return isInstantiatedModule(node, !!compilerOptions.preserveConstEnums || !!compilerOptions.isolatedModules);
}

Expand Down
128 changes: 112 additions & 16 deletions src/server/project.ts
Expand Up @@ -258,7 +258,8 @@ namespace ts.server {
private compilerOptions: CompilerOptions,
public compileOnSaveEnabled: boolean,
directoryStructureHost: DirectoryStructureHost,
currentDirectory: string | undefined) {
currentDirectory: string | undefined,
customRealpath?: (s: string) => string) {
this.directoryStructureHost = directoryStructureHost;
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || "");
this.getCanonicalFileName = this.projectService.toCanonicalFileName;
Expand Down Expand Up @@ -286,7 +287,7 @@ namespace ts.server {
}

if (host.realpath) {
this.realpath = path => host.realpath!(path);
this.realpath = customRealpath || (path => host.realpath!(path));
}

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

/*@internal*/
interface SymlinkedDirectory {
real: string;
realPath: Path;
}

/**
* If a file is opened, the server will look for a tsconfig (or jsconfig)
* and if successfull create a ConfiguredProject for it.
Expand All @@ -1673,6 +1680,8 @@ namespace ts.server {
readonly canonicalConfigFilePath: NormalizedPath;
private projectReferenceCallbacks: ResolvedProjectReferenceCallbacks | undefined;
private mapOfDeclarationDirectories: Map<true> | undefined;
private symlinkedDirectories: Map<SymlinkedDirectory | false> | undefined;
private symlinkedFiles: Map<string> | undefined;

/* @internal */
pendingReload: ConfigFileProgramReloadLevel | undefined;
Expand Down Expand Up @@ -1714,7 +1723,9 @@ namespace ts.server {
/*compilerOptions*/ {},
/*compileOnSaveEnabled*/ false,
cachedDirectoryStructureHost,
getDirectoryPath(configFileName));
getDirectoryPath(configFileName),
projectService.host.realpath && (s => this.getRealpath(s))
);
this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName));
}

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

private fileExistsIfProjectReferenceDts(file: string) {
const source = this.projectReferenceCallbacks!.getSourceOfProjectReferenceRedirect(file);
return source !== undefined ?
isString(source) ? super.fileExists(source) : true :
undefined;
}

/**
* This implementation of fileExists checks if the file being requested is
* .d.ts file for the referenced Project.
* If it is it returns true irrespective of whether that file exists on host
*/
fileExists(file: string): boolean {
if (super.fileExists(file)) return true;
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false;
if (!isDeclarationFileName(file)) return false;

// Project references go to source file instead of .d.ts file
if (this.useSourceOfProjectReferenceRedirect() && this.projectReferenceCallbacks) {
const source = this.projectReferenceCallbacks.getSourceOfProjectReferenceRedirect(file);
if (source) return isString(source) ? super.fileExists(source) : true;
}
return super.fileExists(file);
return this.fileOrDirectoryExistsUsingSource(file, /*isFile*/ true);
}

private directoryExistsIfProjectReferenceDeclDir(dir: string) {
const dirPath = this.toPath(dir);
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
return forEachKey(
this.mapOfDeclarationDirectories!,
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
);
}

/**
Expand All @@ -1747,14 +1774,17 @@ namespace ts.server {
* If it is it returns true irrespective of whether that directory exists on host
*/
directoryExists(path: string): boolean {
if (super.directoryExists(path)) return true;
if (super.directoryExists(path)) {
this.handleDirectoryCouldBeSymlink(path);
return true;
}
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return false;

if (!this.mapOfDeclarationDirectories) {
this.mapOfDeclarationDirectories = createMap();
this.projectReferenceCallbacks.forEachResolvedProjectReference(ref => {
if (!ref) return;
const out = ref.commandLine.options.outFile || ref.commandLine.options.outDir;
const out = ref.commandLine.options.outFile || ref.commandLine.options.out;
if (out) {
this.mapOfDeclarationDirectories!.set(getDirectoryPath(this.toPath(out)), true);
}
Expand All @@ -1767,12 +1797,74 @@ namespace ts.server {
}
});
}
const dirPath = this.toPath(path);
const dirPathWithTrailingDirectorySeparator = `${dirPath}${directorySeparator}`;
return !!forEachKey(
this.mapOfDeclarationDirectories,
declDirPath => dirPath === declDirPath || startsWith(declDirPath, dirPathWithTrailingDirectorySeparator)
);

return this.fileOrDirectoryExistsUsingSource(path, /*isFile*/ false);
}

private realpathIfSymlinkedProjectReferenceDts(s: string): string | undefined {
return this.symlinkedFiles && this.symlinkedFiles.get(this.toPath(s));
}

private getRealpath(s: string): string {
return this.realpathIfSymlinkedProjectReferenceDts(s) ||
this.projectService.host.realpath!(s);
}

private handleDirectoryCouldBeSymlink(directory: string) {
if (!this.useSourceOfProjectReferenceRedirect() || !this.projectReferenceCallbacks) return;

// Because we already watch node_modules, handle symlinks in there
if (!this.realpath || !stringContains(directory, nodeModulesPathPart)) return;
if (!this.symlinkedDirectories) this.symlinkedDirectories = createMap();
const directoryPath = ensureTrailingDirectorySeparator(this.toPath(directory));
if (this.symlinkedDirectories.has(directoryPath)) return;

const real = this.projectService.host.realpath!(directory);
let realPath: Path;
if (real === directory ||
(realPath = ensureTrailingDirectorySeparator(this.toPath(real))) === directoryPath) {
// not symlinked
this.symlinkedDirectories.set(directoryPath, false);
return;
}

this.symlinkedDirectories.set(directoryPath, {
real: ensureTrailingDirectorySeparator(real),
realPath
});
}

private fileOrDirectoryExistsUsingSource(fileOrDirectory: string, isFile: boolean): boolean {
const fileOrDirectoryExistsUsingSource = isFile ?
(file: string) => this.fileExistsIfProjectReferenceDts(file) :
(dir: string) => this.directoryExistsIfProjectReferenceDeclDir(dir);
// Check current directory or file
const result = fileOrDirectoryExistsUsingSource(fileOrDirectory);
if (result !== undefined) return result;

if (!this.symlinkedDirectories) return false;
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
if (!stringContains(fileOrDirectoryPath, nodeModulesPathPart)) return false;
if (isFile && this.symlinkedFiles && this.symlinkedFiles.has(fileOrDirectoryPath)) return true;

// If it contains node_modules check if its one of the symlinked path we know of
return firstDefinedIterator(
this.symlinkedDirectories.entries(),
([directoryPath, symlinkedDirectory]) => {
if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined;
const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath));
if (isFile && result) {
if (!this.symlinkedFiles) this.symlinkedFiles = createMap();
// Store the real path for the file'
const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, this.currentDirectory);
this.symlinkedFiles.set(
fileOrDirectoryPath,
`${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`
);
}
return result;
}
) || false;
}

/**
Expand All @@ -1785,6 +1877,8 @@ namespace ts.server {
this.pendingReload = ConfigFileProgramReloadLevel.None;
this.projectReferenceCallbacks = undefined;
this.mapOfDeclarationDirectories = undefined;
this.symlinkedDirectories = undefined;
this.symlinkedFiles = undefined;
let result: boolean;
switch (reloadLevel) {
case ConfigFileProgramReloadLevel.Partial:
Expand Down Expand Up @@ -1917,6 +2011,8 @@ namespace ts.server {
this.configFileSpecs = undefined;
this.projectReferenceCallbacks = undefined;
this.mapOfDeclarationDirectories = undefined;
this.symlinkedDirectories = undefined;
this.symlinkedFiles = undefined;
super.close();
}

Expand Down
5 changes: 3 additions & 2 deletions src/services/formatting/smartIndenter.ts
Expand Up @@ -326,8 +326,9 @@ namespace ts.formatting {
export function argumentStartsOnSameLineAsPreviousArgument(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFileLike): boolean {
if (isCallOrNewExpression(parent)) {
if (!parent.arguments) return false;

const currentNode = Debug.assertDefined(find(parent.arguments, arg => arg.pos === child.pos));
const currentNode = find(parent.arguments, arg => arg.pos === child.pos);
// If it's not one of the arguments, don't look past this
if (!currentNode) return false;
const currentIndex = parent.arguments.indexOf(currentNode);
if (currentIndex === 0) return false; // Can't look at previous node if first

Expand Down
29 changes: 29 additions & 0 deletions src/testRunner/unittests/transform.ts
Expand Up @@ -447,6 +447,35 @@ namespace Foo {
}).outputText;
});

testBaseline("transformUpdateModuleMember", () => {
return transpileModule(`
module MyModule {
const myVariable = 1;
function foo(param: string) {}
}
`, {
transformers: {
before: [renameVariable],
},
compilerOptions: {
target: ScriptTarget.ES2015,
newLine: NewLineKind.CarriageReturnLineFeed,
}
}).outputText;

function renameVariable(context: TransformationContext) {
return (sourceFile: SourceFile): SourceFile => {
return visitNode(sourceFile, rootTransform, isSourceFile);
};
function rootTransform<T extends Node>(node: T): Node {
if (isVariableDeclaration(node)) {
return updateVariableDeclaration(node, createIdentifier("newName"), /* type */ undefined, node.initializer);
}
return visitEachChild(node, rootTransform, context);
}
}
});

// https://github.com/Microsoft/TypeScript/issues/24709
testBaseline("issue24709", () => {
const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true);
Expand Down

0 comments on commit 14d7a44

Please sign in to comment.