1import { 2 __String, AccessorDeclaration, addEmitFlags, addEmitHelper, addEmitHelpers, addRange, advancedAsyncSuperHelper, 3 append, ArrowFunction, asyncSuperHelper, AwaitExpression, BinaryExpression, CallExpression, CatchClause, 4 chainBundle, CommaListExpression, concatenate, ConciseBody, ConstructorDeclaration, createForOfBindingStatement, 5 createSuperAccessVariableStatement, Debug, ElementAccessExpression, EmitFlags, EmitHint, Expression, 6 ExpressionStatement, flattenDestructuringAssignment, flattenDestructuringBinding, FlattenLevel, ForInitializer, 7 ForOfStatement, ForStatement, FunctionBody, FunctionDeclaration, FunctionExpression, FunctionFlags, 8 FunctionLikeDeclaration, GeneratedIdentifierFlags, GetAccessorDeclaration, getEmitScriptTarget, getFunctionFlags, 9 getNodeId, hasSyntacticModifier, Identifier, insertStatementsAfterStandardPrologue, isAssignmentPattern, 10 isBindingPattern, isBlock, isConciseBody, isDestructuringAssignment, isEffectiveStrictModeSourceFile, isExpression, 11 isForInitializer, isIdentifier, isModifier, isModifierLike, isObjectLiteralElementLike, isParameter, 12 isPropertyAccessExpression, isPropertyName, isStatement, isSuperProperty, isToken, isVariableDeclarationList, 13 LabeledStatement, LeftHandSideExpression, MethodDeclaration, ModifierFlags, Node, NodeCheckFlags, NodeFlags, 14 ObjectLiteralElementLike, ObjectLiteralExpression, ParameterDeclaration, ParenthesizedExpression, ProcessLevel, 15 processTaggedTemplateExpression, PropertyAccessExpression, ReturnStatement, ScriptTarget, Set, 16 SetAccessorDeclaration, setEmitFlags, setOriginalNode, setSourceMapRange, setTextRange, SignatureDeclaration, 17 skipParentheses, some, SourceFile, startOnNewLine, Statement, SyntaxKind, TaggedTemplateExpression, TextRange, 18 Token, TransformationContext, TransformFlags, unwrapInnermostStatementOfLabel, VariableDeclaration, 19 VariableStatement, visitEachChild, visitIterationBody, visitLexicalEnvironment, visitNode, visitNodes, 20 visitParameterList, VisitResult, VoidExpression, YieldExpression, Bundle, 21} from "../_namespaces/ts"; 22 23const enum ESNextSubstitutionFlags { 24 /** Enables substitutions for async methods with `super` calls. */ 25 AsyncMethodsWithSuper = 1 << 0 26} 27 28// Facts we track as we traverse the tree 29const enum HierarchyFacts { 30 None = 0, 31 32 // 33 // Ancestor facts 34 // 35 36 HasLexicalThis = 1 << 0, 37 IterationContainer = 1 << 1, 38 // NOTE: do not add more ancestor flags without also updating AncestorFactsMask below. 39 40 // 41 // Ancestor masks 42 // 43 44 AncestorFactsMask = (IterationContainer << 1) - 1, 45 46 SourceFileIncludes = HasLexicalThis, 47 SourceFileExcludes = IterationContainer, 48 StrictModeSourceFileIncludes = None, 49 50 ClassOrFunctionIncludes = HasLexicalThis, 51 ClassOrFunctionExcludes = IterationContainer, 52 53 ArrowFunctionIncludes = None, 54 ArrowFunctionExcludes = ClassOrFunctionExcludes, 55 56 IterationStatementIncludes = IterationContainer, 57 IterationStatementExcludes = None, 58} 59 60/** @internal */ 61export function transformES2018(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle { 62 const { 63 factory, 64 getEmitHelperFactory: emitHelpers, 65 resumeLexicalEnvironment, 66 endLexicalEnvironment, 67 hoistVariableDeclaration 68 } = context; 69 70 const resolver = context.getEmitResolver(); 71 const compilerOptions = context.getCompilerOptions(); 72 const languageVersion = getEmitScriptTarget(compilerOptions); 73 74 const previousOnEmitNode = context.onEmitNode; 75 context.onEmitNode = onEmitNode; 76 77 const previousOnSubstituteNode = context.onSubstituteNode; 78 context.onSubstituteNode = onSubstituteNode; 79 80 let exportedVariableStatement = false; 81 let enabledSubstitutions: ESNextSubstitutionFlags; 82 let enclosingFunctionFlags: FunctionFlags; 83 let parametersWithPrecedingObjectRestOrSpread: Set<ParameterDeclaration> | undefined; 84 let enclosingSuperContainerFlags: NodeCheckFlags = 0; 85 let hierarchyFacts: HierarchyFacts = 0; 86 87 let currentSourceFile: SourceFile; 88 let taggedTemplateStringDeclarations: VariableDeclaration[]; 89 90 /** Keeps track of property names accessed on super (`super.x`) within async functions. */ 91 let capturedSuperProperties: Set<__String>; 92 /** Whether the async function contains an element access on super (`super[x]`). */ 93 let hasSuperElementAccess: boolean; 94 /** A set of node IDs for generated super accessors. */ 95 const substitutedSuperAccessors: boolean[] = []; 96 97 return chainBundle(context, transformSourceFile); 98 99 function affectsSubtree(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { 100 return hierarchyFacts !== (hierarchyFacts & ~excludeFacts | includeFacts); 101 } 102 103 /** 104 * Sets the `HierarchyFacts` for this node prior to visiting this node's subtree, returning the facts set prior to modification. 105 * @param excludeFacts The existing `HierarchyFacts` to reset before visiting the subtree. 106 * @param includeFacts The new `HierarchyFacts` to set before visiting the subtree. 107 */ 108 function enterSubtree(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { 109 const ancestorFacts = hierarchyFacts; 110 hierarchyFacts = (hierarchyFacts & ~excludeFacts | includeFacts) & HierarchyFacts.AncestorFactsMask; 111 return ancestorFacts; 112 } 113 114 /** 115 * Restores the `HierarchyFacts` for this node's ancestor after visiting this node's 116 * subtree. 117 * @param ancestorFacts The `HierarchyFacts` of the ancestor to restore after visiting the subtree. 118 */ 119 function exitSubtree(ancestorFacts: HierarchyFacts) { 120 hierarchyFacts = ancestorFacts; 121 } 122 123 function recordTaggedTemplateString(temp: Identifier) { 124 taggedTemplateStringDeclarations = append( 125 taggedTemplateStringDeclarations, 126 factory.createVariableDeclaration(temp)); 127 } 128 129 function transformSourceFile(node: SourceFile) { 130 if (node.isDeclarationFile) { 131 return node; 132 } 133 134 currentSourceFile = node; 135 const visited = visitSourceFile(node); 136 addEmitHelpers(visited, context.readEmitHelpers()); 137 138 currentSourceFile = undefined!; 139 taggedTemplateStringDeclarations = undefined!; 140 return visited; 141 } 142 143 function visitor(node: Node): VisitResult<Node> { 144 return visitorWorker(node, /*expressionResultIsUnused*/ false); 145 } 146 147 function visitorWithUnusedExpressionResult(node: Node): VisitResult<Node> { 148 return visitorWorker(node, /*expressionResultIsUnused*/ true); 149 } 150 151 function visitorNoAsyncModifier(node: Node): VisitResult<Node> { 152 if (node.kind === SyntaxKind.AsyncKeyword) { 153 return undefined; 154 } 155 return node; 156 } 157 158 function doWithHierarchyFacts<T, U>(cb: (value: T) => U, value: T, excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts) { 159 if (affectsSubtree(excludeFacts, includeFacts)) { 160 const ancestorFacts = enterSubtree(excludeFacts, includeFacts); 161 const result = cb(value); 162 exitSubtree(ancestorFacts); 163 return result; 164 } 165 return cb(value); 166 } 167 168 function visitDefault(node: Node): VisitResult<Node> { 169 return visitEachChild(node, visitor, context); 170 } 171 172 /** 173 * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the 174 * expression of an `ExpressionStatement`). 175 */ 176 function visitorWorker(node: Node, expressionResultIsUnused: boolean): VisitResult<Node> { 177 if ((node.transformFlags & TransformFlags.ContainsES2018) === 0) { 178 return node; 179 } 180 switch (node.kind) { 181 case SyntaxKind.AwaitExpression: 182 return visitAwaitExpression(node as AwaitExpression); 183 case SyntaxKind.YieldExpression: 184 return visitYieldExpression(node as YieldExpression); 185 case SyntaxKind.ReturnStatement: 186 return visitReturnStatement(node as ReturnStatement); 187 case SyntaxKind.LabeledStatement: 188 return visitLabeledStatement(node as LabeledStatement); 189 case SyntaxKind.ObjectLiteralExpression: 190 return visitObjectLiteralExpression(node as ObjectLiteralExpression); 191 case SyntaxKind.BinaryExpression: 192 return visitBinaryExpression(node as BinaryExpression, expressionResultIsUnused); 193 case SyntaxKind.CommaListExpression: 194 return visitCommaListExpression(node as CommaListExpression, expressionResultIsUnused); 195 case SyntaxKind.CatchClause: 196 return visitCatchClause(node as CatchClause); 197 case SyntaxKind.VariableStatement: 198 return visitVariableStatement(node as VariableStatement); 199 case SyntaxKind.VariableDeclaration: 200 return visitVariableDeclaration(node as VariableDeclaration); 201 case SyntaxKind.DoStatement: 202 case SyntaxKind.WhileStatement: 203 case SyntaxKind.ForInStatement: 204 return doWithHierarchyFacts( 205 visitDefault, 206 node, 207 HierarchyFacts.IterationStatementExcludes, 208 HierarchyFacts.IterationStatementIncludes); 209 case SyntaxKind.ForOfStatement: 210 return visitForOfStatement(node as ForOfStatement, /*outermostLabeledStatement*/ undefined); 211 case SyntaxKind.ForStatement: 212 return doWithHierarchyFacts( 213 visitForStatement, 214 node as ForStatement, 215 HierarchyFacts.IterationStatementExcludes, 216 HierarchyFacts.IterationStatementIncludes); 217 case SyntaxKind.VoidExpression: 218 return visitVoidExpression(node as VoidExpression); 219 case SyntaxKind.Constructor: 220 return doWithHierarchyFacts( 221 visitConstructorDeclaration, 222 node as ConstructorDeclaration, 223 HierarchyFacts.ClassOrFunctionExcludes, 224 HierarchyFacts.ClassOrFunctionIncludes); 225 case SyntaxKind.MethodDeclaration: 226 return doWithHierarchyFacts( 227 visitMethodDeclaration, 228 node as MethodDeclaration, 229 HierarchyFacts.ClassOrFunctionExcludes, 230 HierarchyFacts.ClassOrFunctionIncludes); 231 case SyntaxKind.GetAccessor: 232 return doWithHierarchyFacts( 233 visitGetAccessorDeclaration, 234 node as GetAccessorDeclaration, 235 HierarchyFacts.ClassOrFunctionExcludes, 236 HierarchyFacts.ClassOrFunctionIncludes); 237 case SyntaxKind.SetAccessor: 238 return doWithHierarchyFacts( 239 visitSetAccessorDeclaration, 240 node as SetAccessorDeclaration, 241 HierarchyFacts.ClassOrFunctionExcludes, 242 HierarchyFacts.ClassOrFunctionIncludes); 243 case SyntaxKind.FunctionDeclaration: 244 return doWithHierarchyFacts( 245 visitFunctionDeclaration, 246 node as FunctionDeclaration, 247 HierarchyFacts.ClassOrFunctionExcludes, 248 HierarchyFacts.ClassOrFunctionIncludes); 249 case SyntaxKind.FunctionExpression: 250 return doWithHierarchyFacts( 251 visitFunctionExpression, 252 node as FunctionExpression, 253 HierarchyFacts.ClassOrFunctionExcludes, 254 HierarchyFacts.ClassOrFunctionIncludes); 255 case SyntaxKind.ArrowFunction: 256 return doWithHierarchyFacts( 257 visitArrowFunction, 258 node as ArrowFunction, 259 HierarchyFacts.ArrowFunctionExcludes, 260 HierarchyFacts.ArrowFunctionIncludes); 261 case SyntaxKind.Parameter: 262 return visitParameter(node as ParameterDeclaration); 263 case SyntaxKind.ExpressionStatement: 264 return visitExpressionStatement(node as ExpressionStatement); 265 case SyntaxKind.ParenthesizedExpression: 266 return visitParenthesizedExpression(node as ParenthesizedExpression, expressionResultIsUnused); 267 case SyntaxKind.TaggedTemplateExpression: 268 return visitTaggedTemplateExpression(node as TaggedTemplateExpression); 269 case SyntaxKind.PropertyAccessExpression: 270 if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) { 271 capturedSuperProperties.add(node.name.escapedText); 272 } 273 return visitEachChild(node, visitor, context); 274 case SyntaxKind.ElementAccessExpression: 275 if (capturedSuperProperties && (node as ElementAccessExpression).expression.kind === SyntaxKind.SuperKeyword) { 276 hasSuperElementAccess = true; 277 } 278 return visitEachChild(node, visitor, context); 279 case SyntaxKind.ClassDeclaration: 280 case SyntaxKind.ClassExpression: 281 return doWithHierarchyFacts( 282 visitDefault, 283 node, 284 HierarchyFacts.ClassOrFunctionExcludes, 285 HierarchyFacts.ClassOrFunctionIncludes); 286 default: 287 return visitEachChild(node, visitor, context); 288 } 289 } 290 291 function visitAwaitExpression(node: AwaitExpression): Expression { 292 if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { 293 return setOriginalNode( 294 setTextRange( 295 factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(visitNode(node.expression, visitor, isExpression))), 296 /*location*/ node 297 ), 298 node 299 ); 300 } 301 return visitEachChild(node, visitor, context); 302 } 303 304 function visitYieldExpression(node: YieldExpression) { 305 if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { 306 if (node.asteriskToken) { 307 const expression = visitNode(Debug.checkDefined(node.expression), visitor, isExpression); 308 309 return setOriginalNode( 310 setTextRange( 311 factory.createYieldExpression( 312 /*asteriskToken*/ undefined, 313 emitHelpers().createAwaitHelper( 314 factory.updateYieldExpression( 315 node, 316 node.asteriskToken, 317 setTextRange( 318 emitHelpers().createAsyncDelegatorHelper( 319 setTextRange( 320 emitHelpers().createAsyncValuesHelper(expression), 321 expression 322 ) 323 ), 324 expression 325 ) 326 ) 327 ) 328 ), 329 node 330 ), 331 node 332 ); 333 } 334 335 return setOriginalNode( 336 setTextRange( 337 factory.createYieldExpression( 338 /*asteriskToken*/ undefined, 339 createDownlevelAwait( 340 node.expression 341 ? visitNode(node.expression, visitor, isExpression) 342 : factory.createVoidZero() 343 ) 344 ), 345 node 346 ), 347 node 348 ); 349 } 350 351 return visitEachChild(node, visitor, context); 352 } 353 354 function visitReturnStatement(node: ReturnStatement) { 355 if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) { 356 return factory.updateReturnStatement(node, createDownlevelAwait( 357 node.expression ? visitNode(node.expression, visitor, isExpression) : factory.createVoidZero() 358 )); 359 } 360 361 return visitEachChild(node, visitor, context); 362 } 363 364 function visitLabeledStatement(node: LabeledStatement) { 365 if (enclosingFunctionFlags & FunctionFlags.Async) { 366 const statement = unwrapInnermostStatementOfLabel(node); 367 if (statement.kind === SyntaxKind.ForOfStatement && (statement as ForOfStatement).awaitModifier) { 368 return visitForOfStatement(statement as ForOfStatement, node); 369 } 370 return factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node); 371 } 372 return visitEachChild(node, visitor, context); 373 } 374 375 function chunkObjectLiteralElements(elements: readonly ObjectLiteralElementLike[]): Expression[] { 376 let chunkObject: ObjectLiteralElementLike[] | undefined; 377 const objects: Expression[] = []; 378 for (const e of elements) { 379 if (e.kind === SyntaxKind.SpreadAssignment) { 380 if (chunkObject) { 381 objects.push(factory.createObjectLiteralExpression(chunkObject)); 382 chunkObject = undefined; 383 } 384 const target = e.expression; 385 objects.push(visitNode(target, visitor, isExpression)); 386 } 387 else { 388 chunkObject = append(chunkObject, e.kind === SyntaxKind.PropertyAssignment 389 ? factory.createPropertyAssignment(e.name, visitNode(e.initializer, visitor, isExpression)) 390 : visitNode(e, visitor, isObjectLiteralElementLike)); 391 } 392 } 393 if (chunkObject) { 394 objects.push(factory.createObjectLiteralExpression(chunkObject)); 395 } 396 397 return objects; 398 } 399 400 function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression { 401 if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 402 // spread elements emit like so: 403 // non-spread elements are chunked together into object literals, and then all are passed to __assign: 404 // { a, ...o, b } => __assign(__assign({a}, o), {b}); 405 // If the first element is a spread element, then the first argument to __assign is {}: 406 // { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2) 407 // 408 // We cannot call __assign with more than two elements, since any element could cause side effects. For 409 // example: 410 // var k = { a: 1, b: 2 }; 411 // var o = { a: 3, ...k, b: k.a++ }; 412 // // expected: { a: 1, b: 1 } 413 // If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before 414 // `k` is spread and we end up with `{ a: 2, b: 1 }`. 415 // 416 // This also occurs for spread elements, not just property assignments: 417 // var k = { a: 1, get b() { l = { z: 9 }; return 2; } }; 418 // var l = { c: 3 }; 419 // var o = { ...k, ...l }; 420 // // expected: { a: 1, b: 2, z: 9 } 421 // If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we 422 // end up with `{ a: 1, b: 2, c: 3 }` 423 const objects = chunkObjectLiteralElements(node.properties); 424 if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { 425 objects.unshift(factory.createObjectLiteralExpression()); 426 } 427 let expression: Expression = objects[0]; 428 if (objects.length > 1) { 429 for (let i = 1; i < objects.length; i++) { 430 expression = emitHelpers().createAssignHelper([expression, objects[i]]); 431 } 432 return expression; 433 } 434 else { 435 return emitHelpers().createAssignHelper(objects); 436 } 437 } 438 return visitEachChild(node, visitor, context); 439 } 440 441 function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement { 442 return visitEachChild(node, visitorWithUnusedExpressionResult, context); 443 } 444 445 /** 446 * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the 447 * expression of an `ExpressionStatement`). 448 */ 449 function visitParenthesizedExpression(node: ParenthesizedExpression, expressionResultIsUnused: boolean): ParenthesizedExpression { 450 return visitEachChild(node, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, context); 451 } 452 453 function visitSourceFile(node: SourceFile): SourceFile { 454 const ancestorFacts = enterSubtree( 455 HierarchyFacts.SourceFileExcludes, 456 isEffectiveStrictModeSourceFile(node, compilerOptions) ? 457 HierarchyFacts.StrictModeSourceFileIncludes : 458 HierarchyFacts.SourceFileIncludes); 459 exportedVariableStatement = false; 460 const visited = visitEachChild(node, visitor, context); 461 const statement = concatenate(visited.statements, taggedTemplateStringDeclarations && [ 462 factory.createVariableStatement(/*modifiers*/ undefined, 463 factory.createVariableDeclarationList(taggedTemplateStringDeclarations)) 464 ]); 465 const result = factory.updateSourceFile(visited, setTextRange(factory.createNodeArray(statement), node.statements)); 466 exitSubtree(ancestorFacts); 467 return result; 468 } 469 470 function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { 471 return processTaggedTemplateExpression( 472 context, 473 node, 474 visitor, 475 currentSourceFile, 476 recordTaggedTemplateString, 477 ProcessLevel.LiftRestriction 478 ); 479 } 480 481 /** 482 * Visits a BinaryExpression that contains a destructuring assignment. 483 * 484 * @param node A BinaryExpression node. 485 * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the 486 * expression of an `ExpressionStatement`). 487 */ 488 function visitBinaryExpression(node: BinaryExpression, expressionResultIsUnused: boolean): Expression { 489 if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 490 return flattenDestructuringAssignment( 491 node, 492 visitor, 493 context, 494 FlattenLevel.ObjectRest, 495 !expressionResultIsUnused 496 ); 497 } 498 if (node.operatorToken.kind === SyntaxKind.CommaToken) { 499 return factory.updateBinaryExpression( 500 node, 501 visitNode(node.left, visitorWithUnusedExpressionResult, isExpression), 502 node.operatorToken, 503 visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression) 504 ); 505 } 506 return visitEachChild(node, visitor, context); 507 } 508 509 /** 510 * @param expressionResultIsUnused Indicates the result of an expression is unused by the parent node (i.e., the left side of a comma or the 511 * expression of an `ExpressionStatement`). 512 */ 513 function visitCommaListExpression(node: CommaListExpression, expressionResultIsUnused: boolean): Expression { 514 if (expressionResultIsUnused) { 515 return visitEachChild(node, visitorWithUnusedExpressionResult, context); 516 } 517 let result: Expression[] | undefined; 518 for (let i = 0; i < node.elements.length; i++) { 519 const element = node.elements[i]; 520 const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); 521 if (result || visited !== element) { 522 result ||= node.elements.slice(0, i); 523 result.push(visited); 524 } 525 } 526 const elements = result ? setTextRange(factory.createNodeArray(result), node.elements) : node.elements; 527 return factory.updateCommaListExpression(node, elements); 528 } 529 530 function visitCatchClause(node: CatchClause) { 531 if (node.variableDeclaration && 532 isBindingPattern(node.variableDeclaration.name) && 533 node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 534 const name = factory.getGeneratedNameForNode(node.variableDeclaration.name); 535 const updatedDecl = factory.updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*exclamationToken*/ undefined, /*type*/ undefined, name); 536 const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest); 537 let block = visitNode(node.block, visitor, isBlock); 538 if (some(visitedBindings)) { 539 block = factory.updateBlock(block, [ 540 factory.createVariableStatement(/*modifiers*/ undefined, visitedBindings), 541 ...block.statements, 542 ]); 543 } 544 return factory.updateCatchClause( 545 node, 546 factory.updateVariableDeclaration(node.variableDeclaration, name, /*exclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined), 547 block); 548 } 549 return visitEachChild(node, visitor, context); 550 } 551 552 function visitVariableStatement(node: VariableStatement): VisitResult<VariableStatement> { 553 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 554 const savedExportedVariableStatement = exportedVariableStatement; 555 exportedVariableStatement = true; 556 const visited = visitEachChild(node, visitor, context); 557 exportedVariableStatement = savedExportedVariableStatement; 558 return visited; 559 } 560 return visitEachChild(node, visitor, context); 561 } 562 563 /** 564 * Visits a VariableDeclaration node with a binding pattern. 565 * 566 * @param node A VariableDeclaration node. 567 */ 568 function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> { 569 if (exportedVariableStatement) { 570 const savedExportedVariableStatement = exportedVariableStatement; 571 exportedVariableStatement = false; 572 const visited = visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ true); 573 exportedVariableStatement = savedExportedVariableStatement; 574 return visited; 575 } 576 return visitVariableDeclarationWorker(node, /*exportedVariableStatement*/ false); 577 } 578 579 function visitVariableDeclarationWorker(node: VariableDeclaration, exportedVariableStatement: boolean): VisitResult<VariableDeclaration> { 580 // If we are here it is because the name contains a binding pattern with a rest somewhere in it. 581 if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 582 return flattenDestructuringBinding( 583 node, 584 visitor, 585 context, 586 FlattenLevel.ObjectRest, 587 /*rval*/ undefined, 588 exportedVariableStatement 589 ); 590 } 591 return visitEachChild(node, visitor, context); 592 } 593 594 function visitForStatement(node: ForStatement): VisitResult<Statement> { 595 return factory.updateForStatement( 596 node, 597 visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer), 598 visitNode(node.condition, visitor, isExpression), 599 visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression), 600 visitIterationBody(node.statement, visitor, context) 601 ); 602 } 603 604 function visitVoidExpression(node: VoidExpression) { 605 return visitEachChild(node, visitorWithUnusedExpressionResult, context); 606 } 607 608 /** 609 * Visits a ForOfStatement and converts it into a ES2015-compatible ForOfStatement. 610 * 611 * @param node A ForOfStatement. 612 */ 613 function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult<Statement> { 614 const ancestorFacts = enterSubtree(HierarchyFacts.IterationStatementExcludes, HierarchyFacts.IterationStatementIncludes); 615 if (node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 616 node = transformForOfStatementWithObjectRest(node); 617 } 618 const result = node.awaitModifier ? 619 transformForAwaitOfStatement(node, outermostLabeledStatement, ancestorFacts) : 620 factory.restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement); 621 exitSubtree(ancestorFacts); 622 return result; 623 } 624 625 function transformForOfStatementWithObjectRest(node: ForOfStatement) { 626 const initializerWithoutParens = skipParentheses(node.initializer) as ForInitializer; 627 if (isVariableDeclarationList(initializerWithoutParens) || isAssignmentPattern(initializerWithoutParens)) { 628 let bodyLocation: TextRange | undefined; 629 let statementsLocation: TextRange | undefined; 630 const temp = factory.createTempVariable(/*recordTempVariable*/ undefined); 631 const statements: Statement[] = [createForOfBindingStatement(factory, initializerWithoutParens, temp)]; 632 if (isBlock(node.statement)) { 633 addRange(statements, node.statement.statements); 634 bodyLocation = node.statement; 635 statementsLocation = node.statement.statements; 636 } 637 else if (node.statement) { 638 append(statements, node.statement); 639 bodyLocation = node.statement; 640 statementsLocation = node.statement; 641 } 642 return factory.updateForOfStatement( 643 node, 644 node.awaitModifier, 645 setTextRange( 646 factory.createVariableDeclarationList( 647 [ 648 setTextRange(factory.createVariableDeclaration(temp), node.initializer) 649 ], 650 NodeFlags.Let 651 ), 652 node.initializer 653 ), 654 node.expression, 655 setTextRange( 656 factory.createBlock( 657 setTextRange(factory.createNodeArray(statements), statementsLocation), 658 /*multiLine*/ true 659 ), 660 bodyLocation 661 ) 662 ); 663 } 664 return node; 665 } 666 667 function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, nonUserCode: Identifier) { 668 const value = factory.createTempVariable(hoistVariableDeclaration); 669 const iteratorValueExpression = factory.createAssignment(value, boundValue); 670 const iteratorValueStatement = factory.createExpressionStatement(iteratorValueExpression); 671 setSourceMapRange(iteratorValueStatement, node.expression); 672 673 const exitNonUserCodeExpression = factory.createAssignment(nonUserCode, factory.createFalse()); 674 const exitNonUserCodeStatement = factory.createExpressionStatement(exitNonUserCodeExpression); 675 setSourceMapRange(exitNonUserCodeStatement, node.expression); 676 677 const enterNonUserCodeExpression = factory.createAssignment(nonUserCode, factory.createTrue()); 678 const enterNonUserCodeStatement = factory.createExpressionStatement(enterNonUserCodeExpression); 679 setSourceMapRange(exitNonUserCodeStatement, node.expression); 680 681 const statements: Statement[] = []; 682 const binding = createForOfBindingStatement(factory, node.initializer, value); 683 statements.push(visitNode(binding, visitor, isStatement)); 684 685 let bodyLocation: TextRange | undefined; 686 let statementsLocation: TextRange | undefined; 687 const statement = visitIterationBody(node.statement, visitor, context); 688 if (isBlock(statement)) { 689 addRange(statements, statement.statements); 690 bodyLocation = statement; 691 statementsLocation = statement.statements; 692 } 693 else { 694 statements.push(statement); 695 } 696 697 const body = setEmitFlags( 698 setTextRange( 699 factory.createBlock( 700 setTextRange(factory.createNodeArray(statements), statementsLocation), 701 /*multiLine*/ true 702 ), 703 bodyLocation 704 ), 705 EmitFlags.NoSourceMap | EmitFlags.NoTokenSourceMaps 706 ); 707 708 return factory.createBlock([ 709 iteratorValueStatement, 710 exitNonUserCodeStatement, 711 factory.createTryStatement( 712 body, 713 /*catchClause*/ undefined, 714 factory.createBlock([ 715 enterNonUserCodeStatement 716 ]) 717 ) 718 ]); 719 } 720 721 function createDownlevelAwait(expression: Expression) { 722 return enclosingFunctionFlags & FunctionFlags.Generator 723 ? factory.createYieldExpression(/*asteriskToken*/ undefined, emitHelpers().createAwaitHelper(expression)) 724 : factory.createAwaitExpression(expression); 725 } 726 727 function transformForAwaitOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts) { 728 const expression = visitNode(node.expression, visitor, isExpression); 729 const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); 730 const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); 731 const nonUserCode = factory.createTempVariable(/*recordTempVariable*/ undefined); 732 const done = factory.createTempVariable(hoistVariableDeclaration); 733 const errorRecord = factory.createUniqueName("e"); 734 const catchVariable = factory.getGeneratedNameForNode(errorRecord); 735 const returnMethod = factory.createTempVariable(/*recordTempVariable*/ undefined); 736 const callValues = setTextRange(emitHelpers().createAsyncValuesHelper(expression), node.expression); 737 const callNext = factory.createCallExpression(factory.createPropertyAccessExpression(iterator, "next"), /*typeArguments*/ undefined, []); 738 const getDone = factory.createPropertyAccessExpression(result, "done"); 739 const getValue = factory.createPropertyAccessExpression(result, "value"); 740 const callReturn = factory.createFunctionCallCall(returnMethod, iterator, []); 741 742 hoistVariableDeclaration(errorRecord); 743 hoistVariableDeclaration(returnMethod); 744 745 // if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration 746 const initializer = ancestorFacts & HierarchyFacts.IterationContainer ? 747 factory.inlineExpressions([factory.createAssignment(errorRecord, factory.createVoidZero()), callValues]) : 748 callValues; 749 750 const forStatement = setEmitFlags( 751 setTextRange( 752 factory.createForStatement( 753 /*initializer*/ setEmitFlags( 754 setTextRange( 755 factory.createVariableDeclarationList([ 756 factory.createVariableDeclaration(nonUserCode, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createTrue()), 757 setTextRange(factory.createVariableDeclaration(iterator, /*exclamationToken*/ undefined, /*type*/ undefined, initializer), node.expression), 758 factory.createVariableDeclaration(result) 759 ]), 760 node.expression 761 ), 762 EmitFlags.NoHoisting 763 ), 764 /*condition*/ factory.inlineExpressions([ 765 factory.createAssignment(result, createDownlevelAwait(callNext)), 766 factory.createAssignment(done, getDone), 767 factory.createLogicalNot(done) 768 ]), 769 /*incrementor*/ undefined, 770 /*statement*/ convertForOfStatementHead(node, getValue, nonUserCode) 771 ), 772 /*location*/ node 773 ), 774 EmitFlags.NoTokenTrailingSourceMaps 775 ); 776 setOriginalNode(forStatement, node); 777 778 return factory.createTryStatement( 779 factory.createBlock([ 780 factory.restoreEnclosingLabel( 781 forStatement, 782 outermostLabeledStatement 783 ) 784 ]), 785 factory.createCatchClause( 786 factory.createVariableDeclaration(catchVariable), 787 setEmitFlags( 788 factory.createBlock([ 789 factory.createExpressionStatement( 790 factory.createAssignment( 791 errorRecord, 792 factory.createObjectLiteralExpression([ 793 factory.createPropertyAssignment("error", catchVariable) 794 ]) 795 ) 796 ) 797 ]), 798 EmitFlags.SingleLine 799 ) 800 ), 801 factory.createBlock([ 802 factory.createTryStatement( 803 /*tryBlock*/ factory.createBlock([ 804 setEmitFlags( 805 factory.createIfStatement( 806 factory.createLogicalAnd( 807 factory.createLogicalAnd( 808 factory.createLogicalNot(nonUserCode), 809 factory.createLogicalNot(done), 810 ), 811 factory.createAssignment( 812 returnMethod, 813 factory.createPropertyAccessExpression(iterator, "return") 814 ) 815 ), 816 factory.createExpressionStatement(createDownlevelAwait(callReturn)) 817 ), 818 EmitFlags.SingleLine 819 ) 820 ]), 821 /*catchClause*/ undefined, 822 /*finallyBlock*/ setEmitFlags( 823 factory.createBlock([ 824 setEmitFlags( 825 factory.createIfStatement( 826 errorRecord, 827 factory.createThrowStatement( 828 factory.createPropertyAccessExpression(errorRecord, "error") 829 ) 830 ), 831 EmitFlags.SingleLine 832 ) 833 ]), 834 EmitFlags.SingleLine 835 ) 836 ) 837 ]) 838 ); 839 } 840 841 function parameterVisitor(node: Node) { 842 Debug.assertNode(node, isParameter); 843 return visitParameter(node); 844 } 845 846 function visitParameter(node: ParameterDeclaration): ParameterDeclaration { 847 if (parametersWithPrecedingObjectRestOrSpread?.has(node)) { 848 return factory.updateParameterDeclaration( 849 node, 850 /*modifiers*/ undefined, 851 node.dotDotDotToken, 852 isBindingPattern(node.name) ? factory.getGeneratedNameForNode(node) : node.name, 853 /*questionToken*/ undefined, 854 /*type*/ undefined, 855 /*initializer*/ undefined 856 ); 857 } 858 if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 859 // Binding patterns are converted into a generated name and are 860 // evaluated inside the function body. 861 return factory.updateParameterDeclaration( 862 node, 863 /*modifiers*/ undefined, 864 node.dotDotDotToken, 865 factory.getGeneratedNameForNode(node), 866 /*questionToken*/ undefined, 867 /*type*/ undefined, 868 visitNode(node.initializer, visitor, isExpression) 869 ); 870 } 871 return visitEachChild(node, visitor, context); 872 } 873 874 function collectParametersWithPrecedingObjectRestOrSpread(node: SignatureDeclaration) { 875 let parameters: Set<ParameterDeclaration> | undefined; 876 for (const parameter of node.parameters) { 877 if (parameters) { 878 parameters.add(parameter); 879 } 880 else if (parameter.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 881 parameters = new Set(); 882 } 883 } 884 return parameters; 885 } 886 887 function visitConstructorDeclaration(node: ConstructorDeclaration) { 888 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 889 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 890 enclosingFunctionFlags = getFunctionFlags(node); 891 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 892 const updated = factory.updateConstructorDeclaration( 893 node, 894 node.modifiers, 895 visitParameterList(node.parameters, parameterVisitor, context), 896 transformFunctionBody(node) 897 ); 898 enclosingFunctionFlags = savedEnclosingFunctionFlags; 899 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 900 return updated; 901 } 902 903 function visitGetAccessorDeclaration(node: GetAccessorDeclaration) { 904 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 905 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 906 enclosingFunctionFlags = getFunctionFlags(node); 907 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 908 const updated = factory.updateGetAccessorDeclaration( 909 node, 910 node.modifiers, 911 visitNode(node.name, visitor, isPropertyName), 912 visitParameterList(node.parameters, parameterVisitor, context), 913 /*type*/ undefined, 914 transformFunctionBody(node) 915 ); 916 enclosingFunctionFlags = savedEnclosingFunctionFlags; 917 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 918 return updated; 919 } 920 921 function visitSetAccessorDeclaration(node: SetAccessorDeclaration) { 922 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 923 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 924 enclosingFunctionFlags = getFunctionFlags(node); 925 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 926 const updated = factory.updateSetAccessorDeclaration( 927 node, 928 node.modifiers, 929 visitNode(node.name, visitor, isPropertyName), 930 visitParameterList(node.parameters, parameterVisitor, context), 931 transformFunctionBody(node) 932 ); 933 enclosingFunctionFlags = savedEnclosingFunctionFlags; 934 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 935 return updated; 936 } 937 938 function visitMethodDeclaration(node: MethodDeclaration) { 939 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 940 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 941 enclosingFunctionFlags = getFunctionFlags(node); 942 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 943 const updated = factory.updateMethodDeclaration( 944 node, 945 enclosingFunctionFlags & FunctionFlags.Generator 946 ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifierLike) 947 : node.modifiers, 948 enclosingFunctionFlags & FunctionFlags.Async 949 ? undefined 950 : node.asteriskToken, 951 visitNode(node.name, visitor, isPropertyName), 952 visitNode<Token<SyntaxKind.QuestionToken>>(/*questionToken*/ undefined, visitor, isToken), 953 /*typeParameters*/ undefined, 954 visitParameterList(node.parameters, parameterVisitor, context), 955 /*type*/ undefined, 956 enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator 957 ? transformAsyncGeneratorFunctionBody(node) 958 : transformFunctionBody(node) 959 ); 960 enclosingFunctionFlags = savedEnclosingFunctionFlags; 961 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 962 return updated; 963 } 964 965 function visitFunctionDeclaration(node: FunctionDeclaration) { 966 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 967 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 968 enclosingFunctionFlags = getFunctionFlags(node); 969 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 970 const updated = factory.updateFunctionDeclaration( 971 node, 972 enclosingFunctionFlags & FunctionFlags.Generator 973 ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifier) 974 : node.modifiers, 975 enclosingFunctionFlags & FunctionFlags.Async 976 ? undefined 977 : node.asteriskToken, 978 node.name, 979 /*typeParameters*/ undefined, 980 visitParameterList(node.parameters, parameterVisitor, context), 981 /*type*/ undefined, 982 enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator 983 ? transformAsyncGeneratorFunctionBody(node) 984 : transformFunctionBody(node) 985 ); 986 enclosingFunctionFlags = savedEnclosingFunctionFlags; 987 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 988 return updated; 989 } 990 991 function visitArrowFunction(node: ArrowFunction) { 992 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 993 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 994 enclosingFunctionFlags = getFunctionFlags(node); 995 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 996 const updated = factory.updateArrowFunction( 997 node, 998 node.modifiers, 999 /*typeParameters*/ undefined, 1000 visitParameterList(node.parameters, parameterVisitor, context), 1001 /*type*/ undefined, 1002 node.equalsGreaterThanToken, 1003 transformFunctionBody(node), 1004 ); 1005 enclosingFunctionFlags = savedEnclosingFunctionFlags; 1006 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 1007 return updated; 1008 } 1009 1010 function visitFunctionExpression(node: FunctionExpression) { 1011 const savedEnclosingFunctionFlags = enclosingFunctionFlags; 1012 const savedParametersWithPrecedingObjectRestOrSpread = parametersWithPrecedingObjectRestOrSpread; 1013 enclosingFunctionFlags = getFunctionFlags(node); 1014 parametersWithPrecedingObjectRestOrSpread = collectParametersWithPrecedingObjectRestOrSpread(node); 1015 const updated = factory.updateFunctionExpression( 1016 node, 1017 enclosingFunctionFlags & FunctionFlags.Generator 1018 ? visitNodes(node.modifiers, visitorNoAsyncModifier, isModifier) 1019 : node.modifiers, 1020 enclosingFunctionFlags & FunctionFlags.Async 1021 ? undefined 1022 : node.asteriskToken, 1023 node.name, 1024 /*typeParameters*/ undefined, 1025 visitParameterList(node.parameters, parameterVisitor, context), 1026 /*type*/ undefined, 1027 enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator 1028 ? transformAsyncGeneratorFunctionBody(node) 1029 : transformFunctionBody(node) 1030 ); 1031 enclosingFunctionFlags = savedEnclosingFunctionFlags; 1032 parametersWithPrecedingObjectRestOrSpread = savedParametersWithPrecedingObjectRestOrSpread; 1033 return updated; 1034 } 1035 1036 function transformAsyncGeneratorFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { 1037 resumeLexicalEnvironment(); 1038 const statements: Statement[] = []; 1039 const statementOffset = factory.copyPrologue(node.body!.statements, statements, /*ensureUseStrict*/ false, visitor); 1040 appendObjectRestAssignmentsIfNeeded(statements, node); 1041 1042 const savedCapturedSuperProperties = capturedSuperProperties; 1043 const savedHasSuperElementAccess = hasSuperElementAccess; 1044 capturedSuperProperties = new Set(); 1045 hasSuperElementAccess = false; 1046 1047 const returnStatement = factory.createReturnStatement( 1048 emitHelpers().createAsyncGeneratorHelper( 1049 factory.createFunctionExpression( 1050 /*modifiers*/ undefined, 1051 factory.createToken(SyntaxKind.AsteriskToken), 1052 node.name && factory.getGeneratedNameForNode(node.name), 1053 /*typeParameters*/ undefined, 1054 /*parameters*/ [], 1055 /*type*/ undefined, 1056 factory.updateBlock( 1057 node.body!, 1058 visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset) 1059 ) 1060 ), 1061 !!(hierarchyFacts & HierarchyFacts.HasLexicalThis) 1062 ) 1063 ); 1064 1065 // Minor optimization, emit `_super` helper to capture `super` access in an arrow. 1066 // This step isn't needed if we eventually transform this to ES5. 1067 const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync | NodeCheckFlags.MethodWithSuperPropertyAccessInAsync); 1068 1069 if (emitSuperHelpers) { 1070 enableSubstitutionForAsyncMethodsWithSuper(); 1071 const variableStatement = createSuperAccessVariableStatement(factory, resolver, node, capturedSuperProperties); 1072 substitutedSuperAccessors[getNodeId(variableStatement)] = true; 1073 insertStatementsAfterStandardPrologue(statements, [variableStatement]); 1074 } 1075 1076 statements.push(returnStatement); 1077 1078 insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); 1079 const block = factory.updateBlock(node.body!, statements); 1080 1081 if (emitSuperHelpers && hasSuperElementAccess) { 1082 if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) { 1083 addEmitHelper(block, advancedAsyncSuperHelper); 1084 } 1085 else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.MethodWithSuperPropertyAccessInAsync) { 1086 addEmitHelper(block, asyncSuperHelper); 1087 } 1088 } 1089 1090 capturedSuperProperties = savedCapturedSuperProperties; 1091 hasSuperElementAccess = savedHasSuperElementAccess; 1092 1093 return block; 1094 } 1095 1096 function transformFunctionBody(node: FunctionDeclaration | FunctionExpression | ConstructorDeclaration | MethodDeclaration | AccessorDeclaration): FunctionBody; 1097 function transformFunctionBody(node: ArrowFunction): ConciseBody; 1098 function transformFunctionBody(node: FunctionLikeDeclaration): ConciseBody { 1099 resumeLexicalEnvironment(); 1100 let statementOffset = 0; 1101 const statements: Statement[] = []; 1102 const body = visitNode(node.body, visitor, isConciseBody) ?? factory.createBlock([]); 1103 if (isBlock(body)) { 1104 statementOffset = factory.copyPrologue(body.statements, statements, /*ensureUseStrict*/ false, visitor); 1105 } 1106 addRange(statements, appendObjectRestAssignmentsIfNeeded(/*statements*/ undefined, node)); 1107 1108 const leadingStatements = endLexicalEnvironment(); 1109 if (statementOffset > 0 || some(statements) || some(leadingStatements)) { 1110 const block = factory.converters.convertToFunctionBlock(body, /*multiLine*/ true); 1111 insertStatementsAfterStandardPrologue(statements, leadingStatements); 1112 addRange(statements, block.statements.slice(statementOffset)); 1113 return factory.updateBlock(block, setTextRange(factory.createNodeArray(statements), block.statements)); 1114 } 1115 return body; 1116 } 1117 1118 function appendObjectRestAssignmentsIfNeeded(statements: Statement[] | undefined, node: FunctionLikeDeclaration): Statement[] | undefined { 1119 let containsPrecedingObjectRestOrSpread = false; 1120 for (const parameter of node.parameters) { 1121 if (containsPrecedingObjectRestOrSpread) { 1122 if (isBindingPattern(parameter.name)) { 1123 // In cases where a binding pattern is simply '[]' or '{}', 1124 // we usually don't want to emit a var declaration; however, in the presence 1125 // of an initializer, we must emit that expression to preserve side effects. 1126 // 1127 // NOTE: see `insertDefaultValueAssignmentForBindingPattern` in es2015.ts 1128 if (parameter.name.elements.length > 0) { 1129 const declarations = flattenDestructuringBinding( 1130 parameter, 1131 visitor, 1132 context, 1133 FlattenLevel.All, 1134 factory.getGeneratedNameForNode(parameter)); 1135 if (some(declarations)) { 1136 const declarationList = factory.createVariableDeclarationList(declarations); 1137 const statement = factory.createVariableStatement(/*modifiers*/ undefined, declarationList); 1138 setEmitFlags(statement, EmitFlags.CustomPrologue); 1139 statements = append(statements, statement); 1140 } 1141 } 1142 else if (parameter.initializer) { 1143 const name = factory.getGeneratedNameForNode(parameter); 1144 const initializer = visitNode(parameter.initializer, visitor, isExpression); 1145 const assignment = factory.createAssignment(name, initializer); 1146 const statement = factory.createExpressionStatement(assignment); 1147 setEmitFlags(statement, EmitFlags.CustomPrologue); 1148 statements = append(statements, statement); 1149 } 1150 } 1151 else if (parameter.initializer) { 1152 // Converts a parameter initializer into a function body statement, i.e.: 1153 // 1154 // function f(x = 1) { } 1155 // 1156 // becomes 1157 // 1158 // function f(x) { 1159 // if (typeof x === "undefined") { x = 1; } 1160 // } 1161 1162 const name = factory.cloneNode(parameter.name); 1163 setTextRange(name, parameter.name); 1164 setEmitFlags(name, EmitFlags.NoSourceMap); 1165 1166 const initializer = visitNode(parameter.initializer, visitor, isExpression); 1167 addEmitFlags(initializer, EmitFlags.NoSourceMap | EmitFlags.NoComments); 1168 1169 const assignment = factory.createAssignment(name, initializer); 1170 setTextRange(assignment, parameter); 1171 setEmitFlags(assignment, EmitFlags.NoComments); 1172 1173 const block = factory.createBlock([factory.createExpressionStatement(assignment)]); 1174 setTextRange(block, parameter); 1175 setEmitFlags(block, EmitFlags.SingleLine | EmitFlags.NoTrailingSourceMap | EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); 1176 1177 const typeCheck = factory.createTypeCheck(factory.cloneNode(parameter.name), "undefined"); 1178 const statement = factory.createIfStatement(typeCheck, block); 1179 startOnNewLine(statement); 1180 setTextRange(statement, parameter); 1181 setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoTrailingSourceMap | EmitFlags.CustomPrologue | EmitFlags.NoComments); 1182 statements = append(statements, statement); 1183 } 1184 } 1185 else if (parameter.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { 1186 containsPrecedingObjectRestOrSpread = true; 1187 const declarations = flattenDestructuringBinding( 1188 parameter, 1189 visitor, 1190 context, 1191 FlattenLevel.ObjectRest, 1192 factory.getGeneratedNameForNode(parameter), 1193 /*doNotRecordTempVariablesInLine*/ false, 1194 /*skipInitializer*/ true, 1195 ); 1196 if (some(declarations)) { 1197 const declarationList = factory.createVariableDeclarationList(declarations); 1198 const statement = factory.createVariableStatement(/*modifiers*/ undefined, declarationList); 1199 setEmitFlags(statement, EmitFlags.CustomPrologue); 1200 statements = append(statements, statement); 1201 } 1202 } 1203 } 1204 return statements; 1205 } 1206 1207 function enableSubstitutionForAsyncMethodsWithSuper() { 1208 if ((enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper) === 0) { 1209 enabledSubstitutions |= ESNextSubstitutionFlags.AsyncMethodsWithSuper; 1210 1211 // We need to enable substitutions for call, property access, and element access 1212 // if we need to rewrite super calls. 1213 context.enableSubstitution(SyntaxKind.CallExpression); 1214 context.enableSubstitution(SyntaxKind.PropertyAccessExpression); 1215 context.enableSubstitution(SyntaxKind.ElementAccessExpression); 1216 1217 // We need to be notified when entering and exiting declarations that bind super. 1218 context.enableEmitNotification(SyntaxKind.ClassDeclaration); 1219 context.enableEmitNotification(SyntaxKind.MethodDeclaration); 1220 context.enableEmitNotification(SyntaxKind.GetAccessor); 1221 context.enableEmitNotification(SyntaxKind.SetAccessor); 1222 context.enableEmitNotification(SyntaxKind.Constructor); 1223 // We need to be notified when entering the generated accessor arrow functions. 1224 context.enableEmitNotification(SyntaxKind.VariableStatement); 1225 } 1226 } 1227 1228 /** 1229 * Called by the printer just before a node is printed. 1230 * 1231 * @param hint A hint as to the intended usage of the node. 1232 * @param node The node to be printed. 1233 * @param emitCallback The callback used to emit the node. 1234 */ 1235 function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { 1236 // If we need to support substitutions for `super` in an async method, 1237 // we should track it here. 1238 if (enabledSubstitutions & ESNextSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { 1239 const superContainerFlags = resolver.getNodeCheckFlags(node) & (NodeCheckFlags.MethodWithSuperPropertyAccessInAsync | NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync); 1240 if (superContainerFlags !== enclosingSuperContainerFlags) { 1241 const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; 1242 enclosingSuperContainerFlags = superContainerFlags; 1243 previousOnEmitNode(hint, node, emitCallback); 1244 enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags; 1245 return; 1246 } 1247 } 1248 // Disable substitution in the generated super accessor itself. 1249 else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) { 1250 const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags; 1251 enclosingSuperContainerFlags = 0 as NodeCheckFlags; 1252 previousOnEmitNode(hint, node, emitCallback); 1253 enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags; 1254 return; 1255 } 1256 1257 previousOnEmitNode(hint, node, emitCallback); 1258 } 1259 1260 /** 1261 * Hooks node substitutions. 1262 * 1263 * @param hint The context for the emitter. 1264 * @param node The node to substitute. 1265 */ 1266 function onSubstituteNode(hint: EmitHint, node: Node) { 1267 node = previousOnSubstituteNode(hint, node); 1268 if (hint === EmitHint.Expression && enclosingSuperContainerFlags) { 1269 return substituteExpression(node as Expression); 1270 } 1271 return node; 1272 } 1273 1274 function substituteExpression(node: Expression) { 1275 switch (node.kind) { 1276 case SyntaxKind.PropertyAccessExpression: 1277 return substitutePropertyAccessExpression(node as PropertyAccessExpression); 1278 case SyntaxKind.ElementAccessExpression: 1279 return substituteElementAccessExpression(node as ElementAccessExpression); 1280 case SyntaxKind.CallExpression: 1281 return substituteCallExpression(node as CallExpression); 1282 } 1283 return node; 1284 } 1285 1286 function substitutePropertyAccessExpression(node: PropertyAccessExpression) { 1287 if (node.expression.kind === SyntaxKind.SuperKeyword) { 1288 return setTextRange( 1289 factory.createPropertyAccessExpression( 1290 factory.createUniqueName("_super", GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel), 1291 node.name), 1292 node 1293 ); 1294 } 1295 return node; 1296 } 1297 1298 function substituteElementAccessExpression(node: ElementAccessExpression) { 1299 if (node.expression.kind === SyntaxKind.SuperKeyword) { 1300 return createSuperElementAccessInAsyncMethod( 1301 node.argumentExpression, 1302 node 1303 ); 1304 } 1305 return node; 1306 } 1307 1308 function substituteCallExpression(node: CallExpression): Expression { 1309 const expression = node.expression; 1310 if (isSuperProperty(expression)) { 1311 const argumentExpression = isPropertyAccessExpression(expression) 1312 ? substitutePropertyAccessExpression(expression) 1313 : substituteElementAccessExpression(expression); 1314 return factory.createCallExpression( 1315 factory.createPropertyAccessExpression(argumentExpression, "call"), 1316 /*typeArguments*/ undefined, 1317 [ 1318 factory.createThis(), 1319 ...node.arguments 1320 ] 1321 ); 1322 } 1323 return node; 1324 } 1325 1326 function isSuperContainer(node: Node) { 1327 const kind = node.kind; 1328 return kind === SyntaxKind.ClassDeclaration 1329 || kind === SyntaxKind.Constructor 1330 || kind === SyntaxKind.MethodDeclaration 1331 || kind === SyntaxKind.GetAccessor 1332 || kind === SyntaxKind.SetAccessor; 1333 } 1334 1335 function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression { 1336 if (enclosingSuperContainerFlags & NodeCheckFlags.MethodWithSuperPropertyAssignmentInAsync) { 1337 return setTextRange( 1338 factory.createPropertyAccessExpression( 1339 factory.createCallExpression( 1340 factory.createIdentifier("_superIndex"), 1341 /*typeArguments*/ undefined, 1342 [argumentExpression] 1343 ), 1344 "value" 1345 ), 1346 location 1347 ); 1348 } 1349 else { 1350 return setTextRange( 1351 factory.createCallExpression( 1352 factory.createIdentifier("_superIndex"), 1353 /*typeArguments*/ undefined, 1354 [argumentExpression] 1355 ), 1356 location 1357 ); 1358 } 1359 } 1360} 1361