diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d2dda22ef1fe2..a1acfc425346c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -120,6 +120,7 @@ namespace ts { return node ? getTypeFromTypeNode(node) : errorType; }, getParameterType: getTypeAtPosition, + getPromisedTypeOfPromise, getReturnTypeOfSignature, getNullableType, getNonNullableType, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5d4d9ae701d38..16b064f255cc4 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4183,7 +4183,10 @@ "category": "Suggestion", "code": 80005 }, - + "This may be converted to an async function.": { + "category": "Suggestion", + "code": 80006 + }, "Add missing 'super()' call": { "category": "Message", "code": 90001 @@ -4556,6 +4559,7 @@ "category": "Message", "code": 95062 }, + "Add missing enum member '{0}'": { "category": "Message", "code": 95063 @@ -4563,5 +4567,13 @@ "Add all missing imports": { "category": "Message", "code": 95064 + }, + "Convert to async function":{ + "category": "Message", + "code": 95065 + }, + "Convert all to async functions": { + "category": "Message", + "code": 95066 } -} +} \ No newline at end of file diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e553bf2e6847b..84fb08f1472a9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2911,6 +2911,8 @@ namespace ts { getBaseTypes(type: InterfaceType): BaseType[]; getBaseTypeOfLiteralType(type: Type): Type; getWidenedType(type: Type): Type; + /* @internal */ + getPromisedTypeOfPromise(promise: Type, errorNode?: Node): Type | undefined; getReturnTypeOfSignature(signature: Signature): Type; /** * Gets the type of a parameter at a given position in a signature. diff --git a/src/services/codefixes/convertToAsyncFunction.ts b/src/services/codefixes/convertToAsyncFunction.ts new file mode 100644 index 0000000000000..195586c6b6eba --- /dev/null +++ b/src/services/codefixes/convertToAsyncFunction.ts @@ -0,0 +1,538 @@ +/* @internal */ +namespace ts.codefix { + const fixId = "convertToAsyncFunction"; + const errorCodes = [Diagnostics.This_may_be_converted_to_an_async_function.code]; + registerCodeFix({ + errorCodes, + getCodeActions(context: CodeFixContext) { + const changes = textChanges.ChangeTracker.with(context, (t) => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context)); + return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)]; + }, + fixIds: [fixId], + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)), + }); + + + /* + custom type to encapsulate information for variable declarations synthesized in the refactor + numberOfUsesOriginal - number of times the variable should be assigned in the refactor + numberOfUsesSynthesized - count of how many times the variable has been assigned so far + At the end of the refactor, numberOfUsesOriginal should === numberOfUsesSynthesized + */ + interface SynthIdentifier { + identifier: Identifier; + types: Type[]; + numberOfAssignmentsOriginal: number; + } + + interface SymbolAndIdentifier { + identifier: Identifier; + symbol: Symbol; + } + + interface Transformer { + checker: TypeChecker; + synthNamesMap: Map; // keys are the symbol id of the identifier + allVarNames: SymbolAndIdentifier[]; + setOfExpressionsToReturn: Map; // keys are the node ids of the expressions + constIdentifiers: Identifier[]; + originalTypeMap: Map; // keys are the node id of the identifier + isInJSFile: boolean; + } + + function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, context: CodeFixContextBase): void { + // get the function declaration - returns a promise + const functionToConvert: FunctionLikeDeclaration = getContainingFunction(getTokenAtPosition(sourceFile, position)) as FunctionLikeDeclaration; + if (!functionToConvert) { + return; + } + + const synthNamesMap: Map = createMap(); + const originalTypeMap: Map = createMap(); + const allVarNames: SymbolAndIdentifier[] = []; + const isInJSFile = isInJavaScriptFile(functionToConvert); + const setOfExpressionsToReturn = getAllPromiseExpressionsToReturn(functionToConvert, checker); + const functionToConvertRenamed: FunctionLikeDeclaration = renameCollidingVarNames(functionToConvert, checker, synthNamesMap, context, setOfExpressionsToReturn, originalTypeMap, allVarNames); + const constIdentifiers = getConstIdentifiers(synthNamesMap); + const returnStatements = getReturnStatementsWithPromiseHandlers(functionToConvertRenamed); + const transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile }; + + if (!returnStatements.length) { + return; + } + + // add the async keyword + changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, functionToConvert); + + function startTransformation(node: CallExpression, nodeToReplace: Node) { + const newNodes = transformExpression(node, transformer, node); + changes.replaceNodeWithNodes(sourceFile, nodeToReplace, newNodes); + } + + for (const statement of returnStatements) { + if (isCallExpression(statement)) { + startTransformation(statement, statement); + } + else { + forEachChild(statement, function visit(node: Node) { + if (isCallExpression(node)) { + startTransformation(node, statement); + } + else if (!isFunctionLike(node)) { + forEachChild(node, visit); + } + }); + } + } + } + + // Returns the identifiers that are never reassigned in the refactor + function getConstIdentifiers(synthNamesMap: Map): Identifier[] { + const constIdentifiers: Identifier[] = []; + synthNamesMap.forEach((val) => { + if (val.numberOfAssignmentsOriginal === 0) { + constIdentifiers.push(val.identifier); + } + }); + return constIdentifiers; + } + + + /* + Finds all of the expressions of promise type that should not be saved in a variable during the refactor + */ + function getAllPromiseExpressionsToReturn(func: FunctionLikeDeclaration, checker: TypeChecker): Map { + if (!func.body) { + return createMap(); + } + + const setOfExpressionsToReturn: Map = createMap(); + + forEachChild(func.body, function visit(node: Node) { + if (isPromiseReturningExpression(node, checker, "then")) { + setOfExpressionsToReturn.set(getNodeId(node).toString(), true); + forEach((node).arguments, visit); + } + else if (isPromiseReturningExpression(node, checker, "catch")) { + setOfExpressionsToReturn.set(getNodeId(node).toString(), true); + // if .catch() is the last call in the chain, move leftward in the chain until we hit something else that should be returned + forEachChild(node, visit); + } + else if (isPromiseReturningExpression(node, checker)) { + setOfExpressionsToReturn.set(getNodeId(node).toString(), true); + // don't recurse here, since we won't refactor any children or arguments of the expression + } + else { + forEachChild(node, visit); + } + }); + + return setOfExpressionsToReturn; + } + + + /* + Returns true if node is a promise returning expression + If name is not undefined, node is a promise returning call of name + */ + function isPromiseReturningExpression(node: Node, checker: TypeChecker, name?: string): boolean { + const isNodeExpression = name ? isCallExpression(node) : isExpression(node); + const isExpressionOfName = isNodeExpression && (!name || hasPropertyAccessExpressionWithName(node as CallExpression, name)); + const nodeType = isExpressionOfName && checker.getTypeAtLocation(node); + return !!(nodeType && checker.getPromisedTypeOfPromise(nodeType)); + } + + function declaredInFile(symbol: Symbol, sourceFile: SourceFile): boolean { + return symbol.valueDeclaration && symbol.valueDeclaration.getSourceFile() === sourceFile; + } + + /* + Renaming of identifiers may be neccesary as the refactor changes scopes - + This function collects all existing identifier names and names of identifiers that will be created in the refactor. + It then checks for any collisions and renames them through getSynthesizedDeepClone + */ + function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map, context: CodeFixContextBase, setOfAllExpressionsToReturn: Map, originalType: Map, allVarNames: SymbolAndIdentifier[]): FunctionLikeDeclaration { + + const identsToRenameMap: Map = createMap(); // key is the symbol id + forEachChild(nodeToRename, function visit(node: Node) { + if (!isIdentifier(node)) { + forEachChild(node, visit); + return; + } + + const symbol = checker.getSymbolAtLocation(node); + const isDefinedInFile = symbol && declaredInFile(symbol, context.sourceFile); + + if (symbol && isDefinedInFile) { + const type = checker.getTypeAtLocation(node); + const lastCallSignature = getLastCallSignature(type, checker); + const symbolIdString = getSymbolId(symbol).toString(); + + // if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg)) + // Note - the choice of the last call signature is arbitrary + if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) { + const synthName = getNewNameIfConflict(createIdentifier(lastCallSignature.parameters[0].name), allVarNames); + synthNamesMap.set(symbolIdString, synthName); + allVarNames.push({ identifier: synthName.identifier, symbol }); + } + // we only care about identifiers that are parameters and declarations (don't care about other uses) + else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent))) { + + // if the identifier name conflicts with a different identifier that we've already seen + if (allVarNames.some(ident => ident.identifier.text === node.text && ident.symbol !== symbol)) { + const newName = getNewNameIfConflict(node, allVarNames); + identsToRenameMap.set(symbolIdString, newName.identifier); + synthNamesMap.set(symbolIdString, newName); + allVarNames.push({ identifier: newName.identifier, symbol }); + } + else { + const identifier = getSynthesizedDeepClone(node); + identsToRenameMap.set(symbolIdString, identifier); + synthNamesMap.set(symbolIdString, { identifier, types: [], numberOfAssignmentsOriginal: allVarNames.filter(elem => elem.identifier.text === node.text).length/*, numberOfAssignmentsSynthesized: 0*/ }); + if ((isParameter(node.parent) && isExpressionOrCallOnTypePromise(node.parent.parent)) || isVariableDeclaration(node.parent)) { + allVarNames.push({ identifier, symbol }); + } + } + } + } + }); + + return getSynthesizedDeepCloneWithRenames(nodeToRename, /*includeTrivia*/ true, identsToRenameMap, checker, deepCloneCallback); + + function isExpressionOrCallOnTypePromise(child: Node): boolean { + const node = child.parent; + if (isCallExpression(node) || isIdentifier(node) && !setOfAllExpressionsToReturn.get(getNodeId(node).toString())) { + const nodeType = checker.getTypeAtLocation(node); + const isPromise = nodeType && checker.getPromisedTypeOfPromise(nodeType); + return !!isPromise; + } + + return false; + } + + function deepCloneCallback(node: Node, clone: Node) { + if (isIdentifier(node)) { + const symbol = checker.getSymbolAtLocation(node); + const symboldIdString = symbol && getSymbolId(symbol).toString(); + const renameInfo = symbol && synthNamesMap.get(symboldIdString!); + + if (renameInfo) { + const type = checker.getTypeAtLocation(node); + if (type) { + originalType.set(getNodeId(clone).toString(), type); + } + } + } + + const val = setOfAllExpressionsToReturn.get(getNodeId(node).toString()); + if (val !== undefined) { + setOfAllExpressionsToReturn.delete(getNodeId(node).toString()); + setOfAllExpressionsToReturn.set(getNodeId(clone).toString(), val); + } + } + + } + + function getNewNameIfConflict(name: Identifier, allVarNames: SymbolAndIdentifier[]): SynthIdentifier { + const numVarsSameName = allVarNames.filter(elem => elem.identifier.text === name.text).length; + const numberOfAssignmentsOriginal = 0; + const identifier = numVarsSameName === 0 ? name : createIdentifier(name.text + "_" + numVarsSameName); + return { identifier, types: [], numberOfAssignmentsOriginal }; + } + + // dispatch function to recursively build the refactoring + function transformExpression(node: Expression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] { + if (!node) { + return []; + } + + const originalType = isIdentifier(node) && transformer.originalTypeMap.get(getNodeId(node).toString()); + const nodeType = originalType || transformer.checker.getTypeAtLocation(node); + + if (isCallExpression(node) && hasPropertyAccessExpressionWithName(node, "then") && nodeType && !!transformer.checker.getPromisedTypeOfPromise(nodeType)) { + return transformThen(node, transformer, outermostParent, prevArgName); + } + else if (isCallExpression(node) && hasPropertyAccessExpressionWithName(node, "catch") && nodeType && !!transformer.checker.getPromisedTypeOfPromise(nodeType)) { + return transformCatch(node, transformer, prevArgName); + } + else if (isPropertyAccessExpression(node)) { + return transformExpression(node.expression, transformer, outermostParent, prevArgName); + } + else if (nodeType && transformer.checker.getPromisedTypeOfPromise(nodeType)) { + return transformPromiseCall(node, transformer, prevArgName); + } + + return []; + } + + function transformCatch(node: CallExpression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] { + const func = node.arguments[0]; + const argName = getArgName(func, transformer); + const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString()); + + /* + If there is another call in the chain after the .catch() we are transforming, we will need to save the result of both paths (try block and catch block) + To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap + We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step + */ + if (prevArgName && !shouldReturn) { + prevArgName.numberOfAssignmentsOriginal = 2; // Try block and catch block + transformer.synthNamesMap.forEach((val, key) => { + if (val.identifier.text === prevArgName.identifier.text) { + transformer.synthNamesMap.set(key, getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames)); + } + }); + + // update the constIdentifiers list + if (transformer.constIdentifiers.some(elem => elem.text === prevArgName.identifier.text)) { + transformer.constIdentifiers.push(getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames).identifier); + } + } + + const tryBlock = createBlock(transformExpression(node.expression, transformer, node, prevArgName)); + + const transformationBody = getTransformationBody(func, prevArgName, argName, node, transformer); + const catchArg = argName.identifier.text.length > 0 ? argName.identifier.text : "e"; + const catchClause = createCatchClause(catchArg, createBlock(transformationBody)); + + /* + In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block) + */ + let varDeclList; + if (prevArgName && !shouldReturn) { + const typeArray: Type[] = prevArgName.types; + const unionType = transformer.checker.getUnionType(typeArray, UnionReduction.Subtype); + const unionTypeNode = transformer.isInJSFile ? undefined : transformer.checker.typeToTypeNode(unionType); + const varDecl = [createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), unionTypeNode)]; + varDeclList = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList(varDecl, NodeFlags.Let)); + } + + const tryStatement = createTry(tryBlock, catchClause, /*finallyBlock*/ undefined); + return varDeclList ? [varDeclList, tryStatement] : [tryStatement]; + } + + function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] { + const [res, rej] = node.arguments; + + if (!res) { + return transformExpression(node.expression, transformer, outermostParent); + } + + const argNameRes = getArgName(res, transformer); + const transformationBody = getTransformationBody(res, prevArgName, argNameRes, node, transformer); + + if (rej) { + const argNameRej = getArgName(rej, transformer); + + const tryBlock = createBlock(transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody)); + + const transformationBody2 = getTransformationBody(rej, prevArgName, argNameRej, node, transformer); + + const catchArg = argNameRej.identifier.text.length > 0 ? argNameRej.identifier.text : "e"; + const catchClause = createCatchClause(catchArg, createBlock(transformationBody2)); + + return [createTry(tryBlock, catchClause, /* finallyBlock */ undefined) as Statement]; + } + else { + return transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody); + } + + return []; + } + + function getFlagOfIdentifier(node: Identifier, constIdentifiers: Identifier[]): NodeFlags { + const inArr: boolean = constIdentifiers.some(elem => elem.text === node.text); + return inArr ? NodeFlags.Const : NodeFlags.Let; + } + + function transformPromiseCall(node: Expression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] { + const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString()); + // the identifier is empty when the handler (.then()) ignores the argument - In this situation we do not need to save the result of the promise returning call + const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0; + const originalNodeParent = node.original ? node.original.parent : node.parent; + if (hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { + return createVariableDeclarationOrAssignment(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match + } + else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) { + return [createStatement(createAwait(node))]; + } + + return [createReturn(getSynthesizedDeepClone(node))]; + } + + function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier, rightHandSide: Expression, transformer: Transformer): NodeArray { + + if (prevArgName.types.length < prevArgName.numberOfAssignmentsOriginal) { + return createNodeArray([createStatement(createAssignment(getSynthesizedDeepClone(prevArgName.identifier), rightHandSide))]); + } + + return createNodeArray([createVariableStatement(/*modifiers*/ undefined, + (createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), /*type*/ undefined, rightHandSide)], getFlagOfIdentifier(prevArgName.identifier, transformer.constIdentifiers))))]); + } + + function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray { + + const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0; + const hasArgName = argName && argName.identifier.text.length > 0; + const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString()); + switch (func.kind) { + case SyntaxKind.Identifier: + if (!hasArgName) break; + + const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]); + if (shouldReturn) { + return createNodeArray([createReturn(synthCall)]); + } + + if (!hasPrevArgName) break; + + const type = transformer.originalTypeMap.get(getNodeId(func).toString()); + const callSignatures = type && transformer.checker.getSignaturesOfType(type, SignatureKind.Call); + const returnType = callSignatures && callSignatures[0].getReturnType(); + const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, createAwait(synthCall), transformer); + prevArgName!.types.push(returnType!); + return varDeclOrAssignment; + + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + // Arrow functions with block bodies { } will enter this control flow + if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) { + let refactoredStmts: Statement[] = []; + + for (const statement of func.body.statements) { + if (getReturnStatementsWithPromiseHandlers(statement).length) { + refactoredStmts = refactoredStmts.concat(getInnerTransformationBody(transformer, [statement], prevArgName)); + } + else { + refactoredStmts.push(statement); + } + } + + return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) : + removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers); + } + else { + const funcBody = (func).body; + const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody as Expression)); + const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName); + + if (innerCbBody.length > 0) { + return createNodeArray(innerCbBody); + } + + if (hasPrevArgName && !shouldReturn) { + const type = transformer.checker.getTypeAtLocation(func); + const returnType = getLastCallSignature(type, transformer.checker).getReturnType(); + const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, getSynthesizedDeepClone(funcBody) as Expression, transformer); + prevArgName!.types.push(returnType); + return varDeclOrAssignment; + } + else { + return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]); + } + } + break; + } + return createNodeArray([]); + } + + function getLastCallSignature(type: Type, checker: TypeChecker): Signature { + const callSignatures = type && checker.getSignaturesOfType(type, SignatureKind.Call); + return callSignatures && callSignatures[callSignatures.length - 1]; + } + + + function removeReturns(stmts: NodeArray, prevArgName: Identifier, constIdentifiers: Identifier[]): NodeArray { + const ret: Statement[] = []; + for (const stmt of stmts) { + if (isReturnStatement(stmt)) { + if (stmt.expression) { + ret.push(createVariableStatement(/*modifiers*/ undefined, + (createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, stmt.expression)], getFlagOfIdentifier(prevArgName, constIdentifiers))))); + } + } + else { + ret.push(getSynthesizedDeepClone(stmt)); + } + } + + return createNodeArray(ret); + } + + + function getInnerTransformationBody(transformer: Transformer, innerRetStmts: Node[], prevArgName?: SynthIdentifier) { + + let innerCbBody: Statement[] = []; + for (const stmt of innerRetStmts) { + forEachChild(stmt, function visit(node: Node) { + if (isCallExpression(node)) { + const temp = transformExpression(node, transformer, node, prevArgName); + innerCbBody = innerCbBody.concat(temp); + if (innerCbBody.length > 0) { + return; + } + } + else if (!isFunctionLike(node)) { + forEachChild(node, visit); + } + }); + } + return innerCbBody; + } + + function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean { + if (!isPropertyAccessExpression(node.expression)) { + return false; + } + + return node.expression.name.text === funcName; + } + + function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier { + + const numberOfAssignmentsOriginal = 0; + const types: Type[] = []; + + let name: SynthIdentifier | undefined; + + if (isFunctionLikeDeclaration(funcNode)) { + if (funcNode.parameters.length > 0) { + const param = funcNode.parameters[0].name as Identifier; + name = getMapEntryIfExists(param); + } + } + else if (isCallExpression(funcNode) && funcNode.arguments.length > 0 && isIdentifier(funcNode.arguments[0])) { + name = { identifier: funcNode.arguments[0] as Identifier, types, numberOfAssignmentsOriginal }; + } + else if (isIdentifier(funcNode)) { + name = getMapEntryIfExists(funcNode); + } + + if (!name || name.identifier === undefined || name.identifier.text === "_" || name.identifier.text === "undefined") { + return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal }; + } + + return name; + + function getMapEntryIfExists(identifier: Identifier): SynthIdentifier { + const originalNode = getOriginalNode(identifier); + const symbol = getSymbol(originalNode); + + if (!symbol) { + return { identifier, types, numberOfAssignmentsOriginal }; + } + + const mapEntry = transformer.synthNamesMap.get(getSymbolId(symbol).toString()); + return mapEntry || { identifier, types, numberOfAssignmentsOriginal }; + } + + function getSymbol(node: Node): Symbol | undefined { + return node.symbol ? node.symbol : transformer.checker.getSymbolAtLocation(node); + } + + function getOriginalNode(node: Node): Node { + return node.original ? node.original : node; + } + } +} \ No newline at end of file diff --git a/src/services/suggestionDiagnostics.ts b/src/services/suggestionDiagnostics.ts index 1f4ced611918d..51a1701c351dd 100644 --- a/src/services/suggestionDiagnostics.ts +++ b/src/services/suggestionDiagnostics.ts @@ -3,6 +3,7 @@ namespace ts { export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] { program.getSemanticDiagnostics(sourceFile, cancellationToken); const diags: DiagnosticWithLocation[] = []; + const checker = program.getDiagnosticsProducingTypeChecker(); if (sourceFile.commonJsModuleIndicator && (programContainsEs6Modules(program) || compilerOptionsIndicateEs6Modules(program.getCompilerOptions())) && @@ -68,6 +69,9 @@ namespace ts { } } + if (isFunctionLikeDeclaration(node)) { + addConvertToAsyncFunctionDiagnostics(node, checker, diags); + } node.forEachChild(check); } } @@ -109,7 +113,64 @@ namespace ts { } } + function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: DiagnosticWithLocation[]): void { + + const functionType = node.type ? checker.getTypeFromTypeNode(node.type) : undefined; + if (isAsyncFunction(node) || !node.body || !functionType) { + return; + } + + const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call); + const returnType = callSignatures.length ? checker.getReturnTypeOfSignature(callSignatures[0]) : undefined; + + if (!returnType || !checker.getPromisedTypeOfPromise(returnType)) { + return; + } + + // collect all the return statements + // check that a property access expression exists in there and that it is a handler + const returnStatements = getReturnStatementsWithPromiseHandlers(node); + if (returnStatements.length > 0) { + diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_may_be_converted_to_an_async_function)); + } + } + function getErrorNodeFromCommonJsIndicator(commonJsModuleIndicator: Node): Node { return isBinaryExpression(commonJsModuleIndicator) ? commonJsModuleIndicator.left : commonJsModuleIndicator; } + + /** @internal */ + export function getReturnStatementsWithPromiseHandlers(node: Node): Node[] { + const returnStatements: Node[] = []; + if (isFunctionLike(node)) { + forEachChild(node, visit); + } + else { + visit(node); + } + + function visit(child: Node) { + if (isFunctionLike(child)) { + return; + } + + if (isReturnStatement(child)) { + forEachChild(child, addHandlers); + } + + function addHandlers(returnChild: Node) { + if (isPromiseHandler(returnChild)) { + returnStatements.push(child as ReturnStatement); + } + } + + forEachChild(child, visit); + } + return returnStatements; + } + + function isPromiseHandler(node: Node): boolean { + return (isCallExpression(node) && isPropertyAccessExpression(node.expression) && + (node.expression.name.text === "then" || node.expression.name.text === "catch")); + } } diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 355a4d302c0e8..fee6da0f8a317 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -46,6 +46,7 @@ "codefixes/addMissingInvocationForDecorator.ts", "codefixes/annotateWithTypeFromJSDoc.ts", "codefixes/convertFunctionToEs6Class.ts", + "codefixes/convertToAsyncFunction.ts", "codefixes/convertToEs6Module.ts", "codefixes/correctQualifiedNameToIndexedAccessType.ts", "codefixes/fixClassIncorrectlyImplementsInterface.ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index a3d4d987cb425..e51b5489e5142 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -226,7 +226,7 @@ namespace ts { export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } { return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node; - } + } export function isLabelOfLabeledStatement(node: Node): node is Identifier { return node.kind === SyntaxKind.Identifier && isLabeledStatement(node.parent) && node.parent.label === node; @@ -396,7 +396,7 @@ namespace ts { export function isThis(node: Node): boolean { switch (node.kind) { case SyntaxKind.ThisKeyword: - // case SyntaxKind.ThisType: TODO: GH#9267 + // case SyntaxKind.ThisType: TODO: GH#9267 return true; case SyntaxKind.Identifier: // 'this' as a parameter @@ -1656,8 +1656,34 @@ namespace ts { return clone; } - function getSynthesizedDeepCloneWorker(node: T): T { - const visited = visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext); + export function getSynthesizedDeepCloneWithRenames(node: T, includeTrivia = true, renameMap?: Map, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T { + + let clone; + if (node && isIdentifier(node!) && renameMap && checker) { + const symbol = checker.getSymbolAtLocation(node!); + const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol))); + + if (renameInfo) { + clone = createIdentifier(renameInfo.text); + } + } + + if (!clone) { + clone = node && getSynthesizedDeepCloneWorker(node as NonNullable, renameMap, checker, callback); + } + + if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone); + if (callback && node) callback(node!, clone); + + return clone as T; + } + + + function getSynthesizedDeepCloneWorker(node: T, renameMap?: Map, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T { + const visited = (renameMap || checker || callback) ? + visitEachChild(node, wrapper, nullTransformationContext) : + visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext); + if (visited === node) { // This only happens for leaf nodes - internal nodes always see their children change. const clone = getSynthesizedClone(node); @@ -1675,6 +1701,10 @@ namespace ts { // would have made. visited.parent = undefined!; return visited; + + function wrapper(node: T) { + return getSynthesizedDeepCloneWithRenames(node, /*includeTrivia*/ true, renameMap, checker, callback); + } } export function getSynthesizedDeepClones(nodes: NodeArray, includeTrivia?: boolean): NodeArray; diff --git a/src/testRunner/tsconfig.json b/src/testRunner/tsconfig.json index b02f1a6c17532..12c671f9cf09b 100644 --- a/src/testRunner/tsconfig.json +++ b/src/testRunner/tsconfig.json @@ -48,6 +48,7 @@ "unittests/compileOnSave.ts", "unittests/configurationExtension.ts", "unittests/convertCompilerOptionsFromJson.ts", + "unittests/convertToAsyncFunction.ts", "unittests/convertToBase64.ts", "unittests/convertTypeAcquisitionFromJson.ts", "unittests/customTransforms.ts", diff --git a/src/testRunner/unittests/convertToAsyncFunction.ts b/src/testRunner/unittests/convertToAsyncFunction.ts new file mode 100644 index 0000000000000..342a6cba0ff35 --- /dev/null +++ b/src/testRunner/unittests/convertToAsyncFunction.ts @@ -0,0 +1,1225 @@ +namespace ts { + interface Range { + pos: number; + end: number; + name: string; + } + + interface Test { + source: string; + ranges: Map; + } + + function getTest(source: string): Test { + const activeRanges: Range[] = []; + let text = ""; + let lastPos = 0; + let pos = 0; + const ranges = createMap(); + + while (pos < source.length) { + if (source.charCodeAt(pos) === CharacterCodes.openBracket && + (source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) { + const saved = pos; + pos += 2; + const s = pos; + consumeIdentifier(); + const e = pos; + if (source.charCodeAt(pos) === CharacterCodes.bar) { + pos++; + text += source.substring(lastPos, saved); + const name = s === e + ? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted" + : source.substring(s, e); + activeRanges.push({ name, pos: text.length, end: undefined! }); + lastPos = pos; + continue; + } + else { + pos = saved; + } + } + else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) { + text += source.substring(lastPos, pos); + activeRanges[activeRanges.length - 1].end = text.length; + const range = activeRanges.pop()!; + if (range.name in ranges) { + throw new Error(`Duplicate name of range ${range.name}`); + } + ranges.set(range.name, range); + pos += 2; + lastPos = pos; + continue; + } + pos++; + } + text += source.substring(lastPos, pos); + + function consumeIdentifier() { + while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) { + pos++; + } + } + return { source: text, ranges }; + } + + const libFile: TestFSWithWatch.File = { + path: "/a/lib/lib.d.ts", + content: `/// +interface Boolean {} +interface Function {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +declare function fetch(input?, init?): Promise; +interface Response extends Body { + readonly headers: Headers; + readonly ok: boolean; + readonly redirected: boolean; + readonly status: number; + readonly statusText: string; + readonly trailer: Promise; + readonly type: ResponseType; + readonly url: string; + clone(): Response; +} +interface Body { + readonly body: ReadableStream | null; + readonly bodyUsed: boolean; + arrayBuffer(): Promise; + blob(): Promise; + formData(): Promise; + json(): Promise; + text(): Promise; +} +declare type PromiseConstructorLike = new (executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void) => PromiseLike; +interface PromiseLike { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): PromiseLike; +} +interface Promise { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): Promise; + + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): Promise; +} +interface PromiseConstructor { + /** + * A reference to the prototype. + */ + readonly prototype: Promise; + + /** + * Creates a new Promise. + * @param executor A callback used to initialize the promise. This callback is passed two arguments: + * a resolve callback used resolve the promise with a value or the result of another promise, + * and a reject callback used to reject the promise with a provided reason or error. + */ + new (executor: (resolve: (value?: T | PromiseLike) => void, reject: (reason?: any) => void) => void): Promise; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike, T10 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6, T7]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike, T6 | PromiseLike]): Promise<[T1, T2, T3, T4, T5, T6]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike , T5 | PromiseLike]): Promise<[T1, T2, T3, T4, T5]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike ]): Promise<[T1, T2, T3, T4]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike]): Promise<[T1, T2, T3]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: [T1 | PromiseLike, T2 | PromiseLike]): Promise<[T1, T2]>; + + /** + * Creates a Promise that is resolved with an array of results when all of the provided Promises + * resolve, or rejected when any Promise is rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + all(values: (T | PromiseLike)[]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike, T10 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike, T9 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike, T8 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike, T7 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike, T6 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike, T5 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike, T4 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike, T3 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: [T1 | PromiseLike, T2 | PromiseLike]): Promise; + + /** + * Creates a Promise that is resolved or rejected when any of the provided Promises are resolved + * or rejected. + * @param values An array of Promises. + * @returns A new Promise. + */ + race(values: (T | PromiseLike)[]): Promise; + + /** + * Creates a new rejected promise for the provided reason. + * @param reason The reason the promise was rejected. + * @returns A new rejected Promise. + */ + reject(reason?: any): Promise; + + /** + * Creates a new resolved promise for the provided value. + * @param value A promise. + * @returns A promise whose internal state matches the provided promise. + */ + resolve(value: T | PromiseLike): Promise; + + /** + * Creates a new resolved promise . + * @returns A resolved promise. + */ + resolve(): Promise; +} + +declare var Promise: PromiseConstructor; +interface RegExp {} +interface String { charAt: any; } +interface Array {}` + }; + + const newLineCharacter = "\n"; + const formatOptions: FormatCodeSettings = { + indentSize: 4, + tabSize: 4, + newLineCharacter, + convertTabsToSpaces: true, + indentStyle: IndentStyle.Smart, + insertSpaceAfterConstructor: false, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterSemicolonInForStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, + insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceBeforeFunctionParenthesis: false, + placeOpenBraceOnNewLineForFunctions: false, + placeOpenBraceOnNewLineForControlBlocks: false, + }; + + const notImplementedHost: LanguageServiceHost = { + getCompilationSettings: notImplemented, + getScriptFileNames: notImplemented, + getScriptVersion: notImplemented, + getScriptSnapshot: notImplemented, + getDefaultLibFileName: notImplemented, + getCurrentDirectory: notImplemented, + }; + + function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, description: DiagnosticMessage, includeLib?: boolean) { + const t = getTest(text); + const selectionRange = t.ranges.get("selection")!; + if (!selectionRange) { + throw new Error(`Test ${caption} does not specify selection range`); + } + + [Extension.Ts, Extension.Js].forEach(extension => + it(`${caption} [${extension}]`, () => runBaseline(extension))); + + function runBaseline(extension: Extension) { + const path = "/a" + extension; + const program = makeProgram({ path, content: t.source }, includeLib)!; + + if (hasSyntacticDiagnostics(program)) { + // Don't bother generating JS baselines for inputs that aren't valid JS. + assert.equal(Extension.Js, extension, "Syntactic diagnostics found in non-JS file"); + return; + } + + const f = { + path, + content: t.source + }; + + const sourceFile = program.getSourceFile(path)!; + const host = projectSystem.createServerHost([f, libFile]); + const projectService = projectSystem.createProjectService(host); + projectService.openClientFile(f.path); + const languageService = projectService.inferredProjects[0].getLanguageService(); + const context: CodeFixContext = { + errorCode: 80006, + span: { start: selectionRange.pos, length: selectionRange.end - selectionRange.pos }, + sourceFile, + program, + cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse }, + preferences: emptyOptions, + host: notImplementedHost, + formatContext: formatting.getFormatContext(formatOptions) + }; + + const diagnostics = languageService.getSuggestionDiagnostics(f.path); + const diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === description.message); + assert.isNotNull(diagnostic); + + const actions = codefix.getFixes(context); + const action = find(actions, action => action.description === description.message)!; + assert.isNotNull(action); + + Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, () => { + const data: string[] = []; + data.push(`// ==ORIGINAL==`); + data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/")); + const changes = action.changes; + assert.lengthOf(changes, 1); + + data.push(`// ==ASYNC FUNCTION::${action.description}==`); + const newText = textChanges.applyChanges(sourceFile.text, changes[0].textChanges); + data.push(newText); + + const diagProgram = makeProgram({ path, content: newText }, includeLib)!; + assert.isFalse(hasSyntacticDiagnostics(diagProgram)); + return data.join(newLineCharacter); + }); + } + + function makeProgram(f: { path: string, content: string }, includeLib?: boolean) { + + const host = projectSystem.createServerHost(includeLib ? [f, libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required + const projectService = projectSystem.createProjectService(host); + projectService.openClientFile(f.path); + const program = projectService.inferredProjects[0].getLanguageService().getProgram(); + return program; + } + + function hasSyntacticDiagnostics(program: Program) { + const diags = program.getSyntacticDiagnostics(); + return length(diags) > 0; + } + } + + function testConvertToAsyncFunctionFailed(caption: string, text: string, description: DiagnosticMessage) { + it(caption, () => { + const t = extractTest(text); + const selectionRange = t.ranges.get("selection"); + if (!selectionRange) { + throw new Error(`Test ${caption} does not specify selection range`); + } + const f = { + path: "/a.ts", + content: t.source + }; + const host = projectSystem.createServerHost([f, libFile]); + const projectService = projectSystem.createProjectService(host); + projectService.openClientFile(f.path); + const languageService = projectService.inferredProjects[0].getLanguageService(); + + const actions = languageService.getSuggestionDiagnostics(f.path); + assert.isUndefined(find(actions, action => action.messageText === description.message)); + }); + } + + describe("convertToAsyncFunctions", () => { + _testConvertToAsyncFunction("convertToAsyncFunction_basic", ` +function [#|f|](): Promise{ + return fetch('https://typescriptlang.org').then(result => { console.log(result) }); +}`); + _testConvertToAsyncFunction("convertToAsyncFunction_basicWithComments", ` +function [#|f|](): Promise{ + /* Note - some of these comments are removed during the refactor. This is not ideal. */ + + // a + /*b*/ return /*c*/ fetch( /*d*/ 'https://typescriptlang.org' /*e*/).then( /*f*/ result /*g*/ => { /*h*/ console.log(/*i*/ result /*j*/) /*k*/}/*l*/); + // m +}`); + + _testConvertToAsyncFunction("convertToAsyncFunction_ArrowFunction", ` +[#|():Promise => {|] + return fetch('https://typescriptlang.org').then(result => console.log(result)); +}`); + _testConvertToAsyncFunction("convertToAsyncFunction_Catch", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }).catch(err => { console.log(err); }); +}`); + _testConvertToAsyncFunction("convertToAsyncFunction_CatchAndRej", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }).catch(err => { console.log(err) }); +}`); + _testConvertToAsyncFunction("convertToAsyncFunction_CatchAndRejRef", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res, rej).catch(catch_err) +} +function res(result){ + console.log(result); +} +function rej(rejection){ + return rejection.ok; +} +function catch_err(err){ + console.log(err); +}`); + _testConvertToAsyncFunction("convertToAsyncFunction_CatchRef", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res).catch(catch_err) +} +function res(result){ + console.log(result); +} +function catch_err(err){ + console.log(err); +} +`); + _testConvertToAsyncFunction("convertToAsyncFunction_CatchNoBrackets", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)).catch(err => console.log(err)); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs1", ` +function [#|f|](): Promise { + return fetch('https://typescriptlang.org').then( _ => { console.log("done"); }); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs2", ` +function [#|f|](): Promise { + return fetch('https://typescriptlang.org').then( () => console.log("done") ); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_Method", ` +class Parser { + [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)); + } +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_MultipleCatches", ` +function [#|f|](): Promise { + return fetch('https://typescriptlang.org').then(res => console.log(res)).catch(err => console.log("err", err)).catch(err2 => console.log("err2", err2)); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThens", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res).then(res2); +} +function res(result){ + return result.ok; +} +function res2(result2){ + console.log(result2); +}` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_MultipleThensSameVarName", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res).then(res2); +} +function res(result){ + return result.ok; +} +function res2(result){ + return result.bodyUsed; +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_NoRes", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(null, rejection => console.log("rejected:", rejection)); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_NoRes2", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(undefined).catch(rej => console.log(rej)); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_NoRes3", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').catch(rej => console.log(rej)); +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org'); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_PromiseDotAll", ` +function [#|f|]():Promise{ + return Promise.all([fetch('https://typescriptlang.org'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(function(vals){ + vals.forEach(console.log); + }); +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestionNoPromise", ` +function [#|f|]():void{ +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_Rej", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_RejRef", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res, rej); +} +function res(result){ + console.log(result); +} +function rej(err){ + console.log(err); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_RejNoBrackets", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result), rejection => console.log("rejected:", rejection)); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_ResRef", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res); +} +function res(result){ + return result.ok; +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_ResRefNoReturnVal", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(res); +} +function res(result){ + console.log(result); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_NoBrackets", ` +function [#|f|]():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)); +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally1", ` +function [#|finallyTest|](): Promise { + return fetch("https://typescriptlang.org").then(res => console.log(res)).catch(rej => console.log("error", rej)).finally(console.log("finally!")); +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally2", ` +function [#|finallyTest|](): Promise { + return fetch("https://typescriptlang.org").then(res => console.log(res)).finally(console.log("finally!")); +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Finally3", ` +function [#|finallyTest|](): Promise { + return fetch("https://typescriptlang.org").finally(console.log("finally!")); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromise", ` +function [#|innerPromise|](): Promise { + return fetch("https://typescriptlang.org").then(resp => { + var blob2 = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + return blob2; + }).then(blob => { + return blob.toString(); + }); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseRet", ` +function [#|innerPromise|](): Promise { + return fetch("https://typescriptlang.org").then(resp => { + return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }).then(blob => { + return blob.toString(); + }); +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn01", ` +function [#|f|]() { + let blob = fetch("https://typescriptlang.org").then(resp => console.log(resp)); + return blob; +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn02", ` +function [#|f|]() { + let blob = fetch("https://typescriptlang.org"); + blob.then(resp => console.log(resp)); + return blob; +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn03", ` +function [#|f|]() { + let blob = fetch("https://typescriptlang.org") + let blob2 = blob.then(resp => console.log(resp)); + blob2.catch(err); + return blob; +} + +function err (rej) { + console.log(rej) +} +` + ); + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn04", ` +function [#|f|]() { + var blob = fetch("https://typescriptlang.org").then(res => console.log(res)), blob2 = fetch("https://microsoft.com").then(res => res.ok).catch(err); + return blob; +} +function err (rej) { + console.log(rej) +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn05", ` +function [#|f|]() { + var blob = fetch("https://typescriptlang.org").then(res => console.log(res)); + blob.then(x => x); + return blob; +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn06", ` +function [#|f|]() { + var blob = fetch("https://typescriptlang.org"); + return blob; +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn07", ` +function [#|f|]() { + let blob = fetch("https://typescriptlang.org"); + let blob2 = fetch("https://microsoft.com"); + blob2.then(res => console.log("res:", res)); + blob.then(resp => console.log(resp)); + return blob; +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn08", ` +function [#|f|]() { + let blob = fetch("https://typescriptlang.org"); + if (!blob.ok){ + return blob; + } + blob.then(resp => console.log(resp)); + return blob; +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn09", ` +function [#|f|]() { + let blob3; + let blob = fetch("https://typescriptlang.org"); + let blob2 = fetch("https://microsoft.com"); + blob2.then(res => console.log("res:", res)); + blob.then(resp => console.log(resp)); + blob3 = blob2.catch(rej => rej.ok); + return blob; +} +` + ); + + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn10", ` +function [#|f|]() { + let blob3; + let blob = fetch("https://typescriptlang.org"); + let blob2 = fetch("https://microsoft.com"); + blob2.then(res => console.log("res:", res)); + blob.then(resp => console.log(resp)); + blob3 = fetch("test.com"); + blob3 = blob2; + return blob; +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_VarReturn11", ` +function [#|f|]() { + let blob; + return blob; +} +` + ); + + + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_Param1", ` +function [#|f|]() { + return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))); +} +function my_print (resp) { + if (resp.ok) { + console.log(resp.buffer); + } + return resp; +} + +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_Param2", ` +function [#|f|]() { + return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))).catch(err => console.log("Error!", err)); +} +function my_print (resp): Promise { + if (resp.ok) { + console.log(resp.buffer); + } + return resp; +} + + +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns1", ` +function [#|f|](): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return x.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }); +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_MultipleReturns2", ` +function [#|f|](): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return x.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + return fetch("https://micorosft.com").then(res => console.log("Another one!")); + }); +} +` + ); + + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_SeperateLines", ` +function [#|f|](): Promise { + var blob = fetch("https://typescriptlang.org") + blob.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }); + blob.then(blob => { + return blob.toString(); + }); + + return blob; +} +` + ); + + + _testConvertToAsyncFunction("convertToAsyncFunction_InnerVarNameConflict", ` +function [#|f|](): Promise { + return fetch("https://typescriptlang.org").then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }).then(blob => { + return blob.toString(); + }); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_InnerPromiseSimple", ` +function [#|f|](): Promise { + return fetch("https://typescriptlang.org").then(resp => { + return resp.blob().then(blob => blob.byteOffset); + }).then(blob => { + return blob.toString(); + }); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen", ` +function [#|f|]() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + }).then(res => res.toString())]); + }); +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_PromiseAllAndThen2", ` +function [#|f|]() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + })]).then(res => res.toString()); + }); +} +` + ); + _testConvertToAsyncFunction("convertToAsyncFunction_Scope1", ` +function [#|f|]() { + var var1:Promise, var2; + return fetch('https://typescriptlang.org').then( _ => + Promise.resolve().then( res => { + var2 = "test"; + return fetch("https://microsoft.com"); + }).then(res => + var1 === res + ) + ).then(res); + } + function res(response){ + console.log(response); + } +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_Conditionals", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res => { + if (res.ok) { + return fetch("https://microsoft.com"); + } + else { + if (res.buffer.length > 5) { + return res; + } + else { + return fetch("https://github.com"); + } + } + }); +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThen", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result): number { + return 5; +} + +function rej(reject): number { + return 3; +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return 3; +} +` + ); + + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); +} + +function res(result): number { + return 5; +} +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); +} + +function res(result){ + return 5; +} +` +); + + _testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes01", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return "Error"; +} +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject): Response{ + return reject; +} +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return reject; +} +` + ); + + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes03", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return Promise.resolve(1); +} +` + ); + +_testConvertToAsyncFunction("convertToAsyncFunction_CatchFollowedByThenMismatchTypes04", ` +interface a { + name: string; + age: number; +} + +interface b extends a { + color: string; +} + + +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result): b{ + return {name: "myName", age: 22, color: "red"}; +} + +function rej(reject): a{ + return {name: "myName", age: 27}; +} +` + ); + + + + + _testConvertToAsyncFunction("convertToAsyncFunction_LocalReturn", ` +function [#|f|]() { + let x = fetch("https://typescriptlang.org").then(res => console.log(res)); + return x.catch(err => console.log("Error!", err)); +} + +`); + _testConvertToAsyncFunction("convertToAsyncFunction_PromiseCallInner", ` +function [#|f|]() { + return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")).catch(err => console.log(err)); +} + +`); +_testConvertToAsyncFunctionFailed("convertToAsyncFunction_CatchFollowedByCall", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res).catch(rej).toString(); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} +` + ); + + + _testConvertToAsyncFunction("convertToAsyncFunction_Scope2", ` +function [#|f|](){ + var i:number; + return fetch("https://typescriptlang.org").then(i => i.ok).then(res => i+1).catch(err => i-1) +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_Loop", ` +function [#|f|](){ + return fetch("https://typescriptlang.org").then(res => { for(let i=0; i<10; i++){ + console.log(res); + }}) +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_Conditional2", ` +function [#|f|](){ + var res = 100; + if (res > 50) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + else { + return fetch("https://typescriptlang.org").then(res_func); + } +} + +function res_func(result){ + console.log(result); +} +` + ); + + _testConvertToAsyncFunction("convertToAsyncFunction_Scope3", ` +function [#|f|]() { + var obj; + return fetch("https://typescriptlang.org").then(function (res) { + obj = { + func: function f() { + console.log(res); + } + }; + }); +} +` + ); + + _testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunction", ` +function [#|f|]() { + function fn2(){ + function fn3(){ + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return fn3(); + } + return fn2(); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_UntypedFunction", ` +function [#|f|]() { + return Promise.resolve().then(res => console.log(res)); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_TernaryConditional", ` +function [#|f|]() { + let i; + return Promise.resolve().then(res => res ? i = res : i = 100); +} +`); + + _testConvertToAsyncFunction("convertToAsyncFunction_ResRejNoArgsArrow", ` + function [#|f|]() { + return Promise.resolve().then(() => 1, () => "a"); + } +`); + + + }); + + function _testConvertToAsyncFunction(caption: string, text: string) { + testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", Diagnostics.Convert_to_async_function, /*includeLib*/ true); + } + + function _testConvertToAsyncFunctionFailed(caption: string, text: string) { + testConvertToAsyncFunctionFailed(caption, text, Diagnostics.Convert_to_async_function); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ArrowFunction.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ArrowFunction.ts new file mode 100644 index 0000000000000..4fa6f23580e5f --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ArrowFunction.ts @@ -0,0 +1,11 @@ +// ==ORIGINAL== + +/*[#|*/():Promise => {/*|]*/ + return fetch('https://typescriptlang.org').then(result => console.log(result)); +} +// ==ASYNC FUNCTION::Convert to async function== + +async ():Promise => { + const result = await fetch('https://typescriptlang.org'); + return console.log(result); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Catch.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Catch.ts new file mode 100644 index 0000000000000..b356e47f85acc --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Catch.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }).catch(err => { console.log(err); }); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + console.log(result); + } + catch (err) { + console.log(err); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRej.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRej.ts new file mode 100644 index 0000000000000..247191aa1fb0a --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRej.ts @@ -0,0 +1,21 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }).catch(err => { console.log(err) }); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + try { + const result = await fetch('https://typescriptlang.org'); + console.log(result); + } + catch (rejection) { + console.log("rejected:", rejection); + } + } + catch (err) { + console.log(err); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRejRef.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRejRef.ts new file mode 100644 index 0000000000000..883da342a6195 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchAndRejRef.ts @@ -0,0 +1,39 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res, rej).catch(catch_err) +} +function res(result){ + console.log(result); +} +function rej(rejection){ + return rejection.ok; +} +function catch_err(err){ + console.log(err); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + try { + const result = await fetch('https://typescriptlang.org'); + return res(result); + } + catch (rejection) { + return rej(rejection); + } + } + catch (err) { + return catch_err(err); + } +} +function res(result){ + console.log(result); +} +function rej(rejection){ + return rejection.ok; +} +function catch_err(err){ + console.log(err); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.js new file mode 100644 index 0000000000000..cb39bbad5e1ad --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.js @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.ts new file mode 100644 index 0000000000000..d675993aadfb5 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThen.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: any; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return result; +} + +function rej(reject){ + return reject; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01.ts new file mode 100644 index 0000000000000..2c9a02e6637d8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result): number { + return 5; +} + +function rej(reject): number { + return 3; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result): number { + return 5; +} + +function rej(reject): number { + return 3; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.js new file mode 100644 index 0000000000000..53d4d82e8dbcb --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.js @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return 3; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return 3; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.ts new file mode 100644 index 0000000000000..8e5e2c82a9735 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes01NoAnnotations.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return 3; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return 3; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02.ts new file mode 100644 index 0000000000000..a385d5bb13abd --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02.ts @@ -0,0 +1,27 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); +} + +function res(result): number { + return 5; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number; + try { + const res = await fetch("https://typescriptlang.org"); + result = 0; + } + catch (rej) { + result = 1; + } + return res(result); +} + +function res(result): number { + return 5; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.js new file mode 100644 index 0000000000000..44a8c3b3b65f7 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.js @@ -0,0 +1,27 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); +} + +function res(result){ + return 5; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const res = await fetch("https://typescriptlang.org"); + result = 0; + } + catch (rej) { + result = 1; + } + return res(result); +} + +function res(result){ + return 5; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.ts new file mode 100644 index 0000000000000..68563c3a348ea --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMatchingTypes02NoAnnotations.ts @@ -0,0 +1,27 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => 0).catch(rej => 1).then(res); +} + +function res(result){ + return 5; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number; + try { + const res = await fetch("https://typescriptlang.org"); + result = 0; + } + catch (rej) { + result = 1; + } + return res(result); +} + +function res(result){ + return 5; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.js new file mode 100644 index 0000000000000..49cd8dd0cddba --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.js @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return "Error"; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return "Error"; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.ts new file mode 100644 index 0000000000000..6bbd496de7d0a --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes01.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return "Error"; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: string | number; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return "Error"; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02.ts new file mode 100644 index 0000000000000..2d415c090e211 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject): Response{ + return reject; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number | Response; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject): Response{ + return reject; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.js new file mode 100644 index 0000000000000..f7be616009ffa --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.js @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return reject; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return reject; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.ts new file mode 100644 index 0000000000000..5cfae1be7584c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes02NoAnnotations.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return reject; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: any; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return reject; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.js new file mode 100644 index 0000000000000..5ae54306d1122 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.js @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return Promise.resolve(1); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return Promise.resolve(1); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.ts new file mode 100644 index 0000000000000..2ee8796ab203c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes03.ts @@ -0,0 +1,35 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return Promise.resolve(1); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + let result: number | Promise; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result){ + return 5; +} + +function rej(reject){ + return Promise.resolve(1); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes04.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes04.ts new file mode 100644 index 0000000000000..ac542ca8cf595 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchFollowedByThenMismatchTypes04.ts @@ -0,0 +1,55 @@ +// ==ORIGINAL== + +interface a { + name: string; + age: number; +} + +interface b extends a { + color: string; +} + + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res).catch(rej).then(res); +} + +function res(result): b{ + return {name: "myName", age: 22, color: "red"}; +} + +function rej(reject): a{ + return {name: "myName", age: 27}; +} + +// ==ASYNC FUNCTION::Convert to async function== + +interface a { + name: string; + age: number; +} + +interface b extends a { + color: string; +} + + +async function f(){ + let result: a; + try { + const result_1 = await fetch("https://typescriptlang.org"); + result = await res(result_1); + } + catch (reject) { + result = await rej(reject); + } + return res(result); +} + +function res(result): b{ + return {name: "myName", age: 22, color: "red"}; +} + +function rej(reject): a{ + return {name: "myName", age: 27}; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchNoBrackets.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchNoBrackets.ts new file mode 100644 index 0000000000000..54c2b22921b1e --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchNoBrackets.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)).catch(err => console.log(err)); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + return console.log(result); + } + catch (err) { + return console.log(err); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchRef.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchRef.ts new file mode 100644 index 0000000000000..709e777668d11 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_CatchRef.ts @@ -0,0 +1,29 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res).catch(catch_err) +} +function res(result){ + console.log(result); +} +function catch_err(err){ + console.log(err); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + return res(result); + } + catch (err) { + return catch_err(err); + } +} +function res(result){ + console.log(result); +} +function catch_err(err){ + console.log(err); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.js new file mode 100644 index 0000000000000..b7bd2c087f12e --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.js @@ -0,0 +1,33 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + var res = 100; + if (res > 50) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + else { + return fetch("https://typescriptlang.org").then(res_func); + } +} + +function res_func(result){ + console.log(result); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + var res = 100; + if (res > 50) { + const res_1 = await fetch("https://typescriptlang.org"); + return console.log(res_1); + } + else { + const result = await fetch("https://typescriptlang.org"); + return res_func(result); + } +} + +function res_func(result){ + console.log(result); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.ts new file mode 100644 index 0000000000000..b7bd2c087f12e --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditional2.ts @@ -0,0 +1,33 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + var res = 100; + if (res > 50) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + else { + return fetch("https://typescriptlang.org").then(res_func); + } +} + +function res_func(result){ + console.log(result); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + var res = 100; + if (res > 50) { + const res_1 = await fetch("https://typescriptlang.org"); + return console.log(res_1); + } + else { + const result = await fetch("https://typescriptlang.org"); + return res_func(result); + } +} + +function res_func(result){ + console.log(result); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.js new file mode 100644 index 0000000000000..637469938a749 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.js @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => { + if (res.ok) { + return fetch("https://microsoft.com"); + } + else { + if (res.buffer.length > 5) { + return res; + } + else { + return fetch("https://github.com"); + } + } + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + const res = await fetch("https://typescriptlang.org"); + if (res.ok) { + return fetch("https://microsoft.com"); + } + else { + if (res.buffer.length > 5) { + return res; + } + else { + return fetch("https://github.com"); + } + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.ts new file mode 100644 index 0000000000000..637469938a749 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Conditionals.ts @@ -0,0 +1,34 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => { + if (res.ok) { + return fetch("https://microsoft.com"); + } + else { + if (res.buffer.length > 5) { + return res; + } + else { + return fetch("https://github.com"); + } + } + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + const res = await fetch("https://typescriptlang.org"); + if (res.ok) { + return fetch("https://microsoft.com"); + } + else { + if (res.buffer.length > 5) { + return res; + } + else { + return fetch("https://github.com"); + } + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts new file mode 100644 index 0000000000000..2cb2ef5b32d9b --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs1.ts @@ -0,0 +1,11 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch('https://typescriptlang.org').then( _ => { console.log("done"); }); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + await fetch('https://typescriptlang.org'); + console.log("done"); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs2.ts new file mode 100644 index 0000000000000..395226496947f --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_IgnoreArgs2.ts @@ -0,0 +1,11 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch('https://typescriptlang.org').then( () => console.log("done") ); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + await fetch('https://typescriptlang.org'); + return console.log("done"); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromise.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromise.ts new file mode 100644 index 0000000000000..5288a84875f2b --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromise.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/innerPromise/*|]*/(): Promise { + return fetch("https://typescriptlang.org").then(resp => { + var blob2 = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + return blob2; + }).then(blob => { + return blob.toString(); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function innerPromise(): Promise { + const resp = await fetch("https://typescriptlang.org"); + var blob2 = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + const blob_1 = blob2; + return blob_1.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseRet.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseRet.ts new file mode 100644 index 0000000000000..098b3c4627afd --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseRet.ts @@ -0,0 +1,24 @@ +// ==ORIGINAL== + +function /*[#|*/innerPromise/*|]*/(): Promise { + return fetch("https://typescriptlang.org").then(resp => { + return resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }).then(blob => { + return blob.toString(); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function innerPromise(): Promise { + const resp = await fetch("https://typescriptlang.org"); + let blob_1: any; + try { + const blob = await resp.blob(); + blob_1 = blob.byteOffset; + } + catch (err) { + blob_1 = 'Error'; + } + return blob_1.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseSimple.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseSimple.ts new file mode 100644 index 0000000000000..522e97491f6b0 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerPromiseSimple.ts @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch("https://typescriptlang.org").then(resp => { + return resp.blob().then(blob => blob.byteOffset); + }).then(blob => { + return blob.toString(); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + const resp = await fetch("https://typescriptlang.org"); + const blob = await resp.blob(); + const blob_1 = blob.byteOffset; + return blob_1.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerVarNameConflict.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerVarNameConflict.ts new file mode 100644 index 0000000000000..3570a90a0b166 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_InnerVarNameConflict.ts @@ -0,0 +1,17 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch("https://typescriptlang.org").then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }).then(blob => { + return blob.toString(); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + const resp = await fetch("https://typescriptlang.org"); + var blob = resp.blob().then(blob_1 => blob_1.byteOffset).catch(err => 'Error'); + return blob_1.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.js new file mode 100644 index 0000000000000..f9bc67dd19b71 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.js @@ -0,0 +1,20 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + let x = fetch("https://typescriptlang.org").then(res => console.log(res)); + return x.catch(err => console.log("Error!", err)); +} + + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + let x = fetch("https://typescriptlang.org").then(res => console.log(res)); + try { + return x; + } + catch (err) { + return console.log("Error!", err); + } +} + diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.ts new file mode 100644 index 0000000000000..f9bc67dd19b71 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_LocalReturn.ts @@ -0,0 +1,20 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + let x = fetch("https://typescriptlang.org").then(res => console.log(res)); + return x.catch(err => console.log("Error!", err)); +} + + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + let x = fetch("https://typescriptlang.org").then(res => console.log(res)); + try { + return x; + } + catch (err) { + return console.log("Error!", err); + } +} + diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.js new file mode 100644 index 0000000000000..9ca280474d555 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.js @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => { for(let i=0; i<10; i++){ + console.log(res); + }}) +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + const res = await fetch("https://typescriptlang.org"); + for (let i = 0; i < 10; i++) { + console.log(res); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.ts new file mode 100644 index 0000000000000..9ca280474d555 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Loop.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + return fetch("https://typescriptlang.org").then(res => { for(let i=0; i<10; i++){ + console.log(res); + }}) +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + const res = await fetch("https://typescriptlang.org"); + for (let i = 0; i < 10; i++) { + console.log(res); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Method.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Method.ts new file mode 100644 index 0000000000000..4737ce9249329 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Method.ts @@ -0,0 +1,15 @@ +// ==ORIGINAL== + +class Parser { + /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)); + } +} +// ==ASYNC FUNCTION::Convert to async function== + +class Parser { + async f():Promise { + const result = await fetch('https://typescriptlang.org'); + return console.log(result); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleCatches.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleCatches.ts new file mode 100644 index 0000000000000..654df9a1e4c6f --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleCatches.ts @@ -0,0 +1,21 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + return fetch('https://typescriptlang.org').then(res => console.log(res)).catch(err => console.log("err", err)).catch(err2 => console.log("err2", err2)); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + try { + try { + const res = await fetch('https://typescriptlang.org'); + return console.log(res); + } + catch (err) { + return console.log("err", err); + } + } + catch (err2) { + return console.log("err2", err2); + } +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns.ts new file mode 100644 index 0000000000000..1250ea44359d2 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns.ts @@ -0,0 +1,23 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return x.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + let res_2 = await fetch("https://typescriptlang.org"); + return console.log(res_2); + } + let resp = await x; + var blob = resp.blob().then(blob_1 => blob_1.byteOffset).catch(err => 'Error'); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns1.ts new file mode 100644 index 0000000000000..074091e33596c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns1.ts @@ -0,0 +1,23 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return x.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + const res_1 = await fetch("https://typescriptlang.org"); + return console.log(res_1); + } + const resp = await x; + var blob = resp.blob().then(blob_1 => blob_1.byteOffset).catch(err => 'Error'); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns2.ts new file mode 100644 index 0000000000000..6569c1fb0ef99 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleReturns2.ts @@ -0,0 +1,26 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + return fetch("https://typescriptlang.org").then(res => console.log(res)); + } + return x.then(resp => { + var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error'); + return fetch("https://micorosft.com").then(res => console.log("Another one!")); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise { + let x = fetch("https://microsoft.com").then(res => console.log("Microsoft:", res)); + if (x.ok) { + const res_1 = await fetch("https://typescriptlang.org"); + return console.log(res_1); + } + const resp = await x; + var blob = resp.blob().then(blob_1 => blob_1.byteOffset).catch(err => 'Error'); + const res_1 = await fetch("https://micorosft.com"); + return console.log("Another one!"); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThens.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThens.ts new file mode 100644 index 0000000000000..f9329346ceda2 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThens.ts @@ -0,0 +1,24 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res).then(res2); +} +function res(result){ + return result.ok; +} +function res2(result2){ + console.log(result2); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + const result = await fetch('https://typescriptlang.org'); + const result2 = await res(result); + return res2(result2); +} +function res(result){ + return result.ok; +} +function res2(result2){ + console.log(result2); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThensSameVarName.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThensSameVarName.ts new file mode 100644 index 0000000000000..bc635f855759e --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_MultipleThensSameVarName.ts @@ -0,0 +1,25 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res).then(res2); +} +function res(result){ + return result.ok; +} +function res2(result){ + return result.bodyUsed; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + const result = await fetch('https://typescriptlang.org'); + const result_1 = await res(result); + return res2(result_1); +} +function res(result){ + return result.ok; +} +function res2(result){ + return result.bodyUsed; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoBrackets.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoBrackets.ts new file mode 100644 index 0000000000000..923d73085f6bb --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoBrackets.ts @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + const result = await fetch('https://typescriptlang.org'); + return console.log(result); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes.ts new file mode 100644 index 0000000000000..8817f682a8108 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(null, rejection => console.log("rejected:", rejection)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + await fetch('https://typescriptlang.org'); + } + catch (rejection) { + return console.log("rejected:", rejection); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes2.ts new file mode 100644 index 0000000000000..33d2f9808c97d --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes2.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(undefined).catch(rej => console.log(rej)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + await fetch('https://typescriptlang.org'); + } + catch (rej) { + return console.log(rej); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes3.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes3.ts new file mode 100644 index 0000000000000..09081dbabd5d8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_NoRes3.ts @@ -0,0 +1,16 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').catch(rej => console.log(rej)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + return fetch('https://typescriptlang.org'); + } + catch (rej) { + return console.log(rej); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Param2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Param2.ts new file mode 100644 index 0000000000000..167b6430a059c --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Param2.ts @@ -0,0 +1,32 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))).catch(err => console.log("Error!", err)); +} +function my_print (resp): Promise { + if (resp.ok) { + console.log(resp.buffer); + } + return resp; +} + + + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + try { + return my_print(fetch("https://typescriptlang.org").then(res => console.log(res))); + } + catch (err) { + return console.log("Error!", err); + } +} +function my_print (resp): Promise { + if (resp.ok) { + console.log(resp.buffer); + } + return resp; +} + + diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.js new file mode 100644 index 0000000000000..8b4b5afd88ca0 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.js @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + }).then(res => res.toString())]); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + await Promise.resolve(); + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function() { + return fetch("https://github.com"); + }).then(res => res.toString())]); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.ts new file mode 100644 index 0000000000000..8b4b5afd88ca0 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen.ts @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + }).then(res => res.toString())]); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + await Promise.resolve(); + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function() { + return fetch("https://github.com"); + }).then(res => res.toString())]); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.js new file mode 100644 index 0000000000000..3fdcdf6dd8329 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.js @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + })]).then(res => res.toString()); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + await Promise.resolve(); + const res = await Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function() { + return fetch("https://github.com"); + })]); + return res.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.ts new file mode 100644 index 0000000000000..3fdcdf6dd8329 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseAllAndThen2.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(function () { + return Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function () { + return fetch("https://github.com"); + })]).then(res => res.toString()); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + await Promise.resolve(); + const res = await Promise.all([fetch("https://typescriptlang.org"), fetch("https://microsoft.com"), Promise.resolve().then(function() { + return fetch("https://github.com"); + })]); + return res.toString(); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.js new file mode 100644 index 0000000000000..0049c661c3904 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.js @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")).catch(err => console.log(err)); +} + + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + try { + return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")); + } + catch (err) { + return console.log(err); + } +} + diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.ts new file mode 100644 index 0000000000000..0049c661c3904 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseCallInner.ts @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")).catch(err => console.log(err)); +} + + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + try { + return fetch(Promise.resolve(1).then(res => "https://typescriptlang.org")); + } + catch (err) { + return console.log(err); + } +} + diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseDotAll.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseDotAll.ts new file mode 100644 index 0000000000000..9e9601eca7af8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_PromiseDotAll.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise{ + return Promise.all([fetch('https://typescriptlang.org'), fetch('https://microsoft.com'), fetch('https://youtube.com')]).then(function(vals){ + vals.forEach(console.log); + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise{ + const vals = await Promise.all([fetch('https://typescriptlang.org'), fetch('https://microsoft.com'), fetch('https://youtube.com')]); + vals.forEach(console.log); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Rej.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Rej.ts new file mode 100644 index 0000000000000..bf3ee9c420cd6 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Rej.ts @@ -0,0 +1,17 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => { console.log(result); }, rejection => { console.log("rejected:", rejection); }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + console.log(result); + } + catch (rejection) { + console.log("rejected:", rejection); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejNoBrackets.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejNoBrackets.ts new file mode 100644 index 0000000000000..8169745f5bde9 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejNoBrackets.ts @@ -0,0 +1,17 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(result => console.log(result), rejection => console.log("rejected:", rejection)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + return console.log(result); + } + catch (rejection) { + return console.log("rejected:", rejection); + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejRef.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejRef.ts new file mode 100644 index 0000000000000..77fadff7ee993 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_RejRef.ts @@ -0,0 +1,29 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res, rej); +} +function res(result){ + console.log(result); +} +function rej(err){ + console.log(err); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + try { + const result = await fetch('https://typescriptlang.org'); + return res(result); + } + catch (err) { + return rej(err); + } +} +function res(result){ + console.log(result); +} +function rej(err){ + console.log(err); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRef.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRef.ts new file mode 100644 index 0000000000000..74ace51e4f5b8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRef.ts @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res); +} +function res(result){ + return result.ok; +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + const result = await fetch('https://typescriptlang.org'); + return res(result); +} +function res(result){ + return result.ok; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRefNoReturnVal.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRefNoReturnVal.ts new file mode 100644 index 0000000000000..e1e5a28b75528 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRefNoReturnVal.ts @@ -0,0 +1,18 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/():Promise { + return fetch('https://typescriptlang.org').then(res); +} +function res(result){ + console.log(result); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f():Promise { + const result = await fetch('https://typescriptlang.org'); + return res(result); +} +function res(result){ + console.log(result); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.js new file mode 100644 index 0000000000000..c874c6ea61240 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.js @@ -0,0 +1,17 @@ +// ==ORIGINAL== + + function /*[#|*/f/*|]*/() { + return Promise.resolve().then(() => 1, () => "a"); + } + +// ==ASYNC FUNCTION::Convert to async function== + + async function f() { + try { + await Promise.resolve(); + return 1; + } + catch (e) { + return "a"; + } + } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.ts new file mode 100644 index 0000000000000..c874c6ea61240 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_ResRejNoArgsArrow.ts @@ -0,0 +1,17 @@ +// ==ORIGINAL== + + function /*[#|*/f/*|]*/() { + return Promise.resolve().then(() => 1, () => "a"); + } + +// ==ASYNC FUNCTION::Convert to async function== + + async function f() { + try { + await Promise.resolve(); + return 1; + } + catch (e) { + return "a"; + } + } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope.ts new file mode 100644 index 0000000000000..1c6a9694fd7a9 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope.ts @@ -0,0 +1,31 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + var var1:Promise, var2; + return fetch('https://typescriptlang.org').then( _ => + Promise.resolve().then( res => { + var2 = "test"; + return fetch("https://microsoft.com"); + }).then(res => + var1 === res + ) + ).then(res); + } + function res(response){ + console.log(response); + } + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + var var1:Promise, var2; + await fetch('https://typescriptlang.org'); + let res = await Promise.resolve(); + var2 = "test"; + let res_1 = fetch("https://microsoft.com"); + let response = var1 === res_1; + return res(response); + } + function res(response){ + console.log(response); + } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts new file mode 100644 index 0000000000000..c1326b0528e28 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope1.ts @@ -0,0 +1,31 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + var var1:Promise, var2; + return fetch('https://typescriptlang.org').then( _ => + Promise.resolve().then( res => { + var2 = "test"; + return fetch("https://microsoft.com"); + }).then(res => + var1 === res + ) + ).then(res); + } + function res(response){ + console.log(response); + } + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + var var1:Promise, var2; + await fetch('https://typescriptlang.org'); + const res = await Promise.resolve(); + var2 = "test"; + const res_1 = fetch("https://microsoft.com"); + const response = var1 === res_1; + return res(response); + } + function res(response){ + console.log(response); + } diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope2.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope2.ts new file mode 100644 index 0000000000000..ee7cdd695db28 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope2.ts @@ -0,0 +1,20 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(){ + var i:number; + return fetch("https://typescriptlang.org").then(i => i.ok).then(res => i+1).catch(err => i-1) +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f(){ + var i:number; + try { + const i_1 = await fetch("https://typescriptlang.org"); + const res = i_1.ok; + return i + 1; + } + catch (err) { + return i - 1; + } +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.js new file mode 100644 index 0000000000000..f9b7c3c59a4da --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.js @@ -0,0 +1,24 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + var obj; + return fetch("https://typescriptlang.org").then(function (res) { + obj = { + func: function f() { + console.log(res); + } + }; + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + var obj; + const res = await fetch("https://typescriptlang.org"); + obj = { + func: function f() { + console.log(res); + } + }; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.ts new file mode 100644 index 0000000000000..f9b7c3c59a4da --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_Scope3.ts @@ -0,0 +1,24 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + var obj; + return fetch("https://typescriptlang.org").then(function (res) { + obj = { + func: function f() { + console.log(res); + } + }; + }); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + var obj; + const res = await fetch("https://typescriptlang.org"); + obj = { + func: function f() { + console.log(res); + } + }; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.js new file mode 100644 index 0000000000000..35c2029c4fad8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.js @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + let i; + return Promise.resolve().then(res => res ? i = res : i = 100); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + let i; + const res = await Promise.resolve(); + return res ? i = res : i = 100; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.ts new file mode 100644 index 0000000000000..35c2029c4fad8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_TernaryConditional.ts @@ -0,0 +1,14 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + let i; + return Promise.resolve().then(res => res ? i = res : i = 100); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + let i; + const res = await Promise.resolve(); + return res ? i = res : i = 100; +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.js b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.js new file mode 100644 index 0000000000000..d6f0bc06540b2 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.js @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(res => console.log(res)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const res = await Promise.resolve(); + return console.log(res); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.ts new file mode 100644 index 0000000000000..d6f0bc06540b2 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_UntypedFunction.ts @@ -0,0 +1,12 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/() { + return Promise.resolve().then(res => console.log(res)); +} + +// ==ASYNC FUNCTION::Convert to async function== + +async function f() { + const res = await Promise.resolve(); + return console.log(res); +} diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basic.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basic.ts new file mode 100644 index 0000000000000..0058253541cce --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basic.ts @@ -0,0 +1,11 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise{ + return fetch('https://typescriptlang.org').then(result => { console.log(result) }); +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise{ + const result = await fetch('https://typescriptlang.org'); + console.log(result); +} \ No newline at end of file diff --git a/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basicWithComments.ts b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basicWithComments.ts new file mode 100644 index 0000000000000..84d0355357ac8 --- /dev/null +++ b/tests/baselines/reference/convertToAsyncFunction/convertToAsyncFunction_basicWithComments.ts @@ -0,0 +1,19 @@ +// ==ORIGINAL== + +function /*[#|*/f/*|]*/(): Promise{ + /* Note - some of these comments are removed during the refactor. This is not ideal. */ + + // a + /*b*/ return /*c*/ fetch( /*d*/ 'https://typescriptlang.org' /*e*/).then( /*f*/ result /*g*/ => { /*h*/ console.log(/*i*/ result /*j*/) /*k*/}/*l*/); + // m +} +// ==ASYNC FUNCTION::Convert to async function== + +async function f(): Promise{ + /* Note - some of these comments are removed during the refactor. This is not ideal. */ + + // a + /*b*/ const result = await fetch(/*d*/ 'https://typescriptlang.org' /*e*/); + console.log(result); /*k*/ + // m +} \ No newline at end of file