1/*@internal*/ 2namespace ts { 3 4 export function transformModule(context: TransformationContext) { 5 interface AsynchronousDependencies { 6 aliasedModuleNames: Expression[]; 7 unaliasedModuleNames: Expression[]; 8 importAliasNames: ParameterDeclaration[]; 9 } 10 11 function getTransformModuleDelegate(moduleKind: ModuleKind): (node: SourceFile) => SourceFile { 12 switch (moduleKind) { 13 case ModuleKind.AMD: return transformAMDModule; 14 case ModuleKind.UMD: return transformUMDModule; 15 default: return transformCommonJSModule; 16 } 17 } 18 19 const { 20 factory, 21 getEmitHelperFactory: emitHelpers, 22 startLexicalEnvironment, 23 endLexicalEnvironment, 24 hoistVariableDeclaration 25 } = context; 26 27 const compilerOptions = context.getCompilerOptions(); 28 const resolver = context.getEmitResolver(); 29 const host = context.getEmitHost(); 30 const languageVersion = getEmitScriptTarget(compilerOptions); 31 const moduleKind = getEmitModuleKind(compilerOptions); 32 const previousOnSubstituteNode = context.onSubstituteNode; 33 const previousOnEmitNode = context.onEmitNode; 34 context.onSubstituteNode = onSubstituteNode; 35 context.onEmitNode = onEmitNode; 36 context.enableSubstitution(SyntaxKind.CallExpression); // Substitute calls to imported/exported symbols to avoid incorrect `this`. 37 context.enableSubstitution(SyntaxKind.TaggedTemplateExpression); // Substitute calls to imported/exported symbols to avoid incorrect `this`. 38 context.enableSubstitution(SyntaxKind.Identifier); // Substitutes expression identifiers with imported/exported symbols. 39 context.enableSubstitution(SyntaxKind.BinaryExpression); // Substitutes assignments to exported symbols. 40 context.enableSubstitution(SyntaxKind.ShorthandPropertyAssignment); // Substitutes shorthand property assignments for imported/exported symbols. 41 context.enableEmitNotification(SyntaxKind.SourceFile); // Restore state when substituting nodes in a file. 42 43 const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file. 44 const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found. 45 46 let currentSourceFile: SourceFile; // The current file. 47 let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file. 48 const noSubstitution: boolean[] = []; // Set of nodes for which substitution rules should be ignored. 49 let needUMDDynamicImportHelper: boolean; 50 51 return chainBundle(context, transformSourceFile); 52 53 /** 54 * Transforms the module aspects of a SourceFile. 55 * 56 * @param node The SourceFile node. 57 */ 58 function transformSourceFile(node: SourceFile) { 59 if (node.isDeclarationFile || 60 !(isEffectiveExternalModule(node, compilerOptions) || 61 node.transformFlags & TransformFlags.ContainsDynamicImport || 62 (isJsonSourceFile(node) && hasJsonModuleEmitEnabled(compilerOptions) && outFile(compilerOptions)))) { 63 return node; 64 } 65 66 currentSourceFile = node; 67 currentModuleInfo = collectExternalModuleInfo(context, node, resolver, compilerOptions); 68 moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo; 69 70 // Perform the transformation. 71 const transformModule = getTransformModuleDelegate(moduleKind); 72 const updated = transformModule(node); 73 currentSourceFile = undefined!; 74 currentModuleInfo = undefined!; 75 needUMDDynamicImportHelper = false; 76 return updated; 77 } 78 79 80 function shouldEmitUnderscoreUnderscoreESModule() { 81 if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile) && !isOnlyAnnotationsAreExportedOrImported(currentSourceFile, resolver)) { 82 return true; 83 } 84 return false; 85 } 86 87 /** 88 * Transforms a SourceFile into a CommonJS module. 89 * 90 * @param node The SourceFile node. 91 */ 92 function transformCommonJSModule(node: SourceFile) { 93 startLexicalEnvironment(); 94 95 const statements: Statement[] = []; 96 const ensureUseStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") || (!compilerOptions.noImplicitUseStrict && isExternalModule(currentSourceFile)); 97 const statementOffset = factory.copyPrologue(node.statements, statements, ensureUseStrict && !isJsonSourceFile(node), topLevelVisitor); 98 99 if (shouldEmitUnderscoreUnderscoreESModule()) { 100 append(statements, createUnderscoreUnderscoreESModule()); 101 } 102 if (length(currentModuleInfo.exportedNames)) { 103 const chunkSize = 50; 104 for (let i=0; i<currentModuleInfo.exportedNames!.length; i += chunkSize) { 105 append( 106 statements, 107 factory.createExpressionStatement( 108 reduceLeft( 109 currentModuleInfo.exportedNames!.slice(i, i + chunkSize), 110 (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), 111 factory.createVoidZero() as Expression 112 ) 113 ) 114 ); 115 } 116 } 117 118 append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement)); 119 addRange(statements, visitNodes(node.statements, topLevelVisitor, isStatement, statementOffset)); 120 addExportEqualsIfNeeded(statements, /*emitAsReturn*/ false); 121 insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); 122 123 const updated = factory.updateSourceFile(node, setTextRange(factory.createNodeArray(statements), node.statements)); 124 addEmitHelpers(updated, context.readEmitHelpers()); 125 return updated; 126 } 127 128 /** 129 * Transforms a SourceFile into an AMD module. 130 * 131 * @param node The SourceFile node. 132 */ 133 function transformAMDModule(node: SourceFile) { 134 const define = factory.createIdentifier("define"); 135 const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); 136 const jsonSourceFile = isJsonSourceFile(node) && node; 137 138 // An AMD define function has the following shape: 139 // 140 // define(id?, dependencies?, factory); 141 // 142 // This has the shape of the following: 143 // 144 // define(name, ["module1", "module2"], function (module1Alias) { ... } 145 // 146 // The location of the alias in the parameter list in the factory function needs to 147 // match the position of the module name in the dependency list. 148 // 149 // To ensure this is true in cases of modules with no aliases, e.g.: 150 // 151 // import "module" 152 // 153 // or 154 // 155 // /// <amd-dependency path= "a.css" /> 156 // 157 // we need to add modules without alias names to the end of the dependencies list 158 159 const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ true); 160 161 // Create an updated SourceFile: 162 // 163 // define(mofactory.updateSourceFile", "module2"], function ... 164 const updated = factory.updateSourceFile(node, 165 setTextRange( 166 factory.createNodeArray([ 167 factory.createExpressionStatement( 168 factory.createCallExpression( 169 define, 170 /*typeArguments*/ undefined, 171 [ 172 // Add the module name (if provided). 173 ...(moduleName ? [moduleName] : []), 174 175 // Add the dependency array argument: 176 // 177 // ["require", "exports", module1", "module2", ...] 178 factory.createArrayLiteralExpression(jsonSourceFile ? emptyArray : [ 179 factory.createStringLiteral("require"), 180 factory.createStringLiteral("exports"), 181 ...aliasedModuleNames, 182 ...unaliasedModuleNames 183 ]), 184 185 // Add the module body function argument: 186 // 187 // function (require, exports, module1, module2) ... 188 jsonSourceFile ? 189 jsonSourceFile.statements.length ? jsonSourceFile.statements[0].expression : factory.createObjectLiteralExpression() : 190 factory.createFunctionExpression( 191 /*modifiers*/ undefined, 192 /*asteriskToken*/ undefined, 193 /*name*/ undefined, 194 /*typeParameters*/ undefined, 195 [ 196 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), 197 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), 198 ...importAliasNames 199 ], 200 /*type*/ undefined, 201 transformAsynchronousModuleBody(node) 202 ) 203 ] 204 ) 205 ) 206 ]), 207 /*location*/ node.statements 208 ) 209 ); 210 211 addEmitHelpers(updated, context.readEmitHelpers()); 212 return updated; 213 } 214 215 /** 216 * Transforms a SourceFile into a UMD module. 217 * 218 * @param node The SourceFile node. 219 */ 220 function transformUMDModule(node: SourceFile) { 221 const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false); 222 const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions); 223 const umdHeader = factory.createFunctionExpression( 224 /*modifiers*/ undefined, 225 /*asteriskToken*/ undefined, 226 /*name*/ undefined, 227 /*typeParameters*/ undefined, 228 [factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")], 229 /*type*/ undefined, 230 setTextRange( 231 factory.createBlock( 232 [ 233 factory.createIfStatement( 234 factory.createLogicalAnd( 235 factory.createTypeCheck(factory.createIdentifier("module"), "object"), 236 factory.createTypeCheck(factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), "object") 237 ), 238 factory.createBlock([ 239 factory.createVariableStatement( 240 /*modifiers*/ undefined, 241 [ 242 factory.createVariableDeclaration( 243 "v", 244 /*exclamationToken*/ undefined, 245 /*type*/ undefined, 246 factory.createCallExpression( 247 factory.createIdentifier("factory"), 248 /*typeArguments*/ undefined, 249 [ 250 factory.createIdentifier("require"), 251 factory.createIdentifier("exports") 252 ] 253 ) 254 ) 255 ] 256 ), 257 setEmitFlags( 258 factory.createIfStatement( 259 factory.createStrictInequality( 260 factory.createIdentifier("v"), 261 factory.createIdentifier("undefined") 262 ), 263 factory.createExpressionStatement( 264 factory.createAssignment( 265 factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports"), 266 factory.createIdentifier("v") 267 ) 268 ) 269 ), 270 EmitFlags.SingleLine 271 ) 272 ]), 273 factory.createIfStatement( 274 factory.createLogicalAnd( 275 factory.createTypeCheck(factory.createIdentifier("define"), "function"), 276 factory.createPropertyAccessExpression(factory.createIdentifier("define"), "amd") 277 ), 278 factory.createBlock([ 279 factory.createExpressionStatement( 280 factory.createCallExpression( 281 factory.createIdentifier("define"), 282 /*typeArguments*/ undefined, 283 [ 284 // Add the module name (if provided). 285 ...(moduleName ? [moduleName] : []), 286 factory.createArrayLiteralExpression([ 287 factory.createStringLiteral("require"), 288 factory.createStringLiteral("exports"), 289 ...aliasedModuleNames, 290 ...unaliasedModuleNames 291 ]), 292 factory.createIdentifier("factory") 293 ] 294 ) 295 ) 296 ]) 297 ) 298 ) 299 ], 300 /*multiLine*/ true 301 ), 302 /*location*/ undefined 303 ) 304 ); 305 306 // Create an updated SourceFile: 307 // 308 // (function (factory) { 309 // if (typeof module === "object" && typeof module.exports === "object") { 310 // var v = factory(require, exports); 311 // if (v !== undefined) module.exports = v; 312 // } 313 // else if (typeof define === 'function' && define.amd) { 314 // define(["require", "exports"], factory); 315 // } 316 // })(function ...) 317 318 const updated = factory.updateSourceFile( 319 node, 320 setTextRange( 321 factory.createNodeArray([ 322 factory.createExpressionStatement( 323 factory.createCallExpression( 324 umdHeader, 325 /*typeArguments*/ undefined, 326 [ 327 // Add the module body function argument: 328 // 329 // function (require, exports) ... 330 factory.createFunctionExpression( 331 /*modifiers*/ undefined, 332 /*asteriskToken*/ undefined, 333 /*name*/ undefined, 334 /*typeParameters*/ undefined, 335 [ 336 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"), 337 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"), 338 ...importAliasNames 339 ], 340 /*type*/ undefined, 341 transformAsynchronousModuleBody(node) 342 ) 343 ] 344 ) 345 ) 346 ]), 347 /*location*/ node.statements 348 ) 349 ); 350 351 addEmitHelpers(updated, context.readEmitHelpers()); 352 return updated; 353 } 354 355 /** 356 * Collect the additional asynchronous dependencies for the module. 357 * 358 * @param node The source file. 359 * @param includeNonAmdDependencies A value indicating whether to include non-AMD dependencies. 360 */ 361 function collectAsynchronousDependencies(node: SourceFile, includeNonAmdDependencies: boolean): AsynchronousDependencies { 362 // names of modules with corresponding parameter in the factory function 363 const aliasedModuleNames: Expression[] = []; 364 365 // names of modules with no corresponding parameters in factory function 366 const unaliasedModuleNames: Expression[] = []; 367 368 // names of the parameters in the factory function; these 369 // parameters need to match the indexes of the corresponding 370 // module names in aliasedModuleNames. 371 const importAliasNames: ParameterDeclaration[] = []; 372 373 // Fill in amd-dependency tags 374 for (const amdDependency of node.amdDependencies) { 375 if (amdDependency.name) { 376 aliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); 377 importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, amdDependency.name)); 378 } 379 else { 380 unaliasedModuleNames.push(factory.createStringLiteral(amdDependency.path)); 381 } 382 } 383 384 for (const importNode of currentModuleInfo.externalImports) { 385 // Find the name of the external module 386 const externalModuleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); 387 388 // Find the name of the module alias, if there is one 389 const importAliasName = getLocalNameForExternalImport(factory, importNode, currentSourceFile); 390 // It is possible that externalModuleName is undefined if it is not string literal. 391 // This can happen in the invalid import syntax. 392 // E.g : "import * from alias from 'someLib';" 393 if (externalModuleName) { 394 if (includeNonAmdDependencies && importAliasName) { 395 // Set emitFlags on the name of the classDeclaration 396 // This is so that when printer will not substitute the identifier 397 setEmitFlags(importAliasName, EmitFlags.NoSubstitution); 398 aliasedModuleNames.push(externalModuleName); 399 importAliasNames.push(factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, importAliasName)); 400 } 401 else { 402 unaliasedModuleNames.push(externalModuleName); 403 } 404 } 405 } 406 407 return { aliasedModuleNames, unaliasedModuleNames, importAliasNames }; 408 } 409 410 function getAMDImportExpressionForImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) { 411 if (isImportEqualsDeclaration(node) || isExportDeclaration(node) || !getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions)) { 412 return undefined; 413 } 414 const name = getLocalNameForExternalImport(factory, node, currentSourceFile)!; // TODO: GH#18217 415 const expr = getHelperExpressionForImport(node, name); 416 if (expr === name) { 417 return undefined; 418 } 419 return factory.createExpressionStatement(factory.createAssignment(name, expr)); 420 } 421 422 /** 423 * Transforms a SourceFile into an AMD or UMD module body. 424 * 425 * @param node The SourceFile node. 426 */ 427 function transformAsynchronousModuleBody(node: SourceFile) { 428 startLexicalEnvironment(); 429 430 const statements: Statement[] = []; 431 const statementOffset = factory.copyPrologue(node.statements, statements, /*ensureUseStrict*/ !compilerOptions.noImplicitUseStrict, topLevelVisitor); 432 433 if (shouldEmitUnderscoreUnderscoreESModule()) { 434 append(statements, createUnderscoreUnderscoreESModule()); 435 } 436 if (length(currentModuleInfo.exportedNames)) { 437 append(statements, factory.createExpressionStatement(reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), factory.createVoidZero() as Expression))); 438 } 439 440 // Visit each statement of the module body. 441 append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement)); 442 if (moduleKind === ModuleKind.AMD) { 443 addRange(statements, mapDefined(currentModuleInfo.externalImports, getAMDImportExpressionForImport)); 444 } 445 addRange(statements, visitNodes(node.statements, topLevelVisitor, isStatement, statementOffset)); 446 447 // Append the 'export =' statement if provided. 448 addExportEqualsIfNeeded(statements, /*emitAsReturn*/ true); 449 450 // End the lexical environment for the module body 451 // and merge any new lexical declarations. 452 insertStatementsAfterStandardPrologue(statements, endLexicalEnvironment()); 453 454 const body = factory.createBlock(statements, /*multiLine*/ true); 455 if (needUMDDynamicImportHelper) { 456 addEmitHelper(body, dynamicImportUMDHelper); 457 } 458 459 return body; 460 } 461 462 /** 463 * Adds the down-level representation of `export=` to the statement list if one exists 464 * in the source file. 465 * 466 * @param statements The Statement list to modify. 467 * @param emitAsReturn A value indicating whether to emit the `export=` statement as a 468 * return statement. 469 */ 470 function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) { 471 if (currentModuleInfo.exportEquals) { 472 const expressionResult = visitNode(currentModuleInfo.exportEquals.expression, visitor); 473 if (expressionResult) { 474 if (emitAsReturn) { 475 const statement = factory.createReturnStatement(expressionResult); 476 setTextRange(statement, currentModuleInfo.exportEquals); 477 setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); 478 statements.push(statement); 479 } 480 else { 481 const statement = factory.createExpressionStatement( 482 factory.createAssignment( 483 factory.createPropertyAccessExpression( 484 factory.createIdentifier("module"), 485 "exports" 486 ), 487 expressionResult 488 ) 489 ); 490 491 setTextRange(statement, currentModuleInfo.exportEquals); 492 setEmitFlags(statement, EmitFlags.NoComments); 493 statements.push(statement); 494 } 495 } 496 } 497 } 498 499 // 500 // Top-Level Source Element Visitors 501 // 502 503 /** 504 * Visits a node at the top level of the source file. 505 * 506 * @param node The node to visit. 507 */ 508 function topLevelVisitor(node: Node): VisitResult<Node> { 509 switch (node.kind) { 510 case SyntaxKind.ImportDeclaration: 511 return visitImportDeclaration(node as ImportDeclaration); 512 513 case SyntaxKind.ImportEqualsDeclaration: 514 return visitImportEqualsDeclaration(node as ImportEqualsDeclaration); 515 516 case SyntaxKind.ExportDeclaration: 517 return visitExportDeclaration(node as ExportDeclaration); 518 519 case SyntaxKind.ExportAssignment: 520 return visitExportAssignment(node as ExportAssignment); 521 522 case SyntaxKind.VariableStatement: 523 return visitVariableStatement(node as VariableStatement); 524 525 case SyntaxKind.FunctionDeclaration: 526 return visitFunctionDeclaration(node as FunctionDeclaration); 527 528 case SyntaxKind.ClassDeclaration: 529 return visitClassDeclaration(node as ClassDeclaration); 530 531 case SyntaxKind.MergeDeclarationMarker: 532 return visitMergeDeclarationMarker(node as MergeDeclarationMarker); 533 534 case SyntaxKind.EndOfDeclarationMarker: 535 return visitEndOfDeclarationMarker(node as EndOfDeclarationMarker); 536 537 default: 538 return visitor(node); 539 } 540 } 541 542 function visitorWorker(node: Node, valueIsDiscarded: boolean): VisitResult<Node> { 543 // This visitor does not need to descend into the tree if there is no dynamic import, destructuring assignment, or update expression 544 // as export/import statements are only transformed at the top level of a file. 545 if (!(node.transformFlags & (TransformFlags.ContainsDynamicImport | TransformFlags.ContainsDestructuringAssignment | TransformFlags.ContainsUpdateExpressionForIdentifier))) { 546 return node; 547 } 548 549 switch (node.kind) { 550 case SyntaxKind.ForStatement: 551 return visitForStatement(node as ForStatement); 552 case SyntaxKind.ExpressionStatement: 553 return visitExpressionStatement(node as ExpressionStatement); 554 case SyntaxKind.ParenthesizedExpression: 555 return visitParenthesizedExpression(node as ParenthesizedExpression, valueIsDiscarded); 556 case SyntaxKind.PartiallyEmittedExpression: 557 return visitPartiallyEmittedExpression(node as PartiallyEmittedExpression, valueIsDiscarded); 558 case SyntaxKind.CallExpression: 559 if (isImportCall(node) && currentSourceFile.impliedNodeFormat === undefined) { 560 return visitImportCallExpression(node); 561 } 562 break; 563 case SyntaxKind.BinaryExpression: 564 if (isDestructuringAssignment(node)) { 565 return visitDestructuringAssignment(node, valueIsDiscarded); 566 } 567 break; 568 case SyntaxKind.PrefixUnaryExpression: 569 case SyntaxKind.PostfixUnaryExpression: 570 return visitPreOrPostfixUnaryExpression(node as PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded); 571 } 572 573 return visitEachChild(node, visitor, context); 574 } 575 576 function visitor(node: Node): VisitResult<Node> { 577 return visitorWorker(node, /*valueIsDiscarded*/ false); 578 } 579 580 function discardedValueVisitor(node: Node): VisitResult<Node> { 581 return visitorWorker(node, /*valueIsDiscarded*/ true); 582 } 583 584 function destructuringNeedsFlattening(node: Expression): boolean { 585 if (isObjectLiteralExpression(node)) { 586 for (const elem of node.properties) { 587 switch (elem.kind) { 588 case SyntaxKind.PropertyAssignment: 589 if (destructuringNeedsFlattening(elem.initializer)) { 590 return true; 591 } 592 break; 593 case SyntaxKind.ShorthandPropertyAssignment: 594 if (destructuringNeedsFlattening(elem.name)) { 595 return true; 596 } 597 break; 598 case SyntaxKind.SpreadAssignment: 599 if (destructuringNeedsFlattening(elem.expression)) { 600 return true; 601 } 602 break; 603 case SyntaxKind.MethodDeclaration: 604 case SyntaxKind.GetAccessor: 605 case SyntaxKind.SetAccessor: 606 return false; 607 default: Debug.assertNever(elem, "Unhandled object member kind"); 608 } 609 } 610 } 611 else if (isArrayLiteralExpression(node)) { 612 for (const elem of node.elements) { 613 if (isSpreadElement(elem)) { 614 if (destructuringNeedsFlattening(elem.expression)) { 615 return true; 616 } 617 } 618 else if (destructuringNeedsFlattening(elem)) { 619 return true; 620 } 621 } 622 } 623 else if (isIdentifier(node)) { 624 return length(getExports(node)) > (isExportName(node) ? 1 : 0); 625 } 626 return false; 627 } 628 629 function visitDestructuringAssignment(node: DestructuringAssignment, valueIsDiscarded: boolean): Expression { 630 if (destructuringNeedsFlattening(node.left)) { 631 return flattenDestructuringAssignment(node, visitor, context, FlattenLevel.All, !valueIsDiscarded, createAllExportExpressions); 632 } 633 return visitEachChild(node, visitor, context); 634 } 635 636 function visitForStatement(node: ForStatement) { 637 return factory.updateForStatement( 638 node, 639 visitNode(node.initializer, discardedValueVisitor, isForInitializer), 640 visitNode(node.condition, visitor, isExpression), 641 visitNode(node.incrementor, discardedValueVisitor, isExpression), 642 visitIterationBody(node.statement, visitor, context) 643 ); 644 } 645 646 function visitExpressionStatement(node: ExpressionStatement) { 647 return factory.updateExpressionStatement( 648 node, 649 visitNode(node.expression, discardedValueVisitor, isExpression) 650 ); 651 } 652 653 function visitParenthesizedExpression(node: ParenthesizedExpression, valueIsDiscarded: boolean) { 654 return factory.updateParenthesizedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); 655 } 656 657 function visitPartiallyEmittedExpression(node: PartiallyEmittedExpression, valueIsDiscarded: boolean) { 658 return factory.updatePartiallyEmittedExpression(node, visitNode(node.expression, valueIsDiscarded ? discardedValueVisitor : visitor, isExpression)); 659 } 660 661 function visitPreOrPostfixUnaryExpression(node: PrefixUnaryExpression | PostfixUnaryExpression, valueIsDiscarded: boolean) { 662 // When we see a prefix or postfix increment expression whose operand is an exported 663 // symbol, we should ensure all exports of that symbol are updated with the correct 664 // value. 665 // 666 // - We do not transform generated identifiers for any reason. 667 // - We do not transform identifiers tagged with the LocalName flag. 668 // - We do not transform identifiers that were originally the name of an enum or 669 // namespace due to how they are transformed in TypeScript. 670 // - We only transform identifiers that are exported at the top level. 671 if ((node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) 672 && isIdentifier(node.operand) 673 && !isGeneratedIdentifier(node.operand) 674 && !isLocalName(node.operand) 675 && !isDeclarationNameOfEnumOrNamespace(node.operand)) { 676 const exportedNames = getExports(node.operand); 677 if (exportedNames) { 678 let temp: Identifier | undefined; 679 let expression: Expression = visitNode(node.operand, visitor, isExpression); 680 if (isPrefixUnaryExpression(node)) { 681 expression = factory.updatePrefixUnaryExpression(node, expression); 682 } 683 else { 684 expression = factory.updatePostfixUnaryExpression(node, expression); 685 if (!valueIsDiscarded) { 686 temp = factory.createTempVariable(hoistVariableDeclaration); 687 expression = factory.createAssignment(temp, expression); 688 setTextRange(expression, node); 689 } 690 expression = factory.createComma(expression, factory.cloneNode(node.operand)); 691 setTextRange(expression, node); 692 } 693 694 for (const exportName of exportedNames) { 695 noSubstitution[getNodeId(expression)] = true; 696 expression = createExportExpression(exportName, expression); 697 setTextRange(expression, node); 698 } 699 700 if (temp) { 701 noSubstitution[getNodeId(expression)] = true; 702 expression = factory.createComma(expression, temp); 703 setTextRange(expression, node); 704 } 705 return expression; 706 } 707 } 708 return visitEachChild(node, visitor, context); 709 } 710 711 function visitImportCallExpression(node: ImportCall): Expression { 712 const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); 713 const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor); 714 // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. 715 const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; 716 const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis); 717 switch (compilerOptions.module) { 718 case ModuleKind.AMD: 719 return createImportCallExpressionAMD(argument, containsLexicalThis); 720 case ModuleKind.UMD: 721 return createImportCallExpressionUMD(argument ?? factory.createVoidZero(), containsLexicalThis); 722 case ModuleKind.CommonJS: 723 default: 724 return createImportCallExpressionCommonJS(argument); 725 } 726 } 727 728 function createImportCallExpressionUMD(arg: Expression, containsLexicalThis: boolean): Expression { 729 // (function (factory) { 730 // ... (regular UMD) 731 // } 732 // })(function (require, exports, useSyncRequire) { 733 // "use strict"; 734 // Object.defineProperty(exports, "__esModule", { value: true }); 735 // var __syncRequire = typeof module === "object" && typeof module.exports === "object"; 736 // var __resolved = new Promise(function (resolve) { resolve(); }); 737 // ..... 738 // __syncRequire 739 // ? __resolved.then(function () { return require(x); }) /*CommonJs Require*/ 740 // : new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/ 741 // }); 742 needUMDDynamicImportHelper = true; 743 if (isSimpleCopiableExpression(arg)) { 744 const argClone = isGeneratedIdentifier(arg) ? arg : isStringLiteral(arg) ? factory.createStringLiteralFromNode(arg) : setEmitFlags(setTextRange(factory.cloneNode(arg), arg), EmitFlags.NoComments); 745 return factory.createConditionalExpression( 746 /*condition*/ factory.createIdentifier("__syncRequire"), 747 /*questionToken*/ undefined, 748 /*whenTrue*/ createImportCallExpressionCommonJS(arg), 749 /*colonToken*/ undefined, 750 /*whenFalse*/ createImportCallExpressionAMD(argClone, containsLexicalThis) 751 ); 752 } 753 else { 754 const temp = factory.createTempVariable(hoistVariableDeclaration); 755 return factory.createComma(factory.createAssignment(temp, arg), factory.createConditionalExpression( 756 /*condition*/ factory.createIdentifier("__syncRequire"), 757 /*questionToken*/ undefined, 758 /*whenTrue*/ createImportCallExpressionCommonJS(temp, /* isInlineable */ true), 759 /*colonToken*/ undefined, 760 /*whenFalse*/ createImportCallExpressionAMD(temp, containsLexicalThis) 761 )); 762 } 763 } 764 765 function createImportCallExpressionAMD(arg: Expression | undefined, containsLexicalThis: boolean): Expression { 766 // improt("./blah") 767 // emit as 768 // define(["require", "exports", "blah"], function (require, exports) { 769 // ... 770 // new Promise(function (_a, _b) { require([x], _a, _b); }); /*Amd Require*/ 771 // }); 772 const resolve = factory.createUniqueName("resolve"); 773 const reject = factory.createUniqueName("reject"); 774 const parameters = [ 775 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve), 776 factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject) 777 ]; 778 const body = factory.createBlock([ 779 factory.createExpressionStatement( 780 factory.createCallExpression( 781 factory.createIdentifier("require"), 782 /*typeArguments*/ undefined, 783 [factory.createArrayLiteralExpression([arg || factory.createOmittedExpression()]), resolve, reject] 784 ) 785 ) 786 ]); 787 788 let func: FunctionExpression | ArrowFunction; 789 if (languageVersion >= ScriptTarget.ES2015) { 790 func = factory.createArrowFunction( 791 /*modifiers*/ undefined, 792 /*typeParameters*/ undefined, 793 parameters, 794 /*type*/ undefined, 795 /*equalsGreaterThanToken*/ undefined, 796 body); 797 } 798 else { 799 func = factory.createFunctionExpression( 800 /*modifiers*/ undefined, 801 /*asteriskToken*/ undefined, 802 /*name*/ undefined, 803 /*typeParameters*/ undefined, 804 parameters, 805 /*type*/ undefined, 806 body); 807 808 // if there is a lexical 'this' in the import call arguments, ensure we indicate 809 // that this new function expression indicates it captures 'this' so that the 810 // es2015 transformer will properly substitute 'this' with '_this'. 811 if (containsLexicalThis) { 812 setEmitFlags(func, EmitFlags.CapturesThis); 813 } 814 } 815 816 const promise = factory.createNewExpression(factory.createIdentifier("Promise"), /*typeArguments*/ undefined, [func]); 817 if (getESModuleInterop(compilerOptions)) { 818 return factory.createCallExpression(factory.createPropertyAccessExpression(promise, factory.createIdentifier("then")), /*typeArguments*/ undefined, [emitHelpers().createImportStarCallbackHelper()]); 819 } 820 return promise; 821 } 822 823 function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression { 824 // import(x) 825 // emit as 826 // var _a; 827 // (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/ 828 // We have to wrap require in then callback so that require is done in asynchronously 829 // if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately 830 // If the arg is not inlineable, we have to evaluate it in the current scope with a temp var 831 const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined; 832 const promiseResolveCall = factory.createCallExpression( 833 factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), 834 /*typeArguments*/ undefined, 835 /*argumentsArray*/ [], 836 ); 837 let requireCall: Expression = factory.createCallExpression( 838 factory.createIdentifier("require"), 839 /*typeArguments*/ undefined, 840 temp ? [temp] : arg ? [arg] : [], 841 ); 842 if (getESModuleInterop(compilerOptions)) { 843 requireCall = emitHelpers().createImportStarHelper(requireCall); 844 } 845 846 let func: FunctionExpression | ArrowFunction; 847 if (languageVersion >= ScriptTarget.ES2015) { 848 func = factory.createArrowFunction( 849 /*modifiers*/ undefined, 850 /*typeParameters*/ undefined, 851 /*parameters*/ [], 852 /*type*/ undefined, 853 /*equalsGreaterThanToken*/ undefined, 854 requireCall); 855 } 856 else { 857 func = factory.createFunctionExpression( 858 /*modifiers*/ undefined, 859 /*asteriskToken*/ undefined, 860 /*name*/ undefined, 861 /*typeParameters*/ undefined, 862 /*parameters*/ [], 863 /*type*/ undefined, 864 factory.createBlock([factory.createReturnStatement(requireCall)])); 865 } 866 867 const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]); 868 869 return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]); 870 } 871 872 function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) { 873 if (!getESModuleInterop(compilerOptions) || getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) { 874 return innerExpr; 875 } 876 if (getExportNeedsImportStarHelper(node)) { 877 return emitHelpers().createImportStarHelper(innerExpr); 878 } 879 return innerExpr; 880 } 881 882 function getHelperExpressionForImport(node: ImportDeclaration, innerExpr: Expression) { 883 if (!getESModuleInterop(compilerOptions) || getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) { 884 return innerExpr; 885 } 886 if (getImportNeedsImportStarHelper(node)) { 887 return emitHelpers().createImportStarHelper(innerExpr); 888 } 889 if (getImportNeedsImportDefaultHelper(node)) { 890 return emitHelpers().createImportDefaultHelper(innerExpr); 891 } 892 return innerExpr; 893 } 894 895 /** 896 * Visits an ImportDeclaration node. 897 * 898 * @param node The node to visit. 899 */ 900 function visitImportDeclaration(node: ImportDeclaration): VisitResult<Statement> { 901 let statements: Statement[] | undefined; 902 const namespaceDeclaration = getNamespaceDeclarationNode(node); 903 if (moduleKind !== ModuleKind.AMD) { 904 if (!node.importClause) { 905 // import "mod"; 906 return setOriginalNode(setTextRange(factory.createExpressionStatement(createRequireCall(node)), node), node); 907 } 908 else { 909 const variables: VariableDeclaration[] = []; 910 if (namespaceDeclaration && !isDefaultImport(node)) { 911 // import * as n from "mod"; 912 variables.push( 913 factory.createVariableDeclaration( 914 factory.cloneNode(namespaceDeclaration.name), 915 /*exclamationToken*/ undefined, 916 /*type*/ undefined, 917 getHelperExpressionForImport(node, createRequireCall(node)) 918 ) 919 ); 920 } 921 else { 922 // import d from "mod"; 923 // import { x, y } from "mod"; 924 // import d, { x, y } from "mod"; 925 // import d, * as n from "mod"; 926 variables.push( 927 factory.createVariableDeclaration( 928 factory.getGeneratedNameForNode(node), 929 /*exclamationToken*/ undefined, 930 /*type*/ undefined, 931 getHelperExpressionForImport(node, createRequireCall(node)) 932 ) 933 ); 934 935 if (namespaceDeclaration && isDefaultImport(node)) { 936 variables.push( 937 factory.createVariableDeclaration( 938 factory.cloneNode(namespaceDeclaration.name), 939 /*exclamationToken*/ undefined, 940 /*type*/ undefined, 941 factory.getGeneratedNameForNode(node) 942 ) 943 ); 944 } 945 } 946 947 statements = append(statements, 948 setOriginalNode( 949 setTextRange( 950 factory.createVariableStatement( 951 /*modifiers*/ undefined, 952 factory.createVariableDeclarationList( 953 variables, 954 languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None 955 ) 956 ), 957 /*location*/ node), 958 /*original*/ node 959 ) 960 ); 961 } 962 } 963 else if (namespaceDeclaration && isDefaultImport(node)) { 964 // import d, * as n from "mod"; 965 statements = append(statements, 966 factory.createVariableStatement( 967 /*modifiers*/ undefined, 968 factory.createVariableDeclarationList( 969 [ 970 setOriginalNode( 971 setTextRange( 972 factory.createVariableDeclaration( 973 factory.cloneNode(namespaceDeclaration.name), 974 /*exclamationToken*/ undefined, 975 /*type*/ undefined, 976 factory.getGeneratedNameForNode(node) 977 ), 978 /*location*/ node), 979 /*original*/ node 980 ) 981 ], 982 languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None 983 ) 984 ) 985 ); 986 } 987 988 if (hasAssociatedEndOfDeclarationMarker(node)) { 989 // Defer exports until we encounter an EndOfDeclarationMarker node 990 const id = getOriginalNodeId(node); 991 deferredExports[id] = appendExportsOfImportDeclaration(deferredExports[id], node); 992 } 993 else { 994 statements = appendExportsOfImportDeclaration(statements, node); 995 } 996 997 return singleOrMany(statements); 998 } 999 1000 /** 1001 * Creates a `require()` call to import an external module. 1002 * 1003 * @param importNode The declararation to import. 1004 */ 1005 function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { 1006 const moduleName = getExternalModuleNameLiteral(factory, importNode, currentSourceFile, host, resolver, compilerOptions); 1007 const args: Expression[] = []; 1008 if (moduleName) { 1009 args.push(moduleName); 1010 } 1011 1012 return factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, args); 1013 } 1014 1015 /** 1016 * Visits an ImportEqualsDeclaration node. 1017 * 1018 * @param node The node to visit. 1019 */ 1020 function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> { 1021 Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); 1022 1023 let statements: Statement[] | undefined; 1024 if (moduleKind !== ModuleKind.AMD) { 1025 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 1026 statements = append(statements, 1027 setOriginalNode( 1028 setTextRange( 1029 factory.createExpressionStatement( 1030 createExportExpression( 1031 node.name, 1032 createRequireCall(node) 1033 ) 1034 ), 1035 node), 1036 node 1037 ) 1038 ); 1039 } 1040 else { 1041 statements = append(statements, 1042 setOriginalNode( 1043 setTextRange( 1044 factory.createVariableStatement( 1045 /*modifiers*/ undefined, 1046 factory.createVariableDeclarationList( 1047 [ 1048 factory.createVariableDeclaration( 1049 factory.cloneNode(node.name), 1050 /*exclamationToken*/ undefined, 1051 /*type*/ undefined, 1052 createRequireCall(node) 1053 ) 1054 ], 1055 /*flags*/ languageVersion >= ScriptTarget.ES2015 ? NodeFlags.Const : NodeFlags.None 1056 ) 1057 ), 1058 node), 1059 node 1060 ) 1061 ); 1062 } 1063 } 1064 else { 1065 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 1066 statements = append(statements, 1067 setOriginalNode( 1068 setTextRange( 1069 factory.createExpressionStatement( 1070 createExportExpression(factory.getExportName(node), factory.getLocalName(node)) 1071 ), 1072 node), 1073 node 1074 ) 1075 ); 1076 } 1077 } 1078 1079 if (hasAssociatedEndOfDeclarationMarker(node)) { 1080 // Defer exports until we encounter an EndOfDeclarationMarker node 1081 const id = getOriginalNodeId(node); 1082 deferredExports[id] = appendExportsOfImportEqualsDeclaration(deferredExports[id], node); 1083 } 1084 else { 1085 statements = appendExportsOfImportEqualsDeclaration(statements, node); 1086 } 1087 1088 return singleOrMany(statements); 1089 } 1090 1091 /** 1092 * Visits an ExportDeclaration node. 1093 * 1094 * @param The node to visit. 1095 */ 1096 function visitExportDeclaration(node: ExportDeclaration): VisitResult<Statement> { 1097 if (!node.moduleSpecifier) { 1098 // Elide export declarations with no module specifier as they are handled 1099 // elsewhere. 1100 return undefined; 1101 } 1102 1103 const generatedName = factory.getGeneratedNameForNode(node); 1104 1105 if (node.exportClause && isNamedExports(node.exportClause)) { 1106 const allExportsAreAnnotations = every(node.exportClause.elements, s => resolver.isReferredToAnnotation(s) === true); 1107 if (node.exportClause.elements.length > 0 && allExportsAreAnnotations) { 1108 return undefined; 1109 } 1110 const statements: Statement[] = []; 1111 // export { x, y } from "mod"; 1112 if (moduleKind !== ModuleKind.AMD) { 1113 statements.push( 1114 setOriginalNode( 1115 setTextRange( 1116 factory.createVariableStatement( 1117 /*modifiers*/ undefined, 1118 factory.createVariableDeclarationList([ 1119 factory.createVariableDeclaration( 1120 generatedName, 1121 /*exclamationToken*/ undefined, 1122 /*type*/ undefined, 1123 createRequireCall(node) 1124 ) 1125 ]) 1126 ), 1127 /*location*/ node), 1128 /* original */ node 1129 ) 1130 ); 1131 } 1132 for (const specifier of node.exportClause.elements) { 1133 if (resolver.isReferredToAnnotation(specifier) === true) { 1134 continue; 1135 } 1136 if (languageVersion === ScriptTarget.ES3) { 1137 statements.push( 1138 setOriginalNode( 1139 setTextRange( 1140 factory.createExpressionStatement( 1141 emitHelpers().createCreateBindingHelper(generatedName, factory.createStringLiteralFromNode(specifier.propertyName || specifier.name), specifier.propertyName ? factory.createStringLiteralFromNode(specifier.name) : undefined) 1142 ), 1143 specifier), 1144 specifier 1145 ) 1146 ); 1147 } 1148 else { 1149 const exportNeedsImportDefault = 1150 !!getESModuleInterop(compilerOptions) && 1151 !(getEmitFlags(node) & EmitFlags.NeverApplyImportHelper) && 1152 idText(specifier.propertyName || specifier.name) === "default"; 1153 const exportedValue = factory.createPropertyAccessExpression( 1154 exportNeedsImportDefault ? emitHelpers().createImportDefaultHelper(generatedName) : generatedName, 1155 specifier.propertyName || specifier.name); 1156 statements.push( 1157 setOriginalNode( 1158 setTextRange( 1159 factory.createExpressionStatement( 1160 createExportExpression(factory.getExportName(specifier), exportedValue, /* location */ undefined, /* liveBinding */ true) 1161 ), 1162 specifier), 1163 specifier 1164 ) 1165 ); 1166 } 1167 } 1168 1169 return singleOrMany(statements); 1170 } 1171 else if (node.exportClause) { 1172 const statements: Statement[] = []; 1173 // export * as ns from "mod"; 1174 // export * as default from "mod"; 1175 statements.push( 1176 setOriginalNode( 1177 setTextRange( 1178 factory.createExpressionStatement( 1179 createExportExpression( 1180 factory.cloneNode(node.exportClause.name), 1181 getHelperExpressionForExport(node, moduleKind !== ModuleKind.AMD ? 1182 createRequireCall(node) : 1183 isExportNamespaceAsDefaultDeclaration(node) ? generatedName : 1184 factory.createIdentifier(idText(node.exportClause.name))) 1185 ) 1186 ), 1187 node 1188 ), 1189 node 1190 ) 1191 ); 1192 1193 return singleOrMany(statements); 1194 } 1195 else { 1196 // export * from "mod"; 1197 return setOriginalNode( 1198 setTextRange( 1199 factory.createExpressionStatement( 1200 emitHelpers().createExportStarHelper(moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName) 1201 ), 1202 node), 1203 node 1204 ); 1205 } 1206 } 1207 1208 /** 1209 * Visits an ExportAssignment node. 1210 * 1211 * @param node The node to visit. 1212 */ 1213 function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> { 1214 if (node.isExportEquals) { 1215 return undefined; 1216 } 1217 1218 let statements: Statement[] | undefined; 1219 const original = node.original; 1220 if (original && hasAssociatedEndOfDeclarationMarker(original)) { 1221 // Defer exports until we encounter an EndOfDeclarationMarker node 1222 const id = getOriginalNodeId(node); 1223 deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); 1224 } 1225 else { 1226 statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); 1227 } 1228 1229 return singleOrMany(statements); 1230 } 1231 1232 /** 1233 * Visits a FunctionDeclaration node. 1234 * 1235 * @param node The node to visit. 1236 */ 1237 function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult<Statement> { 1238 let statements: Statement[] | undefined; 1239 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 1240 statements = append(statements, 1241 setOriginalNode( 1242 setTextRange( 1243 factory.createFunctionDeclaration( 1244 visitNodes(node.modifiers, modifierVisitor, isModifier), 1245 node.asteriskToken, 1246 factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), 1247 /*typeParameters*/ undefined, 1248 visitNodes(node.parameters, visitor), 1249 /*type*/ undefined, 1250 visitEachChild(node.body, visitor, context) 1251 ), 1252 /*location*/ node 1253 ), 1254 /*original*/ node 1255 ) 1256 ); 1257 } 1258 else { 1259 statements = append(statements, visitEachChild(node, visitor, context)); 1260 } 1261 1262 if (hasAssociatedEndOfDeclarationMarker(node)) { 1263 // Defer exports until we encounter an EndOfDeclarationMarker node 1264 const id = getOriginalNodeId(node); 1265 deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); 1266 } 1267 else { 1268 statements = appendExportsOfHoistedDeclaration(statements, node); 1269 } 1270 1271 return singleOrMany(statements); 1272 } 1273 1274 /** 1275 * Visits a ClassDeclaration node. 1276 * 1277 * @param node The node to visit. 1278 */ 1279 function visitClassDeclaration(node: ClassDeclaration): VisitResult<Statement> { 1280 let statements: Statement[] | undefined; 1281 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 1282 statements = append(statements, 1283 setOriginalNode( 1284 setTextRange( 1285 factory.createClassDeclaration( 1286 visitNodes(node.modifiers, modifierVisitor, isModifierLike), 1287 factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), 1288 /*typeParameters*/ undefined, 1289 visitNodes(node.heritageClauses, visitor), 1290 visitNodes(node.members, visitor) 1291 ), 1292 node 1293 ), 1294 node 1295 ) 1296 ); 1297 } 1298 else { 1299 statements = append(statements, visitEachChild(node, visitor, context)); 1300 } 1301 1302 if (hasAssociatedEndOfDeclarationMarker(node)) { 1303 // Defer exports until we encounter an EndOfDeclarationMarker node 1304 const id = getOriginalNodeId(node); 1305 deferredExports[id] = appendExportsOfHoistedDeclaration(deferredExports[id], node); 1306 } 1307 else { 1308 statements = appendExportsOfHoistedDeclaration(statements, node); 1309 } 1310 1311 return singleOrMany(statements); 1312 } 1313 1314 /** 1315 * Visits a VariableStatement node. 1316 * 1317 * @param node The node to visit. 1318 */ 1319 function visitVariableStatement(node: VariableStatement): VisitResult<Statement> { 1320 let statements: Statement[] | undefined; 1321 let variables: VariableDeclaration[] | undefined; 1322 let expressions: Expression[] | undefined; 1323 1324 if (hasSyntacticModifier(node, ModifierFlags.Export)) { 1325 let modifiers: NodeArray<Modifier> | undefined; 1326 let removeCommentsOnExpressions = false; 1327 1328 // If we're exporting these variables, then these just become assignments to 'exports.x'. 1329 for (const variable of node.declarationList.declarations) { 1330 if (isIdentifier(variable.name) && isLocalName(variable.name)) { 1331 if (!modifiers) { 1332 modifiers = visitNodes(node.modifiers, modifierVisitor, isModifier); 1333 } 1334 1335 variables = append(variables, variable); 1336 } 1337 else if (variable.initializer) { 1338 if (!isBindingPattern(variable.name) && (isArrowFunction(variable.initializer) || isFunctionExpression(variable.initializer) || isClassExpression(variable.initializer))) { 1339 const expression = factory.createAssignment( 1340 setTextRange( 1341 factory.createPropertyAccessExpression( 1342 factory.createIdentifier("exports"), 1343 variable.name 1344 ), 1345 /*location*/ variable.name 1346 ), 1347 factory.createIdentifier(getTextOfIdentifierOrLiteral(variable.name)) 1348 ); 1349 const updatedVariable = factory.createVariableDeclaration( 1350 variable.name, 1351 variable.exclamationToken, 1352 variable.type, 1353 visitNode(variable.initializer, visitor) 1354 ); 1355 1356 variables = append(variables, updatedVariable); 1357 expressions = append(expressions, expression); 1358 removeCommentsOnExpressions = true; 1359 } 1360 else { 1361 expressions = append(expressions, transformInitializedVariable(variable as InitializedVariableDeclaration)); 1362 } 1363 } 1364 } 1365 1366 if (variables) { 1367 statements = append(statements, factory.updateVariableStatement(node, modifiers, factory.updateVariableDeclarationList(node.declarationList, variables))); 1368 } 1369 1370 if (expressions) { 1371 const statement = setOriginalNode(setTextRange(factory.createExpressionStatement(factory.inlineExpressions(expressions)), node), node); 1372 if (removeCommentsOnExpressions) { 1373 removeAllComments(statement); 1374 } 1375 statements = append(statements, statement); 1376 } 1377 } 1378 else { 1379 statements = append(statements, visitEachChild(node, visitor, context)); 1380 } 1381 1382 if (hasAssociatedEndOfDeclarationMarker(node)) { 1383 // Defer exports until we encounter an EndOfDeclarationMarker node 1384 const id = getOriginalNodeId(node); 1385 deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node); 1386 } 1387 else { 1388 statements = appendExportsOfVariableStatement(statements, node); 1389 } 1390 1391 return singleOrMany(statements); 1392 } 1393 1394 function createAllExportExpressions(name: Identifier, value: Expression, location?: TextRange) { 1395 const exportedNames = getExports(name); 1396 if (exportedNames) { 1397 // For each additional export of the declaration, apply an export assignment. 1398 let expression: Expression = isExportName(name) ? value : factory.createAssignment(name, value); 1399 for (const exportName of exportedNames) { 1400 // Mark the node to prevent triggering substitution. 1401 setEmitFlags(expression, EmitFlags.NoSubstitution); 1402 expression = createExportExpression(exportName, expression, /*location*/ location); 1403 } 1404 1405 return expression; 1406 } 1407 return factory.createAssignment(name, value); 1408 } 1409 1410 /** 1411 * Transforms an exported variable with an initializer into an expression. 1412 * 1413 * @param node The node to transform. 1414 */ 1415 function transformInitializedVariable(node: InitializedVariableDeclaration): Expression { 1416 if (isBindingPattern(node.name)) { 1417 return flattenDestructuringAssignment( 1418 visitNode(node, visitor), 1419 /*visitor*/ undefined, 1420 context, 1421 FlattenLevel.All, 1422 /*needsValue*/ false, 1423 createAllExportExpressions 1424 ); 1425 } 1426 else { 1427 return factory.createAssignment( 1428 setTextRange( 1429 factory.createPropertyAccessExpression( 1430 factory.createIdentifier("exports"), 1431 node.name 1432 ), 1433 /*location*/ node.name 1434 ), 1435 node.initializer ? visitNode(node.initializer, visitor) : factory.createVoidZero() 1436 ); 1437 } 1438 } 1439 1440 /** 1441 * Visits a MergeDeclarationMarker used as a placeholder for the beginning of a merged 1442 * and transformed declaration. 1443 * 1444 * @param node The node to visit. 1445 */ 1446 function visitMergeDeclarationMarker(node: MergeDeclarationMarker): VisitResult<Statement> { 1447 // For an EnumDeclaration or ModuleDeclaration that merges with a preceeding 1448 // declaration we do not emit a leading variable declaration. To preserve the 1449 // begin/end semantics of the declararation and to properly handle exports 1450 // we wrapped the leading variable declaration in a `MergeDeclarationMarker`. 1451 // 1452 // To balance the declaration, add the exports of the elided variable 1453 // statement. 1454 if (hasAssociatedEndOfDeclarationMarker(node) && node.original!.kind === SyntaxKind.VariableStatement) { 1455 const id = getOriginalNodeId(node); 1456 deferredExports[id] = appendExportsOfVariableStatement(deferredExports[id], node.original as VariableStatement); 1457 } 1458 1459 return node; 1460 } 1461 1462 /** 1463 * Determines whether a node has an associated EndOfDeclarationMarker. 1464 * 1465 * @param node The node to test. 1466 */ 1467 function hasAssociatedEndOfDeclarationMarker(node: Node) { 1468 return (getEmitFlags(node) & EmitFlags.HasEndOfDeclarationMarker) !== 0; 1469 } 1470 1471 /** 1472 * Visits a DeclarationMarker used as a placeholder for the end of a transformed 1473 * declaration. 1474 * 1475 * @param node The node to visit. 1476 */ 1477 function visitEndOfDeclarationMarker(node: EndOfDeclarationMarker): VisitResult<Statement> { 1478 // For some transformations we emit an `EndOfDeclarationMarker` to mark the actual 1479 // end of the transformed declaration. We use this marker to emit any deferred exports 1480 // of the declaration. 1481 const id = getOriginalNodeId(node); 1482 const statements = deferredExports[id]; 1483 if (statements) { 1484 delete deferredExports[id]; 1485 return append(statements, node); 1486 } 1487 1488 return node; 1489 } 1490 1491 /** 1492 * Appends the exports of an ImportDeclaration to a statement list, returning the 1493 * statement list. 1494 * 1495 * @param statements A statement list to which the down-level export statements are to be 1496 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1497 * appended. 1498 * @param decl The declaration whose exports are to be recorded. 1499 */ 1500 function appendExportsOfImportDeclaration(statements: Statement[] | undefined, decl: ImportDeclaration): Statement[] | undefined { 1501 if (currentModuleInfo.exportEquals) { 1502 return statements; 1503 } 1504 1505 const importClause = decl.importClause; 1506 if (!importClause) { 1507 return statements; 1508 } 1509 1510 if (importClause.name) { 1511 statements = appendExportsOfDeclaration(statements, importClause); 1512 } 1513 1514 const namedBindings = importClause.namedBindings; 1515 if (namedBindings) { 1516 switch (namedBindings.kind) { 1517 case SyntaxKind.NamespaceImport: 1518 statements = appendExportsOfDeclaration(statements, namedBindings); 1519 break; 1520 1521 case SyntaxKind.NamedImports: 1522 for (const importBinding of namedBindings.elements) { 1523 statements = appendExportsOfDeclaration(statements, importBinding, /* liveBinding */ true); 1524 } 1525 1526 break; 1527 } 1528 } 1529 1530 return statements; 1531 } 1532 1533 /** 1534 * Appends the exports of an ImportEqualsDeclaration to a statement list, returning the 1535 * statement list. 1536 * 1537 * @param statements A statement list to which the down-level export statements are to be 1538 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1539 * appended. 1540 * @param decl The declaration whose exports are to be recorded. 1541 */ 1542 function appendExportsOfImportEqualsDeclaration(statements: Statement[] | undefined, decl: ImportEqualsDeclaration): Statement[] | undefined { 1543 if (currentModuleInfo.exportEquals) { 1544 return statements; 1545 } 1546 1547 return appendExportsOfDeclaration(statements, decl); 1548 } 1549 1550 /** 1551 * Appends the exports of a VariableStatement to a statement list, returning the statement 1552 * list. 1553 * 1554 * @param statements A statement list to which the down-level export statements are to be 1555 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1556 * appended. 1557 * @param node The VariableStatement whose exports are to be recorded. 1558 */ 1559 function appendExportsOfVariableStatement(statements: Statement[] | undefined, node: VariableStatement): Statement[] | undefined { 1560 if (currentModuleInfo.exportEquals) { 1561 return statements; 1562 } 1563 1564 for (const decl of node.declarationList.declarations) { 1565 statements = appendExportsOfBindingElement(statements, decl); 1566 } 1567 1568 return statements; 1569 } 1570 1571 /** 1572 * Appends the exports of a VariableDeclaration or BindingElement to a statement list, 1573 * returning the statement list. 1574 * 1575 * @param statements A statement list to which the down-level export statements are to be 1576 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1577 * appended. 1578 * @param decl The declaration whose exports are to be recorded. 1579 */ 1580 function appendExportsOfBindingElement(statements: Statement[] | undefined, decl: VariableDeclaration | BindingElement): Statement[] | undefined { 1581 if (currentModuleInfo.exportEquals) { 1582 return statements; 1583 } 1584 1585 if (isBindingPattern(decl.name)) { 1586 for (const element of decl.name.elements) { 1587 if (!isOmittedExpression(element)) { 1588 statements = appendExportsOfBindingElement(statements, element); 1589 } 1590 } 1591 } 1592 else if (!isGeneratedIdentifier(decl.name)) { 1593 statements = appendExportsOfDeclaration(statements, decl); 1594 } 1595 1596 return statements; 1597 } 1598 1599 /** 1600 * Appends the exports of a ClassDeclaration or FunctionDeclaration to a statement list, 1601 * returning the statement list. 1602 * 1603 * @param statements A statement list to which the down-level export statements are to be 1604 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1605 * appended. 1606 * @param decl The declaration whose exports are to be recorded. 1607 */ 1608 function appendExportsOfHoistedDeclaration(statements: Statement[] | undefined, decl: ClassDeclaration | FunctionDeclaration): Statement[] | undefined { 1609 if (currentModuleInfo.exportEquals) { 1610 return statements; 1611 } 1612 1613 if (hasSyntacticModifier(decl, ModifierFlags.Export)) { 1614 const exportName = hasSyntacticModifier(decl, ModifierFlags.Default) ? factory.createIdentifier("default") : factory.getDeclarationName(decl); 1615 statements = appendExportStatement(statements, exportName, factory.getLocalName(decl), /*location*/ decl); 1616 } 1617 1618 if (decl.name) { 1619 statements = appendExportsOfDeclaration(statements, decl); 1620 } 1621 1622 return statements; 1623 } 1624 1625 /** 1626 * Appends the exports of a declaration to a statement list, returning the statement list. 1627 * 1628 * @param statements A statement list to which the down-level export statements are to be 1629 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1630 * appended. 1631 * @param decl The declaration to export. 1632 */ 1633 function appendExportsOfDeclaration(statements: Statement[] | undefined, decl: Declaration, liveBinding?: boolean): Statement[] | undefined { 1634 const name = factory.getDeclarationName(decl); 1635 const exportSpecifiers = currentModuleInfo.exportSpecifiers.get(idText(name)); 1636 if (exportSpecifiers) { 1637 for (const exportSpecifier of exportSpecifiers) { 1638 statements = appendExportStatement(statements, exportSpecifier.name, name, /*location*/ exportSpecifier.name, /* allowComments */ undefined, liveBinding); 1639 } 1640 } 1641 return statements; 1642 } 1643 1644 /** 1645 * Appends the down-level representation of an export to a statement list, returning the 1646 * statement list. 1647 * 1648 * @param statements A statement list to which the down-level export statements are to be 1649 * appended. If `statements` is `undefined`, a new array is allocated if statements are 1650 * appended. 1651 * @param exportName The name of the export. 1652 * @param expression The expression to export. 1653 * @param location The location to use for source maps and comments for the export. 1654 * @param allowComments Whether to allow comments on the export. 1655 */ 1656 function appendExportStatement(statements: Statement[] | undefined, exportName: Identifier, expression: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean): Statement[] | undefined { 1657 statements = append(statements, createExportStatement(exportName, expression, location, allowComments, liveBinding)); 1658 return statements; 1659 } 1660 1661 function createUnderscoreUnderscoreESModule() { 1662 let statement: Statement; 1663 if (languageVersion === ScriptTarget.ES3) { 1664 statement = factory.createExpressionStatement( 1665 createExportExpression( 1666 factory.createIdentifier("__esModule"), 1667 factory.createTrue() 1668 ) 1669 ); 1670 } 1671 else { 1672 statement = factory.createExpressionStatement( 1673 factory.createCallExpression( 1674 factory.createPropertyAccessExpression(factory.createIdentifier("Object"), "defineProperty"), 1675 /*typeArguments*/ undefined, 1676 [ 1677 factory.createIdentifier("exports"), 1678 factory.createStringLiteral("__esModule"), 1679 factory.createObjectLiteralExpression([ 1680 factory.createPropertyAssignment("value", factory.createTrue()) 1681 ]) 1682 ] 1683 ) 1684 ); 1685 } 1686 setEmitFlags(statement, EmitFlags.CustomPrologue); 1687 return statement; 1688 } 1689 1690 /** 1691 * Creates a call to the current file's export function to export a value. 1692 * 1693 * @param name The bound name of the export. 1694 * @param value The exported value. 1695 * @param location The location to use for source maps and comments for the export. 1696 * @param allowComments An optional value indicating whether to emit comments for the statement. 1697 */ 1698 function createExportStatement(name: Identifier, value: Expression, location?: TextRange, allowComments?: boolean, liveBinding?: boolean) { 1699 const statement = setTextRange(factory.createExpressionStatement(createExportExpression(name, value, /* location */ undefined, liveBinding)), location); 1700 startOnNewLine(statement); 1701 if (!allowComments) { 1702 setEmitFlags(statement, EmitFlags.NoComments); 1703 } 1704 1705 return statement; 1706 } 1707 1708 /** 1709 * Creates a call to the current file's export function to export a value. 1710 * 1711 * @param name The bound name of the export. 1712 * @param value The exported value. 1713 * @param location The location to use for source maps and comments for the export. 1714 */ 1715 function createExportExpression(name: Identifier, value: Expression, location?: TextRange, liveBinding?: boolean) { 1716 return setTextRange( 1717 liveBinding && languageVersion !== ScriptTarget.ES3 ? factory.createCallExpression( 1718 factory.createPropertyAccessExpression( 1719 factory.createIdentifier("Object"), 1720 "defineProperty" 1721 ), 1722 /*typeArguments*/ undefined, 1723 [ 1724 factory.createIdentifier("exports"), 1725 factory.createStringLiteralFromNode(name), 1726 factory.createObjectLiteralExpression([ 1727 factory.createPropertyAssignment("enumerable", factory.createTrue()), 1728 factory.createPropertyAssignment("get", factory.createFunctionExpression( 1729 /*modifiers*/ undefined, 1730 /*asteriskToken*/ undefined, 1731 /*name*/ undefined, 1732 /*typeParameters*/ undefined, 1733 /*parameters*/ [], 1734 /*type*/ undefined, 1735 factory.createBlock([factory.createReturnStatement(value)]) 1736 )) 1737 ]) 1738 ] 1739 ) : factory.createAssignment( 1740 factory.createPropertyAccessExpression( 1741 factory.createIdentifier("exports"), 1742 factory.cloneNode(name) 1743 ), 1744 value 1745 ), 1746 location 1747 ); 1748 } 1749 1750 // 1751 // Modifier Visitors 1752 // 1753 1754 /** 1755 * Visit nodes to elide module-specific modifiers. 1756 * 1757 * @param node The node to visit. 1758 */ 1759 function modifierVisitor(node: Node): VisitResult<Node> { 1760 // Elide module-specific modifiers. 1761 switch (node.kind) { 1762 case SyntaxKind.ExportKeyword: 1763 case SyntaxKind.DefaultKeyword: 1764 return undefined; 1765 } 1766 1767 return node; 1768 } 1769 1770 // 1771 // Emit Notification 1772 // 1773 1774 /** 1775 * Hook for node emit notifications. 1776 * 1777 * @param hint A hint as to the intended usage of the node. 1778 * @param node The node to emit. 1779 * @param emit A callback used to emit the node in the printer. 1780 */ 1781 function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void { 1782 if (node.kind === SyntaxKind.SourceFile) { 1783 currentSourceFile = node as SourceFile; 1784 currentModuleInfo = moduleInfoMap[getOriginalNodeId(currentSourceFile)]; 1785 1786 previousOnEmitNode(hint, node, emitCallback); 1787 1788 currentSourceFile = undefined!; 1789 currentModuleInfo = undefined!; 1790 } 1791 else { 1792 previousOnEmitNode(hint, node, emitCallback); 1793 } 1794 } 1795 1796 // 1797 // Substitutions 1798 // 1799 1800 /** 1801 * Hooks node substitutions. 1802 * 1803 * @param hint A hint as to the intended usage of the node. 1804 * @param node The node to substitute. 1805 */ 1806 function onSubstituteNode(hint: EmitHint, node: Node) { 1807 node = previousOnSubstituteNode(hint, node); 1808 if (node.id && noSubstitution[node.id]) { 1809 return node; 1810 } 1811 1812 if (hint === EmitHint.Expression) { 1813 return substituteExpression(node as Expression); 1814 } 1815 else if (isShorthandPropertyAssignment(node)) { 1816 return substituteShorthandPropertyAssignment(node); 1817 } 1818 1819 return node; 1820 } 1821 1822 /** 1823 * Substitution for a ShorthandPropertyAssignment whose declaration name is an imported 1824 * or exported symbol. 1825 * 1826 * @param node The node to substitute. 1827 */ 1828 function substituteShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElementLike { 1829 const name = node.name; 1830 const exportedOrImportedName = substituteExpressionIdentifier(name); 1831 if (exportedOrImportedName !== name) { 1832 // A shorthand property with an assignment initializer is probably part of a 1833 // destructuring assignment 1834 if (node.objectAssignmentInitializer) { 1835 const initializer = factory.createAssignment(exportedOrImportedName, node.objectAssignmentInitializer); 1836 return setTextRange(factory.createPropertyAssignment(name, initializer), node); 1837 } 1838 return setTextRange(factory.createPropertyAssignment(name, exportedOrImportedName), node); 1839 } 1840 return node; 1841 } 1842 1843 /** 1844 * Substitution for an Expression that may contain an imported or exported symbol. 1845 * 1846 * @param node The node to substitute. 1847 */ 1848 function substituteExpression(node: Expression) { 1849 switch (node.kind) { 1850 case SyntaxKind.Identifier: 1851 return substituteExpressionIdentifier(node as Identifier); 1852 case SyntaxKind.CallExpression: 1853 return substituteCallExpression(node as CallExpression); 1854 case SyntaxKind.TaggedTemplateExpression: 1855 return substituteTaggedTemplateExpression(node as TaggedTemplateExpression); 1856 case SyntaxKind.BinaryExpression: 1857 return substituteBinaryExpression(node as BinaryExpression); 1858 } 1859 1860 return node; 1861 } 1862 1863 function substituteCallExpression(node: CallExpression) { 1864 if (isIdentifier(node.expression)) { 1865 const expression = substituteExpressionIdentifier(node.expression); 1866 noSubstitution[getNodeId(expression)] = true; 1867 if (!isIdentifier(expression) && !(getEmitFlags(node.expression) & EmitFlags.HelperName)) { 1868 return addEmitFlags( 1869 factory.updateCallExpression(node, 1870 expression, 1871 /*typeArguments*/ undefined, 1872 node.arguments 1873 ), 1874 EmitFlags.IndirectCall 1875 ); 1876 1877 } 1878 } 1879 return node; 1880 } 1881 1882 function substituteTaggedTemplateExpression(node: TaggedTemplateExpression) { 1883 if (isIdentifier(node.tag)) { 1884 const tag = substituteExpressionIdentifier(node.tag); 1885 noSubstitution[getNodeId(tag)] = true; 1886 if (!isIdentifier(tag) && !(getEmitFlags(node.tag) & EmitFlags.HelperName)) { 1887 return addEmitFlags( 1888 factory.updateTaggedTemplateExpression(node, 1889 tag, 1890 /*typeArguments*/ undefined, 1891 node.template 1892 ), 1893 EmitFlags.IndirectCall 1894 ); 1895 } 1896 } 1897 return node; 1898 } 1899 1900 /** 1901 * Substitution for an Identifier expression that may contain an imported or exported 1902 * symbol. 1903 * 1904 * @param node The node to substitute. 1905 */ 1906 function substituteExpressionIdentifier(node: Identifier): Expression { 1907 if (getEmitFlags(node) & EmitFlags.HelperName) { 1908 const externalHelpersModuleName = getExternalHelpersModuleName(currentSourceFile); 1909 if (externalHelpersModuleName) { 1910 return factory.createPropertyAccessExpression(externalHelpersModuleName, node); 1911 } 1912 return node; 1913 } 1914 else if (!(isGeneratedIdentifier(node) && !(node.autoGenerateFlags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) { 1915 const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node)); 1916 if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) { 1917 return setTextRange( 1918 factory.createPropertyAccessExpression( 1919 factory.createIdentifier("exports"), 1920 factory.cloneNode(node) 1921 ), 1922 /*location*/ node 1923 ); 1924 } 1925 const importDeclaration = resolver.getReferencedImportDeclaration(node); 1926 if (importDeclaration) { 1927 if (isImportClause(importDeclaration)) { 1928 return setTextRange( 1929 factory.createPropertyAccessExpression( 1930 factory.getGeneratedNameForNode(importDeclaration.parent), 1931 factory.createIdentifier("default") 1932 ), 1933 /*location*/ node 1934 ); 1935 } 1936 else if (isImportSpecifier(importDeclaration)) { 1937 const name = importDeclaration.propertyName || importDeclaration.name; 1938 return setTextRange( 1939 factory.createPropertyAccessExpression( 1940 factory.getGeneratedNameForNode(importDeclaration.parent?.parent?.parent || importDeclaration), 1941 factory.cloneNode(name) 1942 ), 1943 /*location*/ node 1944 ); 1945 } 1946 } 1947 } 1948 return node; 1949 } 1950 1951 /** 1952 * Substitution for a BinaryExpression that may contain an imported or exported symbol. 1953 * 1954 * @param node The node to substitute. 1955 */ 1956 function substituteBinaryExpression(node: BinaryExpression): Expression { 1957 // When we see an assignment expression whose left-hand side is an exported symbol, 1958 // we should ensure all exports of that symbol are updated with the correct value. 1959 // 1960 // - We do not substitute generated identifiers for any reason. 1961 // - We do not substitute identifiers tagged with the LocalName flag. 1962 // - We do not substitute identifiers that were originally the name of an enum or 1963 // namespace due to how they are transformed in TypeScript. 1964 // - We only substitute identifiers that are exported at the top level. 1965 if (isAssignmentOperator(node.operatorToken.kind) 1966 && isIdentifier(node.left) 1967 && !isGeneratedIdentifier(node.left) 1968 && !isLocalName(node.left) 1969 && !isDeclarationNameOfEnumOrNamespace(node.left)) { 1970 const exportedNames = getExports(node.left); 1971 if (exportedNames) { 1972 // For each additional export of the declaration, apply an export assignment. 1973 let expression: Expression = node; 1974 for (const exportName of exportedNames) { 1975 // Mark the node to prevent triggering this rule again. 1976 noSubstitution[getNodeId(expression)] = true; 1977 expression = createExportExpression(exportName, expression, /*location*/ node); 1978 } 1979 1980 return expression; 1981 } 1982 } 1983 1984 return node; 1985 } 1986 1987 /** 1988 * Gets the additional exports of a name. 1989 * 1990 * @param name The name. 1991 */ 1992 function getExports(name: Identifier): Identifier[] | undefined { 1993 if (!isGeneratedIdentifier(name)) { 1994 const valueDeclaration = resolver.getReferencedImportDeclaration(name) 1995 || resolver.getReferencedValueDeclaration(name); 1996 if (valueDeclaration) { 1997 return currentModuleInfo 1998 && currentModuleInfo.exportedBindings[getOriginalNodeId(valueDeclaration)]; 1999 } 2000 } 2001 } 2002 } 2003 2004 // emit helper for dynamic import 2005 const dynamicImportUMDHelper: EmitHelper = { 2006 name: "typescript:dynamicimport-sync-require", 2007 scoped: true, 2008 text: ` 2009 var __syncRequire = typeof module === "object" && typeof module.exports === "object";` 2010 }; 2011} 2012