mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
This commit is contained in:
@@ -10891,7 +10891,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getAliasSymbolForTypeNode(node: TypeNode) {
|
||||
return isTypeAlias(node.parent) ? getSymbolOfNode(node.parent) : undefined;
|
||||
let host = node.parent;
|
||||
while (isParenthesizedTypeNode(host)) {
|
||||
host = host.parent;
|
||||
}
|
||||
return isTypeAlias(host) ? getSymbolOfNode(host) : undefined;
|
||||
}
|
||||
|
||||
function getTypeArgumentsForAliasSymbol(symbol: Symbol | undefined) {
|
||||
|
||||
@@ -5116,6 +5116,10 @@
|
||||
"category": "Message",
|
||||
"code": 95088
|
||||
},
|
||||
"Add 'await' to initializers": {
|
||||
"category": "Message",
|
||||
"code": 95089
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -90,14 +90,28 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
|
||||
let nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
|
||||
if (nextDirectorySeparator === -1) {
|
||||
// ignore "/user", "c:/users" or "c:/folderAtRoot"
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dirPath.charCodeAt(0) !== CharacterCodes.slash &&
|
||||
dirPath.substr(rootLength, nextDirectorySeparator).search(/users/i) === -1) {
|
||||
let pathPartForUserCheck = dirPath.substring(rootLength, nextDirectorySeparator + 1);
|
||||
const isNonDirectorySeparatorRoot = rootLength > 1 || dirPath.charCodeAt(0) !== CharacterCodes.slash;
|
||||
if (isNonDirectorySeparatorRoot &&
|
||||
dirPath.search(/[a-zA-Z]:/) !== 0 && // Non dos style paths
|
||||
pathPartForUserCheck.search(/[a-zA-z]\$\//) === 0) { // Dos style nextPart
|
||||
nextDirectorySeparator = dirPath.indexOf(directorySeparator, nextDirectorySeparator + 1);
|
||||
if (nextDirectorySeparator === -1) {
|
||||
// ignore "//vda1cs4850/c$/folderAtRoot"
|
||||
return false;
|
||||
}
|
||||
|
||||
pathPartForUserCheck = dirPath.substring(rootLength + pathPartForUserCheck.length, nextDirectorySeparator + 1);
|
||||
}
|
||||
|
||||
if (isNonDirectorySeparatorRoot &&
|
||||
pathPartForUserCheck.search(/users\//i) !== 0) {
|
||||
// Paths like c:/folderAtRoot/subFolder are allowed
|
||||
return true;
|
||||
}
|
||||
@@ -105,7 +119,7 @@ namespace ts {
|
||||
for (let searchIndex = nextDirectorySeparator + 1, searchLevels = 2; searchLevels > 0; searchLevels--) {
|
||||
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
|
||||
if (searchIndex === 0) {
|
||||
// Folder isnt at expected minimun levels
|
||||
// Folder isnt at expected minimum levels
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2183,7 +2183,7 @@ namespace ts {
|
||||
|
||||
if (isIdentifierStart(ch, languageVersion)) {
|
||||
let char = ch;
|
||||
while (pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion)) pos += charSize(char);
|
||||
while (pos < end && isIdentifierPart(char = codePointAt(text, pos), languageVersion) || text.charCodeAt(pos) === CharacterCodes.minus) pos += charSize(char);
|
||||
tokenValue = text.substring(tokenPos, pos);
|
||||
if (char === CharacterCodes.backslash) {
|
||||
tokenValue += scanIdentifierParts();
|
||||
|
||||
@@ -35,38 +35,16 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
executingFilePath?: string;
|
||||
currentDirectory?: string;
|
||||
newLine?: string;
|
||||
useWindowsStylePaths?: boolean;
|
||||
windowsStyleRoot?: string;
|
||||
environmentVariables?: Map<string>;
|
||||
}
|
||||
|
||||
export function createWatchedSystem(fileOrFolderList: readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
const host = new TestServerHost(/*withSafelist*/ false,
|
||||
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
|
||||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine,
|
||||
params.useWindowsStylePaths,
|
||||
params.environmentVariables);
|
||||
return host;
|
||||
return new TestServerHost(/*withSafelist*/ false, fileOrFolderList, params);
|
||||
}
|
||||
|
||||
export function createServerHost(fileOrFolderList: readonly FileOrFolderOrSymLink[], params?: TestServerHostCreationParameters): TestServerHost {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
const host = new TestServerHost(/*withSafelist*/ true,
|
||||
params.useCaseSensitiveFileNames !== undefined ? params.useCaseSensitiveFileNames : false,
|
||||
params.executingFilePath || getExecutingFilePathFromLibFile(),
|
||||
params.currentDirectory || "/",
|
||||
fileOrFolderList,
|
||||
params.newLine,
|
||||
params.useWindowsStylePaths,
|
||||
params.environmentVariables);
|
||||
return host;
|
||||
return new TestServerHost(/*withSafelist*/ true, fileOrFolderList, params);
|
||||
}
|
||||
|
||||
export interface File {
|
||||
@@ -326,6 +304,16 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
}
|
||||
|
||||
const timeIncrements = 1000;
|
||||
export interface TestServerHostOptions {
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
executingFilePath: string;
|
||||
currentDirectory: string;
|
||||
fileOrFolderorSymLinkList: readonly FileOrFolderOrSymLink[];
|
||||
newLine?: string;
|
||||
useWindowsStylePaths?: boolean;
|
||||
environmentVariables?: Map<string>;
|
||||
}
|
||||
|
||||
export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, ModuleResolutionHost {
|
||||
args: string[] = [];
|
||||
|
||||
@@ -342,16 +330,31 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
readonly watchedDirectories = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedDirectoriesRecursive = createMultiMap<TestDirectoryWatcher>();
|
||||
readonly watchedFiles = createMultiMap<TestFileWatcher>();
|
||||
public readonly useCaseSensitiveFileNames: boolean;
|
||||
public readonly newLine: string;
|
||||
public readonly windowsStyleRoot?: string;
|
||||
private readonly environmentVariables?: Map<string>;
|
||||
private readonly executingFilePath: string;
|
||||
private readonly currentDirectory: string;
|
||||
private readonly customWatchFile: HostWatchFile | undefined;
|
||||
private readonly customRecursiveWatchDirectory: HostWatchDirectory | undefined;
|
||||
public require: ((initialPath: string, moduleName: string) => server.RequireResult) | undefined;
|
||||
|
||||
constructor(public withSafeList: boolean, public useCaseSensitiveFileNames: boolean, executingFilePath: string, currentDirectory: string, fileOrFolderorSymLinkList: readonly FileOrFolderOrSymLink[], public readonly newLine = "\n", public readonly useWindowsStylePath?: boolean, private readonly environmentVariables?: Map<string>) {
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
||||
constructor(
|
||||
public withSafeList: boolean,
|
||||
fileOrFolderorSymLinkList: readonly FileOrFolderOrSymLink[],
|
||||
{
|
||||
useCaseSensitiveFileNames, executingFilePath, currentDirectory,
|
||||
newLine, windowsStyleRoot, environmentVariables
|
||||
}: TestServerHostCreationParameters = {}) {
|
||||
this.useCaseSensitiveFileNames = !!useCaseSensitiveFileNames;
|
||||
this.newLine = newLine || "\n";
|
||||
this.windowsStyleRoot = windowsStyleRoot;
|
||||
this.environmentVariables = environmentVariables;
|
||||
currentDirectory = currentDirectory || "/";
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
|
||||
this.toPath = s => toPath(s, currentDirectory, this.getCanonicalFileName);
|
||||
this.executingFilePath = this.getHostSpecificPath(executingFilePath);
|
||||
this.executingFilePath = this.getHostSpecificPath(executingFilePath || getExecutingFilePathFromLibFile());
|
||||
this.currentDirectory = this.getHostSpecificPath(currentDirectory);
|
||||
this.reloadFS(fileOrFolderorSymLinkList);
|
||||
const tscWatchFile = this.environmentVariables && this.environmentVariables.get("TSC_WATCHFILE") as Tsc_WatchFile;
|
||||
@@ -418,8 +421,8 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
}
|
||||
|
||||
getHostSpecificPath(s: string) {
|
||||
if (this.useWindowsStylePath && s.startsWith(directorySeparator)) {
|
||||
return "c:/" + s.substring(1);
|
||||
if (this.windowsStyleRoot && s.startsWith(directorySeparator)) {
|
||||
return this.windowsStyleRoot + s.substring(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -433,7 +436,7 @@ interface Array<T> { length: number; [n: number]: T; }`
|
||||
const mapNewLeaves = createMap<true>();
|
||||
const isNewFs = this.fs.size === 0;
|
||||
fileOrFolderOrSymLinkList = fileOrFolderOrSymLinkList.concat(this.withSafeList ? safeList : []);
|
||||
const filesOrFoldersToLoad: readonly FileOrFolderOrSymLink[] = !this.useWindowsStylePath ? fileOrFolderOrSymLinkList :
|
||||
const filesOrFoldersToLoad: readonly FileOrFolderOrSymLink[] = !this.windowsStyleRoot ? fileOrFolderOrSymLinkList :
|
||||
fileOrFolderOrSymLinkList.map<FileOrFolderOrSymLink>(f => {
|
||||
const result = clone(f);
|
||||
result.path = this.getHostSpecificPath(f.path);
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace ts.codefix {
|
||||
errorCodes,
|
||||
getCodeActions: context => {
|
||||
const { sourceFile, errorCode, span, cancellationToken, program } = context;
|
||||
const expression = getAwaitableExpression(sourceFile, errorCode, span, cancellationToken, program);
|
||||
const expression = getFixableErrorSpanExpression(sourceFile, errorCode, span, cancellationToken, program);
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
@@ -45,32 +45,40 @@ namespace ts.codefix {
|
||||
getAllCodeActions: context => {
|
||||
const { sourceFile, program, cancellationToken } = context;
|
||||
const checker = context.program.getTypeChecker();
|
||||
const fixedDeclarations = createMap<true>();
|
||||
return codeFixAll(context, errorCodes, (t, diagnostic) => {
|
||||
const expression = getAwaitableExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program);
|
||||
const expression = getFixableErrorSpanExpression(sourceFile, diagnostic.code, diagnostic, cancellationToken, program);
|
||||
if (!expression) {
|
||||
return;
|
||||
}
|
||||
const trackChanges: ContextualTrackChangesFunction = cb => (cb(t), []);
|
||||
return getDeclarationSiteFix(context, expression, diagnostic.code, checker, trackChanges)
|
||||
|| getUseSiteFix(context, expression, diagnostic.code, checker, trackChanges);
|
||||
return getDeclarationSiteFix(context, expression, diagnostic.code, checker, trackChanges, fixedDeclarations)
|
||||
|| getUseSiteFix(context, expression, diagnostic.code, checker, trackChanges, fixedDeclarations);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction) {
|
||||
const { sourceFile } = context;
|
||||
const awaitableInitializer = findAwaitableInitializer(expression, sourceFile, checker);
|
||||
if (awaitableInitializer) {
|
||||
const initializerChanges = trackChanges(t => makeChange(t, errorCode, sourceFile, checker, awaitableInitializer));
|
||||
function getDeclarationSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Map<true>) {
|
||||
const { sourceFile, program, cancellationToken } = context;
|
||||
const awaitableInitializers = findAwaitableInitializers(expression, sourceFile, cancellationToken, program, checker);
|
||||
if (awaitableInitializers) {
|
||||
const initializerChanges = trackChanges(t => {
|
||||
forEach(awaitableInitializers.initializers, ({ expression }) => makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations));
|
||||
if (fixedDeclarations && awaitableInitializers.needsSecondPassForFixAll) {
|
||||
makeChange(t, errorCode, sourceFile, checker, expression, fixedDeclarations);
|
||||
}
|
||||
});
|
||||
return createCodeFixActionNoFixId(
|
||||
"addMissingAwaitToInitializer",
|
||||
initializerChanges,
|
||||
[Diagnostics.Add_await_to_initializer_for_0, expression.getText(sourceFile)]);
|
||||
awaitableInitializers.initializers.length === 1
|
||||
? [Diagnostics.Add_await_to_initializer_for_0, awaitableInitializers.initializers[0].declarationSymbol.name]
|
||||
: Diagnostics.Add_await_to_initializers);
|
||||
}
|
||||
}
|
||||
|
||||
function getUseSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction) {
|
||||
const changes = trackChanges(t => makeChange(t, errorCode, context.sourceFile, checker, expression));
|
||||
function getUseSiteFix(context: CodeFixContext | CodeFixAllContext, expression: Expression, errorCode: number, checker: TypeChecker, trackChanges: ContextualTrackChangesFunction, fixedDeclarations?: Map<true>) {
|
||||
const changes = trackChanges(t => makeChange(t, errorCode, context.sourceFile, checker, expression, fixedDeclarations));
|
||||
return createCodeFixAction(fixId, changes, Diagnostics.Add_await, fixId, Diagnostics.Fix_all_expressions_possibly_missing_await);
|
||||
}
|
||||
|
||||
@@ -84,7 +92,7 @@ namespace ts.codefix {
|
||||
some(relatedInformation, related => related.code === Diagnostics.Did_you_forget_to_use_await.code));
|
||||
}
|
||||
|
||||
function getAwaitableExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program): Expression | undefined {
|
||||
function getFixableErrorSpanExpression(sourceFile: SourceFile, errorCode: number, span: TextSpan, cancellationToken: CancellationToken, program: Program): Expression | undefined {
|
||||
const token = getTokenAtPosition(sourceFile, span.start);
|
||||
// Checker has already done work to determine that await might be possible, and has attached
|
||||
// related info to the node, so start by finding the expression that exactly matches up
|
||||
@@ -101,38 +109,117 @@ namespace ts.codefix {
|
||||
&& isInsideAwaitableBody(expression) ? expression : undefined;
|
||||
}
|
||||
|
||||
function findAwaitableInitializer(expression: Node, sourceFile: SourceFile, checker: TypeChecker): Expression | undefined {
|
||||
if (!isIdentifier(expression)) {
|
||||
interface AwaitableInitializer {
|
||||
expression: Expression;
|
||||
declarationSymbol: Symbol;
|
||||
}
|
||||
|
||||
interface AwaitableInitializers {
|
||||
initializers: readonly AwaitableInitializer[];
|
||||
needsSecondPassForFixAll: boolean;
|
||||
}
|
||||
|
||||
function findAwaitableInitializers(
|
||||
expression: Node,
|
||||
sourceFile: SourceFile,
|
||||
cancellationToken: CancellationToken,
|
||||
program: Program,
|
||||
checker: TypeChecker,
|
||||
): AwaitableInitializers | undefined {
|
||||
const identifiers = getIdentifiersFromErrorSpanExpression(expression, checker);
|
||||
if (!identifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
const symbol = checker.getSymbolAtLocation(expression);
|
||||
if (!symbol) {
|
||||
return;
|
||||
let isCompleteFix = identifiers.isCompleteFix;
|
||||
let initializers: AwaitableInitializer[] | undefined;
|
||||
for (const identifier of identifiers.identifiers) {
|
||||
const symbol = checker.getSymbolAtLocation(identifier);
|
||||
if (!symbol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const declaration = tryCast(symbol.valueDeclaration, isVariableDeclaration);
|
||||
const variableName = declaration && tryCast(declaration.name, isIdentifier);
|
||||
const variableStatement = getAncestor(declaration, SyntaxKind.VariableStatement);
|
||||
if (!declaration || !variableStatement ||
|
||||
declaration.type ||
|
||||
!declaration.initializer ||
|
||||
variableStatement.getSourceFile() !== sourceFile ||
|
||||
hasModifier(variableStatement, ModifierFlags.Export) ||
|
||||
!variableName ||
|
||||
!isInsideAwaitableBody(declaration.initializer)) {
|
||||
isCompleteFix = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const diagnostics = program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile(variableName, checker, sourceFile, reference => {
|
||||
return identifier !== reference && !symbolReferenceIsAlsoMissingAwait(reference, diagnostics, sourceFile, checker);
|
||||
});
|
||||
|
||||
if (isUsedElsewhere) {
|
||||
isCompleteFix = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
(initializers || (initializers = [])).push({
|
||||
expression: declaration.initializer,
|
||||
declarationSymbol: symbol,
|
||||
});
|
||||
}
|
||||
return initializers && {
|
||||
initializers,
|
||||
needsSecondPassForFixAll: !isCompleteFix,
|
||||
};
|
||||
}
|
||||
|
||||
const declaration = tryCast(symbol.valueDeclaration, isVariableDeclaration);
|
||||
const variableName = tryCast(declaration && declaration.name, isIdentifier);
|
||||
const variableStatement = getAncestor(declaration, SyntaxKind.VariableStatement);
|
||||
if (!declaration || !variableStatement ||
|
||||
declaration.type ||
|
||||
!declaration.initializer ||
|
||||
variableStatement.getSourceFile() !== sourceFile ||
|
||||
hasModifier(variableStatement, ModifierFlags.Export) ||
|
||||
!variableName ||
|
||||
!isInsideAwaitableBody(declaration.initializer)) {
|
||||
return;
|
||||
interface Identifiers {
|
||||
identifiers: readonly Identifier[];
|
||||
isCompleteFix: boolean;
|
||||
}
|
||||
|
||||
function getIdentifiersFromErrorSpanExpression(expression: Node, checker: TypeChecker): Identifiers | undefined {
|
||||
if (isPropertyAccessExpression(expression.parent) && isIdentifier(expression.parent.expression)) {
|
||||
return { identifiers: [expression.parent.expression], isCompleteFix: true };
|
||||
}
|
||||
|
||||
const isUsedElsewhere = FindAllReferences.Core.eachSymbolReferenceInFile(variableName, checker, sourceFile, identifier => {
|
||||
return identifier !== expression;
|
||||
});
|
||||
|
||||
if (isUsedElsewhere) {
|
||||
return;
|
||||
if (isIdentifier(expression)) {
|
||||
return { identifiers: [expression], isCompleteFix: true };
|
||||
}
|
||||
if (isBinaryExpression(expression)) {
|
||||
let sides: Identifier[] | undefined;
|
||||
let isCompleteFix = true;
|
||||
for (const side of [expression.left, expression.right]) {
|
||||
const type = checker.getTypeAtLocation(side);
|
||||
if (checker.getPromisedTypeOfPromise(type)) {
|
||||
if (!isIdentifier(side)) {
|
||||
isCompleteFix = false;
|
||||
continue;
|
||||
}
|
||||
(sides || (sides = [])).push(side);
|
||||
}
|
||||
}
|
||||
return sides && { identifiers: sides, isCompleteFix };
|
||||
}
|
||||
}
|
||||
|
||||
return declaration.initializer;
|
||||
function symbolReferenceIsAlsoMissingAwait(reference: Identifier, diagnostics: readonly Diagnostic[], sourceFile: SourceFile, checker: TypeChecker) {
|
||||
const errorNode = isPropertyAccessExpression(reference.parent) ? reference.parent.name :
|
||||
isBinaryExpression(reference.parent) ? reference.parent :
|
||||
reference;
|
||||
const diagnostic = find(diagnostics, diagnostic =>
|
||||
diagnostic.start === errorNode.getStart(sourceFile) &&
|
||||
diagnostic.start + diagnostic.length! === errorNode.getEnd());
|
||||
|
||||
return diagnostic && contains(errorCodes, diagnostic.code) ||
|
||||
// A Promise is usually not correct in a binary expression (it’s not valid
|
||||
// in an arithmetic expression and an equality comparison seems unusual),
|
||||
// but if the other side of the binary expression has an error, the side
|
||||
// is typed `any` which will squash the error that would identify this
|
||||
// Promise as an invalid operand. So if the whole binary expression is
|
||||
// typed `any` as a result, there is a strong likelihood that this Promise
|
||||
// is accidentally missing `await`.
|
||||
checker.getTypeAtLocation(errorNode).flags & TypeFlags.Any;
|
||||
}
|
||||
|
||||
function isInsideAwaitableBody(node: Node) {
|
||||
@@ -145,26 +232,48 @@ namespace ts.codefix {
|
||||
ancestor.parent.kind === SyntaxKind.MethodDeclaration));
|
||||
}
|
||||
|
||||
function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, checker: TypeChecker, insertionSite: Expression) {
|
||||
function makeChange(changeTracker: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, checker: TypeChecker, insertionSite: Expression, fixedDeclarations?: Map<true>) {
|
||||
if (isBinaryExpression(insertionSite)) {
|
||||
const { left, right } = insertionSite;
|
||||
const leftType = checker.getTypeAtLocation(left);
|
||||
const rightType = checker.getTypeAtLocation(right);
|
||||
const newLeft = checker.getPromisedTypeOfPromise(leftType) ? createAwait(left) : left;
|
||||
const newRight = checker.getPromisedTypeOfPromise(rightType) ? createAwait(right) : right;
|
||||
changeTracker.replaceNode(sourceFile, left, newLeft);
|
||||
changeTracker.replaceNode(sourceFile, right, newRight);
|
||||
for (const side of [insertionSite.left, insertionSite.right]) {
|
||||
if (fixedDeclarations && isIdentifier(side)) {
|
||||
const symbol = checker.getSymbolAtLocation(side);
|
||||
if (symbol && fixedDeclarations.has(getSymbolId(symbol).toString())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const type = checker.getTypeAtLocation(side);
|
||||
const newNode = checker.getPromisedTypeOfPromise(type) ? createAwait(side) : side;
|
||||
changeTracker.replaceNode(sourceFile, side, newNode);
|
||||
}
|
||||
}
|
||||
else if (errorCode === propertyAccessCode && isPropertyAccessExpression(insertionSite.parent)) {
|
||||
if (fixedDeclarations && isIdentifier(insertionSite.parent.expression)) {
|
||||
const symbol = checker.getSymbolAtLocation(insertionSite.parent.expression);
|
||||
if (symbol && fixedDeclarations.has(getSymbolId(symbol).toString())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
changeTracker.replaceNode(
|
||||
sourceFile,
|
||||
insertionSite.parent.expression,
|
||||
createParen(createAwait(insertionSite.parent.expression)));
|
||||
}
|
||||
else if (contains(callableConstructableErrorCodes, errorCode) && isCallOrNewExpression(insertionSite.parent)) {
|
||||
if (fixedDeclarations && isIdentifier(insertionSite)) {
|
||||
const symbol = checker.getSymbolAtLocation(insertionSite);
|
||||
if (symbol && fixedDeclarations.has(getSymbolId(symbol).toString())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
changeTracker.replaceNode(sourceFile, insertionSite, createParen(createAwait(insertionSite)));
|
||||
}
|
||||
else {
|
||||
if (fixedDeclarations && isVariableDeclaration(insertionSite.parent) && isIdentifier(insertionSite.parent.name)) {
|
||||
const symbol = checker.getSymbolAtLocation(insertionSite.parent.name);
|
||||
if (symbol && !addToSeen(fixedDeclarations, getSymbolId(symbol))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
changeTracker.replaceNode(sourceFile, insertionSite, createAwait(insertionSite));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +626,7 @@ namespace Harness.Parallel.Host {
|
||||
|
||||
const perfData = readSavedPerfData(configOption);
|
||||
context.describe = addSuite as Mocha.SuiteFunction;
|
||||
context.it = addSuite as Mocha.TestFunction;
|
||||
|
||||
function addSuite(title: string) {
|
||||
// Note, sub-suites are not indexed (we assume such granularity is not required)
|
||||
|
||||
@@ -151,24 +151,42 @@ namespace Harness.Parallel.Worker {
|
||||
unitTestSuiteMap.set(suite.title, suite);
|
||||
}
|
||||
}
|
||||
if (!unitTestTestMap && unitTestSuite.tests.length) {
|
||||
unitTestTestMap = ts.createMap<Mocha.Test>();
|
||||
for (const test of unitTestSuite.tests) {
|
||||
unitTestTestMap.set(test.title, test);
|
||||
}
|
||||
}
|
||||
|
||||
if (!unitTestSuiteMap) {
|
||||
if (!unitTestSuiteMap && !unitTestTestMap) {
|
||||
throw new Error(`Asked to run unit test ${task.file}, but no unit tests were discovered!`);
|
||||
}
|
||||
|
||||
const suite = unitTestSuiteMap.get(task.file);
|
||||
if (!suite) {
|
||||
let suite = unitTestSuiteMap.get(task.file);
|
||||
const test = unitTestTestMap.get(task.file);
|
||||
if (!suite && !test) {
|
||||
throw new Error(`Unit test with name "${task.file}" was asked to be run, but such a test does not exist!`);
|
||||
}
|
||||
|
||||
const root = new Suite("", new Mocha.Context());
|
||||
root.timeout(globalTimeout || 40_000);
|
||||
root.addSuite(suite);
|
||||
Object.setPrototypeOf(suite.ctx, root.ctx);
|
||||
if (suite) {
|
||||
root.addSuite(suite);
|
||||
Object.setPrototypeOf(suite.ctx, root.ctx);
|
||||
}
|
||||
else if (test) {
|
||||
const newSuite = new Suite("", new Mocha.Context());
|
||||
newSuite.addTest(test);
|
||||
root.addSuite(newSuite);
|
||||
Object.setPrototypeOf(newSuite.ctx, root.ctx);
|
||||
Object.setPrototypeOf(test.ctx, root.ctx);
|
||||
test.parent = newSuite;
|
||||
suite = newSuite;
|
||||
}
|
||||
|
||||
runSuite(task, suite, payload => {
|
||||
suite.parent = unitTestSuite;
|
||||
Object.setPrototypeOf(suite.ctx, unitTestSuite.ctx);
|
||||
runSuite(task, suite!, payload => {
|
||||
suite!.parent = unitTestSuite;
|
||||
Object.setPrototypeOf(suite!.ctx, unitTestSuite.ctx);
|
||||
fn(payload);
|
||||
});
|
||||
}
|
||||
@@ -284,6 +302,8 @@ namespace Harness.Parallel.Worker {
|
||||
// The root suite for all unit tests.
|
||||
let unitTestSuite: Suite;
|
||||
let unitTestSuiteMap: ts.Map<Mocha.Suite>;
|
||||
// (Unit) Tests directly within the root suite
|
||||
let unitTestTestMap: ts.Map<Mocha.Test>;
|
||||
|
||||
if (runUnitTests) {
|
||||
unitTestSuite = new Suite("", new Mocha.Context());
|
||||
|
||||
@@ -1064,7 +1064,7 @@ namespace ts.projectSystem {
|
||||
content: "let x = 1;"
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, configFile], { useWindowsStylePaths: true });
|
||||
const host = createServerHost([file1, configFile], { windowsStyleRoot: "c:/" });
|
||||
const projectService = createProjectService(host);
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace ts.projectSystem {
|
||||
content: "let y = 10;"
|
||||
};
|
||||
const files = [configFile, file1, file2, libFile];
|
||||
const host = createServerHost(files, { useWindowsStylePaths: true });
|
||||
const host = createServerHost(files, { windowsStyleRoot: "c:/" });
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file1.path);
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
@@ -211,4 +211,39 @@ namespace ts.projectSystem {
|
||||
}
|
||||
});
|
||||
|
||||
describe("unittests:: tsserver:: watchEnvironment:: tsserverProjectSystem watching files with network style paths", () => {
|
||||
function verifyFilePathStyle(path: string) {
|
||||
const windowsStyleRoot = path.substr(0, getRootLength(path));
|
||||
const host = createServerHost(
|
||||
[libFile, { path, content: "const x = 10" }],
|
||||
{ windowsStyleRoot }
|
||||
);
|
||||
const service = createProjectService(host);
|
||||
service.openClientFile(path);
|
||||
checkNumberOfProjects(service, { inferredProjects: 1 });
|
||||
const libPath = `${windowsStyleRoot}${libFile.path.substring(1)}`;
|
||||
checkProjectActualFiles(service.inferredProjects[0], [path, libPath]);
|
||||
checkWatchedFiles(host, [libPath, `${getDirectoryPath(path)}/tsconfig.json`, `${getDirectoryPath(path)}/jsconfig.json`]);
|
||||
}
|
||||
|
||||
it("for file of style c:/myprojects/project/x.js", () => {
|
||||
verifyFilePathStyle("c:/myprojects/project/x.js");
|
||||
});
|
||||
|
||||
it("for file of style //vda1cs4850/myprojects/project/x.js", () => {
|
||||
verifyFilePathStyle("//vda1cs4850/myprojects/project/x.js");
|
||||
});
|
||||
|
||||
it("for file of style //vda1cs4850/c$/myprojects/project/x.js", () => {
|
||||
verifyFilePathStyle("//vda1cs4850/c$/myprojects/project/x.js");
|
||||
});
|
||||
|
||||
it("for file of style c:/users/username/myprojects/project/x.js", () => {
|
||||
verifyFilePathStyle("c:/users/username/myprojects/project/x.js");
|
||||
});
|
||||
|
||||
it("for file of style //vda1cs4850/c$/users/username/myprojects/project/x.js", () => {
|
||||
verifyFilePathStyle("//vda1cs4850/c$/users/username/myprojects/project/x.js");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type F1 = ([a, b, c]) => void;
|
||||
>c : any
|
||||
|
||||
type T2 = ({ a });
|
||||
>T2 : { a: any; }
|
||||
>T2 : T2
|
||||
>a : any
|
||||
|
||||
type F2 = ({ a }) => void;
|
||||
|
||||
@@ -46,7 +46,7 @@ type Result3 = Example3<'x' | 'y'>; // "x" | "y"
|
||||
>Result3 : "x" | "y"
|
||||
|
||||
type Example4<T extends string, U extends string> = (Record<T, any> & Record<U, any>);
|
||||
>Example4 : Record<T, any> & Record<U, any>
|
||||
>Example4 : Example4<T, U>
|
||||
|
||||
type Result4 = keyof Example4<'x', 'y'>; // "x" | "y"
|
||||
>Result4 : "x" | "y"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//// [parenthesisDoesNotBlockAliasSymbolCreation.ts]
|
||||
export type InvalidKeys<K extends string|number|symbol> = { [P in K]? : never };
|
||||
export type InvalidKeys2<K extends string|number|symbol> = (
|
||||
{ [P in K]? : never }
|
||||
);
|
||||
|
||||
export type A<T> = (
|
||||
T & InvalidKeys<"a">
|
||||
);
|
||||
export type A2<T> = (
|
||||
T & InvalidKeys2<"a">
|
||||
);
|
||||
|
||||
export const a = null as A<{ x : number }>;
|
||||
export const a2 = null as A2<{ x : number }>;
|
||||
export const a3 = null as { x : number } & InvalidKeys<"a">;
|
||||
export const a4 = null as { x : number } & InvalidKeys2<"a">;
|
||||
|
||||
|
||||
//// [parenthesisDoesNotBlockAliasSymbolCreation.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.a = null;
|
||||
exports.a2 = null;
|
||||
exports.a3 = null;
|
||||
exports.a4 = null;
|
||||
|
||||
|
||||
//// [parenthesisDoesNotBlockAliasSymbolCreation.d.ts]
|
||||
export declare type InvalidKeys<K extends string | number | symbol> = {
|
||||
[P in K]?: never;
|
||||
};
|
||||
export declare type InvalidKeys2<K extends string | number | symbol> = ({
|
||||
[P in K]?: never;
|
||||
});
|
||||
export declare type A<T> = (T & InvalidKeys<"a">);
|
||||
export declare type A2<T> = (T & InvalidKeys2<"a">);
|
||||
export declare const a: A<{
|
||||
x: number;
|
||||
}>;
|
||||
export declare const a2: A2<{
|
||||
x: number;
|
||||
}>;
|
||||
export declare const a3: {
|
||||
x: number;
|
||||
} & InvalidKeys<"a">;
|
||||
export declare const a4: {
|
||||
x: number;
|
||||
} & InvalidKeys2<"a">;
|
||||
@@ -0,0 +1,56 @@
|
||||
=== tests/cases/compiler/parenthesisDoesNotBlockAliasSymbolCreation.ts ===
|
||||
export type InvalidKeys<K extends string|number|symbol> = { [P in K]? : never };
|
||||
>InvalidKeys : Symbol(InvalidKeys, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 0))
|
||||
>K : Symbol(K, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 24))
|
||||
>P : Symbol(P, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 61))
|
||||
>K : Symbol(K, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 24))
|
||||
|
||||
export type InvalidKeys2<K extends string|number|symbol> = (
|
||||
>InvalidKeys2 : Symbol(InvalidKeys2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 80))
|
||||
>K : Symbol(K, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 1, 25))
|
||||
|
||||
{ [P in K]? : never }
|
||||
>P : Symbol(P, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 2, 7))
|
||||
>K : Symbol(K, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 1, 25))
|
||||
|
||||
);
|
||||
|
||||
export type A<T> = (
|
||||
>A : Symbol(A, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 3, 2))
|
||||
>T : Symbol(T, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 5, 14))
|
||||
|
||||
T & InvalidKeys<"a">
|
||||
>T : Symbol(T, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 5, 14))
|
||||
>InvalidKeys : Symbol(InvalidKeys, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 0))
|
||||
|
||||
);
|
||||
export type A2<T> = (
|
||||
>A2 : Symbol(A2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 7, 2))
|
||||
>T : Symbol(T, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 8, 15))
|
||||
|
||||
T & InvalidKeys2<"a">
|
||||
>T : Symbol(T, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 8, 15))
|
||||
>InvalidKeys2 : Symbol(InvalidKeys2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 80))
|
||||
|
||||
);
|
||||
|
||||
export const a = null as A<{ x : number }>;
|
||||
>a : Symbol(a, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 12, 12))
|
||||
>A : Symbol(A, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 3, 2))
|
||||
>x : Symbol(x, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 12, 28))
|
||||
|
||||
export const a2 = null as A2<{ x : number }>;
|
||||
>a2 : Symbol(a2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 13, 12))
|
||||
>A2 : Symbol(A2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 7, 2))
|
||||
>x : Symbol(x, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 13, 30))
|
||||
|
||||
export const a3 = null as { x : number } & InvalidKeys<"a">;
|
||||
>a3 : Symbol(a3, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 14, 12))
|
||||
>x : Symbol(x, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 14, 27))
|
||||
>InvalidKeys : Symbol(InvalidKeys, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 0))
|
||||
|
||||
export const a4 = null as { x : number } & InvalidKeys2<"a">;
|
||||
>a4 : Symbol(a4, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 15, 12))
|
||||
>x : Symbol(x, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 15, 27))
|
||||
>InvalidKeys2 : Symbol(InvalidKeys2, Decl(parenthesisDoesNotBlockAliasSymbolCreation.ts, 0, 80))
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
=== tests/cases/compiler/parenthesisDoesNotBlockAliasSymbolCreation.ts ===
|
||||
export type InvalidKeys<K extends string|number|symbol> = { [P in K]? : never };
|
||||
>InvalidKeys : InvalidKeys<K>
|
||||
|
||||
export type InvalidKeys2<K extends string|number|symbol> = (
|
||||
>InvalidKeys2 : InvalidKeys2<K>
|
||||
|
||||
{ [P in K]? : never }
|
||||
);
|
||||
|
||||
export type A<T> = (
|
||||
>A : A<T>
|
||||
|
||||
T & InvalidKeys<"a">
|
||||
);
|
||||
export type A2<T> = (
|
||||
>A2 : A2<T>
|
||||
|
||||
T & InvalidKeys2<"a">
|
||||
);
|
||||
|
||||
export const a = null as A<{ x : number }>;
|
||||
>a : A<{ x: number; }>
|
||||
>null as A<{ x : number }> : A<{ x: number; }>
|
||||
>null : null
|
||||
>x : number
|
||||
|
||||
export const a2 = null as A2<{ x : number }>;
|
||||
>a2 : A2<{ x: number; }>
|
||||
>null as A2<{ x : number }> : A2<{ x: number; }>
|
||||
>null : null
|
||||
>x : number
|
||||
|
||||
export const a3 = null as { x : number } & InvalidKeys<"a">;
|
||||
>a3 : { x: number; } & InvalidKeys<"a">
|
||||
>null as { x : number } & InvalidKeys<"a"> : { x: number; } & InvalidKeys<"a">
|
||||
>null : null
|
||||
>x : number
|
||||
|
||||
export const a4 = null as { x : number } & InvalidKeys2<"a">;
|
||||
>a4 : { x: number; } & InvalidKeys2<"a">
|
||||
>null as { x : number } & InvalidKeys2<"a"> : { x: number; } & InvalidKeys2<"a">
|
||||
>null : null
|
||||
>x : number
|
||||
|
||||
+6
-6
@@ -14,8 +14,8 @@ exports.__esModule = true;
|
||||
"program": {
|
||||
"fileInfos": {
|
||||
"../../../.ts/lib.es5.d.ts": {
|
||||
"version": "146944634190",
|
||||
"signature": "146944634190"
|
||||
"version": "406734842058",
|
||||
"signature": "406734842058"
|
||||
},
|
||||
"../../../.ts/lib.es2015.d.ts": {
|
||||
"version": "57263133672",
|
||||
@@ -114,8 +114,8 @@ exports.__esModule = true;
|
||||
"program": {
|
||||
"fileInfos": {
|
||||
"../../../.ts/lib.es5.d.ts": {
|
||||
"version": "146944634190",
|
||||
"signature": "146944634190"
|
||||
"version": "406734842058",
|
||||
"signature": "406734842058"
|
||||
},
|
||||
"../../../.ts/lib.es2015.d.ts": {
|
||||
"version": "57263133672",
|
||||
@@ -237,8 +237,8 @@ exports.getVar = getVar;
|
||||
"program": {
|
||||
"fileInfos": {
|
||||
"../../../.ts/lib.es5.d.ts": {
|
||||
"version": "146944634190",
|
||||
"signature": "146944634190"
|
||||
"version": "406734842058",
|
||||
"signature": "406734842058"
|
||||
},
|
||||
"../../../.ts/lib.es2015.d.ts": {
|
||||
"version": "57263133672",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// @declaration: true
|
||||
|
||||
export type InvalidKeys<K extends string|number|symbol> = { [P in K]? : never };
|
||||
export type InvalidKeys2<K extends string|number|symbol> = (
|
||||
{ [P in K]? : never }
|
||||
);
|
||||
|
||||
export type A<T> = (
|
||||
T & InvalidKeys<"a">
|
||||
);
|
||||
export type A2<T> = (
|
||||
T & InvalidKeys2<"a">
|
||||
);
|
||||
|
||||
export const a = null as A<{ x : number }>;
|
||||
export const a2 = null as A2<{ x : number }>;
|
||||
export const a3 = null as { x : number } & InvalidKeys<"a">;
|
||||
export const a4 = null as { x : number } & InvalidKeys2<"a">;
|
||||
@@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
////async function fn(a: Promise<string>) {
|
||||
//// const x = a;
|
||||
//// x.toLowerCase();
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: "Add 'await' to initializer for 'x'",
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`async function fn(a: Promise<string>) {
|
||||
const x = await a;
|
||||
x.toLowerCase();
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
////async function fn(a: number, b: Promise<number>) {
|
||||
//// const x = b;
|
||||
//// const y = b;
|
||||
//// fn(x, b);
|
||||
//// fn(y, b);
|
||||
//// x.toFixed();
|
||||
//// y.then;
|
||||
////
|
||||
//// b + b;
|
||||
//// x + b;
|
||||
//// x + x.toFixed();
|
||||
////}
|
||||
|
||||
verify.codeFixAll({
|
||||
fixAllDescription: ts.Diagnostics.Fix_all_expressions_possibly_missing_await.message,
|
||||
fixId: "addMissingAwait",
|
||||
newFileContent:
|
||||
`async function fn(a: number, b: Promise<number>) {
|
||||
const x = await b;
|
||||
const y = b;
|
||||
fn(x, b);
|
||||
fn(await y, b);
|
||||
x.toFixed();
|
||||
y.then;
|
||||
|
||||
await b + await b;
|
||||
x + await b;
|
||||
x + x.toFixed();
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
////async function fn(a: string, b: Promise<string>) {
|
||||
//// const x = b;
|
||||
//// const y = b;
|
||||
//// x + y;
|
||||
////}
|
||||
|
||||
verify.codeFix({
|
||||
description: "Add 'await' to initializers",
|
||||
index: 0,
|
||||
newFileContent:
|
||||
`async function fn(a: string, b: Promise<string>) {
|
||||
const x = await b;
|
||||
const y = await b;
|
||||
x + y;
|
||||
}`
|
||||
});
|
||||
|
||||
verify.codeFixAll({
|
||||
fixAllDescription: ts.Diagnostics.Fix_all_expressions_possibly_missing_await.message,
|
||||
fixId: "addMissingAwait",
|
||||
newFileContent:
|
||||
`async function fn(a: string, b: Promise<string>) {
|
||||
const x = await b;
|
||||
const y = await b;
|
||||
x + y;
|
||||
}`
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
// @allowJs: true
|
||||
// @Filename: dummy.js
|
||||
|
||||
//// /**
|
||||
//// * @typedef Product
|
||||
//// * @property {string} title
|
||||
//// * @property {boolean} h/*1*/igh-top some-comments
|
||||
//// */
|
||||
////
|
||||
//// /**
|
||||
//// * @type {Pro/*2*/duct}
|
||||
//// */
|
||||
//// const product = {
|
||||
//// /*3*/
|
||||
//// }
|
||||
verify.quickInfoAt('1', '(property) high-top: boolean', 'some-comments');
|
||||
|
||||
verify.quickInfoAt('2', 'type Product = {\n title: string;\n high-top: boolean;\n}');
|
||||
|
||||
verify.completions({
|
||||
marker: ['3'],
|
||||
includes: ['"high-top"']
|
||||
});
|
||||
Submodule tests/cases/user/prettier/prettier updated: 2314640485...1e471a0079
Reference in New Issue
Block a user