diff --git a/Jakefile.js b/Jakefile.js index 3dd9999aa8ae5..1929a3a475f72 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -42,8 +42,18 @@ var compilerSources = [ "checker.ts", "factory.ts", "visitor.ts", + "transformers/destructuring.ts", + "transformers/ts.ts", + "transformers/module/es6.ts", + "transformers/module/system.ts", + "transformers/module/module.ts", + "transformers/jsx.ts", + "transformers/es7.ts", + "transformers/es6.ts", "transformer.ts", "sourcemap.ts", + "comments.ts", + "printer.ts", "declarationEmitter.ts", "emitter.ts", "program.ts", @@ -65,8 +75,18 @@ var servicesSources = [ "checker.ts", "factory.ts", "visitor.ts", + "transformers/destructuring.ts", + "transformers/ts.ts", + "transformers/module/es6.ts", + "transformers/module/system.ts", + "transformers/module/module.ts", + "transformers/jsx.ts", + "transformers/es7.ts", + "transformers/es6.ts", "transformer.ts", "sourcemap.ts", + "comments.ts", + "printer.ts", "declarationEmitter.ts", "emitter.ts", "program.ts", @@ -218,6 +238,7 @@ function concatenateFiles(destinationFile, sourceFiles) { } var useDebugMode = true; +var useTransforms = process.env.USE_TRANSFORMS || false; var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node"); var compilerFilename = "tsc.js"; var LKGCompiler = path.join(LKGDirectory, compilerFilename); @@ -277,6 +298,10 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu options += " --stripInternal" } + if (useBuiltCompiler && useTransforms) { + options += " --experimentalTransforms" + } + var cmd = host + " " + compilerPath + " " + options + " "; cmd = cmd + sources.join(" "); console.log(cmd + "\n"); @@ -400,6 +425,10 @@ task("setDebugMode", function() { useDebugMode = true; }); +task("setTransforms", function() { + useTransforms = true; +}); + task("configure-nightly", [configureNightlyJs], function() { var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs; console.log(cmd); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4ea2489de8886..08233c24fa013 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -37,7 +37,7 @@ namespace ts { return ModuleInstanceState.ConstEnumOnly; } // 3. non-exported import declarations - else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && !(node.flags & NodeFlags.Export)) { + else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && !(hasModifier(node, ModifierFlags.Export))) { return ModuleInstanceState.NonInstantiated; } // 4. other uninstantiated module declarations. @@ -133,7 +133,7 @@ namespace ts { let classifiableNames: Map; // state used to aggregate transform flags during bind. - let subtreeTransformFlags: TransformFlags; + let subtreeTransformFlags: TransformFlags = TransformFlags.None; let skipTransformFlagAggregation: boolean; function bindSourceFile(f: SourceFile, opts: CompilerOptions) { @@ -141,7 +141,6 @@ namespace ts { options = opts; inStrictMode = !!file.externalModuleIndicator; classifiableNames = {}; - subtreeTransformFlags = undefined; skipTransformFlagAggregation = isDeclarationFile(file); Symbol = objectAllocator.getSymbolConstructor(); @@ -167,6 +166,7 @@ namespace ts { hasAsyncFunctions = false; hasDecorators = false; hasParameterDecorators = false; + subtreeTransformFlags = TransformFlags.None; } return bindSourceFile; @@ -256,7 +256,7 @@ namespace ts { case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: - return node.flags & NodeFlags.Default ? "default" : undefined; + return hasModifier(node, ModifierFlags.Default) ? "default" : undefined; case SyntaxKind.JSDocFunctionType: return isJSDocConstructSignature(node) ? "__new" : "__call"; case SyntaxKind.Parameter: @@ -284,7 +284,7 @@ namespace ts { function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); - const isDefaultExport = node.flags & NodeFlags.Default; + const isDefaultExport = hasModifier(node, ModifierFlags.Default); // The exported symbol for an export default function/class node is always named "default" const name = isDefaultExport && parent ? "default" : getDeclarationName(node); @@ -329,7 +329,7 @@ namespace ts { : Diagnostics.Duplicate_identifier_0; forEach(symbol.declarations, declaration => { - if (declaration.flags & NodeFlags.Default) { + if (hasModifier(declaration, ModifierFlags.Default)) { message = Diagnostics.A_module_cannot_have_multiple_default_exports; } }); @@ -353,7 +353,7 @@ namespace ts { } function declareModuleMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags): Symbol { - const hasExportModifier = getCombinedNodeFlags(node) & NodeFlags.Export; + const hasExportModifier = getCombinedModifierFlags(node) & ModifierFlags.Export; if (symbolFlags & SymbolFlags.Alias) { if (node.kind === SyntaxKind.ExportSpecifier || (node.kind === SyntaxKind.ImportEqualsDeclaration && hasExportModifier)) { return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); @@ -862,7 +862,7 @@ namespace ts { } function declareClassMember(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) { - return node.flags & NodeFlags.Static + return hasModifier(node, ModifierFlags.Static) ? declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes) : declareSymbol(container.symbol.members, container.symbol, node, symbolFlags, symbolExcludes); } @@ -899,7 +899,7 @@ namespace ts { function bindModuleDeclaration(node: ModuleDeclaration) { setExportContextFlag(node); if (isAmbientModule(node)) { - if (node.flags & NodeFlags.Export) { + if (hasModifier(node, ModifierFlags.Export)) { errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible); } declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes); @@ -1184,41 +1184,22 @@ namespace ts { // symbols we do specialized work when we recurse. For example, we'll keep track of // the current 'container' node when it changes. This helps us know which symbol table // a local should go into for example. - aggregateTransformFlagsIfNeededAndBindChildren(node); - - inStrictMode = savedInStrictMode; - } - - function aggregateTransformFlagsIfNeededAndBindChildren(node: Node) { - if (node.transformFlags !== undefined) { - skipTransformFlagAggregationAndBindChildren(node); - } - else { - aggregateTransformFlagsAndBindChildren(node); + if (skipTransformFlagAggregation) { + bindChildren(node); } - } - - function skipTransformFlagAggregationAndBindChildren(node: Node) { - if (!skipTransformFlagAggregation) { + else if (node.transformFlags & TransformFlags.HasComputedFlags) { skipTransformFlagAggregation = true; bindChildren(node); skipTransformFlagAggregation = false; } else { - bindChildren(node); - } - } - - function aggregateTransformFlagsAndBindChildren(node: Node) { - if (!skipTransformFlagAggregation) { const savedSubtreeTransformFlags = subtreeTransformFlags; subtreeTransformFlags = 0; bindChildren(node); subtreeTransformFlags = savedSubtreeTransformFlags | computeTransformFlagsForNode(node, subtreeTransformFlags); } - else { - bindChildren(node); - } + + inStrictMode = savedInStrictMode; } function updateStrictMode(node: Node) { @@ -1799,15 +1780,9 @@ namespace ts { * @param subtreeFlags Transform flags computed for this node's subtree */ export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags): TransformFlags { - // Ambient nodes are TypeScript syntax and the flags of their subtree are ignored. - if (node.flags & NodeFlags.Ambient) { - return (node.transformFlags = TransformFlags.AssertTypeScript) - & ~(node.excludeTransformFlags = TransformFlags.NodeExcludes); - } - // Mark transformations needed for each node - let transformFlags: TransformFlags; - let excludeFlags: TransformFlags; + let transformFlags = TransformFlags.None; + let excludeFlags = TransformFlags.None; switch (node.kind) { case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: @@ -1823,7 +1798,7 @@ namespace ts { case SyntaxKind.AsExpression: case SyntaxKind.ReadonlyKeyword: // These nodes are TypeScript syntax. - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; break; case SyntaxKind.JsxElement: @@ -1835,12 +1810,12 @@ namespace ts { case SyntaxKind.JsxSpreadAttribute: case SyntaxKind.JsxExpression: // These nodes are Jsx syntax. - transformFlags |= TransformFlags.AssertJsx; + transformFlags = TransformFlags.AssertJsx; break; case SyntaxKind.ExportKeyword: // This node is both ES6 and TypeScript syntax. - transformFlags |= TransformFlags.AssertES6 | TransformFlags.TypeScript; + transformFlags = TransformFlags.AssertES6 | TransformFlags.TypeScript; break; case SyntaxKind.DefaultKeyword: @@ -1854,10 +1829,9 @@ namespace ts { case SyntaxKind.ForOfStatement: case SyntaxKind.YieldExpression: // These nodes are ES6 syntax. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; break; - case SyntaxKind.AnyKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.StringKeyword: @@ -1886,36 +1860,42 @@ namespace ts { case SyntaxKind.ThisType: case SyntaxKind.StringLiteralType: // Types and signatures are TypeScript syntax, and exclude all other facts. + subtreeFlags = TransformFlags.None; excludeFlags = TransformFlags.TypeExcludes; - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; break; case SyntaxKind.ComputedPropertyName: // Even though computed property names are ES6, we don't treat them as such. // This is so that they can flow through PropertyName transforms unaffected. // Instead, we mark the container as ES6, so that it can properly handle the transform. - transformFlags |= TransformFlags.ContainsComputedPropertyName; + transformFlags = TransformFlags.ContainsComputedPropertyName; break; case SyntaxKind.SpreadElementExpression: // This node is ES6 syntax, but is handled by a containing node. - transformFlags |= TransformFlags.ContainsSpreadElementExpression; + transformFlags = TransformFlags.ContainsSpreadElementExpression; break; case SyntaxKind.SuperKeyword: // This node is ES6 syntax. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; break; case SyntaxKind.ThisKeyword: // Mark this node and its ancestors as containing a lexical `this` keyword. - transformFlags |= TransformFlags.ContainsLexicalThis; + transformFlags = TransformFlags.ContainsLexicalThis; break; case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: // These nodes are ES6 syntax. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; + break; + + case SyntaxKind.Decorator: + // This node is TypeScript syntax, and marks its container as also being TypeScript syntax. + transformFlags = TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators; break; case SyntaxKind.ObjectLiteralExpression: @@ -1923,19 +1903,12 @@ namespace ts { if (subtreeFlags & TransformFlags.ContainsComputedPropertyName) { // If an ObjectLiteralExpression contains a ComputedPropertyName, then it // is an ES6 node. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; } break; case SyntaxKind.CallExpression: - excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes; - if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression - || isSuperCall(node)) { - // If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6 - // node. - transformFlags |= TransformFlags.AssertES6; - } - break; + return computeCallExpression(node, subtreeFlags); case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.NewExpression: @@ -1943,163 +1916,66 @@ namespace ts { if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression) { // If the this node contains a SpreadElementExpression, then it is an ES6 // node. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; } - break; - case SyntaxKind.Decorator: - // This node is TypeScript syntax, and marks its container as also being TypeScript syntax. - transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators; break; case SyntaxKind.ModuleDeclaration: + // An ambient declaration is TypeScript syntax. + if (hasModifier(node, ModifierFlags.Ambient)) { + subtreeFlags = TransformFlags.None; + } + // This node is TypeScript syntax, and excludes markers that should not escape the module scope. excludeFlags = TransformFlags.ModuleExcludes; - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; break; case SyntaxKind.ParenthesizedExpression: - // If the node is synthesized, it means the emitter put the parentheses there, - // not the user. If we didn't want them, the emitter would not have put them - // there. - if (!nodeIsSynthesized(node)) { - if ((node).expression.kind === SyntaxKind.AsExpression - || (node).expression.kind === SyntaxKind.TypeAssertionExpression) { - transformFlags = TransformFlags.AssertTypeScript; - } - } - - break; + return computeParenthesizedExpression(node, subtreeFlags); case SyntaxKind.BinaryExpression: - if (isDestructuringAssignment(node)) { - // Destructuring assignments are ES6 syntax. - transformFlags |= TransformFlags.AssertES6; - } - else if ((node).operatorToken.kind === SyntaxKind.AsteriskAsteriskToken - || (node).operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) { - // Exponentiation is ES7 syntax. - transformFlags |= TransformFlags.AssertES7; + return computeBinaryExpression(node, subtreeFlags); + + case SyntaxKind.ExpressionStatement: + // If the expression of an expression statement is a destructuring assignment, + // then we treat the statement as ES6 so that we can indicate that we do not + // need to hold on to the right-hand side. + if ((node).expression.transformFlags & TransformFlags.DestructuringAssignment) { + transformFlags = TransformFlags.AssertES6; } break; case SyntaxKind.Parameter: - // If the parameter has a question token, then it is TypeScript syntax. - if ((node).questionToken) { - transformFlags |= TransformFlags.AssertTypeScript; - } - - // If a parameter has an accessibility modifier, then it is TypeScript syntax. - if ((node).flags & NodeFlags.AccessibilityModifier) { - transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments; - } - - // If a parameter has an initializer, a binding pattern or a dotDotDot token, then - // it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel. - if ((node).initializer - || (node).dotDotDotToken - || isBindingPattern((node).name)) { - transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments; - } - - break; + return computeParameter(node, subtreeFlags); case SyntaxKind.ArrowFunction: - // An ArrowFunction is ES6 syntax, and excludes markers that should not escape the scope of an ArrowFunction. - excludeFlags = TransformFlags.ArrowFunctionExcludes; - transformFlags = TransformFlags.AssertES6; - - // If an ArrowFunction contains a lexical this, its container must capture the lexical this. - if (subtreeFlags & TransformFlags.ContainsLexicalThis) { - transformFlags |= TransformFlags.ContainsCapturedLexicalThis; - } - - // An async arrow function is TypeScript syntax. - if (node.flags & NodeFlags.Async) { - transformFlags |= TransformFlags.AssertTypeScript; - } - - break; + return computeArrowFunction(node, subtreeFlags); case SyntaxKind.FunctionExpression: - // A FunctionExpression excludes markers that should not escape the scope of a FunctionExpression. - excludeFlags = TransformFlags.FunctionExcludes; - - // If a FunctionExpression contains an asterisk token, or its subtree has marked the container - // as needing to capture the lexical this, then this node is ES6 syntax. - if ((node).asteriskToken - || subtreeFlags & TransformFlags.ContainsCapturedLexicalThis - || subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) { - transformFlags |= TransformFlags.AssertES6; - } - - // An async function expression is TypeScript syntax. - if (node.flags & NodeFlags.Async) { - transformFlags |= TransformFlags.AssertTypeScript; - } - - break; + return computeFunctionExpression(node, subtreeFlags); case SyntaxKind.FunctionDeclaration: - // A FunctionDeclaration excludes markers that should not escape the scope of a FunctionDeclaration. - excludeFlags = TransformFlags.FunctionExcludes; - - // A FunctionDeclaration without a body is an overload and is TypeScript syntax. - if (!(node).body) { - transformFlags = TransformFlags.AssertTypeScript; - break; - } - - // If a FunctionDeclaration has an asterisk token, is exported, or its - // subtree has marked the container as needing to capture the lexical `this`, - // then this node is ES6 syntax. - if ((node).asteriskToken - || node.flags & NodeFlags.Export - || subtreeFlags & TransformFlags.ContainsCapturedLexicalThis - || subtreeFlags & TransformFlags.ContainsDefaultValueAssignments) { - transformFlags |= TransformFlags.AssertES6; - } - - // An async function declaration is TypeScript syntax. - if (node.flags & NodeFlags.Async) { - transformFlags |= TransformFlags.AssertTypeScript; - } - - break; + return computeFunctionDeclaration(node, subtreeFlags); case SyntaxKind.VariableDeclaration: - // A VariableDeclaration with a binding pattern is ES6 syntax. - if (isBindingPattern((node).name)) { - transformFlags |= TransformFlags.AssertES6; - } - - break; + return computeVariableDeclaration(node, subtreeFlags); case SyntaxKind.VariableDeclarationList: // If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax. if (node.flags & NodeFlags.BlockScoped) { - transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding; + transformFlags = TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding; } break; case SyntaxKind.VariableStatement: - // If a VariableStatement is exported, then it is either ES6 or TypeScript syntax. - if (node.flags & NodeFlags.Export) { - transformFlags |= TransformFlags.AssertES6 | TransformFlags.AssertTypeScript; - } - - break; + return computeVariableStatement(node, subtreeFlags); case SyntaxKind.LabeledStatement: - // A labeled statement containing a block scoped binding *may* need to be transformed from ES6. - if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding - && isIterationStatement(this, /*lookInLabeledStatements*/ true)) { - transformFlags |= TransformFlags.AssertES6; - } - - break; + return computeLabeledStatement(node, subtreeFlags); case SyntaxKind.DoStatement: case SyntaxKind.WhileStatement: @@ -2107,36 +1983,26 @@ namespace ts { case SyntaxKind.ForInStatement: // A loop containing a block scoped binding *may* need to be transformed from ES6. if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding) { - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; } break; case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - // A ClassDeclarations or ClassExpression is ES6 syntax. - excludeFlags = TransformFlags.ClassExcludes; - transformFlags = TransformFlags.AssertES6; - - // A class with a parameter property assignment, property initializer, or decorator is - // TypeScript syntax. - if (subtreeFlags & TransformFlags.ContainsParameterPropertyAssignments - || subtreeFlags & TransformFlags.ContainsPropertyInitializer - || subtreeFlags & TransformFlags.ContainsDecorators) { - transformFlags |= TransformFlags.AssertTypeScript; - } + return computeClassDeclaration(node, subtreeFlags); - break; + case SyntaxKind.ClassExpression: + return computeClassExpression(node, subtreeFlags); case SyntaxKind.HeritageClause: if ((node).token === SyntaxKind.ExtendsKeyword) { // An `extends` HeritageClause is ES6 syntax. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; } else { // An `implements` HeritageClause is TypeScript syntax. Debug.assert((node).token === SyntaxKind.ImplementsKeyword); - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; } break; @@ -2144,7 +2010,7 @@ namespace ts { case SyntaxKind.ExpressionWithTypeArguments: // An ExpressionWithTypeArguments is ES6 syntax, as it is used in the // extends clause of a class. - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; // If an ExpressionWithTypeArguments contains type arguments, then it // is TypeScript syntax. @@ -2157,7 +2023,7 @@ namespace ts { case SyntaxKind.Constructor: // A Constructor is ES6 syntax. excludeFlags = TransformFlags.ConstructorExcludes; - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; // An overload constructor is TypeScript syntax. if (!(node).body) { @@ -2168,7 +2034,7 @@ namespace ts { case SyntaxKind.PropertyDeclaration: // A PropertyDeclaration is TypeScript syntax. - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; // If the PropertyDeclaration has an initializer, we need to inform its ancestor // so that it handle the transformation. @@ -2181,14 +2047,13 @@ namespace ts { case SyntaxKind.MethodDeclaration: // A MethodDeclaration is ES6 syntax. excludeFlags = TransformFlags.MethodOrAccessorExcludes; - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; // A MethodDeclaration is TypeScript syntax if it is either async, abstract, overloaded, // generic, or has both a computed property name and a decorator. if ((node).body === undefined || (node).typeParameters !== undefined - || node.flags & NodeFlags.Async - || node.flags & NodeFlags.Abstract + || hasModifier(node, ModifierFlags.Async | ModifierFlags.Abstract) || (subtreeFlags & TransformFlags.ContainsDecorators && subtreeFlags & TransformFlags.ContainsComputedPropertyName)) { transformFlags |= TransformFlags.AssertTypeScript; @@ -2203,10 +2068,10 @@ namespace ts { // A GetAccessor or SetAccessor is TypeScript syntax if it is either abstract, // or has both a computed property name and a decorator. - if (node.flags & NodeFlags.Abstract || - subtreeFlags & TransformFlags.ContainsDecorators && - subtreeFlags & TransformFlags.ContainsComputedPropertyName) { - transformFlags |= TransformFlags.AssertTypeScript; + if (hasModifier(node, ModifierFlags.Abstract) + || (subtreeFlags & TransformFlags.ContainsDecorators + && subtreeFlags & TransformFlags.ContainsComputedPropertyName)) { + transformFlags = TransformFlags.AssertTypeScript; } break; @@ -2214,7 +2079,7 @@ namespace ts { case SyntaxKind.ImportEqualsDeclaration: // An ImportEqualsDeclaration with a namespace reference is TypeScript. if (!isExternalModuleImportEqualsDeclaration(node)) { - transformFlags |= TransformFlags.AssertTypeScript; + transformFlags = TransformFlags.AssertTypeScript; } break; @@ -2223,20 +2088,258 @@ namespace ts { // If a PropertyAccessExpression starts with a super keyword, then it is // ES6 syntax, and requires a lexical `this` binding. if ((node).expression.kind === SyntaxKind.SuperKeyword) { - transformFlags |= TransformFlags.ContainsLexicalThis; + transformFlags = TransformFlags.ContainsLexicalThis; } break; case SyntaxKind.SourceFile: if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) { - transformFlags |= TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6; } break; } - return (node.transformFlags = subtreeFlags | transformFlags) - & ~(node.excludeTransformFlags = excludeFlags | TransformFlags.NodeExcludes); + return updateTransformFlags(node, subtreeFlags, transformFlags, excludeFlags); + } + + function computeCallExpression(node: CallExpression, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + if (subtreeFlags & TransformFlags.ContainsSpreadElementExpression + || isSuperCall(node) + || isSuperPropertyCall(node)) { + // If the this node contains a SpreadElementExpression, or is a super call, then it is an ES6 + // node. + transformFlags = TransformFlags.AssertES6; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ArrayLiteralOrCallOrNewExcludes); + } + + function computeBinaryExpression(node: BinaryExpression, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + if (isDestructuringAssignment(node)) { + // Destructuring assignments are ES6 syntax. + transformFlags = TransformFlags.AssertES6 | TransformFlags.DestructuringAssignment; + } + else if (isExponentiation(node)) { + // Exponentiation is ES7 syntax. + transformFlags = TransformFlags.AssertES7; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function isDestructuringAssignment(node: BinaryExpression) { + return node.operatorToken.kind === SyntaxKind.EqualsToken + && isObjectOrArrayLiteral(node.left); + } + + function isObjectOrArrayLiteral(node: Node) { + switch (node.kind) { + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ArrayLiteralExpression: + return true; + } + + return false; + } + + function isExponentiation(operatorToken: Node) { + switch (operatorToken.kind) { + case SyntaxKind.AsteriskAsteriskToken: + case SyntaxKind.AsteriskAsteriskEqualsToken: + return true; + } + + return false; + } + + function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + // If the parameter has a question token, then it is TypeScript syntax. + if (isDefined(node.questionToken)) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + // If a parameter has an accessibility modifier, then it is TypeScript syntax. + if (hasModifier(node, ModifierFlags.AccessibilityModifier)) { + transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments; + } + + // If a parameter has an initializer, a binding pattern or a dotDotDot token, then + // it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel. + if (isDefined(node.initializer) || isDefined(node.dotDotDotToken) || isBindingPattern(node.name)) { + transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function computeParenthesizedExpression(node: ParenthesizedExpression, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + // If the node is synthesized, it means the emitter put the parentheses there, + // not the user. If we didn't want them, the emitter would not have put them + // there. + if (node.expression.kind === SyntaxKind.AsExpression + || node.expression.kind === SyntaxKind.TypeAssertionExpression) { + transformFlags = TransformFlags.AssertTypeScript; + } + + // If the expression of a ParenthesizedExpression is a destructuring assignment, + // then the ParenthesizedExpression is a destructuring assignment. + if (node.expression.transformFlags & TransformFlags.DestructuringAssignment) { + transformFlags |= TransformFlags.DestructuringAssignment; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) { + // An ambient declaration is TypeScript syntax. + if (hasModifier(node, ModifierFlags.Ambient)) { + return updateTransformFlags(node, TransformFlags.None, TransformFlags.TypeScript, TransformFlags.ClassExcludes); + } + + // A ClassDeclaration is ES6 syntax. + let transformFlags = TransformFlags.AssertES6; + + // A class with a parameter property assignment, property initializer, or decorator is + // TypeScript syntax. + // An exported declaration may be TypeScript syntax. + if (subtreeFlags + & (TransformFlags.ContainsParameterPropertyAssignments + | TransformFlags.ContainsPropertyInitializer + | TransformFlags.ContainsDecorators) + || hasModifier(node, ModifierFlags.Export)) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); + } + + function computeClassExpression(node: ClassExpression, subtreeFlags: TransformFlags) { + // A ClassExpression is ES6 syntax. + let transformFlags = TransformFlags.AssertES6; + + // A class with a parameter property assignment, property initializer, or decorator is + // TypeScript syntax. + if (subtreeFlags + & (TransformFlags.ContainsParameterPropertyAssignments + | TransformFlags.ContainsPropertyInitializer + | TransformFlags.ContainsDecorators)) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ClassExcludes); + } + + function computeFunctionDeclaration(node: FunctionDeclaration, subtreeFlags: TransformFlags) { + const modifiers = getModifierFlags(node); + + // An ambient declaration is TypeScript syntax. + // A FunctionDeclaration without a body is an overload and is TypeScript syntax. + if (!node.body || modifiers & ModifierFlags.Ambient) { + return updateTransformFlags(node, TransformFlags.None, TransformFlags.AssertTypeScript, TransformFlags.FunctionExcludes); + } + + let transformFlags = TransformFlags.None; + + // If a FunctionDeclaration is exported, then it is either ES6 or TypeScript syntax. + if (modifiers & ModifierFlags.Export) { + transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.AssertES6; + } + + // If a FunctionDeclaration has an asterisk token, is exported, or its + // subtree has marked the container as needing to capture the lexical `this`, + // then this node is ES6 syntax. + if (subtreeFlags & (TransformFlags.ContainsCapturedLexicalThis | TransformFlags.ContainsDefaultValueAssignments) + || node.asteriskToken) { + transformFlags |= TransformFlags.AssertES6; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.FunctionExcludes); + } + + function computeFunctionExpression(node: FunctionExpression, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + + // An async function expression is TypeScript syntax. + if (hasModifier(node, ModifierFlags.Async)) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + // If a FunctionExpression contains an asterisk token, or its subtree has marked the container + // as needing to capture the lexical this, then this node is ES6 syntax. + if (subtreeFlags & (TransformFlags.ContainsCapturedLexicalThis | TransformFlags.ContainsDefaultValueAssignments) + || node.asteriskToken) { + transformFlags |= TransformFlags.AssertES6; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.FunctionExcludes); + } + + function computeArrowFunction(node: ArrowFunction, subtreeFlags: TransformFlags) { + // An ArrowFunction is ES6 syntax, and excludes markers that should not escape the scope of an ArrowFunction. + let transformFlags = TransformFlags.AssertES6; + + // An async arrow function is TypeScript syntax. + if (hasModifier(node, ModifierFlags.Async)) { + transformFlags |= TransformFlags.AssertTypeScript; + } + + // If an ArrowFunction contains a lexical this, its container must capture the lexical this. + if (subtreeFlags & TransformFlags.ContainsLexicalThis) { + transformFlags |= TransformFlags.ContainsCapturedLexicalThis; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ArrowFunctionExcludes); + } + + function computeVariableDeclaration(node: VariableDeclaration, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + + // A VariableDeclaration with a binding pattern is ES6 syntax. + if (isBindingPattern((node).name)) { + transformFlags = TransformFlags.AssertES6; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) { + const modifiers = getModifierFlags(node); + // An ambient declaration is TypeScript syntax. + if (modifiers & ModifierFlags.Ambient) { + return updateTransformFlags(node, TransformFlags.None, TransformFlags.AssertTypeScript, TransformFlags.None); + } + + let transformFlags = TransformFlags.None; + + // If a VariableStatement is exported, then it is either ES6 or TypeScript syntax. + if (modifiers & ModifierFlags.Export) { + transformFlags = TransformFlags.AssertES6 | TransformFlags.AssertTypeScript; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function computeLabeledStatement(node: LabeledStatement, subtreeFlags: TransformFlags) { + let transformFlags = TransformFlags.None; + + // A labeled statement containing a block scoped binding *may* need to be transformed from ES6. + if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding + && isIterationStatement(this, /*lookInLabeledStatements*/ true)) { + transformFlags = TransformFlags.AssertES6; + } + + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + } + + function updateTransformFlags(node: Node, subtreeFlags: TransformFlags, transformFlags: TransformFlags, excludeFlags: TransformFlags) { + node.transformFlags = transformFlags | subtreeFlags | TransformFlags.HasComputedFlags; + node.excludeTransformFlags = excludeFlags | TransformFlags.NodeExcludes; + return node.transformFlags & ~node.excludeTransformFlags; } } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cb9031fd9913..9b48b60b477a6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -535,7 +535,7 @@ namespace ts { const initializerOfNonStaticProperty = current.parent && current.parent.kind === SyntaxKind.PropertyDeclaration && - (current.parent.flags & NodeFlags.Static) === 0 && + (getModifierFlags(current.parent) & ModifierFlags.Static) === 0 && (current.parent).initializer === current; if (initializerOfNonStaticProperty) { @@ -653,7 +653,7 @@ namespace ts { // local variables of the constructor. This effectively means that entities from outer scopes // by the same name as a constructor parameter or local variable are inaccessible // in initializer expressions for instance member variables. - if (isClassLike(location.parent) && !(location.flags & NodeFlags.Static)) { + if (isClassLike(location.parent) && !(getModifierFlags(location) & ModifierFlags.Static)) { const ctor = findConstructorDeclaration(location.parent); if (ctor && ctor.locals) { if (getSymbol(ctor.locals, name, meaning & SymbolFlags.Value)) { @@ -667,7 +667,7 @@ namespace ts { case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: if (result = getSymbol(getSymbolOfNode(location).members, name, meaning & SymbolFlags.Type)) { - if (lastLocation && lastLocation.flags & NodeFlags.Static) { + if (lastLocation && getModifierFlags(lastLocation) & ModifierFlags.Static) { // TypeScript 1.0 spec (April 2014): 3.4.1 // The scope of a type parameter extends over the entire declaration with which the type // parameter list is associated, with the exception of static member declarations in classes. @@ -824,7 +824,7 @@ namespace ts { // No static member is present. // Check if we're in an instance method and look for a relevant instance member. - if (location === container && !(location.flags & NodeFlags.Static)) { + if (location === container && !(getModifierFlags(location) & ModifierFlags.Static)) { const instanceType = (getDeclaredTypeOfSymbol(classSymbol)).thisType; if (getPropertyOfType(instanceType, name)) { error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); @@ -1617,7 +1617,7 @@ namespace ts { const anyImportSyntax = getAnyImportSyntax(declaration); if (anyImportSyntax && - !(anyImportSyntax.flags & NodeFlags.Export) && // import clause without export + !(getModifierFlags(anyImportSyntax) & ModifierFlags.Export) && // import clause without export isDeclarationVisible(anyImportSyntax.parent)) { getNodeLinks(declaration).isVisible = true; if (aliasesToMakeVisible) { @@ -2014,7 +2014,7 @@ namespace ts { function shouldWriteTypeOfFunctionSymbol() { const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method - forEach(symbol.declarations, declaration => declaration.flags & NodeFlags.Static)); + forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static)); const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) && (symbol.parent || // is exported function symbol forEach(symbol.declarations, declaration => @@ -2306,7 +2306,7 @@ namespace ts { } const parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) - if (!(getCombinedNodeFlags(node) & NodeFlags.Export) && + if (!(getCombinedModifierFlags(node) & ModifierFlags.Export) && !(node.kind !== SyntaxKind.ImportEqualsDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { return isGlobalSourceFile(parent); } @@ -2319,7 +2319,7 @@ namespace ts { case SyntaxKind.SetAccessor: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - if (node.flags & (NodeFlags.Private | NodeFlags.Protected)) { + if (getModifierFlags(node) & (ModifierFlags.Private | ModifierFlags.Protected)) { // Private/protected properties/methods are not visible return false; } @@ -3867,7 +3867,7 @@ namespace ts { const type = getApparentType(current); if (type !== unknownType) { const prop = getPropertyOfType(type, name); - if (prop && !(getDeclarationFlagsFromSymbol(prop) & (NodeFlags.Private | NodeFlags.Protected))) { + if (prop && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))) { commonFlags &= prop.flags; if (!props) { props = [prop]; @@ -4309,7 +4309,7 @@ namespace ts { const declaration = getIndexDeclarationOfSymbol(symbol, kind); if (declaration) { return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType, - (declaration.flags & NodeFlags.Readonly) !== 0, declaration); + (getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration); } return undefined; } @@ -4845,8 +4845,8 @@ namespace ts { const container = getThisContainer(node, /*includeArrowFunctions*/ false); const parent = container && container.parent; if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) { - if (!(container.flags & NodeFlags.Static) && - (container.kind !== SyntaxKind.Constructor || isNodeDescendentOf(node, (container).body))) { + if (!(getModifierFlags(container) & ModifierFlags.Static) && + (container.kind !== SyntaxKind.Constructor || isNodeDescendantOf(node, (container).body))) { return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent)).thisType; } } @@ -5791,24 +5791,24 @@ namespace ts { } } else if (!(targetProp.flags & SymbolFlags.Prototype)) { - const sourcePropFlags = getDeclarationFlagsFromSymbol(sourceProp); - const targetPropFlags = getDeclarationFlagsFromSymbol(targetProp); - if (sourcePropFlags & NodeFlags.Private || targetPropFlags & NodeFlags.Private) { + const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp); + const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp); + if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) { if (sourceProp.valueDeclaration !== targetProp.valueDeclaration) { if (reportErrors) { - if (sourcePropFlags & NodeFlags.Private && targetPropFlags & NodeFlags.Private) { + if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) { reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp)); } else { reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp), - typeToString(sourcePropFlags & NodeFlags.Private ? source : target), - typeToString(sourcePropFlags & NodeFlags.Private ? target : source)); + typeToString(sourcePropFlags & ModifierFlags.Private ? source : target), + typeToString(sourcePropFlags & ModifierFlags.Private ? target : source)); } } return Ternary.False; } } - else if (targetPropFlags & NodeFlags.Protected) { + else if (targetPropFlags & ModifierFlags.Protected) { const sourceDeclaredInClass = sourceProp.parent && sourceProp.parent.flags & SymbolFlags.Class; const sourceClass = sourceDeclaredInClass ? getDeclaredTypeOfSymbol(getParentOfSymbol(sourceProp)) : undefined; const targetClass = getDeclaredTypeOfSymbol(getParentOfSymbol(targetProp)); @@ -5820,7 +5820,7 @@ namespace ts { return Ternary.False; } } - else if (sourcePropFlags & NodeFlags.Protected) { + else if (sourcePropFlags & ModifierFlags.Protected) { if (reportErrors) { reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2, symbolToString(targetProp), typeToString(source), typeToString(target)); @@ -6060,7 +6060,7 @@ namespace ts { const symbol = type.symbol; if (symbol && symbol.flags & SymbolFlags.Class) { const declaration = getClassLikeDeclarationOfSymbol(symbol); - if (declaration && declaration.flags & NodeFlags.Abstract) { + if (declaration && getModifierFlags(declaration) & ModifierFlags.Abstract) { return true; } } @@ -6100,8 +6100,8 @@ namespace ts { if (sourceProp === targetProp) { return Ternary.True; } - const sourcePropAccessibility = getDeclarationFlagsFromSymbol(sourceProp) & (NodeFlags.Private | NodeFlags.Protected); - const targetPropAccessibility = getDeclarationFlagsFromSymbol(targetProp) & (NodeFlags.Private | NodeFlags.Protected); + const sourcePropAccessibility = getDeclarationModifierFlagsFromSymbol(sourceProp) & ModifierFlags.NonPublicAccessibilityModifier; + const targetPropAccessibility = getDeclarationModifierFlagsFromSymbol(targetProp) & ModifierFlags.NonPublicAccessibilityModifier; if (sourcePropAccessibility !== targetPropAccessibility) { return Ternary.False; } @@ -7206,8 +7206,8 @@ namespace ts { let container = getContainingClass(node); while (container !== undefined) { if (container === localOrExportSymbol.valueDeclaration && container.name !== node) { - getNodeLinks(container).flags |= NodeCheckFlags.ClassWithBodyScopedClassBinding; - getNodeLinks(node).flags |= NodeCheckFlags.BodyScopedClassBinding; + getNodeLinks(container).flags |= NodeCheckFlags.DecoratedClassWithSelfReference; + getNodeLinks(node).flags |= NodeCheckFlags.SelfReferenceInDecoratedClass; break; } @@ -7323,7 +7323,7 @@ namespace ts { break; case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - if (container.flags & NodeFlags.Static) { + if (getModifierFlags(container) & ModifierFlags.Static) { error(node, Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer); // do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks } @@ -7339,7 +7339,7 @@ namespace ts { if (isClassLike(container.parent)) { const symbol = getSymbolOfNode(container.parent); - return container.flags & NodeFlags.Static ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol)).thisType; + return getModifierFlags(container) & ModifierFlags.Static ? getTypeOfSymbol(symbol) : (getDeclaredTypeOfSymbol(symbol)).thisType; } if (isInJavaScriptFile(node)) { @@ -7429,7 +7429,7 @@ namespace ts { return unknownType; } - if ((container.flags & NodeFlags.Static) || isCallExpression) { + if ((getModifierFlags(container) & ModifierFlags.Static) || isCallExpression) { nodeCheckFlag = NodeCheckFlags.SuperStatic; } else { @@ -7494,8 +7494,8 @@ namespace ts { // This helper creates an object with a "value" property that wraps the `super` property or indexed access for both get and set. // This is required for destructuring assignments, as a call expression cannot be used as the target of a destructuring assignment // while a property access can. - if (container.kind === SyntaxKind.MethodDeclaration && container.flags & NodeFlags.Async) { - if (isSuperPropertyOrElementAccess(node.parent) && isAssignmentTarget(node.parent)) { + if (container.kind === SyntaxKind.MethodDeclaration && getModifierFlags(container) & ModifierFlags.Async) { + if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) { getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding; } else { @@ -7560,7 +7560,7 @@ namespace ts { // topmost container must be something that is directly nested in the class declaration\object literal expression if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) { - if (container.flags & NodeFlags.Static) { + if (getModifierFlags(container) & ModifierFlags.Static) { return container.kind === SyntaxKind.MethodDeclaration || container.kind === SyntaxKind.MethodSignature || container.kind === SyntaxKind.GetAccessor || @@ -8785,8 +8785,12 @@ namespace ts { return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.PropertyDeclaration; } - function getDeclarationFlagsFromSymbol(s: Symbol): NodeFlags { - return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; + function getDeclarationModifierFlagsFromSymbol(s: Symbol): ModifierFlags { + return s.valueDeclaration ? getCombinedModifierFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? ModifierFlags.Public | ModifierFlags.Static : 0; + } + + function getDeclarationNodeFlagsFromSymbol(s: Symbol): NodeFlags { + return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : 0; } /** @@ -8798,7 +8802,7 @@ namespace ts { * @param prop The symbol for the right hand side of the property access. */ function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol): boolean { - const flags = getDeclarationFlagsFromSymbol(prop); + const flags = getDeclarationModifierFlagsFromSymbol(prop); const declaringClass = getDeclaredTypeOfSymbol(getParentOfSymbol(prop)); if (left.kind === SyntaxKind.SuperKeyword) { @@ -8821,7 +8825,7 @@ namespace ts { return false; } - if (flags & NodeFlags.Abstract) { + if (flags & ModifierFlags.Abstract) { // A method cannot be accessed in a super property access if the method is abstract. // This error could mask a private property access error. But, a member // cannot simultaneously be private and abstract, so this will trigger an @@ -8833,7 +8837,7 @@ namespace ts { } // Public properties are otherwise accessible. - if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) { + if (!(flags & ModifierFlags.NonPublicAccessibilityModifier)) { return true; } @@ -8844,7 +8848,7 @@ namespace ts { const enclosingClass = enclosingClassDeclaration ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined; // Private property is accessible if declaring and enclosing class are the same - if (flags & NodeFlags.Private) { + if (flags & ModifierFlags.Private) { if (declaringClass !== enclosingClass) { error(node, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(declaringClass)); return false; @@ -8864,7 +8868,7 @@ namespace ts { return false; } // No further restrictions for static properties - if (flags & NodeFlags.Static) { + if (flags & ModifierFlags.Static) { return true; } // An instance property must be accessed through an instance of the enclosing class @@ -10082,7 +10086,7 @@ namespace ts { // In the case of a merged class-module or class-interface declaration, // only the class declaration node will have the Abstract flag set. const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); - if (valueDecl && valueDecl.flags & NodeFlags.Abstract) { + if (valueDecl && getModifierFlags(valueDecl) & ModifierFlags.Abstract) { error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(valueDecl.name)); return resolveErrorCall(node); } @@ -10700,8 +10704,8 @@ namespace ts { // Variables declared with 'const' // Get accessors without matching set accessors // Enum members - return symbol.flags & SymbolFlags.Property && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Readonly) !== 0 || - symbol.flags & SymbolFlags.Variable && (getDeclarationFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 || + return symbol.flags & SymbolFlags.Property && (getDeclarationModifierFlagsFromSymbol(symbol) & ModifierFlags.Readonly) !== 0 || + symbol.flags & SymbolFlags.Variable && (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Const) !== 0 || symbol.flags & SymbolFlags.Accessor && !(symbol.flags & SymbolFlags.SetAccessor) || (symbol.flags & SymbolFlags.EnumMember) !== 0; } @@ -11516,7 +11520,7 @@ namespace ts { checkVariableLikeDeclaration(node); let func = getContainingFunction(node); - if (node.flags & NodeFlags.AccessibilityModifier) { + if (getModifierFlags(node) & ModifierFlags.AccessibilityModifier) { func = getContainingFunction(node); if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); @@ -11760,7 +11764,7 @@ namespace ts { // Abstract methods cannot have an implementation. // Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node. - if (node.flags & NodeFlags.Abstract && node.body) { + if (getModifierFlags(node) & ModifierFlags.Abstract && node.body) { error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); } } @@ -11822,7 +11826,7 @@ namespace ts { function isInstancePropertyWithInitializer(n: Node): boolean { return n.kind === SyntaxKind.PropertyDeclaration && - !(n.flags & NodeFlags.Static) && + !(getModifierFlags(n) & ModifierFlags.Static) && !!(n).initializer; } @@ -11847,7 +11851,7 @@ namespace ts { // or the containing class declares instance member variables with initializers. const superCallShouldBeFirst = forEach((node.parent).members, isInstancePropertyWithInitializer) || - forEach(node.parameters, p => p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)); + forEach(node.parameters, p => getModifierFlags(p) & ModifierFlags.AccessibilityModifier); // Skip past any prologue directives to find the first statement // to ensure that it was a super call. @@ -11905,7 +11909,7 @@ namespace ts { const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor; const otherAccessor = getDeclarationOfKind(node.symbol, otherKind); if (otherAccessor) { - if (((node.flags & NodeFlags.AccessibilityModifier) !== (otherAccessor.flags & NodeFlags.AccessibilityModifier))) { + if ((getModifierFlags(node) & ModifierFlags.AccessibilityModifier) !== (getModifierFlags(otherAccessor) & ModifierFlags.AccessibilityModifier)) { error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility); } @@ -12006,11 +12010,11 @@ namespace ts { } function isPrivateWithinAmbient(node: Node): boolean { - return (node.flags & NodeFlags.Private) && isInAmbientContext(node); + return (getModifierFlags(node) & ModifierFlags.Private) && isInAmbientContext(node); } - function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags): NodeFlags { - let flags = getCombinedNodeFlags(n); + function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags { + let flags = getCombinedModifierFlags(n); // children of classes (even ambient classes) should not be marked as ambient or export // because those flags have no useful semantics there. @@ -12018,11 +12022,11 @@ namespace ts { n.parent.kind !== SyntaxKind.ClassDeclaration && n.parent.kind !== SyntaxKind.ClassExpression && isInAmbientContext(n)) { - if (!(flags & NodeFlags.Ambient)) { + if (!(flags & ModifierFlags.Ambient)) { // It is nested in an ambient context, which means it is automatically exported - flags |= NodeFlags.Export; + flags |= ModifierFlags.Export; } - flags |= NodeFlags.Ambient; + flags |= ModifierFlags.Ambient; } return flags & flagsToCheck; @@ -12043,7 +12047,7 @@ namespace ts { return implementationSharesContainerWithFirstOverload ? implementation : overloads[0]; } - function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, flagsToCheck: NodeFlags, someOverloadFlags: NodeFlags, allOverloadFlags: NodeFlags): void { + function checkFlagAgreementBetweenOverloads(overloads: Declaration[], implementation: FunctionLikeDeclaration, flagsToCheck: ModifierFlags, someOverloadFlags: ModifierFlags, allOverloadFlags: ModifierFlags): void { // Error if some overloads have a flag that is not shared by all overloads. To find the // deviations, we XOR someOverloadFlags with allOverloadFlags const someButNotAllOverloadFlags = someOverloadFlags ^ allOverloadFlags; @@ -12052,16 +12056,16 @@ namespace ts { forEach(overloads, o => { const deviation = getEffectiveDeclarationFlags(o, flagsToCheck) ^ canonicalFlags; - if (deviation & NodeFlags.Export) { + if (deviation & ModifierFlags.Export) { error(o.name, Diagnostics.Overload_signatures_must_all_be_exported_or_not_exported); } - else if (deviation & NodeFlags.Ambient) { + else if (deviation & ModifierFlags.Ambient) { error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient); } - else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) { + else if (deviation & (ModifierFlags.Private | ModifierFlags.Protected)) { error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected); } - else if (deviation & NodeFlags.Abstract) { + else if (deviation & ModifierFlags.Abstract) { error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_not_abstract); } }); @@ -12080,8 +12084,8 @@ namespace ts { } } - const flagsToCheck: NodeFlags = NodeFlags.Export | NodeFlags.Ambient | NodeFlags.Private | NodeFlags.Protected | NodeFlags.Abstract; - let someNodeFlags: NodeFlags = 0; + const flagsToCheck: ModifierFlags = ModifierFlags.Export | ModifierFlags.Ambient | ModifierFlags.Private | ModifierFlags.Protected | ModifierFlags.Abstract; + let someNodeFlags: ModifierFlags = ModifierFlags.None; let allNodeFlags = flagsToCheck; let someHaveQuestionToken = false; let allHaveQuestionToken = true; @@ -12116,13 +12120,13 @@ namespace ts { if (node.name && (subsequentNode).name && (node.name).text === ((subsequentNode).name).text) { const reportError = (node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) && - (node.flags & NodeFlags.Static) !== (subsequentNode.flags & NodeFlags.Static); + (getModifierFlags(node) & ModifierFlags.Static) !== (getModifierFlags(subsequentNode) & ModifierFlags.Static); // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging // here we'll report error only for the first case since for second we should already report error in binder if (reportError) { - const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; + const diagnostic = getModifierFlags(node) & ModifierFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); } return; @@ -12140,7 +12144,7 @@ namespace ts { else { // Report different errors regarding non-consecutive blocks of declarations depending on whether // the node in question is abstract. - if (node.flags & NodeFlags.Abstract) { + if (getModifierFlags(node) & ModifierFlags.Abstract) { error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive); } else { @@ -12219,7 +12223,7 @@ namespace ts { // Abstract methods can't have an implementation -- in particular, they don't need one. if (!isExportSymbolInsideModule && lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body && - !(lastSeenNonAmbientDeclaration.flags & NodeFlags.Abstract)) { + !(getModifierFlags(lastSeenNonAmbientDeclaration) & ModifierFlags.Abstract)) { reportImplementationExpectedError(lastSeenNonAmbientDeclaration); } @@ -12269,10 +12273,10 @@ namespace ts { let defaultExportedDeclarationSpaces = SymbolFlags.None; for (const d of symbol.declarations) { const declarationSpaces = getDeclarationSpaces(d); - const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, NodeFlags.Export | NodeFlags.Default); + const effectiveDeclarationFlags = getEffectiveDeclarationFlags(d, ModifierFlags.Export | ModifierFlags.Default); - if (effectiveDeclarationFlags & NodeFlags.Export) { - if (effectiveDeclarationFlags & NodeFlags.Default) { + if (effectiveDeclarationFlags & ModifierFlags.Export) { + if (effectiveDeclarationFlags & ModifierFlags.Default) { defaultExportedDeclarationSpaces |= declarationSpaces; } else { @@ -13012,7 +13016,7 @@ namespace ts { if (localDeclarationSymbol && localDeclarationSymbol !== symbol && localDeclarationSymbol.flags & SymbolFlags.BlockScopedVariable) { - if (getDeclarationFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { + if (getDeclarationNodeFlagsFromSymbol(localDeclarationSymbol) & NodeFlags.BlockScoped) { const varDeclList = getAncestor(localDeclarationSymbol.valueDeclaration, SyntaxKind.VariableDeclarationList); const container = varDeclList.parent.kind === SyntaxKind.VariableStatement && varDeclList.parent.parent @@ -13788,7 +13792,7 @@ namespace ts { // Only process instance properties with computed names here. // Static properties cannot be in conflict with indexers, // and properties with literal names were already checked. - if (!(member.flags & NodeFlags.Static) && hasDynamicName(member)) { + if (!(getModifierFlags(member) & ModifierFlags.Static) && hasDynamicName(member)) { const propType = getTypeOfSymbol(member.symbol); checkIndexConstraintForProperty(member.symbol, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String); checkIndexConstraintForProperty(member.symbol, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number); @@ -13899,7 +13903,7 @@ namespace ts { } function checkClassDeclaration(node: ClassDeclaration) { - if (!node.name && !(node.flags & NodeFlags.Default)) { + if (!node.name && !(getModifierFlags(node) & ModifierFlags.Default)) { grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name); } checkClassLikeDeclaration(node); @@ -14019,7 +14023,7 @@ namespace ts { } const derived = getTargetSymbol(getPropertyOfObjectType(type, base.name)); - const baseDeclarationFlags = getDeclarationFlagsFromSymbol(base); + const baseDeclarationFlags = getDeclarationModifierFlagsFromSymbol(base); Debug.assert(!!derived, "derived should point to something, even if it is the base class' declaration."); @@ -14035,7 +14039,7 @@ namespace ts { // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - if (baseDeclarationFlags & NodeFlags.Abstract && (!derivedClassDecl || !(derivedClassDecl.flags & NodeFlags.Abstract))) { + if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !(getModifierFlags(derivedClassDecl) & ModifierFlags.Abstract))) { if (derivedClassDecl.kind === SyntaxKind.ClassExpression) { error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, symbolToString(baseProperty), typeToString(baseType)); @@ -14048,13 +14052,13 @@ namespace ts { } else { // derived overrides base. - const derivedDeclarationFlags = getDeclarationFlagsFromSymbol(derived); - if ((baseDeclarationFlags & NodeFlags.Private) || (derivedDeclarationFlags & NodeFlags.Private)) { + const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); + if ((baseDeclarationFlags & ModifierFlags.Private) || (derivedDeclarationFlags & ModifierFlags.Private)) { // either base or derived property is private - not override, skip it continue; } - if ((baseDeclarationFlags & NodeFlags.Static) !== (derivedDeclarationFlags & NodeFlags.Static)) { + if ((baseDeclarationFlags & ModifierFlags.Static) !== (derivedDeclarationFlags & ModifierFlags.Static)) { // value of 'static' is not the same for properties - not override, skip it continue; } @@ -14727,7 +14731,7 @@ namespace ts { // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors. return; } - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) { grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers); } if (checkExternalImportOrExportDeclaration(node)) { @@ -14757,7 +14761,7 @@ namespace ts { checkGrammarDecorators(node) || checkGrammarModifiers(node); if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) { checkImportBinding(node); - if (node.flags & NodeFlags.Export) { + if (getModifierFlags(node) & ModifierFlags.Export) { markExportAsReferenced(node); } if (isInternalModuleImportEqualsDeclaration(node)) { @@ -14790,7 +14794,7 @@ namespace ts { return; } - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) { grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers); } @@ -14849,7 +14853,7 @@ namespace ts { return; } // Grammar checking - if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && (node.flags & NodeFlags.Modifier)) { + if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) { grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers); } if (node.expression.kind === SyntaxKind.Identifier) { @@ -15177,7 +15181,7 @@ namespace ts { function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] { const symbols: SymbolTable = {}; - let memberFlags: NodeFlags = 0; + let memberFlags: ModifierFlags = ModifierFlags.None; if (isInsideWithStatementBody(location)) { // We cannot answer semantic questions within a with block, do not proceed any further @@ -15218,7 +15222,7 @@ namespace ts { // add the type parameters into the symbol table // (type parameters of classDeclaration/classExpression and interface are in member property of the symbol. // Note: that the memberFlags come from previous iteration. - if (!(memberFlags & NodeFlags.Static)) { + if (!(memberFlags & ModifierFlags.Static)) { copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type); } break; @@ -15234,7 +15238,7 @@ namespace ts { copySymbol(argumentsSymbol, meaning); } - memberFlags = location.flags; + memberFlags = getModifierFlags(location); location = location.parent; } @@ -15592,7 +15596,7 @@ namespace ts { */ function getParentTypeOfClassElement(node: ClassElement) { const classSymbol = getSymbolOfNode(node.parent); - return node.flags & NodeFlags.Static + return getModifierFlags(node) & ModifierFlags.Static ? getTypeOfSymbol(classSymbol) : getDeclaredTypeOfSymbol(classSymbol); } @@ -16169,7 +16173,7 @@ namespace ts { } let lastStatic: Node, lastPrivate: Node, lastProtected: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node; - let flags = 0; + let flags = ModifierFlags.None; for (const modifier of node.modifiers) { if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { if (node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.MethodSignature) { @@ -16201,22 +16205,22 @@ namespace ts { lastPrivate = modifier; } - if (flags & NodeFlags.AccessibilityModifier) { + if (flags & ModifierFlags.AccessibilityModifier) { return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen); } - else if (flags & NodeFlags.Static) { + else if (flags & ModifierFlags.Static) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static"); } - else if (flags & NodeFlags.Readonly) { + else if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "readonly"); } - else if (flags & NodeFlags.Async) { + else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); } else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); } - else if (flags & NodeFlags.Abstract) { + else if (flags & ModifierFlags.Abstract) { if (modifier.kind === SyntaxKind.PrivateKeyword) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "abstract"); } @@ -16228,13 +16232,13 @@ namespace ts { break; case SyntaxKind.StaticKeyword: - if (flags & NodeFlags.Static) { + if (flags & ModifierFlags.Static) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "static"); } - else if (flags & NodeFlags.Readonly) { + else if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly"); } - else if (flags & NodeFlags.Async) { + else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async"); } else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { @@ -16243,35 +16247,35 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "static"); } - else if (flags & NodeFlags.Abstract) { + else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); } - flags |= NodeFlags.Static; + flags |= ModifierFlags.Static; lastStatic = modifier; break; case SyntaxKind.ReadonlyKeyword: - if (flags & NodeFlags.Readonly) { + if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "readonly"); } else if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature && node.kind !== SyntaxKind.IndexSignature) { return grammarErrorOnNode(modifier, Diagnostics.readonly_modifier_can_only_appear_on_a_property_declaration_or_index_signature); } - flags |= NodeFlags.Readonly; + flags |= ModifierFlags.Readonly; lastReadonly = modifier; break; case SyntaxKind.ExportKeyword: - if (flags & NodeFlags.Export) { + if (flags & ModifierFlags.Export) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); } - else if (flags & NodeFlags.Ambient) { + else if (flags & ModifierFlags.Ambient) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "declare"); } - else if (flags & NodeFlags.Abstract) { + else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "abstract"); } - else if (flags & NodeFlags.Async) { + else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "export", "async"); } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { @@ -16280,14 +16284,14 @@ namespace ts { else if (node.kind === SyntaxKind.Parameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "export"); } - flags |= NodeFlags.Export; + flags |= ModifierFlags.Export; break; case SyntaxKind.DeclareKeyword: - if (flags & NodeFlags.Ambient) { + if (flags & ModifierFlags.Ambient) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "declare"); } - else if (flags & NodeFlags.Async) { + else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); } else if (node.parent.kind === SyntaxKind.ClassDeclaration) { @@ -16299,76 +16303,76 @@ namespace ts { else if (isInAmbientContext(node.parent) && node.parent.kind === SyntaxKind.ModuleBlock) { return grammarErrorOnNode(modifier, Diagnostics.A_declare_modifier_cannot_be_used_in_an_already_ambient_context); } - flags |= NodeFlags.Ambient; + flags |= ModifierFlags.Ambient; lastDeclare = modifier; break; case SyntaxKind.AbstractKeyword: - if (flags & NodeFlags.Abstract) { + if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); } if (node.kind !== SyntaxKind.ClassDeclaration) { if (node.kind !== SyntaxKind.MethodDeclaration) { return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_or_method_declaration); } - if (!(node.parent.kind === SyntaxKind.ClassDeclaration && node.parent.flags & NodeFlags.Abstract)) { + if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) { return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class); } - if (flags & NodeFlags.Static) { + if (flags & ModifierFlags.Static) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); } - if (flags & NodeFlags.Private) { + if (flags & ModifierFlags.Private) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); } } - flags |= NodeFlags.Abstract; + flags |= ModifierFlags.Abstract; break; case SyntaxKind.AsyncKeyword: - if (flags & NodeFlags.Async) { + if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); } - else if (flags & NodeFlags.Ambient || isInAmbientContext(node.parent)) { + else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); } else if (node.kind === SyntaxKind.Parameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); } - flags |= NodeFlags.Async; + flags |= ModifierFlags.Async; lastAsync = modifier; break; } } if (node.kind === SyntaxKind.Constructor) { - if (flags & NodeFlags.Static) { + if (flags & ModifierFlags.Static) { return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); } - if (flags & NodeFlags.Abstract) { + if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract"); } - else if (flags & NodeFlags.Protected) { + else if (flags & ModifierFlags.Protected) { return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected"); } - else if (flags & NodeFlags.Private) { + else if (flags & ModifierFlags.Private) { return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private"); } - else if (flags & NodeFlags.Async) { + else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); } - else if (flags & NodeFlags.Readonly) { + else if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(lastReadonly, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "readonly"); } return; } - else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & NodeFlags.Ambient) { + else if ((node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportEqualsDeclaration) && flags & ModifierFlags.Ambient) { return grammarErrorOnNode(lastDeclare, Diagnostics.A_0_modifier_cannot_be_used_with_an_import_declaration, "declare"); } - else if (node.kind === SyntaxKind.Parameter && (flags & NodeFlags.AccessibilityModifier) && isBindingPattern((node).name)) { + else if (node.kind === SyntaxKind.Parameter && (flags & ModifierFlags.AccessibilityModifier) && isBindingPattern((node).name)) { return grammarErrorOnNode(node, Diagnostics.A_parameter_property_may_not_be_a_binding_pattern); } - if (flags & NodeFlags.Async) { + if (flags & ModifierFlags.Async) { return checkGrammarAsyncModifier(node, lastAsync); } } @@ -16485,7 +16489,7 @@ namespace ts { if (parameter.dotDotDotToken) { return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter); } - if (parameter.flags & NodeFlags.Modifier) { + if (getModifierFlags(parameter) !== 0) { return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier); } if (parameter.questionToken) { @@ -16672,11 +16676,13 @@ namespace ts { } // Modifiers are never allowed on properties except for 'async' on a method declaration - forEach(prop.modifiers, mod => { - if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) { - grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); + if (prop.modifiers) { + for (const mod of prop.modifiers) { + if (mod.kind !== SyntaxKind.AsyncKeyword || prop.kind !== SyntaxKind.MethodDeclaration) { + grammarErrorOnNode(mod, Diagnostics._0_modifier_cannot_be_used_here, getTextOfNode(mod)); + } } - }); + } // ECMA-262 11.1.5 Object Initialiser // If previous is not undefined then throw a SyntaxError exception if any of the following conditions are true @@ -16830,7 +16836,7 @@ namespace ts { if (parameter.dotDotDotToken) { return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_set_accessor_cannot_have_rest_parameter); } - else if (parameter.flags & NodeFlags.Modifier) { + else if (getModifierFlags(parameter) !== 0) { return grammarErrorOnNode(accessor.name, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); } else if (parameter.questionToken) { @@ -17136,8 +17142,7 @@ namespace ts { node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.ExportDeclaration || node.kind === SyntaxKind.ExportAssignment || - (node.flags & NodeFlags.Ambient) || - (node.flags & (NodeFlags.Export | NodeFlags.Default))) { + getModifierFlags(node) & (ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default)) { return false; } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index d5bf95a64058a..cc2806f93c140 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -320,6 +320,13 @@ namespace ts { name: "allowSyntheticDefaultImports", type: "boolean", description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking + }, + { + // this option will be removed when this is merged with master and exists solely + // to enable the tree transforming emitter side-by-side with the existing emitter. + name: "experimentalTransforms", + type: "boolean", + experimental: true } ]; diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts new file mode 100644 index 0000000000000..a680d01e102a1 --- /dev/null +++ b/src/compiler/comments.ts @@ -0,0 +1,248 @@ +/// + +/* @internal */ +namespace ts { + export interface CommentWriter { + reset(): void; + setSourceFile(sourceFile: SourceFile): void; + getLeadingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[]; + getLeadingComments(range: TextRange): CommentRange[]; + getLeadingCommentsOfPosition(pos: number): CommentRange[]; + getTrailingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[]; + getTrailingComments(range: TextRange): CommentRange[]; + getTrailingCommentsOfPosition(pos: number): CommentRange[]; + emitLeadingComments(range: TextRange, comments?: CommentRange[]): void; + emitTrailingComments(range: TextRange, comments?: CommentRange[]): void; + emitDetachedComments(range: TextRange): void; + } + + export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter { + const compilerOptions = host.getCompilerOptions(); + const newLine = host.getNewLine(); + const { emitPos } = sourceMap; + + let currentSourceFile: SourceFile; + let currentText: string; + let currentLineMap: number[]; + let detachedCommentsInfo: { nodePos: number, detachedCommentEndPos: number}[]; + + // This maps start->end for a comment range. See `hasConsumedCommentRange` and + // `consumeCommentRange` for usage. + let consumedCommentRanges: number[]; + let leadingCommentRangePositions: boolean[]; + let trailingCommentRangePositions: boolean[]; + + return compilerOptions.removeComments + ? createCommentRemovingWriter() + : createCommentPreservingWriter(); + + function createCommentRemovingWriter(): CommentWriter { + return { + reset, + setSourceFile, + getLeadingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; }, + getLeadingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, + getTrailingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; }, + getTrailingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, + emitLeadingComments(range: TextRange, comments?: CommentRange[]): void { }, + emitTrailingComments(range: TextRange, comments?: CommentRange[]): void { }, + emitDetachedComments, + }; + + function emitDetachedComments(node: TextRange): void { + emitDetachedCommentsAndUpdateCommentsInfo(node, /*removeComments*/ true); + } + } + + function createCommentPreservingWriter(): CommentWriter { + const noComments: CommentRange[] = []; + return { + reset, + setSourceFile, + getLeadingComments, + getLeadingCommentsOfPosition, + getTrailingComments, + getTrailingCommentsOfPosition, + emitLeadingComments, + emitTrailingComments, + emitDetachedComments, + }; + + function getLeadingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) { + let comments = getLeadingCommentsOfPosition(range.pos); + if (getAdditionalRange) { + let additionalRange = getAdditionalRange(range); + while (additionalRange) { + comments = concatenate( + getLeadingCommentsOfPosition(additionalRange.pos), + comments + ); + + additionalRange = getAdditionalRange(additionalRange); + } + } + + return comments; + } + + function getTrailingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) { + let comments = getTrailingCommentsOfPosition(range.end); + if (getAdditionalRange) { + let additionalRange = getAdditionalRange(range); + while (additionalRange) { + comments = concatenate( + comments, + getTrailingCommentsOfPosition(additionalRange.end) + ); + + additionalRange = getAdditionalRange(additionalRange); + } + } + + return comments; + } + + function getLeadingCommentsOfPosition(pos: number) { + if (positionIsSynthesized(pos) || leadingCommentRangePositions[pos]) { + return undefined; + } + + leadingCommentRangePositions[pos] = true; + const comments = hasDetachedComments(pos) + ? getLeadingCommentsWithoutDetachedComments() + : getLeadingCommentRanges(currentText, pos); + return consumeCommentRanges(comments); + } + + function getTrailingCommentsOfPosition(pos: number) { + if (positionIsSynthesized(pos) || trailingCommentRangePositions[pos]) { + return undefined; + } + + trailingCommentRangePositions[pos] = true; + const comments = getTrailingCommentRanges(currentText, pos); + return consumeCommentRanges(comments); + } + + function emitLeadingComments(range: TextRange, comments = getLeadingComments(range)) { + emitNewLineBeforeLeadingComments(currentLineMap, writer, range, comments); + + // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space + emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); + } + + function emitTrailingComments(range: TextRange, comments = getTrailingComments(range)) { + // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ + emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment); + } + + function emitDetachedComments(range: TextRange) { + emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false); + } + + function hasConsumedCommentRange(comment: CommentRange) { + return comment.end === consumedCommentRanges[comment.pos]; + } + + function consumeCommentRange(comment: CommentRange) { + if (!hasConsumedCommentRange(comment)) { + consumedCommentRanges[comment.pos] = comment.end; + return true; + } + + return false; + } + + function consumeCommentRanges(comments: CommentRange[]) { + let consumed: CommentRange[]; + if (comments) { + let commentsSkipped = 0; + let commentsConsumed = 0; + for (let i = 0; i < comments.length; i++) { + const comment = comments[i]; + if (consumeCommentRange(comment)) { + commentsConsumed++; + if (commentsSkipped !== 0) { + if (consumed === undefined) { + consumed = [comment]; + } + else { + consumed.push(comment); + } + } + } + else { + commentsSkipped++; + if (commentsConsumed !== 0 && consumed === undefined) { + consumed = comments.slice(0, i); + } + } + } + + if (commentsConsumed) { + return consumed || comments; + } + } + + return noComments; + } + } + + function reset() { + currentSourceFile = undefined; + currentText = undefined; + currentLineMap = undefined; + detachedCommentsInfo = undefined; + consumedCommentRanges = undefined; + trailingCommentRangePositions = undefined; + leadingCommentRangePositions = undefined; + } + + function setSourceFile(sourceFile: SourceFile) { + currentSourceFile = sourceFile; + currentText = sourceFile.text; + currentLineMap = getLineStarts(sourceFile); + detachedCommentsInfo = undefined; + consumedCommentRanges = []; + leadingCommentRangePositions = []; + trailingCommentRangePositions = []; + } + + function hasDetachedComments(pos: number) { + return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos; + } + + function getLeadingCommentsWithoutDetachedComments() { + // get the leading comments from detachedPos + const pos = lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos; + const leadingComments = getLeadingCommentRanges(currentText, pos); + if (detachedCommentsInfo.length - 1) { + detachedCommentsInfo.pop(); + } + else { + detachedCommentsInfo = undefined; + } + + return leadingComments; + } + + function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange, removeComments: boolean) { + const currentDetachedCommentInfo = emitDetachedComments(currentText, currentLineMap, writer, writeComment, node, newLine, removeComments); + + if (currentDetachedCommentInfo) { + if (detachedCommentsInfo) { + detachedCommentsInfo.push(currentDetachedCommentInfo); + } + else { + detachedCommentsInfo = [currentDetachedCommentInfo]; + } + } + } + + function writeComment(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) { + emitPos(comment.pos); + writeCommentRange(text, lineMap, writer, comment, newLine); + emitPos(comment.end); + } + } +} \ No newline at end of file diff --git a/src/compiler/core.ts b/src/compiler/core.ts index a464bd8668240..e4bc42ee45e26 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -171,23 +171,116 @@ namespace ts { return result; } + /** + * Flattens an array containing a mix of array or non-array elements. + * + * @param array The array to flatten. + */ + export function flatten(array: (T | T[])[]): T[] { + let result: T[]; + if (array) { + result = []; + for (const v of array) { + if (v) { + if (isArray(v)) { + addRange(result, v); + } + else { + result.push(v); + } + } + } + } + + return result; + } + /** * Maps an array. If the mapped value is an array, it is spread into the result. + * + * @param array The array to map. + * @param mapfn The callback used to map the result into one or more values. */ - export function flatMap(array: T[], f: (x: T, i: number) => U | U[]): U[] { + export function flatMap(array: T[], mapfn: (x: T, i: number) => U | U[]): U[] { let result: U[]; if (array) { result = []; for (let i = 0; i < array.length; i++) { - const v = array[i]; - const ar = f(v, i); - if (ar) { - // We cast to here to leverage the behavior of Array#concat - // which will append a single value here. - result = result.concat(ar); + const v = mapfn(array[i], i); + if (v) { + if (isArray(v)) { + addRange(result, v); + } + else { + result.push(v); + } + } + } + } + return result; + } + + /** + * Computes the first matching span of elements and returns a tuple of the first span + * and the remaining elements. + */ + export function span(array: T[], f: (x: T, i: number) => boolean): [T[], T[]] { + if (array) { + for (let i = 0; i < array.length; i++) { + if (!f(array[i], i)) { + return [array.slice(0, i), array.slice(i)]; + } + } + return [array.slice(0), []]; + } + + return undefined; + } + + /** + * Maps contiguous spans of values with the same key. + * + * @param array The array to map. + * @param keyfn A callback used to select the key for an element. + * @param mapfn A callback used to map a contiguous chunk of values to a single value. + */ + export function spanMap(array: T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K) => U): U[] { + let result: U[]; + if (array) { + result = []; + const len = array.length; + let previousKey: K; + let key: K; + let start = 0; + let pos = 0; + while (start < len) { + while (pos < len) { + const value = array[pos]; + key = keyfn(value, pos); + if (pos === 0) { + previousKey = key; + } + else if (key !== previousKey) { + break; + } + + pos++; } + + if (start < pos) { + const v = mapfn(array.slice(start, pos), previousKey); + if (v) { + result.push(v); + } + + start = pos; + } + + previousKey = key; + pos++; } } + return result; } @@ -920,8 +1013,9 @@ namespace ts { this.pos = pos; this.end = end; this.flags = NodeFlags.None; - this.transformFlags = undefined; - this.excludeTransformFlags = undefined; + this.modifierFlagsCache = ModifierFlags.None; + this.transformFlags = TransformFlags.None; + this.excludeTransformFlags = TransformFlags.None; this.parent = undefined; this.original = undefined; } @@ -942,7 +1036,12 @@ namespace ts { } export namespace Debug { - const currentAssertionLevel = AssertionLevel.None; + declare var process: any; + declare var require: any; + + const currentAssertionLevel = getDevelopmentMode() === "development" + ? AssertionLevel.Normal + : AssertionLevel.None; export function shouldAssert(level: AssertionLevel): boolean { return currentAssertionLevel >= level; @@ -962,6 +1061,17 @@ namespace ts { export function fail(message?: string): void { Debug.assert(/*expression*/ false, message); } + + function getDevelopmentMode() { + return typeof require !== "undefined" + && typeof process !== "undefined" + && !process.browser + && process.nextTick + && process.env + && process.env.NODE_ENV + ? String(process.env.NODE_ENV).toLowerCase() + : undefined; + } } export function copyListRemovingItem(item: T, list: T[]) { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index ab0b16947fc49..655169b88e919 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -91,7 +91,7 @@ namespace ts { // Emit reference in dts, if the file reference was not already emitted if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) { // Add a reference to generated dts file, - // global file reference is added only + // global file reference is added only // - if it is not bundled emit (because otherwise it would be self reference) // - and it is not already added if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) { @@ -144,7 +144,7 @@ namespace ts { if (!isBundledEmit && isExternalModule(sourceFile) && sourceFile.moduleAugmentations.length && !resultHasExternalModuleIndicator) { // if file was external module with augmentations - this fact should be preserved in .d.ts as well. - // in case if we didn't write any external module specifiers in .d.ts we need to emit something + // in case if we didn't write any external module specifiers in .d.ts we need to emit something // that will force compiler to think that this file is an external module - 'export {}' is a reasonable choice here. write("export {};"); writeLine(); @@ -349,7 +349,7 @@ namespace ts { const jsDocComments = getJsDocCommentsFromText(declaration, currentText); emitNewLineBeforeLeadingComments(currentLineMap, writer, declaration, jsDocComments); // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange); + emitComments(currentText, currentLineMap, writer, jsDocComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeCommentRange); } } @@ -623,12 +623,13 @@ namespace ts { function emitModuleElementDeclarationFlags(node: Node) { // If the node is parented in the current source file we need to emit export declare or just export if (node.parent.kind === SyntaxKind.SourceFile) { + const modifiers = getModifierFlags(node); // If the node is exported - if (node.flags & NodeFlags.Export) { + if (modifiers & ModifierFlags.Export) { write("export "); } - if (node.flags & NodeFlags.Default) { + if (modifiers & ModifierFlags.Default) { write("default "); } else if (node.kind !== SyntaxKind.InterfaceDeclaration && !noDeclare) { @@ -637,21 +638,21 @@ namespace ts { } } - function emitClassMemberDeclarationFlags(flags: NodeFlags) { - if (flags & NodeFlags.Private) { + function emitClassMemberDeclarationFlags(flags: ModifierFlags) { + if (flags & ModifierFlags.Private) { write("private "); } - else if (flags & NodeFlags.Protected) { + else if (flags & ModifierFlags.Protected) { write("protected "); } - if (flags & NodeFlags.Static) { + if (flags & ModifierFlags.Static) { write("static "); } - if (flags & NodeFlags.Readonly) { + if (flags & ModifierFlags.Readonly) { write("readonly "); } - if (flags & NodeFlags.Abstract) { + if (flags & ModifierFlags.Abstract) { write("abstract "); } } @@ -660,7 +661,7 @@ namespace ts { // note usage of writer. methods instead of aliases created, just to make sure we are using // correct writer especially to handle asynchronous alias writing emitJsDocComments(node); - if (node.flags & NodeFlags.Export) { + if (hasModifier(node, ModifierFlags.Export)) { write("export "); } write("import "); @@ -698,12 +699,12 @@ namespace ts { } function writeImportDeclaration(node: ImportDeclaration) { - if (!node.importClause && !(node.flags & NodeFlags.Export)) { + if (!node.importClause && !hasModifier(node, ModifierFlags.Export)) { // do not write non-exported import declarations that don't have import clauses return; } emitJsDocComments(node); - if (node.flags & NodeFlags.Export) { + if (hasModifier(node, ModifierFlags.Export)) { write("export "); } write("import "); @@ -736,7 +737,7 @@ namespace ts { function emitExternalModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration) { // emitExternalModuleSpecifier is usually called when we emit something in the.d.ts file that will make it an external module (i.e. import/export declarations). - // the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered + // the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered // external modules since they are indistingushable from script files with ambient modules. To fix this in such d.ts files we'll emit top level 'export {}' // so compiler will treat them as external modules. resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || parent.kind !== SyntaxKind.ModuleDeclaration; @@ -893,7 +894,7 @@ namespace ts { } function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) { - return node.parent.kind === SyntaxKind.MethodDeclaration && (node.parent.flags & NodeFlags.Private); + return node.parent.kind === SyntaxKind.MethodDeclaration && hasModifier(node.parent, ModifierFlags.Private); } function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) { @@ -943,7 +944,7 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - if (node.parent.flags & NodeFlags.Static) { + if (hasModifier(node.parent, ModifierFlags.Static)) { diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1; } else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) { @@ -1018,7 +1019,7 @@ namespace ts { function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) { if (constructorDeclaration) { forEach(constructorDeclaration.parameters, param => { - if (param.flags & NodeFlags.AccessibilityModifier) { + if (hasModifier(param, ModifierFlags.AccessibilityModifier)) { emitPropertyDeclaration(param); } }); @@ -1027,7 +1028,7 @@ namespace ts { emitJsDocComments(node); emitModuleElementDeclarationFlags(node); - if (node.flags & NodeFlags.Abstract) { + if (hasModifier(node, ModifierFlags.Abstract)) { write("abstract "); } @@ -1077,7 +1078,7 @@ namespace ts { } emitJsDocComments(node); - emitClassMemberDeclarationFlags(node.flags); + emitClassMemberDeclarationFlags(getModifierFlags(node)); emitVariableDeclaration(node); write(";"); writeLine(); @@ -1102,7 +1103,7 @@ namespace ts { if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) { emitTypeOfVariableDeclarationFromTypeLiteral(node); } - else if (!(node.flags & NodeFlags.Private)) { + else if (!hasModifier(node, ModifierFlags.Private)) { writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError); } } @@ -1119,7 +1120,7 @@ namespace ts { // This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) { // TODO(jfreeman): Deal with computed properties in error reporting. - if (node.flags & NodeFlags.Static) { + if (hasModifier(node, ModifierFlags.Static)) { return symbolAccesibilityResult.errorModuleName ? symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : @@ -1230,9 +1231,9 @@ namespace ts { if (node === accessors.firstAccessor) { emitJsDocComments(accessors.getAccessor); emitJsDocComments(accessors.setAccessor); - emitClassMemberDeclarationFlags(node.flags | (accessors.setAccessor ? 0 : NodeFlags.Readonly)); + emitClassMemberDeclarationFlags(getModifierFlags(node) | (accessors.setAccessor ? 0 : ModifierFlags.Readonly)); writeTextOfNode(currentText, node.name); - if (!(node.flags & NodeFlags.Private)) { + if (!hasModifier(node, ModifierFlags.Private)) { accessorWithTypeAnnotation = node; let type = getTypeAnnotationFromAccessor(node); if (!type) { @@ -1263,7 +1264,7 @@ namespace ts { let diagnosticMessage: DiagnosticMessage; if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) { // Setters have to have type named and cannot infer it so, the type should always be named - if (accessorWithTypeAnnotation.parent.flags & NodeFlags.Static) { + if (hasModifier(accessorWithTypeAnnotation.parent, ModifierFlags.Static)) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 : Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1; @@ -1281,7 +1282,7 @@ namespace ts { }; } else { - if (accessorWithTypeAnnotation.flags & NodeFlags.Static) { + if (hasModifier(accessorWithTypeAnnotation, ModifierFlags.Static)) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : @@ -1317,7 +1318,7 @@ namespace ts { emitModuleElementDeclarationFlags(node); } else if (node.kind === SyntaxKind.MethodDeclaration) { - emitClassMemberDeclarationFlags(node.flags); + emitClassMemberDeclarationFlags(getModifierFlags(node)); } if (node.kind === SyntaxKind.FunctionDeclaration) { write("function "); @@ -1347,7 +1348,7 @@ namespace ts { if (node.kind === SyntaxKind.IndexSignature) { // Index signature can have readonly modifier - emitClassMemberDeclarationFlags(node.flags); + emitClassMemberDeclarationFlags(getModifierFlags(node)); write("["); } else { @@ -1378,7 +1379,7 @@ namespace ts { emitType(node.type); } } - else if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) { + else if (node.kind !== SyntaxKind.Constructor && !hasModifier(node, ModifierFlags.Private)) { writeReturnTypeAtSignature(node, getReturnTypeVisibilityError); } @@ -1415,7 +1416,7 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - if (node.flags & NodeFlags.Static) { + if (hasModifier(node, ModifierFlags.Static)) { diagnosticMessage = symbolAccesibilityResult.errorModuleName ? symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named : @@ -1481,7 +1482,7 @@ namespace ts { node.parent.parent.kind === SyntaxKind.TypeLiteral) { emitTypeOfVariableDeclarationFromTypeLiteral(node); } - else if (!(node.parent.flags & NodeFlags.Private)) { + else if (!hasModifier(node.parent, ModifierFlags.Private)) { writeTypeOfDeclaration(node, node.type, getParameterDeclarationTypeVisibilityError); } @@ -1517,7 +1518,7 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - if (node.parent.flags & NodeFlags.Static) { + if (hasModifier(node.parent, ModifierFlags.Static)) { return symbolAccesibilityResult.errorModuleName ? symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ? Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named : diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 37a278aee7a8a..ad942cdca5c10 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -346,7 +346,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; function isUniqueLocalName(name: string, container: Node): boolean { - for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) { + for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) { if (node.locals && hasProperty(node.locals, name)) { // We conservatively include alias symbols to cover cases where they're emitted as locals if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) { @@ -895,7 +895,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } function emitLiteral(node: LiteralExpression | TemplateLiteralFragment) { - const text = getLiteralText(node); + const text = getLiteralText(node, currentSourceFile, languageVersion); if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writer.writeLiteral(text); @@ -909,43 +909,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } } - function getLiteralText(node: LiteralExpression | TemplateLiteralFragment) { - // Any template literal or string literal with an extended escape - // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal. - if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { - return getQuotedEscapedLiteralText("\"", node.text, "\""); - } - - // If we don't need to downlevel and we can reach the original source text using - // the node's parent reference, then simply get the text as it was originally written. - if (node.parent) { - return getTextOfNodeFromSourceText(currentText, node); - } - - // If we can't reach the original source text, use the canonical form if it's a number, - // or an escaped quoted form of the original text if it's string-like. - switch (node.kind) { - case SyntaxKind.StringLiteral: - return getQuotedEscapedLiteralText("\"", node.text, "\""); - case SyntaxKind.NoSubstitutionTemplateLiteral: - return getQuotedEscapedLiteralText("`", node.text, "`"); - case SyntaxKind.TemplateHead: - return getQuotedEscapedLiteralText("`", node.text, "${"); - case SyntaxKind.TemplateMiddle: - return getQuotedEscapedLiteralText("}", node.text, "${"); - case SyntaxKind.TemplateTail: - return getQuotedEscapedLiteralText("}", node.text, "`"); - case SyntaxKind.NumericLiteral: - return node.text; - } - - Debug.fail(`Literal kind '${node.kind}' not accounted for.`); - } - - function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { - return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; - } - function emitDownlevelRawTemplateLiteral(node: LiteralExpression) { // Find original source text, since we need to emit the raw strings of the tagged template. // The raw strings contain the (escaped) strings of what the user wrote. @@ -1566,7 +1529,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge return; } } - else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.BodyScopedClassBinding) { + else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.SelfReferenceInDecoratedClass) { // Due to the emit for class decorators, any reference to the class from inside of the class body // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind // behavior of class names in ES6. @@ -1952,7 +1915,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge if (multiLine) { decreaseIndent(); - writeLine(); } write(")"); @@ -2272,13 +2234,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge return forEach(elements, e => e.kind === SyntaxKind.SpreadElementExpression); } - function skipParentheses(node: Expression): Expression { + function skipParenthesesAndAssertions(node: Expression): Expression { while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) { node = (node).expression; } return node; } + function skipAssertions(node: Expression): Expression { + while (node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) { + node = (node).expression; + } + return node; + } + function emitCallTarget(node: Expression): Expression { if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) { emit(node); @@ -2296,7 +2265,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function emitCallWithSpread(node: CallExpression) { let target: Expression; - const expr = skipParentheses(node.expression); + const expr = skipParenthesesAndAssertions(node.expression); if (expr.kind === SyntaxKind.PropertyAccessExpression) { // Target will be emitted as "this" argument target = emitCallTarget((expr).expression); @@ -2370,7 +2339,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge superCall = true; } else { - superCall = isSuperPropertyOrElementAccess(expression); + superCall = isSuperProperty(expression); isAsyncMethodWithSuper = superCall && isInAsyncMethodWithSuperInES6(node); emit(expression); } @@ -2610,7 +2579,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge let current = getRootDeclaration(node).parent; while (current) { if (current.kind === SyntaxKind.SourceFile) { - return !isExported || ((getCombinedNodeFlags(node) & NodeFlags.Export) !== 0); + return !isExported || ((getCombinedModifierFlags(node) & ModifierFlags.Export) !== 0); } else if (isDeclaration(current)) { return false; @@ -3345,8 +3314,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge // we can't reuse 'arr' because it might be modified within the body of the loop. const counter = createTempVariable(TempFlags._i); const rhsReference = createSynthesizedNode(SyntaxKind.Identifier) as Identifier; - rhsReference.text = node.expression.kind === SyntaxKind.Identifier ? - makeUniqueName((node.expression).text) : + const expressionWithoutAssertions = skipAssertions(node.expression); + rhsReference.text = expressionWithoutAssertions.kind === SyntaxKind.Identifier ? + makeUniqueName((expressionWithoutAssertions).text) : makeTempVariableName(TempFlags.Auto); // This is the let keyword for the counter and rhsReference. The let keyword for @@ -3657,7 +3627,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function emitModuleMemberName(node: Declaration) { emitStart(node.name); - if (getCombinedNodeFlags(node) & NodeFlags.Export) { + if (getCombinedModifierFlags(node) & ModifierFlags.Export) { const container = getContainingModule(node); if (container) { write(getGeneratedNameForNode(container)); @@ -3681,7 +3651,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function emitEs6ExportDefaultCompat(node: Node) { if (node.parent.kind === SyntaxKind.SourceFile) { - Debug.assert(!!(node.flags & NodeFlags.Default) || node.kind === SyntaxKind.ExportAssignment); + Debug.assert(hasModifier(node, ModifierFlags.Default) || node.kind === SyntaxKind.ExportAssignment); // only allow export default at a source file level if (modulekind === ModuleKind.CommonJS || modulekind === ModuleKind.AMD || modulekind === ModuleKind.UMD) { if (!isEs6Module) { @@ -3700,7 +3670,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } function emitExportMemberAssignment(node: FunctionLikeDeclaration | ClassDeclaration) { - if (node.flags & NodeFlags.Export) { + if (hasModifier(node, ModifierFlags.Export)) { writeLine(); emitStart(node); @@ -3709,7 +3679,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge // emit export default as // export("default", ) write(`${exportFunctionForFile}("`); - if (node.flags & NodeFlags.Default) { + if (hasModifier(node, ModifierFlags.Default)) { write("default"); } else { @@ -3720,7 +3690,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge write(")"); } else { - if (node.flags & NodeFlags.Default) { + if (hasModifier(node, ModifierFlags.Default)) { emitEs6ExportDefaultCompat(node); if (languageVersion === ScriptTarget.ES3) { write("exports[\"default\"]"); @@ -3851,7 +3821,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge // because actual variable declarations are hoisted let canDefineTempVariablesInPlace = false; if (root.kind === SyntaxKind.VariableDeclaration) { - const isExported = getCombinedNodeFlags(root) & NodeFlags.Export; + const isExported = getCombinedModifierFlags(root) & ModifierFlags.Export; const isSourceLevelForSystemModuleKind = shouldHoistDeclarationInSystemJsModule(root); canDefineTempVariablesInPlace = !isExported && !isSourceLevelForSystemModuleKind; } @@ -4193,7 +4163,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } function isES6ExportedDeclaration(node: Node) { - return !!(node.flags & NodeFlags.Export) && + return hasModifier(node, ModifierFlags.Export) && modulekind === ModuleKind.ES6 && node.parent.kind === SyntaxKind.SourceFile; } @@ -4201,7 +4171,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function emitVariableStatement(node: VariableStatement) { let startIsEmitted = false; - if (node.flags & NodeFlags.Export) { + if (hasModifier(node, ModifierFlags.Export)) { if (isES6ExportedDeclaration(node)) { // Exported ES6 module member write("export "); @@ -4230,7 +4200,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge function shouldEmitLeadingAndTrailingCommentsForVariableStatement(node: VariableStatement) { // If we're not exporting the variables, there's nothing special here. // Always emit comments for these nodes. - if (!(node.flags & NodeFlags.Export)) { + if (!hasModifier(node, ModifierFlags.Export)) { return true; } @@ -4361,7 +4331,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge writeLine(); emitStart(restParam); emitNodeWithCommentsAndWithoutSourcemap(restParam.name); - write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];"); + write(`[${tempName} - ${restIndex}] = arguments[${tempName}];`); emitEnd(restParam); decreaseIndent(); writeLine(); @@ -4438,7 +4408,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge if (!shouldEmitAsArrowFunction(node)) { if (isES6ExportedDeclaration(node)) { write("export "); - if (node.flags & NodeFlags.Default) { + if (hasModifier(node, ModifierFlags.Default)) { write("default "); } } @@ -4691,7 +4661,7 @@ const _super = (function (geti, seti) { } function emitExpressionFunctionBody(node: FunctionLikeDeclaration, body: Expression) { - if (languageVersion < ScriptTarget.ES6 || node.flags & NodeFlags.Async) { + if (languageVersion < ScriptTarget.ES6 || hasModifier(node, ModifierFlags.Async)) { emitDownLevelExpressionFunctionBody(node, body); return; } @@ -4807,7 +4777,7 @@ const _super = (function (geti, seti) { function emitParameterPropertyAssignments(node: ConstructorDeclaration) { forEach(node.parameters, param => { - if (param.flags & NodeFlags.AccessibilityModifier) { + if (hasModifier(param, ModifierFlags.AccessibilityModifier)) { writeLine(); emitStart(param); emitStart(param.name); @@ -4843,7 +4813,7 @@ const _super = (function (geti, seti) { function getInitializedProperties(node: ClassLikeDeclaration, isStatic: boolean) { const properties: PropertyDeclaration[] = []; for (const member of node.members) { - if (member.kind === SyntaxKind.PropertyDeclaration && isStatic === ((member.flags & NodeFlags.Static) !== 0) && (member).initializer) { + if (member.kind === SyntaxKind.PropertyDeclaration && isStatic === hasModifier(member, ModifierFlags.Static) && (member).initializer) { properties.push(member); } } @@ -4866,7 +4836,7 @@ const _super = (function (geti, seti) { emit(receiver); } else { - if (property.flags & NodeFlags.Static) { + if (hasModifier(property, ModifierFlags.Static)) { emitDeclarationName(node); } else { @@ -4968,7 +4938,7 @@ const _super = (function (geti, seti) { writeLine(); emitLeadingComments(member); emitStart(member); - if (member.flags & NodeFlags.Static) { + if (hasModifier(member, ModifierFlags.Static)) { write("static "); } @@ -5026,7 +4996,7 @@ const _super = (function (geti, seti) { emitCommentsOnNotEmittedNode(member); } // Check if there is any non-static property assignment - if (member.kind === SyntaxKind.PropertyDeclaration && (member).initializer && (member.flags & NodeFlags.Static) === 0) { + if (member.kind === SyntaxKind.PropertyDeclaration && (member).initializer && !hasModifier(member, ModifierFlags.Static)) { hasInstancePropertyWithInitializer = true; } }); @@ -5233,14 +5203,14 @@ const _super = (function (geti, seti) { // [Example 4] // - if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) { + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.DecoratedClassWithSelfReference) { decoratedClassAlias = unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default")); decoratedClassAliases[getNodeId(node)] = decoratedClassAlias; write(`let ${decoratedClassAlias};`); writeLine(); } - if (isES6ExportedDeclaration(node) && !(node.flags & NodeFlags.Default)) { + if (isES6ExportedDeclaration(node) && !hasModifier(node, ModifierFlags.Default)) { write("export "); } @@ -5254,7 +5224,7 @@ const _super = (function (geti, seti) { } else if (isES6ExportedDeclaration(node)) { write("export "); - if (node.flags & NodeFlags.Default) { + if (hasModifier(node, ModifierFlags.Default)) { write("default "); } } @@ -5288,7 +5258,7 @@ const _super = (function (geti, seti) { // emit name if // - node has a name // - this is default export with static initializers - if (node.name || (node.flags & NodeFlags.Default && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !thisNodeIsDecorated)) { + if (node.name || (hasModifier(node, ModifierFlags.Default) && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !thisNodeIsDecorated)) { write(" "); emitDeclarationName(node); } @@ -5337,7 +5307,7 @@ const _super = (function (geti, seti) { emitDecoratorsOfClass(node, decoratedClassAlias); } - if (!(node.flags & NodeFlags.Export)) { + if (!hasModifier(node, ModifierFlags.Export)) { return; } if (modulekind !== ModuleKind.ES6) { @@ -5346,7 +5316,7 @@ const _super = (function (geti, seti) { else { // If this is an exported class, but not on the top level (i.e. on an internal // module), export it - if (node.flags & NodeFlags.Default) { + if (hasModifier(node, ModifierFlags.Default)) { // if this is a top level default export of decorated class, write the export after the declaration. if (thisNodeIsDecorated) { writeLine(); @@ -5377,6 +5347,18 @@ const _super = (function (geti, seti) { write(" = "); } + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression; + let tempVariable: Identifier; + + if (isClassExpressionWithStaticProperties) { + tempVariable = createAndRecordTempVariable(TempFlags.Auto); + write("("); + increaseIndent(); + emit(tempVariable); + write(" = "); + } + write("(function ("); const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { @@ -5406,9 +5388,6 @@ const _super = (function (geti, seti) { writeLine(); emitConstructor(node, baseTypeNode); emitMemberFunctionsForES5AndLower(node); - emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true)); - writeLine(); - emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined); writeLine(); emitToken(SyntaxKind.CloseBraceToken, node.members.end, () => { write("return "); @@ -5435,7 +5414,22 @@ const _super = (function (geti, seti) { write("))"); if (node.kind === SyntaxKind.ClassDeclaration) { write(";"); + emitPropertyDeclarations(node, staticProperties); + emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined); } + else if (isClassExpressionWithStaticProperties) { + for (const property of staticProperties) { + write(","); + writeLine(); + emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true); + } + write(","); + writeLine(); + emit(tempVariable); + decreaseIndent(); + write(")"); + } + emitEnd(node); if (node.kind === SyntaxKind.ClassDeclaration) { @@ -5445,14 +5439,14 @@ const _super = (function (geti, seti) { function emitClassMemberPrefix(node: ClassLikeDeclaration, member: Node) { emitDeclarationName(node); - if (!(member.flags & NodeFlags.Static)) { + if (!hasModifier(member, ModifierFlags.Static)) { write(".prototype"); } } function emitDecoratorsOfClass(node: ClassLikeDeclaration, decoratedClassAlias: string) { emitDecoratorsOfMembers(node, /*staticFlag*/ 0); - emitDecoratorsOfMembers(node, NodeFlags.Static); + emitDecoratorsOfMembers(node, ModifierFlags.Static); emitDecoratorsOfConstructor(node, decoratedClassAlias); } @@ -5506,10 +5500,10 @@ const _super = (function (geti, seti) { writeLine(); } - function emitDecoratorsOfMembers(node: ClassLikeDeclaration, staticFlag: NodeFlags) { + function emitDecoratorsOfMembers(node: ClassLikeDeclaration, staticFlag: ModifierFlags) { for (const member of node.members) { // only emit members in the correct group - if ((member.flags & NodeFlags.Static) !== staticFlag) { + if ((getModifierFlags(member) & ModifierFlags.Static) !== staticFlag) { continue; } @@ -5970,7 +5964,7 @@ const _super = (function (geti, seti) { // do not emit var if variable was already hoisted const isES6ExportedEnum = isES6ExportedDeclaration(node); - if (!(node.flags & NodeFlags.Export) || (isES6ExportedEnum && isFirstDeclarationOfKind(node, node.symbol && node.symbol.declarations, SyntaxKind.EnumDeclaration))) { + if (!hasModifier(node, ModifierFlags.Export) || (isES6ExportedEnum && isFirstDeclarationOfKind(node, node.symbol && node.symbol.declarations, SyntaxKind.EnumDeclaration))) { emitStart(node); if (isES6ExportedEnum) { write("export "); @@ -5999,7 +5993,7 @@ const _super = (function (geti, seti) { emitModuleMemberName(node); write(" = {}));"); emitEnd(node); - if (!isES6ExportedDeclaration(node) && node.flags & NodeFlags.Export && !shouldHoistDeclarationInSystemJsModule(node)) { + if (!isES6ExportedDeclaration(node) && hasModifier(node, ModifierFlags.Export) && !shouldHoistDeclarationInSystemJsModule(node)) { // do not emit var if variable was already hoisted writeLine(); emitStart(node); @@ -6011,7 +6005,7 @@ const _super = (function (geti, seti) { write(";"); } if (modulekind !== ModuleKind.ES6 && node.parent === currentSourceFile) { - if (modulekind === ModuleKind.System && (node.flags & NodeFlags.Export)) { + if (modulekind === ModuleKind.System && hasModifier(node, ModifierFlags.Export)) { // write the call to exporter for enum writeLine(); write(`${exportFunctionForFile}("`); @@ -6133,7 +6127,7 @@ const _super = (function (geti, seti) { } write(")("); // write moduleDecl = containingModule.m only if it is not exported es6 module member - if ((node.flags & NodeFlags.Export) && !isES6ExportedDeclaration(node)) { + if (hasModifier(node, ModifierFlags.Export) && !isES6ExportedDeclaration(node)) { emit(node.name); write(" = "); } @@ -6143,7 +6137,7 @@ const _super = (function (geti, seti) { write(" = {}));"); emitEnd(node); if (!isES6ExportedDeclaration(node) && node.name.kind === SyntaxKind.Identifier && node.parent === currentSourceFile) { - if (modulekind === ModuleKind.System && (node.flags & NodeFlags.Export)) { + if (modulekind === ModuleKind.System && hasModifier(node, ModifierFlags.Export)) { writeLine(); write(`${exportFunctionForFile}("`); emitDeclarationName(node); @@ -6255,7 +6249,7 @@ const _super = (function (geti, seti) { function emitExternalImportDeclaration(node: ImportDeclaration | ImportEqualsDeclaration) { if (contains(externalImports, node)) { - const isExportedImport = node.kind === SyntaxKind.ImportEqualsDeclaration && (node.flags & NodeFlags.Export) !== 0; + const isExportedImport = node.kind === SyntaxKind.ImportEqualsDeclaration && hasModifier(node, ModifierFlags.Export); const namespaceDeclaration = getNamespaceDeclarationNode(node); const varOrConst = (languageVersion <= ScriptTarget.ES5) ? "var " : "const "; @@ -6345,7 +6339,7 @@ const _super = (function (geti, seti) { write("export "); write("var "); } - else if (!(node.flags & NodeFlags.Export)) { + else if (!hasModifier(node, ModifierFlags.Export)) { write("var "); } } @@ -6590,7 +6584,8 @@ const _super = (function (geti, seti) { } const moduleName = getExternalModuleName(importNode); if (moduleName.kind === SyntaxKind.StringLiteral) { - return tryRenameExternalModule(moduleName) || getLiteralText(moduleName); + return tryRenameExternalModule(moduleName) + || getLiteralText(moduleName, currentSourceFile, languageVersion); } return undefined; @@ -6737,7 +6732,7 @@ const _super = (function (geti, seti) { function writeExportedName(node: Identifier | Declaration): void { // do not record default exports // they are local to module and never overwritten (explicitly skipped) by star export - if (node.kind !== SyntaxKind.Identifier && node.flags & NodeFlags.Default) { + if (node.kind !== SyntaxKind.Identifier && hasModifier(node, ModifierFlags.Default)) { return; } @@ -6809,8 +6804,8 @@ const _super = (function (geti, seti) { emit(local); } - const flags = getCombinedNodeFlags(local.kind === SyntaxKind.Identifier ? local.parent : local); - if (flags & NodeFlags.Export) { + const flags = getCombinedModifierFlags(local.kind === SyntaxKind.Identifier ? local.parent : local); + if (flags & ModifierFlags.Export) { if (!exportedDeclarations) { exportedDeclarations = []; } @@ -6825,7 +6820,7 @@ const _super = (function (geti, seti) { writeLine(); emit(f); - if (f.flags & NodeFlags.Export) { + if (hasModifier(f, ModifierFlags.Export)) { if (!exportedDeclarations) { exportedDeclarations = []; } @@ -6837,7 +6832,7 @@ const _super = (function (geti, seti) { return exportedDeclarations; function visit(node: Node): void { - if (node.flags & NodeFlags.Ambient) { + if (hasModifier(node, ModifierFlags.Ambient)) { return; } @@ -7601,7 +7596,7 @@ const _super = (function (geti, seti) { function emitNodeConsideringCommentsOption(node: Node, emitNodeConsideringSourcemap: (node: Node) => void): void { if (node) { - if (node.flags & NodeFlags.Ambient) { + if (hasModifier(node, ModifierFlags.Ambient)) { return emitCommentsOnNotEmittedNode(node); } @@ -7973,7 +7968,7 @@ const _super = (function (geti, seti) { emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitTrailingComments(node: Node) { @@ -7985,7 +7980,7 @@ const _super = (function (geti, seti) { const trailingComments = getTrailingCommentsToEmit(node); // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ - emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment); } /** @@ -8000,8 +7995,8 @@ const _super = (function (geti, seti) { const trailingComments = getTrailingCommentRanges(currentText, pos); - // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ - emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ true, newLine, writeComment); + // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space + emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitLeadingCommentsOfPositionWorker(pos: number) { @@ -8022,7 +8017,7 @@ const _super = (function (geti, seti) { emitNewLineBeforeLeadingComments(currentLineMap, writer, { pos: pos, end: pos }, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 8f388a01520b6..84eb1ac62ccd8 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -46,55 +46,9 @@ namespace ts { array.hasTrailingComma = true; } - array.arrayKind = ArrayKind.NodeArray; return array; } - export function createModifiersArray(elements?: Modifier[], location?: TextRange): ModifiersArray { - let flags: NodeFlags; - if (elements) { - if (isModifiersArray(elements)) { - return elements; - } - - flags = 0; - for (const modifier of elements) { - flags |= modifierToFlag(modifier.kind); - } - } - else { - elements = []; - flags = 0; - } - - const array = elements; - if (location) { - array.pos = location.pos; - array.end = location.end; - } - else { - array.pos = -1; - array.end = -1; - } - - array.arrayKind = ArrayKind.ModifiersArray; - array.flags = flags; - return array; - } - - export function setModifiers(node: T, modifiers: Modifier[]) { - if (modifiers) { - const array = createModifiersArray(modifiers); - node.modifiers = array; - node.flags |= array.flags; - } - else { - node.modifiers = undefined; - } - - return node; - } - export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { const node = createNode(kind, /*location*/ undefined); node.startsOnNewLine = startsOnNewLine; @@ -105,26 +59,16 @@ namespace ts { return createNodeArray(elements, /*location*/ undefined); } - export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray { - return createModifiersArray(elements, /*location*/ undefined); - } - /** - * Creates a shallow, memberwise clone of a node. The "kind", "pos", "end", "flags", and "parent" - * properties are excluded by default, and can be provided via the "location", "flags", and - * "parent" parameters. - * - * @param node The node to clone. - * @param location An optional TextRange to use to supply the new position. - * @param flags The NodeFlags to use for the cloned node. - * @param parent The parent for the new node. - * @param original An optional pointer to the original source tree node. + * Creates a shallow, memberwise clone of a node with no source map location. */ - export function cloneNode(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node, original?: Node): T { + export function getSynthesizedClone(node: T): T { // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of // the original node. We also need to exclude specific properties and only include own- // properties (to skip members already defined on the shared prototype). - const clone = createNode(node.kind, location); + const clone = createSynthesizedNode(node.kind); + clone.flags = node.flags; + clone.original = node; for (const key in node) { if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { @@ -134,32 +78,28 @@ namespace ts { (clone)[key] = (node)[key]; } - if (flags !== undefined) { - clone.flags = flags; - } - - if (parent !== undefined) { - clone.parent = parent; - } - - if (original !== undefined) { - clone.original = original; - } - return clone; } /** * Creates a shallow, memberwise clone of a node for mutation. */ - export function getMutableNode(node: T): T { - return cloneNode(node, node, node.flags, node.parent, node); + export function getMutableClone(node: T): T { + const clone = getSynthesizedClone(node); + clone.pos = node.pos; + clone.end = node.end; + clone.parent = node.parent; + return clone; } - export function createNodeArrayNode(elements: T[]): NodeArrayNode { - const node = >createSynthesizedNode(SyntaxKind.NodeArrayNode); - node.nodes = createNodeArray(elements); - return node; + /** + * Creates a shallow, memberwise clone of a node at the specified source map location. + */ + export function getRelocatedClone(node: T, location: TextRange): T { + const clone = getSynthesizedClone(node); + clone.pos = location.pos; + clone.end = location.end; + return clone; } // Literals @@ -185,24 +125,38 @@ namespace ts { // Identifiers - export function createIdentifier(text: string): Identifier { - const node = createNode(SyntaxKind.Identifier); + export function createIdentifier(text: string, location?: TextRange): Identifier { + const node = createNode(SyntaxKind.Identifier, location); node.text = text; return node; } - export function createTempVariable(): Identifier { - const name = createNode(SyntaxKind.Identifier); - name.text = undefined; - name.tempKind = TempVariableKind.Auto; + export function createTempVariable(location?: TextRange): Identifier { + const name = createNode(SyntaxKind.Identifier, location); + name.autoGenerateKind = GeneratedIdentifierKind.Auto; getNodeId(name); return name; } - export function createLoopVariable(): Identifier { - const name = createNode(SyntaxKind.Identifier); - name.text = undefined; - name.tempKind = TempVariableKind.Loop; + export function createLoopVariable(location?: TextRange): Identifier { + const name = createNode(SyntaxKind.Identifier, location); + name.autoGenerateKind = GeneratedIdentifierKind.Loop; + getNodeId(name); + return name; + } + + export function createUniqueName(text: string, location?: TextRange): Identifier { + const name = createNode(SyntaxKind.Identifier, location); + name.text = text; + name.autoGenerateKind = GeneratedIdentifierKind.Unique; + getNodeId(name); + return name; + } + + export function getGeneratedNameForNode(node: Node, location?: TextRange): Identifier { + const name = createNode(SyntaxKind.Identifier, location); + name.autoGenerateKind = GeneratedIdentifierKind.Node; + name.original = node; getNodeId(name); return name; } @@ -237,7 +191,7 @@ namespace ts { export function createMethod(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { const node = createNode(SyntaxKind.MethodDeclaration, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; node.parameters = createNodeArray(parameters); @@ -259,7 +213,7 @@ namespace ts { export function createGetAccessor(modifiers: Modifier[], name: string | PropertyName, body: Block, location?: TextRange) { const node = createNode(SyntaxKind.GetAccessor, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; node.parameters = createNodeArray(); @@ -270,7 +224,7 @@ namespace ts { export function createSetAccessor(modifiers: Modifier[], name: string | PropertyName, parameter: ParameterDeclaration, body: Block, location?: TextRange) { const node = createNode(SyntaxKind.SetAccessor, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; node.parameters = createNodeArray([parameter]); @@ -292,15 +246,21 @@ namespace ts { // Expression - export function createArrayLiteral(elements?: Expression[]) { - const node = createNode(SyntaxKind.ArrayLiteralExpression); + export function createArrayLiteral(elements?: Expression[], location?: TextRange, multiLine?: boolean) { + const node = createNode(SyntaxKind.ArrayLiteralExpression, location); node.elements = parenthesizeListElements(createNodeArray(elements)); + if (multiLine) { + node.multiLine = multiLine; + } return node; } - export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange) { + export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange, multiLine?: boolean) { const node = createNode(SyntaxKind.ObjectLiteralExpression, location); node.properties = createNodeArray(properties); + if (multiLine) { + node.multiLine = multiLine; + } return node; } @@ -328,7 +288,7 @@ namespace ts { export function createNew(expression: Expression, argumentsArray: Expression[], location?: TextRange) { const node = createNode(SyntaxKind.NewExpression, location); - node.expression = parenthesizeForAccess(expression); + node.expression = parenthesizeForNew(expression); node.arguments = argumentsArray ? parenthesizeListElements(createNodeArray(argumentsArray)) : undefined; @@ -341,7 +301,7 @@ namespace ts { return node; } - export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { + export function createFunctionExpression(asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) { const node = createNode(SyntaxKind.FunctionExpression, location); node.modifiers = undefined; node.asteriskToken = asteriskToken; @@ -350,6 +310,10 @@ namespace ts { node.parameters = createNodeArray(parameters); node.type = undefined; node.body = body; + if (original) { + node.original = original; + } + return node; } @@ -440,16 +404,19 @@ namespace ts { // Element - export function createBlock(statements: Statement[], location?: TextRange): Block { + export function createBlock(statements: Statement[], location?: TextRange, multiLine?: boolean): Block { const block = createNode(SyntaxKind.Block, location); block.statements = createNodeArray(statements); + if (multiLine) { + block.multiLine = true; + } return block; } export function createVariableStatement(modifiers: Modifier[], declarationList: VariableDeclarationList, location?: TextRange): VariableStatement { const node = createNode(SyntaxKind.VariableStatement, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.declarationList = declarationList; return node; } @@ -545,23 +512,26 @@ namespace ts { return node; } - export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { + export function createFunctionDeclaration(modifiers: Modifier[], asteriskToken: Node, name: string | Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, original?: Node) { const node = createNode(SyntaxKind.FunctionDeclaration, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.asteriskToken = asteriskToken; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; node.parameters = createNodeArray(parameters); node.type = undefined; node.body = body; + if (original) { + node.original = original; + } return node; } export function createClassDeclaration(modifiers: Modifier[], name: Identifier, heritageClauses: HeritageClause[], members: ClassElement[], location?: TextRange) { const node = createNode(SyntaxKind.ClassDeclaration, location); node.decorators = undefined; - setModifiers(node, modifiers); + node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = name; node.typeParameters = undefined; node.heritageClauses = createNodeArray(heritageClauses); @@ -674,8 +644,8 @@ namespace ts { export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { return isIdentifier(memberName) - ? createPropertyAccess(target, cloneNode(memberName), location) - : createElementAccess(target, cloneNode(isComputedPropertyName(memberName) ? memberName.expression : memberName), location); + ? createPropertyAccess(target, getSynthesizedClone(memberName), location) + : createElementAccess(target, getSynthesizedClone(isComputedPropertyName(memberName) ? memberName.expression : memberName), location); } export function createRestParameter(name: string | Identifier) { @@ -854,7 +824,7 @@ namespace ts { ); if (preferNewLine) { - property.startsOnNewLine = true; + startOnNewLine(property); } properties.push(property); @@ -1040,6 +1010,68 @@ namespace ts { ); } + export interface CallBinding { + target: LeftHandSideExpression; + thisArg: Expression; + } + + export function createCallBinding(expression: Expression, languageVersion?: ScriptTarget): CallBinding { + const callee = skipParentheses(expression); + let thisArg: Expression; + let target: LeftHandSideExpression; + if (isSuperProperty(callee)) { + thisArg = createThis(/*location*/ callee.expression); + target = callee; + } + else if (callee.kind === SyntaxKind.SuperKeyword) { + thisArg = createThis(/*location*/ callee); + target = languageVersion < ScriptTarget.ES6 ? createIdentifier("_super", /*location*/ callee) : callee; + } + else { + switch (callee.kind) { + case SyntaxKind.PropertyAccessExpression: { + // for `a.b()` target is `(_a = a).b` and thisArg is `_a` + thisArg = createTempVariable(); + target = createPropertyAccess( + createAssignment( + thisArg, + (callee).expression, + /*location*/ (callee).expression + ), + (callee).name, + /*location*/ callee + ); + break; + } + + case SyntaxKind.ElementAccessExpression: { + // for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a` + thisArg = createTempVariable(); + target = createElementAccess( + createAssignment( + thisArg, + (callee).expression, + /*location*/ (callee).expression + ), + (callee).argumentExpression, + /*location*/ callee + ); + + break; + } + + default: { + // for `a()` target is `a` and thisArg is `void 0` + thisArg = createVoidZero(); + target = parenthesizeForAccess(expression); + break; + } + } + } + + return { target, thisArg }; + } + export function inlineExpressions(expressions: Expression[]) { return reduceLeft(expressions, createComma); } @@ -1048,18 +1080,17 @@ namespace ts { return isQualifiedName(node) ? createPropertyAccess( createExpressionFromEntityName(node.left), - cloneNode(node.right) + getSynthesizedClone(node.right) ) - : cloneNode(node); + : getSynthesizedClone(node); } export function createExpressionForPropertyName(memberName: PropertyName, location?: TextRange): Expression { return isIdentifier(memberName) ? createLiteral(memberName.text, location) - : isComputedPropertyName(memberName) ? cloneNode(memberName.expression, location) - : cloneNode(memberName, location); + : isComputedPropertyName(memberName) ? getRelocatedClone(memberName.expression, location) + : getRelocatedClone(memberName, location); } - // Utilities /** @@ -1179,6 +1210,23 @@ namespace ts { || binaryOperator === SyntaxKind.CaretToken; } + /** + * Wraps an expression in parentheses if it is needed in order to use the expression + * as the expression of a NewExpression node. + * + * @param expression The Expression node. + */ + export function parenthesizeForNew(expression: Expression): LeftHandSideExpression { + const lhs = parenthesizeForAccess(expression); + switch (lhs.kind) { + case SyntaxKind.CallExpression: + case SyntaxKind.NewExpression: + return createParen(lhs); + } + + return lhs; + } + /** * Wraps an expression in parentheses if it is needed in order to use the expression for * property or element access. @@ -1248,7 +1296,7 @@ namespace ts { const callee = expression.expression; if (callee.kind === SyntaxKind.FunctionExpression || callee.kind === SyntaxKind.ArrowFunction) { - const clone = cloneNode(expression, expression, expression.flags, expression.parent, expression); + const clone = getMutableClone(expression); clone.expression = createParen(callee, /*location*/ callee); return clone; } @@ -1327,7 +1375,13 @@ namespace ts { return node; } - export function getSynthesizedNode(node: T): T { - return nodeIsSynthesized(node) ? node : cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node); + export function setMultiLine(node: T, multiLine: boolean): T { + node.multiLine = multiLine; + return node; + } + + export function setHasTrailingComma(nodes: NodeArray, hasTrailingComma: boolean): NodeArray { + nodes.hasTrailingComma = hasTrailingComma; + return nodes; } } \ No newline at end of file diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c4813ac993217..14c701fb09e64 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -997,19 +997,6 @@ namespace ts { } array.pos = pos; array.end = pos; - array.arrayKind = ArrayKind.NodeArray; - return array; - } - - function createModifiersArray(elements?: Modifier[], pos?: number): ModifiersArray { - const array = (elements || []); - if (!(pos >= 0)) { - pos = getNodePos(); - } - array.pos = pos; - array.end = pos; - array.arrayKind = ArrayKind.ModifiersArray; - array.flags = 0; return array; } @@ -2019,17 +2006,10 @@ namespace ts { return token === SyntaxKind.DotDotDotToken || isIdentifierOrPattern() || isModifierKind(token) || token === SyntaxKind.AtToken; } - function setModifiers(node: Node, modifiers: ModifiersArray) { - if (modifiers) { - node.flags |= modifiers.flags; - node.modifiers = modifiers; - } - } - function parseParameter(): ParameterDeclaration { const node = createNode(SyntaxKind.Parameter); node.decorators = parseDecorators(); - setModifiers(node, parseModifiers()); + node.modifiers = parseModifiers(); node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); // FormalParameter [Yield,Await]: @@ -2218,23 +2198,23 @@ namespace ts { return token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBracketToken; } - function parseIndexSignatureDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): IndexSignatureDeclaration { + function parseIndexSignatureDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): IndexSignatureDeclaration { const node = createNode(SyntaxKind.IndexSignature, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); node.type = parseTypeAnnotation(); parseTypeMemberSemicolon(); return finishNode(node); } - function parsePropertyOrMethodSignature(fullStart: number, modifiers: ModifiersArray): PropertySignature | MethodSignature { + function parsePropertyOrMethodSignature(fullStart: number, modifiers: NodeArray): PropertySignature | MethodSignature { const name = parsePropertyName(); const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { const method = createNode(SyntaxKind.MethodSignature, fullStart); - setModifiers(method, modifiers); + method.modifiers = modifiers; method.name = name; method.questionToken = questionToken; @@ -2246,7 +2226,7 @@ namespace ts { } else { const property = createNode(SyntaxKind.PropertySignature, fullStart); - setModifiers(property, modifiers); + property.modifiers = modifiers; property.name = name; property.questionToken = questionToken; property.type = parseTypeAnnotation(); @@ -2826,7 +2806,7 @@ namespace ts { return undefined; } - const isAsync = !!(arrowFunction.flags & NodeFlags.Async); + const isAsync = !!(getModifierFlags(arrowFunction) & ModifierFlags.Async); // If we have an arrow, then try to parse the body. Even if not, try to parse if we // have an opening brace, just in case we're in an error state. @@ -2971,8 +2951,8 @@ namespace ts { function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction { const node = createNode(SyntaxKind.ArrowFunction); - setModifiers(node, parseModifiersForArrowFunction()); - const isAsync = !!(node.flags & NodeFlags.Async); + node.modifiers = parseModifiersForArrowFunction(); + const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async); // Arrow functions are never generators. // @@ -3942,7 +3922,7 @@ namespace ts { return finishNode(node); } - function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): AccessorDeclaration { + function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): AccessorDeclaration { if (parseContextualModifier(SyntaxKind.GetKeyword)) { return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers); } @@ -4027,12 +4007,12 @@ namespace ts { } const node = createNode(SyntaxKind.FunctionExpression); - setModifiers(node, parseModifiers()); + node.modifiers = parseModifiers(); parseExpected(SyntaxKind.FunctionKeyword); node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); const isGenerator = !!node.asteriskToken; - const isAsync = !!(node.flags & NodeFlags.Async); + const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async); node.name = isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) : isGenerator ? doInYieldContext(parseOptionalIdentifier) : @@ -4615,7 +4595,7 @@ namespace ts { const node = createMissingNode(SyntaxKind.MissingDeclaration, /*reportAtCurrentPosition*/ true, Diagnostics.Declaration_expected); node.pos = fullStart; node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; return finishNode(node); } } @@ -4750,57 +4730,57 @@ namespace ts { return nextTokenIsIdentifier() && nextToken() === SyntaxKind.CloseParenToken; } - function parseVariableStatement(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): VariableStatement { + function parseVariableStatement(fullStart: number, decorators: NodeArray, modifiers: NodeArray): VariableStatement { const node = createNode(SyntaxKind.VariableStatement, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; node.declarationList = parseVariableDeclarationList(/*inForStatementInitializer*/ false); parseSemicolon(); return addJSDocComment(finishNode(node)); } - function parseFunctionDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): FunctionDeclaration { + function parseFunctionDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): FunctionDeclaration { const node = createNode(SyntaxKind.FunctionDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.FunctionKeyword); node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); - node.name = node.flags & NodeFlags.Default ? parseOptionalIdentifier() : parseIdentifier(); + node.name = hasModifier(node, ModifierFlags.Default) ? parseOptionalIdentifier() : parseIdentifier(); const isGenerator = !!node.asteriskToken; - const isAsync = !!(node.flags & NodeFlags.Async); + const isAsync = hasModifier(node, ModifierFlags.Async); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, Diagnostics.or_expected); return addJSDocComment(finishNode(node)); } - function parseConstructorDeclaration(pos: number, decorators: NodeArray, modifiers: ModifiersArray): ConstructorDeclaration { + function parseConstructorDeclaration(pos: number, decorators: NodeArray, modifiers: NodeArray): ConstructorDeclaration { const node = createNode(SyntaxKind.Constructor, pos); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.ConstructorKeyword); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false, Diagnostics.or_expected); return addJSDocComment(finishNode(node)); } - function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { + function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { const method = createNode(SyntaxKind.MethodDeclaration, fullStart); method.decorators = decorators; - setModifiers(method, modifiers); + method.modifiers = modifiers; method.asteriskToken = asteriskToken; method.name = name; method.questionToken = questionToken; const isGenerator = !!asteriskToken; - const isAsync = !!(method.flags & NodeFlags.Async); + const isAsync = hasModifier(method, ModifierFlags.Async); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, method); method.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, diagnosticMessage); return addJSDocComment(finishNode(method)); } - function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement { + function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray, name: PropertyName, questionToken: Node): ClassElement { const property = createNode(SyntaxKind.PropertyDeclaration, fullStart); property.decorators = decorators; - setModifiers(property, modifiers); + property.modifiers = modifiers; property.name = name; property.questionToken = questionToken; property.type = parseTypeAnnotation(); @@ -4814,7 +4794,7 @@ namespace ts { // AccessibilityModifier_opt static_opt PropertyName TypeAnnotation_opt Initialiser_opt[In, ?Yield]; // // The checker may still error in the static case to explicitly disallow the yield expression. - property.initializer = modifiers && modifiers.flags & NodeFlags.Static + property.initializer = hasModifier(property, ModifierFlags.Static) ? allowInAnd(parseNonParameterInitializer) : doOutsideOfContext(NodeFlags.YieldContext | NodeFlags.DisallowInContext, parseNonParameterInitializer); @@ -4822,7 +4802,7 @@ namespace ts { return finishNode(property); } - function parsePropertyOrMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ClassElement { + function parsePropertyOrMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ClassElement { const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); const name = parsePropertyName(); @@ -4841,10 +4821,10 @@ namespace ts { return parseInitializer(/*inParameter*/ false); } - function parseAccessorDeclaration(kind: SyntaxKind, fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): AccessorDeclaration { + function parseAccessorDeclaration(kind: SyntaxKind, fullStart: number, decorators: NodeArray, modifiers: NodeArray): AccessorDeclaration { const node = createNode(kind, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; node.name = parsePropertyName(); fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false); @@ -4963,9 +4943,8 @@ namespace ts { * * In such situations, 'permitInvalidConstAsModifier' should be set to true. */ - function parseModifiers(permitInvalidConstAsModifier?: boolean): ModifiersArray { - let flags = 0; - let modifiers: ModifiersArray; + function parseModifiers(permitInvalidConstAsModifier?: boolean): NodeArray { + let modifiers: NodeArray; while (true) { const modifierStart = scanner.getStartPos(); const modifierKind = token; @@ -4983,31 +4962,28 @@ namespace ts { } } - flags |= modifierToFlag(modifierKind); const modifier = finishNode(createNode(modifierKind, modifierStart)); if (!modifiers) { - modifiers = createModifiersArray([modifier], modifierStart); + modifiers = createNodeArray([modifier], modifierStart); } else { modifiers.push(modifier); } } if (modifiers) { - modifiers.flags = flags; modifiers.end = scanner.getStartPos(); } return modifiers; } - function parseModifiersForArrowFunction(): ModifiersArray { - let modifiers: ModifiersArray; + function parseModifiersForArrowFunction(): NodeArray { + let modifiers: NodeArray; if (token === SyntaxKind.AsyncKeyword) { const modifierStart = scanner.getStartPos(); const modifierKind = token; nextToken(); const modifier = finishNode(createNode(modifierKind, modifierStart)); - modifiers = createModifiersArray([modifier], modifierStart); - modifiers.flags = modifierToFlag(modifierKind); + modifiers = createNodeArray([modifier], modifierStart); modifiers.end = scanner.getStartPos(); } @@ -5067,14 +5043,14 @@ namespace ts { SyntaxKind.ClassExpression); } - function parseClassDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ClassDeclaration { + function parseClassDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ClassDeclaration { return parseClassDeclarationOrExpression(fullStart, decorators, modifiers, SyntaxKind.ClassDeclaration); } - function parseClassDeclarationOrExpression(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, kind: SyntaxKind): ClassLikeDeclaration { + function parseClassDeclarationOrExpression(fullStart: number, decorators: NodeArray, modifiers: NodeArray, kind: SyntaxKind): ClassLikeDeclaration { const node = createNode(kind, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.ClassKeyword); node.name = parseNameOfClassDeclarationOrExpression(); node.typeParameters = parseTypeParameters(); @@ -5149,10 +5125,10 @@ namespace ts { return parseList(ParsingContext.ClassMembers, parseClassElement); } - function parseInterfaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): InterfaceDeclaration { + function parseInterfaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): InterfaceDeclaration { const node = createNode(SyntaxKind.InterfaceDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.InterfaceKeyword); node.name = parseIdentifier(); node.typeParameters = parseTypeParameters(); @@ -5161,10 +5137,10 @@ namespace ts { return finishNode(node); } - function parseTypeAliasDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): TypeAliasDeclaration { + function parseTypeAliasDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): TypeAliasDeclaration { const node = createNode(SyntaxKind.TypeAliasDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.TypeKeyword); node.name = parseIdentifier(); node.typeParameters = parseTypeParameters(); @@ -5185,10 +5161,10 @@ namespace ts { return finishNode(node); } - function parseEnumDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): EnumDeclaration { + function parseEnumDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): EnumDeclaration { const node = createNode(SyntaxKind.EnumDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; parseExpected(SyntaxKind.EnumKeyword); node.name = parseIdentifier(); if (parseExpected(SyntaxKind.OpenBraceToken)) { @@ -5213,25 +5189,25 @@ namespace ts { return finishNode(node); } - function parseModuleOrNamespaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, flags: NodeFlags): ModuleDeclaration { + function parseModuleOrNamespaceDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray, flags: NodeFlags): ModuleDeclaration { const node = createNode(SyntaxKind.ModuleDeclaration, fullStart); // If we are parsing a dotted namespace name, we want to // propagate the 'Namespace' flag across the names if set. const namespaceFlag = flags & NodeFlags.Namespace; node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; node.flags |= flags; node.name = parseIdentifier(); node.body = parseOptional(SyntaxKind.DotToken) - ? parseModuleOrNamespaceDeclaration(getNodePos(), /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.Export | namespaceFlag) + ? parseModuleOrNamespaceDeclaration(getNodePos(), /*decorators*/ undefined, /*modifiers*/ undefined, NodeFlags.NestedNamespace | namespaceFlag) : parseModuleBlock(); return finishNode(node); } - function parseAmbientExternalModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ModuleDeclaration { + function parseAmbientExternalModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ModuleDeclaration { const node = createNode(SyntaxKind.ModuleDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; if (token === SyntaxKind.GlobalKeyword) { // parse 'global' as name of global scope augmentation node.name = parseIdentifier(); @@ -5244,8 +5220,8 @@ namespace ts { return finishNode(node); } - function parseModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ModuleDeclaration { - let flags = modifiers ? modifiers.flags : 0; + function parseModuleDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ModuleDeclaration { + let flags: NodeFlags = 0; if (token === SyntaxKind.GlobalKeyword) { // global augmentation return parseAmbientExternalModuleDeclaration(fullStart, decorators, modifiers); @@ -5275,7 +5251,7 @@ namespace ts { return nextToken() === SyntaxKind.SlashToken; } - function parseImportDeclarationOrImportEqualsDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ImportEqualsDeclaration | ImportDeclaration { + function parseImportDeclarationOrImportEqualsDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ImportEqualsDeclaration | ImportDeclaration { parseExpected(SyntaxKind.ImportKeyword); const afterImportPos = scanner.getStartPos(); @@ -5288,7 +5264,7 @@ namespace ts { // import x = M.x; const importEqualsDeclaration = createNode(SyntaxKind.ImportEqualsDeclaration, fullStart); importEqualsDeclaration.decorators = decorators; - setModifiers(importEqualsDeclaration, modifiers); + importEqualsDeclaration.modifiers = modifiers; importEqualsDeclaration.name = identifier; parseExpected(SyntaxKind.EqualsToken); importEqualsDeclaration.moduleReference = parseModuleReference(); @@ -5300,7 +5276,7 @@ namespace ts { // Import statement const importDeclaration = createNode(SyntaxKind.ImportDeclaration, fullStart); importDeclaration.decorators = decorators; - setModifiers(importDeclaration, modifiers); + importDeclaration.modifiers = modifiers; // ImportDeclaration: // import ImportClause from ModuleSpecifier ; @@ -5436,10 +5412,10 @@ namespace ts { return finishNode(node); } - function parseExportDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ExportDeclaration { + function parseExportDeclaration(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ExportDeclaration { const node = createNode(SyntaxKind.ExportDeclaration, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; if (parseOptional(SyntaxKind.AsteriskToken)) { parseExpected(SyntaxKind.FromKeyword); node.moduleSpecifier = parseModuleSpecifier(); @@ -5459,10 +5435,10 @@ namespace ts { return finishNode(node); } - function parseExportAssignment(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray): ExportAssignment { + function parseExportAssignment(fullStart: number, decorators: NodeArray, modifiers: NodeArray): ExportAssignment { const node = createNode(SyntaxKind.ExportAssignment, fullStart); node.decorators = decorators; - setModifiers(node, modifiers); + node.modifiers = modifiers; if (parseOptional(SyntaxKind.EqualsToken)) { node.isExportEquals = true; } @@ -5541,7 +5517,7 @@ namespace ts { function setExternalModuleIndicator(sourceFile: SourceFile) { sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node => - node.flags & NodeFlags.Export + hasModifier(node, ModifierFlags.Export) || node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference || node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ExportAssignment diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts new file mode 100644 index 0000000000000..8b1c73abae544 --- /dev/null +++ b/src/compiler/printer.ts @@ -0,0 +1,2623 @@ +/// +/// +/// +/// +/// + +/* @internal */ +namespace ts { + // Flags enum to track count of temp variables and a few dedicated names + const enum TempFlags { + Auto = 0x00000000, // No preferred name + CountMask = 0x0FFFFFFF, // Temp variable counter + _i = 0x10000000, // Use/preference flag for '_i' + } + + // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature + export function printFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult { + const delimiters = createDelimiterMap(); + const brackets = createBracketsMap(); + + // emit output for the __extends helper function + const extendsHelper = ` +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +};`; + + // emit output for the __decorate helper function + const decorateHelper = ` +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +};`; + + // emit output for the __metadata helper function + const metadataHelper = ` +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +};`; + + // emit output for the __param helper function + const paramHelper = ` +var __param = (this && this.__param) || function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +};`; + + // emit output for the __awaiter helper function + const awaiterHelper = ` +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments)).next()); + }); +};`; + + // emit output for the __export helper function + const exportStarHelper = ` +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +}`; + + // emit output for the UMD helper function. + const umdHelper = ` +(function (dependencies, factory) { + if (typeof module === 'object' && typeof module.exports === 'object') { + var v = factory(require, exports); if (v !== undefined) module.exports = v; + } + else if (typeof define === 'function' && define.amd) { + define(dependencies, factory); + } +})`; + + const superHelper = ` +const _super = name => super[name];`; + + const advancedSuperHelper = ` +const _super = (function (geti, seti) { + const cache = Object.create(null); + return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } }); +})(name => super[name], (name, value) => super[name] = value);`; + + const compilerOptions = host.getCompilerOptions(); + const languageVersion = getEmitScriptTarget(compilerOptions); + const moduleKind = getEmitModuleKind(compilerOptions); + const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined; + const emitterDiagnostics = createDiagnosticCollection(); + + let emitSkipped = false; + const newLine = host.getNewLine(); + const printFile = createFilePrinter(); + forEachExpectedEmitFile(host, emitFile, targetSourceFile); + + return { + emitSkipped, + diagnostics: emitterDiagnostics.getDiagnostics(), + sourceMaps: sourceMapDataList + }; + + function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath}: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) { + // Make sure not to write js file and source map file if any of them cannot be written + if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) { + printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); + } + else { + emitSkipped = true; + } + + if (declarationFilePath) { + emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped; + } + } + + function createFilePrinter() { + const transformers = getTransformers(compilerOptions).concat(initializePrinter); + + const writer = createTextWriter(newLine); + const { + write, + writeLine, + increaseIndent, + decreaseIndent + } = writer; + + const sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter(); + const { + emitStart, + emitEnd, + emitPos + } = sourceMap; + + const comments = createCommentWriter(host, writer, sourceMap); + const { + getLeadingComments, + getTrailingComments, + getTrailingCommentsOfPosition, + emitLeadingComments, + emitTrailingComments, + emitDetachedComments + } = comments; + + let context: TransformationContext; + let startLexicalEnvironment: () => void; + let endLexicalEnvironment: () => Statement[]; + let getNodeEmitFlags: (node: Node) => NodeEmitFlags; + let setNodeEmitFlags: (node: Node, flags: NodeEmitFlags) => void; + let isExpressionSubstitutionEnabled: (node: Node) => boolean; + let isEmitNotificationEnabled: (node: Node) => boolean; + let expressionSubstitution: (node: Expression) => Expression; + let identifierSubstitution: (node: Identifier) => Identifier; + let onEmitNode: (node: Node, emit: (node: Node) => void) => void; + let nodeToGeneratedName: string[]; + let generatedNameSet: Map; + let tempFlags: TempFlags; + let currentSourceFile: SourceFile; + let currentText: string; + let currentFileIdentifiers: Map; + let extendsEmitted: boolean; + let decorateEmitted: boolean; + let paramEmitted: boolean; + let awaiterEmitted: boolean; + let isOwnFileEmit: boolean; + + return doPrint; + + function doPrint(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { + sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); + nodeToGeneratedName = []; + generatedNameSet = {}; + isOwnFileEmit = !isBundledEmit; + + // Emit helpers from all the files + if (isBundledEmit && moduleKind) { + forEach(sourceFiles, emitEmitHelpers); + } + + // Transform and print the source files + transformFiles(resolver, host, sourceFiles, transformers); + + writeLine(); + + const sourceMappingURL = sourceMap.getSourceMappingURL(); + if (sourceMappingURL) { + write(`//# sourceMappingURL=${sourceMappingURL}`); + } + + // Write the source map + if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) { + writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), compilerOptions.emitBOM); + } + + // Record source map data for the test harness. + if (sourceMapDataList) { + sourceMapDataList.push(sourceMap.getSourceMapData()); + } + + // Write the output file + writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), compilerOptions.emitBOM); + + // Reset state + sourceMap.reset(); + comments.reset(); + writer.reset(); + + startLexicalEnvironment = undefined; + endLexicalEnvironment = undefined; + getNodeEmitFlags = undefined; + setNodeEmitFlags = undefined; + isExpressionSubstitutionEnabled = undefined; + isEmitNotificationEnabled = undefined; + expressionSubstitution = undefined; + identifierSubstitution = undefined; + onEmitNode = undefined; + tempFlags = TempFlags.Auto; + currentSourceFile = undefined; + currentText = undefined; + extendsEmitted = false; + decorateEmitted = false; + paramEmitted = false; + awaiterEmitted = false; + isOwnFileEmit = false; + } + + function initializePrinter(_context: TransformationContext) { + context = _context; + startLexicalEnvironment = context.startLexicalEnvironment; + endLexicalEnvironment = context.endLexicalEnvironment; + getNodeEmitFlags = context.getNodeEmitFlags; + setNodeEmitFlags = context.setNodeEmitFlags; + isExpressionSubstitutionEnabled = context.isExpressionSubstitutionEnabled; + isEmitNotificationEnabled = context.isEmitNotificationEnabled; + expressionSubstitution = context.expressionSubstitution; + identifierSubstitution = context.identifierSubstitution; + onEmitNode = context.onEmitNode; + return printSourceFile; + } + + function printSourceFile(node: SourceFile) { + currentSourceFile = node; + currentText = node.text; + currentFileIdentifiers = node.identifiers; + sourceMap.setSourceFile(node); + comments.setSourceFile(node); + emitWorker(node); + return node; + } + + /** + * Emits a node. + */ + function emit(node: Node) { + emitNodeWithNotificationOption(node, emitWithoutNotificationOption); + } + + /** + * Emits a node without calling onEmitNode. + * NOTE: Do not call this method directly. + */ + function emitWithoutNotificationOption(node: Node) { + emitNodeWithWorker(node, emitWorker); + } + + /** + * Emits an expression node. + */ + function emitExpression(node: Expression) { + emitNodeWithNotificationOption(node, emitExpressionWithoutNotificationOption); + } + + /** + * Emits an expression without calling onEmitNode. + * NOTE: Do not call this method directly. + */ + function emitExpressionWithoutNotificationOption(node: Expression) { + emitNodeWithWorker(node, emitExpressionWorker); + } + + /** + * Emits a node with emit notification if available. + */ + function emitNodeWithNotificationOption(node: Node, emit: (node: Node) => void) { + if (node) { + if (isEmitNotificationEnabled(node)) { + onEmitNode(node, emit); + } + else { + emit(node); + } + } + } + + function emitNodeWithWorker(node: Node, emitWorker: (node: Node) => void) { + if (node) { + const leadingComments = getLeadingComments(node, getNotEmittedParent); + const trailingComments = getTrailingComments(node, getNotEmittedParent); + emitLeadingComments(node, leadingComments); + emitStart(node); + emitWorker(node); + emitEnd(node); + emitTrailingComments(node, trailingComments); + } + } + + function emitWorker(node: Node): void { + const kind = node.kind; + switch (kind) { + // Pseudo-literals + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + if (tryEmitSubstitute(node, identifierSubstitution)) { + return; + } + + return emitIdentifier(node); + + // Reserved words + case SyntaxKind.ConstKeyword: + case SyntaxKind.DefaultKeyword: + case SyntaxKind.ExportKeyword: + case SyntaxKind.VoidKeyword: + + // Strict mode reserved words + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.PublicKeyword: + case SyntaxKind.StaticKeyword: + + // Contextual keywords + case SyntaxKind.AbstractKeyword: + case SyntaxKind.AnyKeyword: + case SyntaxKind.AsyncKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.DeclareKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.GlobalKeyword: + return writeTokenNode(node); + + // Parse tree nodes + + // Names + case SyntaxKind.QualifiedName: + return emitQualifiedName(node); + case SyntaxKind.ComputedPropertyName: + return emitComputedPropertyName(node); + + // Signature elements + case SyntaxKind.TypeParameter: + return emitTypeParameter(node); + case SyntaxKind.Parameter: + return emitParameter(node); + case SyntaxKind.Decorator: + return emitDecorator(node); + + // Type members + case SyntaxKind.PropertySignature: + return emitPropertySignature(node); + case SyntaxKind.PropertyDeclaration: + return emitPropertyDeclaration(node); + case SyntaxKind.MethodSignature: + return emitMethodSignature(node); + case SyntaxKind.MethodDeclaration: + return emitMethodDeclaration(node); + case SyntaxKind.Constructor: + return emitConstructor(node); + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return emitAccessorDeclaration(node); + case SyntaxKind.CallSignature: + return emitCallSignature(node); + case SyntaxKind.ConstructSignature: + return emitConstructSignature(node); + case SyntaxKind.IndexSignature: + return emitIndexSignature(node); + + // Types + case SyntaxKind.TypePredicate: + return emitTypePredicate(node); + case SyntaxKind.TypeReference: + return emitTypeReference(node); + case SyntaxKind.FunctionType: + return emitFunctionType(node); + case SyntaxKind.ConstructorType: + return emitConstructorType(node); + case SyntaxKind.TypeQuery: + return emitTypeQuery(node); + case SyntaxKind.TypeLiteral: + return emitTypeLiteral(node); + case SyntaxKind.ArrayType: + return emitArrayType(node); + case SyntaxKind.TupleType: + return emitTupleType(node); + case SyntaxKind.UnionType: + return emitUnionType(node); + case SyntaxKind.IntersectionType: + return emitIntersectionType(node); + case SyntaxKind.ParenthesizedType: + return emitParenthesizedType(node); + case SyntaxKind.ExpressionWithTypeArguments: + return emitExpressionWithTypeArguments(node); + case SyntaxKind.ThisType: + return emitThisType(node); + case SyntaxKind.StringLiteralType: + return emitLiteral(node); + + // Binding patterns + case SyntaxKind.ObjectBindingPattern: + return emitObjectBindingPattern(node); + case SyntaxKind.ArrayBindingPattern: + return emitArrayBindingPattern(node); + case SyntaxKind.BindingElement: + return emitBindingElement(node); + + // Misc + case SyntaxKind.TemplateSpan: + return emitTemplateSpan(node); + case SyntaxKind.SemicolonClassElement: + return emitSemicolonClassElement(node); + + // Statements + case SyntaxKind.Block: + return emitBlock(node); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.EmptyStatement: + return emitEmptyStatement(node); + case SyntaxKind.ExpressionStatement: + return emitExpressionStatement(node); + case SyntaxKind.IfStatement: + return emitIfStatement(node); + case SyntaxKind.DoStatement: + return emitDoStatement(node); + case SyntaxKind.WhileStatement: + return emitWhileStatement(node); + case SyntaxKind.ForStatement: + return emitForStatement(node); + case SyntaxKind.ForInStatement: + return emitForInStatement(node); + case SyntaxKind.ForOfStatement: + return emitForOfStatement(node); + case SyntaxKind.ContinueStatement: + return emitContinueStatement(node); + case SyntaxKind.BreakStatement: + return emitBreakStatement(node); + case SyntaxKind.ReturnStatement: + return emitReturnStatement(node); + case SyntaxKind.WithStatement: + return emitWithStatement(node); + case SyntaxKind.SwitchStatement: + return emitSwitchStatement(node); + case SyntaxKind.LabeledStatement: + return emitLabeledStatement(node); + case SyntaxKind.ThrowStatement: + return emitThrowStatement(node); + case SyntaxKind.TryStatement: + return emitTryStatement(node); + case SyntaxKind.DebuggerStatement: + return emitDebuggerStatement(node); + + // Declarations + case SyntaxKind.VariableDeclaration: + return emitVariableDeclaration(node); + case SyntaxKind.VariableDeclarationList: + return emitVariableDeclarationList(node); + case SyntaxKind.FunctionDeclaration: + return emitFunctionDeclaration(node); + case SyntaxKind.ClassDeclaration: + return emitClassDeclaration(node); + case SyntaxKind.InterfaceDeclaration: + return emitInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return emitTypeAliasDeclaration(node); + case SyntaxKind.EnumDeclaration: + return emitEnumDeclaration(node); + case SyntaxKind.ModuleDeclaration: + return emitModuleDeclaration(node); + case SyntaxKind.ModuleBlock: + return emitModuleBlock(node); + case SyntaxKind.CaseBlock: + return emitCaseBlock(node); + case SyntaxKind.ImportEqualsDeclaration: + return emitImportEqualsDeclaration(node); + case SyntaxKind.ImportDeclaration: + return emitImportDeclaration(node); + case SyntaxKind.ImportClause: + return emitImportClause(node); + case SyntaxKind.NamespaceImport: + return emitNamespaceImport(node); + case SyntaxKind.NamedImports: + return emitNamedImports(node); + case SyntaxKind.ImportSpecifier: + return emitImportSpecifier(node); + case SyntaxKind.ExportAssignment: + return emitExportAssignment(node); + case SyntaxKind.ExportDeclaration: + return emitExportDeclaration(node); + case SyntaxKind.NamedExports: + return emitNamedExports(node); + case SyntaxKind.ExportSpecifier: + return emitExportSpecifier(node); + case SyntaxKind.MissingDeclaration: + return; + + // Module references + case SyntaxKind.ExternalModuleReference: + return emitExternalModuleReference(node); + + // JSX (non-expression) + case SyntaxKind.JsxText: + return emitJsxText(node); + case SyntaxKind.JsxClosingElement: + return emitJsxClosingElement(node); + case SyntaxKind.JsxAttribute: + return emitJsxAttribute(node); + case SyntaxKind.JsxSpreadAttribute: + return emitJsxSpreadAttribute(node); + + // Clauses + case SyntaxKind.CaseClause: + return emitCaseClause(node); + case SyntaxKind.DefaultClause: + return emitDefaultClause(node); + case SyntaxKind.HeritageClause: + return emitHeritageClause(node); + case SyntaxKind.CatchClause: + return emitCatchClause(node); + + // Property assignments + case SyntaxKind.PropertyAssignment: + return emitPropertyAssignment(node); + case SyntaxKind.ShorthandPropertyAssignment: + return emitShorthandPropertyAssignment(node); + + // Enum + case SyntaxKind.EnumMember: + return emitEnumMember(node); + + // Top-level nodes + case SyntaxKind.SourceFile: + return emitSourceFile(node); + + // JSDoc nodes (ignored) + } + + if (isExpression(node)) { + return emitExpressionWorker(node); + } + } + + function emitExpressionWorker(node: Node) { + const kind = node.kind; + if (isExpressionSubstitutionEnabled(node) && tryEmitSubstitute(node, expressionSubstitution)) { + return; + } + + switch (kind) { + // Literals + case SyntaxKind.NumericLiteral: + case SyntaxKind.StringLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + return emitIdentifier(node); + + // Reserved words + case SyntaxKind.FalseKeyword: + case SyntaxKind.NullKeyword: + case SyntaxKind.SuperKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.ThisKeyword: + return writeTokenNode(node); + + // Expressions + case SyntaxKind.ArrayLiteralExpression: + return emitArrayLiteralExpression(node); + case SyntaxKind.ObjectLiteralExpression: + return emitObjectLiteralExpression(node); + case SyntaxKind.PropertyAccessExpression: + return emitPropertyAccessExpression(node); + case SyntaxKind.ElementAccessExpression: + return emitElementAccessExpression(node); + case SyntaxKind.CallExpression: + return emitCallExpression(node); + case SyntaxKind.NewExpression: + return emitNewExpression(node); + case SyntaxKind.TaggedTemplateExpression: + return emitTaggedTemplateExpression(node); + case SyntaxKind.TypeAssertionExpression: + return emitTypeAssertionExpression(node); + case SyntaxKind.ParenthesizedExpression: + return emitParenthesizedExpression(node); + case SyntaxKind.FunctionExpression: + return emitFunctionExpression(node); + case SyntaxKind.ArrowFunction: + return emitArrowFunction(node); + case SyntaxKind.DeleteExpression: + return emitDeleteExpression(node); + case SyntaxKind.TypeOfExpression: + return emitTypeOfExpression(node); + case SyntaxKind.VoidExpression: + return emitVoidExpression(node); + case SyntaxKind.AwaitExpression: + return emitAwaitExpression(node); + case SyntaxKind.PrefixUnaryExpression: + return emitPrefixUnaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return emitPostfixUnaryExpression(node); + case SyntaxKind.BinaryExpression: + return emitBinaryExpression(node); + case SyntaxKind.ConditionalExpression: + return emitConditionalExpression(node); + case SyntaxKind.TemplateExpression: + return emitTemplateExpression(node); + case SyntaxKind.YieldExpression: + return emitYieldExpression(node); + case SyntaxKind.SpreadElementExpression: + return emitSpreadElementExpression(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.AsExpression: + return emitAsExpression(node); + + // JSX + case SyntaxKind.JsxElement: + return emitJsxElement(node); + case SyntaxKind.JsxSelfClosingElement: + return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxOpeningElement: + return emitJsxOpeningElement(node); + case SyntaxKind.JsxExpression: + return emitJsxExpression(node); + } + } + + // + // Literals/Pseudo-literals + // + + // SyntaxKind.NumericLiteral + // SyntaxKind.StringLiteral + // SyntaxKind.RegularExpressionLiteral + // SyntaxKind.NoSubstitutionTemplateLiteral + // SyntaxKind.TemplateHead + // SyntaxKind.TemplateMiddle + // SyntaxKind.TemplateTail + function emitLiteral(node: LiteralLikeNode) { + const text = getLiteralText(node, currentSourceFile, languageVersion); + if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) + && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { + writer.writeLiteral(text); + } + else { + write(text); + } + } + + // + // Identifiers + // + + function emitIdentifier(node: Identifier) { + if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) { + writeLines(umdHelper); + } + else { + write(getTextOfNode(node, /*includeTrivia*/ false)); + } + } + + // + // Names + // + + function emitQualifiedName(node: QualifiedName) { + emitEntityName(node.left); + write("."); + emit(node.right); + } + + function emitEntityName(node: EntityName) { + if (node.kind === SyntaxKind.Identifier) { + emitExpression(node); + } + else { + emit(node); + } + } + + function emitComputedPropertyName(node: ComputedPropertyName) { + write("["); + emitExpression(node.expression); + write("]"); + } + + // + // Signature elements + // + + function emitTypeParameter(node: TypeParameterDeclaration) { + emit(node.name); + emitWithPrefix(" extends ", node.constraint); + } + + function emitParameter(node: ParameterDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitExpressionWithPrefix(" = ", node.initializer); + emitWithPrefix(": ", node.type); + } + + function emitDecorator(decorator: Decorator) { + write("@"); + emitExpression(decorator.expression); + } + + // + // Type members + // + + function emitPropertySignature(node: PropertySignature) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitPropertyDeclaration(node: PropertyDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + emitWithPrefix(": ", node.type); + emitExpressionWithPrefix(" = ", node.initializer); + write(";"); + } + + function emitMethodSignature(node: MethodSignature) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emit(node.name); + writeIfPresent(node.questionToken, "?"); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitMethodDeclaration(node: MethodDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + writeIfPresent(node.asteriskToken, "*"); + emit(node.name); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitConstructor(node: ConstructorDeclaration) { + emitModifiers(node, node.modifiers); + write("constructor"); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitAccessorDeclaration(node: AccessorDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); + emit(node.name); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitCallSignature(node: CallSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitConstructSignature(node: ConstructSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("new "); + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitIndexSignature(node: IndexSignatureDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitParametersForIndexSignature(node, node.parameters); + emitWithPrefix(": ", node.type); + write(";"); + } + + function emitSemicolonClassElement(node: SemicolonClassElement) { + write(";"); + } + + // + // Types + // + + function emitTypePredicate(node: TypePredicateNode) { + emit(node.parameterName); + write(" is "); + emit(node.type); + } + + function emitTypeReference(node: TypeReferenceNode) { + emit(node.typeName); + emitTypeArguments(node, node.typeArguments); + } + + function emitFunctionType(node: FunctionTypeNode) { + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + write(" => "); + emit(node.type); + } + + function emitConstructorType(node: ConstructorTypeNode) { + write("new "); + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + write(" => "); + emit(node.type); + } + + function emitTypeQuery(node: TypeQueryNode) { + write("typeof "); + emit(node.exprName); + } + + function emitTypeLiteral(node: TypeLiteralNode) { + write("{"); + emitList(node, node.members, ListFormat.TypeLiteralMembers); + write("}"); + } + + function emitArrayType(node: ArrayTypeNode) { + emit(node.elementType); + write("[]"); + } + + function emitTupleType(node: TupleTypeNode) { + write("["); + emitList(node, node.elementTypes, ListFormat.TupleTypeElements); + write("]"); + } + + function emitUnionType(node: UnionTypeNode) { + emitList(node, node.types, ListFormat.UnionTypeConstituents); + } + + function emitIntersectionType(node: IntersectionTypeNode) { + emitList(node, node.types, ListFormat.IntersectionTypeConstituents); + } + + function emitParenthesizedType(node: ParenthesizedTypeNode) { + write("("); + emit(node.type); + write(")"); + } + + function emitThisType(node: ThisTypeNode) { + write("this"); + } + + // + // Binding patterns + // + + function emitObjectBindingPattern(node: ObjectBindingPattern) { + const elements = node.elements; + if (elements.length === 0) { + write("{}"); + } + else { + write("{"); + emitList(node, elements, ListFormat.ObjectBindingPatternElements); + write("}"); + } + } + + function emitArrayBindingPattern(node: ArrayBindingPattern) { + const elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else { + write("["); + emitList(node, node.elements, ListFormat.ArrayBindingPatternElements); + write("]"); + } + } + + function emitBindingElement(node: BindingElement) { + emitWithSuffix(node.propertyName, ": "); + writeIfPresent(node.dotDotDotToken, "..."); + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + // + // Expressions + // + + function emitArrayLiteralExpression(node: ArrayLiteralExpression) { + const elements = node.elements; + if (elements.length === 0) { + write("[]"); + } + else { + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); + } + } + + function emitObjectLiteralExpression(node: ObjectLiteralExpression) { + const properties = node.properties; + if (properties.length === 0) { + write("{}"); + } + else { + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; + const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; + emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); + } + } + + function emitPropertyAccessExpression(node: PropertyAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + + const indentBeforeDot = needsIndentation(node, node.expression, node.dotToken); + const indentAfterDot = needsIndentation(node, node.dotToken, node.name); + const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression); + + emitExpression(node.expression); + increaseIndentIf(indentBeforeDot); + write(shouldEmitDotDot ? ".." : "."); + increaseIndentIf(indentAfterDot); + emit(node.name); + decreaseIndentIf(indentBeforeDot, indentAfterDot); + } + + // 1..toString is a valid property access, emit a dot after the literal + // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal + function needsDotDotForPropertyAccess(expression: Expression) { + if (expression.kind === SyntaxKind.NumericLiteral) { + // check if numeric literal was originally written with a dot + const text = getLiteralText(expression, currentSourceFile, languageVersion); + return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0; + } + else { + // check if constant enum value is integer + const constantValue = tryGetConstEnumValue(expression); + // isFinite handles cases when constantValue is undefined + return isFinite(constantValue) && Math.floor(constantValue) === constantValue; + } + } + + function emitElementAccessExpression(node: ElementAccessExpression) { + if (tryEmitConstantValue(node)) { + return; + } + + emitExpression(node.expression); + write("["); + emitExpression(node.argumentExpression); + write("]"); + } + + function emitCallExpression(node: CallExpression) { + emitExpression(node.expression); + emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments); + } + + function emitNewExpression(node: NewExpression) { + write("new "); + emitExpression(node.expression); + if (node.arguments) { + emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments); + } + } + + function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { + emitExpression(node.tag); + emitExpression(node.template); + } + + function emitTypeAssertionExpression(node: TypeAssertion) { + if (node.type) { + write("<"); + emit(node.type); + write(">"); + } + + emitExpression(node.expression); + } + + function emitParenthesizedExpression(node: ParenthesizedExpression) { + write("("); + emitExpression(node.expression); + write(")"); + } + + function emitFunctionExpression(node: FunctionExpression) { + emitFunctionDeclarationOrExpression(node); + } + + function emitArrowFunction(node: ArrowFunction) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + emitSignatureAndBody(node, emitArrowFunctionHead); + + } + + function emitArrowFunctionHead(node: ArrowFunction) { + emitTypeParameters(node, node.typeParameters); + emitParametersForArrow(node, node.parameters); + emitWithPrefix(": ", node.type); + write(" =>"); + } + + function emitDeleteExpression(node: DeleteExpression) { + write("delete "); + emitExpression(node.expression); + } + + function emitTypeOfExpression(node: TypeOfExpression) { + write("typeof "); + emitExpression(node.expression); + } + + function emitVoidExpression(node: VoidExpression) { + write("void "); + emitExpression(node.expression); + } + + function emitAwaitExpression(node: AwaitExpression) { + write("await "); + emitExpression(node.expression); + } + + function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { + writeToken(node.operator); + if (shouldEmitWhitespaceBeforeOperand(node)) { + write(" "); + } + emitExpression(node.operand); + } + + function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) { + // In some cases, we need to emit a space between the operator and the operand. One obvious case + // is when the operator is an identifier, like delete or typeof. We also need to do this for plus + // and minus expressions in certain cases. Specifically, consider the following two cases (parens + // are just for clarity of exposition, and not part of the source code): + // + // (+(+1)) + // (+(++1)) + // + // We need to emit a space in both cases. In the first case, the absence of a space will make + // the resulting expression a prefix increment operation. And in the second, it will make the resulting + // expression a prefix increment whose operand is a plus expression - (++(+x)) + // The same is true of minus of course. + const operand = node.operand; + return operand.kind === SyntaxKind.PrefixUnaryExpression + && ((node.operator === SyntaxKind.PlusToken && ((operand).operator === SyntaxKind.PlusToken || (operand).operator === SyntaxKind.PlusPlusToken)) + || (node.operator === SyntaxKind.MinusToken && ((operand).operator === SyntaxKind.MinusToken || (operand).operator === SyntaxKind.MinusMinusToken))); + } + + function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { + emitExpression(node.operand); + writeToken(node.operator); + } + + function emitBinaryExpression(node: BinaryExpression) { + const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken; + const indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken); + const indentAfterOperator = needsIndentation(node, node.operatorToken, node.right); + + emitExpression(node.left); + increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined); + writeTokenNode(node.operatorToken); + increaseIndentIf(indentAfterOperator, " "); + emitExpression(node.right); + decreaseIndentIf(indentBeforeOperator, indentAfterOperator); + } + + function emitConditionalExpression(node: ConditionalExpression) { + const indentBeforeQuestion = needsIndentation(node, node.condition, node.questionToken); + const indentAfterQuestion = needsIndentation(node, node.questionToken, node.whenTrue); + const indentBeforeColon = needsIndentation(node, node.whenTrue, node.colonToken); + const indentAfterColon = needsIndentation(node, node.colonToken, node.whenFalse); + + emitExpression(node.condition); + increaseIndentIf(indentBeforeQuestion, " "); + write("?"); + increaseIndentIf(indentAfterQuestion, " "); + emitExpression(node.whenTrue); + decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion); + + increaseIndentIf(indentBeforeColon, " "); + write(":"); + increaseIndentIf(indentAfterColon, " "); + emitExpression(node.whenFalse); + decreaseIndentIf(indentBeforeColon, indentAfterColon); + } + + function emitTemplateExpression(node: TemplateExpression) { + emit(node.head); + emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans); + } + + function emitYieldExpression(node: YieldExpression) { + write(node.asteriskToken ? "yield*" : "yield"); + emitExpressionWithPrefix(" ", node.expression); + } + + function emitSpreadElementExpression(node: SpreadElementExpression) { + write("..."); + emitExpression(node.expression); + } + + function emitClassExpression(node: ClassExpression) { + emitClassDeclarationOrExpression(node); + } + + function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { + emitStart(node); + emitExpression(node.expression); + emitTypeArguments(node, node.typeArguments); + emitEnd(node); + } + + function emitAsExpression(node: AsExpression) { + emitExpression(node.expression); + if (node.type) { + write(" as "); + emit(node.type); + } + } + + // + // Misc + // + + function emitTemplateSpan(node: TemplateSpan) { + emitExpression(node.expression); + emit(node.literal); + } + + // + // Statements + // + + function emitBlock(node: Block, format?: ListFormat) { + if (isSingleLineEmptyBlock(node)) { + write("{ }"); + } + else { + write("{"); + emitBlockStatements(node); + write("}"); + } + } + + function emitBlockStatements(node: Block) { + if (getNodeEmitFlags(node) & NodeEmitFlags.SingleLine) { + emitList(node, node.statements, ListFormat.SingleLineBlockStatements); + } + else { + emitList(node, node.statements, ListFormat.MultiLineBlockStatements); + } + } + + function emitVariableStatement(node: VariableStatement) { + emitModifiers(node, node.modifiers); + emit(node.declarationList); + write(";"); + } + + function emitEmptyStatement(node: EmptyStatement) { + write(";"); + } + + function emitExpressionStatement(node: ExpressionStatement) { + emitExpression(node.expression); + write(";"); + } + + function emitIfStatement(node: IfStatement) { + write("if ("); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.thenStatement); + if (node.elseStatement) { + writeLine(); + write("else"); + if (node.elseStatement.kind === SyntaxKind.IfStatement) { + write(" "); + emit(node.elseStatement); + } + else { + emitEmbeddedStatement(node.elseStatement); + } + } + } + + function emitDoStatement(node: DoStatement) { + write("do"); + emitEmbeddedStatement(node.statement); + if (isBlock(node.statement)) { + write(" "); + } + else { + writeLine(); + } + + write("while ("); + emitExpression(node.expression); + write(");"); + } + + function emitWhileStatement(node: WhileStatement) { + write("while ("); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForStatement(node: ForStatement) { + write("for ("); + emitForBinding(node.initializer); + write(";"); + emitExpressionWithPrefix(" ", node.condition); + write(";"); + emitExpressionWithPrefix(" ", node.incrementor); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForInStatement(node: ForInStatement) { + write("for ("); + emitForBinding(node.initializer); + write(" in "); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForOfStatement(node: ForOfStatement) { + write("for ("); + emitForBinding(node.initializer); + write(" of "); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitForBinding(node: VariableDeclarationList | Expression) { + if (node !== undefined) { + if (node.kind === SyntaxKind.VariableDeclarationList) { + emit(node); + } + else { + emitExpression(node); + } + } + } + + function emitContinueStatement(node: ContinueStatement) { + write("continue"); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitBreakStatement(node: BreakStatement) { + write("break"); + emitWithPrefix(" ", node.label); + write(";"); + } + + function emitReturnStatement(node: ReturnStatement) { + write("return"); + emitExpressionWithPrefix(" ", node.expression); + write(";"); + } + + function emitWithStatement(node: WithStatement) { + write("with ("); + emitExpression(node.expression); + write(")"); + emitEmbeddedStatement(node.statement); + } + + function emitSwitchStatement(node: SwitchStatement) { + write("switch ("); + emitExpression(node.expression); + write(") "); + emit(node.caseBlock); + } + + function emitLabeledStatement(node: LabeledStatement) { + emit(node.label); + write(": "); + emit(node.statement); + } + + function emitThrowStatement(node: ThrowStatement) { + write("throw"); + emitExpressionWithPrefix(" ", node.expression); + write(";"); + } + + function emitTryStatement(node: TryStatement) { + write("try "); + emit(node.tryBlock); + emit(node.catchClause); + if (node.finallyBlock) { + writeLine(); + write("finally "); + emit(node.finallyBlock); + } + } + + function emitDebuggerStatement(node: DebuggerStatement) { + write("debugger;"); + } + + // + // Declarations + // + + function emitVariableDeclaration(node: VariableDeclaration) { + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + function emitVariableDeclarationList(node: VariableDeclarationList) { + write(isLet(node) ? "let " : isConst(node) ? "const " : "var "); + emitList(node, node.declarations, ListFormat.VariableDeclarationList); + } + + function emitFunctionDeclaration(node: FunctionDeclaration) { + emitFunctionDeclarationOrExpression(node); + } + + function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write(node.asteriskToken ? "function* " : "function "); + emit(node.name); + emitSignatureAndBody(node, emitSignatureHead); + } + + function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { + const body = node.body; + if (body) { + if (isBlock(body)) { + const savedTempFlags = tempFlags; + tempFlags = 0; + startLexicalEnvironment(); + emitSignatureHead(node); + write(" {"); + emitBlockFunctionBody(node, body); + write("}"); + tempFlags = savedTempFlags; + } + else { + emitSignatureHead(node); + write(" "); + emitExpression(body); + } + } + else { + emitSignatureHead(node); + write(";"); + } + + } + + function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { + emitTypeParameters(node, node.typeParameters); + emitParameters(node, node.parameters); + emitWithPrefix(": ", node.type); + } + + function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) { + if (body.multiLine) { + return false; + } + + const originalNode = getOriginalNode(parentNode); + if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) { + const body = originalNode.body; + if (isBlock(body)) { + if (rangeEndIsOnSameLineAsRangeStart(body, body)) { + for (const statement of body.statements) { + if (synthesizedNodeStartsOnNewLine(statement)) { + return false; + } + } + + return true; + } + } + else { + return rangeEndIsOnSameLineAsRangeStart((originalNode).equalsGreaterThanToken, originalNode.body); + } + } + + return false; + } + + function emitBlockFunctionBody(parentNode: Node, body: Block) { + const startingLine = writer.getLine(); + increaseIndent(); + emitDetachedComments(body.statements); + + // Emit all the prologue directives (like "use strict"). + const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true); + const helpersEmitted = emitHelpers(body); + + if (statementOffset === 0 && !helpersEmitted && shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)) { + decreaseIndent(); + emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements); + increaseIndent(); + } + else { + emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset); + } + + const endingLine = writer.getLine(); + emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine); + emitLeadingComments(collapseTextRange(body.statements, TextRangeCollapse.CollapseToEnd)); + decreaseIndent(); + } + + function emitClassDeclaration(node: ClassDeclaration) { + emitClassDeclarationOrExpression(node); + } + + function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("class"); + emitWithPrefix(" ", node.name); + emitTypeParameters(node, node.typeParameters); + emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses); + + const savedTempFlags = tempFlags; + tempFlags = 0; + + write(" {"); + emitList(node, node.members, ListFormat.ClassMembers); + write("}"); + + tempFlags = savedTempFlags; + } + + function emitInterfaceDeclaration(node: InterfaceDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("interface "); + emit(node.name); + emitTypeParameters(node, node.typeParameters); + emitList(node, node.heritageClauses, ListFormat.SingleLine); + write(" {"); + emitList(node, node.members, ListFormat.InterfaceMembers); + write("}"); + } + + function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { + emitDecorators(node, node.decorators); + emitModifiers(node, node.modifiers); + write("type "); + emit(node.name); + emitTypeParameters(node, node.typeParameters); + write(" = "); + emit(node.type); + write(";"); + } + + function emitEnumDeclaration(node: EnumDeclaration) { + emitModifiers(node, node.modifiers); + write("enum "); + emit(node.name); + + const savedTempFlags = tempFlags; + tempFlags = 0; + + write(" {"); + emitList(node, node.members, ListFormat.EnumMembers); + write("}"); + tempFlags = savedTempFlags; + } + + function emitModuleDeclaration(node: ModuleDeclaration) { + emitModifiers(node, node.modifiers); + write(node.flags & NodeFlags.Namespace ? "namespace " : "module "); + emit(node.name); + + let body = node.body; + while (body.kind === SyntaxKind.ModuleDeclaration) { + write("."); + emit((body).name); + body = (body).body; + } + + write(" "); + emit(body); + } + + function emitModuleBlock(node: ModuleBlock) { + if (isSingleLineEmptyBlock(node)) { + write("{ }"); + } + else { + const savedTempFlags = tempFlags; + tempFlags = 0; + startLexicalEnvironment(); + write("{"); + increaseIndent(); + + const startingLine = writer.getLine(); + emitBlockStatements(node); + + const endingLine = writer.getLine(); + emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine); + write("}"); + tempFlags = savedTempFlags; + } + } + + function emitCaseBlock(node: CaseBlock) { + write("{"); + emitList(node, node.clauses, ListFormat.CaseBlockClauses); + write("}"); + } + + function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { + emitModifiers(node, node.modifiers); + write("import "); + emit(node.name); + write(" = "); + emitModuleReference(node.moduleReference); + write(";"); + } + + function emitModuleReference(node: ModuleReference) { + if (node.kind === SyntaxKind.Identifier) { + emitExpression(node); + } + else { + emit(node); + } + } + + function emitImportDeclaration(node: ImportDeclaration) { + emitModifiers(node, node.modifiers); + write("import "); + emit(node.importClause); + emitExpression(node.moduleSpecifier); + write(";"); + } + + function emitImportClause(node: ImportClause) { + emitStart(node); + emit(node.name); + if (node.name && node.namedBindings) { + write(", "); + } + emit(node.namedBindings); + emitEnd(node); + write(" from "); + } + + function emitNamespaceImport(node: NamespaceImport) { + emitStart(node); + write("* as "); + emit(node.name); + emitEnd(node); + } + + function emitNamedImports(node: NamedImports) { + emitNamedImportsOrExports(node); + } + + function emitImportSpecifier(node: ImportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitExportAssignment(node: ExportAssignment) { + write(node.isExportEquals ? "export = " : "export default "); + emitExpression(node.expression); + write(";"); + } + + function emitExportDeclaration(node: ExportDeclaration) { + write("export "); + if (node.exportClause) { + emit(node.exportClause); + write(" from "); + } + else { + write("* from "); + } + emitExpression(node.moduleSpecifier); + write(";"); + } + + function emitNamedExports(node: NamedExports) { + emitNamedImportsOrExports(node); + } + + function emitExportSpecifier(node: ExportSpecifier) { + emitImportOrExportSpecifier(node); + } + + function emitNamedImportsOrExports(node: NamedImportsOrExports) { + write("{"); + emitList(node, node.elements, ListFormat.NamedImportsOrExportsElements); + write("}"); + } + + function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) { + if (node.propertyName) { + emit(node.propertyName); + write(" as "); + } + + emit(node.name); + } + + // + // Module references + // + + function emitExternalModuleReference(node: ExternalModuleReference) { + write("require("); + emitExpression(node.expression); + write(")"); + } + + // + // JSX + // + + function emitJsxElement(node: JsxElement) { + emit(node.openingElement); + emitList(node, node.children, ListFormat.JsxElementChildren); + emit(node.closingElement); + } + + function emitJsxSelfClosingElement(node: JsxSelfClosingElement) { + write("<"); + emit(node.tagName); + write(" "); + emitList(node, node.attributes, ListFormat.JsxElementAttributes); + write("/>"); + } + + function emitJsxOpeningElement(node: JsxOpeningElement) { + write("<"); + emit(node.tagName); + writeIfAny(node.attributes, " "); + emitList(node, node.attributes, ListFormat.JsxElementAttributes); + write(">"); + } + + function emitJsxText(node: JsxText) { + writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); + } + + function emitJsxClosingElement(node: JsxClosingElement) { + write(""); + } + + function emitJsxAttribute(node: JsxAttribute) { + emit(node.name); + emitWithPrefix("=", node.initializer); + } + + function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { + write("{..."); + emitExpression(node.expression); + write("}"); + } + + function emitJsxExpression(node: JsxExpression) { + write("{"); + emitExpression(node.expression); + write("}"); + } + + // + // Clauses + // + + function emitCaseClause(node: CaseClause) { + write("case "); + emitExpression(node.expression); + write(":"); + + emitCaseOrDefaultClauseStatements(node, node.statements); + } + + function emitDefaultClause(node: DefaultClause) { + write("default:"); + emitCaseOrDefaultClauseStatements(node, node.statements); + } + + function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray) { + if (statements.length === 1 && rangeStartPositionsAreOnSameLine(parentNode, statements[0])) { + write(" "); + emit(statements[0]); + } + else { + emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements); + } + } + + function emitHeritageClause(node: HeritageClause) { + emitStart(node); + write(" "); + writeToken(node.token); + write(" "); + emitList(node, node.types, ListFormat.HeritageClauseTypes); + emitEnd(node); + } + + function emitCatchClause(node: CatchClause) { + writeLine(); + write("catch ("); + emit(node.variableDeclaration); + write(") "); + emit(node.block); + } + + // + // Property assignments + // + + function emitPropertyAssignment(node: PropertyAssignment) { + emit(node.name); + write(": "); + // This is to ensure that we emit comment in the following case: + // For example: + // obj = { + // id: /*comment1*/ ()=>void + // } + // "comment1" is not considered to be leading comment for node.initializer + // but rather a trailing comment on the previous node. + emitLeadingComments(node.initializer, getTrailingComments(collapseTextRange(node.initializer, TextRangeCollapse.CollapseToStart))); + emitExpression(node.initializer); + } + + function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { + emit(node.name); + } + + // + // Enum + // + + function emitEnumMember(node: EnumMember) { + emit(node.name); + emitExpressionWithPrefix(" = ", node.initializer); + } + + // + // Top-level nodes + // + + function emitSourceFile(node: SourceFile) { + writeLine(); + emitShebang(); + emitDetachedComments(node); + + const statements = node.statements; + const statementOffset = emitPrologueDirectives(statements); + if (getNodeEmitFlags(node) & NodeEmitFlags.NoLexicalEnvironment) { + emitHelpers(node); + emitList(node, statements, ListFormat.MultiLine, statementOffset); + } + else { + const savedTempFlags = tempFlags; + tempFlags = 0; + startLexicalEnvironment(); + emitHelpers(node); + emitList(node, statements, ListFormat.MultiLine, statementOffset); + emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ true); + tempFlags = savedTempFlags; + } + + emitLeadingComments(node.endOfFileToken); + } + + function emitLexicalEnvironment(declarations: Statement[], newLine: boolean) { + if (declarations && declarations.length > 0) { + for (const node of declarations) { + if (newLine) { + writeLine(); + } + else { + write(" "); + } + + emit(node); + } + + if (newLine) { + writeLine(); + } + else { + write(" "); + } + } + } + + /** + * Emits any prologue directives at the start of a Statement list, returning the + * number of prologue directives written to the output. + */ + function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean): number { + for (let i = 0; i < statements.length; i++) { + if (isPrologueDirective(statements[i])) { + if (startWithNewLine || i > 0) { + writeLine(); + } + emit(statements[i]); + } + else { + // return index of the first non prologue directive + return i; + } + } + + return statements.length; + } + + function emitHelpers(node: Node) { + const emitFlags = getNodeEmitFlags(node); + let helpersEmitted = false; + if (emitFlags & NodeEmitFlags.EmitEmitHelpers) { + helpersEmitted = emitEmitHelpers(currentSourceFile); + } + + if (emitFlags & NodeEmitFlags.EmitExportStar) { + writeLines(exportStarHelper); + helpersEmitted = true; + } + + if (emitFlags & NodeEmitFlags.EmitSuperHelper) { + writeLines(superHelper); + helpersEmitted = true; + } + + if (emitFlags & NodeEmitFlags.EmitAdvancedSuperHelper) { + writeLines(advancedSuperHelper); + helpersEmitted = true; + } + + return helpersEmitted; + } + + function emitEmitHelpers(node: SourceFile) { + let helpersEmitted = false; + + // Only emit helpers if the user did not say otherwise. + if (!compilerOptions.noEmitHelpers) { + // Only Emit __extends function when target ES5. + // For target ES6 and above, we can emit classDeclaration as is. + if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && node.flags & NodeFlags.HasClassExtends)) { + writeLines(extendsHelper); + extendsEmitted = true; + helpersEmitted = true; + } + + if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) { + writeLines(decorateHelper); + if (compilerOptions.emitDecoratorMetadata) { + writeLines(metadataHelper); + } + + decorateEmitted = true; + helpersEmitted = true; + } + + if (!paramEmitted && node.flags & NodeFlags.HasParamDecorators) { + writeLines(paramHelper); + paramEmitted = true; + helpersEmitted = true; + } + + if (!awaiterEmitted && node.flags & NodeFlags.HasAsyncFunctions) { + writeLines(awaiterHelper); + awaiterEmitted = true; + helpersEmitted = true; + } + + if (helpersEmitted) { + writeLine(); + } + } + + return helpersEmitted; + } + + function writeLines(text: string): void { + const lines = text.split(/\r\n|\r|\n/g); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (line.length) { + if (i > 0) { + writeLine(); + } + write(line); + } + } + } + + // + // Helpers + // + + function emitShebang() { + const shebang = getShebang(currentText); + if (shebang) { + write(shebang); + } + } + + function emitModifiers(node: Node, modifiers: NodeArray) { + if (modifiers && modifiers.length) { + emitList(node, modifiers, ListFormat.SingleLine); + write(" "); + } + } + + function emitWithPrefix(prefix: string, node: Node) { + emitNodeWithPrefix(prefix, node, emit); + } + + function emitExpressionWithPrefix(prefix: string, node: Node) { + emitNodeWithPrefix(prefix, node, emitExpression); + } + + function emitNodeWithPrefix(prefix: string, node: Node, emit: (node: Node) => void) { + if (node) { + write(prefix); + emit(node); + } + } + + function emitWithSuffix(node: Node, suffix: string) { + if (node) { + emit(node); + write(suffix); + } + } + + function tryEmitSubstitute(node: Node, substitution: (node: Node) => Node) { + if (substitution && (getNodeEmitFlags(node) & NodeEmitFlags.NoSubstitution) === 0) { + const substitute = substitution(node); + if (substitute !== node) { + setNodeEmitFlags(substitute, NodeEmitFlags.NoSubstitution | getNodeEmitFlags(substitute)); + emitWorker(substitute); + return true; + } + } + + return false; + } + + function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { + const constantValue = tryGetConstEnumValue(node); + if (constantValue !== undefined) { + write(String(constantValue)); + if (!compilerOptions.removeComments) { + const propertyName = isPropertyAccessExpression(node) + ? declarationNameToString(node.name) + : getTextOfNode(node.argumentExpression); + write(` /* ${propertyName} */`); + } + + return true; + } + + return false; + } + + function emitEmbeddedStatement(node: Statement) { + if (isBlock(node)) { + write(" "); + emit(node); + } + else { + writeLine(); + increaseIndent(); + emit(node); + decreaseIndent(); + } + } + + function emitDecorators(parentNode: Node, decorators: NodeArray) { + emitList(parentNode, decorators, ListFormat.Decorators); + } + + function emitTypeArguments(parentNode: Node, typeArguments: NodeArray) { + emitList(parentNode, typeArguments, ListFormat.TypeArguments); + } + + function emitTypeParameters(parentNode: Node, typeParameters: NodeArray) { + emitList(parentNode, typeParameters, ListFormat.TypeParameters); + } + + function emitParameters(parentNode: Node, parameters: NodeArray) { + emitList(parentNode, parameters, ListFormat.Parameters); + } + + function emitParametersForArrow(parentNode: Node, parameters: NodeArray) { + if (parameters && + parameters.length === 1 && + parameters[0].type === undefined && + parameters[0].pos === parentNode.pos) { + emit(parameters[0]); + } + else { + emitParameters(parentNode, parameters); + } + } + + function emitParametersForIndexSignature(parentNode: Node, parameters: NodeArray) { + emitList(parentNode, parameters, ListFormat.IndexSignatureParameters); + } + + function emitList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { + emitNodeList(emit, parentNode, children, format, start, count); + } + + function emitExpressionList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { + emitNodeList(emitExpression, parentNode, children, format, start, count); + } + + function emitNodeList(emit: (node: Node) => void, parentNode: Node, children: NodeArray, format: ListFormat, start = 0, count = children ? children.length - start : 0) { + const isUndefined = children === undefined; + if (isUndefined && format & ListFormat.OptionalIfUndefined) { + return; + } + + const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0; + if (isEmpty && format & ListFormat.OptionalIfEmpty) { + return; + } + + if (format & ListFormat.BracketsMask) { + write(getOpeningBracket(format)); + } + + if (isEmpty) { + // Write a line terminator if the parent node was multi-line + if (format & ListFormat.MultiLine) { + writeLine(); + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + } + else { + // Write the opening line terminator or leading whitespace. + let shouldEmitInterveningComments = true; + if (shouldWriteLeadingLineTerminator(parentNode, children, format)) { + writeLine(); + shouldEmitInterveningComments = false; + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + + // Increase the indent, if requested. + if (format & ListFormat.Indented) { + increaseIndent(); + } + + // Emit each child. + let previousSibling: Node; + const delimiter = getDelimiter(format); + for (let i = 0; i < count; i++) { + const child = children[start + i]; + + // Write the delimiter if this is not the first node. + if (previousSibling) { + write(delimiter); + + // Write either a line terminator or whitespace to separate the elements. + if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) { + writeLine(); + shouldEmitInterveningComments = false; + } + else if (previousSibling) { + write(" "); + } + } + + if (shouldEmitInterveningComments) { + emitLeadingComments(child, getTrailingCommentsOfPosition(child.pos)); + } + else { + shouldEmitInterveningComments = true; + } + + // Emit this child. + emit(child); + + previousSibling = child; + } + + // Write a trailing comma, if requested. + const hasTrailingComma = (format & ListFormat.AllowTrailingComma) && children.hasTrailingComma; + if (format & ListFormat.CommaDelimited && hasTrailingComma) { + write(","); + } + + // Decrease the indent, if requested. + if (format & ListFormat.Indented) { + decreaseIndent(); + } + + // Write the closing line terminator or closing whitespace. + if (shouldWriteClosingLineTerminator(parentNode, children, format)) { + writeLine(); + } + else if (format & ListFormat.SpaceBetweenBraces) { + write(" "); + } + } + + if (format & ListFormat.BracketsMask) { + write(getClosingBracket(format)); + } + } + + function writeIfAny(nodes: NodeArray, text: string) { + if (nodes && nodes.length > 0) { + write(text); + } + } + + function writeIfPresent(node: Node, text: string) { + if (node !== undefined) { + write(text); + } + } + + function writeToken(token: SyntaxKind, pos?: number) { + const tokenStartPos = skipTrivia(currentText, pos); + emitPos(tokenStartPos); + const tokenEndPos = writeTokenText(token, pos); + emitPos(tokenEndPos); + return tokenEndPos; + } + + function writeTokenText(token: SyntaxKind, pos?: number) { + const tokenString = tokenToString(token); + write(tokenString); + return positionIsSynthesized(pos) ? -1 : pos + tokenString.length; + } + + function writeTokenNode(node: Node) { + if (node) { + emitStart(node); + writeTokenText(node.kind); + emitEnd(node); + } + } + + function increaseIndentIf(value: boolean, valueToWriteWhenNotIndenting?: string) { + if (value) { + increaseIndent(); + writeLine(); + } + else if (valueToWriteWhenNotIndenting) { + write(valueToWriteWhenNotIndenting); + } + } + + // Helper function to decrease the indent if we previously indented. Allows multiple + // previous indent values to be considered at a time. This also allows caller to just + // call this once, passing in all their appropriate indent values, instead of needing + // to call this helper function multiple times. + function decreaseIndentIf(value1: boolean, value2?: boolean) { + if (value1) { + decreaseIndent(); + } + if (value2) { + decreaseIndent(); + } + } + + function shouldWriteLeadingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return true; + } + else if (format & ListFormat.PreserveLines) { + if (format & ListFormat.PreferNewLine) { + return true; + } + + const firstChild = children[0]; + if (firstChild === undefined) { + return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end); + } + else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { + return synthesizedNodeStartsOnNewLine(firstChild, format); + } + else { + return !rangeStartPositionsAreOnSameLine(parentNode, firstChild); + } + } + else { + return false; + } + } + + function shouldWriteSeparatingLineTerminator(previousNode: Node, nextNode: Node, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return true; + } + else if (format & ListFormat.PreserveLines) { + if (previousNode === undefined || nextNode === undefined) { + return false; + } + else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) { + return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); + } + else { + return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode); + } + } + else { + return false; + } + } + + function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { + if (format & ListFormat.MultiLine) { + return (format & ListFormat.NoTrailingNewLine) === 0; + } + else if (format & ListFormat.PreserveLines) { + if (format & ListFormat.PreferNewLine) { + return true; + } + + const lastChild = lastOrUndefined(children); + if (lastChild === undefined) { + return !positionsAreOnSameLine(getStartPos(parentNode), parentNode.end); + } + else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { + return synthesizedNodeStartsOnNewLine(lastChild, format); + } + else { + return !rangeEndPositionsAreOnSameLine(parentNode, lastChild); + } + } + else { + return false; + } + } + + function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) { + if (nodeIsSynthesized(node)) { + const startsOnNewLine = node.startsOnNewLine; + if (startsOnNewLine === undefined) { + return (format & ListFormat.PreferNewLine) !== 0; + } + + return startsOnNewLine; + } + return (format & ListFormat.PreferNewLine) !== 0; + } + + function rangeStartPositionsAreOnSameLine(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(getStartPos(range1), getStartPos(range2)); + } + + function rangeEndPositionsAreOnSameLine(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(range1.end, range2.end); + } + + function rangeEndIsOnSameLineAsRangeStart(range1: TextRange, range2: TextRange) { + return positionsAreOnSameLine(range1.end, getStartPos(range2)); + } + + function positionsAreOnSameLine(pos1: number, pos2: number) { + return pos1 === pos2 || + getLineOfLocalPosition(currentSourceFile, pos1) === getLineOfLocalPosition(currentSourceFile, pos2); + } + + function getStartPos(range: TextRange) { + return range.pos === -1 ? -1 : skipTrivia(currentText, range.pos); + } + + function needsIndentation(parent: Node, node1: Node, node2: Node): boolean { + parent = skipSynthesizedParentheses(parent); + node1 = skipSynthesizedParentheses(node1); + node2 = skipSynthesizedParentheses(node2); + + // Always use a newline for synthesized code if the synthesizer desires it. + if (node2.startsOnNewLine) { + return true; + } + + return !nodeIsSynthesized(parent) + && !nodeIsSynthesized(node1) + && !nodeIsSynthesized(node2) + && !rangeEndIsOnSameLineAsRangeStart(node1, node2); + } + + function skipSynthesizedParentheses(node: Node) { + while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) { + node = (node).expression; + } + + return node; + } + + function getTextOfNode(node: Node, includeTrivia?: boolean) { + if (isIdentifier(node)) { + if (node.autoGenerateKind) { + return getGeneratedIdentifier(node); + } + else if (nodeIsSynthesized(node) || !node.parent) { + return node.text; + } + } + else if (isLiteralExpression(node) && (nodeIsSynthesized(node) || !node.parent)) { + return node.text; + } + + return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia); + } + + function tryGetConstEnumValue(node: Node): number { + if (compilerOptions.isolatedModules) { + return undefined; + } + + return isPropertyAccessExpression(node) || isElementAccessExpression(node) + ? resolver.getConstantValue(node) + : undefined; + } + + function isSingleLineEmptyBlock(block: Block) { + return !block.multiLine + && block.statements.length === 0 + && rangeEndIsOnSameLineAsRangeStart(block, block); + } + + function getNotEmittedParent(node: Node): Node { + if (getNodeEmitFlags(node) & NodeEmitFlags.EmitCommentsOfNotEmittedParent) { + const parent = getOriginalNode(node).parent; + if (getNodeEmitFlags(parent) & NodeEmitFlags.IsNotEmittedNode) { + return parent; + } + } + + return undefined; + } + + function isUniqueName(name: string): boolean { + return !resolver.hasGlobalName(name) && + !hasProperty(currentFileIdentifiers, name) && + !hasProperty(generatedNameSet, name); + } + + function isUniqueLocalName(name: string, container: Node): boolean { + for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) { + if (node.locals && hasProperty(node.locals, name)) { + // We conservatively include alias symbols to cover cases where they're emitted as locals + if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) { + return false; + } + } + } + return true; + } + + /** + * Return the next available name in the pattern _a ... _z, _0, _1, ... + * TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name. + * Note that names generated by makeTempVariableName and makeUniqueName will never conflict. + */ + function makeTempVariableName(flags: TempFlags): string { + if (flags && !(tempFlags & flags)) { + const name = flags === TempFlags._i ? "_i" : "_n"; + if (isUniqueName(name)) { + tempFlags |= flags; + return name; + } + } + while (true) { + const count = tempFlags & TempFlags.CountMask; + tempFlags++; + // Skip over 'i' and 'n' + if (count !== 8 && count !== 13) { + const name = count < 26 + ? "_" + String.fromCharCode(CharacterCodes.a + count) + : "_" + (count - 26); + if (isUniqueName(name)) { + return name; + } + } + } + } + + // Generate a name that is unique within the current file and doesn't conflict with any names + // in global scope. The name is formed by adding an '_n' suffix to the specified base name, + // where n is a positive integer. Note that names generated by makeTempVariableName and + // makeUniqueName are guaranteed to never conflict. + function makeUniqueName(baseName: string): string { + // Find the first unique 'name_n', where n is a positive number + if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) { + baseName += "_"; + } + let i = 1; + while (true) { + const generatedName = baseName + i; + if (isUniqueName(generatedName)) { + return generatedNameSet[generatedName] = generatedName; + } + i++; + } + } + + function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { + const name = node.name.text; + // Use module/enum name itself if it is unique, otherwise make a unique variation + return isUniqueLocalName(name, node) ? name : makeUniqueName(name); + } + + function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { + const expr = getExternalModuleName(node); + const baseName = expr.kind === SyntaxKind.StringLiteral ? + escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; + return makeUniqueName(baseName); + } + + function generateNameForExportDefault() { + return makeUniqueName("default"); + } + + function generateNameForClassExpression() { + return makeUniqueName("class"); + } + + function generateNameForNode(node: Node) { + switch (node.kind) { + case SyntaxKind.Identifier: + return makeUniqueName((node).text); + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return generateNameForModuleOrEnum(node); + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: + return generateNameForImportOrExportDeclaration(node); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ExportAssignment: + return generateNameForExportDefault(); + case SyntaxKind.ClassExpression: + return generateNameForClassExpression(); + default: + return makeTempVariableName(TempFlags.Auto); + } + } + + function generateIdentifier(node: Identifier) { + switch (node.autoGenerateKind) { + case GeneratedIdentifierKind.Auto: + return makeTempVariableName(TempFlags.Auto); + case GeneratedIdentifierKind.Loop: + return makeTempVariableName(TempFlags._i); + case GeneratedIdentifierKind.Unique: + return makeUniqueName(node.text); + case GeneratedIdentifierKind.Node: + return generateNameForNode(getOriginalNode(node)); + } + } + + function getGeneratedIdentifier(node: Identifier) { + const id = getOriginalNodeId(node); + return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = unescapeIdentifier(generateIdentifier(node))); + } + } + + function createDelimiterMap() { + const delimiters: string[] = []; + delimiters[ListFormat.None] = ""; + delimiters[ListFormat.CommaDelimited] = ","; + delimiters[ListFormat.BarDelimited] = " |"; + delimiters[ListFormat.AmpersandDelimited] = " &"; + return delimiters; + } + + function getDelimiter(format: ListFormat) { + return delimiters[format & ListFormat.DelimitersMask]; + } + + function createBracketsMap() { + const brackets: string[][] = []; + brackets[ListFormat.Braces] = ["{", "}"]; + brackets[ListFormat.Parenthesis] = ["(", ")"]; + brackets[ListFormat.AngleBrackets] = ["<", ">"]; + brackets[ListFormat.SquareBrackets] = ["[", "]"]; + return brackets; + } + + function getOpeningBracket(format: ListFormat) { + return brackets[format & ListFormat.BracketsMask][0]; + } + + function getClosingBracket(format: ListFormat) { + return brackets[format & ListFormat.BracketsMask][1]; + } + } + + const enum ListFormat { + None = 0, + + // Line separators + SingleLine = 1 << 0, // Prints the list on a single line (default). + MultiLine = 1 << 1, // Prints the list on multiple lines. + PreserveLines = 1 << 2, // Prints the list using line preservation if possible. + + // Delimiters + NotDelimited = 0, // There is no delimiter between list items (default). + BarDelimited = 1 << 3, // Each list item is space-and-bar (" |") delimited. + AmpersandDelimited = 1 << 4, // Each list item is space-and-ampersand (" &") delimited. + CommaDelimited = 1 << 5, // Each list item is comma (",") delimited. + AllowTrailingComma = 1 << 6, // Write a trailing comma (",") if present. + DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited, + + // Whitespace + Indented = 1 << 7, // The list should be indented. + SpaceBetweenBraces = 1 << 8, // Inserts a space after the opening brace and before the closing brace. + + // Brackets/Braces + Braces = 1 << 9, // The list is surrounded by "{" and "}". + Parenthesis = 1 << 10, // The list is surrounded by "(" and ")". + AngleBrackets = 1 << 11, // The list is surrounded by "<" and ">". + SquareBrackets = 1 << 12, // The list is surrounded by "[" and "]". + BracketsMask = Braces | Parenthesis | AngleBrackets | SquareBrackets, + OptionalIfUndefined = 1 << 13, // Do not emit brackets if the list is undefined. + OptionalIfEmpty = 1 << 14, // Do not emit brackets if the list is empty. + Optional = OptionalIfUndefined | OptionalIfEmpty, + + // Other + PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes. + NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list. + + // Precomputed Formats + TypeLiteralMembers = MultiLine | Indented, + TupleTypeElements = CommaDelimited | SingleLine | Indented, + UnionTypeConstituents = BarDelimited | SingleLine, + IntersectionTypeConstituents = AmpersandDelimited | SingleLine, + ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces, + ArrayBindingPatternElements = SingleLine | AllowTrailingComma, + ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenBraces | Indented | Braces, + ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | AllowTrailingComma | Indented | SquareBrackets, + CallExpressionArguments = CommaDelimited | SingleLine | Parenthesis, + NewExpressionArguments = CommaDelimited | SingleLine | Parenthesis | OptionalIfUndefined, + TemplateExpressionSpans = SingleLine, + SingleLineBlockStatements = SpaceBetweenBraces | SingleLine, + MultiLineBlockStatements = Indented | MultiLine, + VariableDeclarationList = CommaDelimited | SingleLine, + SingleLineFunctionBodyStatements = SingleLine | SpaceBetweenBraces, + MultiLineFunctionBodyStatements = MultiLine, + ClassHeritageClauses = SingleLine, + ClassMembers = Indented | MultiLine, + InterfaceMembers = Indented | MultiLine, + EnumMembers = CommaDelimited | Indented | MultiLine, + CaseBlockClauses = Indented | MultiLine, + NamedImportsOrExportsElements = CommaDelimited | AllowTrailingComma | SingleLine | SpaceBetweenBraces, + JsxElementChildren = SingleLine, + JsxElementAttributes = SingleLine, + CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, + HeritageClauseTypes = CommaDelimited | SingleLine, + SourceFileStatements = MultiLine | NoTrailingNewLine, + Decorators = MultiLine | Optional, + TypeArguments = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional, + TypeParameters = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional, + Parameters = CommaDelimited | SingleLine | Indented | Parenthesis, + IndexSignatureParameters = CommaDelimited | SingleLine | Indented | SquareBrackets, + } +} \ No newline at end of file diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 4a3d0cbc164bf..d5472907edb23 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1,6 +1,7 @@ /// /// /// +/// namespace ts { /* @internal */ export let programTime = 0; @@ -968,7 +969,8 @@ namespace ts { const start = new Date().getTime(); - const emitResult = emitFiles( + const fileEmitter = options.experimentalTransforms ? printFiles : emitFiles; + const emitResult = fileEmitter( emitResolver, getEmitHost(writeFileCallback), sourceFile); @@ -1194,7 +1196,7 @@ namespace ts { return false; } - function checkModifiers(modifiers: ModifiersArray): boolean { + function checkModifiers(modifiers: NodeArray): boolean { if (modifiers) { for (const modifier of modifiers) { switch (modifier.kind) { @@ -1309,7 +1311,7 @@ namespace ts { } break; case SyntaxKind.ModuleDeclaration: - if (isAmbientModule(node) && (inAmbientModule || node.flags & NodeFlags.Ambient || isDeclarationFile(file))) { + if (isAmbientModule(node) && (inAmbientModule || hasModifier(node, ModifierFlags.Ambient) || isDeclarationFile(file))) { const moduleName = (node).name; // Ambient module declarations can be interpreted as augmentations for some existing external modules. // This will happen in two cases: diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 68c8f5bc79485..2ce54b9b9ed4d 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -433,9 +433,7 @@ namespace ts { /* @internal */ export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number { - // Using ! with a greater than test is a fast way of testing the following conditions: - // pos === undefined || pos === null || isNaN(pos) || pos < 0; - if (!(pos >= 0)) { + if (positionIsSynthesized(pos)) { return pos; } @@ -642,6 +640,7 @@ namespace ts { pos++; } } + if (collecting) { if (!result) { result = []; diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index 86bad38cb6e1f..967fa0c715f2c 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -7,12 +7,15 @@ namespace ts { setSourceFile(sourceFile: SourceFile): void; emitPos(pos: number): void; emitStart(range: TextRange): void; - emitEnd(range: TextRange, stopOverridingSpan?: boolean): void; - changeEmitSourcePos(): void; + emitEnd(range: TextRange): void; + /*@deprecated*/ emitEnd(range: TextRange, stopOverridingSpan: boolean): void; + /*@deprecated*/ changeEmitSourcePos(): void; getText(): string; getSourceMappingURL(): string; initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void; reset(): void; + enable(): void; + disable(): void; } let nullSourceMapWriter: SourceMapWriter; @@ -38,6 +41,8 @@ namespace ts { getSourceMappingURL(): string { return undefined; }, initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void { }, reset(): void { }, + enable(): void { }, + disable(): void { } }; } @@ -62,6 +67,13 @@ namespace ts { // Source map data let sourceMapData: SourceMapData; + // This keeps track of the number of times `disable` has been called without a + // corresponding call to `enable`. As long as this value is non-zero, mappings will not + // be recorded. + // This is primarily used to provide a better experience when debugging binding + // patterns and destructuring assignments for simple expressions. + let disableDepth: number; + return { getSourceMapData: () => sourceMapData, setSourceFile, @@ -73,6 +85,8 @@ namespace ts { getSourceMappingURL, initialize, reset, + enable, + disable, }; function initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { @@ -81,6 +95,7 @@ namespace ts { } currentSourceFile = undefined; + disableDepth = 0; // Current source map file and its index in the sources list sourceMapSourceIndex = -1; @@ -147,6 +162,23 @@ namespace ts { lastEncodedSourceMapSpan = undefined; lastEncodedNameIndex = undefined; sourceMapData = undefined; + disableDepth = 0; + } + + /** + * Re-enables the recording of mappings. + */ + function enable() { + if (disableDepth > 0) { + disableDepth--; + } + } + + /** + * Disables the recording of mappings. + */ + function disable() { + disableDepth++; } function updateLastEncodedAndRecordedSpans() { @@ -168,7 +200,7 @@ namespace ts { sourceMapData.sourceMapDecodedMappings[sourceMapData.sourceMapDecodedMappings.length - 1] : defaultLastEncodedSourceMapSpan; - // TODO: Update lastEncodedNameIndex + // TODO: Update lastEncodedNameIndex // Since we dont support this any more, lets not worry about it right now. // When we start supporting nameIndex, we will get back to this @@ -236,7 +268,7 @@ namespace ts { } function emitPos(pos: number) { - if (pos === -1) { + if (positionIsSynthesized(pos) || disableDepth > 0) { return; } @@ -288,9 +320,17 @@ namespace ts { function emitStart(range: TextRange) { emitPos(getStartPos(range)); + + if (range.disableSourceMap) { + disable(); + } } function emitEnd(range: TextRange, stopOverridingEnd?: boolean) { + if (range.disableSourceMap) { + enable(); + } + emitPos(range.end); stopOverridingSpan = stopOverridingEnd; } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 9c3972b27566a..f3973e852c6bb 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -8,6 +8,7 @@ namespace ts { args: string[]; newLine: string; useCaseSensitiveFileNames: boolean; + /*@internal*/ developmentMode?: boolean; write(s: string): void; readFile(path: string, encoding?: string): string; writeFile(path: string, data: string, writeByteOrderMark?: boolean): void; @@ -22,6 +23,7 @@ namespace ts { readDirectory(path: string, extension?: string, exclude?: string[]): string[]; getMemoryUsage?(): number; exit(exitCode?: number): void; + /*@internal*/ tryEnableSourceMapsForHost?(): void; } interface WatchedFile { @@ -494,6 +496,7 @@ namespace ts { args: process.argv.slice(2), newLine: _os.EOL, useCaseSensitiveFileNames: useCaseSensitiveFileNames, + developmentMode: /^development$/i.test(String(process.env.NODE_ENV)), write(s: string): void { process.stdout.write(s); }, @@ -564,6 +567,14 @@ namespace ts { }, exit(exitCode?: number): void { process.exit(exitCode); + }, + tryEnableSourceMapsForHost() { + try { + require("source-map-support").install(); + } + catch (e) { + // Could not enable source maps. + } } }; } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 9edecce89ef32..ebacacf6c5fe8 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -1,12 +1,50 @@ /// +/// +/// +/// +/// +/// +/// +/// /* @internal */ namespace ts { + const moduleTransformerMap: Map = { + [ModuleKind.ES6]: transformES6Module, + [ModuleKind.System]: transformSystemModule, + [ModuleKind.AMD]: transformModule, + [ModuleKind.CommonJS]: transformModule, + [ModuleKind.UMD]: transformModule, + [ModuleKind.None]: transformModule, + }; + const enum SyntaxKindFeatureFlags { ExpressionSubstitution = 1 << 0, EmitNotifications = 1 << 1, } + export function getTransformers(compilerOptions: CompilerOptions) { + const jsx = compilerOptions.jsx; + const languageVersion = getEmitScriptTarget(compilerOptions); + const moduleKind = getEmitModuleKind(compilerOptions); + const transformers: Transformer[] = []; + + transformers.push(transformTypeScript); + transformers.push(moduleTransformerMap[moduleKind]); + + if (jsx === JsxEmit.React) { + transformers.push(transformJsx); + } + + transformers.push(transformES7); + + if (languageVersion < ScriptTarget.ES6) { + transformers.push(transformES6); + } + + return transformers; + } + /** * Transforms an array of SourceFiles by passing them through each transformer. * @@ -16,8 +54,6 @@ namespace ts { * @param transforms An array of Transformers. */ export function transformFiles(resolver: EmitResolver, host: EmitHost, sourceFiles: SourceFile[], transformers: Transformer[]) { - const nodeToGeneratedName: Identifier[] = []; - const generatedNameSet: Map = {}; const nodeEmitFlags: NodeEmitFlags[] = []; const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = []; const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = []; @@ -34,10 +70,6 @@ namespace ts { getEmitResolver: () => resolver, getNodeEmitFlags, setNodeEmitFlags, - isUniqueName, - getGeneratedNameForNode, - nodeHasGeneratedName, - makeUniqueName, hoistVariableDeclaration, hoistFunctionDeclaration, startLexicalEnvironment, @@ -46,8 +78,7 @@ namespace ts { expressionSubstitution: node => node, enableExpressionSubstitution, isExpressionSubstitutionEnabled, - onBeforeEmitNode: node => { }, - onAfterEmitNode: node => { }, + onEmitNode: (node, emit) => emit(node), enableEmitNotification, isEmitNotificationEnabled, }; @@ -113,118 +144,6 @@ namespace ts { return node; } - /** - * Generate a name that is unique within the current file and doesn't conflict with any names - * in global scope. The name is formed by adding an '_n' suffix to the specified base name, - * where n is a positive integer. Note that names generated by makeTempVariableName and - * makeUniqueName are guaranteed to never conflict. - */ - function makeUniqueName(baseName: string): Identifier { - // Find the first unique 'name_n', where n is a positive number - if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) { - baseName += "_"; - } - - let i = 1; - while (true) { - const generatedName = baseName + i; - if (isUniqueName(generatedName)) { - return createIdentifier(generatedNameSet[generatedName] = generatedName); - } - - i++; - } - } - - /** - * Gets the generated name for a node. - */ - function getGeneratedNameForNode(node: Node) { - const id = getNodeId(node); - return nodeToGeneratedName[id] || (nodeToGeneratedName[id] = generateNameForNode(node)); - } - - /** - * Gets a value indicating whether a node has a generated name. - */ - function nodeHasGeneratedName(node: Node) { - const id = getNodeId(node); - return nodeToGeneratedName[id] !== undefined; - } - - /** - * Tests whether the provided name is unique. - */ - function isUniqueName(name: string): boolean { - return !resolver.hasGlobalName(name) - && !hasProperty(currentSourceFile.identifiers, name) - && !hasProperty(generatedNameSet, name); - } - - /** - * Tests whether the provided name is unique within a container. - */ - function isUniqueLocalName(name: string, container: Node): boolean { - container = getOriginalNode(container); - for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) { - if (node.locals && hasProperty(node.locals, name)) { - // We conservatively include alias symbols to cover cases where they're emitted as locals - if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) { - return false; - } - } - } - return true; - } - - /** - * Generates a name for a node. - */ - function generateNameForNode(node: Node): Identifier { - switch (node.kind) { - case SyntaxKind.Identifier: - return makeUniqueName((node).text); - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.EnumDeclaration: - return generateNameForModuleOrEnum(node); - case SyntaxKind.ImportDeclaration: - case SyntaxKind.ExportDeclaration: - return generateNameForImportOrExportDeclaration(node); - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ClassDeclaration: - Debug.assert((node.flags & NodeFlags.Default) !== 0, "Can only generate a name for a default export."); - return generateNameForExportDefault(); - case SyntaxKind.ExportAssignment: - return generateNameForExportDefault(); - case SyntaxKind.ClassExpression: - return generateNameForClassExpression(); - default: - return createTempVariable(); - } - } - - function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { - const name = node.name; - // Use module/enum name itself if it is unique, otherwise make a unique variation - return isUniqueLocalName(name.text, node) ? name : makeUniqueName(name.text); - } - - function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { - const expr = getExternalModuleName(node); - const baseName = expr.kind === SyntaxKind.StringLiteral - ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) - : "module"; - return makeUniqueName(baseName); - } - - function generateNameForExportDefault() { - return makeUniqueName("default"); - } - - function generateNameForClassExpression() { - return makeUniqueName("class"); - } - /** * Records a hoisted variable declaration for the provided name within a lexical environment. */ diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts new file mode 100644 index 0000000000000..59dbe0307bc15 --- /dev/null +++ b/src/compiler/transformers/destructuring.ts @@ -0,0 +1,397 @@ +/// +/// + +/*@internal*/ +namespace ts { + /** + * Flattens a destructuring assignment expression. + * + * @param root The destructuring assignment expression. + * @param needsValue Indicates whether the value from the right-hand-side of the + * destructuring assignment is needed as part of a larger expression. + * @param recordTempVariable A callback used to record new temporary variables. + * @param visitor An optional visitor to use to visit expressions. + */ + export function flattenDestructuringAssignment( + node: BinaryExpression, + needsValue: boolean, + recordTempVariable: (node: Identifier) => void, + visitor?: (node: Node) => VisitResult) { + + if (isEmptyObjectLiteralOrArrayLiteral(node.left)) { + return node.right; + } + + let location: TextRange = node; + let value = node.right; + const expressions: Expression[] = []; + if (needsValue) { + // If the right-hand value of the destructuring assignment needs to be preserved (as + // is the case when the destructuring assignmen) is part of a larger expression), + // then we need to cache the right-hand value. + // + // The source map location for the assignment should point to the entire binary + // expression. + value = ensureIdentifier(node.right, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + } + else if (nodeIsSynthesized(node)) { + // Generally, the source map location for a destructuring assignment is the root + // expression. + // + // However, if the root expression is synthesized (as in the case + // of the initializer when transforming a ForOfStatement), then the source map + // location should point to the right-hand value of the expression. + location = node.right; + } + + flattenDestructuring(node, value, location, emitAssignment, emitTempVariableAssignment, visitor); + + if (needsValue) { + expressions.push(value); + } + + const expression = inlineExpressions(expressions); + aggregateTransformFlags(expression); + return expression; + + function emitAssignment(name: Identifier, value: Expression, location: TextRange) { + const expression = createAssignment(name, value, location); + if (isSimpleExpression(value)) { + expression.disableSourceMap = true; + } + + aggregateTransformFlags(expression); + expressions.push(expression); + } + + function emitTempVariableAssignment(value: Expression, location: TextRange) { + const name = createTempVariable(); + recordTempVariable(name); + emitAssignment(name, value, location); + return name; + } + } + + /** + * Flattens binding patterns in a parameter declaration. + * + * @param node The ParameterDeclaration to flatten. + * @param value The rhs value for the binding pattern. + * @param visitor An optional visitor to use to visit expressions. + */ + export function flattenParameterDestructuring(node: ParameterDeclaration, value: Expression, visitor?: (node: Node) => VisitResult) { + const declarations: VariableDeclaration[] = []; + + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor); + + return declarations; + + function emitAssignment(name: Identifier, value: Expression, location: TextRange) { + const declaration = createVariableDeclaration(name, value, location); + if (isSimpleExpression(value)) { + declaration.disableSourceMap = true; + } + + aggregateTransformFlags(declaration); + declarations.push(declaration); + } + + function emitTempVariableAssignment(value: Expression, location: TextRange) { + const name = createTempVariable(); + emitAssignment(name, value, location); + return name; + } + } + + /** + * Flattens binding patterns in a variable declaration. + * + * @param node The VariableDeclaration to flatten. + * @param value An optional rhs value for the binding pattern. + * @param visitor An optional visitor to use to visit expressions. + */ + export function flattenVariableDestructuring(node: VariableDeclaration, value?: Expression, visitor?: (node: Node) => VisitResult) { + const declarations: VariableDeclaration[] = []; + + flattenDestructuring(node, value, node, emitAssignment, emitTempVariableAssignment, visitor); + + return declarations; + + function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + const declaration = createVariableDeclaration(name, value, location); + if (declarations.length === 0) { + declaration.pos = -1; + } + + if (isSimpleExpression(value)) { + declaration.disableSourceMap = true; + } + + declaration.original = original; + declarations.push(declaration); + aggregateTransformFlags(declaration); + } + + function emitTempVariableAssignment(value: Expression, location: TextRange) { + const name = createTempVariable(); + emitAssignment(name, value, location, /*original*/ undefined); + return name; + } + } + + /** + * Flattens binding patterns in a variable declaration and transforms them into an expression. + * + * @param node The VariableDeclaration to flatten. + * @param recordTempVariable A callback used to record new temporary variables. + * @param nameSubstitution An optional callback used to substitute binding names. + * @param visitor An optional visitor to use to visit expressions. + */ + export function flattenVariableDestructuringToExpression( + node: VariableDeclaration, + recordTempVariable: (name: Identifier) => void, + nameSubstitution?: (name: Identifier) => Expression, + visitor?: (node: Node) => VisitResult) { + + const pendingAssignments: Expression[] = []; + + flattenDestructuring(node, /*value*/ undefined, node, emitAssignment, emitTempVariableAssignment); + + const expression = inlineExpressions(pendingAssignments); + aggregateTransformFlags(expression); + return expression; + + function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + const left = nameSubstitution && nameSubstitution(name) || name; + emitPendingAssignment(left, value, location, original); + } + + function emitTempVariableAssignment(value: Expression, location: TextRange) { + const name = createTempVariable(); + recordTempVariable(name); + emitPendingAssignment(name, value, location, /*original*/ undefined); + return name; + } + + function emitPendingAssignment(name: Expression, value: Expression, location: TextRange, original: Node) { + const expression = createAssignment(name, value, location); + if (isSimpleExpression(value)) { + expression.disableSourceMap = true; + } + + expression.original = original; + pendingAssignments.push(expression); + return expression; + } + } + + function flattenDestructuring( + root: BindingElement | BinaryExpression, + value: Expression, + location: TextRange, + emitAssignment: (name: Identifier, value: Expression, location: TextRange, original: Node) => void, + emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier, + visitor?: (node: Node) => VisitResult) { + if (value && visitor) { + value = visitNode(value, visitor, isExpression); + } + + if (isBinaryExpression(root)) { + emitDestructuringAssignment(root.left, value, location); + } + else { + emitBindingElement(root, value); + } + + function emitDestructuringAssignment(bindingTarget: Expression | ShorthandPropertyAssignment, value: Expression, location: TextRange) { + // When emitting target = value use source map node to highlight, including any temporary assignments needed for this + let target: Expression; + if (isShorthandPropertyAssignment(bindingTarget)) { + const initializer = visitor + ? visitNode(bindingTarget.objectAssignmentInitializer, visitor, isExpression) + : bindingTarget.objectAssignmentInitializer; + + if (initializer) { + value = createDefaultValueCheck(value, initializer, location); + } + + target = bindingTarget.name; + } + else if (isBinaryExpression(bindingTarget) && bindingTarget.operatorToken.kind === SyntaxKind.EqualsToken) { + const initializer = visitor + ? visitNode(bindingTarget.right, visitor, isExpression) + : bindingTarget.right; + + value = createDefaultValueCheck(value, initializer, location); + target = bindingTarget.left; + } + else { + target = bindingTarget; + } + + if (target.kind === SyntaxKind.ObjectLiteralExpression) { + emitObjectLiteralAssignment(target, value, location); + } + else if (target.kind === SyntaxKind.ArrayLiteralExpression) { + emitArrayLiteralAssignment(target, value, location); + } + else { + const name = getRelocatedClone(target, /*location*/ target); + emitAssignment(name, value, location, /*original*/ undefined); + } + } + + function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression, location: TextRange) { + const properties = target.properties; + if (properties.length !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment + value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + } + + for (const p of properties) { + if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { + const propName = (p).name; + const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? p : (p).initializer || propName; + // Assignment for target = value.propName should highligh whole property, hence use p as source map node + emitDestructuringAssignment(target, createDestructuringPropertyAccess(value, propName), p); + } + } + } + + function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, location: TextRange) { + const elements = target.elements; + const numElements = elements.length; + if (numElements !== 1) { + // For anything but a single element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. + // When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment + value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + } + + for (let i = 0; i < numElements; i++) { + const e = elements[i]; + if (e.kind !== SyntaxKind.OmittedExpression) { + // Assignment for target = value.propName should highligh whole property, hence use e as source map node + if (e.kind !== SyntaxKind.SpreadElementExpression) { + emitDestructuringAssignment(e, createElementAccess(value, createLiteral(i)), e); + } + else if (i === numElements - 1) { + emitDestructuringAssignment((e).expression, createArraySlice(value, i), e); + } + } + } + } + + function emitBindingElement(target: BindingElement, value: Expression) { + // Any temporary assignments needed to emit target = value should point to target + const initializer = visitor ? visitNode(target.initializer, visitor, isExpression) : target.initializer; + if (initializer) { + // Combine value and initializer + value = value ? createDefaultValueCheck(value, initializer, target) : initializer; + } + else if (!value) { + // Use 'void 0' in absence of value and initializer + value = createVoidZero(); + } + + const name = target.name; + if (isBindingPattern(name)) { + const elements = name.elements; + const numElements = elements.length; + if (numElements !== 1) { + // For anything other than a single-element destructuring we need to generate a temporary + // to ensure value is evaluated exactly once. Additionally, if we have zero elements + // we need to emit *something* to ensure that in case a 'var' keyword was already emitted, + // so in that case, we'll intentionally create that temporary. + value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target, emitTempVariableAssignment); + } + for (let i = 0; i < numElements; i++) { + const element = elements[i]; + if (name.kind === SyntaxKind.ObjectBindingPattern) { + // Rewrite element to a declaration with an initializer that fetches property + const propName = element.propertyName || element.name; + emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); + } + else if (element.kind !== SyntaxKind.OmittedExpression) { + if (!element.dotDotDotToken) { + // Rewrite element to a declaration that accesses array element at index i + emitBindingElement(element, createElementAccess(value, i)); + } + else if (i === numElements - 1) { + emitBindingElement(element, createArraySlice(value, i)); + } + } + } + } + else { + const clonedName = getSynthesizedClone(name); + emitAssignment(clonedName, value, target, target); + } + } + + function createDefaultValueCheck(value: Expression, defaultValue: Expression, location: TextRange): Expression { + value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, location, emitTempVariableAssignment); + return createConditional( + createStrictEquality(value, createVoidZero()), + defaultValue, + value + ); + } + + /** + * Creates either a PropertyAccessExpression or an ElementAccessExpression for the + * right-hand side of a transformed destructuring assignment. + * + * @param expression The right-hand expression that is the source of the property. + * @param propertyName The destructuring property name. + */ + function createDestructuringPropertyAccess(expression: Expression, propertyName: PropertyName): LeftHandSideExpression { + if (isComputedPropertyName(propertyName)) { + return createElementAccess( + expression, + ensureIdentifier(propertyName.expression, /*reuseIdentifierExpressions*/ false, /*location*/ propertyName, emitTempVariableAssignment) + ); + } + else if (isIdentifier(propertyName)) { + return createPropertyAccess( + expression, + propertyName.text + ); + } + else { + // We create a synthetic copy of the identifier in order to avoid the rewriting that might + // otherwise occur when the identifier is emitted. + return createElementAccess( + expression, + getSynthesizedClone(propertyName) + ); + } + } + } + + /** + * Ensures that there exists a declared identifier whose value holds the given expression. + * This function is useful to ensure that the expression's value can be read from in subsequent expressions. + * Unless 'reuseIdentifierExpressions' is false, 'value' will be returned if it is just an identifier. + * + * @param value the expression whose value needs to be bound. + * @param reuseIdentifierExpressions true if identifier expressions can simply be returned; + * false if it is necessary to always emit an identifier. + * @param location The location to use for source maps and comments. + * @param emitTempVariableAssignment A callback used to emit a temporary variable. + */ + function ensureIdentifier( + value: Expression, + reuseIdentifierExpressions: boolean, + location: TextRange, + emitTempVariableAssignment: (value: Expression, location: TextRange) => Identifier) { + if (isIdentifier(value) && reuseIdentifierExpressions) { + return value; + } + else { + return emitTempVariableAssignment(value, location); + } + } +} \ No newline at end of file diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts new file mode 100644 index 0000000000000..05c001a711411 --- /dev/null +++ b/src/compiler/transformers/es6.ts @@ -0,0 +1,1882 @@ +/// +/// + +/*@internal*/ +namespace ts { + + const enum ES6SubstitutionFlags { + /** Enables substitutions for captured `this` */ + CapturedThis = 1 << 0, + /** Enables substitutions for block-scoped bindings. */ + BlockScopedBindings = 1 << 1, + } + + export function transformES6(context: TransformationContext) { + const { + startLexicalEnvironment, + endLexicalEnvironment, + hoistVariableDeclaration, + getNodeEmitFlags, + setNodeEmitFlags, + } = context; + + const resolver = context.getEmitResolver(); + const previousIdentifierSubstitution = context.identifierSubstitution; + const previousExpressionSubstitution = context.expressionSubstitution; + const previousOnEmitNode = context.onEmitNode; + context.onEmitNode = onEmitNode; + context.identifierSubstitution = substituteIdentifier; + context.expressionSubstitution = substituteExpression; + + let currentSourceFile: SourceFile; + let currentParent: Node; + let currentNode: Node; + let enclosingBlockScopeContainer: Node; + let enclosingBlockScopeContainerParent: Node; + let containingNonArrowFunction: FunctionLikeDeclaration; + + /** + * Keeps track of whether substitutions have been enabled for specific cases. + * They are persisted between each SourceFile transformation and should not + * be reset. + */ + let enabledSubstitutions: ES6SubstitutionFlags; + + /** + * This is used to determine whether we need to emit `_this` instead of `this`. + */ + let useCapturedThis: boolean; + + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + currentSourceFile = node; + enclosingBlockScopeContainer = node; + return visitEachChild(node, visitor, context); + } + + function visitor(node: Node): VisitResult { + const savedContainingNonArrowFunction = containingNonArrowFunction; + const savedCurrentParent = currentParent; + const savedCurrentNode = currentNode; + const savedEnclosingBlockScopeContainer = enclosingBlockScopeContainer; + const savedEnclosingBlockScopeContainerParent = enclosingBlockScopeContainerParent; + + onBeforeVisitNode(node); + + const visited = visitorWorker(node); + + containingNonArrowFunction = savedContainingNonArrowFunction; + currentParent = savedCurrentParent; + currentNode = savedCurrentNode; + enclosingBlockScopeContainer = savedEnclosingBlockScopeContainer; + enclosingBlockScopeContainerParent = savedEnclosingBlockScopeContainerParent; + return visited; + } + + function visitorWorker(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.ES6) { + return visitJavaScript(node); + } + else if (node.transformFlags & TransformFlags.ContainsES6) { + return visitEachChild(node, visitor, context); + } + else { + return node; + } + } + + function visitJavaScript(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node); + + case SyntaxKind.ClassExpression: + return visitClassExpression(node); + + case SyntaxKind.Parameter: + return visitParameter(node); + + case SyntaxKind.FunctionDeclaration: + return visitFunctionDeclaration(node); + + case SyntaxKind.ArrowFunction: + return visitArrowFunction(node); + + case SyntaxKind.FunctionExpression: + return visitFunctionExpression(node); + + case SyntaxKind.VariableDeclaration: + return visitVariableDeclaration(node); + + case SyntaxKind.VariableDeclarationList: + return visitVariableDeclarationList(node); + + case SyntaxKind.LabeledStatement: + return visitLabeledStatement(node); + + case SyntaxKind.DoStatement: + return visitDoStatement(node); + + case SyntaxKind.WhileStatement: + return visitWhileStatement(node); + + case SyntaxKind.ForStatement: + return visitForStatement(node); + + case SyntaxKind.ForInStatement: + return visitForInStatement(node); + + case SyntaxKind.ForOfStatement: + return visitForOfStatement(node); + + case SyntaxKind.ExpressionStatement: + return visitExpressionStatement(node); + + case SyntaxKind.ObjectLiteralExpression: + return visitObjectLiteralExpression(node); + + case SyntaxKind.ShorthandPropertyAssignment: + return visitShorthandPropertyAssignment(node); + + case SyntaxKind.ArrayLiteralExpression: + return visitArrayLiteralExpression(node); + + case SyntaxKind.CallExpression: + return visitCallExpression(node); + + case SyntaxKind.NewExpression: + return visitNewExpression(node); + + case SyntaxKind.ParenthesizedExpression: + return visitParenthesizedExpression(node, /*needsDestructuringValue*/ true); + + case SyntaxKind.BinaryExpression: + return visitBinaryExpression(node, /*needsDestructuringValue*/ true); + + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return visitTemplateLiteral(node); + + case SyntaxKind.TaggedTemplateExpression: + return visitTaggedTemplateExpression(node); + + case SyntaxKind.TemplateExpression: + return visitTemplateExpression(node); + + case SyntaxKind.SuperKeyword: + return visitSuperKeyword(node); + + case SyntaxKind.MethodDeclaration: + return visitMethodDeclaration(node); + + case SyntaxKind.SourceFile: + return visitSourceFileNode(node); + + default: + Debug.failBadSyntaxKind(node); + return visitEachChild(node, visitor, context); + } + + } + + function onBeforeVisitNode(node: Node) { + const currentGrandparent = currentParent; + currentParent = currentNode; + currentNode = node; + + if (currentParent) { + if (isBlockScope(currentParent, currentGrandparent)) { + enclosingBlockScopeContainer = currentParent; + enclosingBlockScopeContainerParent = currentGrandparent; + } + + switch (currentParent.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + containingNonArrowFunction = currentParent; + break; + } + } + } + + /** + * Visits a ClassDeclaration and transforms it into a variable statement. + * + * @param node A ClassDeclaration node. + */ + function visitClassDeclaration(node: ClassDeclaration): Statement { + // [source] + // class C { } + // + // [output] + // var C = (function () { + // function C() { + // } + // return C; + // }()); + + return startOnNewLine( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + getDeclarationName(node), + transformClassLikeDeclarationToExpression(node) + ) + ]), + node + ) + ); + } + + /** + * Visits a ClassExpression and transforms it into an expression. + * + * @param node A ClassExpression node. + */ + function visitClassExpression(node: ClassExpression): Expression { + // [source] + // C = class { } + // + // [output] + // C = (function () { + // function class_1() { + // } + // return class_1; + // }()) + + return transformClassLikeDeclarationToExpression(node); + } + + /** + * Transforms a ClassExpression or ClassDeclaration into an expression. + * + * @param node A ClassExpression or ClassDeclaration node. + */ + function transformClassLikeDeclarationToExpression(node: ClassExpression | ClassDeclaration): Expression { + // [source] + // class C extends D { + // constructor() {} + // method() {} + // get prop() {} + // set prop(v) {} + // } + // + // [output] + // (function (_super) { + // __extends(C, _super); + // function C() { + // } + // C.prototype.method = function () {} + // Object.defineProperty(C.prototype, "prop", { + // get: function() {}, + // set: function() {}, + // enumerable: true, + // configurable: true + // }); + // return C; + // }(D)) + + const baseTypeNode = getClassExtendsHeritageClauseElement(node); + return createParen( + createCall( + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + baseTypeNode ? [createParameter("_super")] : [], + transformClassBody(node, baseTypeNode !== undefined) + ), + baseTypeNode + ? [visitNode(baseTypeNode.expression, visitor, isExpression)] + : [] + ) + ); + } + + /** + * Transforms a ClassExpression or ClassDeclaration into a function body. + * + * @param node A ClassExpression or ClassDeclaration node. + * @param hasExtendsClause A value indicating whether the class has an `extends` clause. + */ + function transformClassBody(node: ClassExpression | ClassDeclaration, hasExtendsClause: boolean): Block { + const statements: Statement[] = []; + startLexicalEnvironment(); + addExtendsHelperIfNeeded(statements, node, hasExtendsClause); + addConstructor(statements, node, hasExtendsClause); + addClassMembers(statements, node); + statements.push(createReturn(getDeclarationName(node))); + addRange(statements, endLexicalEnvironment()); + return createBlock(statements, /*location*/ undefined, /*multiLine*/ true); + } + + /** + * Adds a call to the `__extends` helper if needed for a class. + * + * @param statements The statements of the class body function. + * @param node The ClassExpression or ClassDeclaration node. + * @param hasExtendsClause A value indicating whether the class has an `extends` clause. + */ + function addExtendsHelperIfNeeded(statements: Statement[], node: ClassExpression | ClassDeclaration, hasExtendsClause: boolean): void { + if (hasExtendsClause) { + statements.push( + createStatement( + createExtendsHelper(getDeclarationName(node)) + ) + ); + } + } + + /** + * Adds the constructor of the class to a class body function. + * + * @param statements The statements of the class body function. + * @param node The ClassExpression or ClassDeclaration node. + * @param hasExtendsClause A value indicating whether the class has an `extends` clause. + */ + function addConstructor(statements: Statement[], node: ClassExpression | ClassDeclaration, hasExtendsClause: boolean): void { + const constructor = getFirstConstructorWithBody(node); + const hasSynthesizedSuper = hasSynthesizedDefaultSuperCall(constructor, hasExtendsClause); + statements.push( + createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + getDeclarationName(node), + transformConstructorParameters(constructor, hasSynthesizedSuper), + transformConstructorBody(constructor, hasExtendsClause, hasSynthesizedSuper), + /*location*/ constructor + ) + ); + } + + /** + * Transforms the parameters of the constructor declaration of a class. + * + * @param constructor The constructor for the class. + * @param hasSynthesizedSuper A value indicating whether the constructor starts with a + * synthesized `super` call. + */ + function transformConstructorParameters(constructor: ConstructorDeclaration, hasSynthesizedSuper: boolean): ParameterDeclaration[] { + // If the TypeScript transformer needed to synthesize a constructor for property + // initializers, it would have also added a synthetic `...args` parameter and + // `super` call. + // If this is the case, we do not include the synthetic `...args` parameter and + // will instead use the `arguments` object in ES5/3. + if (constructor && !hasSynthesizedSuper) { + return visitNodes(constructor.parameters, visitor, isParameter); + } + + return []; + } + + /** + * Transforms the body of a constructor declaration of a class. + * + * @param constructor The constructor for the class. + * @param hasExtendsClause A value indicating whether the class has an `extends` clause. + * @param hasSynthesizedSuper A value indicating whether the constructor starts with a + * synthesized `super` call. + */ + function transformConstructorBody(constructor: ConstructorDeclaration, hasExtendsClause: boolean, hasSynthesizedSuper: boolean) { + const statements: Statement[] = []; + startLexicalEnvironment(); + if (constructor) { + addCaptureThisForNodeIfNeeded(statements, constructor); + addDefaultValueAssignmentsIfNeeded(statements, constructor); + addRestParameterIfNeeded(statements, constructor, hasSynthesizedSuper); + } + + addDefaultSuperCallIfNeeded(statements, constructor, hasExtendsClause, hasSynthesizedSuper); + + if (constructor) { + addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, hasSynthesizedSuper ? 1 : 0)); + } + + addRange(statements, endLexicalEnvironment()); + return createBlock(statements, /*location*/ constructor && constructor.body, /*multiLine*/ true); + } + + /** + * Adds a synthesized call to `_super` if it is needed. + * + * @param statements The statements for the new constructor body. + * @param constructor The constructor for the class. + * @param hasExtendsClause A value indicating whether the class has an `extends` clause. + * @param hasSynthesizedSuper A value indicating whether the constructor starts with a + * synthesized `super` call. + */ + function addDefaultSuperCallIfNeeded(statements: Statement[], constructor: ConstructorDeclaration, hasExtendsClause: boolean, hasSynthesizedSuper: boolean) { + // If the TypeScript transformer needed to synthesize a constructor for property + // initializers, it would have also added a synthetic `...args` parameter and + // `super` call. + // If this is the case, or if the class has an `extends` clause but no + // constructor, we emit a synthesized call to `_super`. + if (constructor ? hasSynthesizedSuper : hasExtendsClause) { + statements.push( + createStatement( + createFunctionApply( + createIdentifier("_super"), + createThis(), + createIdentifier("arguments") + ) + ) + ); + } + } + + /** + * Visits a parameter declaration. + * + * @param node A ParameterDeclaration node. + */ + function visitParameter(node: ParameterDeclaration): ParameterDeclaration { + if (isBindingPattern(node.name)) { + // Binding patterns are converted into a generated name and are + // evaluated inside the function body. + return createParameter( + getGeneratedNameForNode(node), + /*initializer*/ undefined, + /*location*/ node + ); + } + else if (node.initializer) { + // Initializers are elided + return createParameter( + node.name, + /*initializer*/ undefined, + /*location*/ node + ); + } + else if (node.dotDotDotToken) { + // rest parameters are elided + return undefined; + } + else { + return node; + } + } + + /** + * Gets a value indicating whether we need to add default value assignments for a + * function-like node. + * + * @param node A function-like node. + */ + function shouldAddDefaultValueAssignments(node: FunctionLikeDeclaration): boolean { + return (node.transformFlags & TransformFlags.ContainsDefaultValueAssignments) !== 0; + } + + /** + * Adds statements to the body of a function-like node if it contains parameters with + * binding patterns or initializers. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + */ + function addDefaultValueAssignmentsIfNeeded(statements: Statement[], node: FunctionLikeDeclaration): void { + if (!shouldAddDefaultValueAssignments(node)) { + return; + } + + for (const parameter of node.parameters) { + const { name, initializer, dotDotDotToken } = parameter; + + // A rest parameter cannot have a binding pattern or an initializer, + // so let's just ignore it. + if (dotDotDotToken) { + continue; + } + + if (isBindingPattern(name)) { + addDefaultValueAssignmentForBindingPattern(statements, parameter, name, initializer); + } + else if (initializer) { + addDefaultValueAssignmentForInitializer(statements, parameter, name, initializer); + } + } + } + + /** + * Adds statements to the body of a function-like node for parameters with binding patterns + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForBindingPattern(statements: Statement[], parameter: ParameterDeclaration, name: BindingPattern, initializer: Expression): void { + const temp = getGeneratedNameForNode(parameter); + + // In cases where a binding pattern is simply '[]' or '{}', + // we usually don't want to emit a var declaration; however, in the presence + // of an initializer, we must emit that expression to preserve side effects. + if (name.elements.length > 0) { + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + flattenParameterDestructuring(parameter, temp, visitor) + ) + ) + ); + } + else if (initializer) { + statements.push( + createStatement( + createAssignment( + temp, + visitNode(initializer, visitor, isExpression) + ) + ) + ); + } + } + + /** + * Adds statements to the body of a function-like node for parameters with initializers. + * + * @param statements The statements for the new function body. + * @param parameter The parameter for the function. + * @param name The name of the parameter. + * @param initializer The initializer for the parameter. + */ + function addDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { + statements.push( + createIf( + createStrictEquality( + getSynthesizedClone(name), + createVoidZero() + ), + setNodeEmitFlags( + createBlock([ + createStatement( + createAssignment( + getSynthesizedClone(name), + visitNode(initializer, visitor, isExpression) + ) + ) + ]), + NodeEmitFlags.SingleLine + ) + ) + ); + } + + /** + * Gets a value indicating whether we need to add statements to handle a rest parameter. + * + * @param node A ParameterDeclaration node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + function shouldAddRestParameter(node: ParameterDeclaration, inConstructorWithSynthesizedSuper: boolean) { + return node && node.dotDotDotToken && !inConstructorWithSynthesizedSuper; + } + + /** + * Adds statements to the body of a function-like node if it contains a rest parameter. + * + * @param statements The statements for the new function body. + * @param node A function-like node. + * @param inConstructorWithSynthesizedSuper A value indicating whether the parameter is + * part of a constructor declaration with a + * synthesized call to `super` + */ + function addRestParameterIfNeeded(statements: Statement[], node: FunctionLikeDeclaration, inConstructorWithSynthesizedSuper: boolean): void { + const parameter = lastOrUndefined(node.parameters); + if (!shouldAddRestParameter(parameter, inConstructorWithSynthesizedSuper)) { + return; + } + + const name = getSynthesizedClone(parameter.name); + const restIndex = node.parameters.length - 1; + const temp = createLoopVariable(); + + // var param = []; + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + name, + createArrayLiteral([]) + ) + ]) + ) + ); + + // for (var _i = restIndex; _i < arguments.length; _i++) { + // param[_i - restIndex] = arguments[_i]; + // } + statements.push( + createFor( + createVariableDeclarationList([ + createVariableDeclaration(temp, createLiteral(restIndex)) + ]), + createLessThan( + temp, + createPropertyAccess(createIdentifier("arguments"), "length") + ), + createPostfixIncrement(temp), + createBlock([ + startOnNewLine( + createStatement( + createAssignment( + createElementAccess( + name, + createSubtract(temp, createLiteral(restIndex)) + ), + createElementAccess(createIdentifier("arguments"), temp) + ) + ) + ) + ]) + ) + ); + } + + /** + * Adds a statement to capture the `this` of a function declaration if it is needed. + * + * @param statements The statements for the new function body. + * @param node A node. + */ + function addCaptureThisForNodeIfNeeded(statements: Statement[], node: Node): void { + if (node.transformFlags & TransformFlags.ContainsCapturedLexicalThis && node.kind !== SyntaxKind.ArrowFunction) { + enableSubstitutionsForCapturedThis(); + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + "_this", + createThis() + ) + ]) + ) + ); + } + } + + /** + * Adds statements to the class body function for a class to define the members of the + * class. + * + * @param statements The statements for the class body function. + * @param node The ClassExpression or ClassDeclaration node. + */ + function addClassMembers(statements: Statement[], node: ClassExpression | ClassDeclaration): void { + for (const member of node.members) { + switch (member.kind) { + case SyntaxKind.SemicolonClassElement: + statements.push(transformSemicolonClassElementToStatement(member)); + break; + + case SyntaxKind.MethodDeclaration: + statements.push(transformClassMethodDeclarationToStatement(getClassMemberPrefix(node, member), member)); + break; + + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + const accessors = getAllAccessorDeclarations(node.members, member); + if (member === accessors.firstAccessor) { + statements.push(transformAccessorsToStatement(getClassMemberPrefix(node, member), accessors)); + } + + break; + + case SyntaxKind.Constructor: + // Constructors are handled in visitClassExpression/visitClassDeclaration + break; + + default: + Debug.failBadSyntaxKind(node); + break; + } + } + } + + /** + * Transforms a SemicolonClassElement into a statement for a class body function. + * + * @param member The SemicolonClassElement node. + */ + function transformSemicolonClassElementToStatement(member: SemicolonClassElement) { + return createEmptyStatement(/*location*/ member); + } + + /** + * Transforms a MethodDeclaration into a statement for a class body function. + * + * @param receiver The receiver for the member. + * @param member The MethodDeclaration node. + */ + function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration) { + return createStatement( + createAssignment( + createMemberAccessForPropertyName( + receiver, + visitNode(member.name, visitor, isPropertyName) + ), + transformFunctionLikeToExpression(member, /*location*/ undefined, /*name*/ undefined) + ), + /*location*/ member + ); + } + + /** + * Transforms a set of related of get/set accessors into a statement for a class body function. + * + * @param receiver The receiver for the member. + * @param accessors The set of related get/set accessors. + */ + function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations): Statement { + return createStatement( + transformAccessorsToExpression(receiver, accessors) + ); + } + + /** + * Transforms a set of related get/set accessors into an expression for either a class + * body function or an ObjectLiteralExpression with computed properties. + * + * @param receiver The receiver for the member. + */ + function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations): Expression { + return createObjectDefineProperty( + receiver, + createExpressionForPropertyName( + visitNode(firstAccessor.name, visitor, isPropertyName), + /*location*/ firstAccessor.name + ), + { + get: getAccessor && transformFunctionLikeToExpression(getAccessor, /*location*/ getAccessor, /*name*/ undefined), + set: setAccessor && transformFunctionLikeToExpression(setAccessor, /*location*/ setAccessor, /*name*/ undefined), + enumerable: true, + configurable: true + }, + /*preferNewLine*/ true, + /*location*/ firstAccessor + ); + } + + /** + * Visits an ArrowFunction and transforms it into a FunctionExpression. + * + * @param node An ArrowFunction node. + */ + function visitArrowFunction(node: ArrowFunction) { + if (node.transformFlags & TransformFlags.ContainsLexicalThis) { + enableSubstitutionsForCapturedThis(); + } + + const func = transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined); + setNodeEmitFlags(func, NodeEmitFlags.CapturesThis); + return func; + } + + /** + * Visits a FunctionExpression node. + * + * @param node a FunctionExpression node. + */ + function visitFunctionExpression(node: FunctionExpression): Expression { + return transformFunctionLikeToExpression(node, /*location*/ node, node.name); + } + + /** + * Visits a FunctionDeclaration node. + * + * @param node a FunctionDeclaration node. + */ + function visitFunctionDeclaration(node: FunctionDeclaration): FunctionDeclaration { + return createFunctionDeclaration( + /*modifiers*/ undefined, + node.asteriskToken, + node.name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBody(node), + /*location*/ node, + /*original*/ node + ); + } + + /** + * Transforms a function-like node into a FunctionExpression. + * + * @param node The function-like node to transform. + * @param location The source-map location for the new FunctionExpression. + * @param name The name of the new FunctionExpression. + */ + function transformFunctionLikeToExpression(node: FunctionLikeDeclaration, location: TextRange, name: Identifier): FunctionExpression { + const savedContainingNonArrowFunction = containingNonArrowFunction; + if (node.kind !== SyntaxKind.ArrowFunction) { + containingNonArrowFunction = node; + } + + const expression = createFunctionExpression( + /*asteriskToken*/ undefined, + name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBody(node), + location, + /*original*/ node + ); + + containingNonArrowFunction = savedContainingNonArrowFunction; + return expression; + } + + /** + * Transforms the body of a function-like node. + * + * @param node A function-like node. + */ + function transformFunctionBody(node: FunctionLikeDeclaration) { + const statements: Statement[] = []; + startLexicalEnvironment(); + addCaptureThisForNodeIfNeeded(statements, node); + addDefaultValueAssignmentsIfNeeded(statements, node); + addRestParameterIfNeeded(statements, node, /*inConstructorWithSynthesizedSuper*/ false); + + const body = node.body; + if (isBlock(body)) { + addRange(statements, visitNodes(body.statements, visitor, isStatement)); + } + else { + const expression = visitNode(body, visitor, isExpression); + if (expression) { + statements.push(createReturn(expression, /*location*/ body)); + } + } + + addRange(statements, endLexicalEnvironment()); + return createBlock(statements, node.body); + } + + /** + * Visits an ExpressionStatement that contains a destructuring assignment. + * + * @param node An ExpressionStatement node. + */ + function visitExpressionStatement(node: ExpressionStatement): ExpressionStatement { + // If we are here it is most likely because our expression is a destructuring assignment. + switch (node.expression.kind) { + case SyntaxKind.ParenthesizedExpression: + return createStatement( + visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ false), + /*location*/ node + ); + + case SyntaxKind.BinaryExpression: + return createStatement( + visitBinaryExpression(node.expression, /*needsDestructuringValue*/ false), + /*location*/ node + ); + } + + return visitEachChild(node, visitor, context); + } + + /** + * Visits a ParenthesizedExpression that may contain a destructuring assignment. + * + * @param node A ParenthesizedExpression node. + * @param needsDestructuringValue A value indicating whether we need to hold onto the rhs + * of a destructuring assignment. + */ + function visitParenthesizedExpression(node: ParenthesizedExpression, needsDestructuringValue: boolean): ParenthesizedExpression { + // If we are here it is most likely because our expression is a destructuring assignment. + if (needsDestructuringValue) { + switch (node.expression.kind) { + case SyntaxKind.ParenthesizedExpression: + return createParen( + visitParenthesizedExpression(node.expression, /*needsDestructuringValue*/ true), + /*location*/ node + ); + + case SyntaxKind.BinaryExpression: + return createParen( + visitBinaryExpression(node.expression, /*needsDestructuringValue*/ true), + /*location*/ node + ); + } + } + + return visitEachChild(node, visitor, context); + } + + /** + * Visits a BinaryExpression that contains a destructuring assignment. + * + * @param node A BinaryExpression node. + * @param needsDestructuringValue A value indicating whether we need to hold onto the rhs + * of a destructuring assignment. + */ + function visitBinaryExpression(node: BinaryExpression, needsDestructuringValue: boolean): Expression { + // If we are here it is because this is a destructuring assignment. + Debug.assert(isDestructuringAssignment(node)); + return flattenDestructuringAssignment(node, needsDestructuringValue, hoistVariableDeclaration, visitor); + } + + /** + * Visits a VariableDeclarationList that is block scoped (e.g. `let` or `const`). + * + * @param node A VariableDeclarationList node. + */ + function visitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList { + // If we are here it is because the list is defined as `let` or `const`. + Debug.assert((node.flags & NodeFlags.BlockScoped) !== 0); + + enableSubstitutionsForBlockScopedBindings(); + return setOriginalNode( + createVariableDeclarationList( + flatten(map(node.declarations, visitVariableDeclarationInLetDeclarationList)), + /*location*/ node + ), + node + ); + } + + /** + * Gets a value indicating whether we should emit an explicit initializer for a variable + * declaration in a `let` declaration list. + * + * @param node A VariableDeclaration node. + */ + function shouldEmitExplicitInitializerForLetDeclaration(node: VariableDeclaration) { + // Nested let bindings might need to be initialized explicitly to preserve + // ES6 semantic: + // + // { let x = 1; } + // { let x; } // x here should be undefined. not 1 + // + // Top level bindings never collide with anything and thus don't require + // explicit initialization. As for nested let bindings there are two cases: + // + // - Nested let bindings that were not renamed definitely should be + // initialized explicitly: + // + // { let x = 1; } + // { let x; if (some-condition) { x = 1}; if (x) { /*1*/ } } + // + // Without explicit initialization code in /*1*/ can be executed even if + // some-condition is evaluated to false. + // + // - Renaming introduces fresh name that should not collide with any + // existing names, however renamed bindings sometimes also should be + // explicitly initialized. One particular case: non-captured binding + // declared inside loop body (but not in loop initializer): + // + // let x; + // for (;;) { + // let x; + // } + // + // In downlevel codegen inner 'x' will be renamed so it won't collide + // with outer 'x' however it will should be reset on every iteration as + // if it was declared anew. + // + // * Why non-captured binding? + // - Because if loop contains block scoped binding captured in some + // function then loop body will be rewritten to have a fresh scope + // on every iteration so everything will just work. + // + // * Why loop initializer is excluded? + // - Since we've introduced a fresh name it already will be undefined. + + const original = getOriginalNode(node); + Debug.assert(isVariableDeclaration(original)); + + const flags = resolver.getNodeCheckFlags(original); + const isCapturedInFunction = flags & NodeCheckFlags.CapturedBlockScopedBinding; + const isDeclaredInLoop = flags & NodeCheckFlags.BlockScopedBindingInLoop; + const emittedAsTopLevel = + isBlockScopedContainerTopLevel(enclosingBlockScopeContainer) + || (isCapturedInFunction + && isDeclaredInLoop + && isBlock(enclosingBlockScopeContainer) + && isIterationStatement(enclosingBlockScopeContainerParent, /*lookInLabeledStatements*/ false)); + + const emitExplicitInitializer = + !emittedAsTopLevel + && enclosingBlockScopeContainer.kind !== SyntaxKind.ForInStatement + && enclosingBlockScopeContainer.kind !== SyntaxKind.ForOfStatement + && (!resolver.isDeclarationWithCollidingName(original) + || (isDeclaredInLoop + && !isCapturedInFunction + && !isIterationStatement(enclosingBlockScopeContainer, /*lookInLabeledStatements*/ false))); + + return emitExplicitInitializer; + } + + /** + * Visits a VariableDeclaration in a `let` declaration list. + * + * @param node A VariableDeclaration node. + */ + function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration) { + // For binding pattern names that lack initializers there is no point to emit + // explicit initializer since downlevel codegen for destructuring will fail + // in the absence of initializer so all binding elements will say uninitialized + const name = node.name; + if (isBindingPattern(name)) { + return visitVariableDeclaration(node); + } + + if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) { + const clone = getMutableClone(node); + clone.initializer = createVoidZero(); + return clone; + } + + return visitEachChild(node, visitor, context); + } + + /** + * Visits a VariableDeclaration node with a binding pattern. + * + * @param node A VariableDeclaration node. + */ + function visitVariableDeclaration(node: VariableDeclaration): VisitResult { + // If we are here it is because the name contains a binding pattern. + Debug.assert(isBindingPattern(node.name)); + + return flattenVariableDestructuring(node, /*value*/ undefined, visitor); + } + + function visitLabeledStatement(node: LabeledStatement) { + // TODO: Convert loop body for block scoped bindings. + return visitEachChild(node, visitor, context); + } + + function visitDoStatement(node: DoStatement) { + // TODO: Convert loop body for block scoped bindings. + return visitEachChild(node, visitor, context); + } + + function visitWhileStatement(node: WhileStatement) { + // TODO: Convert loop body for block scoped bindings. + return visitEachChild(node, visitor, context); + } + + function visitForStatement(node: ForStatement) { + // TODO: Convert loop body for block scoped bindings. + return visitEachChild(node, visitor, context); + } + + function visitForInStatement(node: ForInStatement) { + // TODO: Convert loop body for block scoped bindings. + return visitEachChild(node, visitor, context); + } + + /** + * Visits a ForOfStatement and converts it into a compatible ForStatement. + * + * @param node A ForOfStatement. + */ + function visitForOfStatement(node: ForOfStatement): Statement { + // TODO: Convert loop body for block scoped bindings. + + // The following ES6 code: + // + // for (let v of expr) { } + // + // should be emitted as + // + // for (var _i = 0, _a = expr; _i < _a.length; _i++) { + // var v = _a[_i]; + // } + // + // where _a and _i are temps emitted to capture the RHS and the counter, + // respectively. + // When the left hand side is an expression instead of a let declaration, + // the "let v" is not emitted. + // When the left hand side is a let/const, the v is renamed if there is + // another v in scope. + // Note that all assignments to the LHS are emitted in the body, including + // all destructuring. + // Note also that because an extra statement is needed to assign to the LHS, + // for-of bodies are always emitted as blocks. + + const expression = visitNode(node.expression, visitor, isExpression); + const initializer = node.initializer; + const statements: Statement[] = []; + + // In the case where the user wrote an identifier as the RHS, like this: + // + // for (let v of arr) { } + // + // we don't want to emit a temporary variable for the RHS, just use it directly. + const counter = createLoopVariable(); + const rhsReference = expression.kind === SyntaxKind.Identifier + ? createUniqueName((expression).text) + : createTempVariable(); + + // Initialize LHS + // var v = _a[_i]; + if (isVariableDeclarationList(initializer)) { + const firstDeclaration = firstOrUndefined(initializer.declarations); + if (firstDeclaration && isBindingPattern(firstDeclaration.name)) { + // This works whether the declaration is a var, let, or const. + // It will use rhsIterationValue _a[_i] as the initializer. + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList( + flattenVariableDestructuring( + firstDeclaration, + createElementAccess(rhsReference, counter), + visitor + ) + ), + /*location*/ initializer + ) + ); + } + else { + // The following call does not include the initializer, so we have + // to emit it separately. + statements.push( + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + firstDeclaration ? firstDeclaration.name : createTempVariable(), + createElementAccess(rhsReference, counter) + ) + ]), + /*location*/ initializer + ) + ); + } + } + else { + // Initializer is an expression. Emit the expression in the body, so that it's + // evaluated on every iteration. + const assignment = createAssignment(initializer, createElementAccess(rhsReference, counter)); + if (isDestructuringAssignment(assignment)) { + // This is a destructuring pattern, so we flatten the destructuring instead. + statements.push( + createStatement( + flattenDestructuringAssignment( + assignment, + /*needsValue*/ false, + hoistVariableDeclaration, + visitor + ) + ) + ); + } + else { + statements.push(createStatement(assignment, /*location*/ node.initializer)); + } + } + + const statement = visitNode(node.statement, visitor, isStatement); + if (isBlock(statement)) { + addRange(statements, statement.statements); + } + else { + statements.push(statement); + } + + return createFor( + createVariableDeclarationList( + [ + createVariableDeclaration(counter, createLiteral(0), /*location*/ node.expression), + createVariableDeclaration(rhsReference, expression, /*location*/ node.expression) + ], + /*location*/ node.expression + ), + createLessThan( + counter, + createPropertyAccess(rhsReference, "length"), + /*location*/ initializer + ), + createPostfixIncrement(counter, /*location*/ initializer), + createBlock( + statements + ), + /*location*/ node + ); + } + + /** + * Visits an ObjectLiteralExpression with computed propety names. + * + * @param node An ObjectLiteralExpression node. + */ + function visitObjectLiteralExpression(node: ObjectLiteralExpression): LeftHandSideExpression { + // We are here because a ComputedPropertyName was used somewhere in the expression. + const properties = node.properties; + const numProperties = properties.length; + + // Find the first computed property. + // Everything until that point can be emitted as part of the initial object literal. + let numInitialNonComputedProperties = numProperties; + for (let i = 0, n = properties.length; i < n; i++) { + if (properties[i].name.kind === SyntaxKind.ComputedPropertyName) { + numInitialNonComputedProperties = i; + break; + } + } + + Debug.assert(numInitialNonComputedProperties !== numProperties); + + // For computed properties, we need to create a unique handle to the object + // literal so we can modify it without risking internal assignments tainting the object. + const temp = createTempVariable(); + hoistVariableDeclaration(temp); + + // Write out the first non-computed properties, then emit the rest through indexing on the temp variable. + const expressions: Expression[] = []; + addNode(expressions, + createAssignment( + temp, + createObjectLiteral( + visitNodes(properties, visitor, isObjectLiteralElement, 0, numInitialNonComputedProperties), + /*location*/ undefined, + node.multiLine + ) + ), + node.multiLine + ); + + addObjectLiteralMembers(expressions, node, temp, numInitialNonComputedProperties); + + // We need to clone the temporary identifier so that we can write it on a + // new line + addNode(expressions, getMutableClone(temp), node.multiLine); + return createParen(inlineExpressions(expressions)); + } + + /** + * Adds the members of an object literal to an array of expressions. + * + * @param expressions An array of expressions. + * @param node An ObjectLiteralExpression node. + * @param receiver The receiver for members of the ObjectLiteralExpression. + * @param numInitialNonComputedProperties The number of initial properties without + * computed property names. + */ + function addObjectLiteralMembers(expressions: Expression[], node: ObjectLiteralExpression, receiver: Identifier, numInitialNonComputedProperties: number) { + const properties = node.properties; + const numProperties = properties.length; + for (let i = numInitialNonComputedProperties; i < numProperties; i++) { + const property = properties[i]; + switch (property.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + const accessors = getAllAccessorDeclarations(node.properties, property); + if (property === accessors.firstAccessor) { + addNode(expressions, transformAccessorsToExpression(receiver, accessors), node.multiLine); + } + + break; + + case SyntaxKind.PropertyAssignment: + addNode(expressions, transformPropertyAssignmentToExpression(node, property, receiver), node.multiLine); + break; + + case SyntaxKind.ShorthandPropertyAssignment: + addNode(expressions, transformShorthandPropertyAssignmentToExpression(node, property, receiver), node.multiLine); + break; + + case SyntaxKind.MethodDeclaration: + addNode(expressions, transformObjectLiteralMethodDeclarationToExpression(node, property, receiver), node.multiLine); + break; + + default: + Debug.failBadSyntaxKind(node); + break; + } + } + } + + /** + * Transforms a PropertyAssignment node into an expression. + * + * @param node The ObjectLiteralExpression that contains the PropertyAssignment. + * @param property The PropertyAssignment node. + * @param receiver The receiver for the assignment. + */ + function transformPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: PropertyAssignment, receiver: Expression) { + return createAssignment( + createMemberAccessForPropertyName( + receiver, + visitNode(property.name, visitor, isPropertyName) + ), + visitNode(property.initializer, visitor, isExpression), + /*location*/ property + ); + } + + /** + * Transforms a ShorthandPropertyAssignment node into an expression. + * + * @param node The ObjectLiteralExpression that contains the ShorthandPropertyAssignment. + * @param property The ShorthandPropertyAssignment node. + * @param receiver The receiver for the assignment. + */ + function transformShorthandPropertyAssignmentToExpression(node: ObjectLiteralExpression, property: ShorthandPropertyAssignment, receiver: Expression) { + return createAssignment( + createMemberAccessForPropertyName( + receiver, + visitNode(property.name, visitor, isPropertyName) + ), + getSynthesizedClone(property.name), + /*location*/ property + ); + } + + /** + * Transforms a MethodDeclaration of an ObjectLiteralExpression into an expression. + * + * @param node The ObjectLiteralExpression that contains the MethodDeclaration. + * @param method The MethodDeclaration node. + * @param receiver The receiver for the assignment. + */ + function transformObjectLiteralMethodDeclarationToExpression(node: ObjectLiteralExpression, method: MethodDeclaration, receiver: Expression) { + return createAssignment( + createMemberAccessForPropertyName( + receiver, + visitNode(method.name, visitor, isPropertyName) + ), + transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined), + /*location*/ method + ); + } + + /** + * Visits a MethodDeclaration of an ObjectLiteralExpression and transforms it into a + * PropertyAssignment. + * + * @param node A MethodDeclaration node. + */ + function visitMethodDeclaration(node: MethodDeclaration): ObjectLiteralElement { + // We should only get here for methods on an object literal with regular identifier names. + // Methods on classes are handled in visitClassDeclaration/visitClassExpression. + // Methods with computed property names are handled in visitObjectLiteralExpression. + Debug.assert(!isComputedPropertyName(node.name)); + return createPropertyAssignment( + node.name, + transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined), + /*location*/ node + ); + } + + /** + * Visits a ShorthandPropertyAssignment and transforms it into a PropertyAssignment. + * + * @param node A ShorthandPropertyAssignment node. + */ + function visitShorthandPropertyAssignment(node: ShorthandPropertyAssignment): ObjectLiteralElement { + return createPropertyAssignment( + node.name, + getSynthesizedClone(node.name), + /*location*/ node + ); + } + + /** + * Visits an ArrayLiteralExpression that contains a spread element. + * + * @param node An ArrayLiteralExpression node. + */ + function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression { + // We are here because we contain a SpreadElementExpression. + return transformAndSpreadElements(node.elements, /*needsUniqueCopy*/ true, node.multiLine); + } + + /** + * Visits a CallExpression that contains either a spread element or `super`. + * + * @param node a CallExpression. + */ + function visitCallExpression(node: CallExpression): LeftHandSideExpression { + // We are here either because SuperKeyword was used somewhere in the expression, or + // because we contain a SpreadElementExpression. + + const { target, thisArg } = createCallBinding(node.expression); + if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) { + // [source] + // f(...a, b) + // x.m(...a, b) + // super(...a, b) + // super.m(...a, b) // in static + // super.m(...a, b) // in instance + // + // [output] + // f.apply(void 0, a.concat([b])) + // (_a = x).m.apply(_a, a.concat([b])) + // _super.apply(this, a.concat([b])) + // _super.m.apply(this, a.concat([b])) + // _super.prototype.m.apply(this, a.concat([b])) + + return createFunctionApply( + visitNode(target, visitor, isExpression), + visitNode(thisArg, visitor, isExpression), + transformAndSpreadElements(node.arguments, /*needsUniqueCopy*/ false, /*multiLine*/ false) + ); + } + else { + // [source] + // super(a) + // super.m(a) // in static + // super.m(a) // in instance + // + // [output] + // _super.call(this, a) + // _super.m.call(this, a) + // _super.prototype.m.call(this, a) + + return createFunctionCall( + visitNode(target, visitor, isExpression), + visitNode(thisArg, visitor, isExpression), + visitNodes(node.arguments, visitor, isExpression), + /*location*/ node + ); + } + } + + /** + * Visits a NewExpression that contains a spread element. + * + * @param node A NewExpression node. + */ + function visitNewExpression(node: NewExpression): LeftHandSideExpression { + // We are here because we contain a SpreadElementExpression. + Debug.assert((node.transformFlags & TransformFlags.ContainsSpreadElementExpression) !== 0); + + // [source] + // new C(...a) + // + // [output] + // new ((_a = C).bind.apply(_a, [void 0].concat(a)))() + + const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind")); + return createNew( + createFunctionApply( + visitNode(target, visitor, isExpression), + thisArg, + transformAndSpreadElements(createNodeArray([createVoidZero(), ...node.arguments]), /*needsUniqueCopy*/ false, /*multiLine*/ false) + ), + [] + ); + } + + /** + * Transforms an array of Expression nodes that contains a SpreadElementExpression. + * + * @param elements The array of Expression nodes. + * @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array. + * @param multiLine A value indicating whether the result should be emitted on multiple lines. + */ + function transformAndSpreadElements(elements: NodeArray, needsUniqueCopy: boolean, multiLine: boolean): Expression { + // [source] + // [a, ...b, c] + // + // [output] + // [a].concat(b, [c]) + + // Map spans of spread expressions into their expressions and spans of other + // expressions into an array literal. + const segments = flatten( + spanMap(elements, isSpreadElementExpression, (chunk: Expression[], isSpread: boolean) => isSpread + ? map(chunk, visitExpressionOfSpreadElement) + : createArrayLiteral(visitNodes(createNodeArray(chunk), visitor, isExpression), /*location*/ undefined, multiLine))); + + if (segments.length === 1) { + return needsUniqueCopy && isSpreadElementExpression(elements[0]) + ? createArraySlice(segments[0]) + : segments[0]; + } + + // Rewrite using the pattern .concat(, , ...) + return createArrayConcat(segments.shift(), segments); + } + + /** + * Transforms the expression of a SpreadElementExpression node. + * + * @param node A SpreadElementExpression node. + */ + function visitExpressionOfSpreadElement(node: SpreadElementExpression) { + return visitNode(node.expression, visitor, isExpression); + } + + /** + * Visits a template literal. + * + * @param node A template literal. + */ + function visitTemplateLiteral(node: LiteralExpression): LeftHandSideExpression { + return createLiteral(node.text, /*location*/ node); + } + + /** + * Visits a TaggedTemplateExpression node. + * + * @param node A TaggedTemplateExpression node. + */ + function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { + // Visit the tag expression + const tag = visitNode(node.tag, visitor, isExpression); + + // Allocate storage for the template site object + const temp = createTempVariable(); + hoistVariableDeclaration(temp); + + // Build up the template arguments and the raw and cooked strings for the template. + const templateArguments: Expression[] = [temp]; + const cookedStrings: Expression[] = []; + const rawStrings: Expression[] = []; + const template = node.template; + if (isNoSubstitutionTemplateLiteral(template)) { + cookedStrings.push(createLiteral(template.text)); + rawStrings.push(getRawLiteral(template)); + } + else { + cookedStrings.push(createLiteral(template.head.text)); + rawStrings.push(getRawLiteral(template.head)); + for (const templateSpan of template.templateSpans) { + cookedStrings.push(createLiteral(templateSpan.literal.text)); + rawStrings.push(getRawLiteral(templateSpan.literal)); + templateArguments.push(visitNode(templateSpan.expression, visitor, isExpression)); + } + } + + return inlineExpressions([ + createAssignment(temp, createArrayLiteral(cookedStrings)), + createAssignment(createPropertyAccess(temp, "raw"), createArrayLiteral(rawStrings)), + createCall(tag, templateArguments) + ]); + } + + /** + * Creates an ES5 compatible literal from an ES6 template literal. + * + * @param node The ES6 template literal. + */ + function getRawLiteral(node: LiteralLikeNode) { + // Find original source text, since we need to emit the raw strings of the tagged template. + // The raw strings contain the (escaped) strings of what the user wrote. + // Examples: `\n` is converted to "\\n", a template string with a newline to "\n". + let text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node); + + // text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"), + // thus we need to remove those characters. + // First template piece starts with "`", others with "}" + // Last template piece ends with "`", others with "${" + const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail; + text = text.substring(1, text.length - (isLast ? 1 : 2)); + + // Newline normalization: + // ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's + // and LineTerminatorSequences are normalized to for both TV and TRV. + text = text.replace(/\r\n?/g, "\n"); + text = escapeString(text); + return createLiteral(text, /*location*/ node); + } + + /** + * Visits a TemplateExpression node. + * + * @param node A TemplateExpression node. + */ + function visitTemplateExpression(node: TemplateExpression): Expression { + const expressions: Expression[] = []; + addTemplateHead(expressions, node); + addTemplateSpans(expressions, node); + + // createAdd will check if each expression binds less closely than binary '+'. + // If it does, it wraps the expression in parentheses. Otherwise, something like + // `abc${ 1 << 2 }` + // becomes + // "abc" + 1 << 2 + "" + // which is really + // ("abc" + 1) << (2 + "") + // rather than + // "abc" + (1 << 2) + "" + const expression = reduceLeft(expressions, createAdd); + if (nodeIsSynthesized(expression)) { + setTextRange(expression, node); + } + + return expression; + } + + /** + * Gets a value indicating whether we need to include the head of a TemplateExpression. + * + * @param node A TemplateExpression node. + */ + function shouldAddTemplateHead(node: TemplateExpression) { + // If this expression has an empty head literal and the first template span has a non-empty + // literal, then emitting the empty head literal is not necessary. + // `${ foo } and ${ bar }` + // can be emitted as + // foo + " and " + bar + // This is because it is only required that one of the first two operands in the emit + // output must be a string literal, so that the other operand and all following operands + // are forced into strings. + // + // If the first template span has an empty literal, then the head must still be emitted. + // `${ foo }${ bar }` + // must still be emitted as + // "" + foo + bar + + // There is always atleast one templateSpan in this code path, since + // NoSubstitutionTemplateLiterals are directly emitted via emitLiteral() + Debug.assert(node.templateSpans.length !== 0); + + return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0; + } + + /** + * Adds the head of a TemplateExpression to an array of expressions. + * + * @param expressions An array of expressions. + * @param node A TemplateExpression node. + */ + function addTemplateHead(expressions: Expression[], node: TemplateExpression): void { + if (!shouldAddTemplateHead(node)) { + return; + } + + expressions.push(createLiteral(node.head.text)); + } + + /** + * Visits and adds the template spans of a TemplateExpression to an array of expressions. + * + * @param expressions An array of expressions. + * @param node A TemplateExpression node. + */ + function addTemplateSpans(expressions: Expression[], node: TemplateExpression): void { + for (const span of node.templateSpans) { + expressions.push(visitNode(span.expression, visitor, isExpression)); + + // Only emit if the literal is non-empty. + // The binary '+' operator is left-associative, so the first string concatenation + // with the head will force the result up to this point to be a string. + // Emitting a '+ ""' has no semantic effect for middles and tails. + if (span.literal.text.length !== 0) { + expressions.push(createLiteral(span.literal.text)); + } + } + } + + /** + * Visits the `super` keyword + */ + function visitSuperKeyword(node: PrimaryExpression): LeftHandSideExpression { + return containingNonArrowFunction + && isClassElement(containingNonArrowFunction) + && !hasModifier(containingNonArrowFunction, ModifierFlags.Static) + ? createPropertyAccess(createIdentifier("_super"), "prototype") + : createIdentifier("_super"); + } + + function visitSourceFileNode(node: SourceFile): SourceFile { + const [prologue, remaining] = span(node.statements, isPrologueDirective); + const statements: Statement[] = []; + startLexicalEnvironment(); + addRange(statements, prologue); + addCaptureThisForNodeIfNeeded(statements, node); + addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement)); + addRange(statements, endLexicalEnvironment()); + const clone = getMutableClone(node); + clone.statements = createNodeArray(statements, /*location*/ node.statements); + return clone; + } + + /** + * Called by the printer just before a node is printed. + * + * @param node The node to be printed. + */ + function onEmitNode(node: Node, emit: (node: Node) => void) { + const savedUseCapturedThis = useCapturedThis; + + if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis && isFunctionLike(node)) { + // If we are tracking a captured `this`, push a bit that indicates whether the + // containing function is an arrow function. + useCapturedThis = (getNodeEmitFlags(node) & NodeEmitFlags.CapturesThis) !== 0; + } + + previousOnEmitNode(node, emit); + + useCapturedThis = savedUseCapturedThis; + } + + /** + * Enables a more costly code path for substitutions when we determine a source file + * contains block-scoped bindings (e.g. `let` or `const`). + */ + function enableSubstitutionsForBlockScopedBindings() { + if ((enabledSubstitutions & ES6SubstitutionFlags.BlockScopedBindings) === 0) { + enabledSubstitutions |= ES6SubstitutionFlags.BlockScopedBindings; + context.enableExpressionSubstitution(SyntaxKind.Identifier); + } + } + + /** + * Enables a more costly code path for substitutions when we determine a source file + * contains a captured `this`. + */ + function enableSubstitutionsForCapturedThis() { + if ((enabledSubstitutions & ES6SubstitutionFlags.CapturedThis) === 0) { + enabledSubstitutions |= ES6SubstitutionFlags.CapturedThis; + context.enableExpressionSubstitution(SyntaxKind.ThisKeyword); + context.enableEmitNotification(SyntaxKind.Constructor); + context.enableEmitNotification(SyntaxKind.MethodDeclaration); + context.enableEmitNotification(SyntaxKind.GetAccessor); + context.enableEmitNotification(SyntaxKind.SetAccessor); + context.enableEmitNotification(SyntaxKind.ArrowFunction); + context.enableEmitNotification(SyntaxKind.FunctionExpression); + context.enableEmitNotification(SyntaxKind.FunctionDeclaration); + } + } + + /** + * Hooks substitutions for non-expression identifiers. + */ + function substituteIdentifier(node: Identifier) { + node = previousIdentifierSubstitution(node); + + // Only substitute the identifier if we have enabled substitutions for block-scoped + // bindings. + if (enabledSubstitutions & ES6SubstitutionFlags.BlockScopedBindings) { + const original = getOriginalNode(node); + if (isIdentifier(original) && !nodeIsSynthesized(original) && original.parent && isNameOfDeclarationWithCollidingName(original)) { + return getGeneratedNameForNode(original); + } + } + + return node; + } + + /** + * Determines whether a name is the name of a declaration with a colliding name. + * NOTE: This function expects to be called with an original source tree node. + * + * @param node An original source tree node. + */ + function isNameOfDeclarationWithCollidingName(node: Identifier) { + const parent = node.parent; + switch (parent.kind) { + case SyntaxKind.BindingElement: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.VariableDeclaration: + return (parent).name === node + && resolver.isDeclarationWithCollidingName(parent); + } + + return false; + } + + /** + * Substitutes an expression. + * + * @param node An Expression node. + */ + function substituteExpression(node: Expression): Expression { + node = previousExpressionSubstitution(node); + switch (node.kind) { + case SyntaxKind.Identifier: + return substituteExpressionIdentifier(node); + + case SyntaxKind.ThisKeyword: + return substituteThisKeyword(node); + } + + return node; + } + + /** + * Substitutes an expression identifier. + * + * @param node An Identifier node. + */ + function substituteExpressionIdentifier(node: Identifier): Identifier { + if (enabledSubstitutions & ES6SubstitutionFlags.BlockScopedBindings) { + const original = getOriginalNode(node); + if (isIdentifier(original)) { + const declaration = resolver.getReferencedDeclarationWithCollidingName(original); + if (declaration) { + return getGeneratedNameForNode(declaration.name); + } + } + } + + return node; + } + + /** + * Substitutes `this` when contained within an arrow function. + * + * @param node The ThisKeyword node. + */ + function substituteThisKeyword(node: PrimaryExpression): PrimaryExpression { + if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis && useCapturedThis) { + return createIdentifier("_this", /*location*/ node); + } + + return node; + } + + function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration) { + return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node); + } + + function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) { + const expression = getDeclarationName(node); + return hasModifier(member, ModifierFlags.Static) ? expression : createPropertyAccess(expression, "prototype"); + } + + function hasSynthesizedDefaultSuperCall(constructor: ConstructorDeclaration, hasExtendsClause: boolean) { + if (!constructor || !hasExtendsClause) { + return false; + } + + const parameter = singleOrUndefined(constructor.parameters); + if (!parameter || !nodeIsSynthesized(parameter) || !parameter.dotDotDotToken) { + return false; + } + + const statement = firstOrUndefined(constructor.body.statements); + if (!statement || !nodeIsSynthesized(statement) || statement.kind !== SyntaxKind.ExpressionStatement) { + return false; + } + + const statementExpression = (statement).expression; + if (!nodeIsSynthesized(statementExpression) || statementExpression.kind !== SyntaxKind.CallExpression) { + return false; + } + + const callTarget = (statementExpression).expression; + if (!nodeIsSynthesized(callTarget) || callTarget.kind !== SyntaxKind.SuperKeyword) { + return false; + } + + const callArgument = singleOrUndefined((statementExpression).arguments); + if (!callArgument || !nodeIsSynthesized(callArgument) || callArgument.kind !== SyntaxKind.SpreadElementExpression) { + return false; + } + + const expression = (callArgument).expression; + return isIdentifier(expression) && expression === parameter.name; + } + } +} \ No newline at end of file diff --git a/src/compiler/transformers/es7.ts b/src/compiler/transformers/es7.ts new file mode 100644 index 0000000000000..d04ca55db4b31 --- /dev/null +++ b/src/compiler/transformers/es7.ts @@ -0,0 +1,100 @@ +/// +/// + +/*@internal*/ +namespace ts { + export function transformES7(context: TransformationContext) { + const { hoistVariableDeclaration } = context; + + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + return visitEachChild(node, visitor, context); + } + + function visitor(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.ES7) { + return visitorWorker(node); + } + else if (node.transformFlags & TransformFlags.ContainsES7) { + return visitEachChild(node, visitor, context); + } + else { + return node; + } + } + + function visitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.BinaryExpression: + return visitBinaryExpression(node); + + default: + Debug.failBadSyntaxKind(node); + return visitEachChild(node, visitor, context); + } + } + + function visitBinaryExpression(node: BinaryExpression): Expression { + // We are here because ES7 adds support for the exponentiation operator. + const left = visitNode(node.left, visitor, isExpression); + const right = visitNode(node.right, visitor, isExpression); + if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) { + let target: Expression; + let value: Expression; + if (isElementAccessExpression(left)) { + // Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)` + const expressionTemp = createTempVariable(); + hoistVariableDeclaration(expressionTemp); + + const argumentExpressionTemp = createTempVariable(); + hoistVariableDeclaration(argumentExpressionTemp); + + target = createElementAccess( + createAssignment(expressionTemp, left.expression, /*location*/ left.expression), + createAssignment(argumentExpressionTemp, left.argumentExpression, /*location*/ left.argumentExpression), + /*location*/ left + ); + + value = createElementAccess( + expressionTemp, + argumentExpressionTemp, + /*location*/ left + ); + } + else if (isPropertyAccessExpression(left)) { + // Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)` + const expressionTemp = createTempVariable(); + hoistVariableDeclaration(expressionTemp); + + target = createPropertyAccess( + createAssignment(expressionTemp, left.expression, /*location*/ left.expression), + left.name, + /*location*/ left + ); + + value = createPropertyAccess( + expressionTemp, + left.name, + /*location*/ left + ); + } + else { + // Transforms `a **= b` into `a = Math.pow(a, b)` + target = left; + value = left; + } + + return createAssignment(target, createMathPow(value, right, /*location*/ node), /*location*/ node); + } + else if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken) { + // Transforms `a ** b` into `Math.pow(a, b)` + return createMathPow(left, right, /*location*/ node); + } + else { + Debug.failBadSyntaxKind(node); + return visitEachChild(node, visitor, context); + } + } + } +} \ No newline at end of file diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts new file mode 100644 index 0000000000000..dc423e8da7b15 --- /dev/null +++ b/src/compiler/transformers/jsx.ts @@ -0,0 +1,490 @@ +/// +/// + +/*@internal*/ +namespace ts { + const entities: Map = createEntitiesMap(); + + export function transformJsx(context: TransformationContext) { + const compilerOptions = context.getCompilerOptions(); + return transformSourceFile; + + /** + * Transform JSX-specific syntax in a SourceFile. + * + * @param node A SourceFile node. + */ + function transformSourceFile(node: SourceFile) { + return visitEachChild(node, visitor, context); + } + + function visitor(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.Jsx) { + return visitorWorker(node); + } + else if (node.transformFlags & TransformFlags.ContainsJsx) { + return visitEachChild(node, visitor, context); + } + else { + return node; + } + } + + function visitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.JsxElement: + return visitJsxElement(node); + + case SyntaxKind.JsxSelfClosingElement: + return visitJsxSelfClosingElement(node); + + default: + Debug.failBadSyntaxKind(node); + return undefined; + } + } + + function transformJsxChildToExpression(node: JsxChild): Expression { + switch (node.kind) { + case SyntaxKind.JsxText: + return visitJsxText(node); + + case SyntaxKind.JsxExpression: + return visitJsxExpression(node); + + case SyntaxKind.JsxElement: + return visitJsxElement(node); + + case SyntaxKind.JsxSelfClosingElement: + return visitJsxSelfClosingElement(node); + + default: + Debug.failBadSyntaxKind(node); + return undefined; + } + } + + function visitJsxElement(node: JsxElement) { + return visitJsxOpeningLikeElement(node.openingElement, node.children); + } + + function visitJsxSelfClosingElement(node: JsxSelfClosingElement) { + return visitJsxOpeningLikeElement(node, /*children*/ undefined); + } + + function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: JsxChild[]) { + const tagName = getTagName(node); + let objectProperties: Expression; + const attrs = node.attributes; + if (attrs.length === 0) { + // When there are no attributes, React wants "null" + objectProperties = createNull(); + } + else { + // Map spans of JsxAttribute nodes into object literals and spans + // of JsxSpreadAttribute nodes into expressions. + const segments = flatten( + spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread + ? map(attrs, transformJsxSpreadAttributeToExpression) + : createObjectLiteral(map(attrs, transformJsxAttributeToObjectLiteralElement)) + ) + ); + + if (isJsxSpreadAttribute(attrs[0])) { + // We must always emit at least one object literal before a spread + // argument. + segments.unshift(createObjectLiteral()); + } + + // Either emit one big object literal (no spread attribs), or + // a call to React.__spread + objectProperties = singleOrUndefined(segments) + || createJsxSpread(compilerOptions.reactNamespace, segments); + } + + return createJsxCreateElement( + compilerOptions.reactNamespace, + tagName, + objectProperties, + filter(map(children, transformJsxChildToExpression), isDefined) + ); + } + + function transformJsxSpreadAttributeToExpression(node: JsxSpreadAttribute) { + return visitNode(node.expression, visitor, isExpression); + } + + function transformJsxAttributeToObjectLiteralElement(node: JsxAttribute) { + const name = getAttributeName(node); + const expression = node.initializer + ? visitNode(node.initializer, visitor, isExpression) + : createLiteral(true); + return createPropertyAssignment(name, expression); + } + + function visitJsxText(node: JsxText) { + const text = getTextOfNode(node, /*includeTrivia*/ true); + let parts: Expression[]; + let firstNonWhitespace = 0; + let lastNonWhitespace = -1; + + // JSX trims whitespace at the end and beginning of lines, except that the + // start/end of a tag is considered a start/end of a line only if that line is + // on the same line as the closing tag. See examples in + // tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx + for (let i = 0; i < text.length; i++) { + const c = text.charCodeAt(i); + if (isLineBreak(c)) { + if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) { + const part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1); + if (!parts) { + parts = []; + } + + // We do not escape the string here as that is handled by the printer + // when it emits the literal. We do, however, need to decode JSX entities. + parts.push(createLiteral(decodeEntities(part))); + } + + firstNonWhitespace = -1; + } + else if (!isWhiteSpace(c)) { + lastNonWhitespace = i; + if (firstNonWhitespace === -1) { + firstNonWhitespace = i; + } + } + } + + if (firstNonWhitespace !== -1) { + const part = text.substr(firstNonWhitespace); + if (!parts) { + parts = []; + } + + // We do not escape the string here as that is handled by the printer + // when it emits the literal. We do, however, need to decode JSX entities. + parts.push(createLiteral(decodeEntities(part))); + } + + if (parts) { + return reduceLeft(parts, aggregateJsxTextParts); + } + + return undefined; + } + + /** + * Aggregates two expressions by interpolating them with a whitespace literal. + */ + function aggregateJsxTextParts(left: Expression, right: Expression) { + return createAdd(createAdd(left, createLiteral(" ")), right); + } + + /** + * Decodes JSX entities. + */ + function decodeEntities(text: string) { + return text.replace(/&(\w+);/g, function(s: any, m: string) { + if (entities[m] !== undefined) { + return String.fromCharCode(entities[m]); + } + else { + return s; + } + }); + } + + function getTagName(node: JsxElement | JsxOpeningLikeElement): Expression { + if (node.kind === SyntaxKind.JsxElement) { + return getTagName((node).openingElement); + } + else { + const name = (node).tagName; + if (isIdentifier(name) && isIntrinsicJsxName(name.text)) { + return createLiteral(name.text); + } + else { + return createExpressionFromEntityName(name); + } + } + } + + /** + * Emit an attribute name, which is quoted if it needs to be quoted. Because + * these emit into an object literal property name, we don't need to be worried + * about keywords, just non-identifier characters + */ + function getAttributeName(node: JsxAttribute): StringLiteral | Identifier { + const name = node.name; + if (/^[A-Za-z_]\w*$/.test(name.text)) { + return createLiteral(name.text); + } + else { + return name; + } + } + + function visitJsxExpression(node: JsxExpression) { + return visitNode(node.expression, visitor, isExpression); + } + } + + function createEntitiesMap(): Map { + return { + "quot": 0x0022, + "amp": 0x0026, + "apos": 0x0027, + "lt": 0x003C, + "gt": 0x003E, + "nbsp": 0x00A0, + "iexcl": 0x00A1, + "cent": 0x00A2, + "pound": 0x00A3, + "curren": 0x00A4, + "yen": 0x00A5, + "brvbar": 0x00A6, + "sect": 0x00A7, + "uml": 0x00A8, + "copy": 0x00A9, + "ordf": 0x00AA, + "laquo": 0x00AB, + "not": 0x00AC, + "shy": 0x00AD, + "reg": 0x00AE, + "macr": 0x00AF, + "deg": 0x00B0, + "plusmn": 0x00B1, + "sup2": 0x00B2, + "sup3": 0x00B3, + "acute": 0x00B4, + "micro": 0x00B5, + "para": 0x00B6, + "middot": 0x00B7, + "cedil": 0x00B8, + "sup1": 0x00B9, + "ordm": 0x00BA, + "raquo": 0x00BB, + "frac14": 0x00BC, + "frac12": 0x00BD, + "frac34": 0x00BE, + "iquest": 0x00BF, + "Agrave": 0x00C0, + "Aacute": 0x00C1, + "Acirc": 0x00C2, + "Atilde": 0x00C3, + "Auml": 0x00C4, + "Aring": 0x00C5, + "AElig": 0x00C6, + "Ccedil": 0x00C7, + "Egrave": 0x00C8, + "Eacute": 0x00C9, + "Ecirc": 0x00CA, + "Euml": 0x00CB, + "Igrave": 0x00CC, + "Iacute": 0x00CD, + "Icirc": 0x00CE, + "Iuml": 0x00CF, + "ETH": 0x00D0, + "Ntilde": 0x00D1, + "Ograve": 0x00D2, + "Oacute": 0x00D3, + "Ocirc": 0x00D4, + "Otilde": 0x00D5, + "Ouml": 0x00D6, + "times": 0x00D7, + "Oslash": 0x00D8, + "Ugrave": 0x00D9, + "Uacute": 0x00DA, + "Ucirc": 0x00DB, + "Uuml": 0x00DC, + "Yacute": 0x00DD, + "THORN": 0x00DE, + "szlig": 0x00DF, + "agrave": 0x00E0, + "aacute": 0x00E1, + "acirc": 0x00E2, + "atilde": 0x00E3, + "auml": 0x00E4, + "aring": 0x00E5, + "aelig": 0x00E6, + "ccedil": 0x00E7, + "egrave": 0x00E8, + "eacute": 0x00E9, + "ecirc": 0x00EA, + "euml": 0x00EB, + "igrave": 0x00EC, + "iacute": 0x00ED, + "icirc": 0x00EE, + "iuml": 0x00EF, + "eth": 0x00F0, + "ntilde": 0x00F1, + "ograve": 0x00F2, + "oacute": 0x00F3, + "ocirc": 0x00F4, + "otilde": 0x00F5, + "ouml": 0x00F6, + "divide": 0x00F7, + "oslash": 0x00F8, + "ugrave": 0x00F9, + "uacute": 0x00FA, + "ucirc": 0x00FB, + "uuml": 0x00FC, + "yacute": 0x00FD, + "thorn": 0x00FE, + "yuml": 0x00FF, + "OElig": 0x0152, + "oelig": 0x0153, + "Scaron": 0x0160, + "scaron": 0x0161, + "Yuml": 0x0178, + "fnof": 0x0192, + "circ": 0x02C6, + "tilde": 0x02DC, + "Alpha": 0x0391, + "Beta": 0x0392, + "Gamma": 0x0393, + "Delta": 0x0394, + "Epsilon": 0x0395, + "Zeta": 0x0396, + "Eta": 0x0397, + "Theta": 0x0398, + "Iota": 0x0399, + "Kappa": 0x039A, + "Lambda": 0x039B, + "Mu": 0x039C, + "Nu": 0x039D, + "Xi": 0x039E, + "Omicron": 0x039F, + "Pi": 0x03A0, + "Rho": 0x03A1, + "Sigma": 0x03A3, + "Tau": 0x03A4, + "Upsilon": 0x03A5, + "Phi": 0x03A6, + "Chi": 0x03A7, + "Psi": 0x03A8, + "Omega": 0x03A9, + "alpha": 0x03B1, + "beta": 0x03B2, + "gamma": 0x03B3, + "delta": 0x03B4, + "epsilon": 0x03B5, + "zeta": 0x03B6, + "eta": 0x03B7, + "theta": 0x03B8, + "iota": 0x03B9, + "kappa": 0x03BA, + "lambda": 0x03BB, + "mu": 0x03BC, + "nu": 0x03BD, + "xi": 0x03BE, + "omicron": 0x03BF, + "pi": 0x03C0, + "rho": 0x03C1, + "sigmaf": 0x03C2, + "sigma": 0x03C3, + "tau": 0x03C4, + "upsilon": 0x03C5, + "phi": 0x03C6, + "chi": 0x03C7, + "psi": 0x03C8, + "omega": 0x03C9, + "thetasym": 0x03D1, + "upsih": 0x03D2, + "piv": 0x03D6, + "ensp": 0x2002, + "emsp": 0x2003, + "thinsp": 0x2009, + "zwnj": 0x200C, + "zwj": 0x200D, + "lrm": 0x200E, + "rlm": 0x200F, + "ndash": 0x2013, + "mdash": 0x2014, + "lsquo": 0x2018, + "rsquo": 0x2019, + "sbquo": 0x201A, + "ldquo": 0x201C, + "rdquo": 0x201D, + "bdquo": 0x201E, + "dagger": 0x2020, + "Dagger": 0x2021, + "bull": 0x2022, + "hellip": 0x2026, + "permil": 0x2030, + "prime": 0x2032, + "Prime": 0x2033, + "lsaquo": 0x2039, + "rsaquo": 0x203A, + "oline": 0x203E, + "frasl": 0x2044, + "euro": 0x20AC, + "image": 0x2111, + "weierp": 0x2118, + "real": 0x211C, + "trade": 0x2122, + "alefsym": 0x2135, + "larr": 0x2190, + "uarr": 0x2191, + "rarr": 0x2192, + "darr": 0x2193, + "harr": 0x2194, + "crarr": 0x21B5, + "lArr": 0x21D0, + "uArr": 0x21D1, + "rArr": 0x21D2, + "dArr": 0x21D3, + "hArr": 0x21D4, + "forall": 0x2200, + "part": 0x2202, + "exist": 0x2203, + "empty": 0x2205, + "nabla": 0x2207, + "isin": 0x2208, + "notin": 0x2209, + "ni": 0x220B, + "prod": 0x220F, + "sum": 0x2211, + "minus": 0x2212, + "lowast": 0x2217, + "radic": 0x221A, + "prop": 0x221D, + "infin": 0x221E, + "ang": 0x2220, + "and": 0x2227, + "or": 0x2228, + "cap": 0x2229, + "cup": 0x222A, + "int": 0x222B, + "there4": 0x2234, + "sim": 0x223C, + "cong": 0x2245, + "asymp": 0x2248, + "ne": 0x2260, + "equiv": 0x2261, + "le": 0x2264, + "ge": 0x2265, + "sub": 0x2282, + "sup": 0x2283, + "nsub": 0x2284, + "sube": 0x2286, + "supe": 0x2287, + "oplus": 0x2295, + "otimes": 0x2297, + "perp": 0x22A5, + "sdot": 0x22C5, + "lceil": 0x2308, + "rceil": 0x2309, + "lfloor": 0x230A, + "rfloor": 0x230B, + "lang": 0x2329, + "rang": 0x232A, + "loz": 0x25CA, + "spades": 0x2660, + "clubs": 0x2663, + "hearts": 0x2665, + "diams": 0x2666 + }; + } +} \ No newline at end of file diff --git a/src/compiler/transformers/module/es6.ts b/src/compiler/transformers/module/es6.ts new file mode 100644 index 0000000000000..63b147b6e602d --- /dev/null +++ b/src/compiler/transformers/module/es6.ts @@ -0,0 +1,13 @@ +/// +/// + +/*@internal*/ +namespace ts { + export function transformES6Module(context: TransformationContext) { + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + return node; + } + } +} \ No newline at end of file diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts new file mode 100644 index 0000000000000..d6a89c4ed77c5 --- /dev/null +++ b/src/compiler/transformers/module/module.ts @@ -0,0 +1,759 @@ +/// +/// + +/*@internal*/ +namespace ts { + export function transformModule(context: TransformationContext) { + const transformModuleDelegates: Map<(node: SourceFile) => SourceFile> = { + [ModuleKind.None]: transformCommonJSModule, + [ModuleKind.CommonJS]: transformCommonJSModule, + [ModuleKind.AMD]: transformAMDModule, + [ModuleKind.UMD]: transformUMDModule, + }; + + const { + startLexicalEnvironment, + endLexicalEnvironment, + hoistVariableDeclaration, + setNodeEmitFlags + } = context; + + const compilerOptions = context.getCompilerOptions(); + const resolver = context.getEmitResolver(); + const languageVersion = getEmitScriptTarget(compilerOptions); + const moduleKind = getEmitModuleKind(compilerOptions); + const previousExpressionSubstitution = context.expressionSubstitution; + context.enableExpressionSubstitution(SyntaxKind.Identifier); + context.expressionSubstitution = substituteExpression; + + let currentSourceFile: SourceFile; + let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; + let exportSpecifiers: Map; + let exportEquals: ExportAssignment; + let hasExportStars: boolean; + + return transformSourceFile; + + /** + * Transforms the module aspects of a SourceFile. + * + * @param node The SourceFile node. + */ + function transformSourceFile(node: SourceFile) { + if (isExternalModule(node) || compilerOptions.isolatedModules) { + currentSourceFile = node; + + // Collect information about the external module. + ({ externalImports, exportSpecifiers, exportEquals, hasExportStars } = collectExternalModuleInfo(node, resolver)); + + // Perform the transformation. + const updated = transformModuleDelegates[moduleKind](node); + + currentSourceFile = undefined; + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + return updated; + } + + return node; + } + + /** + * Transforms a SourceFile into a CommonJS module. + * + * @param node The SourceFile node. + */ + function transformCommonJSModule(node: SourceFile) { + startLexicalEnvironment(); + return setNodeEmitFlags( + updateSourceFile( + node, + [ + ...visitNodes(node.statements, visitor, isStatement), + ...(endLexicalEnvironment() || []), + tryCreateExportEquals(/*emitAsReturn*/ false) + ] + ), + hasExportStars ? NodeEmitFlags.EmitExportStar : 0 + ); + } + + /** + * Transforms a SourceFile into an AMD module. + * + * @param node The SourceFile node. + */ + function transformAMDModule(node: SourceFile) { + const define = createIdentifier("define"); + const moduleName = node.moduleName ? createLiteral(node.moduleName) : undefined; + return transformAsynchronousModule(node, define, moduleName, /*includeNonAmdDependencies*/ true); + } + + /** + * Transforms a SourceFile into a UMD module. + * + * @param node The SourceFile node. + */ + function transformUMDModule(node: SourceFile) { + const define = createIdentifier("define"); + setNodeEmitFlags(define, NodeEmitFlags.UMDDefine); + return transformAsynchronousModule(node, define, /*moduleName*/ undefined, /*includeNonAmdDependencies*/ false); + } + + /** + * Transforms a SourceFile into an AMD or UMD module. + * + * @param node The SourceFile node. + * @param define The expression used to define the module. + * @param moduleName An expression for the module name, if available. + * @param includeNonAmdDependencies A value indicating whether to incldue any non-AMD dependencies. + */ + function transformAsynchronousModule(node: SourceFile, define: Expression, moduleName: Expression, includeNonAmdDependencies: boolean) { + // Start the lexical environment for the module body. + startLexicalEnvironment(); + + const { importModuleNames, importAliasNames } = collectAsynchronousDependencies(node, includeNonAmdDependencies); + + // Create an updated SourceFile: + // + // define(moduleName?, ["module1", "module2"], function ... + return updateSourceFile(node, [ + createStatement( + createCall( + define, + flatten([ + // Add the module name (if provided). + moduleName, + + // Add the dependency array argument: + // + // ["module1", "module2", ...] + createArrayLiteral(importModuleNames), + + // Add the module body function argument: + // + // function (module1, module2) ... + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + importAliasNames, + setNodeEmitFlags( + setMultiLine( + createBlock( + flatten([ + // Visit each statement of the module body. + ...visitNodes(node.statements, visitor, isStatement), + + // End the lexical environment for the module body + // and merge any new lexical declarations. + ...(endLexicalEnvironment() || []), + + // Append the 'export =' statement if provided. + tryCreateExportEquals(/*emitAsReturn*/ true) + ]) + ), + /*multiLine*/ true + ), + + // If we have any `export * from ...` declarations + // we need to inform the emitter to add the __export helper. + hasExportStars ? NodeEmitFlags.EmitExportStar : 0 + ) + ) + ]) + ) + ) + ]); + } + + function tryCreateExportEquals(emitAsReturn: boolean) { + if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) { + if (emitAsReturn) { + return createReturn(exportEquals.expression); + } + else { + return createStatement( + createAssignment( + createPropertyAccess( + createIdentifier("module"), + "exports" + ), + exportEquals.expression + ) + ); + } + } + return undefined; + } + + /** + * Visits a node at the top level of the source file. + * + * @param node The node. + */ + function visitor(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + return visitImportDeclaration(node); + + case SyntaxKind.ImportEqualsDeclaration: + return visitImportEqualsDeclaration(node); + + case SyntaxKind.ExportDeclaration: + return visitExportDeclaration(node); + + case SyntaxKind.ExportAssignment: + return visitExportAssignment(node); + + case SyntaxKind.VariableStatement: + return visitVariableStatement(node); + + case SyntaxKind.FunctionDeclaration: + return visitFunctionDeclaration(node); + + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node); + + default: + // This visitor does not descend into the tree, as export/import statements + // are only transformed at the top level of a file. + return node; + } + } + + /** + * Visits an ImportDeclaration node. + * + * @param node The ImportDeclaration node. + */ + function visitImportDeclaration(node: ImportDeclaration): VisitResult { + if (!contains(externalImports, node)) { + return undefined; + } + + const statements: Statement[] = []; + const namespaceDeclaration = getNamespaceDeclarationNode(node); + if (moduleKind !== ModuleKind.AMD) { + if (!node.importClause) { + // import "mod"; + addNode(statements, + createStatement( + createRequireCall(node), + /*location*/ node + ) + ); + } + else { + const variables: VariableDeclaration[] = []; + if (namespaceDeclaration && !isDefaultImport(node)) { + // import * as n from "mod"; + addNode(variables, + createVariableDeclaration( + getSynthesizedClone(namespaceDeclaration.name), + createRequireCall(node) + ) + ); + } + else { + // import d from "mod"; + // import { x, y } from "mod"; + // import d, { x, y } from "mod"; + // import d, * as n from "mod"; + addNode(variables, + createVariableDeclaration( + getGeneratedNameForNode(node), + createRequireCall(node) + ) + ); + + if (namespaceDeclaration && isDefaultImport(node)) { + addNode(variables, + createVariableDeclaration( + getSynthesizedClone(namespaceDeclaration.name), + getGeneratedNameForNode(node) + ) + ); + } + } + + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList(variables), + /*location*/ node + ) + ); + } + } + else if (namespaceDeclaration && isDefaultImport(node)) { + // import d, * as n from "mod"; + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + getSynthesizedClone(namespaceDeclaration.name), + getGeneratedNameForNode(node), + /*location*/ node + ) + ]) + ) + ); + } + + addExportImportAssignments(statements, node); + return statements; + } + + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + if (!contains(externalImports, node)) { + return undefined; + } + + const statements: Statement[] = []; + if (moduleKind !== ModuleKind.AMD) { + if (hasModifier(node, ModifierFlags.Export)) { + addNode(statements, + createStatement( + createExportAssignment( + node.name, + createRequireCall(node) + ), + /*location*/ node + ) + ); + } + else { + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + getSynthesizedClone(node.name), + createRequireCall(node), + /*location*/ node + ) + ]) + ) + ); + } + } + else { + if (hasModifier(node, ModifierFlags.Export)) { + addNode(statements, + createStatement( + createExportAssignment(node.name, node.name), + /*location*/ node + ) + ); + } + } + + addExportImportAssignments(statements, node); + return statements; + } + + function visitExportDeclaration(node: ExportDeclaration): VisitResult { + if (!contains(externalImports, node)) { + return undefined; + } + + const generatedName = getGeneratedNameForNode(node); + if (node.exportClause) { + const statements: Statement[] = []; + // export { x, y } from "mod"; + if (moduleKind !== ModuleKind.AMD) { + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + generatedName, + createRequireCall(node), + /*location*/ node + ) + ]) + ) + ); + } + for (const specifier of node.exportClause.elements) { + if (resolver.isValueAliasDeclaration(specifier)) { + const exportedValue = createPropertyAccess( + generatedName, + specifier.propertyName || specifier.name + ); + addNode(statements, + createStatement( + createExportAssignment(specifier.name, exportedValue), + /*location*/ specifier + ) + ); + } + } + + return statements; + } + else { + // export * from "mod"; + return createStatement( + createCall( + createIdentifier("__export"), + [ + moduleKind !== ModuleKind.AMD + ? createRequireCall(node) + : generatedName + ] + ), + /*location*/ node + ); + } + } + + function visitExportAssignment(node: ExportAssignment): VisitResult { + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { + const statements: Statement[] = []; + addExportDefault(statements, node.expression, /*location*/ node); + return statements; + } + + return undefined; + } + + function addExportDefault(statements: Statement[], expression: Expression, location: TextRange): void { + addNode(statements, tryCreateExportDefaultCompat()); + addNode(statements, + createStatement( + createExportAssignment( + createIdentifier("default"), + expression + ), + location + ) + ); + } + + function tryCreateExportDefaultCompat(): Statement { + const original = getOriginalNode(currentSourceFile); + Debug.assert(original.kind === SyntaxKind.SourceFile); + + if (!(original).symbol.exports["___esModule"]) { + if (languageVersion === ScriptTarget.ES3) { + return createStatement( + createExportAssignment( + createIdentifier("__esModule"), + createLiteral(true) + ) + ); + } + else { + return createStatement( + createObjectDefineProperty( + createIdentifier("exports"), + createLiteral("_esModule"), + { value: createLiteral(true) } + ) + ); + } + } + } + + function addExportImportAssignments(statements: Statement[], node: Node) { + const names = reduceEachChild(node, collectExportMembers, []); + for (const name of names) { + addExportMemberAssignments(statements, name); + } + } + + function collectExportMembers(names: Identifier[], node: Node): Identifier[] { + if (isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node) && isDeclaration(node)) { + const name = node.name; + if (isIdentifier(name)) { + names.push(name); + } + } + + return reduceEachChild(node, collectExportMembers, names); + } + + function addExportMemberAssignments(statements: Statement[], name: Identifier): void { + if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) { + for (const specifier of exportSpecifiers[name.text]) { + addNode(statements, + createStatement( + createExportAssignment(specifier.name, name), + /*location*/ specifier.name + ) + ); + } + } + } + + function visitVariableStatement(node: VariableStatement): VisitResult { + const variables = getInitializedVariables(node.declarationList); + if (variables.length === 0) { + // elide statement if there are no initialized variables + return undefined; + } + + return createStatement( + inlineExpressions( + map(variables, transformInitializedVariable) + ) + ); + } + + function transformInitializedVariable(node: VariableDeclaration): Expression { + const name = node.name; + if (isBindingPattern(name)) { + return flattenVariableDestructuringToExpression( + node, + hoistVariableDeclaration, + getModuleMemberName, + visitor + ); + } + else { + return createAssignment( + getModuleMemberName(name), + visitNode(node.initializer, visitor, isExpression) + ); + } + } + + function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { + const statements: Statement[] = []; + if (node.name) { + if (hasModifier(node, ModifierFlags.Export)) { + addNode(statements, + createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + node.name, + node.parameters, + node.body, + /*location*/ node + ) + ); + + if (hasModifier(node, ModifierFlags.Default)) { + addExportDefault(statements, getSynthesizedClone(node.name), /*location*/ node); + } + } + else { + addNode(statements, node); + } + + addExportMemberAssignments(statements, node.name); + } + else { + Debug.assert(hasModifier(node, ModifierFlags.Default)); + addExportDefault(statements, + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + node.parameters, + node.body, + /*location*/ node + ), + /*location*/ node + ); + } + return statements; + } + + function visitClassDeclaration(node: ClassDeclaration): VisitResult { + const statements: Statement[] = []; + if (node.name) { + if (hasModifier(node, ModifierFlags.Export)) { + addNode(statements, + createClassDeclaration( + /*modifiers*/ undefined, + node.name, + node.heritageClauses, + node.members, + /*location*/ node + ) + ); + + if (hasModifier(node, ModifierFlags.Default)) { + addExportDefault(statements, getSynthesizedClone(node.name), /*location*/ node); + } + } + else { + addNode(statements, node); + } + + addExportMemberAssignments(statements, node.name); + } + else { + Debug.assert(hasModifier(node, ModifierFlags.Default)); + addExportDefault(statements, + createClassExpression( + /*name*/ undefined, + node.heritageClauses, + node.members, + /*location*/ node + ), + /*location*/ node + ); + } + + return statements; + } + + function substituteExpression(node: Expression) { + node = previousExpressionSubstitution(node); + if (isIdentifier(node)) { + return substituteExpressionIdentifier(node); + } + + return node; + } + + function substituteExpressionIdentifier(node: Identifier): Expression { + const container = resolver.getReferencedExportContainer(node); + if (container && container.kind === SyntaxKind.SourceFile) { + return createPropertyAccess( + createIdentifier("exports"), + getSynthesizedClone(node), + /*location*/ node + ); + } + + return node; + } + + function getModuleMemberName(name: Identifier) { + return createPropertyAccess( + createIdentifier("exports"), + name, + /*location*/ name + ); + } + + function getExternalModuleNameLiteral(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) { + const moduleName = getExternalModuleName(importNode); + if (moduleName.kind === SyntaxKind.StringLiteral) { + return tryRenameExternalModule(moduleName) + || getSynthesizedClone(moduleName); + } + + return undefined; + } + + /** + * Some bundlers (SystemJS builder) sometimes want to rename dependencies. + * Here we check if alternative name was provided for a given moduleName and return it if possible. + */ + function tryRenameExternalModule(moduleName: LiteralExpression) { + if (currentSourceFile.renamedDependencies && hasProperty(currentSourceFile.renamedDependencies, moduleName.text)) { + return createLiteral(currentSourceFile.renamedDependencies[moduleName.text]); + } + return undefined; + } + + function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): Identifier { + const namespaceDeclaration = getNamespaceDeclarationNode(node); + if (namespaceDeclaration && !isDefaultImport(node)) { + return createIdentifier(getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name)); + } + if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { + return getGeneratedNameForNode(node); + } + if (node.kind === SyntaxKind.ExportDeclaration && (node).moduleSpecifier) { + return getGeneratedNameForNode(node); + } + } + + function createRequireCall(importNode: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + const moduleName = getExternalModuleNameLiteral(importNode); + Debug.assert(isDefined(moduleName)); + return createCall( + createIdentifier("require"), + [moduleName] + ); + } + + function createExportAssignment(name: Identifier, value: Expression) { + return createAssignment( + name.originalKeywordKind && languageVersion === ScriptTarget.ES3 + ? createElementAccess( + createIdentifier("exports"), + createLiteral(name.text) + ) + : createPropertyAccess( + createIdentifier("exports"), + getSynthesizedClone(name) + ), + value + ); + } + + function collectAsynchronousDependencies(node: SourceFile, includeNonAmdDependencies: boolean) { + // An AMD define function has the following shape: + // + // define(id?, dependencies?, factory); + // + // This has the shape of the following: + // + // define(name, ["module1", "module2"], function (module1Alias) { ... } + // + // The location of the alias in the parameter list in the factory function needs to + // match the position of the module name in the dependency list. + // + // To ensure this is true in cases of modules with no aliases, e.g.: + // + // import "module" + // + // or + // + // /// + // + // we need to add modules without alias names to the end of the dependencies list + + const unaliasedModuleNames: Expression[] = []; + const aliasedModuleNames: Expression[] = [createLiteral("require"), createLiteral("exports") ]; + const importAliasNames = [createParameter("require"), createParameter("exports")]; + + for (const amdDependency of node.amdDependencies) { + if (amdDependency.name) { + aliasedModuleNames.push(createLiteral(amdDependency.name)); + importAliasNames.push(createParameter(createIdentifier(amdDependency.name))); + } + else { + unaliasedModuleNames.push(createLiteral(amdDependency.path)); + } + } + + for (const importNode of externalImports) { + // Find the name of the external module + const externalModuleName = getExternalModuleNameLiteral(importNode); + // Find the name of the module alias, if there is one + const importAliasName = getLocalNameForExternalImport(importNode); + if (includeNonAmdDependencies && importAliasName) { + aliasedModuleNames.push(externalModuleName); + importAliasNames.push(createParameter(importAliasName)); + } + else { + unaliasedModuleNames.push(externalModuleName); + } + } + + return { + importModuleNames: [ + ...unaliasedModuleNames, + ...aliasedModuleNames + ], + importAliasNames + }; + } + + function updateSourceFile(node: SourceFile, statements: Statement[]) { + const updated = getMutableClone(node); + updated.statements = createNodeArray(statements, node.statements); + return updated; + } + } +} diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts new file mode 100644 index 0000000000000..aab231dd2f414 --- /dev/null +++ b/src/compiler/transformers/module/system.ts @@ -0,0 +1,1279 @@ +/// +/// + +/*@internal*/ +namespace ts { + export function transformSystemModule(context: TransformationContext) { + interface DependencyGroup { + name: Identifier; + externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; + } + + const { + startLexicalEnvironment, + endLexicalEnvironment, + hoistVariableDeclaration, + hoistFunctionDeclaration, + setNodeEmitFlags + } = context; + + const compilerOptions = context.getCompilerOptions(); + const resolver = context.getEmitResolver(); + const languageVersion = getEmitScriptTarget(compilerOptions); + const previousExpressionSubstitution = context.expressionSubstitution; + context.enableExpressionSubstitution(SyntaxKind.Identifier); + context.enableExpressionSubstitution(SyntaxKind.BinaryExpression); + context.enableExpressionSubstitution(SyntaxKind.PostfixUnaryExpression); + context.expressionSubstitution = substituteExpression; + + let currentSourceFile: SourceFile; + let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; + let exportSpecifiers: Map; + let exportEquals: ExportAssignment; + let hasExportStars: boolean; + let exportFunctionForFile: Identifier; + let contextObjectForFile: Identifier; + let exportedLocalNames: Identifier[]; + let exportedFunctionDeclarations: ExpressionStatement[]; + + return transformSourceFile; + + function transformSourceFile(node: SourceFile) { + if (isExternalModule(node) || compilerOptions.isolatedModules) { + currentSourceFile = node; + + // Perform the transformation. + const updated = transformSystemModuleWorker(node); + + currentSourceFile = undefined; + externalImports = undefined; + exportSpecifiers = undefined; + exportEquals = undefined; + hasExportStars = false; + exportFunctionForFile = undefined; + contextObjectForFile = undefined; + exportedLocalNames = undefined; + exportedFunctionDeclarations = undefined; + return updated; + } + + return node; + } + + function transformSystemModuleWorker(node: SourceFile) { + // System modules have the following shape: + // + // System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */}) + // + // The parameter 'exports' here is a callback '(name: string, value: T) => T' that + // is used to publish exported values. 'exports' returns its 'value' argument so in + // most cases expressions that mutate exported values can be rewritten as: + // + // expr -> exports('name', expr) + // + // The only exception in this rule is postfix unary operators, + // see comment to 'substitutePostfixUnaryExpression' for more details + Debug.assert(!exportFunctionForFile); + + // Collect information about the external module and dependency groups. + ({ externalImports, exportSpecifiers, exportEquals, hasExportStars } = collectExternalModuleInfo(node, resolver)); + + // Make sure that the name of the 'exports' function does not conflict with + // existing identifiers. + exportFunctionForFile = createUniqueName("exports"); + contextObjectForFile = createUniqueName("context"); + + const dependencyGroups = collectDependencyGroups(externalImports); + + const statements: Statement[] = []; + + // Add any prologue directives. + const statementOffset = copyPrologueDirectives(node.statements, statements); + + // var __moduleName = context_1 && context_1.id; + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + "__moduleName", + createLogicalAnd( + contextObjectForFile, + createPropertyAccess(contextObjectForFile, "id") + ) + ) + ]) + ) + ); + + // Add the body of the module. + addSystemModuleBody(statements, node, dependencyGroups, statementOffset); + + // Write the call to `System.register` + return updateSourceFile(node, [ + createStatement( + createCall( + createPropertyAccess(createIdentifier("System"), "register"), + [ + node.moduleName ? createLiteral(node.moduleName) : undefined, + createArrayLiteral(map(dependencyGroups, getNameOfDependencyGroup)), + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + [ + createParameter(exportFunctionForFile), + createParameter(contextObjectForFile) + ], + setNodeEmitFlags( + setMultiLine( + createBlock(statements), + /*multiLine*/ true + ), + NodeEmitFlags.EmitEmitHelpers + ) + ) + ] + ) + ) + ]); + } + + /** + * Adds the statements for the module body function for the source file. + * + * @param statements The output statements for the module body. + * @param node The source file for the module. + * @param statementOffset The offset at which to begin visiting the statements of the SourceFile. + */ + function addSystemModuleBody(statements: Statement[], node: SourceFile, dependencyGroups: DependencyGroup[], statementOffset: number) { + // Shape of the body in system modules: + // + // function (exports) { + // + // + // + // return { + // setters: [ + // + // ], + // execute: function() { + // + // } + // } + // + // } + // + // i.e: + // + // import {x} from 'file1' + // var y = 1; + // export function foo() { return y + x(); } + // console.log(y); + // + // Will be transformed to: + // + // function(exports) { + // var file_1; // local alias + // var y; + // function foo() { return y + file_1.x(); } + // exports("foo", foo); + // return { + // setters: [ + // function(v) { file_1 = v } + // ], + // execute(): function() { + // y = 1; + // console.log(y); + // } + // }; + // } + + // We start a new lexical environment in this function body, but *not* in the + // body of the execute function. This allows us to emit temporary declarations + // only in the outer module body and not in the inner one. + startLexicalEnvironment(); + + // Visit the statements of the source file, emitting any transformations into + // the `executeStatements` array. We do this *before* we fill the `setters` array + // as we both emit transformations as well as aggregate some data used when creating + // setters. This allows us to reduce the number of times we need to loop through the + // statements of the source file. + const executeStatements = visitNodes(node.statements, visitSourceElement, isStatement, statementOffset); + + // We emit the lexical environment (hoisted variables and function declarations) + // early to align roughly with our previous emit output. + // Two key differences in this approach are: + // - Temporary variables will appear at the top rather than at the bottom of the file + // - Calls to the exporter for exported function declarations are grouped after + // the declarations. + addNodes(statements, endLexicalEnvironment()); + + // Emit early exports for function declarations. + addNodes(statements, exportedFunctionDeclarations); + + const exportStarFunction = addExportStarIfNeeded(statements); + + addNode(statements, + createReturn( + setMultiLine( + createObjectLiteral([ + createPropertyAssignment("setters", + generateSetters(exportStarFunction, dependencyGroups) + ), + createPropertyAssignment("execute", + createFunctionExpression( + /*asteriskToken*/ node, + /*name*/ undefined, + [], + createBlock( + executeStatements + ) + ) + ) + ]), + /*multiLine*/ true + ) + ) + ); + } + + function addExportStarIfNeeded(statements: Statement[]) { + // when resolving exports local exported entries/indirect exported entries in the module + // should always win over entries with similar names that were added via star exports + // to support this we store names of local/indirect exported entries in a set. + // this set is used to filter names brought by star expors. + + // local names set should only be added if we have anything exported + if (!exportedLocalNames && isEmpty(exportSpecifiers)) { + // no exported declarations (export var ...) or export specifiers (export {x}) + // check if we have any non star export declarations. + let hasExportDeclarationWithExportClause = false; + for (const externalImport of externalImports) { + if (externalImport.kind === SyntaxKind.ExportDeclaration && (externalImport).exportClause) { + hasExportDeclarationWithExportClause = true; + break; + } + } + + if (!hasExportDeclarationWithExportClause) { + // we still need to emit exportStar helper + return addExportStarFunction(statements, /*localNames*/ undefined); + } + } + + const exportedNames: ObjectLiteralElement[] = []; + if (exportedLocalNames) { + for (const exportedLocalName of exportedLocalNames) { + // write name of exported declaration, i.e 'export var x...' + addNode(exportedNames, + createPropertyAssignment( + createLiteral(exportedLocalName.text), + createLiteral(true) + ) + ); + } + } + + for (const externalImport of externalImports) { + if (externalImport.kind !== SyntaxKind.ExportDeclaration) { + continue; + } + + const exportDecl = externalImport; + if (!exportDecl.exportClause) { + // export * from ... + continue; + } + + for (const element of exportDecl.exportClause.elements) { + // write name of indirectly exported entry, i.e. 'export {x} from ...' + addNode(exportedNames, + createPropertyAssignment( + createLiteral((element.name || element.propertyName).text), + createLiteral(true) + ) + ); + } + } + + const exportedNamesStorageRef = createUniqueName("exportedNames"); + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + exportedNamesStorageRef, + createObjectLiteral(exportedNames) + ) + ]) + ) + ); + + return addExportStarFunction(statements, exportedNamesStorageRef); + } + + /** + * Emits a setter callback for each dependency group. + * @param write The callback used to write each callback. + */ + function generateSetters(exportStarFunction: Identifier, dependencyGroups: DependencyGroup[]) { + const setters: Expression[] = []; + for (const group of dependencyGroups) { + // derive a unique name for parameter from the first named entry in the group + const parameterName = createUniqueName(forEach(group.externalImports, getLocalNameTextForExternalImport) || ""); + const statements: Statement[] = []; + for (const entry of group.externalImports) { + const importVariableName = getLocalNameForExternalImport(entry); + switch (entry.kind) { + case SyntaxKind.ImportDeclaration: + if (!(entry).importClause) { + // 'import "..."' case + // module is imported only for side-effects, no emit required + break; + } + + // fall-through + case SyntaxKind.ImportEqualsDeclaration: + Debug.assert(importVariableName !== undefined); + // save import into the local + addNode(statements, + createStatement( + createAssignment(importVariableName, parameterName) + ) + ); + break; + + case SyntaxKind.ExportDeclaration: + Debug.assert(importVariableName !== undefined); + if ((entry).exportClause) { + // export {a, b as c} from 'foo' + // + // emit as: + // + // exports_({ + // "a": _["a"], + // "c": _["b"] + // }); + const properties: PropertyAssignment[] = []; + for (const e of (entry).exportClause.elements) { + properties.push( + createPropertyAssignment( + createLiteral(e.name.text), + createElementAccess( + parameterName, + createLiteral((e.propertyName || e.name).text) + ) + ) + ); + } + + addNode(statements, + createStatement( + createCall( + exportFunctionForFile, + [createObjectLiteral(properties)] + ) + ) + ); + } + else { + // export * from 'foo' + // + // emit as: + // + // exportStar(foo_1_1); + addNode(statements, + createStatement( + createCall( + exportStarFunction, + [parameterName] + ) + ) + ); + } + break; + } + } + + addNode(setters, + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + [createParameter(parameterName)], + createBlock(statements) + ) + ); + } + + return createArrayLiteral(setters); + } + + function visitSourceElement(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + return visitImportDeclaration(node); + + case SyntaxKind.ImportEqualsDeclaration: + return visitImportEqualsDeclaration(node); + + case SyntaxKind.ExportDeclaration: + return visitExportDeclaration(node); + + case SyntaxKind.ExportAssignment: + return visitExportAssignment(node); + + default: + return visitNestedNode(node); + } + } + + function visitNestedNode(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.VariableStatement: + return visitVariableStatement(node); + + case SyntaxKind.FunctionDeclaration: + return visitFunctionDeclaration(node); + + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(node); + + case SyntaxKind.ForStatement: + return visitForStatement(node); + + case SyntaxKind.ForInStatement: + return visitForInStatement(node); + + case SyntaxKind.ForOfStatement: + return visitForOfStatement(node); + + case SyntaxKind.DoStatement: + return visitDoStatement(node); + + case SyntaxKind.WhileStatement: + return visitWhileStatement(node); + + case SyntaxKind.LabeledStatement: + return visitLabeledStatement(node); + + case SyntaxKind.WithStatement: + return visitWithStatement(node); + + case SyntaxKind.SwitchStatement: + return visitSwitchStatement(node); + + case SyntaxKind.CaseBlock: + return visitCaseBlock(node); + + case SyntaxKind.CaseClause: + return visitCaseClause(node); + + case SyntaxKind.DefaultClause: + return visitDefaultClause(node); + + case SyntaxKind.TryStatement: + return visitTryStatement(node); + + case SyntaxKind.CatchClause: + return visitCatchClause(node); + + case SyntaxKind.Block: + return visitBlock(node); + + default: + return node; + } + } + + function visitImportDeclaration(node: ImportDeclaration): Node { + if (node.importClause && contains(externalImports, node)) { + hoistVariableDeclaration(getLocalNameForExternalImport(node)); + } + + return undefined; + } + + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): Node { + if (contains(externalImports, node)) { + hoistVariableDeclaration(getLocalNameForExternalImport(node)); + } + + // NOTE(rbuckton): Do we support export import = require('') in System? + return undefined; + } + + function visitExportDeclaration(node: ExportDeclaration): VisitResult { + if (!node.moduleSpecifier) { + const statements: Statement[] = []; + addNodes(statements, map(node.exportClause.elements, visitExportSpecifier)); + return statements; + } + + return undefined; + } + + function visitExportSpecifier(specifier: ExportSpecifier): Statement { + if (resolver.getReferencedValueDeclaration(specifier.propertyName || specifier.name) + || resolver.isValueAliasDeclaration(specifier)) { + recordExportName(specifier.name); + return createExportStatement( + specifier.name, + specifier.propertyName || specifier.name + ); + } + return undefined; + } + + function visitExportAssignment(node: ExportAssignment): Statement { + if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) { + return createExportStatement( + createLiteral("default"), + node.expression + ); + } + + return undefined; + } + + /** + * Visits a variable statement, hoisting declared names to the top-level module body. + * Each declaration is rewritten into an assignment expression. + * + * @param node The variable statement to visit. + */ + function visitVariableStatement(node: VariableStatement): VisitResult { + const isExported = hasModifier(node, ModifierFlags.Export); + const expressions: Expression[] = []; + for (const variable of node.declarationList.declarations) { + addNode(expressions, transformVariable(variable, isExported)); + } + + if (expressions.length) { + return createStatement(inlineExpressions(expressions)); + } + + return undefined; + } + + /** + * Transforms a VariableDeclaration into one or more assignment expressions. + * + * @param node The VariableDeclaration to transform. + * @param isExported A value used to indicate whether the containing statement was exported. + */ + function transformVariable(node: VariableDeclaration, isExported: boolean): Expression { + // Hoist any bound names within the declaration. + hoistBindingElement(node, isExported); + + if (!node.initializer) { + // If the variable has no initializer, ignore it. + return; + } + + const name = node.name; + if (isIdentifier(name)) { + // If the variable has an IdentifierName, write out an assignment expression in its place. + return createAssignment(name, node.initializer); + } + else { + // If the variable has a BindingPattern, flatten the variable into multiple assignment expressions. + return flattenVariableDestructuringToExpression(node, hoistVariableDeclaration); + } + } + + /** + * Visits a FunctionDeclaration, hoisting it to the outer module body function. + * + * @param node The function declaration to visit. + */ + function visitFunctionDeclaration(node: FunctionDeclaration): Node { + if (hasModifier(node, ModifierFlags.Export)) { + // If the function is exported, ensure it has a name and rewrite the function without any export flags. + const name = node.name || getGeneratedNameForNode(node); + node = createFunctionDeclaration( + /*modifiers*/ undefined, + node.asteriskToken, + name, + node.parameters, + node.body, + /*location*/ node); + + // Record a declaration export in the outer module body function. + recordExportedFunctionDeclaration(node); + + if (!hasModifier(node, ModifierFlags.Default)) { + recordExportName(name); + } + } + + // Hoist the function declaration to the outer module body function. + hoistFunctionDeclaration(node); + return undefined; + } + + /** + * Visits a ClassDeclaration, hoisting its name to the outer module body function. + * + * @param node The class declaration to visit. + */ + function visitClassDeclaration(node: ClassDeclaration): VisitResult { + // Hoist the name of the class declaration to the outer module body function. + const name = getDeclarationName(node); + hoistVariableDeclaration(name); + + const statements: Statement[] = []; + + // Rewrite the class declaration into an assignment of a class expression. + addNode(statements, + createStatement( + createAssignment( + name, + createClassExpression( + node.name, + node.heritageClauses, + node.members, + /*location*/ node + ) + ), + /*location*/ node + ) + ); + + // If the class was exported, write a declaration export to the inner module body function. + if (hasModifier(node, ModifierFlags.Export)) { + if (!hasModifier(node, ModifierFlags.Default)) { + recordExportName(name); + } + + addNode(statements, createDeclarationExport(node)); + } + + return statements; + } + + /** + * Visits the body of a ForStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitForStatement(node: ForStatement): ForStatement { + const initializer = node.initializer; + if (isVariableDeclarationList(initializer)) { + const expressions: Expression[] = []; + for (const variable of initializer.declarations) { + addNode(expressions, transformVariable(variable, /*isExported*/ false)); + }; + + return createFor( + expressions.length + ? inlineExpressions(expressions) + : createSynthesizedNode(SyntaxKind.OmittedExpression), + node.condition, + node.incrementor, + visitNode(node.statement, visitNestedNode, isStatement), + /*location*/ node + ); + } + else { + return visitEachChild(node, visitNestedNode, context); + } + } + + /** + * Transforms and hoists the declaration list of a ForInStatement or ForOfStatement into an expression. + * + * @param node The decalaration list to transform. + */ + function transformForBinding(node: VariableDeclarationList): Expression { + const firstDeclaration = firstOrUndefined(node.declarations); + hoistBindingElement(firstDeclaration, /*isExported*/ false); + + const name = firstDeclaration.name; + return isIdentifier(name) + ? name + : flattenVariableDestructuringToExpression(firstDeclaration, hoistVariableDeclaration); + } + + /** + * Visits the body of a ForInStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitForInStatement(node: ForInStatement): ForInStatement { + const initializer = node.initializer; + if (isVariableDeclarationList(initializer)) { + const updated = getMutableClone(node); + updated.initializer = transformForBinding(initializer); + updated.statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + return updated; + } + else { + return visitEachChild(node, visitNestedNode, context); + } + } + + /** + * Visits the body of a ForOfStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitForOfStatement(node: ForOfStatement): ForOfStatement { + const initializer = node.initializer; + if (isVariableDeclarationList(initializer)) { + const updated = getMutableClone(node); + updated.initializer = transformForBinding(initializer); + updated.statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + return updated; + } + else { + return visitEachChild(node, visitNestedNode, context); + } + } + + /** + * Visits the body of a DoStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitDoStatement(node: DoStatement) { + const statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + if (statement !== node.statement) { + const updated = getMutableClone(node); + updated.statement = statement; + return updated; + } + return node; + } + + /** + * Visits the body of a WhileStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitWhileStatement(node: WhileStatement) { + const statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + if (statement !== node.statement) { + const updated = getMutableClone(node); + updated.statement = statement; + return updated; + } + return node; + } + + /** + * Visits the body of a LabeledStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitLabeledStatement(node: LabeledStatement) { + const statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + if (statement !== node.statement) { + const updated = getMutableClone(node); + updated.statement = statement; + return updated; + } + return node; + } + + /** + * Visits the body of a WithStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitWithStatement(node: WithStatement) { + const statement = visitNode(node.statement, visitNestedNode, isStatement, /*optional*/ false, liftToBlock); + if (statement !== node.statement) { + const updated = getMutableClone(node); + updated.statement = statement; + return updated; + } + return node; + } + + /** + * Visits the body of a SwitchStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitSwitchStatement(node: SwitchStatement) { + const caseBlock = visitNode(node.caseBlock, visitNestedNode, isCaseBlock); + if (caseBlock !== node.caseBlock) { + const updated = getMutableClone(node); + updated.caseBlock = caseBlock; + return updated; + } + return node; + } + + /** + * Visits the body of a CaseBlock to hoist declarations. + * + * @param node The node to visit. + */ + function visitCaseBlock(node: CaseBlock) { + const clauses = visitNodes(node.clauses, visitNestedNode, isCaseOrDefaultClause); + if (clauses !== node.clauses) { + const updated = getMutableClone(node); + updated.clauses = clauses; + return updated; + } + return node; + } + + /** + * Visits the body of a CaseClause to hoist declarations. + * + * @param node The clause to visit. + */ + function visitCaseClause(node: CaseClause) { + const statements = visitNodes(node.statements, visitNestedNode, isStatement); + if (statements !== node.statements) { + const updated = getMutableClone(node); + updated.statements = statements; + return updated; + } + return node; + } + + /** + * Visits the body of a DefaultClause to hoist declarations. + * + * @param node The clause to visit. + */ + function visitDefaultClause(node: DefaultClause) { + return visitEachChild(node, visitNestedNode, context); + } + + /** + * Visits the body of a TryStatement to hoist declarations. + * + * @param node The statement to visit. + */ + function visitTryStatement(node: TryStatement) { + return visitEachChild(node, visitNestedNode, context); + } + + /** + * Visits the body of a CatchClause to hoist declarations. + * + * @param node The clause to visit. + */ + function visitCatchClause(node: CatchClause) { + const block = visitNode(node.block, visitNestedNode, isBlock); + if (block !== node.block) { + const updated = getMutableClone(node); + updated.block = block; + return updated; + } + return node; + } + + /** + * Visits the body of a Block to hoist declarations. + * + * @param node The block to visit. + */ + function visitBlock(node: Block) { + return visitEachChild(node, visitNestedNode, context); + } + + // + // Substitutions + // + + /** + * Substitute the expression, if necessary. + * + * @param node The node to substitute. + */ + function substituteExpression(node: Expression): Expression { + node = previousExpressionSubstitution(node); + switch (node.kind) { + case SyntaxKind.Identifier: + return substituteExpressionIdentifier(node); + case SyntaxKind.BinaryExpression: + return substituteBinaryExpression(node); + case SyntaxKind.PostfixUnaryExpression: + return substitutePostfixUnaryExpression(node); + } + return node; + } + + /** + * Substitution for identifiers exported at the top level of a module. + */ + function substituteExpressionIdentifier(node: Identifier): Expression { + const importDeclaration = resolver.getReferencedImportDeclaration(node); + if (importDeclaration) { + return createImportBinding(importDeclaration); + } + + return node; + } + + function substituteBinaryExpression(node: BinaryExpression): Expression { + if (isAssignmentOperator(node.operatorToken.kind)) { + return substituteAssignmentExpression(node); + } + + return node; + } + + function substituteAssignmentExpression(node: BinaryExpression): Expression { + setNodeEmitFlags(node, NodeEmitFlags.NoSubstitution); + + const left = node.left; + switch (left.kind) { + case SyntaxKind.Identifier: + const exportDeclaration = resolver.getReferencedExportContainer(left); + if (exportDeclaration) { + return createExportExpression(left, node); + } + break; + + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.ArrayLiteralExpression: + if (hasExportedReferenceInDestructuringPattern(left)) { + return substituteDestructuring(node); + } + break; + } + + return node; + } + + function isExportedBinding(name: Identifier) { + const container = resolver.getReferencedExportContainer(name); + return container && container.kind === SyntaxKind.SourceFile; + } + + function hasExportedReferenceInDestructuringPattern(node: ObjectLiteralExpression | ArrayLiteralExpression | Identifier): boolean { + switch (node.kind) { + case SyntaxKind.Identifier: + return isExportedBinding(node); + + case SyntaxKind.ObjectLiteralExpression: + for (const property of (node).properties) { + if (hasExportedReferenceInObjectDestructuringElement(property)) { + return true; + } + } + + break; + + case SyntaxKind.ArrayLiteralExpression: + for (const element of (node).elements) { + if (hasExportedReferenceInArrayDestructuringElement(element)) { + return true; + } + } + + break; + } + + return false; + } + + function hasExportedReferenceInObjectDestructuringElement(node: ObjectLiteralElement): boolean { + if (isShorthandPropertyAssignment(node)) { + return isExportedBinding(node.name); + } + else if (isPropertyAssignment(node)) { + return hasExportedReferenceInDestructuringElement(node.initializer); + } + else { + return false; + } + } + + function hasExportedReferenceInArrayDestructuringElement(node: Expression): boolean { + if (isSpreadElementExpression(node)) { + const expression = node.expression; + return isIdentifier(expression) && isExportedBinding(expression); + } + else { + return hasExportedReferenceInDestructuringElement(node); + } + } + + function hasExportedReferenceInDestructuringElement(node: Expression): boolean { + if (isBinaryExpression(node)) { + const left = node.left; + return node.operatorToken.kind === SyntaxKind.EqualsToken + && isDestructuringPattern(left) + && hasExportedReferenceInDestructuringPattern(left); + } + else if (isIdentifier(node)) { + return isExportedBinding(node); + } + else if (isSpreadElementExpression(node)) { + const expression = node.expression; + return isIdentifier(expression) && isExportedBinding(expression); + } + else if (isDestructuringPattern(node)) { + return hasExportedReferenceInDestructuringPattern(node); + } + else { + return false; + } + } + + function isDestructuringPattern(node: Expression): node is ObjectLiteralExpression | ArrayLiteralExpression | Identifier { + const kind = node.kind; + return kind === SyntaxKind.Identifier + || kind === SyntaxKind.ObjectLiteralExpression + || kind === SyntaxKind.ArrayLiteralExpression; + } + + function substituteDestructuring(node: BinaryExpression) { + return flattenDestructuringAssignment(node, /*needsValue*/ true, hoistVariableDeclaration); + } + + function substitutePostfixUnaryExpression(node: PostfixUnaryExpression): Expression { + const operand = node.operand; + if (isIdentifier(operand)) { + const exportDeclaration = resolver.getReferencedExportContainer(operand); + if (exportDeclaration) { + const exportCall = createExportExpression( + operand, + createPrefix(node.operator, operand, node) + ); + + return node.operator === SyntaxKind.PlusPlusToken + ? createSubtract(exportCall, createLiteral(1)) + : createAdd(exportCall, createLiteral(1)); + } + } + return node; + } + + function getExternalModuleNameLiteral(importNode: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration) { + const moduleName = getExternalModuleName(importNode); + if (moduleName.kind === SyntaxKind.StringLiteral) { + return tryRenameExternalModule(moduleName) + || getSynthesizedClone(moduleName); + } + + return undefined; + } + + /** + * Some bundlers (SystemJS builder) sometimes want to rename dependencies. + * Here we check if alternative name was provided for a given moduleName and return it if possible. + */ + function tryRenameExternalModule(moduleName: LiteralExpression) { + if (currentSourceFile.renamedDependencies && hasProperty(currentSourceFile.renamedDependencies, moduleName.text)) { + return createLiteral(currentSourceFile.renamedDependencies[moduleName.text]); + } + + return undefined; + } + + function getLocalNameTextForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): string { + const name = getLocalNameForExternalImport(node); + return name ? name.text : undefined; + } + + function getLocalNameForExternalImport(node: ImportDeclaration | ExportDeclaration | ImportEqualsDeclaration): Identifier { + const namespaceDeclaration = getNamespaceDeclarationNode(node); + if (namespaceDeclaration && !isDefaultImport(node)) { + return createIdentifier(getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name)); + } + if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) { + return getGeneratedNameForNode(node); + } + if (node.kind === SyntaxKind.ExportDeclaration && (node).moduleSpecifier) { + return getGeneratedNameForNode(node); + } + } + + /** + * Gets a name to use for a DeclarationStatement. + * @param node The declaration statement. + */ + function getDeclarationName(node: DeclarationStatement) { + return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node); + } + + function addExportStarFunction(statements: Statement[], localNames: Identifier) { + const exportStarFunction = createUniqueName("exportStar"); + const m = createIdentifier("m"); + const n = createIdentifier("n"); + const exports = createIdentifier("exports"); + let condition: Expression = createStrictInequality(n, createLiteral("default")); + if (localNames) { + condition = createLogicalAnd( + condition, + createLogicalNot(createHasOwnProperty(localNames, n)) + ); + } + + addNode(statements, + createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + exportStarFunction, + [createParameter(m)], + createBlock([ + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + exports, + createObjectLiteral([]) + ) + ]) + ), + createForIn( + createVariableDeclarationList([ + createVariableDeclaration(n) + ]), + m, + createBlock([ + createIf( + condition, + createStatement( + createAssignment( + createElementAccess(exports, n), + createElementAccess(m, n) + ) + ) + ) + ]) + ), + createStatement( + createCall( + exportFunctionForFile, + [exports] + ) + ) + ]) + ) + ); + + return exportStarFunction; + } + + /** + * Creates a call to the current file's export function to export a value. + * @param name The bound name of the export. + * @param value The exported value. + */ + function createExportExpression(name: Identifier | StringLiteral, value: Expression) { + const exportName = isIdentifier(name) ? createLiteral(name.text) : name; + return createCall(exportFunctionForFile, [exportName, value]); + } + + /** + * Creates a call to the current file's export function to export a value. + * @param name The bound name of the export. + * @param value The exported value. + */ + function createExportStatement(name: Identifier | StringLiteral, value: Expression) { + return createStatement(createExportExpression(name, value)); + } + + /** + * Creates a call to the current file's export function to export a declaration. + * @param node The declaration to export. + */ + function createDeclarationExport(node: DeclarationStatement) { + const declarationName = getDeclarationName(node); + const exportName = hasModifier(node, ModifierFlags.Default) ? createLiteral("default") : declarationName; + return createExportStatement(exportName, declarationName); + } + + function createImportBinding(importDeclaration: Declaration): LeftHandSideExpression { + let importAlias: Identifier; + let name: Identifier; + if (isImportClause(importDeclaration)) { + importAlias = getGeneratedNameForNode(importDeclaration.parent); + name = createIdentifier("default"); + name.originalKeywordKind = SyntaxKind.DefaultKeyword; + } + else if (isImportSpecifier(importDeclaration)) { + importAlias = getGeneratedNameForNode(importDeclaration.parent.parent.parent); + name = importDeclaration.propertyName || importDeclaration.name; + } + + if (name.originalKeywordKind && languageVersion === ScriptTarget.ES3) { + return createElementAccess(importAlias, createLiteral(name.text)); + } + else { + return createPropertyAccess(importAlias, getSynthesizedClone(name)); + } + } + + function collectDependencyGroups(externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]) { + const groupIndices: Map = {}; + const dependencyGroups: DependencyGroup[] = []; + for (let i = 0; i < externalImports.length; i++) { + const externalImport = externalImports[i]; + const externalModuleName = getExternalModuleNameLiteral(externalImport); + const text = externalModuleName.text; + if (hasProperty(groupIndices, text)) { + // deduplicate/group entries in dependency list by the dependency name + const groupIndex = groupIndices[text]; + dependencyGroups[groupIndex].externalImports.push(externalImport); + continue; + } + else { + groupIndices[text] = dependencyGroups.length; + dependencyGroups.push({ + name: externalModuleName, + externalImports: [externalImport] + }); + } + } + + return dependencyGroups; + } + + function getNameOfDependencyGroup(dependencyGroup: DependencyGroup) { + return dependencyGroup.name; + } + + function recordExportName(name: Identifier) { + if (!exportedLocalNames) { + exportedLocalNames = []; + } + + exportedLocalNames.push(name); + } + + function recordExportedFunctionDeclaration(node: FunctionDeclaration) { + if (!exportedFunctionDeclarations) { + exportedFunctionDeclarations = []; + } + + exportedFunctionDeclarations.push(createDeclarationExport(node)); + } + + function hoistBindingElement(node: VariableDeclaration | BindingElement, isExported: boolean) { + const name = node.name; + if (isIdentifier(name)) { + hoistVariableDeclaration(getSynthesizedClone(name)); + if (isExported) { + recordExportName(name); + } + } + else if (isBindingPattern(name)) { + forEach(name.elements, isExported ? hoistExportedBindingElement : hoistNonExportedBindingElement); + } + } + + function hoistExportedBindingElement(node: VariableDeclaration | BindingElement) { + hoistBindingElement(node, /*isExported*/ true); + } + + function hoistNonExportedBindingElement(node: VariableDeclaration | BindingElement) { + hoistBindingElement(node, /*isExported*/ false); + } + + function updateSourceFile(node: SourceFile, statements: Statement[]) { + const updated = getMutableClone(node); + updated.statements = createNodeArray(statements, node.statements); + return updated; + } + } +} \ No newline at end of file diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts new file mode 100644 index 0000000000000..8251c0c467ef3 --- /dev/null +++ b/src/compiler/transformers/ts.ts @@ -0,0 +1,2856 @@ +/// +/// +/// + +/*@internal*/ +namespace ts { + type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration; + + const enum TypeScriptSubstitutionFlags { + /** Enables substitutions for decorated classes. */ + DecoratedClasses = 1 << 0, + /** Enables substitutions for namespace exports. */ + NamespaceExports = 1 << 1, + /** Enables substitutions for async methods with `super` calls. */ + AsyncMethodsWithSuper = 1 << 2, + } + + export function transformTypeScript(context: TransformationContext) { + const { + setNodeEmitFlags, + startLexicalEnvironment, + endLexicalEnvironment, + hoistVariableDeclaration, + } = context; + + const resolver = context.getEmitResolver(); + const compilerOptions = context.getCompilerOptions(); + const languageVersion = getEmitScriptTarget(compilerOptions); + + // Save the previous transformation hooks. + const previousOnEmitNode = context.onEmitNode; + const previousExpressionSubstitution = context.expressionSubstitution; + + // Set new transformation hooks. + context.onEmitNode = onEmitNode; + context.expressionSubstitution = substituteExpression; + + // These variables contain state that changes as we descend into the tree. + let currentSourceFile: SourceFile; + let currentNamespace: ModuleDeclaration; + let currentNamespaceLocalName: Identifier; + let currentScope: SourceFile | Block | ModuleBlock | CaseBlock; + let currentParent: Node; + let currentNode: Node; + + /** + * Keeps track of whether expression substitution has been enabled for specific edge cases. + * They are persisted between each SourceFile transformation and should not be reset. + */ + let enabledSubstitutions: TypeScriptSubstitutionFlags; + + /** + * A map that keeps track of aliases created for classes with decorators to avoid issues + * with the double-binding behavior of classes. + */ + let decoratedClassAliases: Map; + + /** + * A map that keeps track of currently active aliases defined in `decoratedClassAliases` + * when just-in-time substitution occurs while printing an expression identifier. + */ + let currentDecoratedClassAliases: Map; + + /** + * Keeps track of whether we are within any containing namespaces when performing + * just-in-time substitution while printing an expression identifier. + */ + let isEnclosedInNamespace: boolean; + + /** + * This keeps track of containers where `super` is valid, for use with + * just-in-time substitution for `super` expressions inside of async methods. + */ + let currentSuperContainer: SuperContainer; + + return transformSourceFile; + + /** + * Transform TypeScript-specific syntax in a SourceFile. + * + * @param node A SourceFile node. + */ + function transformSourceFile(node: SourceFile) { + currentSourceFile = node; + node = visitEachChild(node, visitor, context); + setNodeEmitFlags(node, NodeEmitFlags.EmitEmitHelpers); + return node; + } + + /** + * Visits a node, saving and restoring state variables on the stack. + * + * @param node The node to visit. + */ + function visitWithStack(node: Node, visitor: (node: Node) => VisitResult): VisitResult { + // Save state + const savedCurrentNamespace = currentNamespace; + const savedCurrentScope = currentScope; + const savedCurrentParent = currentParent; + const savedCurrentNode = currentNode; + + // Handle state changes before visiting a node. + onBeforeVisitNode(node); + + const visited = visitor(node); + + // Restore state + currentNamespace = savedCurrentNamespace; + currentScope = savedCurrentScope; + currentParent = savedCurrentParent; + currentNode = savedCurrentNode; + + return visited; + } + + /** + * General-purpose node visitor. + * + * @param node The node to visit. + */ + function visitor(node: Node): VisitResult { + return visitWithStack(node, visitorWorker); + } + + /** + * Visits and possibly transforms any node. + * + * @param node The node to visit. + */ + function visitorWorker(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.TypeScript) { + // This node is explicitly marked as TypeScript, so we should transform the node. + return visitTypeScript(node); + } + else if (node.transformFlags & TransformFlags.ContainsTypeScript) { + // This node contains TypeScript, so we should visit its children. + return visitEachChild(node, visitor, context); + } + + return node; + } + + /** + * Specialized visitor that visits the immediate children of a namespace. + * + * @param node The node to visit. + */ + function namespaceElementVisitor(node: Node): VisitResult { + return visitWithStack(node, namespaceElementVisitorWorker); + } + + /** + * Specialized visitor that visits the immediate children of a namespace. + * + * @param node The node to visit. + */ + function namespaceElementVisitorWorker(node: Node): VisitResult { + if (node.transformFlags & TransformFlags.TypeScript || isExported(node)) { + // This node is explicitly marked as TypeScript, or is exported at the namespace + // level, so we should transform the node. + return visitTypeScript(node); + } + else if (node.transformFlags & TransformFlags.ContainsTypeScript) { + // This node contains TypeScript, so we should visit its children. + return visitEachChild(node, visitor, context); + } + + return node; + } + + /** + * Specialized visitor that visits the immediate children of a class with TypeScript syntax. + * + * @param node The node to visit. + */ + function classElementVisitor(node: Node): VisitResult { + return visitWithStack(node, classElementVisitorWorker); + } + + /** + * Specialized visitor that visits the immediate children of a class with TypeScript syntax. + * + * @param node The node to visit. + */ + function classElementVisitorWorker(node: Node): VisitResult { + switch (node.kind) { + case SyntaxKind.Constructor: + // TypeScript constructors are transformed in `transformClassDeclaration`. + // We elide them here as `visitorWorker` checks transform flags, which could + // erronously include an ES6 constructor without TypeScript syntax. + return undefined; + + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.IndexSignature: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: + // Fallback to the default visit behavior. + return visitorWorker(node); + + case SyntaxKind.SemicolonClassElement: + return node; + + default: + Debug.failBadSyntaxKind(node); + return undefined; + } + } + + /** + * Branching visitor, visits a TypeScript syntax node. + * + * @param node The node to visit. + */ + function visitTypeScript(node: Node): VisitResult { + if (hasModifier(node, ModifierFlags.Ambient)) { + // TypeScript ambient declarations are elided. + return undefined; + } + + switch (node.kind) { + case SyntaxKind.ExportKeyword: + case SyntaxKind.DefaultKeyword: + // ES6 export and default modifiers are elided when inside a namespace. + return currentNamespace ? undefined : node; + + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.ProtectedKeyword: + case SyntaxKind.AbstractKeyword: + case SyntaxKind.AsyncKeyword: + case SyntaxKind.ConstKeyword: + case SyntaxKind.DeclareKeyword: + // TypeScript accessibility modifiers are elided. + + case SyntaxKind.ArrayType: + case SyntaxKind.TupleType: + case SyntaxKind.TypeLiteral: + case SyntaxKind.TypePredicate: + case SyntaxKind.TypeParameter: + case SyntaxKind.AnyKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.ConstructorType: + case SyntaxKind.FunctionType: + case SyntaxKind.TypeQuery: + case SyntaxKind.TypeReference: + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + case SyntaxKind.StringLiteralType: + case SyntaxKind.ThisType: + // TypeScript type nodes are elided. + + case SyntaxKind.IndexSignature: + // TypeScript index signatures are elided. + + case SyntaxKind.Decorator: + // TypeScript decorators are elided. They will be emitted as part of transformClassDeclaration. + + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + // TypeScript type-only declarations are elided + + case SyntaxKind.PropertyDeclaration: + // TypeScript property declarations are elided. + + case SyntaxKind.Constructor: + // TypeScript constructors are transformed in `transformClassDeclaration`. + return undefined; + + case SyntaxKind.ClassDeclaration: + // This is a class declaration with TypeScript syntax extensions. + // + // TypeScript class syntax extensions include: + // - decorators + // - optional `implements` heritage clause + // - parameter property assignments in the constructor + // - property declarations + // - index signatures + // - method overload signatures + // - async methods + return visitClassDeclaration(node); + + case SyntaxKind.ClassExpression: + // This is a class expression with TypeScript syntax extensions. + // + // TypeScript class syntax extensions include: + // - decorators + // - optional `implements` heritage clause + // - parameter property assignments in the constructor + // - property declarations + // - index signatures + // - method overload signatures + // - async methods + return visitClassExpression(node); + + case SyntaxKind.HeritageClause: + // This is a heritage clause with TypeScript syntax extensions. + // + // TypeScript heritage clause extensions include: + // - `implements` clause + return visitHeritageClause(node); + + case SyntaxKind.ExpressionWithTypeArguments: + // TypeScript supports type arguments on an expression in an `extends` heritage clause. + return visitExpressionWithTypeArguments(node); + + case SyntaxKind.MethodDeclaration: + // TypeScript method declarations may be 'async', and may have decorators, modifiers + // or type annotations. + return visitMethodDeclaration(node); + + case SyntaxKind.GetAccessor: + // Get Accessors can have TypeScript modifiers, decorators, and type annotations. + return visitGetAccessor(node); + + case SyntaxKind.SetAccessor: + // Set Accessors can have TypeScript modifiers, decorators, and type annotations. + return visitSetAccessor(node); + + case SyntaxKind.FunctionDeclaration: + // TypeScript function declarations may be 'async' + return visitFunctionDeclaration(node); + + case SyntaxKind.FunctionExpression: + // TypeScript function expressions may be 'async' + return visitFunctionExpression(node); + + case SyntaxKind.ArrowFunction: + // TypeScript arrow functions may be 'async' + return visitArrowFunction(node); + + case SyntaxKind.Parameter: + // This is a parameter declaration with TypeScript syntax extensions. + // + // TypeScript parameter declaration syntax extensions include: + // - decorators + // - accessibility modifiers + // - the question mark (?) token for optional parameters + // - type annotations + return visitParameter(node); + + case SyntaxKind.ParenthesizedExpression: + // ParenthesizedExpressions are TypeScript if their expression is a + // TypeAssertion or AsExpression + return visitParenthesizedExpression(node); + + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.AsExpression: + // TypeScript type assertions are removed, but their subtrees are preserved. + return visitAssertionExpression(node); + + case SyntaxKind.EnumDeclaration: + // TypeScript enum declarations do not exist in ES6 and must be rewritten. + return visitEnumDeclaration(node); + + case SyntaxKind.AwaitExpression: + // TypeScript 'await' expressions must be transformed. + return visitAwaitExpression(node); + + case SyntaxKind.VariableStatement: + // TypeScript namespace exports for variable statements must be transformed. + return visitVariableStatement(node); + + case SyntaxKind.ModuleDeclaration: + // TypeScript namespace declarations must be transformed. + return visitModuleDeclaration(node); + + case SyntaxKind.ImportEqualsDeclaration: + // TypeScript namespace or external module import. + return visitImportEqualsDeclaration(node); + + default: + Debug.failBadSyntaxKind(node); + return undefined; + } + } + + /** + * Performs actions that should always occur immediately before visiting a node. + * + * @param node The node to visit. + */ + function onBeforeVisitNode(node: Node) { + currentParent = currentNode; + currentNode = node; + + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.CaseBlock: + case SyntaxKind.ModuleBlock: + case SyntaxKind.Block: + currentScope = node; + break; + } + } + + /** + * Transforms a class declaration with TypeScript syntax into compatible ES6. + * + * This function will only be called when one of the following conditions are met: + * - The class has decorators. + * - The class has property declarations with initializers. + * - The class contains a constructor that contains parameters with accessibility modifiers. + * - The class is an export in a TypeScript namespace. + * + * @param node The node to transform. + */ + function visitClassDeclaration(node: ClassDeclaration): VisitResult { + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const hasExtendsClause = getClassExtendsHeritageClauseElement(node) !== undefined; + + // emit name if + // - node has a name + // - node has static initializers + // + let name = node.name; + if (!name && staticProperties.length > 0) { + name = getGeneratedNameForNode(node); + } + + let decoratedClassAlias: Identifier; + const statements: Statement[] = []; + if (!node.decorators) { + // ${modifiers} class ${name} ${heritageClauses} { + // ${members} + // } + addNode(statements, + setOriginalNode( + createClassDeclaration( + visitNodes(node.modifiers, visitor, isModifier), + name, + visitNodes(node.heritageClauses, visitor, isHeritageClause), + transformClassMembers(node, hasExtendsClause), + /*location*/ node + ), + node + ) + ); + } + else { + decoratedClassAlias = addClassDeclarationHeadWithDecorators(statements, node, name, hasExtendsClause); + } + + // Emit static property assignment. Because classDeclaration is lexically evaluated, + // it is safe to emit static property assignment after classDeclaration + // From ES6 specification: + // HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using + // a lexical declaration such as a LexicalDeclaration or a ClassDeclaration. + addNodes(statements, generateInitializedPropertyStatements(node, staticProperties, name)); + + // Write any decorators of the node. + addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ false)); + addNodes(statements, generateClassElementDecorationStatements(node, /*isStatic*/ true)); + addNode(statements, generateConstructorDecorationStatement(node, decoratedClassAlias)); + + // If the class is exported as part of a TypeScript namespace, emit the namespace export. + // Otherwise, if the class was exported at the top level and was decorated, emit an export + // declaration or export default for the class. + if (isNamespaceExport(node)) { + addNode(statements, createNamespaceExport(name, name)); + } + else if (node.decorators) { + if (isDefaultExternalModuleExport(node)) { + addNode(statements, createExportDefault(name)); + } + else if (isNamedExternalModuleExport(node)) { + addNode(statements, createExternalModuleExport(name)); + } + } + + return statements; + } + + /** + * Transforms a decorated class declaration and appends the resulting statements. If + * the class requires an alias to avoid issues with double-binding, the alias is returned. + * + * @param node A ClassDeclaration node. + * @param name The name of the class. + * @param hasExtendsClause A value indicating whether + */ + function addClassDeclarationHeadWithDecorators(statements: Statement[], node: ClassDeclaration, name: Identifier, hasExtendsClause: boolean) { + // When we emit an ES6 class that has a class decorator, we must tailor the + // emit to certain specific cases. + // + // In the simplest case, we emit the class declaration as a let declaration, and + // evaluate decorators after the close of the class body: + // + // [Example 1] + // --------------------------------------------------------------------- + // TypeScript | Javascript + // --------------------------------------------------------------------- + // @dec | let C = class C { + // class C { | } + // } | C = __decorate([dec], C); + // --------------------------------------------------------------------- + // @dec | let C = class C { + // export class C { | } + // } | C = __decorate([dec], C); + // | export { C }; + // --------------------------------------------------------------------- + // + // If a class declaration contains a reference to itself *inside* of the class body, + // this introduces two bindings to the class: One outside of the class body, and one + // inside of the class body. If we apply decorators as in [Example 1] above, there + // is the possibility that the decorator `dec` will return a new value for the + // constructor, which would result in the binding inside of the class no longer + // pointing to the same reference as the binding outside of the class. + // + // As a result, we must instead rewrite all references to the class *inside* of the + // class body to instead point to a local temporary alias for the class: + // + // [Example 2] + // --------------------------------------------------------------------- + // TypeScript | Javascript + // --------------------------------------------------------------------- + // @dec | let C_1; + // class C { | let C = C_1 = class C { + // static x() { return C.y; } | static x() { return C_1.y; } + // static y = 1; | } + // } | C.y = 1; + // | C = C_1 = __decorate([dec], C); + // --------------------------------------------------------------------- + // @dec | let C_1; + // export class C { | let C = C_1 = class C { + // static x() { return C.y; } | static x() { return C_1.y; } + // static y = 1; | } + // } | C.y = 1; + // | C = C_1 = __decorate([dec], C); + // | export { C }; + // --------------------------------------------------------------------- + // + // If a class declaration is the default export of a module, we instead emit + // the export after the decorated declaration: + // + // [Example 3] + // --------------------------------------------------------------------- + // TypeScript | Javascript + // --------------------------------------------------------------------- + // @dec | let default_1 = class { + // export default class { | } + // } | default_1 = __decorate([dec], default_1); + // | export default default_1; + // --------------------------------------------------------------------- + // @dec | let C = class C { + // export default class C { | } + // } | C = __decorate([dec], C); + // | export default C; + // --------------------------------------------------------------------- + // + // If the class declaration is the default export and a reference to itself + // inside of the class body, we must emit both an alias for the class *and* + // move the export after the declaration: + // + // [Example 4] + // --------------------------------------------------------------------- + // TypeScript | Javascript + // --------------------------------------------------------------------- + // @dec | let C_1; + // export default class C { | let C = C_1 = class C { + // static x() { return C.y; } | static x() { return C_1.y; } + // static y = 1; | } + // } | C.y = 1; + // | C = C_1 = __decorate([dec], C); + // | export default C; + // --------------------------------------------------------------------- + // + + // ... = class ${name} ${heritageClauses} { + // ${members} + // } + let classExpression: Expression = setOriginalNode( + createClassExpression( + name, + visitNodes(node.heritageClauses, visitor, isHeritageClause), + transformClassMembers(node, hasExtendsClause), + /*location*/ node + ), + node + ); + + // Record an alias to avoid class double-binding. + let decoratedClassAlias: Identifier; + if (resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.DecoratedClassWithSelfReference) { + enableExpressionSubstitutionForDecoratedClasses(); + decoratedClassAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default"); + decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias; + + // We emit the class alias as a `let` declaration here so that it has the same + // TDZ as the class. + + // let ${decoratedClassAlias}; + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration(decoratedClassAlias) + ], + /*location*/ undefined, + NodeFlags.Let) + ) + ); + + // ${decoratedClassAlias} = ${classExpression} + classExpression = createAssignment( + decoratedClassAlias, + classExpression, + /*location*/ node); + } + + // let ${name} = ${classExpression}; + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration( + name, + classExpression + ) + ], + /*location*/ undefined, + NodeFlags.Let) + ) + ); + + return decoratedClassAlias; + } + + /** + * Transforms a class expression with TypeScript syntax into compatible ES6. + * + * This function will only be called when one of the following conditions are met: + * - The class has property declarations with initializers. + * - The class contains a constructor that contains parameters with accessibility modifiers. + * + * @param node The node to transform. + */ + function visitClassExpression(node: ClassExpression): Expression { + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); + const members = transformClassMembers(node, heritageClauses !== undefined); + + // emit name if + // - node has a name + // - node has static initializers + // + let name = node.name; + if (!name && staticProperties.length > 0) { + name = getGeneratedNameForNode(node); + } + + const classExpression = setOriginalNode( + createClassExpression( + name, + heritageClauses, + members, + /*location*/ node + ), + node + ); + + if (staticProperties.length > 0) { + const expressions: Expression[] = []; + const temp = createTempVariable(); + hoistVariableDeclaration(temp); + addNode(expressions, createAssignment(temp, classExpression)); + addNodes(expressions, generateInitializedPropertyExpressions(node, staticProperties, temp)); + addNode(expressions, temp); + return inlineExpressions(expressions); + } + + return classExpression; + } + + /** + * Transforms the members of a class. + * + * @param node The current class. + * @param hasExtendsClause A value indicating whether the class has an extends clause. + */ + function transformClassMembers(node: ClassDeclaration | ClassExpression, hasExtendsClause: boolean) { + const members: ClassElement[] = []; + addNode(members, transformConstructor(node, hasExtendsClause)); + addNodes(members, visitNodes(node.members, classElementVisitor, isClassElement)); + return createNodeArray(members, /*location*/ node.members); + } + + /** + * Transforms (or creates) a constructor for a class. + * + * @param node The current class. + * @param hasExtendsClause A value indicating whether the class has an extends clause. + */ + function transformConstructor(node: ClassDeclaration | ClassExpression, hasExtendsClause: boolean) { + // Check if we have property assignment inside class declaration. + // If there is a property assignment, we need to emit constructor whether users define it or not + // If there is no property assignment, we can omit constructor if users do not define it + const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty); + const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments; + const constructor = getFirstConstructorWithBody(node); + + // If the class does not contain nodes that require a synthesized constructor, + // accept the current constructor if it exists. + if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) { + return visitEachChild(constructor, visitor, context); + } + + const parameters = transformConstructorParameters(constructor, hasExtendsClause); + const body = transformConstructorBody(node, constructor, hasExtendsClause, parameters); + + // constructor(${parameters}) { + // ${body} + // } + return startOnNewLine( + setOriginalNode( + createConstructor( + parameters, + body, + /*location*/ constructor + ), + constructor + ) + ); + } + + /** + * Transforms (or creates) the parameters for the constructor of a class with + * parameter property assignments or instance property initializers. + * + * @param constructor The constructor declaration. + * @param hasExtendsClause A value indicating whether the class has an extends clause. + */ + function transformConstructorParameters(constructor: ConstructorDeclaration, hasExtendsClause: boolean) { + return constructor + ? visitNodes(constructor.parameters, visitor, isParameter) + : hasExtendsClause ? [createRestParameter(createUniqueName("args"))] : []; + } + + /** + * Transforms (or creates) a constructor body for a class with parameter property + * assignments or instance property initializers. + * + * @param node The current class. + * @param constructor The current class constructor. + * @param hasExtendsClause A value indicating whether the class has an extends clause. + * @param parameters The transformed parameters for the constructor. + */ + function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration, hasExtendsClause: boolean, parameters: ParameterDeclaration[]) { + let hasSuperCall = false; + const statements: Statement[] = []; + + // The body of a constructor is a new lexical environment + startLexicalEnvironment(); + + if (constructor) { + const superCall = visitNode(findInitialSuperCall(constructor), visitor, isStatement); + if (superCall) { + // Adds the existing super call as the first line of the constructor. + addNode(statements, superCall); + hasSuperCall = true; + } + + // Add parameters with property assignments. Transforms this: + // + // constructor (public x, public y) { + // } + // + // Into this: + // + // constructor (x, y) { + // this.x = x; + // this.y = y; + // } + // + const propertyAssignments = getParametersWithPropertyAssignments(constructor); + addNodes(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); + } + else if (hasExtendsClause) { + Debug.assert(parameters.length === 1 && isIdentifier(parameters[0].name)); + + // Add a synthetic `super` call: + // + // super(...args); + // + addNode(statements, + createStatement( + createCall( + createSuper(), + [createSpread(parameters[0].name)] + ) + ) + ); + } + + // Add the property initializers. Transforms this: + // + // public x = 1; + // + // Into this: + // + // constructor() { + // this.x = 1; + // } + // + const properties = getInitializedProperties(node, /*isStatic*/ false); + addNodes(statements, generateInitializedPropertyStatements(node, properties, createThis())); + + if (constructor) { + // The class already had a constructor, so we should add the existing statements, skipping the initial super call. + addNodes(statements, visitNodes(constructor.body.statements, visitor, isStatement, hasSuperCall ? 1 : 0)); + } + + // End the lexical environment. + addNodes(statements, endLexicalEnvironment()); + return setMultiLine( + createBlock(statements, constructor ? constructor.body : undefined), + true + ); + } + + /** + * Finds the initial super-call for a constructor. + * + * @param ctor The constructor node. + */ + function findInitialSuperCall(ctor: ConstructorDeclaration): ExpressionStatement { + if (ctor.body) { + const statements = ctor.body.statements; + const statement = firstOrUndefined(statements); + if (statement && statement.kind === SyntaxKind.ExpressionStatement) { + const expression = (statement).expression; + if (expression.kind === SyntaxKind.CallExpression) { + if ((expression).expression.kind === SyntaxKind.SuperKeyword) { + return statement; + } + } + } + } + + return undefined; + } + + /** + * Gets all parameters of a constructor that should be transformed into property assignments. + * + * @param node The constructor node. + */ + function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ParameterDeclaration[] { + return filter(node.parameters, isParameterWithPropertyAssignment); + } + + /** + * Determines whether a parameter should be transformed into a property assignment. + * + * @param parameter The parameter node. + */ + function isParameterWithPropertyAssignment(parameter: ParameterDeclaration) { + return hasModifier(parameter, ModifierFlags.AccessibilityModifier) + && isIdentifier(parameter.name); + } + + /** + * Transforms a parameter into a property assignment statement. + * + * @param node The parameter declaration. + */ + function transformParameterWithPropertyAssignment(node: ParameterDeclaration) { + Debug.assert(isIdentifier(node.name)); + + const name = getSynthesizedClone(node.name); + return startOnNewLine( + createStatement( + createAssignment( + createPropertyAccess(createThis(), name), + name + ) + ) + ); + } + + /** + * Gets all property declarations with initializers on either the static or instance side of a class. + * + * @param node The class node. + * @param isStatic A value indicating whether to get properties from the static or instance side of the class. + */ + function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): PropertyDeclaration[] { + return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty); + } + + /** + * Gets a value indicating whether a class element is a static property declaration with an initializer. + * + * @param member The class element node. + */ + function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration { + return isInitializedProperty(member, /*isStatic*/ true); + } + + /** + * Gets a value indicating whether a class element is an instance property declaration with an initializer. + * + * @param member The class element node. + */ + function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration { + return isInitializedProperty(member, /*isStatic*/ false); + } + + /** + * Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer. + * + * @param member The class element node. + * @param isStatic A value indicating whether the member should be a static or instance member. + */ + function isInitializedProperty(member: ClassElement, isStatic: boolean) { + return member.kind === SyntaxKind.PropertyDeclaration + && isStatic === hasModifier(member, ModifierFlags.Static) + && (member).initializer !== undefined; + } + + /** + * Generates assignment statements for property initializers. + * + * @param node The class node. + * @param properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function generateInitializedPropertyStatements(node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { + const statements: Statement[] = []; + for (const property of properties) { + statements.push( + createStatement( + transformInitializedProperty(node, property, receiver), + /*location*/ property + ) + ); + } + + return statements; + } + + /** + * Generates assignment expressions for property initializers. + * + * @param node The class node. + * @param properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function generateInitializedPropertyExpressions(node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { + const expressions: Expression[] = []; + for (const property of properties) { + expressions.push(transformInitializedProperty(node, property, receiver, /*location*/ property)); + } + + return expressions; + } + + /** + * Transforms a property initializer into an assignment statement. + * + * @param node The class containing the property. + * @param property The property declaration. + * @param receiver The object receiving the property assignment. + */ + function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression, location?: TextRange) { + const propertyName = visitPropertyNameOfClassElement(property); + const initializer = visitNode(property.initializer, visitor, isExpression); + return createAssignment( + createMemberAccessForPropertyName(receiver, propertyName), + initializer, + location + ); + } + + /** + * Gets either the static or instance members of a class that are decorated, or have + * parameters that are decorated. + * + * @param node The class containing the member. + * @param isStatic A value indicating whether to retrieve static or instance members of + * the class. + */ + function getDecoratedClassElements(node: ClassExpression | ClassDeclaration, isStatic: boolean): ClassElement[] { + return filter(node.members, isStatic ? isStaticDecoratedClassElement : isInstanceDecoratedClassElement); + } + + /** + * Determines whether a class member is a static member of a class that is decorated, or + * has parameters that are decorated. + * + * @param member The class member. + */ + function isStaticDecoratedClassElement(member: ClassElement) { + return isDecoratedClassElement(member, /*isStatic*/ true); + } + + /** + * Determines whether a class member is an instance member of a class that is decorated, + * or has parameters that are decorated. + * + * @param member The class member. + */ + function isInstanceDecoratedClassElement(member: ClassElement) { + return isDecoratedClassElement(member, /*isStatic*/ false); + } + + /** + * Determines whether a class member is either a static or an instance member of a class + * that is decorated, or has parameters that are decorated. + * + * @param member The class member. + */ + function isDecoratedClassElement(member: ClassElement, isStatic: boolean) { + return nodeOrChildIsDecorated(member) + && isStatic === hasModifier(member, ModifierFlags.Static); + } + + /** + * A structure describing the decorators for a class element. + */ + interface AllDecorators { + decorators: Decorator[]; + parameters?: Decorator[][]; + } + + /** + * Gets an array of arrays of decorators for the parameters of a function-like node. + * The offset into the result array should correspond to the offset of the parameter. + * + * @param node The function-like node. + */ + function getDecoratorsOfParameters(node: FunctionLikeDeclaration) { + let decorators: Decorator[][]; + if (node) { + const parameters = node.parameters; + for (let i = 0; i < parameters.length; i++) { + const parameter = parameters[i]; + if (decorators || parameter.decorators) { + if (!decorators) { + decorators = new Array(parameters.length); + } + + decorators[i] = parameter.decorators; + } + } + } + + return decorators; + } + + /** + * Gets an AllDecorators object containing the decorators for the class and the decorators for the + * parameters of the constructor of the class. + * + * @param node The class node. + */ + function getAllDecoratorsOfConstructor(node: ClassExpression | ClassDeclaration): AllDecorators { + const decorators = node.decorators; + const parameters = getDecoratorsOfParameters(getFirstConstructorWithBody(node)); + if (!decorators && !parameters) { + return undefined; + } + + return { + decorators, + parameters + }; + } + + /** + * Gets an AllDecorators object containing the decorators for the member and its parameters. + * + * @param node The class node that contains the member. + * @param member The class member. + */ + function getAllDecoratorsOfClassElement(node: ClassExpression | ClassDeclaration, member: ClassElement): AllDecorators { + switch (member.kind) { + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return getAllDecoratorsOfAccessors(node, member); + + case SyntaxKind.MethodDeclaration: + return getAllDecoratorsOfMethod(member); + + case SyntaxKind.PropertyDeclaration: + return getAllDecoratorsOfProperty(member); + + default: + return undefined; + } + } + + /** + * Gets an AllDecorators object containing the decorators for the accessor and its parameters. + * + * @param node The class node that contains the accessor. + * @param accessor The class accessor member. + */ + function getAllDecoratorsOfAccessors(node: ClassExpression | ClassDeclaration, accessor: AccessorDeclaration): AllDecorators { + if (!accessor.body) { + return undefined; + } + + const { firstAccessor, secondAccessor, setAccessor } = getAllAccessorDeclarations(node.members, accessor); + if (accessor !== firstAccessor) { + return undefined; + } + + const decorators = firstAccessor.decorators || (secondAccessor && secondAccessor.decorators); + const parameters = getDecoratorsOfParameters(setAccessor); + if (!decorators && !parameters) { + return undefined; + } + + return { decorators, parameters }; + } + + /** + * Gets an AllDecorators object containing the decorators for the method and its parameters. + * + * @param method The class method member. + */ + function getAllDecoratorsOfMethod(method: MethodDeclaration): AllDecorators { + if (!method.body) { + return undefined; + } + + const decorators = method.decorators; + const parameters = getDecoratorsOfParameters(method); + if (!decorators && !parameters) { + return undefined; + } + + return { decorators, parameters }; + } + + /** + * Gets an AllDecorators object containing the decorators for the property. + * + * @param property The class property member. + */ + function getAllDecoratorsOfProperty(property: PropertyDeclaration): AllDecorators { + const decorators = property.decorators; + if (!decorators) { + return undefined; + + } + + return { decorators }; + } + + /** + * Transforms all of the decorators for a declaration into an array of expressions. + * + * @param node The declaration node. + * @param allDecorators An object containing all of the decorators for the declaration. + */ + function transformAllDecoratorsOfDeclaration(node: Declaration, allDecorators: AllDecorators) { + if (!allDecorators) { + return undefined; + } + + const decoratorExpressions: Expression[] = []; + addNodes(decoratorExpressions, map(allDecorators.decorators, transformDecorator)); + addNodes(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter)); + addTypeMetadata(node, decoratorExpressions); + return decoratorExpressions; + } + + /** + * Generates statements used to apply decorators to either the static or instance members + * of a class. + * + * @param node The class node. + * @param isStatic A value indicating whether to generate statements for static or + * instance members. + */ + function generateClassElementDecorationStatements(node: ClassDeclaration, isStatic: boolean) { + return map(generateClassElementDecorationExpressions(node, isStatic), expressionToStatement); + } + + /** + * Generates expressions used to apply decorators to either the static or instance members + * of a class. + * + * @param node The class node. + * @param isStatic A value indicating whether to generate expressions for static or + * instance members. + */ + function generateClassElementDecorationExpressions(node: ClassExpression | ClassDeclaration, isStatic: boolean) { + const members = getDecoratedClassElements(node, isStatic); + let expressions: Expression[]; + for (const member of members) { + const expression = generateClassElementDecorationExpression(node, member); + if (expression) { + if (!expressions) { + expressions = [expression]; + } + else { + expressions.push(expression); + } + } + } + return expressions; + } + + /** + * Generates an expression used to evaluate class element decorators at runtime. + * + * @param node The class node that contains the member. + * @param member The class member. + */ + function generateClassElementDecorationExpression(node: ClassExpression | ClassDeclaration, member: ClassElement) { + const allDecorators = getAllDecoratorsOfClassElement(node, member); + const decoratorExpressions = transformAllDecoratorsOfDeclaration(member, allDecorators); + if (!decoratorExpressions) { + return undefined; + } + + // Emit the call to __decorate. Given the following: + // + // class C { + // @dec method(@dec2 x) {} + // @dec get accessor() {} + // @dec prop; + // } + // + // The emit for a method is: + // + // __decorate([ + // dec, + // __param(0, dec2), + // __metadata("design:type", Function), + // __metadata("design:paramtypes", [Object]), + // __metadata("design:returntype", void 0) + // ], C.prototype, "method", undefined); + // + // The emit for an accessor is: + // + // __decorate([ + // dec + // ], C.prototype, "accessor", undefined); + // + // The emit for a property is: + // + // __decorate([ + // dec + // ], C.prototype, "prop"); + // + + const prefix = getClassMemberPrefix(node, member); + const memberName = getExpressionForPropertyName(member); + const descriptor = languageVersion > ScriptTarget.ES3 + ? member.kind === SyntaxKind.PropertyDeclaration + // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it + // should not invoke `Object.getOwnPropertyDescriptor`. + ? createVoidZero() + + // We emit `null` here to indicate to `__decorate` that it can invoke `Object.getOwnPropertyDescriptor` directly. + // We have this extra argument here so that we can inject an explicit property descriptor at a later date. + : createNull() + : undefined; + + return createDecorateHelper( + decoratorExpressions, + prefix, + memberName, + descriptor + ); + } + + /** + * Generates a __decorate helper call for a class constructor. + * + * @param node The class node. + */ + function generateConstructorDecorationStatement(node: ClassDeclaration, decoratedClassAlias: Identifier) { + const expression = generateConstructorDecorationExpression(node, decoratedClassAlias); + return expression ? createStatement(expression) : undefined; + } + + /** + * Generates a __decorate helper call for a class constructor. + * + * @param node The class node. + */ + function generateConstructorDecorationExpression(node: ClassExpression | ClassDeclaration, decoratedClassAlias: Identifier) { + const allDecorators = getAllDecoratorsOfConstructor(node); + const decoratorExpressions = transformAllDecoratorsOfDeclaration(node, allDecorators); + if (!decoratorExpressions) { + return undefined; + } + + // Emit the call to __decorate. Given the class: + // + // @dec + // class C { + // } + // + // The emit for the class is: + // + // C = __decorate([dec], C); + // + + const expression = createAssignment( + getDeclarationName(node), + createDecorateHelper( + decoratorExpressions, + getDeclarationName(node) + ) + ); + + return decoratedClassAlias + ? createAssignment(decoratedClassAlias, expression) + : expression; + } + + /** + * Transforms a decorator into an expression. + * + * @param decorator The decorator node. + */ + function transformDecorator(decorator: Decorator) { + return visitNode(decorator.expression, visitor, isExpression); + } + + /** + * Transforms the decorators of a parameter. + * + * @param decorators The decorators for the parameter at the provided offset. + * @param parameterOffset The offset of the parameter. + */ + function transformDecoratorsOfParameter(decorators: Decorator[], parameterOffset: number) { + let expressions: Expression[]; + if (decorators) { + expressions = []; + for (const decorator of decorators) { + expressions.push(createParamHelper(transformDecorator(decorator), parameterOffset)); + } + } + + return expressions; + } + + /** + * Adds optional type metadata for a declaration. + * + * @param node The declaration node. + * @param decoratorExpressions The destination array to which to add new decorator expressions. + */ + function addTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) { + if (compilerOptions.emitDecoratorMetadata) { + if (shouldAddTypeMetadata(node)) { + decoratorExpressions.push(createMetadataHelper("design:type", serializeTypeOfNode(node), /*defer*/ true)); + } + if (shouldAddParamTypesMetadata(node)) { + decoratorExpressions.push(createMetadataHelper("design:paramtypes", serializeParameterTypesOfNode(node), /*defer*/ true)); + } + if (shouldAddReturnTypeMetadata(node)) { + decoratorExpressions.push(createMetadataHelper("design:returntype", serializeReturnTypeOfNode(node), /*defer*/ true)); + } + } + } + + /** + * Determines whether to emit the "design:type" metadata based on the node's kind. + * The caller should have already tested whether the node has decorators and whether the + * emitDecoratorMetadata compiler option is set. + * + * @param node The node to test. + */ + function shouldAddTypeMetadata(node: Declaration): boolean { + const kind = node.kind; + return kind === SyntaxKind.MethodDeclaration + || kind === SyntaxKind.GetAccessor + || kind === SyntaxKind.SetAccessor + || kind === SyntaxKind.PropertyDeclaration; + } + + /** + * Determines whether to emit the "design:returntype" metadata based on the node's kind. + * The caller should have already tested whether the node has decorators and whether the + * emitDecoratorMetadata compiler option is set. + * + * @param node The node to test. + */ + function shouldAddReturnTypeMetadata(node: Declaration): boolean { + return node.kind === SyntaxKind.MethodDeclaration; + } + + /** + * Determines whether to emit the "design:paramtypes" metadata based on the node's kind. + * The caller should have already tested whether the node has decorators and whether the + * emitDecoratorMetadata compiler option is set. + * + * @param node The node to test. + */ + function shouldAddParamTypesMetadata(node: Declaration): boolean { + const kind = node.kind; + return kind === SyntaxKind.ClassDeclaration + || kind === SyntaxKind.ClassExpression + || kind === SyntaxKind.MethodDeclaration + || kind === SyntaxKind.GetAccessor + || kind === SyntaxKind.SetAccessor; + } + + /** + * Serializes the type of a node for use with decorator type metadata. + * + * @param node The node that should have its type serialized. + */ + function serializeTypeOfNode(node: Node): Expression { + switch (node.kind) { + case SyntaxKind.PropertyDeclaration: + case SyntaxKind.Parameter: + case SyntaxKind.GetAccessor: + return serializeTypeNode((node).type); + case SyntaxKind.SetAccessor: + return serializeTypeNode(getSetAccessorTypeAnnotationNode(node)); + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.MethodDeclaration: + return createIdentifier("Function"); + default: + return createVoidZero(); + } + } + + /** + * Gets the most likely element type for a TypeNode. This is not an exhaustive test + * as it assumes a rest argument can only be an array type (either T[], or Array). + * + * @param node The type node. + */ + function getRestParameterElementType(node: TypeNode) { + if (node.kind === SyntaxKind.ArrayType) { + return (node).elementType; + } + else if (node.kind === SyntaxKind.TypeReference) { + return singleOrUndefined((node).typeArguments); + } + else { + return undefined; + } + } + + /** + * Serializes the types of the parameters of a node for use with decorator type metadata. + * + * @param node The node that should have its parameter types serialized. + */ + function serializeParameterTypesOfNode(node: Node): Expression { + const valueDeclaration = + isClassLike(node) + ? getFirstConstructorWithBody(node) + : isFunctionLike(node) && nodeIsPresent(node.body) + ? node + : undefined; + + const expressions: Expression[] = []; + if (valueDeclaration) { + for (const parameter of valueDeclaration.parameters) { + if (parameter.dotDotDotToken) { + expressions.push(serializeTypeNode(getRestParameterElementType(parameter.type))); + } + else { + expressions.push(serializeTypeOfNode(parameter)); + } + } + } + + return createArrayLiteral(expressions); + } + + /** + * Serializes the return type of a node for use with decorator type metadata. + * + * @param node The node that should have its return type serialized. + */ + function serializeReturnTypeOfNode(node: Node): Expression { + if (isFunctionLike(node)) { + return serializeTypeNode(node.type); + } + + return undefined; + } + + /** + * Serializes a type node for use with decorator type metadata. + * + * Types are serialized in the following fashion: + * - Void types point to "undefined" (e.g. "void 0") + * - Function and Constructor types point to the global "Function" constructor. + * - Interface types with a call or construct signature types point to the global + * "Function" constructor. + * - Array and Tuple types point to the global "Array" constructor. + * - Type predicates and booleans point to the global "Boolean" constructor. + * - String literal types and strings point to the global "String" constructor. + * - Enum and number types point to the global "Number" constructor. + * - Symbol types point to the global "Symbol" constructor. + * - Type references to classes (or class-like variables) point to the constructor for the class. + * - Anything else points to the global "Object" constructor. + * + * @param node The type node to serialize. + */ + function serializeTypeNode(node: TypeNode): Expression { + if (node === undefined) { + return createIdentifier("Object"); + } + + switch (node.kind) { + case SyntaxKind.VoidKeyword: + return createVoidZero(); + + case SyntaxKind.ParenthesizedType: + return serializeTypeNode((node).type); + + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + return createIdentifier("Function"); + + case SyntaxKind.ArrayType: + case SyntaxKind.TupleType: + return createIdentifier("Array"); + + case SyntaxKind.TypePredicate: + case SyntaxKind.BooleanKeyword: + return createIdentifier("Boolean"); + + case SyntaxKind.StringKeyword: + case SyntaxKind.StringLiteral: + return createIdentifier("String"); + + case SyntaxKind.NumberKeyword: + return createIdentifier("Number"); + + case SyntaxKind.SymbolKeyword: + return languageVersion < ScriptTarget.ES6 + ? getGlobalSymbolNameWithFallback() + : createIdentifier("Symbol"); + + case SyntaxKind.TypeReference: + return serializeTypeReferenceNode(node); + + case SyntaxKind.TypeQuery: + case SyntaxKind.TypeLiteral: + case SyntaxKind.UnionType: + case SyntaxKind.IntersectionType: + case SyntaxKind.AnyKeyword: + break; + + default: + Debug.failBadSyntaxKind(node); + break; + } + + return createIdentifier("Object"); + } + + /** + * Serializes a TypeReferenceNode to an appropriate JS constructor value for use with + * decorator type metadata. + * + * @param node The type reference node. + */ + function serializeTypeReferenceNode(node: TypeReferenceNode) { + // Clone the type name and parent it to a location outside of the current declaration. + const typeName = cloneEntityName(node.typeName, currentScope); + switch (resolver.getTypeReferenceSerializationKind(typeName)) { + case TypeReferenceSerializationKind.Unknown: + const serialized = serializeEntityNameAsExpression(typeName, /*useFallback*/ true); + const temp = createTempVariable(); + hoistVariableDeclaration(temp); + return createLogicalOr( + createLogicalAnd( + createStrictEquality( + createTypeOf( + createAssignment(temp, serialized) + ), + createLiteral("function") + ), + temp + ), + createIdentifier("Object") + ); + + case TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue: + return serializeEntityNameAsExpression(typeName, /*useFallback*/ false); + + case TypeReferenceSerializationKind.VoidType: + return createVoidZero(); + + case TypeReferenceSerializationKind.BooleanType: + return createIdentifier("Boolean"); + + case TypeReferenceSerializationKind.NumberLikeType: + return createIdentifier("Number"); + + case TypeReferenceSerializationKind.StringLikeType: + return createIdentifier("String"); + + case TypeReferenceSerializationKind.ArrayLikeType: + return createIdentifier("Array"); + + case TypeReferenceSerializationKind.ESSymbolType: + return languageVersion < ScriptTarget.ES6 + ? getGlobalSymbolNameWithFallback() + : createIdentifier("Symbol"); + + case TypeReferenceSerializationKind.TypeWithCallSignature: + return createIdentifier("Function"); + + case TypeReferenceSerializationKind.ObjectType: + default: + return createIdentifier("Object"); + } + } + + /** + * Serializes an entity name as an expression for decorator type metadata. + * + * @param node The entity name to serialize. + * @param useFallback A value indicating whether to use logical operators to test for the + * entity name at runtime. + */ + function serializeEntityNameAsExpression(node: EntityName, useFallback: boolean): Expression { + switch (node.kind) { + case SyntaxKind.Identifier: + if (useFallback) { + return createLogicalAnd( + createStrictInequality( + createTypeOf(node), + createLiteral("undefined") + ), + node + ); + } + + return node; + + case SyntaxKind.QualifiedName: + return serializeQualifiedNameAsExpression(node, useFallback); + } + } + + /** + * Serializes an qualified name as an expression for decorator type metadata. + * + * @param node The qualified name to serialize. + * @param useFallback A value indicating whether to use logical operators to test for the + * qualified name at runtime. + */ + function serializeQualifiedNameAsExpression(node: QualifiedName, useFallback: boolean): Expression { + let left: Expression; + if (node.left.kind === SyntaxKind.Identifier) { + left = serializeEntityNameAsExpression(node.left, useFallback); + } + else if (useFallback) { + const temp = createTempVariable(); + hoistVariableDeclaration(temp); + left = createLogicalAnd( + createAssignment( + temp, + serializeEntityNameAsExpression(node.left, /*useFallback*/ true) + ), + temp + ); + } + else { + left = serializeEntityNameAsExpression(node.left, /*useFallback*/ false); + } + + return createPropertyAccess(left, node.right); + } + + /** + * Gets an expression that points to the global "Symbol" constructor at runtime if it is + * available. + */ + function getGlobalSymbolNameWithFallback(): Expression { + return createConditional( + createStrictEquality( + createTypeOf(createIdentifier("Symbol")), + createLiteral("function") + ), + createIdentifier("Symbol"), + createIdentifier("Object") + ); + } + + /** + * Gets an expression that represents a property name. For a computed property, a + * name is generated for the node. + * + * @param member The member whose name should be converted into an expression. + */ + function getExpressionForPropertyName(member: ClassElement | EnumMember): Expression { + const name = member.name; + if (isComputedPropertyName(name)) { + return getGeneratedNameForNode(name); + } + else if (isIdentifier(name)) { + return createLiteral(name.text); + } + else { + return getSynthesizedClone(name); + } + } + + /** + * Visits the property name of a class element, for use when emitting property + * initializers. For a computed property on a node with decorators, a temporary + * value is stored for later use. + * + * @param member The member whose name should be visited. + */ + function visitPropertyNameOfClassElement(member: ClassElement): PropertyName { + const name = member.name; + if (isComputedPropertyName(name)) { + let expression = visitNode(name.expression, visitor, isExpression); + if (member.decorators) { + const generatedName = getGeneratedNameForNode(name); + hoistVariableDeclaration(generatedName); + expression = createAssignment(generatedName, expression); + } + + return setOriginalNode( + createComputedPropertyName(expression, /*location*/ name), + name + ); + } + else { + return getSynthesizedClone(name); + } + } + + /** + * Transforms a HeritageClause with TypeScript syntax. + * + * This function will only be called when one of the following conditions are met: + * - The node is a non-`extends` heritage clause that should be elided. + * - The node is an `extends` heritage clause that should be visited, but only allow a single type. + * + * @param node The HeritageClause to transform. + */ + function visitHeritageClause(node: HeritageClause): HeritageClause { + if (node.token === SyntaxKind.ExtendsKeyword) { + const types = visitNodes(node.types, visitor, isExpressionWithTypeArguments, 0, 1); + return createHeritageClause( + SyntaxKind.ExtendsKeyword, + types, + node + ); + } + + return undefined; + } + + /** + * Transforms an ExpressionWithTypeArguments with TypeScript syntax. + * + * This function will only be called when one of the following conditions are met: + * - The node contains type arguments that should be elided. + * + * @param node The ExpressionWithTypeArguments to transform. + */ + function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments): ExpressionWithTypeArguments { + const expression = visitNode(node.expression, visitor, isLeftHandSideExpression); + return createExpressionWithTypeArguments( + expression, + node + ); + } + + /** + * Visits a method declaration of a class. + * + * This function will be called when one of the following conditions are met: + * - The node is an overload + * - The node is marked as abstract + * - The node is marked as async + * - The node has both a decorator and a computed property name + * + * @param node The method node. + */ + function visitMethodDeclaration(node: MethodDeclaration) { + if (shouldElideFunctionLikeDeclaration(node)) { + return undefined; + } + + return createMethod( + visitNodes(node.modifiers, visitor, isModifier), + visitPropertyNameOfClassElement(node), + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBody(node), + node + ); + } + + /** + * Visits a get accessor declaration of a class. + * + * This function will be called when one of the following conditions are met: + * - The node is marked as abstract + * - The node has both a decorator and a computed property name + * + * @param node The get accessor node. + */ + function visitGetAccessor(node: GetAccessorDeclaration) { + if (shouldElideFunctionLikeDeclaration(node)) { + return undefined; + } + + return createGetAccessor( + visitNodes(node.modifiers, visitor, isModifier), + visitPropertyNameOfClassElement(node), + visitEachChild(node.body, visitor, context), + node + ); + } + + /** + * Visits a set accessor declaration of a class. + * + * This function will be called when one of the following conditions are met: + * - The node is marked as abstract + * - The node has both a decorator and a computed property name + * + * @param node The set accessor node. + */ + function visitSetAccessor(node: SetAccessorDeclaration) { + if (shouldElideFunctionLikeDeclaration(node)) { + return undefined; + } + + return createSetAccessor( + visitNodes(node.modifiers, visitor, isModifier), + visitPropertyNameOfClassElement(node), + visitNode(firstOrUndefined(node.parameters), visitor, isParameter), + visitEachChild(node.body, visitor, context), + node + ); + } + + /** + * Visits a function declaration. + * + * This function will be called when one of the following conditions are met: + * - The node is an overload + * - The node is marked async + * - The node is exported from a TypeScript namespace + * + * @param node The function node. + */ + function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { + if (shouldElideFunctionLikeDeclaration(node)) { + return undefined; + } + + const func = createFunctionDeclaration( + visitNodes(node.modifiers, visitor, isModifier), + node.asteriskToken, + node.name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBody(node), + node + ); + + if (isNamespaceExport(node)) { + return [ + func, + createNamespaceExport(getSynthesizedClone(node.name), getSynthesizedClone(node.name)) + ]; + } + + return func; + } + + /** + * Visits a function expression node. + * + * This function will be called when one of the following conditions are met: + * - The node is marked async + * + * @param node The function expression node. + */ + function visitFunctionExpression(node: FunctionExpression) { + return createFunctionExpression( + node.asteriskToken, + node.name, + visitNodes(node.parameters, visitor, isParameter), + transformFunctionBody(node), + node + ); + } + + /** + * Determines whether a function-like declaration should be elided. A declaration should + * be elided if it is an overload, is abstract, or is an ambient declaration. + * + * @param node The declaration node. + */ + function shouldElideFunctionLikeDeclaration(node: FunctionLikeDeclaration) { + return node.body === undefined + || hasModifier(node, ModifierFlags.Abstract | ModifierFlags.Ambient); + } + + /** + * @remarks + * This function will be called when one of the following conditions are met: + * - The node is marked async + */ + function visitArrowFunction(node: ArrowFunction) { + return createArrowFunction( + visitNodes(node.parameters, visitor, isParameter), + transformConciseBody(node), + node + ); + } + + function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { + if (isAsyncFunctionLike(node)) { + return transformAsyncFunctionBody(node); + } + + return transformFunctionBodyWorker(node.body); + } + + function transformFunctionBodyWorker(body: Block) { + const savedCurrentScope = currentScope; + currentScope = body; + startLexicalEnvironment(); + const visited = visitEachChild(body, visitor, context); + const declarations = endLexicalEnvironment(); + currentScope = savedCurrentScope; + return mergeFunctionBodyLexicalEnvironment(visited, declarations); + } + + function transformConciseBody(node: ArrowFunction): ConciseBody { + if (isAsyncFunctionLike(node)) { + return transformAsyncFunctionBody(node); + } + + return transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ false); + } + + function transformConciseBodyWorker(body: Block | Expression, forceBlockFunctionBody: boolean) { + if (isBlock(body)) { + return transformFunctionBodyWorker(body); + } + else { + startLexicalEnvironment(); + const visited: Expression | Block = visitNode(body, visitor, isConciseBody); + const declarations = endLexicalEnvironment(); + const merged = mergeConciseBodyLexicalEnvironment(visited, declarations); + if (forceBlockFunctionBody && !isBlock(merged)) { + return createBlock([ + createReturn(merged) + ]); + } + else { + return merged; + } + } + } + + function transformAsyncFunctionBody(node: FunctionLikeDeclaration): ConciseBody | FunctionBody { + const promiseConstructor = getEntityNameFromTypeNode(node.type); + const isArrowFunction = node.kind === SyntaxKind.ArrowFunction; + const hasLexicalArguments = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureArguments) !== 0; + + // An async function is emit as an outer function that calls an inner + // generator function. To preserve lexical bindings, we pass the current + // `this` and `arguments` objects to `__awaiter`. The generator function + // passed to `__awaiter` is executed inside of the callback to the + // promise constructor. + // + // The emit for an async arrow without a lexical `arguments` binding might be: + // + // // input + // let a = async (b) => { await b; } + // + // // output + // let a = (b) => __awaiter(this, void 0, void 0, function* () { + // yield b; + // }); + // + // The emit for an async arrow with a lexical `arguments` binding might be: + // + // // input + // let a = async (b) => { await arguments[0]; } + // + // // output + // let a = (b) => __awaiter(this, arguments, void 0, function* (arguments) { + // yield arguments[0]; + // }); + // + // The emit for an async function expression without a lexical `arguments` binding + // might be: + // + // // input + // let a = async function (b) { + // await b; + // } + // + // // output + // let a = function (b) { + // return __awaiter(this, void 0, void 0, function* () { + // yield b; + // }); + // } + // + // The emit for an async function expression with a lexical `arguments` binding + // might be: + // + // // input + // let a = async function (b) { + // await arguments[0]; + // } + // + // // output + // let a = function (b) { + // return __awaiter(this, arguments, void 0, function* (_arguments) { + // yield _arguments[0]; + // }); + // } + // + // The emit for an async function expression with a lexical `arguments` binding + // and a return type annotation might be: + // + // // input + // let a = async function (b): MyPromise { + // await arguments[0]; + // } + // + // // output + // let a = function (b) { + // return __awaiter(this, arguments, MyPromise, function* (_arguments) { + // yield _arguments[0]; + // }); + // } + // + + if (!isArrowFunction) { + const statements: Statement[] = []; + + addNode(statements, + createReturn( + createAwaiterHelper( + hasLexicalArguments, + promiseConstructor, + transformFunctionBodyWorker(node.body) + ) + ) + ); + + const block = createBlock(statements, /*location*/ node.body); + + // Minor optimization, emit `_super` helper to capture `super` access in an arrow. + // This step isn't needed if we eventually transform this to ES5. + if (languageVersion >= ScriptTarget.ES6) { + if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) { + enableExpressionSubstitutionForAsyncMethodsWithSuper(); + setNodeEmitFlags(block, NodeEmitFlags.EmitAdvancedSuperHelper); + } + else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) { + enableExpressionSubstitutionForAsyncMethodsWithSuper(); + setNodeEmitFlags(block, NodeEmitFlags.EmitSuperHelper); + } + } + + return block; + } + else { + return createAwaiterHelper( + hasLexicalArguments, + promiseConstructor, + transformConciseBodyWorker(node.body, /*forceBlockFunctionBody*/ true) + ); + } + } + + /** + * Visits a parameter declaration node. + * + * This function will be called when one of the following conditions are met: + * - The node has an accessibility modifier. + * + * @param node The parameter declaration node. + */ + function visitParameter(node: ParameterDeclaration) { + Debug.assert(!node.dotDotDotToken); + return createParameter( + visitNode(node.name, visitor, isBindingName), + visitNode(node.initializer, visitor, isExpression) + ); + } + + /** + * Visits a variable statement in a namespace. + * + * This function will be called when one of the following conditions are met: + * - The node is exported from a TypeScript namespace. + */ + function visitVariableStatement(node: VariableStatement): Statement { + if (isNamespaceExport(node)) { + const variables = getInitializedVariables(node.declarationList); + if (variables.length === 0) { + // elide statement if there are no initialized variables. + return undefined; + } + + return createStatement( + inlineExpressions( + map(variables, transformInitializedVariable) + ), + /*location*/ node + ); + } + else { + return visitEachChild(node, visitor, context); + } + } + + function transformInitializedVariable(node: VariableDeclaration): Expression { + const name = node.name; + if (isBindingPattern(name)) { + return flattenVariableDestructuringToExpression( + node, + hoistVariableDeclaration, + getNamespaceMemberName, + visitor + ); + } + else { + return createAssignment( + getNamespaceMemberName(name), + visitNode(node.initializer, visitor, isExpression) + ); + } + } + + /** + * Visits an enum declaration. + * + * This function will be called any time a TypeScript enum is encountered. + * + * @param node The enum declaration node. + */ + function visitEnumDeclaration(node: EnumDeclaration): VisitResult { + if (shouldElideEnumDeclaration(node)) { + return undefined; + } + + const savedCurrentNamespaceLocalName = currentNamespaceLocalName; + const statements: Statement[] = []; + + let location: TextRange = node; + if (!isExported(node) || (isExternalModuleExport(node) && isFirstDeclarationOfKind(node, SyntaxKind.EnumDeclaration))) { + // Emit a VariableStatement if the enum is not exported, or is the first enum + // with the same name exported from an external module. + addNode(statements, + createVariableStatement( + visitNodes(node.modifiers, visitor, isModifier), + createVariableDeclarationList([ + createVariableDeclaration(node.name) + ]), + location + ) + ); + location = undefined; + } + + const name = isNamespaceExport(node) + ? getNamespaceMemberName(node.name) + : getSynthesizedClone(node.name); + + currentNamespaceLocalName = getGeneratedNameForNode(node); + addNode(statements, + createStatement( + createCall( + createParen( + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + [createParameter(currentNamespaceLocalName)], + transformEnumBody(node) + ) + ), + [createLogicalOr( + name, + createAssignment( + name, + createObjectLiteral() + ) + )] + ), + location + ) + ); + + if (isNamespaceExport(node)) { + addNode(statements, + createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList([ + createVariableDeclaration(node.name, name) + ]), + location + ) + ); + } + + currentNamespaceLocalName = savedCurrentNamespaceLocalName; + return statements; + } + + /** + * Transforms the body of an enum declaration. + * + * @param node The enum declaration node. + */ + function transformEnumBody(node: EnumDeclaration): Block { + const statements: Statement[] = []; + startLexicalEnvironment(); + addNodes(statements, map(node.members, transformEnumMember)); + addNodes(statements, endLexicalEnvironment()); + return createBlock(statements); + } + + /** + * Transforms an enum member into a statement. + * + * @param member The enum member node. + */ + function transformEnumMember(member: EnumMember): Statement { + const name = getExpressionForPropertyName(member); + return createStatement( + createAssignment( + createElementAccess( + currentNamespaceLocalName, + createAssignment( + createElementAccess( + currentNamespaceLocalName, + name + ), + transformEnumMemberDeclarationValue(member) + ) + ), + name + ), + member + ); + } + + /** + * Transforms the value of an enum member. + * + * @param member The enum member node. + */ + function transformEnumMemberDeclarationValue(member: EnumMember): Expression { + const value = resolver.getConstantValue(member); + if (value !== undefined) { + return createLiteral(value); + } + else if (member.initializer) { + return visitNode(member.initializer, visitor, isExpression); + } + else { + return createVoidZero(); + } + } + + /** + * Determines whether to elide an enum declaration. + * + * @param node The enum declaration node. + */ + function shouldElideEnumDeclaration(node: EnumDeclaration) { + return isConst(node) + && !compilerOptions.preserveConstEnums + && !compilerOptions.isolatedModules; + } + + /** + * Visits an await expression. + * + * This function will be called any time a TypeScript await expression is encountered. + * + * @param node The await expression node. + */ + function visitAwaitExpression(node: AwaitExpression): Expression { + return setOriginalNode( + createYield( + visitNode(node.expression, visitor, isExpression), + /*location*/ node + ), + node + ); + } + + /** + * Visits a parenthesized expression that contains either a type assertion or an `as` + * expression. + * + * @param node The parenthesized expression node. + */ + function visitParenthesizedExpression(node: ParenthesizedExpression): Expression { + // Make sure we consider all nested cast expressions, e.g.: + // (-A).x; + const expression = visitNode(node.expression, visitor, isExpression); + if (currentParent.kind !== SyntaxKind.ArrowFunction) { + // We have an expression of the form: (SubExpr) + // Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is. + // Omitting the parentheses, however, could cause change in the semantics of the generated + // code if the casted expression has a lower precedence than the rest of the expression, e.g.: + // (new A).foo should be emitted as (new A).foo and not new A.foo + // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString() + // new (A()) should be emitted as new (A()) and not new A() + // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} () + if (expression.kind !== SyntaxKind.PrefixUnaryExpression && + expression.kind !== SyntaxKind.VoidExpression && + expression.kind !== SyntaxKind.TypeOfExpression && + expression.kind !== SyntaxKind.DeleteExpression && + expression.kind !== SyntaxKind.PostfixUnaryExpression && + expression.kind !== SyntaxKind.NewExpression && + !(expression.kind === SyntaxKind.CallExpression && currentParent.kind === SyntaxKind.NewExpression) && + !(expression.kind === SyntaxKind.FunctionExpression && currentParent.kind === SyntaxKind.CallExpression) && + !(expression.kind === SyntaxKind.NumericLiteral && currentParent.kind === SyntaxKind.PropertyAccessExpression)) { + return trackChildOfNotEmittedNode(node, expression, node.expression); + } + } + + return setOriginalNode( + createParen(expression, node), + node + ); + } + + function visitAssertionExpression(node: AssertionExpression): Expression { + const expression = visitNode((node).expression, visitor, isExpression); + return trackChildOfNotEmittedNode(node, expression, node.expression); + } + + function trackChildOfNotEmittedNode(parent: Node, child: T, original: T) { + if (!child.parent && !child.original) { + child = getMutableClone(child); + } + + setNodeEmitFlags(parent, NodeEmitFlags.IsNotEmittedNode); + setNodeEmitFlags(child, NodeEmitFlags.EmitCommentsOfNotEmittedParent); + return child; + } + + /** + * Visits a module declaration node. + * + * This function will be called any time a TypeScript namespace (ModuleDeclaration) is encountered. + * + * @param node The module declaration node. + */ + function visitModuleDeclaration(node: ModuleDeclaration): VisitResult { + if (shouldElideModuleDeclaration(node)) { + return undefined; + } + + Debug.assert(isIdentifier(node.name)); + + enableExpressionSubstitutionForNamespaceExports(); + + const savedCurrentNamespaceLocalName = currentNamespaceLocalName; + const modifiers = visitNodes(node.modifiers, visitor, isModifier); + const statements: Statement[] = []; + + let location = node; + if (!isModuleMergedWithClass(node)) { + // var x; + statements.push( + createVariableStatement( + modifiers, + createVariableDeclarationList([ + createVariableDeclaration(node.name) + ]), + location + ) + ); + location = undefined; + } + + const name = isNamespaceExport(node) + ? getNamespaceMemberName(node.name) + : getSynthesizedClone(node.name); + + let moduleParam: Expression = createLogicalOr( + name, + createAssignment( + name, + createObjectLiteral([]) + ) + ); + + if (isNamespaceExport(node)) { + moduleParam = createAssignment(getSynthesizedClone(node.name), moduleParam); + } + + currentNamespaceLocalName = getGeneratedNameForNode(node); + currentNamespace = node; + + // (function (x_1) { + // x_1.y = ...; + // })(x || (x = {})); + statements.push( + setNodeEmitFlags( + setOriginalNode( + createStatement( + createCall( + createParen( + createFunctionExpression( + /*asteriskToken*/ undefined, + /*name*/ undefined, + [createParameter(currentNamespaceLocalName)], + transformModuleBody(node) + ) + ), + [moduleParam] + ) + ), + node + ), + NodeEmitFlags.AdviseOnEmitNode + ) + ); + + currentNamespaceLocalName = savedCurrentNamespaceLocalName; + return statements; + } + + /** + * Transforms the body of a module declaration. + * + * @param node The module declaration node. + */ + function transformModuleBody(node: ModuleDeclaration): Block { + const statements: Statement[] = []; + startLexicalEnvironment(); + const body = node.body; + if (body.kind === SyntaxKind.ModuleBlock) { + addNodes(statements, visitNodes((body).statements, namespaceElementVisitor, isStatement)); + } + else { + addNode(statements, visitModuleDeclaration(body)); + } + + addNodes(statements, endLexicalEnvironment()); + return createBlock(statements); + } + + /** + * Determines whether to elide a module declaration. + * + * @param node The module declaration node. + */ + function shouldElideModuleDeclaration(node: ModuleDeclaration) { + return !isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.isolatedModules); + } + + /** + * Determines whether a module declaration has a name that merges with a class declaration. + * + * @param node The module declaration node. + */ + function isModuleMergedWithClass(node: ModuleDeclaration) { + return !!(resolver.getNodeCheckFlags(getOriginalNode(node)) & NodeCheckFlags.LexicalModuleMergesWithClass); + } + + /** + * Visits an import equals declaration. + * + * @param node The import equals declaration node. + */ + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + Debug.assert(!isExternalModuleImportEqualsDeclaration(node)); + if (shouldElideImportEqualsDeclaration(node)) { + return undefined; + } + + const moduleReference = createExpressionFromEntityName(node.moduleReference); + if (isNamedExternalModuleExport(node) || !isNamespaceExport(node)) { + // export var ${name} = ${moduleReference}; + // var ${name} = ${moduleReference}; + return setOriginalNode( + createVariableStatement( + visitNodes(node.modifiers, visitor, isModifier), + createVariableDeclarationList([ + createVariableDeclaration(node.name, moduleReference) + ]), + node + ), + node + ); + } + else { + // exports.${name} = ${moduleReference}; + return setOriginalNode( + createNamespaceExport( + getSynthesizedClone(node.name), + moduleReference, + node + ), + node + ); + } + } + + /** + * Determines whether to elide an import equals declaration. + * + * @param node The import equals declaration node. + */ + function shouldElideImportEqualsDeclaration(node: ImportEqualsDeclaration) { + // preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when + // - current file is not external module + // - import declaration is top level and target is value imported by entity name + return !resolver.isReferencedAliasDeclaration(node) + && (isExternalModule(currentSourceFile) || !resolver.isTopLevelValueImportEqualsWithEntityName(node)); + } + + /** + * Gets a value indicating whether the node is exported. + * + * @param node The node to test. + */ + function isExported(node: Node) { + return hasModifier(node, ModifierFlags.Export); + } + + /** + * Gets a value indicating whether the node is exported from a namespace. + * + * @param node The node to test. + */ + function isNamespaceExport(node: Node) { + return currentNamespace !== undefined && isExported(node); + } + + /** + * Gets a value indicating whether the node is exported from an external module. + * + * @param node The node to test. + */ + function isExternalModuleExport(node: Node) { + return currentNamespace === undefined && isExported(node); + } + + /** + * Gets a value indicating whether the node is a named export from an external module. + * + * @param node The node to test. + */ + function isNamedExternalModuleExport(node: Node) { + return isExternalModuleExport(node) + && hasModifier(node, ModifierFlags.Default); + } + + /** + * Gets a value indicating whether the node is the default export of an external module. + * + * @param node The node to test. + */ + function isDefaultExternalModuleExport(node: Node) { + return isExternalModuleExport(node) + && hasModifier(node, ModifierFlags.Default); + } + + /** + * Gets a value indicating whether a node is the first declaration of its kind. + * + * @param node A Declaration node. + * @param kind The SyntaxKind to find among related declarations. + */ + function isFirstDeclarationOfKind(node: Declaration, kind: SyntaxKind) { + const original = getOriginalNode(node); + return original.symbol && getDeclarationOfKind(original.symbol, kind) === original; + } + + /** + * Creates a statement for the provided expression. This is used in calls to `map`. + */ + function expressionToStatement(expression: Expression) { + return createStatement(expression, /*location*/ undefined); + } + + function createNamespaceExport(exportName: Identifier, exportValue: Expression, location?: TextRange) { + return createStatement( + createAssignment( + getNamespaceMemberName(exportName), + exportValue + ), + location + ); + } + + function createExternalModuleExport(exportName: Identifier) { + return createExportDeclaration( + createNamedExports([ + createExportSpecifier(exportName) + ]) + ); + } + + function getNamespaceMemberName(name: Identifier): Expression { + return createPropertyAccess(currentNamespaceLocalName, getSynthesizedClone(name)); + } + + function getDeclarationName(node: ClassExpression | ClassDeclaration | FunctionDeclaration | EnumDeclaration) { + return node.name ? getSynthesizedClone(node.name) : getGeneratedNameForNode(node); + } + + function getClassPrototype(node: ClassExpression | ClassDeclaration) { + return createPropertyAccess(getDeclarationName(node), "prototype"); + } + + function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) { + return hasModifier(member, ModifierFlags.Static) + ? getDeclarationName(node) + : getClassPrototype(node); + } + + function isClassWithDecorators(node: Node): node is ClassDeclaration { + return node.kind === SyntaxKind.ClassDeclaration && node.decorators !== undefined; + } + + function isSuperContainer(node: Node): node is SuperContainer { + const kind = node.kind; + return kind === SyntaxKind.ClassDeclaration + || kind === SyntaxKind.Constructor + || kind === SyntaxKind.MethodDeclaration + || kind === SyntaxKind.GetAccessor + || kind === SyntaxKind.SetAccessor; + } + + function isTransformedModuleDeclaration(node: Node): boolean { + return getOriginalNode(node).kind === SyntaxKind.ModuleDeclaration; + } + + function onEmitNode(node: Node, emit: (node: Node) => void): void { + const savedIsEnclosedInNamespace = isEnclosedInNamespace; + const savedCurrentSuperContainer = currentSuperContainer; + + // If we need support substitutions for aliases for decorated classes, + // we should enable it here. + if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses && isClassWithDecorators(node)) { + currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)]; + } + + // If we need to support substitutions for `super` in an async method, + // we should track it here. + if (enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) { + currentSuperContainer = node; + } + + if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) { + isEnclosedInNamespace = true; + } + + previousOnEmitNode(node, emit); + + if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses && isClassWithDecorators(node)) { + currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined; + } + + isEnclosedInNamespace = savedIsEnclosedInNamespace; + currentSuperContainer = savedCurrentSuperContainer; + } + + function substituteExpression(node: Expression): Expression { + node = previousExpressionSubstitution(node); + + switch (node.kind) { + case SyntaxKind.Identifier: + return substituteExpressionIdentifier(node); + } + + if (enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper) { + switch (node.kind) { + case SyntaxKind.CallExpression: + return substituteCallExpression(node); + case SyntaxKind.PropertyAccessExpression: + return substitutePropertyAccessExpression(node); + case SyntaxKind.ElementAccessExpression: + return substituteElementAccessExpression(node); + } + } + + return node; + } + + function substituteExpressionIdentifier(node: Identifier): Expression { + if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) { + const original = getOriginalNode(node); + if (isIdentifier(original)) { + if (resolver.getNodeCheckFlags(original) & NodeCheckFlags.SelfReferenceInDecoratedClass) { + // Due to the emit for class decorators, any reference to the class from inside of the class body + // must instead be rewritten to point to a temporary variable to avoid issues with the double-bind + // behavior of class names in ES6. + const declaration = resolver.getReferencedValueDeclaration(original); + if (declaration) { + const classAlias = currentDecoratedClassAliases[getNodeId(declaration)]; + if (classAlias) { + return getRelocatedClone(classAlias, /*location*/ node); + } + } + } + } + } + + if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isEnclosedInNamespace) { + // If we are nested within a namespace declaration, we may need to qualifiy + // an identifier that is exported from a merged namespace. + const original = getOriginalNode(node); + if (isIdentifier(original) && original.parent) { + const container = resolver.getReferencedExportContainer(original); + if (container && container.kind === SyntaxKind.ModuleDeclaration) { + return createPropertyAccess(getGeneratedNameForNode(container), node, /*location*/ node); + } + } + } + + return node; + } + + function substituteCallExpression(node: CallExpression): Expression { + const expression = node.expression; + if (isSuperProperty(expression)) { + const flags = getSuperContainerAsyncMethodFlags(); + if (flags) { + const argumentExpression = isPropertyAccessExpression(expression) + ? substitutePropertyAccessExpression(expression) + : substituteElementAccessExpression(expression); + return createCall( + createPropertyAccess(argumentExpression, "call"), + [ + createThis(), + ...node.arguments + ] + ); + } + } + return node; + } + + function substitutePropertyAccessExpression(node: PropertyAccessExpression) { + if (node.expression.kind === SyntaxKind.SuperKeyword) { + const flags = getSuperContainerAsyncMethodFlags(); + if (flags) { + return createSuperAccessInAsyncMethod( + createLiteral(node.name.text), + flags, + node + ); + } + } + + return node; + } + + function substituteElementAccessExpression(node: ElementAccessExpression) { + if (node.expression.kind === SyntaxKind.SuperKeyword) { + const flags = getSuperContainerAsyncMethodFlags(); + if (flags) { + return createSuperAccessInAsyncMethod( + node.argumentExpression, + flags, + node + ); + } + } + + return node; + } + + function enableExpressionSubstitutionForAsyncMethodsWithSuper() { + if ((enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper) === 0) { + enabledSubstitutions |= TypeScriptSubstitutionFlags.AsyncMethodsWithSuper; + + // We need to enable substitutions for call, property access, and element access + // if we need to rewrite super calls. + context.enableExpressionSubstitution(SyntaxKind.CallExpression); + context.enableExpressionSubstitution(SyntaxKind.PropertyAccessExpression); + context.enableExpressionSubstitution(SyntaxKind.ElementAccessExpression); + + // We need to be notified when entering and exiting declarations that bind super. + context.enableEmitNotification(SyntaxKind.ClassDeclaration); + context.enableEmitNotification(SyntaxKind.MethodDeclaration); + context.enableEmitNotification(SyntaxKind.GetAccessor); + context.enableEmitNotification(SyntaxKind.SetAccessor); + context.enableEmitNotification(SyntaxKind.Constructor); + } + } + + function enableExpressionSubstitutionForDecoratedClasses() { + if ((enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) === 0) { + enabledSubstitutions |= TypeScriptSubstitutionFlags.DecoratedClasses; + + // We need to enable substitutions for identifiers. This allows us to + // substitute class names inside of a class declaration. + context.enableExpressionSubstitution(SyntaxKind.Identifier); + + // Keep track of class aliases. + decoratedClassAliases = {}; + currentDecoratedClassAliases = {}; + } + } + + function enableExpressionSubstitutionForNamespaceExports() { + if ((enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports) === 0) { + enabledSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports; + + // We need to enable substitutions for identifiers. This allows us to + // substitute the names of exported members of a namespace. + context.enableExpressionSubstitution(SyntaxKind.Identifier); + + // We need to be notified when entering and exiting namespaces. + context.enableEmitNotification(SyntaxKind.ModuleDeclaration); + } + } + + function createSuperAccessInAsyncMethod(argumentExpression: Expression, flags: NodeCheckFlags, location: TextRange): LeftHandSideExpression { + if (flags & NodeCheckFlags.AsyncMethodWithSuperBinding) { + return createPropertyAccess( + createCall( + createIdentifier("_super"), + [argumentExpression] + ), + "value", + location + ); + } + else { + return createCall( + createIdentifier("_super"), + [argumentExpression], + location + ); + } + } + + function getSuperContainerAsyncMethodFlags() { + return currentSuperContainer !== undefined + && resolver.getNodeCheckFlags(getOriginalNode(currentSuperContainer)) & (NodeCheckFlags.AsyncMethodWithSuper | NodeCheckFlags.AsyncMethodWithSuperBinding); + } + } +} \ No newline at end of file diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 889810bebec54..398c87aab2bdc 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -777,4 +777,8 @@ namespace ts { } } +if (ts.sys.developmentMode && ts.sys.tryEnableSourceMapsForHost) { + ts.sys.tryEnableSourceMapsForHost(); +} + ts.executeCommandLine(ts.sys.args); diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 29f39b983f399..07b59ab67bd28 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -20,6 +20,9 @@ "factory.ts", "visitor.ts", "transformer.ts", + "comments.ts", + "printer.ts", + "declarationEmitter.ts", "emitter.ts", "program.ts", "commandLineParser.ts", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1422b611651dd..38d1687acead7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -20,6 +20,7 @@ namespace ts { export interface TextRange { pos: number; end: number; + /* @internal */ disableSourceMap?: boolean; // Whether a synthesized text range disables source maps for its contents (used by transforms). } // token > SyntaxKind.Identifer => token is a keyword @@ -341,7 +342,7 @@ namespace ts { // Synthesized list SyntaxList, - NodeArrayNode, + // Enum value count Count, // Markers @@ -372,18 +373,9 @@ namespace ts { export const enum NodeFlags { None = 0, - Export = 1 << 0, // Declarations - Ambient = 1 << 1, // Declarations - Public = 1 << 2, // Property/Method - Private = 1 << 3, // Property/Method - Protected = 1 << 4, // Property/Method - Static = 1 << 5, // Property/Method - Readonly = 1 << 6, // Property/Method - Abstract = 1 << 7, // Class/Method/ConstructSignature - Async = 1 << 8, // Property/Method/Function - Default = 1 << 9, // Function/Class (export default declaration) - Let = 1 << 10, // Variable declaration - Const = 1 << 11, // Variable declaration + Let = 1 << 0, // Variable declaration + Const = 1 << 1, // Variable declaration + NestedNamespace = 1 << 2, // Namespace declaration Namespace = 1 << 12, // Namespace declaration ExportContext = 1 << 13, // Export context (initialized by binding) ContainsThis = 1 << 14, // Interface contains references to "this" @@ -403,8 +395,6 @@ namespace ts { ThisNodeOrAnySubNodesHasError = 1 << 28, // If this node or any of its children had an error HasAggregatedChildData = 1 << 29, // If we've computed data from children and cached it in this node - Modifier = Export | Ambient | Public | Private | Protected | Static | Abstract | Default | Async, - AccessibilityModifier = Public | Private | Protected, BlockScoped = Let | Const, ReachabilityCheckFlags = HasImplicitReturn | HasExplicitReturn, @@ -417,6 +407,26 @@ namespace ts { TypeExcludesFlags = YieldContext | AwaitContext, } + export const enum ModifierFlags { + None = 0, + Export = 1 << 0, // Declarations + Ambient = 1 << 1, // Declarations + Public = 1 << 2, // Property/Method + Private = 1 << 3, // Property/Method + Protected = 1 << 4, // Property/Method + Static = 1 << 5, // Property/Method + Readonly = 1 << 6, // Property/Method + Abstract = 1 << 7, // Class/Method/ConstructSignature + Async = 1 << 8, // Property/Method/Function + Default = 1 << 9, // Function/Class (export default declaration) + Const = 1 << 11, // Variable declaration + + HasComputedFlags = 1 << 31, // Modifier flags have been computed + + AccessibilityModifier = Public | Private | Protected, + NonPublicAccessibilityModifier = Private | Protected, + } + export const enum JsxFlags { None = 0, /** An element from a named property of the JSX.IntrinsicElements interface */ @@ -442,10 +452,11 @@ namespace ts { export interface Node extends TextRange { kind: SyntaxKind; flags: NodeFlags; + /* @internal */ modifierFlagsCache?: ModifierFlags; /* @internal */ transformFlags?: TransformFlags; /* @internal */ excludeTransformFlags?: TransformFlags; decorators?: NodeArray; // Array of decorators (in document order) - modifiers?: ModifiersArray; // Array of modifiers + modifiers?: NodeArray; // Array of modifiers /* @internal */ id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. @@ -457,33 +468,10 @@ namespace ts { /* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) } - export const enum ArrayKind { - NodeArray = 1, - ModifiersArray = 2, - } - export interface NodeArray extends Array, TextRange { - arrayKind: ArrayKind; hasTrailingComma?: boolean; } - /** - * A NodeArrayNode is a transient node used during transformations to indicate that more than - * one node will substitute a single node in the source. When the source is a NodeArray (as - * part of a call to `visitNodes`), the nodes of a NodeArrayNode will be spread into the - * result array. When the source is a Node (as part of a call to `visitNode`), the NodeArrayNode - * must be converted into a compatible node via the `lift` callback. - */ - /* @internal */ - // @kind(SyntaxKind.NodeArrayNode) - export interface NodeArrayNode extends Node { - nodes: NodeArray; - } - - export interface ModifiersArray extends NodeArray { - flags: number; - } - // @kind(SyntaxKind.AbstractKeyword) // @kind(SyntaxKind.AsyncKeyword) // @kind(SyntaxKind.ConstKeyword) @@ -496,16 +484,19 @@ namespace ts { // @kind(SyntaxKind.StaticKeyword) export interface Modifier extends Node { } - export const enum TempVariableKind { - Auto, // Automatically generated identifier - Loop, // Automatically generated identifier with a preference for '_i' + export const enum GeneratedIdentifierKind { + None, // Not automatically generated. + Auto, // Automatically generated identifier. + Loop, // Automatically generated identifier with a preference for '_i'. + Unique, // Unique name based on the 'text' property. + Node, // Unique name based on the node in the 'original' property. } // @kind(SyntaxKind.Identifier) export interface Identifier extends PrimaryExpression { text: string; // Text of identifier (with escapes converted to characters) - tempKind?: TempVariableKind; // Specifies whether to auto-generate the text for an identifier. originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later + autoGenerateKind?: GeneratedIdentifierKind; // Specifies whether to auto-generate the text for an identifier. } // @kind(SyntaxKind.QualifiedName) @@ -2087,8 +2078,8 @@ namespace ts { CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement HasSeenSuperCall = 0x00080000, // Set during the binding when encounter 'super' - ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body. - BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body. + DecoratedClassWithSelfReference = 0x00100000, // Decorated class that contains a binding to itself inside of the class body. + SelfReferenceInDecoratedClass = 0x00200000, // Binding to a decorated class inside of the class's body. } /* @internal */ @@ -2468,6 +2459,7 @@ namespace ts { allowSyntheticDefaultImports?: boolean; allowJs?: boolean; /* @internal */ stripInternal?: boolean; + /* @internal */ experimentalTransforms?: boolean; // Skip checking lib.d.ts to help speed up tests. /* @internal */ skipDefaultLibCheck?: boolean; @@ -2746,6 +2738,8 @@ namespace ts { /* @internal */ export const enum TransformFlags { + None = 0, + // Facts // - Flags used to indicate that a node or subtree contains syntax that requires transformation. TypeScript = 1 << 0, @@ -2756,18 +2750,21 @@ namespace ts { ContainsES7 = 1 << 5, ES6 = 1 << 6, ContainsES6 = 1 << 7, + DestructuringAssignment = 1 << 8, // Markers // - Flags used to indicate that a subtree contains a specific transformation. - ContainsDecorators = 1 << 8, - ContainsPropertyInitializer = 1 << 9, - ContainsLexicalThis = 1 << 10, - ContainsCapturedLexicalThis = 1 << 11, - ContainsDefaultValueAssignments = 1 << 12, - ContainsParameterPropertyAssignments = 1 << 13, - ContainsSpreadElementExpression = 1 << 14, - ContainsComputedPropertyName = 1 << 15, - ContainsBlockScopedBinding = 1 << 16, + ContainsDecorators = 1 << 9, + ContainsPropertyInitializer = 1 << 10, + ContainsLexicalThis = 1 << 11, + ContainsCapturedLexicalThis = 1 << 12, + ContainsDefaultValueAssignments = 1 << 13, + ContainsParameterPropertyAssignments = 1 << 14, + ContainsSpreadElementExpression = 1 << 15, + ContainsComputedPropertyName = 1 << 16, + ContainsBlockScopedBinding = 1 << 17, + + HasComputedFlags = 1 << 31, // Transform flags have been computed. // Assertions // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. @@ -2779,7 +2776,7 @@ namespace ts { // Scope Exclusions // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. - NodeExcludes = TypeScript | Jsx | ES7 | ES6, + NodeExcludes = TypeScript | Jsx | ES7 | ES6 | DestructuringAssignment | HasComputedFlags, ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, @@ -2793,14 +2790,18 @@ namespace ts { /* @internal */ export const enum NodeEmitFlags { - EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node. - EmitExportStar = 1 << 1, // The export * helper should be written to this node. - EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods. - EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods. - UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper. - NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module. - SingleLine = 1 << 6, // The contents of this node should be emit on a single line. - AdviseOnEmitNode = 1 << 7, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node. + EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node. + EmitExportStar = 1 << 1, // The export * helper should be written to this node. + EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods. + EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods. + UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper. + NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module. + SingleLine = 1 << 6, // The contents of this node should be emit on a single line. + AdviseOnEmitNode = 1 << 7, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node. + IsNotEmittedNode = 1 << 8, // Is a node that is not emitted but whose comments should be preserved if possible. + EmitCommentsOfNotEmittedParent = 1 << 9, // Emits comments of missing parent nodes. + NoSubstitution = 1 << 10, // Disables further substitution of an expression. + CapturesThis = 1 << 11, // The function captures a lexical `this` } /** Additional context provided to `visitEachChild` */ @@ -2820,10 +2821,6 @@ namespace ts { setNodeEmitFlags(node: T, flags: NodeEmitFlags): T; hoistFunctionDeclaration(node: FunctionDeclaration): void; hoistVariableDeclaration(node: Identifier): void; - isUniqueName(name: string): boolean; - getGeneratedNameForNode(node: Node): Identifier; - nodeHasGeneratedName(node: Node): boolean; - makeUniqueName(baseName: string): Identifier; /** * Hook used by transformers to substitute non-expression identifiers @@ -2862,16 +2859,10 @@ namespace ts { isEmitNotificationEnabled(node: Node): boolean; /** - * Hook used to notify transformers immediately before the pretty printer - * emits a node. - */ - onBeforeEmitNode?: (node: Node) => void; - - /** - * Hook used to notify transformers immediately after the pretty printer - * emits a node. + * Hook used to allow transformers to capture state before or after + * the printer emits a node. */ - onAfterEmitNode?: (node: Node) => void; + onEmitNode?: (node: Node, emit: (node: Node) => void) => void; } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e20ba3ac4de61..a08e2211cdb9d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -190,7 +190,7 @@ namespace ts { // However, this node will be 'missing' in the sense that no actual source-code/tokens are // contained within it. export function nodeIsMissing(node: Node) { - if (!node) { + if (node === undefined) { return true; } @@ -240,6 +240,60 @@ namespace ts { return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia); } + export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, languageVersion: ScriptTarget) { + // Any template literal or string literal with an extended escape + // (e.g. "\u{0067}") will need to be downleveled as a escaped string literal. + if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) { + return getQuotedEscapedLiteralText("\"", node.text, "\""); + } + + // If we don't need to downlevel and we can reach the original source text using + // the node's parent reference, then simply get the text as it was originally written. + if (!nodeIsSynthesized(node) && node.parent) { + const text = getSourceTextOfNodeFromSourceFile(sourceFile, node); + if (languageVersion < ScriptTarget.ES6 && isBinaryOrOctalIntegerLiteral(node, text)) { + return node.text; + } + return text; + } + + // If we can't reach the original source text, use the canonical form if it's a number, + // or an escaped quoted form of the original text if it's string-like. + switch (node.kind) { + case SyntaxKind.StringLiteral: + return getQuotedEscapedLiteralText("\"", node.text, "\""); + case SyntaxKind.NoSubstitutionTemplateLiteral: + return getQuotedEscapedLiteralText("`", node.text, "`"); + case SyntaxKind.TemplateHead: + return getQuotedEscapedLiteralText("`", node.text, "${"); + case SyntaxKind.TemplateMiddle: + return getQuotedEscapedLiteralText("}", node.text, "${"); + case SyntaxKind.TemplateTail: + return getQuotedEscapedLiteralText("}", node.text, "`"); + case SyntaxKind.NumericLiteral: + return node.text; + } + + Debug.fail(`Literal kind '${node.kind}' not accounted for.`); + } + + export function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string) { + if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) { + switch (text.charCodeAt(1)) { + case CharacterCodes.b: + case CharacterCodes.B: + case CharacterCodes.o: + case CharacterCodes.O: + return true; + } + } + return false; + } + + function getQuotedEscapedLiteralText(leftQuote: string, text: string, rightQuote: string) { + return leftQuote + escapeNonAsciiCharacters(escapeString(text)) + rightQuote; + } + // Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' export function escapeIdentifier(identifier: string): string { return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier; @@ -269,8 +323,7 @@ namespace ts { export function isBlockScopedContainerTopLevel(node: Node): boolean { return node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.ModuleDeclaration || - isFunctionLike(node) || - isFunctionBlock(node); + isFunctionLike(node); } export function isGlobalScopeAugmentation(module: ModuleDeclaration): boolean { @@ -293,30 +346,41 @@ namespace ts { return false; } + export function isBlockScope(node: Node, parentNode: Node) { + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.CaseBlock: + case SyntaxKind.CatchClause: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + case SyntaxKind.Constructor: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return true; + + case SyntaxKind.Block: + // function block is not considered block-scope container + // see comment in binder.ts: bind(...), case for SyntaxKind.Block + return parentNode && !isFunctionLike(parentNode); + } + + return false; + } + // Gets the nearest enclosing block scope container that has the provided node // as a descendant, that is not the provided node. export function getEnclosingBlockScopeContainer(node: Node): Node { let current = node.parent; while (current) { - if (isFunctionLike(current)) { + if (isBlockScope(current, current.parent)) { return current; } - switch (current.kind) { - case SyntaxKind.SourceFile: - case SyntaxKind.CaseBlock: - case SyntaxKind.CatchClause: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - return current; - case SyntaxKind.Block: - // function block is not considered block-scope container - // see comment in binder.ts: bind(...), case for SyntaxKind.Block - if (!isFunctionLike(current.parent)) { - return current; - } - } current = current.parent; } @@ -427,6 +491,25 @@ namespace ts { return node; } + export function getCombinedModifierFlags(node: Node): ModifierFlags { + node = walkUpBindingElementsAndPatterns(node); + let flags = getModifierFlags(node); + if (node.kind === SyntaxKind.VariableDeclaration) { + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableDeclarationList) { + flags |= getModifierFlags(node); + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableStatement) { + flags |= getModifierFlags(node); + } + + return flags; + } + // Returns the node flags for this node and all relevant parent nodes. This is done so that // nodes like variable declarations and binding elements can returned a view of their flags // that includes the modifiers from their container. i.e. flags like export/declare aren't @@ -455,7 +538,8 @@ namespace ts { } export function isConst(node: Node): boolean { - return !!(getCombinedNodeFlags(node) & NodeFlags.Const); + return !!(getCombinedNodeFlags(node) & NodeFlags.Const) + || !!(getCombinedModifierFlags(node) & ModifierFlags.Const); } export function isLet(node: Node): boolean { @@ -871,19 +955,20 @@ namespace ts { /** * Determines whether a node is a property or element access expression for super. */ - export function isSuperPropertyOrElementAccess(node: Node): node is (PropertyAccessExpression | ElementAccessExpression) { + export function isSuperProperty(node: Node): node is (PropertyAccessExpression | ElementAccessExpression) { return (node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.ElementAccessExpression) && (node).expression.kind === SyntaxKind.SuperKeyword; } - /** - * Determines whether a node is a call to either `super`, or a super property or element access. - */ + export function isSuperPropertyCall(node: Node): node is CallExpression { + return node.kind === SyntaxKind.CallExpression + && isSuperProperty((node).expression); + } + export function isSuperCall(node: Node): node is CallExpression { return node.kind === SyntaxKind.CallExpression - && ((node).expression.kind === SyntaxKind.SuperKeyword - || isSuperPropertyOrElementAccess((node).expression)); + && (node).expression.kind === SyntaxKind.SuperKeyword; } export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression { @@ -945,6 +1030,20 @@ namespace ts { && nodeCanBeDecorated(node); } + export function nodeOrChildIsDecorated(node: Node): boolean { + return nodeIsDecorated(node) || childIsDecorated(node); + } + + export function childIsDecorated(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + return forEach((node).members, nodeOrChildIsDecorated); + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + return forEach((node).parameters, nodeIsDecorated); + } + } + export function isPartOfExpression(node: Node): boolean { switch (node.kind) { case SyntaxKind.SuperKeyword: @@ -1149,6 +1248,23 @@ namespace ts { } } + export function getNamespaceDeclarationNode(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + if (node.kind === SyntaxKind.ImportEqualsDeclaration) { + return node; + } + + const importClause = (node).importClause; + if (importClause && importClause.namedBindings && importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + return importClause.namedBindings; + } + } + + export function isDefaultImport(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration) { + return node.kind === SyntaxKind.ImportDeclaration + && (node).importClause + && !!(node).importClause.name; + } + export function hasQuestionToken(node: Node) { if (node) { switch (node.kind) { @@ -1284,7 +1400,7 @@ namespace ts { - export function isNodeDescendentOf(node: Node, ancestor: Node): boolean { + export function isNodeDescendantOf(node: Node, ancestor: Node): boolean { while (node) { if (node === ancestor) return true; node = node.parent; @@ -1294,7 +1410,7 @@ namespace ts { export function isInAmbientContext(node: Node): boolean { while (node) { - if (node.flags & NodeFlags.Ambient || (node.kind === SyntaxKind.SourceFile && (node as SourceFile).isDeclarationFile)) { + if (hasModifier(node, ModifierFlags.Ambient) || (node.kind === SyntaxKind.SourceFile && (node as SourceFile).isDeclarationFile)) { return true; } node = node.parent; @@ -1462,7 +1578,7 @@ namespace ts { } export function isAsyncFunctionLike(node: Node): boolean { - return isFunctionLike(node) && (node.flags & NodeFlags.Async) !== 0 && !isAccessor(node); + return isFunctionLike(node) && hasModifier(node, ModifierFlags.Async) && !isAccessor(node); } export function isStringOrNumericLiteral(kind: SyntaxKind): boolean { @@ -1570,11 +1686,13 @@ namespace ts { * @param parent The parent for the cloned node. */ export function cloneEntityName(node: EntityName, parent?: Node): EntityName { - const clone = cloneNode(node, node, node.flags, parent); + const clone = getMutableClone(node); + clone.parent = parent; if (isQualifiedName(clone)) { const { left, right } = clone; clone.left = cloneEntityName(left, clone); - clone.right = cloneNode(right, right, right.flags, parent); + clone.right = getMutableClone(right); + clone.right.parent = clone; } return clone; @@ -2178,7 +2296,14 @@ namespace ts { return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type; } - export function getAllAccessorDeclarations(declarations: NodeArray, accessor: AccessorDeclaration) { + export interface AllAccessorDeclarations { + firstAccessor: AccessorDeclaration; + secondAccessor: AccessorDeclaration; + getAccessor: AccessorDeclaration; + setAccessor: AccessorDeclaration; + } + + export function getAllAccessorDeclarations(declarations: NodeArray, accessor: AccessorDeclaration): AllAccessorDeclarations { let firstAccessor: AccessorDeclaration; let secondAccessor: AccessorDeclaration; let getAccessor: AccessorDeclaration; @@ -2198,7 +2323,7 @@ namespace ts { else { forEach(declarations, (member: Declaration) => { if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) - && (member.flags & NodeFlags.Static) === (accessor.flags & NodeFlags.Static)) { + && hasModifier(member, ModifierFlags.Static) === hasModifier(accessor, ModifierFlags.Static)) { const memberName = getPropertyNameForPropertyNameNode(member.name); const accessorName = getPropertyNameForPropertyNameNode(accessor.name); if (memberName === accessorName) { @@ -2236,26 +2361,33 @@ namespace ts { } } - export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string, + export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], leadingSeparator: boolean, trailingSeparator: boolean, newLine: string, writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) { - let emitLeadingSpace = !trailingSeparator; - forEach(comments, comment => { - if (emitLeadingSpace) { + if (comments && comments.length > 0) { + if (leadingSeparator) { writer.write(" "); - emitLeadingSpace = false; } - writeComment(text, lineMap, writer, comment, newLine); - if (comment.hasTrailingNewLine) { - writer.writeLine(); + + let emitInterveningSeparator = false; + for (const comment of comments) { + if (emitInterveningSeparator) { + writer.write(" "); + emitInterveningSeparator = false; + } + + writeComment(text, lineMap, writer, comment, newLine); + if (comment.hasTrailingNewLine) { + writer.writeLine(); + } + else { + emitInterveningSeparator = true; + } } - else if (trailingSeparator) { + + if (emitInterveningSeparator && trailingSeparator) { writer.write(" "); } - else { - // Emit leading space to separate comment during next comment emit - emitLeadingSpace = true; - } - }); + } } /** @@ -2312,7 +2444,7 @@ namespace ts { if (nodeLine >= lastCommentLine + 2) { // Valid detachedComments emitNewLineBeforeLeadingComments(lineMap, writer, node, leadingComments); - emitComments(text, lineMap, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(text, lineMap, writer, detachedComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end }; } } @@ -2424,21 +2556,49 @@ namespace ts { return currentLineIndent; } - export function modifierToFlag(token: SyntaxKind): NodeFlags { + export function hasModifiers(node: Node) { + return getModifierFlags(node) !== ModifierFlags.None; + } + + export function hasModifier(node: Node, flags: ModifierFlags) { + return (getModifierFlags(node) & flags) !== 0; + } + + export function getModifierFlags(node: Node): ModifierFlags { + if (node.modifierFlagsCache & ModifierFlags.HasComputedFlags) { + return node.modifierFlagsCache & ~ModifierFlags.HasComputedFlags; + } + + let flags = ModifierFlags.None; + if (node.modifiers) { + for (const modifier of node.modifiers) { + flags |= modifierToFlag(modifier.kind); + } + } + + if (node.flags & NodeFlags.NestedNamespace) { + flags |= ModifierFlags.Export; + } + + node.modifierFlagsCache = flags | ModifierFlags.HasComputedFlags; + return flags; + } + + export function modifierToFlag(token: SyntaxKind): ModifierFlags { switch (token) { - case SyntaxKind.StaticKeyword: return NodeFlags.Static; - case SyntaxKind.PublicKeyword: return NodeFlags.Public; - case SyntaxKind.ProtectedKeyword: return NodeFlags.Protected; - case SyntaxKind.PrivateKeyword: return NodeFlags.Private; - case SyntaxKind.AbstractKeyword: return NodeFlags.Abstract; - case SyntaxKind.ExportKeyword: return NodeFlags.Export; - case SyntaxKind.DeclareKeyword: return NodeFlags.Ambient; - case SyntaxKind.ConstKeyword: return NodeFlags.Const; - case SyntaxKind.DefaultKeyword: return NodeFlags.Default; - case SyntaxKind.AsyncKeyword: return NodeFlags.Async; - case SyntaxKind.ReadonlyKeyword: return NodeFlags.Readonly; + case SyntaxKind.StaticKeyword: return ModifierFlags.Static; + case SyntaxKind.PublicKeyword: return ModifierFlags.Public; + case SyntaxKind.ProtectedKeyword: return ModifierFlags.Protected; + case SyntaxKind.PrivateKeyword: return ModifierFlags.Private; + case SyntaxKind.AbstractKeyword: return ModifierFlags.Abstract; + case SyntaxKind.ExportKeyword: return ModifierFlags.Export; + case SyntaxKind.DeclareKeyword: return ModifierFlags.Ambient; + case SyntaxKind.ConstKeyword: return ModifierFlags.Const; + case SyntaxKind.DefaultKeyword: return ModifierFlags.Default; + case SyntaxKind.AsyncKeyword: return ModifierFlags.Async; + case SyntaxKind.ReadonlyKeyword: return ModifierFlags.Readonly; } - return 0; + return ModifierFlags.None; } export function isAssignmentOperator(token: SyntaxKind): boolean { @@ -2498,7 +2658,7 @@ namespace ts { } export function getLocalSymbolForExportDefault(symbol: Symbol) { - return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; + return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; } export function hasJavaScriptFileExtension(fileName: string) { @@ -2651,6 +2811,181 @@ namespace ts { return carriageReturnLineFeed; } + /** + * Tests whether a node and its subtree is simple enough to have its position + * information ignored when emitting source maps in a destructuring assignment. + * + * @param node The expression to test. + */ + export function isSimpleExpression(node: Expression): boolean { + return isSimpleExpressionWorker(node, 0); + } + + function isSimpleExpressionWorker(node: Expression, depth: number): boolean { + if (depth <= 5) { + const kind = node.kind; + if (kind === SyntaxKind.StringLiteral + || kind === SyntaxKind.NumericLiteral + || kind === SyntaxKind.RegularExpressionLiteral + || kind === SyntaxKind.NoSubstitutionTemplateLiteral + || kind === SyntaxKind.Identifier + || kind === SyntaxKind.ThisKeyword + || kind === SyntaxKind.SuperKeyword + || kind === SyntaxKind.TrueKeyword + || kind === SyntaxKind.FalseKeyword + || kind === SyntaxKind.NullKeyword) { + return true; + } + else if (kind === SyntaxKind.PropertyAccessExpression) { + return isSimpleExpressionWorker((node).expression, depth + 1); + } + else if (kind === SyntaxKind.ElementAccessExpression) { + return isSimpleExpressionWorker((node).expression, depth + 1) + && isSimpleExpressionWorker((node).argumentExpression, depth + 1); + } + else if (kind === SyntaxKind.PrefixUnaryExpression + || kind === SyntaxKind.PostfixUnaryExpression) { + return isSimpleExpressionWorker((node).operand, depth + 1); + } + else if (kind === SyntaxKind.BinaryExpression) { + return (node).operatorToken.kind !== SyntaxKind.AsteriskAsteriskToken + && isSimpleExpressionWorker((node).left, depth + 1) + && isSimpleExpressionWorker((node).right, depth + 1); + } + else if (kind === SyntaxKind.ConditionalExpression) { + return isSimpleExpressionWorker((node).condition, depth + 1) + && isSimpleExpressionWorker((node).whenTrue, depth + 1) + && isSimpleExpressionWorker((node).whenFalse, depth + 1); + } + else if (kind === SyntaxKind.VoidExpression + || kind === SyntaxKind.TypeOfExpression + || kind === SyntaxKind.DeleteExpression) { + return isSimpleExpressionWorker((node).expression, depth + 1); + } + else if (kind === SyntaxKind.ArrayLiteralExpression) { + return (node).elements.length === 0; + } + else if (kind === SyntaxKind.ObjectLiteralExpression) { + return (node).properties.length === 0; + } + } + + return false; + } + + export function formatSyntaxKind(kind: SyntaxKind): string { + const syntaxKindEnum = (ts).SyntaxKind; + if (syntaxKindEnum) { + for (const name in syntaxKindEnum) { + if (syntaxKindEnum[name] === kind) { + return kind.toString() + " (" + name + ")"; + } + } + } + else { + return kind.toString(); + } + } + + export const enum TextRangeCollapse { + CollapseToStart, + CollapseToEnd, + } + + export function collapseTextRange(range: TextRange, collapse: TextRangeCollapse) { + if (range.pos === range.end) { + return range; + } + + return collapse === TextRangeCollapse.CollapseToStart + ? { pos: range.pos, end: range.pos } + : { pos: range.end, end: range.end }; + } + + export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver) { + const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = []; + const exportSpecifiers: Map = {}; + let exportEquals: ExportAssignment = undefined; + let hasExportStars = false; + for (const node of sourceFile.statements) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + if (!(node).importClause || + resolver.isReferencedAliasDeclaration((node).importClause, /*checkChildren*/ true)) { + // import "mod" + // import x from "mod" where x is referenced + // import * as x from "mod" where x is referenced + // import { x, y } from "mod" where at least one import is referenced + externalImports.push(node); + } + break; + + case SyntaxKind.ImportEqualsDeclaration: + if ((node).moduleReference.kind === SyntaxKind.ExternalModuleReference && resolver.isReferencedAliasDeclaration(node)) { + // import x = require("mod") where x is referenced + externalImports.push(node); + } + break; + + case SyntaxKind.ExportDeclaration: + if ((node).moduleSpecifier) { + if (!(node).exportClause) { + // export * from "mod" + externalImports.push(node); + hasExportStars = true; + } + else if (resolver.isValueAliasDeclaration(node)) { + // export { x, y } from "mod" where at least one export is a value symbol + externalImports.push(node); + } + } + else { + // export { x, y } + for (const specifier of (node).exportClause.elements) { + const name = (specifier.propertyName || specifier.name).text; + if (!exportSpecifiers[name]) { + exportSpecifiers[name] = [specifier]; + } + else { + exportSpecifiers[name].push(specifier); + } + } + } + break; + + case SyntaxKind.ExportAssignment: + if ((node).isExportEquals && !exportEquals) { + // export = x + exportEquals = node; + } + break; + } + } + + return { externalImports, exportSpecifiers, exportEquals, hasExportStars }; + } + + export function copyPrologueDirectives(from: Statement[], to: Statement[]): number { + for (let i = 0; i < from.length; i++) { + if (isPrologueDirective(from[i])) { + addNode(to, from[i]); + } + else { + return i; + } + } + + return from.length; + } + + export function getInitializedVariables(node: VariableDeclarationList) { + return filter(node.declarations, isInitializedVariable); + } + + function isInitializedVariable(node: VariableDeclaration) { + return node.initializer !== undefined; + } + // Node tests // // All node tests in the following list should *not* reference parent pointers so that @@ -2659,11 +2994,8 @@ namespace ts { // Node Arrays export function isNodeArray(array: T[]): array is NodeArray { - return (>array).arrayKind === ArrayKind.NodeArray; - } - - export function isModifiersArray(array: Modifier[]): array is ModifiersArray { - return (array).arrayKind === ArrayKind.ModifiersArray; + return array.hasOwnProperty("pos") + && array.hasOwnProperty("end"); } // Literals @@ -2706,6 +3038,11 @@ namespace ts { return node.kind === SyntaxKind.Identifier; } + export function isGeneratedIdentifier(node: Node): node is Identifier { + // Using `>` here catches both `GeneratedIdentifierKind.None` and `undefined`. + return isIdentifier(node) && node.autoGenerateKind > GeneratedIdentifierKind.None; + } + // Keywords export function isModifier(node: Node): node is Modifier { @@ -2776,7 +3113,8 @@ namespace ts { || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor - || kind === SyntaxKind.IndexSignature; + || kind === SyntaxKind.IndexSignature + || kind === SyntaxKind.SemicolonClassElement; } export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { @@ -3104,6 +3442,10 @@ namespace ts { return node.kind === SyntaxKind.JsxSpreadAttribute; } + export function isJsxAttribute(node: Node): node is JsxAttribute { + return node.kind === SyntaxKind.JsxAttribute; + } + // Clauses export function isCaseOrDefaultClause(node: Node): node is CaseOrDefaultClause { @@ -3136,13 +3478,6 @@ namespace ts { export function isEnumMember(node: Node): node is EnumMember { return node.kind === SyntaxKind.EnumMember; } - - - // Synthesized - - export function isNodeArrayNode(node: Node): node is NodeArrayNode { - return node.kind === SyntaxKind.NodeArrayNode; - } } namespace ts { @@ -3378,6 +3713,6 @@ namespace ts { } export function isParameterPropertyDeclaration(node: ParameterDeclaration): boolean { - return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent); + return hasModifier(node, ModifierFlags.AccessibilityModifier) && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent); } } diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index ead9119e21a91..051c020558a34 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -3,7 +3,8 @@ /* @internal */ namespace ts { - export type OneOrMany = T | NodeArrayNode; + export type VisitResult = T | T[]; + /** * Describes an edge of a Node, used when traversing a syntax tree. */ @@ -133,7 +134,7 @@ namespace ts { { name: "arguments", test: isExpression }, ], [SyntaxKind.NewExpression]: [ - { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForNew }, { name: "typeArguments", test: isTypeNode }, { name: "arguments", test: isExpression }, ], @@ -447,7 +448,7 @@ namespace ts { * @param f The callback function * @param initial The initial value to supply to the reduction. */ - export function reduceEachChild(node: Node, f: (memo: T, node: Node) => T, initial: T) { + export function reduceEachChild(node: Node, f: (memo: T, node: Node) => T, initial: T): T { if (node === undefined) { return undefined; } @@ -477,7 +478,7 @@ namespace ts { * @param optional An optional value indicating whether the Node is itself optional. * @param lift An optional callback to execute to lift a NodeArrayNode into a valid Node. */ - export function visitNode(node: T, visitor: (node: Node) => Node, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray) => T): T { + export function visitNode(node: T, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional?: boolean, lift?: (node: NodeArray) => T): T { return visitNodeWorker(node, visitor, test, optional, lift, /*parenthesize*/ undefined, /*parentNode*/ undefined); } @@ -492,32 +493,38 @@ namespace ts { * @param parenthesize A callback used to parenthesize the node if needed. * @param parentNode A parentNode for the node. */ - function visitNodeWorker(node: Node, visitor: (node: Node) => Node, test: (node: Node) => boolean, optional: boolean, lift: (node: NodeArray) => Node, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): Node { + function visitNodeWorker(node: Node, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, optional: boolean, lift: (node: Node[]) => Node, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node): Node { if (node === undefined) { return undefined; } - let visited = visitor(node); + const visited = visitor(node); if (visited === node) { return node; } - if (visited !== undefined && isNodeArrayNode(visited)) { - visited = (lift || extractSingleNode)((>visited).nodes); - } + let visitedNode: Node; + if (visited === undefined) { + if (!optional) { + Debug.failNotOptional(); + } - if (parenthesize !== undefined && visited !== undefined) { - visited = parenthesize(visited, parentNode); + return undefined; + } + else if (isArray(visited)) { + visitedNode = (lift || extractSingleNode)(visited); + } + else { + visitedNode = visited; } - if (visited === undefined) { - Debug.assert(optional, "Node not optional."); - return undefined; + if (parenthesize !== undefined) { + visitedNode = parenthesize(visitedNode, parentNode); } - Debug.assert(test === undefined || test(visited), "Wrong node type after visit."); - aggregateTransformFlags(visited); - return visited; + Debug.assertNode(visitedNode, test); + aggregateTransformFlags(visitedNode); + return visitedNode; } /** @@ -529,7 +536,7 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - export function visitNodes>(nodes: TArray, visitor: (node: Node) => Node, test: (node: Node) => boolean, start?: number, count?: number): TArray { + export function visitNodes>(nodes: TArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, start?: number, count?: number): TArray { return visitNodesWorker(nodes, visitor, test, /*parenthesize*/ undefined, /*parentNode*/ undefined, start, count); } @@ -542,12 +549,12 @@ namespace ts { * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - function visitNodesWorker(nodes: NodeArray, visitor: (node: Node) => Node, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, start: number, count: number): NodeArray { + function visitNodesWorker(nodes: NodeArray, visitor: (node: Node) => VisitResult, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, start: number, count: number): NodeArray { if (nodes === undefined) { return undefined; } - let updated: Node[]; + let updated: NodeArray; // Ensure start and count have valid values const length = nodes.length; @@ -559,9 +566,12 @@ namespace ts { count = length - start; } - // If we are not visiting all of the original nodes, we must always create a new array. if (start > 0 || count < length) { - updated = []; + // If we are not visiting all of the original nodes, we must always create a new array. + // Since this is a fragment of a node array, we do not copy over the previous location + // and will only copy over `hasTrailingComma` if we are including the last element. + updated = createNodeArray([], /*location*/ undefined, + /*hasTrailingComma*/ nodes.hasTrailingComma && start + count === length); } // Visit each original node. @@ -571,20 +581,14 @@ namespace ts { if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { // Ensure we have a copy of `nodes`, up to the current index. - updated = nodes.slice(0, i); + updated = createNodeArray(nodes.slice(0, i), /*location*/ nodes, nodes.hasTrailingComma); } addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test, parenthesize, parentNode, /*isVisiting*/ visited !== node); } } - if (updated !== undefined) { - return isModifiersArray(nodes) - ? createModifiersArray(updated, nodes) - : createNodeArray(updated, nodes, nodes.hasTrailingComma); - } - - return nodes; + return updated || nodes; } /** @@ -594,8 +598,8 @@ namespace ts { * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ - export function visitEachChild(node: T, visitor: (node: Node) => Node, context: LexicalEnvironment): T; - export function visitEachChild(node: T & Map, visitor: (node: Node) => Node, context: LexicalEnvironment): T { + export function visitEachChild(node: T, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T; + export function visitEachChild(node: T & Map, visitor: (node: Node) => VisitResult, context: LexicalEnvironment): T { if (node === undefined) { return undefined; } @@ -610,17 +614,12 @@ namespace ts { const edgeTraversalPath = nodeEdgeTraversalMap[node.kind]; if (edgeTraversalPath) { - let modifiers: NodeFlags; for (const edge of edgeTraversalPath) { const value = >node[edge.name]; if (value !== undefined) { let visited: Node | NodeArray; if (isArray(value)) { const visitedArray = visitNodesWorker(value, visitor, edge.test, edge.parenthesize, node, 0, value.length); - if (isModifiersArray(visitedArray)) { - modifiers = visitedArray.flags; - } - visited = visitedArray; } else { @@ -629,13 +628,7 @@ namespace ts { if (updated !== undefined || visited !== value) { if (updated === undefined) { - updated = getMutableNode(node); - updated.flags &= ~NodeFlags.Modifier; - } - - if (modifiers) { - updated.flags |= modifiers; - modifiers = undefined; + updated = getMutableClone(node); } if (visited !== value) { @@ -670,9 +663,8 @@ namespace ts { * * @param to The destination array. * @param from The source Node or NodeArrayNode. - * @param test The node test used to validate each node. */ - export function addNode(to: T[], from: OneOrMany, startOnNewLine?: boolean) { + export function addNode(to: T[], from: VisitResult, startOnNewLine?: boolean): void { addNodeWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false); } @@ -681,38 +673,37 @@ namespace ts { * * @param to The destination NodeArray. * @param from The source array of Node or NodeArrayNode. - * @param test The node test used to validate each node. */ - export function addNodes(to: T[], from: OneOrMany[], startOnNewLine?: boolean) { + export function addNodes(to: T[], from: VisitResult[], startOnNewLine?: boolean): void { addNodesWorker(to, from, startOnNewLine, /*test*/ undefined, /*parenthesize*/ undefined, /*parentNode*/ undefined, /*isVisiting*/ false); } - function addNodeWorker(to: Node[], from: OneOrMany, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) { + function addNodeWorker(to: Node[], from: VisitResult, startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void { if (to && from) { - if (isNodeArrayNode(from)) { - addNodesWorker(to, from.nodes, startOnNewLine, test, parenthesize, parentNode, isVisiting); - return; + if (isArray(from)) { + addNodesWorker(to, from, startOnNewLine, test, parenthesize, parentNode, isVisiting); } + else { + const node = parenthesize !== undefined + ? parenthesize(from, parentNode) + : from; - if (parenthesize !== undefined) { - from = parenthesize(from, parentNode); - } + Debug.assertNode(node, test); - Debug.assert(test === undefined || test(from), "Wrong node type after visit."); + if (startOnNewLine) { + node.startsOnNewLine = true; + } - if (startOnNewLine) { - from.startsOnNewLine = true; - } + if (isVisiting) { + aggregateTransformFlags(node); + } - if (isVisiting) { - aggregateTransformFlags(from); + to.push(node); } - - to.push(from); } } - function addNodesWorker(to: Node[], from: OneOrMany[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean) { + function addNodesWorker(to: Node[], from: VisitResult[], startOnNewLine: boolean, test: (node: Node) => boolean, parenthesize: (node: Node, parentNode: Node) => Node, parentNode: Node, isVisiting: boolean): void { if (to && from) { for (const node of from) { addNodeWorker(to, node, startOnNewLine, test, parenthesize, parentNode, isVisiting); @@ -753,9 +744,9 @@ namespace ts { * @param node The SourceFile node. * @param declarations The generated lexical declarations. */ - export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) { + export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]): SourceFile { if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.statements = mergeStatements(mutableNode.statements, declarations); return mutableNode; } @@ -769,10 +760,10 @@ namespace ts { * @param node The ModuleDeclaration node. * @param declarations The generated lexical declarations. */ - export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]) { + export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]): ModuleDeclaration { Debug.assert(node.body.kind === SyntaxKind.ModuleBlock); if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.body = mergeBlockLexicalEnvironment(node.body, declarations); return mutableNode; } @@ -786,10 +777,10 @@ namespace ts { * @param node The function-like node. * @param declarations The generated lexical declarations. */ - function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) { + function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]): FunctionLikeDeclaration { Debug.assert(node.body !== undefined); if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.body = mergeConciseBodyLexicalEnvironment(mutableNode.body, declarations); return mutableNode; } @@ -803,7 +794,7 @@ namespace ts { * @param node The ConciseBody of an arrow function. * @param declarations The lexical declarations to merge. */ - export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]) { + export function mergeFunctionBodyLexicalEnvironment(body: FunctionBody, declarations: Statement[]): FunctionBody { if (declarations !== undefined && declarations.length > 0) { return mergeBlockLexicalEnvironment(body, declarations); } @@ -817,7 +808,7 @@ namespace ts { * @param node The ConciseBody of an arrow function. * @param declarations The lexical declarations to merge. */ - export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]) { + export function mergeConciseBodyLexicalEnvironment(body: ConciseBody, declarations: Statement[]): ConciseBody { if (declarations !== undefined && declarations.length > 0) { if (isBlock(body)) { return mergeBlockLexicalEnvironment(body, declarations); @@ -839,8 +830,8 @@ namespace ts { * @param node The block into which to merge lexical declarations. * @param declarations The lexical declarations to merge. */ - function mergeBlockLexicalEnvironment(node: T, declarations: Statement[]) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + function mergeBlockLexicalEnvironment(node: T, declarations: Statement[]): T { + const mutableNode = getMutableClone(node); mutableNode.statements = mergeStatements(node.statements, declarations); return mutableNode; } @@ -851,7 +842,7 @@ namespace ts { * @param statements The node array to concatentate with the supplied lexical declarations. * @param declarations The lexical declarations to merge. */ - function mergeStatements(statements: NodeArray, declarations: Statement[]) { + function mergeStatements(statements: NodeArray, declarations: Statement[]): NodeArray { return createNodeArray(concatenate(statements, declarations), /*location*/ statements); } @@ -860,7 +851,7 @@ namespace ts { * * @param nodes The NodeArray. */ - export function liftToBlock(nodes: NodeArray) { + export function liftToBlock(nodes: Node[]): Block { Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block."); return createBlock(>nodes); } @@ -870,9 +861,9 @@ namespace ts { * * @param nodes The NodeArray. */ - function extractSingleNode(nodes: NodeArray) { + function extractSingleNode(nodes: Node[]): Node { Debug.assert(nodes.length <= 1, "Too many nodes written to output."); - return nodes.length > 0 ? nodes[0] : undefined; + return singleOrUndefined(nodes); } /** @@ -891,15 +882,15 @@ namespace ts { */ function aggregateTransformFlagsForNode(node: Node): TransformFlags { if (node === undefined) { - return 0; + return TransformFlags.None; } - - if (node.transformFlags === undefined) { + else if (node.transformFlags & TransformFlags.HasComputedFlags) { + return node.transformFlags & ~node.excludeTransformFlags; + } + else { const subtreeFlags = aggregateTransformFlagsForSubtree(node); return computeTransformFlagsForNode(node, subtreeFlags); } - - return node.transformFlags & ~node.excludeTransformFlags; } /** @@ -908,12 +899,12 @@ namespace ts { function aggregateTransformFlagsForSubtree(node: Node): TransformFlags { // We do not transform ambient declarations or types, so there is no need to // recursively aggregate transform flags. - if (node.flags & NodeFlags.Ambient || isTypeNode(node)) { - return 0; + if (hasModifier(node, ModifierFlags.Ambient) || isTypeNode(node)) { + return TransformFlags.None; } // Aggregate the transform flags of each child. - return reduceEachChild(node, aggregateTransformFlagsForChildNode, 0); + return reduceEachChild(node, aggregateTransformFlagsForChildNode, TransformFlags.None); } /** @@ -923,4 +914,43 @@ namespace ts { function aggregateTransformFlagsForChildNode(transformFlags: TransformFlags, child: Node): TransformFlags { return transformFlags | aggregateTransformFlagsForNode(child); } + + export namespace Debug { + export function failNotOptional(message?: string) { + if (shouldAssert(AssertionLevel.Normal)) { + Debug.assert(false, message || "Node not optional."); + } + } + + export function failBadSyntaxKind(node: Node, message?: string) { + if (shouldAssert(AssertionLevel.Normal)) { + Debug.assert(false, + message || "Unexpected node.", + () => `Node ${formatSyntaxKind(node.kind)} was unexpected.`); + } + } + + export function assertNode(node: Node, test: (node: Node) => boolean, message?: string): void { + if (shouldAssert(AssertionLevel.Normal)) { + Debug.assert( + test === undefined || test(node), + message || "Unexpected node.", + () => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`); + }; + } + + function getFunctionName(func: Function) { + if (typeof func !== "function") { + return ""; + } + else if (func.hasOwnProperty("name")) { + return (func).name; + } + else { + const text = Function.prototype.toString.call(func); + const match = /^function\s+([\w\$]+)\s*\(/.exec(text); + return match ? match[1] : ""; + } + } + } } \ No newline at end of file diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 6f20093c7daed..dbcd6c489300f 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -395,7 +395,7 @@ namespace ts.BreakpointResolver { // Breakpoint is possible in variableDeclaration only if there is initialization // or its declaration from 'for of' if (variableDeclaration.initializer || - (variableDeclaration.flags & NodeFlags.Export) || + hasModifier(variableDeclaration, ModifierFlags.Export) || variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) { return textSpanFromVariableDeclaration(variableDeclaration); } @@ -413,7 +413,7 @@ namespace ts.BreakpointResolver { function canHaveSpanInParameterDeclaration(parameter: ParameterDeclaration): boolean { // Breakpoint is possible on parameter only if it has initializer, is a rest parameter, or has public or private modifier return !!parameter.initializer || parameter.dotDotDotToken !== undefined || - !!(parameter.flags & NodeFlags.Public) || !!(parameter.flags & NodeFlags.Private); + hasModifier(parameter, ModifierFlags.Public | ModifierFlags.Private); } function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan { @@ -439,7 +439,7 @@ namespace ts.BreakpointResolver { } function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) { - return !!(functionDeclaration.flags & NodeFlags.Export) || + return hasModifier(functionDeclaration, ModifierFlags.Export) || (functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor); } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index f62c6cb1700dd..04821b35f4ac2 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -130,7 +130,7 @@ namespace ts.NavigationBar { return topLevelNodes; } - + function sortNodes(nodes: Node[]): Node[] { return nodes.slice(0).sort((n1: Declaration, n2: Declaration) => { if (n1.name && n2.name) { @@ -147,7 +147,7 @@ namespace ts.NavigationBar { } }); } - + function addTopLevelNodes(nodes: Node[], topLevelNodes: Node[]): void { nodes = sortNodes(nodes); @@ -178,8 +178,8 @@ namespace ts.NavigationBar { function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration) { if (functionDeclaration.kind === SyntaxKind.FunctionDeclaration) { - // A function declaration is 'top level' if it contains any function declarations - // within it. + // A function declaration is 'top level' if it contains any function declarations + // within it. if (functionDeclaration.body && functionDeclaration.body.kind === SyntaxKind.Block) { // Proper function declarations can only have identifier names if (forEach((functionDeclaration.body).statements, @@ -198,7 +198,7 @@ namespace ts.NavigationBar { return false; } - + function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { let items: ts.NavigationBarItem[] = []; @@ -258,7 +258,7 @@ namespace ts.NavigationBar { if (isBindingPattern((node).name)) { break; } - if ((node.flags & NodeFlags.Modifier) === 0) { + if (!hasModifiers(node)) { return undefined; } return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.memberVariableElement); @@ -395,19 +395,19 @@ namespace ts.NavigationBar { let result: string[] = []; result.push(moduleDeclaration.name.text); - + while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { moduleDeclaration = moduleDeclaration.body; result.push(moduleDeclaration.name.text); - } + } return result.join("."); } function createModuleItem(node: ModuleDeclaration): NavigationBarItem { let moduleName = getModuleName(node); - + let childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); return getNavigationBarItem(moduleName, diff --git a/src/services/services.ts b/src/services/services.ts index 61b68f78dd8d0..e6e306efbc100 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -962,7 +962,7 @@ namespace ts { case SyntaxKind.Parameter: // Only consider properties defined as constructor parameters - if (!(node.flags & NodeFlags.AccessibilityModifier)) { + if (!(getModifierFlags(node) & ModifierFlags.AccessibilityModifier)) { break; } // fall through @@ -2655,7 +2655,7 @@ namespace ts { case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement; case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; case SyntaxKind.EnumMember: return ScriptElementKind.variableElement; - case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + case SyntaxKind.Parameter: return (getModifierFlags(node) & ModifierFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; case SyntaxKind.ImportEqualsDeclaration: case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportClause: @@ -5046,14 +5046,14 @@ namespace ts { } const keywords: Node[] = []; - const modifierFlag: NodeFlags = getFlagFromModifier(modifier); + const modifierFlag: ModifierFlags = getFlagFromModifier(modifier); let nodes: Node[]; switch (container.kind) { case SyntaxKind.ModuleBlock: case SyntaxKind.SourceFile: // Container is either a class declaration or the declaration is a classDeclaration - if (modifierFlag & NodeFlags.Abstract) { + if (modifierFlag & ModifierFlags.Abstract) { nodes = ((declaration).members).concat(declaration); } else { @@ -5070,7 +5070,7 @@ namespace ts { // If we're an accessibility modifier, we're in an instance member and should search // the constructor's parameter list for instance members as well. - if (modifierFlag & NodeFlags.AccessibilityModifier) { + if (modifierFlag & ModifierFlags.AccessibilityModifier) { const constructor = forEach((container).members, member => { return member.kind === SyntaxKind.Constructor && member; }); @@ -5079,7 +5079,7 @@ namespace ts { nodes = nodes.concat(constructor.parameters); } } - else if (modifierFlag & NodeFlags.Abstract) { + else if (modifierFlag & ModifierFlags.Abstract) { nodes = nodes.concat(container); } break; @@ -5088,7 +5088,7 @@ namespace ts { } forEach(nodes, node => { - if (node.modifiers && node.flags & modifierFlag) { + if (getModifierFlags(node) & modifierFlag) { forEach(node.modifiers, child => pushKeywordIf(keywords, child, modifier)); } }); @@ -5098,19 +5098,19 @@ namespace ts { function getFlagFromModifier(modifier: SyntaxKind) { switch (modifier) { case SyntaxKind.PublicKeyword: - return NodeFlags.Public; + return ModifierFlags.Public; case SyntaxKind.PrivateKeyword: - return NodeFlags.Private; + return ModifierFlags.Private; case SyntaxKind.ProtectedKeyword: - return NodeFlags.Protected; + return ModifierFlags.Protected; case SyntaxKind.StaticKeyword: - return NodeFlags.Static; + return ModifierFlags.Static; case SyntaxKind.ExportKeyword: - return NodeFlags.Export; + return ModifierFlags.Export; case SyntaxKind.DeclareKeyword: - return NodeFlags.Ambient; + return ModifierFlags.Ambient; case SyntaxKind.AbstractKeyword: - return NodeFlags.Abstract; + return ModifierFlags.Abstract; default: Debug.fail(); } @@ -5564,7 +5564,7 @@ namespace ts { // If this is private property or method, the scope is the containing class if (symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) { - const privateDeclaration = forEach(symbol.getDeclarations(), d => (d.flags & NodeFlags.Private) ? d : undefined); + const privateDeclaration = forEach(symbol.getDeclarations(), d => (getModifierFlags(d) & ModifierFlags.Private) ? d : undefined); if (privateDeclaration) { return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration); } @@ -5819,7 +5819,7 @@ namespace ts { return undefined; } // Whether 'super' occurs in a static context within a class. - let staticFlag = NodeFlags.Static; + let staticFlag = ModifierFlags.Static; switch (searchSpaceNode.kind) { case SyntaxKind.PropertyDeclaration: @@ -5829,7 +5829,7 @@ namespace ts { case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - staticFlag &= searchSpaceNode.flags; + staticFlag &= getModifierFlags(searchSpaceNode); searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class break; default: @@ -5854,7 +5854,7 @@ namespace ts { // If we have a 'super' container, we must have an enclosing class. // Now make sure the owning class is the same as the search-space // and has the same static qualifier as the original 'super's owner. - if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { + if (container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { references.push(getReferenceEntryFromNode(node)); } }); @@ -5867,7 +5867,7 @@ namespace ts { let searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); // Whether 'this' occurs in a static context within a class. - let staticFlag = NodeFlags.Static; + let staticFlag = ModifierFlags.Static; switch (searchSpaceNode.kind) { case SyntaxKind.MethodDeclaration: @@ -5881,7 +5881,7 @@ namespace ts { case SyntaxKind.Constructor: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - staticFlag &= searchSpaceNode.flags; + staticFlag &= getModifierFlags(searchSpaceNode); searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class break; case SyntaxKind.SourceFile: @@ -5953,7 +5953,7 @@ namespace ts { case SyntaxKind.ClassDeclaration: // Make sure the container belongs to the same class // and has the appropriate static modifier from the original container. - if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) { + if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag) { result.push(getReferenceEntryFromNode(node)); } break; diff --git a/src/services/utilities.ts b/src/services/utilities.ts index afdc85fffd805..9933e8465c603 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -521,15 +521,15 @@ namespace ts { } export function getNodeModifiers(node: Node): string { - let flags = getCombinedNodeFlags(node); + let flags = getCombinedModifierFlags(node); let result: string[] = []; - if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); - if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); - if (flags & NodeFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); - if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & ModifierFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); + if (flags & ModifierFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & ModifierFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); + if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; @@ -615,7 +615,7 @@ namespace ts { // [a,b,c] from: // [a, b, c] = someExpression; if (node.parent.kind === SyntaxKind.BinaryExpression && - (node.parent).left === node && + (node.parent).left === node && (node.parent).operatorToken.kind === SyntaxKind.EqualsToken) { return true; } @@ -629,7 +629,7 @@ namespace ts { // [a, b, c] of // [x, [a, b, c] ] = someExpression - // or + // or // {x, a: {a, b, c} } = someExpression if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) { return true; diff --git a/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.js b/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.js index a0cb50e73826c..63d3739846b04 100644 --- a/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.js +++ b/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.js @@ -28,9 +28,9 @@ var Point = (function () { this.x = x; this.y = y; } - Point.Origin = { x: 0, y: 0 }; return Point; }()); +Point.Origin = { x: 0, y: 0 }; var Point; (function (Point) { Point.Origin = ""; //expected duplicate identifier error @@ -42,9 +42,9 @@ var A; this.x = x; this.y = y; } - Point.Origin = { x: 0, y: 0 }; return Point; }()); + Point.Origin = { x: 0, y: 0 }; A.Point = Point; var Point; (function (Point) { diff --git a/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndNonExportedVarThatShareAName.js b/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndNonExportedVarThatShareAName.js index 3bbf3b98d6ec3..3921546a21cd1 100644 --- a/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndNonExportedVarThatShareAName.js +++ b/tests/baselines/reference/ClassAndModuleThatMergeWithStaticVariableAndNonExportedVarThatShareAName.js @@ -28,9 +28,9 @@ var Point = (function () { this.x = x; this.y = y; } - Point.Origin = { x: 0, y: 0 }; return Point; }()); +Point.Origin = { x: 0, y: 0 }; var Point; (function (Point) { var Origin = ""; // not an error, since not exported @@ -42,9 +42,9 @@ var A; this.x = x; this.y = y; } - Point.Origin = { x: 0, y: 0 }; return Point; }()); + Point.Origin = { x: 0, y: 0 }; A.Point = Point; var Point; (function (Point) { diff --git a/tests/baselines/reference/ClassDeclarationWithInvalidConstOnPropertyDeclaration.js b/tests/baselines/reference/ClassDeclarationWithInvalidConstOnPropertyDeclaration.js index d5c3b3d63f4fc..7633955b22701 100644 --- a/tests/baselines/reference/ClassDeclarationWithInvalidConstOnPropertyDeclaration.js +++ b/tests/baselines/reference/ClassDeclarationWithInvalidConstOnPropertyDeclaration.js @@ -7,6 +7,6 @@ class AtomicNumbers { var AtomicNumbers = (function () { function AtomicNumbers() { } - AtomicNumbers.H = 1; return AtomicNumbers; }()); +AtomicNumbers.H = 1; diff --git a/tests/baselines/reference/ES5SymbolProperty1.js b/tests/baselines/reference/ES5SymbolProperty1.js index 1073a33163de7..ab3f420c95cf2 100644 --- a/tests/baselines/reference/ES5SymbolProperty1.js +++ b/tests/baselines/reference/ES5SymbolProperty1.js @@ -14,7 +14,6 @@ obj[Symbol.foo]; var Symbol; var obj = (_a = {}, _a[Symbol.foo] = 0, - _a -); + _a); obj[Symbol.foo]; var _a; diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json index fbc795c1cb81e..3fe305d4106fd 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 22, - "arrayKind": 1 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json index fbc795c1cb81e..3fe305d4106fd 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 22, - "arrayKind": 1 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json index 118fedcc381d8..7947de57a58f2 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json @@ -21,7 +21,6 @@ }, "length": 1, "pos": 8, - "end": 15, - "arrayKind": 1 + "end": 15 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json index 98453fb802e2d..7a4b97b133672 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noType.json @@ -21,7 +21,6 @@ }, "length": 1, "pos": 8, - "end": 13, - "arrayKind": 1 + "end": 13 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json index d0c036bea7425..746c4056f833c 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json @@ -37,7 +37,6 @@ }, "length": 1, "pos": 8, - "end": 29, - "arrayKind": 1 + "end": 29 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json index e05c296e10b8f..ff4bba576d240 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json @@ -37,7 +37,6 @@ }, "length": 1, "pos": 8, - "end": 29, - "arrayKind": 1 + "end": 29 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json index f731abb0a8e7b..23264572fedaa 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName1.json @@ -38,7 +38,6 @@ }, "length": 1, "pos": 8, - "end": 31, - "arrayKind": 1 + "end": 31 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json index e230dfcd46cee..ceb123b6b34c7 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagBracketedName2.json @@ -38,7 +38,6 @@ }, "length": 1, "pos": 8, - "end": 36, - "arrayKind": 1 + "end": 36 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json index 44173787d277a..19bab08a77b4e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json @@ -37,7 +37,6 @@ }, "length": 1, "pos": 8, - "end": 29, - "arrayKind": 1 + "end": 29 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json index 224eba3501e33..5da9084897e13 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json @@ -37,7 +37,6 @@ }, "length": 1, "pos": 8, - "end": 29, - "arrayKind": 1 + "end": 29 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json index 0a78384e3e798..293d2a4c2124e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json @@ -27,7 +27,6 @@ }, "length": 1, "pos": 8, - "end": 18, - "arrayKind": 1 + "end": 18 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json index bac9b2a02ef3f..a8425d833ae8e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 24, - "arrayKind": 1 + "end": 24 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json index 6f7fb02b529d5..af4fd91964d13 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 24, - "arrayKind": 1 + "end": 24 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json index d64b56b0a2116..ceca9584a2d80 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnsTag1.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 25, - "arrayKind": 1 + "end": 25 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json index 6be165c0c7661..2804a704ba7d5 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag.json @@ -32,13 +32,11 @@ }, "length": 1, "pos": 17, - "end": 19, - "arrayKind": 1 + "end": 19 } }, "length": 1, "pos": 8, - "end": 19, - "arrayKind": 1 + "end": 19 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json index 85485b2514308..a55761a52b79e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag2.json @@ -43,13 +43,11 @@ }, "length": 2, "pos": 17, - "end": 21, - "arrayKind": 1 + "end": 21 } }, "length": 1, "pos": 8, - "end": 21, - "arrayKind": 1 + "end": 21 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json index e846f5daadac5..64e6e206e1115 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag3.json @@ -43,13 +43,11 @@ }, "length": 2, "pos": 17, - "end": 22, - "arrayKind": 1 + "end": 22 } }, "length": 1, "pos": 8, - "end": 22, - "arrayKind": 1 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json index e846f5daadac5..64e6e206e1115 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag4.json @@ -43,13 +43,11 @@ }, "length": 2, "pos": 17, - "end": 22, - "arrayKind": 1 + "end": 22 } }, "length": 1, "pos": 8, - "end": 22, - "arrayKind": 1 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json index 245ed62698066..9b5a4a6c79006 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag5.json @@ -43,13 +43,11 @@ }, "length": 2, "pos": 17, - "end": 23, - "arrayKind": 1 + "end": 23 } }, "length": 1, "pos": 8, - "end": 23, - "arrayKind": 1 + "end": 23 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json index 323770c644e4b..d5c1c997b021d 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.templateTag6.json @@ -43,13 +43,11 @@ }, "length": 2, "pos": 17, - "end": 23, - "arrayKind": 1 + "end": 23 } }, "length": 1, "pos": 8, - "end": 23, - "arrayKind": 1 + "end": 23 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json index 95c96531bdf09..da4650770666b 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json @@ -69,7 +69,6 @@ }, "length": 2, "pos": 8, - "end": 55, - "arrayKind": 1 + "end": 55 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json index 93b84f00324d5..c995aa8bf22bf 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json @@ -37,7 +37,6 @@ }, "length": 1, "pos": 8, - "end": 29, - "arrayKind": 1 + "end": 29 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json index fbc795c1cb81e..3fe305d4106fd 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json @@ -31,7 +31,6 @@ }, "length": 1, "pos": 8, - "end": 22, - "arrayKind": 1 + "end": 22 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json index e02b9ab7dd908..209b9440a8762 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionReturnType1.json @@ -25,7 +25,6 @@ }, "length": 2, "pos": 10, - "end": 25, - "arrayKind": 1 + "end": 25 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json index 94fe0ec2978de..d3be94a76ffab 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType1.json @@ -5,7 +5,6 @@ "parameters": { "length": 0, "pos": 10, - "end": 10, - "arrayKind": 1 + "end": 10 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json index e02b9ab7dd908..209b9440a8762 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.functionType2.json @@ -25,7 +25,6 @@ }, "length": 2, "pos": 10, - "end": 25, - "arrayKind": 1 + "end": 25 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json index 929f0046cffc8..ab9bb050a8996 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType1.json @@ -5,7 +5,6 @@ "members": { "length": 0, "pos": 2, - "end": 2, - "arrayKind": 1 + "end": 2 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json index 8e6eb1fa11a10..73ff5dbfa6076 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType2.json @@ -16,7 +16,6 @@ }, "length": 1, "pos": 2, - "end": 5, - "arrayKind": 1 + "end": 5 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json index ce5dedcaf56c2..0ffac6cba8f40 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType3.json @@ -21,7 +21,6 @@ }, "length": 1, "pos": 2, - "end": 13, - "arrayKind": 1 + "end": 13 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json index 1192b2a3a3ccb..f49c2fd22ae7f 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType4.json @@ -27,7 +27,6 @@ }, "length": 2, "pos": 2, - "end": 10, - "arrayKind": 1 + "end": 10 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json index b31585c8e3716..4474dba8e21f6 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType5.json @@ -32,7 +32,6 @@ }, "length": 2, "pos": 2, - "end": 18, - "arrayKind": 1 + "end": 18 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json index 81ee5b53451e1..a88005b0cec91 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType6.json @@ -32,7 +32,6 @@ }, "length": 2, "pos": 2, - "end": 18, - "arrayKind": 1 + "end": 18 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json index 595798b1a8380..e69f9a746823e 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType7.json @@ -37,7 +37,6 @@ }, "length": 2, "pos": 2, - "end": 26, - "arrayKind": 1 + "end": 26 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json index b4d00c873ce3f..3570193109715 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json @@ -17,7 +17,6 @@ }, "length": 1, "pos": 2, - "end": 10, - "arrayKind": 1 + "end": 10 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json index dd1b017da00b4..dd9ef74f8c616 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.topLevelNoParenUnionType.json @@ -15,7 +15,6 @@ }, "length": 2, "pos": 1, - "end": 14, - "arrayKind": 1 + "end": 14 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json index dbb6f35ab0026..2b5580f762237 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json @@ -5,7 +5,6 @@ "types": { "length": 0, "pos": 2, - "end": 2, - "arrayKind": 1 + "end": 2 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json index 1ab9530626dc5..f741169be4b73 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json @@ -10,7 +10,6 @@ }, "length": 1, "pos": 2, - "end": 8, - "arrayKind": 1 + "end": 8 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json index aaea91528d7be..939eec1cb0c58 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json @@ -15,7 +15,6 @@ }, "length": 2, "pos": 2, - "end": 15, - "arrayKind": 1 + "end": 15 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json index a685de8662208..50b0a702a84aa 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json @@ -20,7 +20,6 @@ }, "length": 3, "pos": 2, - "end": 23, - "arrayKind": 1 + "end": 23 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json index 970c6fe1b1304..282bc8c8e6469 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json @@ -16,7 +16,6 @@ }, "length": 1, "pos": 4, - "end": 10, - "arrayKind": 1 + "end": 10 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json index 913ba27897d8b..570db90795670 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json @@ -21,7 +21,6 @@ }, "length": 2, "pos": 4, - "end": 17, - "arrayKind": 1 + "end": 17 } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json index aae1d6bc1691f..f9301d05cc505 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.unionType.json @@ -15,7 +15,6 @@ }, "length": 2, "pos": 2, - "end": 15, - "arrayKind": 1 + "end": 15 } } \ No newline at end of file diff --git a/tests/baselines/reference/amdImportNotAsPrimaryExpression.js b/tests/baselines/reference/amdImportNotAsPrimaryExpression.js index beb91191bc013..0739792fddd3e 100644 --- a/tests/baselines/reference/amdImportNotAsPrimaryExpression.js +++ b/tests/baselines/reference/amdImportNotAsPrimaryExpression.js @@ -38,9 +38,9 @@ define(["require", "exports"], function (require, exports) { function C1() { this.m1 = 42; } - C1.s1 = true; return C1; }()); + C1.s1 = true; exports.C1 = C1; (function (E1) { E1[E1["A"] = 0] = "A"; diff --git a/tests/baselines/reference/autolift4.js b/tests/baselines/reference/autolift4.js index 8ee1f397d438d..e6790021f63f1 100644 --- a/tests/baselines/reference/autolift4.js +++ b/tests/baselines/reference/autolift4.js @@ -37,9 +37,9 @@ var Point = (function () { Point.prototype.getDist = function () { return Math.sqrt(this.x * this.x + this.y * this.y); }; - Point.origin = new Point(0, 0); return Point; }()); +Point.origin = new Point(0, 0); var Point3D = (function (_super) { __extends(Point3D, _super); function Point3D(x, y, z, m) { diff --git a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js index 06eaa9916e31e..0197d919fef87 100644 --- a/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js +++ b/tests/baselines/reference/blockScopedVariablesUseBeforeDef.js @@ -163,31 +163,35 @@ function foo8() { var x; } function foo9() { - var y = (function () { - function class_3() { - } - class_3.a = x; - return class_3; - }()); + var y = (_a = (function () { + function class_3() { + } + return class_3; + }()), + _a.a = x, + _a); var x; + var _a; } function foo10() { var A = (function () { function A() { } - A.a = x; return A; }()); + A.a = x; var x; } function foo11() { function f() { - var y = (function () { - function class_4() { - } - class_4.a = x; - return class_4; - }()); + var y = (_a = (function () { + function class_4() { + } + return class_4; + }()), + _a.a = x, + _a); + var _a; } var x; } diff --git a/tests/baselines/reference/class2.js b/tests/baselines/reference/class2.js index 6ef78ed46ee9a..91ac89da1092a 100644 --- a/tests/baselines/reference/class2.js +++ b/tests/baselines/reference/class2.js @@ -5,6 +5,6 @@ class foo { constructor() { static f = 3; } } var foo = (function () { function foo() { } - foo.f = 3; return foo; }()); +foo.f = 3; diff --git a/tests/baselines/reference/classExpressionWithDecorator1.js b/tests/baselines/reference/classExpressionWithDecorator1.js index e051e05251bb6..9b52891b5595c 100644 --- a/tests/baselines/reference/classExpressionWithDecorator1.js +++ b/tests/baselines/reference/classExpressionWithDecorator1.js @@ -12,10 +12,10 @@ var v = ; var C = (function () { function C() { } - C.p = 1; - C = __decorate([ - decorate - ], C); return C; }()); +C.p = 1; +C = __decorate([ + decorate +], C); ; diff --git a/tests/baselines/reference/classExpressionWithStaticProperties1.js b/tests/baselines/reference/classExpressionWithStaticProperties1.js index cfe85d97a7184..23d18d7676627 100644 --- a/tests/baselines/reference/classExpressionWithStaticProperties1.js +++ b/tests/baselines/reference/classExpressionWithStaticProperties1.js @@ -2,10 +2,12 @@ var v = class C { static a = 1; static b = 2 }; //// [classExpressionWithStaticProperties1.js] -var v = (function () { - function C() { - } - C.a = 1; - C.b = 2; - return C; -}()); +var v = (_a = (function () { + function C() { + } + return C; + }()), + _a.a = 1, + _a.b = 2, + _a); +var _a; diff --git a/tests/baselines/reference/classExpressionWithStaticProperties2.js b/tests/baselines/reference/classExpressionWithStaticProperties2.js index 134441e0ad950..b9fc03455918f 100644 --- a/tests/baselines/reference/classExpressionWithStaticProperties2.js +++ b/tests/baselines/reference/classExpressionWithStaticProperties2.js @@ -2,9 +2,11 @@ var v = class C { static a = 1; static b }; //// [classExpressionWithStaticProperties2.js] -var v = (function () { - function C() { - } - C.a = 1; - return C; -}()); +var v = (_a = (function () { + function C() { + } + return C; + }()), + _a.a = 1, + _a); +var _a; diff --git a/tests/baselines/reference/classMemberInitializerScoping.js b/tests/baselines/reference/classMemberInitializerScoping.js index 8f78cfb9ac686..52bbaee894570 100644 --- a/tests/baselines/reference/classMemberInitializerScoping.js +++ b/tests/baselines/reference/classMemberInitializerScoping.js @@ -27,9 +27,9 @@ var CCC = (function () { this.y = aaa; this.y = ''; // was: error, cannot assign string to number } - CCC.staticY = aaa; // This shouldnt be error return CCC; }()); +CCC.staticY = aaa; // This shouldnt be error // above is equivalent to this: var aaaa = 1; var CCCC = (function () { diff --git a/tests/baselines/reference/classMemberInitializerWithLamdaScoping.js b/tests/baselines/reference/classMemberInitializerWithLamdaScoping.js index 752220a4cbc5c..c5b661831a23c 100644 --- a/tests/baselines/reference/classMemberInitializerWithLamdaScoping.js +++ b/tests/baselines/reference/classMemberInitializerWithLamdaScoping.js @@ -40,12 +40,12 @@ var Test = (function () { console.log(field); // Using field here shouldnt be error }; } - Test.staticMessageHandler = function () { - var field = Test.field; - console.log(field); // Using field here shouldnt be error - }; return Test; }()); +Test.staticMessageHandler = function () { + var field = Test.field; + console.log(field); // Using field here shouldnt be error +}; var field1; var Test1 = (function () { function Test1(field1) { @@ -56,8 +56,8 @@ var Test1 = (function () { // it would resolve to private field1 and thats not what user intended here. }; } - Test1.staticMessageHandler = function () { - console.log(field1); // This shouldnt be error as its a static property - }; return Test1; }()); +Test1.staticMessageHandler = function () { + console.log(field1); // This shouldnt be error as its a static property +}; diff --git a/tests/baselines/reference/classWithPrivateProperty.js b/tests/baselines/reference/classWithPrivateProperty.js index 6e75797523fb3..c94f1d8ed80a4 100644 --- a/tests/baselines/reference/classWithPrivateProperty.js +++ b/tests/baselines/reference/classWithPrivateProperty.js @@ -32,9 +32,9 @@ var C = (function () { } C.prototype.c = function () { return ''; }; C.f = function () { return ''; }; - C.g = function () { return ''; }; return C; }()); +C.g = function () { return ''; }; var c = new C(); var r1 = c.x; var r2 = c.a; diff --git a/tests/baselines/reference/classWithProtectedProperty.js b/tests/baselines/reference/classWithProtectedProperty.js index 75eadaf4010be..2b2e01e59df10 100644 --- a/tests/baselines/reference/classWithProtectedProperty.js +++ b/tests/baselines/reference/classWithProtectedProperty.js @@ -42,9 +42,9 @@ var C = (function () { } C.prototype.c = function () { return ''; }; C.f = function () { return ''; }; - C.g = function () { return ''; }; return C; }()); +C.g = function () { return ''; }; var D = (function (_super) { __extends(D, _super); function D() { diff --git a/tests/baselines/reference/classWithPublicProperty.js b/tests/baselines/reference/classWithPublicProperty.js index 054713264bd01..47708b7aff391 100644 --- a/tests/baselines/reference/classWithPublicProperty.js +++ b/tests/baselines/reference/classWithPublicProperty.js @@ -30,9 +30,9 @@ var C = (function () { } C.prototype.c = function () { return ''; }; C.f = function () { return ''; }; - C.g = function () { return ''; }; return C; }()); +C.g = function () { return ''; }; // all of these are valid var c = new C(); var r1 = c.x; diff --git a/tests/baselines/reference/cloduleStaticMembers.js b/tests/baselines/reference/cloduleStaticMembers.js index 6095442b6292f..868b9305bdfca 100644 --- a/tests/baselines/reference/cloduleStaticMembers.js +++ b/tests/baselines/reference/cloduleStaticMembers.js @@ -16,10 +16,10 @@ module Clod { var Clod = (function () { function Clod() { } - Clod.x = 10; - Clod.y = 10; return Clod; }()); +Clod.x = 10; +Clod.y = 10; var Clod; (function (Clod) { var p = Clod.x; diff --git a/tests/baselines/reference/commentsOnStaticMembers.js b/tests/baselines/reference/commentsOnStaticMembers.js index 51ed906841d8a..851f9025be350 100644 --- a/tests/baselines/reference/commentsOnStaticMembers.js +++ b/tests/baselines/reference/commentsOnStaticMembers.js @@ -24,13 +24,13 @@ class test { var test = (function () { function test() { } - /** - * p1 comment appears in output - */ - test.p1 = ""; - /** - * p3 comment appears in output - */ - test.p3 = ""; return test; }()); +/** + * p1 comment appears in output + */ +test.p1 = ""; +/** + * p3 comment appears in output + */ +test.p3 = ""; diff --git a/tests/baselines/reference/commonJSImportAsPrimaryExpression.js b/tests/baselines/reference/commonJSImportAsPrimaryExpression.js index 3f49588c10331..b8cf42ea7622a 100644 --- a/tests/baselines/reference/commonJSImportAsPrimaryExpression.js +++ b/tests/baselines/reference/commonJSImportAsPrimaryExpression.js @@ -19,9 +19,9 @@ var C1 = (function () { function C1() { this.m1 = 42; } - C1.s1 = true; return C1; }()); +C1.s1 = true; exports.C1 = C1; //// [foo_1.js] "use strict"; diff --git a/tests/baselines/reference/commonJSImportNotAsPrimaryExpression.js b/tests/baselines/reference/commonJSImportNotAsPrimaryExpression.js index 720554f7e32b1..34d5c343b3c50 100644 --- a/tests/baselines/reference/commonJSImportNotAsPrimaryExpression.js +++ b/tests/baselines/reference/commonJSImportNotAsPrimaryExpression.js @@ -37,9 +37,9 @@ var C1 = (function () { function C1() { this.m1 = 42; } - C1.s1 = true; return C1; }()); +C1.s1 = true; exports.C1 = C1; (function (E1) { E1[E1["A"] = 0] = "A"; diff --git a/tests/baselines/reference/computedPropertyNames10_ES5.js b/tests/baselines/reference/computedPropertyNames10_ES5.js index 14d9235b12b4f..302f9355be850 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES5.js +++ b/tests/baselines/reference/computedPropertyNames10_ES5.js @@ -32,6 +32,5 @@ var v = (_a = {}, _a[true] = function () { }, _a["hello bye"] = function () { }, _a["hello " + a + " bye"] = function () { }, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames11_ES5.js b/tests/baselines/reference/computedPropertyNames11_ES5.js index 0917f82477049..4fc74b30cbec9 100644 --- a/tests/baselines/reference/computedPropertyNames11_ES5.js +++ b/tests/baselines/reference/computedPropertyNames11_ES5.js @@ -68,6 +68,5 @@ var v = (_a = {}, enumerable: true, configurable: true }), - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames12_ES5.js b/tests/baselines/reference/computedPropertyNames12_ES5.js index 2aec8856286cb..10427b5dc13f6 100644 --- a/tests/baselines/reference/computedPropertyNames12_ES5.js +++ b/tests/baselines/reference/computedPropertyNames12_ES5.js @@ -26,6 +26,6 @@ var C = (function () { this[s + n] = 2; this["hello bye"] = 0; } - C["hello " + a + " bye"] = 0; return C; }()); +C["hello " + a + " bye"] = 0; diff --git a/tests/baselines/reference/computedPropertyNames18_ES5.js b/tests/baselines/reference/computedPropertyNames18_ES5.js index b65c7fd4f7dd5..a62af50653196 100644 --- a/tests/baselines/reference/computedPropertyNames18_ES5.js +++ b/tests/baselines/reference/computedPropertyNames18_ES5.js @@ -9,7 +9,6 @@ function foo() { function foo() { var obj = (_a = {}, _a[this.bar] = 0, - _a - ); + _a); var _a; } diff --git a/tests/baselines/reference/computedPropertyNames19_ES5.js b/tests/baselines/reference/computedPropertyNames19_ES5.js index 36f3e66c7c268..bda3e01bbede8 100644 --- a/tests/baselines/reference/computedPropertyNames19_ES5.js +++ b/tests/baselines/reference/computedPropertyNames19_ES5.js @@ -10,7 +10,6 @@ var M; (function (M) { var obj = (_a = {}, _a[this.bar] = 0, - _a - ); + _a); var _a; })(M || (M = {})); diff --git a/tests/baselines/reference/computedPropertyNames1_ES5.js b/tests/baselines/reference/computedPropertyNames1_ES5.js index 4fdec28c7aa41..75bbe909927ce 100644 --- a/tests/baselines/reference/computedPropertyNames1_ES5.js +++ b/tests/baselines/reference/computedPropertyNames1_ES5.js @@ -17,6 +17,5 @@ var v = (_a = {}, enumerable: true, configurable: true }), - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames20_ES5.js b/tests/baselines/reference/computedPropertyNames20_ES5.js index 65acd7fa08f14..1eec0a7bcdba3 100644 --- a/tests/baselines/reference/computedPropertyNames20_ES5.js +++ b/tests/baselines/reference/computedPropertyNames20_ES5.js @@ -6,6 +6,5 @@ var obj = { //// [computedPropertyNames20_ES5.js] var obj = (_a = {}, _a[this.bar] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames22_ES5.js b/tests/baselines/reference/computedPropertyNames22_ES5.js index 5448f4dcf8d1b..721418ee930d4 100644 --- a/tests/baselines/reference/computedPropertyNames22_ES5.js +++ b/tests/baselines/reference/computedPropertyNames22_ES5.js @@ -15,8 +15,7 @@ var C = (function () { C.prototype.bar = function () { var obj = (_a = {}, _a[this.bar()] = function () { }, - _a - ); + _a); return 0; var _a; }; diff --git a/tests/baselines/reference/computedPropertyNames25_ES5.js b/tests/baselines/reference/computedPropertyNames25_ES5.js index f38ac0b2e0d30..b03dd285ced24 100644 --- a/tests/baselines/reference/computedPropertyNames25_ES5.js +++ b/tests/baselines/reference/computedPropertyNames25_ES5.js @@ -35,8 +35,7 @@ var C = (function (_super) { C.prototype.foo = function () { var obj = (_a = {}, _a[_super.prototype.bar.call(this)] = function () { }, - _a - ); + _a); return 0; var _a; }; diff --git a/tests/baselines/reference/computedPropertyNames28_ES5.js b/tests/baselines/reference/computedPropertyNames28_ES5.js index b5b1fdf77aab7..ed15bbf0145cf 100644 --- a/tests/baselines/reference/computedPropertyNames28_ES5.js +++ b/tests/baselines/reference/computedPropertyNames28_ES5.js @@ -27,8 +27,7 @@ var C = (function (_super) { _super.call(this); var obj = (_a = {}, _a[(_super.call(this), "prop")] = function () { }, - _a - ); + _a); var _a; } return C; diff --git a/tests/baselines/reference/computedPropertyNames29_ES5.js b/tests/baselines/reference/computedPropertyNames29_ES5.js index 46ba529d7a546..af6f93c8ad9ba 100644 --- a/tests/baselines/reference/computedPropertyNames29_ES5.js +++ b/tests/baselines/reference/computedPropertyNames29_ES5.js @@ -19,8 +19,7 @@ var C = (function () { (function () { var obj = (_a = {}, _a[_this.bar()] = function () { }, - _a - ); + _a); var _a; }); return 0; diff --git a/tests/baselines/reference/computedPropertyNames30_ES5.js b/tests/baselines/reference/computedPropertyNames30_ES5.js index e787689d3938c..a900fd44c677e 100644 --- a/tests/baselines/reference/computedPropertyNames30_ES5.js +++ b/tests/baselines/reference/computedPropertyNames30_ES5.js @@ -36,8 +36,7 @@ var C = (function (_super) { // illegal, and not capturing this is consistent with //treatment of other similar violations. _a[(_super.call(this), "prop")] = function () { }, - _a - ); + _a); var _a; }); } diff --git a/tests/baselines/reference/computedPropertyNames31_ES5.js b/tests/baselines/reference/computedPropertyNames31_ES5.js index 8417f103fb77b..86fb6655a27c4 100644 --- a/tests/baselines/reference/computedPropertyNames31_ES5.js +++ b/tests/baselines/reference/computedPropertyNames31_ES5.js @@ -39,8 +39,7 @@ var C = (function (_super) { (function () { var obj = (_a = {}, _a[_super.prototype.bar.call(_this)] = function () { }, - _a - ); + _a); var _a; }); return 0; diff --git a/tests/baselines/reference/computedPropertyNames33_ES5.js b/tests/baselines/reference/computedPropertyNames33_ES5.js index 8db62818e22ce..e6d46b03c100e 100644 --- a/tests/baselines/reference/computedPropertyNames33_ES5.js +++ b/tests/baselines/reference/computedPropertyNames33_ES5.js @@ -17,8 +17,7 @@ var C = (function () { C.prototype.bar = function () { var obj = (_a = {}, _a[foo()] = function () { }, - _a - ); + _a); return 0; var _a; }; diff --git a/tests/baselines/reference/computedPropertyNames34_ES5.js b/tests/baselines/reference/computedPropertyNames34_ES5.js index fa0af2897f7fa..3109c400422d0 100644 --- a/tests/baselines/reference/computedPropertyNames34_ES5.js +++ b/tests/baselines/reference/computedPropertyNames34_ES5.js @@ -17,8 +17,7 @@ var C = (function () { C.bar = function () { var obj = (_a = {}, _a[foo()] = function () { }, - _a - ); + _a); return 0; var _a; }; diff --git a/tests/baselines/reference/computedPropertyNames46_ES5.js b/tests/baselines/reference/computedPropertyNames46_ES5.js index 307dadcbe9115..815f5769f3b28 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES5.js +++ b/tests/baselines/reference/computedPropertyNames46_ES5.js @@ -6,6 +6,5 @@ var o = { //// [computedPropertyNames46_ES5.js] var o = (_a = {}, _a["" || 0] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames47_ES5.js b/tests/baselines/reference/computedPropertyNames47_ES5.js index d03b614b29b6b..a2fff2110b49f 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES5.js +++ b/tests/baselines/reference/computedPropertyNames47_ES5.js @@ -16,6 +16,5 @@ var E2; })(E2 || (E2 = {})); var o = (_a = {}, _a[E1.x || E2.x] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames48_ES5.js b/tests/baselines/reference/computedPropertyNames48_ES5.js index 15123a98f302b..55b08ef8301d3 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES5.js +++ b/tests/baselines/reference/computedPropertyNames48_ES5.js @@ -25,14 +25,11 @@ var E; var a; extractIndexer((_a = {}, _a[a] = "", - _a -)); // Should return string + _a)); // Should return string extractIndexer((_b = {}, _b[E.x] = "", - _b -)); // Should return string + _b)); // Should return string extractIndexer((_c = {}, _c["" || 0] = "", - _c -)); // Should return any (widened form of undefined) + _c)); // Should return any (widened form of undefined) var _a, _b, _c; diff --git a/tests/baselines/reference/computedPropertyNames49_ES5.js b/tests/baselines/reference/computedPropertyNames49_ES5.js index 3427ea665a051..12c3430fbe94f 100644 --- a/tests/baselines/reference/computedPropertyNames49_ES5.js +++ b/tests/baselines/reference/computedPropertyNames49_ES5.js @@ -62,6 +62,5 @@ var x = (_a = { }), , _a.p2 = 20, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.js b/tests/baselines/reference/computedPropertyNames4_ES5.js index f91476c79c160..ac0fa8ec93792 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.js +++ b/tests/baselines/reference/computedPropertyNames4_ES5.js @@ -32,6 +32,5 @@ var v = (_a = {}, _a[true] = 0, _a["hello bye"] = 0, _a["hello " + a + " bye"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames50_ES5.js b/tests/baselines/reference/computedPropertyNames50_ES5.js index a74561295bec3..db9a03578dfa0 100644 --- a/tests/baselines/reference/computedPropertyNames50_ES5.js +++ b/tests/baselines/reference/computedPropertyNames50_ES5.js @@ -58,6 +58,5 @@ var x = (_a = { }), , _a.p2 = 20, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames5_ES5.js b/tests/baselines/reference/computedPropertyNames5_ES5.js index 58c5af2efa3b4..3367faa2c20b2 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES5.js +++ b/tests/baselines/reference/computedPropertyNames5_ES5.js @@ -18,6 +18,5 @@ var v = (_a = {}, _a[{}] = 0, _a[undefined] = undefined, _a[null] = null, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames6_ES5.js b/tests/baselines/reference/computedPropertyNames6_ES5.js index 7e9c62029403d..29d035bfcbfb4 100644 --- a/tests/baselines/reference/computedPropertyNames6_ES5.js +++ b/tests/baselines/reference/computedPropertyNames6_ES5.js @@ -16,6 +16,5 @@ var v = (_a = {}, _a[p1] = 0, _a[p2] = 1, _a[p3] = 2, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames7_ES5.js b/tests/baselines/reference/computedPropertyNames7_ES5.js index 3311ec7e092db..01cf2efc030b8 100644 --- a/tests/baselines/reference/computedPropertyNames7_ES5.js +++ b/tests/baselines/reference/computedPropertyNames7_ES5.js @@ -13,6 +13,5 @@ var E; })(E || (E = {})); var v = (_a = {}, _a[E.member] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNames8_ES5.js b/tests/baselines/reference/computedPropertyNames8_ES5.js index 6eceee81adb10..82d262c7e4e11 100644 --- a/tests/baselines/reference/computedPropertyNames8_ES5.js +++ b/tests/baselines/reference/computedPropertyNames8_ES5.js @@ -15,7 +15,6 @@ function f() { var v = (_a = {}, _a[t] = 0, _a[u] = 1, - _a - ); + _a); var _a; } diff --git a/tests/baselines/reference/computedPropertyNames9_ES5.js b/tests/baselines/reference/computedPropertyNames9_ES5.js index 6c1d7bcb4d076..b1ac6c9e3b656 100644 --- a/tests/baselines/reference/computedPropertyNames9_ES5.js +++ b/tests/baselines/reference/computedPropertyNames9_ES5.js @@ -16,6 +16,5 @@ var v = (_a = {}, _a[f("")] = 0, _a[f(0)] = 0, _a[f(true)] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType10_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType10_ES5.js index 1f7a3ae123e57..d8a33951d4a26 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType10_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType10_ES5.js @@ -12,6 +12,5 @@ var o: I = { var o = (_a = {}, _a[+"foo"] = "", _a[+"bar"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType1_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType1_ES5.js index c4bfde03531ef..1ee8835115415 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType1_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType1_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a["" + 0] = function (y) { return y.length; }, _a["" + 1] = function (y) { return y.length; }, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType2_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType2_ES5.js index 945475f8533f2..6be09e4bef3f3 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType2_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType2_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a[+"foo"] = function (y) { return y.length; }, _a[+"bar"] = function (y) { return y.length; }, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType3_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType3_ES5.js index 98042f201e339..b510cda2916f4 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType3_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType3_ES5.js @@ -12,6 +12,5 @@ var o: I = { var o = (_a = {}, _a[+"foo"] = function (y) { return y.length; }, _a[+"bar"] = function (y) { return y.length; }, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType4_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType4_ES5.js index b17f91be38b41..0c319a526f4a1 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType4_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType4_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a["" + "foo"] = "", _a["" + "bar"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType5_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType5_ES5.js index c7a728e5ef85f..51d78be59d4ff 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType5_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType5_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a[+"foo"] = "", _a[+"bar"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType6_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType6_ES5.js index c97b7c5b1f865..c6ef45d7fabe0 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType6_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType6_ES5.js @@ -21,6 +21,5 @@ foo((_a = { _a["hi" + "bye"] = true, _a[0 + 1] = 0, _a[+"hi"] = [0], - _a -)); + _a)); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType7_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType7_ES5.js index 9ca7e826aa713..9caf5f2aebfde 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType7_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType7_ES5.js @@ -21,6 +21,5 @@ foo((_a = { _a["hi" + "bye"] = true, _a[0 + 1] = 0, _a[+"hi"] = [0], - _a -)); + _a)); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType8_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType8_ES5.js index 419ea906550b5..24f6218864cbd 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType8_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType8_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a["" + "foo"] = "", _a["" + "bar"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.js b/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.js index d3beb8b8deb73..340802da2af91 100644 --- a/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesContextualType9_ES5.js @@ -13,6 +13,5 @@ var o: I = { var o = (_a = {}, _a[+"foo"] = "", _a[+"bar"] = 0, - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesDeclarationEmit5_ES5.js b/tests/baselines/reference/computedPropertyNamesDeclarationEmit5_ES5.js index e77eb79dc709e..c903b8648292a 100644 --- a/tests/baselines/reference/computedPropertyNamesDeclarationEmit5_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesDeclarationEmit5_ES5.js @@ -20,8 +20,7 @@ var v = (_a = {}, enumerable: true, configurable: true }), - _a -); + _a); var _a; diff --git a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js index 39e393c46cce6..972aaf9b52f6a 100644 --- a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js +++ b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js @@ -10,7 +10,6 @@ var v = (_a = {}, _a["hello"] = function () { debugger; }, - _a -); + _a); var _a; //# sourceMappingURL=computedPropertyNamesSourceMap2_ES5.js.map \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js.map b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js.map index baf1e998efdc5..bdc2149765166 100644 --- a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js.map +++ b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.js.map @@ -1,2 +1,2 @@ //// [computedPropertyNamesSourceMap2_ES5.js.map] -{"version":3,"file":"computedPropertyNamesSourceMap2_ES5.js","sourceRoot":"","sources":["computedPropertyNamesSourceMap2_ES5.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG;IACJ,GAAC,OAAO,CAAC,GAAT;QACI,QAAQ,CAAC;IACb,CAAC;;CACJ,CAAA"} \ No newline at end of file +{"version":3,"file":"computedPropertyNamesSourceMap2_ES5.js","sourceRoot":"","sources":["computedPropertyNamesSourceMap2_ES5.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG;IACJ,GAAC,OAAO,CAAC,GAAT;QACI,QAAQ,CAAC;IACb,CAAC;OACJ,CAAA"} \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.sourcemap.txt b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.sourcemap.txt index f6501777985f3..0535196f9235c 100644 --- a/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.sourcemap.txt +++ b/tests/baselines/reference/computedPropertyNamesSourceMap2_ES5.sourcemap.txt @@ -56,23 +56,21 @@ sourceFile:computedPropertyNamesSourceMap2_ES5.ts >>> }, 1 >^^^^ 2 > ^ -3 > ^^-> +3 > ^^^^-> 1 > > 2 > } 1 >Emitted(4, 5) Source(4, 5) + SourceIndex(0) 2 >Emitted(4, 6) Source(4, 6) + SourceIndex(0) --- ->>> _a ->>>); -1->^ -2 > ^ -3 > ^^^^^^-> +>>> _a); +1->^^^^^^^ +2 > ^ 1-> >} -2 > -1->Emitted(6, 2) Source(5, 2) + SourceIndex(0) -2 >Emitted(6, 3) Source(5, 2) + SourceIndex(0) +2 > +1->Emitted(5, 8) Source(5, 2) + SourceIndex(0) +2 >Emitted(5, 9) Source(5, 2) + SourceIndex(0) --- >>>var _a; >>>//# sourceMappingURL=computedPropertyNamesSourceMap2_ES5.js.map \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.js b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.js index 11081be4fb356..2c8efdd424aab 100644 --- a/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.js +++ b/tests/baselines/reference/contextuallyTypedClassExpressionMethodDeclaration01.js @@ -61,28 +61,32 @@ function getFoo1() { }()); } function getFoo2() { - return (function () { - function class_2() { - } - class_2.method1 = function (arg) { + return (_a = (function () { + function class_2() { + } + return class_2; + }()), + _a.method1 = function (arg) { arg.numProp = 10; - }; - class_2.method2 = function (arg) { + }, + _a.method2 = function (arg) { arg.strProp = "hello"; - }; - return class_2; - }()); + }, + _a); + var _a; } function getFoo3() { - return (function () { - function class_3() { - } - class_3.method1 = function (arg) { + return (_a = (function () { + function class_3() { + } + return class_3; + }()), + _a.method1 = function (arg) { arg.numProp = 10; - }; - class_3.method2 = function (arg) { + }, + _a.method2 = function (arg) { arg.strProp = "hello"; - }; - return class_3; - }()); + }, + _a); + var _a; } diff --git a/tests/baselines/reference/declFilePrivateStatic.js b/tests/baselines/reference/declFilePrivateStatic.js index 30cd85444cf7b..fb24bea766088 100644 --- a/tests/baselines/reference/declFilePrivateStatic.js +++ b/tests/baselines/reference/declFilePrivateStatic.js @@ -40,10 +40,10 @@ var C = (function () { enumerable: true, configurable: true }); - C.x = 1; - C.y = 1; return C; }()); +C.x = 1; +C.y = 1; //// [declFilePrivateStatic.d.ts] diff --git a/tests/baselines/reference/decoratorCallGeneric.js b/tests/baselines/reference/decoratorCallGeneric.js index acc9c48297dfe..a1d470b7063c3 100644 --- a/tests/baselines/reference/decoratorCallGeneric.js +++ b/tests/baselines/reference/decoratorCallGeneric.js @@ -24,8 +24,8 @@ var C = (function () { function C() { } C.m = function () { }; - C = __decorate([ - dec - ], C); return C; }()); +C = __decorate([ + dec +], C); diff --git a/tests/baselines/reference/decoratorChecksFunctionBodies.js b/tests/baselines/reference/decoratorChecksFunctionBodies.js index d70c4a334608e..68dbe6bd1ef0c 100644 --- a/tests/baselines/reference/decoratorChecksFunctionBodies.js +++ b/tests/baselines/reference/decoratorChecksFunctionBodies.js @@ -30,12 +30,12 @@ var A = (function () { } A.prototype.m = function () { }; - __decorate([ - (function (x, p) { - var a = 3; - func(a); - return x; - }) - ], A.prototype, "m", null); return A; }()); +__decorate([ + (function (x, p) { + var a = 3; + func(a); + return x; + }) +], A.prototype, "m", null); diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js index 92dcc1f836c5c..28b620a3e8c4c 100644 --- a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js @@ -45,8 +45,8 @@ var Wat = (function () { Wat.whatever = function () { // ... }; - __decorate([ - filter(function () { return a_1.test == 'abc'; }) - ], Wat, "whatever", null); return Wat; }()); +__decorate([ + filter(function () { return a_1.test == 'abc'; }) +], Wat, "whatever", null); diff --git a/tests/baselines/reference/decoratorMetadata.js b/tests/baselines/reference/decoratorMetadata.js index 2f360df061856..d95658c7f18df 100644 --- a/tests/baselines/reference/decoratorMetadata.js +++ b/tests/baselines/reference/decoratorMetadata.js @@ -45,15 +45,15 @@ var MyComponent = (function () { } MyComponent.prototype.method = function (x) { }; - __decorate([ - decorator, - __metadata('design:type', Function), - __metadata('design:paramtypes', [Object]), - __metadata('design:returntype', void 0) - ], MyComponent.prototype, "method", null); - MyComponent = __decorate([ - decorator, - __metadata('design:paramtypes', [service_1.default]) - ], MyComponent); return MyComponent; }()); +__decorate([ + decorator, + __metadata('design:type', Function), + __metadata('design:paramtypes', [Object]), + __metadata('design:returntype', void 0) +], MyComponent.prototype, "method", null); +MyComponent = __decorate([ + decorator, + __metadata('design:paramtypes', [service_1.default]) +], MyComponent); diff --git a/tests/baselines/reference/decoratorMetadataForMethodWithNoReturnTypeAnnotation01.js b/tests/baselines/reference/decoratorMetadataForMethodWithNoReturnTypeAnnotation01.js index f5048ead6313d..e5127987d532b 100644 --- a/tests/baselines/reference/decoratorMetadataForMethodWithNoReturnTypeAnnotation01.js +++ b/tests/baselines/reference/decoratorMetadataForMethodWithNoReturnTypeAnnotation01.js @@ -20,11 +20,11 @@ var MyClass = (function () { } MyClass.prototype.doSomething = function () { }; - __decorate([ - decorator, - __metadata('design:type', Function), - __metadata('design:paramtypes', []), - __metadata('design:returntype', void 0) - ], MyClass.prototype, "doSomething", null); return MyClass; }()); +__decorate([ + decorator, + __metadata('design:type', Function), + __metadata('design:paramtypes', []), + __metadata('design:returntype', void 0) +], MyClass.prototype, "doSomething", null); diff --git a/tests/baselines/reference/decoratorMetadataOnInferredType.js b/tests/baselines/reference/decoratorMetadataOnInferredType.js index 5a39a6ce42ca5..47b6c45e80636 100644 --- a/tests/baselines/reference/decoratorMetadataOnInferredType.js +++ b/tests/baselines/reference/decoratorMetadataOnInferredType.js @@ -31,10 +31,10 @@ var B = (function () { function B() { this.x = new A(); } - __decorate([ - decorator, - __metadata('design:type', Object) - ], B.prototype, "x", void 0); return B; }()); +__decorate([ + decorator, + __metadata('design:type', Object) +], B.prototype, "x", void 0); exports.B = B; diff --git a/tests/baselines/reference/decoratorMetadataWithConstructorType.js b/tests/baselines/reference/decoratorMetadataWithConstructorType.js index 39e8d1811aa7a..0559e62754c57 100644 --- a/tests/baselines/reference/decoratorMetadataWithConstructorType.js +++ b/tests/baselines/reference/decoratorMetadataWithConstructorType.js @@ -31,10 +31,10 @@ var B = (function () { function B() { this.x = new A(); } - __decorate([ - decorator, - __metadata('design:type', A) - ], B.prototype, "x", void 0); return B; }()); +__decorate([ + decorator, + __metadata('design:type', A) +], B.prototype, "x", void 0); exports.B = B; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision.js index b549d28c7f182..a0bc68bd8d884 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision.js @@ -44,10 +44,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [db_1.db]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [db_1.db]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision2.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision2.js index acd86e78d76e6..49a2983ce708e 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision2.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision2.js @@ -44,10 +44,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [db_1.db]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [db_1.db]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision3.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision3.js index 2acd829c107b6..f3c1d1b5da551 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision3.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision3.js @@ -44,10 +44,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [db.db]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [db.db]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision4.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision4.js index 4af0beeddcb99..3448352eaaf0b 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision4.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision4.js @@ -44,10 +44,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [Object]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [Object]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision5.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision5.js index f1537e3b447bc..8eae92ec4d160 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision5.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision5.js @@ -45,10 +45,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [db_1.default]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [db_1.default]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision6.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision6.js index 7ef2c28881067..26e714c16a134 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision6.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision6.js @@ -45,10 +45,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [db_1.default]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [db_1.default]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision7.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision7.js index f8469cdd6a432..1d3b8a92349bf 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision7.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision7.js @@ -45,10 +45,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [Object]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [Object]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision8.js b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision8.js index f1885ccfaec29..910008b9c271b 100644 --- a/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision8.js +++ b/tests/baselines/reference/decoratorMetadataWithImportDeclarationNameCollision8.js @@ -44,10 +44,10 @@ var MyClass = (function () { this.db = db; this.db.doSomething(); } - MyClass = __decorate([ - someDecorator, - __metadata('design:paramtypes', [database.db]) - ], MyClass); return MyClass; }()); +MyClass = __decorate([ + someDecorator, + __metadata('design:paramtypes', [database.db]) +], MyClass); exports.MyClass = MyClass; diff --git a/tests/baselines/reference/decoratorOnClass1.js b/tests/baselines/reference/decoratorOnClass1.js index 7ea46b4698fc8..5cff4c2649c27 100644 --- a/tests/baselines/reference/decoratorOnClass1.js +++ b/tests/baselines/reference/decoratorOnClass1.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec - ], C); return C; }()); +C = __decorate([ + dec +], C); diff --git a/tests/baselines/reference/decoratorOnClass2.js b/tests/baselines/reference/decoratorOnClass2.js index 3f24c7ae55b7b..4d9c2007ad0f2 100644 --- a/tests/baselines/reference/decoratorOnClass2.js +++ b/tests/baselines/reference/decoratorOnClass2.js @@ -16,9 +16,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec - ], C); return C; }()); +C = __decorate([ + dec +], C); exports.C = C; diff --git a/tests/baselines/reference/decoratorOnClass3.js b/tests/baselines/reference/decoratorOnClass3.js index 5a3601fc1f3e8..fd09a6d8de576 100644 --- a/tests/baselines/reference/decoratorOnClass3.js +++ b/tests/baselines/reference/decoratorOnClass3.js @@ -16,8 +16,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec - ], C); return C; }()); +C = __decorate([ + dec +], C); diff --git a/tests/baselines/reference/decoratorOnClass4.js b/tests/baselines/reference/decoratorOnClass4.js index adbe30db662a6..daf19e20327b5 100644 --- a/tests/baselines/reference/decoratorOnClass4.js +++ b/tests/baselines/reference/decoratorOnClass4.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec() - ], C); return C; }()); +C = __decorate([ + dec() +], C); diff --git a/tests/baselines/reference/decoratorOnClass5.js b/tests/baselines/reference/decoratorOnClass5.js index 6741b26373bb9..70fc551514070 100644 --- a/tests/baselines/reference/decoratorOnClass5.js +++ b/tests/baselines/reference/decoratorOnClass5.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec() - ], C); return C; }()); +C = __decorate([ + dec() +], C); diff --git a/tests/baselines/reference/decoratorOnClass8.js b/tests/baselines/reference/decoratorOnClass8.js index e5cd8812ea780..ae50ab75ab8e7 100644 --- a/tests/baselines/reference/decoratorOnClass8.js +++ b/tests/baselines/reference/decoratorOnClass8.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - C = __decorate([ - dec() - ], C); return C; }()); +C = __decorate([ + dec() +], C); diff --git a/tests/baselines/reference/decoratorOnClassAccessor1.js b/tests/baselines/reference/decoratorOnClassAccessor1.js index cf989705b79b4..27966350faecd 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor1.js +++ b/tests/baselines/reference/decoratorOnClassAccessor1.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassAccessor2.js b/tests/baselines/reference/decoratorOnClassAccessor2.js index 9e9455b438051..57cb3b50461b3 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor2.js +++ b/tests/baselines/reference/decoratorOnClassAccessor2.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassAccessor3.js b/tests/baselines/reference/decoratorOnClassAccessor3.js index 8a27914e0c898..c02f984e70ac3 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor3.js +++ b/tests/baselines/reference/decoratorOnClassAccessor3.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassAccessor4.js b/tests/baselines/reference/decoratorOnClassAccessor4.js index 85b35e95cef54..0e0af58f526be 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor4.js +++ b/tests/baselines/reference/decoratorOnClassAccessor4.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassAccessor5.js b/tests/baselines/reference/decoratorOnClassAccessor5.js index 12ec7a08adcb9..c7d5d109cc07f 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor5.js +++ b/tests/baselines/reference/decoratorOnClassAccessor5.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassAccessor6.js b/tests/baselines/reference/decoratorOnClassAccessor6.js index d5477deb5af10..8ac40e722995c 100644 --- a/tests/baselines/reference/decoratorOnClassAccessor6.js +++ b/tests/baselines/reference/decoratorOnClassAccessor6.js @@ -20,8 +20,8 @@ var C = (function () { enumerable: true, configurable: true }); - __decorate([ - dec - ], C.prototype, "accessor", null); return C; }()); +__decorate([ + dec +], C.prototype, "accessor", null); diff --git a/tests/baselines/reference/decoratorOnClassConstructorParameter1.js b/tests/baselines/reference/decoratorOnClassConstructorParameter1.js index fe04f569e30a7..176e2309ae05f 100644 --- a/tests/baselines/reference/decoratorOnClassConstructorParameter1.js +++ b/tests/baselines/reference/decoratorOnClassConstructorParameter1.js @@ -18,8 +18,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { var C = (function () { function C(p) { } - C = __decorate([ - __param(0, dec) - ], C); return C; }()); +C = __decorate([ + __param(0, dec) +], C); diff --git a/tests/baselines/reference/decoratorOnClassConstructorParameter4.js b/tests/baselines/reference/decoratorOnClassConstructorParameter4.js index 8d02bd467d6dc..e14f035880878 100644 --- a/tests/baselines/reference/decoratorOnClassConstructorParameter4.js +++ b/tests/baselines/reference/decoratorOnClassConstructorParameter4.js @@ -18,8 +18,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { var C = (function () { function C(public, p) { } - C = __decorate([ - __param(1, dec) - ], C); return C; }()); +C = __decorate([ + __param(1, dec) +], C); diff --git a/tests/baselines/reference/decoratorOnClassMethod1.js b/tests/baselines/reference/decoratorOnClassMethod1.js index ef029b845431b..b93d7f88771ed 100644 --- a/tests/baselines/reference/decoratorOnClassMethod1.js +++ b/tests/baselines/reference/decoratorOnClassMethod1.js @@ -16,8 +16,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethod10.js b/tests/baselines/reference/decoratorOnClassMethod10.js index f90251d619694..bfa57f0aeb704 100644 --- a/tests/baselines/reference/decoratorOnClassMethod10.js +++ b/tests/baselines/reference/decoratorOnClassMethod10.js @@ -16,8 +16,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethod11.js b/tests/baselines/reference/decoratorOnClassMethod11.js index f1589a39286fa..c703459b88d65 100644 --- a/tests/baselines/reference/decoratorOnClassMethod11.js +++ b/tests/baselines/reference/decoratorOnClassMethod11.js @@ -22,9 +22,9 @@ var M; } C.prototype.decorator = function (target, key) { }; C.prototype.method = function () { }; - __decorate([ - this.decorator - ], C.prototype, "method", null); return C; }()); + __decorate([ + this.decorator + ], C.prototype, "method", null); })(M || (M = {})); diff --git a/tests/baselines/reference/decoratorOnClassMethod12.js b/tests/baselines/reference/decoratorOnClassMethod12.js index 0650f1d00ee25..6e9b9763a3ab9 100644 --- a/tests/baselines/reference/decoratorOnClassMethod12.js +++ b/tests/baselines/reference/decoratorOnClassMethod12.js @@ -35,9 +35,9 @@ var M; _super.apply(this, arguments); } C.prototype.method = function () { }; - __decorate([ - _super.decorator - ], C.prototype, "method", null); return C; }(S)); + __decorate([ + _super.decorator + ], C.prototype, "method", null); })(M || (M = {})); diff --git a/tests/baselines/reference/decoratorOnClassMethod2.js b/tests/baselines/reference/decoratorOnClassMethod2.js index 5db2922ed7187..98ad8ad43ad78 100644 --- a/tests/baselines/reference/decoratorOnClassMethod2.js +++ b/tests/baselines/reference/decoratorOnClassMethod2.js @@ -16,8 +16,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethod3.js b/tests/baselines/reference/decoratorOnClassMethod3.js index 30f527368f28b..4a5943681d4cf 100644 --- a/tests/baselines/reference/decoratorOnClassMethod3.js +++ b/tests/baselines/reference/decoratorOnClassMethod3.js @@ -16,8 +16,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethod8.js b/tests/baselines/reference/decoratorOnClassMethod8.js index bf8c06d9b90f6..c1ad826cab0ef 100644 --- a/tests/baselines/reference/decoratorOnClassMethod8.js +++ b/tests/baselines/reference/decoratorOnClassMethod8.js @@ -16,8 +16,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethodOverload2.js b/tests/baselines/reference/decoratorOnClassMethodOverload2.js index eafa5da711097..db077dd7b516b 100644 --- a/tests/baselines/reference/decoratorOnClassMethodOverload2.js +++ b/tests/baselines/reference/decoratorOnClassMethodOverload2.js @@ -18,8 +18,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassMethodParameter1.js b/tests/baselines/reference/decoratorOnClassMethodParameter1.js index efb1e4abff2cb..d5d8599d7a853 100644 --- a/tests/baselines/reference/decoratorOnClassMethodParameter1.js +++ b/tests/baselines/reference/decoratorOnClassMethodParameter1.js @@ -19,8 +19,8 @@ var C = (function () { function C() { } C.prototype.method = function (p) { }; - __decorate([ - __param(0, dec) - ], C.prototype, "method", null); return C; }()); +__decorate([ + __param(0, dec) +], C.prototype, "method", null); diff --git a/tests/baselines/reference/decoratorOnClassProperty1.js b/tests/baselines/reference/decoratorOnClassProperty1.js index 65a399332f161..6547e0bdb1873 100644 --- a/tests/baselines/reference/decoratorOnClassProperty1.js +++ b/tests/baselines/reference/decoratorOnClassProperty1.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty10.js b/tests/baselines/reference/decoratorOnClassProperty10.js index 9df40eaf83a38..174f26a315a72 100644 --- a/tests/baselines/reference/decoratorOnClassProperty10.js +++ b/tests/baselines/reference/decoratorOnClassProperty10.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec() - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec() +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty11.js b/tests/baselines/reference/decoratorOnClassProperty11.js index 8b771caf8b515..c901637402d70 100644 --- a/tests/baselines/reference/decoratorOnClassProperty11.js +++ b/tests/baselines/reference/decoratorOnClassProperty11.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty2.js b/tests/baselines/reference/decoratorOnClassProperty2.js index 3ab2b515e3c02..ceaf43caa59cf 100644 --- a/tests/baselines/reference/decoratorOnClassProperty2.js +++ b/tests/baselines/reference/decoratorOnClassProperty2.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty3.js b/tests/baselines/reference/decoratorOnClassProperty3.js index 9c0d3f90e42f2..8436be9396853 100644 --- a/tests/baselines/reference/decoratorOnClassProperty3.js +++ b/tests/baselines/reference/decoratorOnClassProperty3.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty6.js b/tests/baselines/reference/decoratorOnClassProperty6.js index 823a652af2404..c7f5490c64869 100644 --- a/tests/baselines/reference/decoratorOnClassProperty6.js +++ b/tests/baselines/reference/decoratorOnClassProperty6.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/decoratorOnClassProperty7.js b/tests/baselines/reference/decoratorOnClassProperty7.js index 134f35022e04a..828d548ff6b29 100644 --- a/tests/baselines/reference/decoratorOnClassProperty7.js +++ b/tests/baselines/reference/decoratorOnClassProperty7.js @@ -15,8 +15,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var C = (function () { function C() { } - __decorate([ - dec - ], C.prototype, "prop", void 0); return C; }()); +__decorate([ + dec +], C.prototype, "prop", void 0); diff --git a/tests/baselines/reference/derivedClassSuperCallsInNonConstructorMembers.js b/tests/baselines/reference/derivedClassSuperCallsInNonConstructorMembers.js index e043ee8a5c53e..50408d3bee764 100644 --- a/tests/baselines/reference/derivedClassSuperCallsInNonConstructorMembers.js +++ b/tests/baselines/reference/derivedClassSuperCallsInNonConstructorMembers.js @@ -77,6 +77,6 @@ var Derived = (function (_super) { enumerable: true, configurable: true }); - Derived.a = _super.call(this); return Derived; }(Base)); +Derived.a = _super.call(this); diff --git a/tests/baselines/reference/errorSuperCalls.js b/tests/baselines/reference/errorSuperCalls.js index 4cc6a4d968fe3..097b16b30242b 100644 --- a/tests/baselines/reference/errorSuperCalls.js +++ b/tests/baselines/reference/errorSuperCalls.js @@ -119,10 +119,10 @@ var NoBase = (function () { enumerable: true, configurable: true }); - //super call in static class member initializer with no base type - NoBase.k = _super.call(this); return NoBase; }()); +//super call in static class member initializer with no base type +NoBase.k = _super.call(this); var Base = (function () { function Base() { } diff --git a/tests/baselines/reference/errorSuperPropertyAccess.js b/tests/baselines/reference/errorSuperPropertyAccess.js index cf6ed2598eade..dbfbdb4694023 100644 --- a/tests/baselines/reference/errorSuperPropertyAccess.js +++ b/tests/baselines/reference/errorSuperPropertyAccess.js @@ -175,10 +175,10 @@ var SomeBase = (function () { SomeBase.prototype.publicFunc = function () { }; SomeBase.privateStaticFunc = function () { }; SomeBase.publicStaticFunc = function () { }; - SomeBase.privateStaticMember = 0; - SomeBase.publicStaticMember = 0; return SomeBase; }()); +SomeBase.privateStaticMember = 0; +SomeBase.publicStaticMember = 0; //super.publicInstanceMemberNotFunction in constructor of derived class //super.publicInstanceMemberNotFunction in instance member function of derived class //super.publicInstanceMemberNotFunction in instance member accessor(get and set) of derived class diff --git a/tests/baselines/reference/es3defaultAliasIsQuoted.js b/tests/baselines/reference/es3defaultAliasIsQuoted.js index ac6a0bd24daab..89fd0c47a7e94 100644 --- a/tests/baselines/reference/es3defaultAliasIsQuoted.js +++ b/tests/baselines/reference/es3defaultAliasIsQuoted.js @@ -19,9 +19,9 @@ assert(Foo.CONSTANT === "Foo"); var Foo = (function () { function Foo() { } - Foo.CONSTANT = "Foo"; return Foo; }()); +Foo.CONSTANT = "Foo"; exports.Foo = Foo; function assert(value) { if (!value) diff --git a/tests/baselines/reference/es6ClassTest.js b/tests/baselines/reference/es6ClassTest.js index 365e91321a451..a722cce167033 100644 --- a/tests/baselines/reference/es6ClassTest.js +++ b/tests/baselines/reference/es6ClassTest.js @@ -113,9 +113,9 @@ var Foo = (function (_super) { } Foo.prototype.bar = function () { return 0; }; Foo.prototype.boo = function (x) { return x; }; - Foo.statVal = 0; return Foo; }(Bar)); +Foo.statVal = 0; var f = new Foo(); //class GetSetMonster { // // attack(target) { diff --git a/tests/baselines/reference/es6ClassTest2.js b/tests/baselines/reference/es6ClassTest2.js index 86ff00121cf15..1881e6b8c878c 100644 --- a/tests/baselines/reference/es6ClassTest2.js +++ b/tests/baselines/reference/es6ClassTest2.js @@ -283,9 +283,9 @@ var Statics = (function () { Statics.baz = function () { return ""; }; - Statics.foo = 1; return Statics; }()); +Statics.foo = 1; var stat = new Statics(); var ImplementsInterface = (function () { function ImplementsInterface() { diff --git a/tests/baselines/reference/generatedContextualTyping.js b/tests/baselines/reference/generatedContextualTyping.js index 8093c8bec4195..e5488121d34eb 100644 --- a/tests/baselines/reference/generatedContextualTyping.js +++ b/tests/baselines/reference/generatedContextualTyping.js @@ -612,219 +612,219 @@ var x48 = (function () { var x49 = (function () { function x49() { } - x49.member = function () { return [d1, d2]; }; return x49; }()); +x49.member = function () { return [d1, d2]; }; var x50 = (function () { function x50() { } - x50.member = function () { return [d1, d2]; }; return x50; }()); +x50.member = function () { return [d1, d2]; }; var x51 = (function () { function x51() { } - x51.member = function named() { return [d1, d2]; }; return x51; }()); +x51.member = function named() { return [d1, d2]; }; var x52 = (function () { function x52() { } - x52.member = function () { return [d1, d2]; }; return x52; }()); +x52.member = function () { return [d1, d2]; }; var x53 = (function () { function x53() { } - x53.member = function () { return [d1, d2]; }; return x53; }()); +x53.member = function () { return [d1, d2]; }; var x54 = (function () { function x54() { } - x54.member = function named() { return [d1, d2]; }; return x54; }()); +x54.member = function named() { return [d1, d2]; }; var x55 = (function () { function x55() { } - x55.member = [d1, d2]; return x55; }()); +x55.member = [d1, d2]; var x56 = (function () { function x56() { } - x56.member = [d1, d2]; return x56; }()); +x56.member = [d1, d2]; var x57 = (function () { function x57() { } - x57.member = [d1, d2]; return x57; }()); +x57.member = [d1, d2]; var x58 = (function () { function x58() { } - x58.member = { n: [d1, d2] }; return x58; }()); +x58.member = { n: [d1, d2] }; var x59 = (function () { function x59() { } - x59.member = function (n) { var n; return null; }; return x59; }()); +x59.member = function (n) { var n; return null; }; var x60 = (function () { function x60() { } - x60.member = { func: function (n) { return [d1, d2]; } }; return x60; }()); +x60.member = { func: function (n) { return [d1, d2]; } }; var x61 = (function () { function x61() { } - x61.member = function () { return [d1, d2]; }; return x61; }()); +x61.member = function () { return [d1, d2]; }; var x62 = (function () { function x62() { } - x62.member = function () { return [d1, d2]; }; return x62; }()); +x62.member = function () { return [d1, d2]; }; var x63 = (function () { function x63() { } - x63.member = function named() { return [d1, d2]; }; return x63; }()); +x63.member = function named() { return [d1, d2]; }; var x64 = (function () { function x64() { } - x64.member = function () { return [d1, d2]; }; return x64; }()); +x64.member = function () { return [d1, d2]; }; var x65 = (function () { function x65() { } - x65.member = function () { return [d1, d2]; }; return x65; }()); +x65.member = function () { return [d1, d2]; }; var x66 = (function () { function x66() { } - x66.member = function named() { return [d1, d2]; }; return x66; }()); +x66.member = function named() { return [d1, d2]; }; var x67 = (function () { function x67() { } - x67.member = [d1, d2]; return x67; }()); +x67.member = [d1, d2]; var x68 = (function () { function x68() { } - x68.member = [d1, d2]; return x68; }()); +x68.member = [d1, d2]; var x69 = (function () { function x69() { } - x69.member = [d1, d2]; return x69; }()); +x69.member = [d1, d2]; var x70 = (function () { function x70() { } - x70.member = { n: [d1, d2] }; return x70; }()); +x70.member = { n: [d1, d2] }; var x71 = (function () { function x71() { } - x71.member = function (n) { var n; return null; }; return x71; }()); +x71.member = function (n) { var n; return null; }; var x72 = (function () { function x72() { } - x72.member = { func: function (n) { return [d1, d2]; } }; return x72; }()); +x72.member = { func: function (n) { return [d1, d2]; } }; var x73 = (function () { function x73() { } - x73.member = function () { return [d1, d2]; }; return x73; }()); +x73.member = function () { return [d1, d2]; }; var x74 = (function () { function x74() { } - x74.member = function () { return [d1, d2]; }; return x74; }()); +x74.member = function () { return [d1, d2]; }; var x75 = (function () { function x75() { } - x75.member = function named() { return [d1, d2]; }; return x75; }()); +x75.member = function named() { return [d1, d2]; }; var x76 = (function () { function x76() { } - x76.member = function () { return [d1, d2]; }; return x76; }()); +x76.member = function () { return [d1, d2]; }; var x77 = (function () { function x77() { } - x77.member = function () { return [d1, d2]; }; return x77; }()); +x77.member = function () { return [d1, d2]; }; var x78 = (function () { function x78() { } - x78.member = function named() { return [d1, d2]; }; return x78; }()); +x78.member = function named() { return [d1, d2]; }; var x79 = (function () { function x79() { } - x79.member = [d1, d2]; return x79; }()); +x79.member = [d1, d2]; var x80 = (function () { function x80() { } - x80.member = [d1, d2]; return x80; }()); +x80.member = [d1, d2]; var x81 = (function () { function x81() { } - x81.member = [d1, d2]; return x81; }()); +x81.member = [d1, d2]; var x82 = (function () { function x82() { } - x82.member = { n: [d1, d2] }; return x82; }()); +x82.member = { n: [d1, d2] }; var x83 = (function () { function x83() { } - x83.member = function (n) { var n; return null; }; return x83; }()); +x83.member = function (n) { var n; return null; }; var x84 = (function () { function x84() { } - x84.member = { func: function (n) { return [d1, d2]; } }; return x84; }()); +x84.member = { func: function (n) { return [d1, d2]; } }; var x85 = (function () { function x85(parm) { if (parm === void 0) { parm = function () { return [d1, d2]; }; } diff --git a/tests/baselines/reference/genericClassWithStaticsUsingTypeArguments.js b/tests/baselines/reference/genericClassWithStaticsUsingTypeArguments.js index 2039e459572ac..053fa785ee01a 100644 --- a/tests/baselines/reference/genericClassWithStaticsUsingTypeArguments.js +++ b/tests/baselines/reference/genericClassWithStaticsUsingTypeArguments.js @@ -25,9 +25,9 @@ var Foo = (function () { Foo.f = function (xs) { return xs.reverse(); }; - Foo.a = function (n) { }; - Foo.c = []; - Foo.d = false || (function (x) { return x || undefined; })(null); - Foo.e = function (x) { return null; }; return Foo; }()); +Foo.a = function (n) { }; +Foo.c = []; +Foo.d = false || (function (x) { return x || undefined; })(null); +Foo.e = function (x) { return null; }; diff --git a/tests/baselines/reference/gettersAndSetters.js b/tests/baselines/reference/gettersAndSetters.js index 16d66c7dc71f6..265a1210b16f4 100644 --- a/tests/baselines/reference/gettersAndSetters.js +++ b/tests/baselines/reference/gettersAndSetters.js @@ -65,9 +65,9 @@ var C = (function () { enumerable: true, configurable: true }); - C.barBack = ""; return C; }()); +C.barBack = ""; var c = new C(); var foo = c.Foo; c.Foo = "foov"; diff --git a/tests/baselines/reference/importImportOnlyModule.js b/tests/baselines/reference/importImportOnlyModule.js index 7b41e4400c5b0..013999321f959 100644 --- a/tests/baselines/reference/importImportOnlyModule.js +++ b/tests/baselines/reference/importImportOnlyModule.js @@ -22,9 +22,9 @@ define(["require", "exports"], function (require, exports) { function C1() { this.m1 = 42; } - C1.s1 = true; return C1; }()); + C1.s1 = true; exports.C1 = C1; }); //// [foo_1.js] diff --git a/tests/baselines/reference/instanceAndStaticDeclarations1.js b/tests/baselines/reference/instanceAndStaticDeclarations1.js index 093e9c15cc8ea..bf9b6963bb2f1 100644 --- a/tests/baselines/reference/instanceAndStaticDeclarations1.js +++ b/tests/baselines/reference/instanceAndStaticDeclarations1.js @@ -25,6 +25,6 @@ var Point = (function () { return Math.sqrt(dx * dx + dy * dy); }; Point.distance = function (p1, p2) { return p1.distance(p2); }; - Point.origin = new Point(0, 0); return Point; }()); +Point.origin = new Point(0, 0); diff --git a/tests/baselines/reference/invalidStaticField.js b/tests/baselines/reference/invalidStaticField.js index dc582e830c7c7..08a06d5ee27e0 100644 --- a/tests/baselines/reference/invalidStaticField.js +++ b/tests/baselines/reference/invalidStaticField.js @@ -12,6 +12,6 @@ var A = (function () { var B = (function () { function B() { } - B.NOT_NULL = new B(); return B; }()); +B.NOT_NULL = new B(); diff --git a/tests/baselines/reference/literalsInComputedProperties1.js b/tests/baselines/reference/literalsInComputedProperties1.js index 82a6367e5d274..4c28a5e908387 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.js +++ b/tests/baselines/reference/literalsInComputedProperties1.js @@ -58,8 +58,7 @@ var x = (_a = { _a[2] = 1, _a["3"] = 1, _a["4"] = 1, - _a -); + _a); x[1].toExponential(); x[2].toExponential(); x[3].toExponential(); diff --git a/tests/baselines/reference/missingDecoratorType.js b/tests/baselines/reference/missingDecoratorType.js index 7356be39798a1..1dcbb3febc5e9 100644 --- a/tests/baselines/reference/missingDecoratorType.js +++ b/tests/baselines/reference/missingDecoratorType.js @@ -33,8 +33,8 @@ var C = (function () { function C() { } C.prototype.method = function () { }; - __decorate([ - dec - ], C.prototype, "method", null); return C; }()); +__decorate([ + dec +], C.prototype, "method", null); diff --git a/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js index 70eea5b2c5c68..211c80bcce853 100644 --- a/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js +++ b/tests/baselines/reference/modifierOnClassExpressionMemberInFunction.js @@ -10,14 +10,16 @@ function g() { //// [modifierOnClassExpressionMemberInFunction.js] function g() { - var x = (function () { - function C() { - this.prop1 = 1; - } - C.prototype.foo = function () { }; - C.prop2 = 43; - return C; - }()); + var x = (_a = (function () { + function C() { + this.prop1 = 1; + } + C.prototype.foo = function () { }; + return C; + }()), + _a.prop2 = 43, + _a); + var _a; } diff --git a/tests/baselines/reference/noEmitHelpers2.js b/tests/baselines/reference/noEmitHelpers2.js index f3bbfe54896d8..fc4baf334c3d7 100644 --- a/tests/baselines/reference/noEmitHelpers2.js +++ b/tests/baselines/reference/noEmitHelpers2.js @@ -12,10 +12,10 @@ class A { var A = (function () { function A(a, b) { } - A = __decorate([ - decorator, - __param(1, decorator), - __metadata('design:paramtypes', [Number, String]) - ], A); return A; }()); +A = __decorate([ + decorator, + __param(1, decorator), + __metadata('design:paramtypes', [Number, String]) +], A); diff --git a/tests/baselines/reference/parserAccessibilityAfterStatic3.js b/tests/baselines/reference/parserAccessibilityAfterStatic3.js index 7a9ae06e43929..38202bc5dc8fe 100644 --- a/tests/baselines/reference/parserAccessibilityAfterStatic3.js +++ b/tests/baselines/reference/parserAccessibilityAfterStatic3.js @@ -9,6 +9,6 @@ static public = 1; var Outer = (function () { function Outer() { } - Outer.public = 1; return Outer; }()); +Outer.public = 1; diff --git a/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable1.js b/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable1.js index 9bb4395e55655..57d0536e97597 100644 --- a/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable1.js +++ b/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable1.js @@ -41,10 +41,10 @@ var Shapes; } // Instance member Point.prototype.getDist = function () { return Math.sqrt(this.x * this.x + this.y * this.y); }; - // Static member - Point.origin = new Point(0, 0); return Point; }()); + // Static member + Point.origin = new Point(0, 0); Shapes.Point = Point; })(Shapes || (Shapes = {})); // Local variables diff --git a/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable2.js b/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable2.js index 0ee73b8b1e5bf..2bb08a14e350b 100644 --- a/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable2.js +++ b/tests/baselines/reference/parserErrorRecovery_IncompleteMemberVariable2.js @@ -42,10 +42,10 @@ var Shapes; } // Instance member Point.prototype.getDist = function () { return Math.sqrt(this.x * this.x + this.y * this.y); }; - // Static member - Point.origin = new Point(0, 0); return Point; }()); + // Static member + Point.origin = new Point(0, 0); Shapes.Point = Point; })(Shapes || (Shapes = {})); // Local variables diff --git a/tests/baselines/reference/parserharness.js b/tests/baselines/reference/parserharness.js index 6b38a8c9e4cc7..1a525c49d197f 100644 --- a/tests/baselines/reference/parserharness.js +++ b/tests/baselines/reference/parserharness.js @@ -2371,11 +2371,11 @@ var Harness; errorHandlerStack[errorHandlerStack.length - 1](e); } }; - // The current stack of Runnable objects - Runnable.currentStack = []; - Runnable.errorHandlerStack = []; return Runnable; }()); + // The current stack of Runnable objects + Runnable.currentStack = []; + Runnable.errorHandlerStack = []; Harness.Runnable = Runnable; var TestCase = (function (_super) { __extends(TestCase, _super); diff --git a/tests/baselines/reference/privacyCannotNameVarTypeDeclFile.js b/tests/baselines/reference/privacyCannotNameVarTypeDeclFile.js index 6c2dcf304cfb7..c139b6279fd1d 100644 --- a/tests/baselines/reference/privacyCannotNameVarTypeDeclFile.js +++ b/tests/baselines/reference/privacyCannotNameVarTypeDeclFile.js @@ -159,12 +159,12 @@ var publicClassWithWithPrivatePropertyTypes = (function () { this.myPublicProperty1 = exporter.createExportedWidget3(); // Error this.myPrivateProperty1 = exporter.createExportedWidget3(); } - publicClassWithWithPrivatePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget1(); // Error - publicClassWithWithPrivatePropertyTypes.myPrivateStaticProperty = exporter.createExportedWidget1(); - publicClassWithWithPrivatePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget3(); // Error - publicClassWithWithPrivatePropertyTypes.myPrivateStaticProperty1 = exporter.createExportedWidget3(); return publicClassWithWithPrivatePropertyTypes; }()); +publicClassWithWithPrivatePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget1(); // Error +publicClassWithWithPrivatePropertyTypes.myPrivateStaticProperty = exporter.createExportedWidget1(); +publicClassWithWithPrivatePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget3(); // Error +publicClassWithWithPrivatePropertyTypes.myPrivateStaticProperty1 = exporter.createExportedWidget3(); exports.publicClassWithWithPrivatePropertyTypes = publicClassWithWithPrivatePropertyTypes; var privateClassWithWithPrivatePropertyTypes = (function () { function privateClassWithWithPrivatePropertyTypes() { @@ -173,12 +173,12 @@ var privateClassWithWithPrivatePropertyTypes = (function () { this.myPublicProperty1 = exporter.createExportedWidget3(); this.myPrivateProperty1 = exporter.createExportedWidget3(); } - privateClassWithWithPrivatePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget1(); - privateClassWithWithPrivatePropertyTypes.myPrivateStaticProperty = exporter.createExportedWidget1(); - privateClassWithWithPrivatePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget3(); - privateClassWithWithPrivatePropertyTypes.myPrivateStaticProperty1 = exporter.createExportedWidget3(); return privateClassWithWithPrivatePropertyTypes; }()); +privateClassWithWithPrivatePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget1(); +privateClassWithWithPrivatePropertyTypes.myPrivateStaticProperty = exporter.createExportedWidget1(); +privateClassWithWithPrivatePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget3(); +privateClassWithWithPrivatePropertyTypes.myPrivateStaticProperty1 = exporter.createExportedWidget3(); exports.publicVarWithPrivatePropertyTypes = exporter.createExportedWidget1(); // Error var privateVarWithPrivatePropertyTypes = exporter.createExportedWidget1(); exports.publicVarWithPrivatePropertyTypes1 = exporter.createExportedWidget3(); // Error @@ -188,10 +188,10 @@ var publicClassWithPrivateModulePropertyTypes = (function () { this.myPublicProperty = exporter.createExportedWidget2(); // Error this.myPublicProperty1 = exporter.createExportedWidget4(); // Error } - publicClassWithPrivateModulePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget2(); // Error - publicClassWithPrivateModulePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget4(); // Error return publicClassWithPrivateModulePropertyTypes; }()); +publicClassWithPrivateModulePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget2(); // Error +publicClassWithPrivateModulePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget4(); // Error exports.publicClassWithPrivateModulePropertyTypes = publicClassWithPrivateModulePropertyTypes; exports.publicVarWithPrivateModulePropertyTypes = exporter.createExportedWidget2(); // Error exports.publicVarWithPrivateModulePropertyTypes1 = exporter.createExportedWidget4(); // Error @@ -200,10 +200,10 @@ var privateClassWithPrivateModulePropertyTypes = (function () { this.myPublicProperty = exporter.createExportedWidget2(); this.myPublicProperty1 = exporter.createExportedWidget4(); } - privateClassWithPrivateModulePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget2(); - privateClassWithPrivateModulePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget4(); return privateClassWithPrivateModulePropertyTypes; }()); +privateClassWithPrivateModulePropertyTypes.myPublicStaticProperty = exporter.createExportedWidget2(); +privateClassWithPrivateModulePropertyTypes.myPublicStaticProperty1 = exporter.createExportedWidget4(); var privateVarWithPrivateModulePropertyTypes = exporter.createExportedWidget2(); var privateVarWithPrivateModulePropertyTypes1 = exporter.createExportedWidget4(); diff --git a/tests/baselines/reference/privateIndexer2.js b/tests/baselines/reference/privateIndexer2.js index 1268c6e4c25a2..a90e03a5bc2bd 100644 --- a/tests/baselines/reference/privateIndexer2.js +++ b/tests/baselines/reference/privateIndexer2.js @@ -14,7 +14,6 @@ var y: { var x = (_a = {}, _a[x] = string, _a.string = , - _a -); + _a); var y; var _a; diff --git a/tests/baselines/reference/privateStaticMemberAccessibility.js b/tests/baselines/reference/privateStaticMemberAccessibility.js index 2074e5aa8649e..352256ac9bd66 100644 --- a/tests/baselines/reference/privateStaticMemberAccessibility.js +++ b/tests/baselines/reference/privateStaticMemberAccessibility.js @@ -25,6 +25,6 @@ var Derived = (function (_super) { _super.apply(this, arguments); this.bing = function () { return Base.foo; }; // error } - Derived.bar = Base.foo; // error return Derived; }(Base)); +Derived.bar = Base.foo; // error diff --git a/tests/baselines/reference/propertyAccessibility2.js b/tests/baselines/reference/propertyAccessibility2.js index afce6c4c24a79..3618b86fcc5b4 100644 --- a/tests/baselines/reference/propertyAccessibility2.js +++ b/tests/baselines/reference/propertyAccessibility2.js @@ -9,7 +9,7 @@ var c = C.x; var C = (function () { function C() { } - C.x = 1; return C; }()); +C.x = 1; var c = C.x; diff --git a/tests/baselines/reference/quotedPropertyName2.js b/tests/baselines/reference/quotedPropertyName2.js index 1c4d85076eac1..550e52997027f 100644 --- a/tests/baselines/reference/quotedPropertyName2.js +++ b/tests/baselines/reference/quotedPropertyName2.js @@ -7,6 +7,6 @@ class Test1 { var Test1 = (function () { function Test1() { } - Test1["prop1"] = 0; return Test1; }()); +Test1["prop1"] = 0; diff --git a/tests/baselines/reference/reassignStaticProp.js b/tests/baselines/reference/reassignStaticProp.js index 2bf2bafa128e2..d9c37c29ad5b6 100644 --- a/tests/baselines/reference/reassignStaticProp.js +++ b/tests/baselines/reference/reassignStaticProp.js @@ -15,6 +15,6 @@ class foo { var foo = (function () { function foo() { } - foo.bar = 1; return foo; }()); +foo.bar = 1; diff --git a/tests/baselines/reference/sourceMap-FileWithComments.js b/tests/baselines/reference/sourceMap-FileWithComments.js index 9bb18dba33d5f..dd2131889afcc 100644 --- a/tests/baselines/reference/sourceMap-FileWithComments.js +++ b/tests/baselines/reference/sourceMap-FileWithComments.js @@ -49,10 +49,10 @@ var Shapes; } // Instance member Point.prototype.getDist = function () { return Math.sqrt(this.x * this.x + this.y * this.y); }; - // Static member - Point.origin = new Point(0, 0); return Point; }()); + // Static member + Point.origin = new Point(0, 0); Shapes.Point = Point; // Variable comment after class var a = 10; diff --git a/tests/baselines/reference/sourceMap-FileWithComments.js.map b/tests/baselines/reference/sourceMap-FileWithComments.js.map index f3e9674336df7..80437501d33a3 100644 --- a/tests/baselines/reference/sourceMap-FileWithComments.js.map +++ b/tests/baselines/reference/sourceMap-FileWithComments.js.map @@ -1,2 +1,2 @@ //// [sourceMap-FileWithComments.js.map] -{"version":3,"file":"sourceMap-FileWithComments.js","sourceRoot":"","sources":["sourceMap-FileWithComments.ts"],"names":[],"mappings":"AAMA,SAAS;AACT,IAAO,MAAM,CAwBZ;AAxBD,WAAO,MAAM,EAAC,CAAC;IAEX,QAAQ;IACR;QACI,cAAc;QACd,eAAmB,CAAS,EAAS,CAAS;YAA3B,MAAC,GAAD,CAAC,CAAQ;YAAS,MAAC,GAAD,CAAC,CAAQ;QAAI,CAAC;QAEnD,kBAAkB;QAClB,uBAAO,GAAP,cAAY,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAElE,gBAAgB;QACT,YAAM,GAAG,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpC,YAAC;IAAD,CAAC,AATD,IASC;IATY,YAAK,QASjB,CAAA;IAED,+BAA+B;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;IAEX;IACA,CAAC;IADe,UAAG,MAClB,CAAA;IAED;;MAEE;IACF,IAAI,CAAC,GAAG,EAAE,CAAC;AACf,CAAC,EAxBM,MAAM,KAAN,MAAM,QAwBZ;AAED,qBAAqB;AACrB,IAAI,CAAC,GAAW,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvC,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMap-FileWithComments.js","sourceRoot":"","sources":["sourceMap-FileWithComments.ts"],"names":[],"mappings":"AAMA,SAAS;AACT,IAAO,MAAM,CAwBZ;AAxBD,WAAO,MAAM,EAAC,CAAC;IAEX,QAAQ;IACR;QACI,cAAc;QACd,eAAmB,CAAS,EAAS,CAAS;YAA3B,MAAC,GAAD,CAAC,CAAQ;YAAS,MAAC,GAAD,CAAC,CAAQ;QAAI,CAAC;QAEnD,kBAAkB;QAClB,uBAAO,GAAP,cAAY,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAItE,YAAC;IAAD,CAAC,AATD;IAOI,gBAAgB;IACT,YAAM,GAAG,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAClC;IATY,YAAK,QASjB,CAAA;IAED,+BAA+B;IAC/B,IAAI,CAAC,GAAG,EAAE,CAAC;IAEX;IACA,CAAC;IADe,UAAG,MAClB,CAAA;IAED;;MAEE;IACF,IAAI,CAAC,GAAG,EAAE,CAAC;AACf,CAAC,EAxBM,MAAM,KAAN,MAAM,QAwBZ;AAED,qBAAqB;AACrB,IAAI,CAAC,GAAW,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvC,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMap-FileWithComments.sourcemap.txt b/tests/baselines/reference/sourceMap-FileWithComments.sourcemap.txt index 3bcf26345079d..2abfabff566b6 100644 --- a/tests/baselines/reference/sourceMap-FileWithComments.sourcemap.txt +++ b/tests/baselines/reference/sourceMap-FileWithComments.sourcemap.txt @@ -271,93 +271,90 @@ sourceFile:sourceMap-FileWithComments.ts 28>Emitted(12, 102) Source(16, 74) + SourceIndex(0) 29>Emitted(12, 103) Source(16, 75) + SourceIndex(0) --- ->>> // Static member -1 >^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^ -3 > ^^^^^^^^^^^^^^^^-> -1 > - > - > -2 > // Static member -1 >Emitted(13, 9) Source(18, 9) + SourceIndex(0) -2 >Emitted(13, 25) Source(18, 25) + SourceIndex(0) ---- ->>> Point.origin = new Point(0, 0); -1->^^^^^^^^ -2 > ^^^^^^^^^^^^ -3 > ^^^ -4 > ^^^^ -5 > ^^^^^ -6 > ^ -7 > ^ -8 > ^^ -9 > ^ -10> ^ -11> ^ -1-> - > static -2 > origin -3 > = -4 > new -5 > Point -6 > ( -7 > 0 -8 > , -9 > 0 -10> ) -11> ; -1->Emitted(14, 9) Source(19, 16) + SourceIndex(0) -2 >Emitted(14, 21) Source(19, 22) + SourceIndex(0) -3 >Emitted(14, 24) Source(19, 25) + SourceIndex(0) -4 >Emitted(14, 28) Source(19, 29) + SourceIndex(0) -5 >Emitted(14, 33) Source(19, 34) + SourceIndex(0) -6 >Emitted(14, 34) Source(19, 35) + SourceIndex(0) -7 >Emitted(14, 35) Source(19, 36) + SourceIndex(0) -8 >Emitted(14, 37) Source(19, 38) + SourceIndex(0) -9 >Emitted(14, 38) Source(19, 39) + SourceIndex(0) -10>Emitted(14, 39) Source(19, 40) + SourceIndex(0) -11>Emitted(14, 40) Source(19, 41) + SourceIndex(0) ---- >>> return Point; 1 >^^^^^^^^ 2 > ^^^^^^^^^^^^ 1 > + > + > // Static member + > static origin = new Point(0, 0); > 2 > } -1 >Emitted(15, 9) Source(20, 5) + SourceIndex(0) -2 >Emitted(15, 21) Source(20, 6) + SourceIndex(0) +1 >Emitted(13, 9) Source(20, 5) + SourceIndex(0) +2 >Emitted(13, 21) Source(20, 6) + SourceIndex(0) --- >>> }()); 1 >^^^^ 2 > ^ 3 > -4 > ^^^^ -5 > ^^^^^^^^^^^^^^^^^-> +4 > ^^^^^^^^^^^^^^^^-> 1 > 2 > } 3 > -4 > export class Point implements IPoint { - > // Constructor - > constructor(public x: number, public y: number) { } - > - > // Instance member - > getDist() { return Math.sqrt(this.x * this.x + this.y * this.y); } - > - > // Static member - > static origin = new Point(0, 0); - > } -1 >Emitted(16, 5) Source(20, 5) + SourceIndex(0) -2 >Emitted(16, 6) Source(20, 6) + SourceIndex(0) -3 >Emitted(16, 6) Source(11, 5) + SourceIndex(0) -4 >Emitted(16, 10) Source(20, 6) + SourceIndex(0) +1 >Emitted(14, 5) Source(20, 5) + SourceIndex(0) +2 >Emitted(14, 6) Source(20, 6) + SourceIndex(0) +3 >Emitted(14, 6) Source(11, 5) + SourceIndex(0) --- ->>> Shapes.Point = Point; +>>> // Static member +1->^^^^ +2 > ^^^^^^^^^^^^^^^^ +3 > ^^^^^^^^^^^^^^^^-> +1->export class Point implements IPoint { + > // Constructor + > constructor(public x: number, public y: number) { } + > + > // Instance member + > getDist() { return Math.sqrt(this.x * this.x + this.y * this.y); } + > + > +2 > // Static member +1->Emitted(15, 5) Source(18, 9) + SourceIndex(0) +2 >Emitted(15, 21) Source(18, 25) + SourceIndex(0) +--- +>>> Point.origin = new Point(0, 0); 1->^^^^ 2 > ^^^^^^^^^^^^ +3 > ^^^ +4 > ^^^^ +5 > ^^^^^ +6 > ^ +7 > ^ +8 > ^^ +9 > ^ +10> ^ +11> ^ +1-> + > static +2 > origin +3 > = +4 > new +5 > Point +6 > ( +7 > 0 +8 > , +9 > 0 +10> ) +11> ; + > } +1->Emitted(16, 5) Source(19, 16) + SourceIndex(0) +2 >Emitted(16, 17) Source(19, 22) + SourceIndex(0) +3 >Emitted(16, 20) Source(19, 25) + SourceIndex(0) +4 >Emitted(16, 24) Source(19, 29) + SourceIndex(0) +5 >Emitted(16, 29) Source(19, 34) + SourceIndex(0) +6 >Emitted(16, 30) Source(19, 35) + SourceIndex(0) +7 >Emitted(16, 31) Source(19, 36) + SourceIndex(0) +8 >Emitted(16, 33) Source(19, 38) + SourceIndex(0) +9 >Emitted(16, 34) Source(19, 39) + SourceIndex(0) +10>Emitted(16, 35) Source(19, 40) + SourceIndex(0) +11>Emitted(16, 36) Source(20, 6) + SourceIndex(0) +--- +>>> Shapes.Point = Point; +1 >^^^^ +2 > ^^^^^^^^^^^^ 3 > ^^^^^^^^ 4 > ^ 5 > ^^^^^^^^^^^-> -1-> +1 > 2 > Point 3 > implements IPoint { > // Constructor @@ -370,7 +367,7 @@ sourceFile:sourceMap-FileWithComments.ts > static origin = new Point(0, 0); > } 4 > -1->Emitted(17, 5) Source(11, 18) + SourceIndex(0) +1 >Emitted(17, 5) Source(11, 18) + SourceIndex(0) 2 >Emitted(17, 17) Source(11, 23) + SourceIndex(0) 3 >Emitted(17, 25) Source(20, 6) + SourceIndex(0) 4 >Emitted(17, 26) Source(20, 6) + SourceIndex(0) diff --git a/tests/baselines/reference/sourceMapValidationDecorators.js b/tests/baselines/reference/sourceMapValidationDecorators.js index c3bb5cd722526..63cdb25900cb9 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.js +++ b/tests/baselines/reference/sourceMapValidationDecorators.js @@ -88,37 +88,37 @@ var Greeter = (function () { enumerable: true, configurable: true }); - Greeter.x1 = 10; - __decorate([ - PropertyDecorator1, - PropertyDecorator2(40) - ], Greeter.prototype, "greet", null); - __decorate([ - PropertyDecorator1, - PropertyDecorator2(50) - ], Greeter.prototype, "x", void 0); - __decorate([ - __param(0, ParameterDecorator1), - __param(0, ParameterDecorator2(70)) - ], Greeter.prototype, "fn", null); - __decorate([ - PropertyDecorator1, - PropertyDecorator2(80), - __param(0, ParameterDecorator1), - __param(0, ParameterDecorator2(90)) - ], Greeter.prototype, "greetings", null); - __decorate([ - PropertyDecorator1, - PropertyDecorator2(60) - ], Greeter, "x1", void 0); - Greeter = __decorate([ - ClassDecorator1, - ClassDecorator2(10), - __param(0, ParameterDecorator1), - __param(0, ParameterDecorator2(20)), - __param(1, ParameterDecorator1), - __param(1, ParameterDecorator2(30)) - ], Greeter); return Greeter; }()); +Greeter.x1 = 10; +__decorate([ + PropertyDecorator1, + PropertyDecorator2(40) +], Greeter.prototype, "greet", null); +__decorate([ + PropertyDecorator1, + PropertyDecorator2(50) +], Greeter.prototype, "x", void 0); +__decorate([ + __param(0, ParameterDecorator1), + __param(0, ParameterDecorator2(70)) +], Greeter.prototype, "fn", null); +__decorate([ + PropertyDecorator1, + PropertyDecorator2(80), + __param(0, ParameterDecorator1), + __param(0, ParameterDecorator2(90)) +], Greeter.prototype, "greetings", null); +__decorate([ + PropertyDecorator1, + PropertyDecorator2(60) +], Greeter, "x1", void 0); +Greeter = __decorate([ + ClassDecorator1, + ClassDecorator2(10), + __param(0, ParameterDecorator1), + __param(0, ParameterDecorator2(20)), + __param(1, ParameterDecorator1), + __param(1, ParameterDecorator2(30)) +], Greeter); //# sourceMappingURL=sourceMapValidationDecorators.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDecorators.js.map b/tests/baselines/reference/sourceMapValidationDecorators.js.map index 0a6b45eb383d3..18b24ddf37e24 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.js.map +++ b/tests/baselines/reference/sourceMapValidationDecorators.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationDecorators.js.map] -{"version":3,"file":"sourceMapValidationDecorators.js","sourceRoot":"","sources":["sourceMapValidationDecorators.ts"],"names":[],"mappings":";;;;;;;;;AASA;IACI,iBAGS,QAAgB;QAIvB,WAAc;aAAd,WAAc,CAAd,sBAAc,CAAd,IAAc;YAAd,0BAAc;;QAJP,aAAQ,GAAR,QAAQ,CAAQ;IAKzB,CAAC;IAID,uBAAK,GAAL;QACI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5C,CAAC;IAUO,oBAAE,GAAV,UAGE,CAAS;QACP,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAID,sBAAI,8BAAS;aAAb;YACI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzB,CAAC;aAED,UAGE,SAAiB;YACf,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,CAAC;;;OAPA;IAbc,UAAE,GAAW,EAAE,CAAC;IAZ/B;QAAC,kBAAkB;QAClB,kBAAkB,CAAC,EAAE,CAAC;wCAAA;IAKvB;QAAC,kBAAkB;QAClB,kBAAkB,CAAC,EAAE,CAAC;sCAAA;IAQrB;mBAAC,mBAAmB;mBACnB,mBAAmB,CAAC,EAAE,CAAC;qCAAA;IAK1B;QAAC,kBAAkB;QAClB,kBAAkB,CAAC,EAAE,CAAC;mBAMpB,mBAAmB;mBACnB,mBAAmB,CAAC,EAAE,CAAC;4CAPH;IAZvB;QAAC,kBAAkB;QAClB,kBAAkB,CAAC,EAAE,CAAC;6BAAA;IAxB3B;QAAC,eAAe;QACf,eAAe,CAAC,EAAE,CAAC;mBAGb,mBAAmB;mBACnB,mBAAmB,CAAC,EAAE,CAAC;mBAGvB,mBAAmB;mBACnB,mBAAmB,CAAC,EAAE,CAAC;eARV;IA6CpB,cAAC;AAAD,CAAC,AA5CD,IA4CC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationDecorators.js","sourceRoot":"","sources":["sourceMapValidationDecorators.ts"],"names":[],"mappings":";;;;;;;;;AASA;IACI,iBAGS,QAAgB;QAIvB,WAAc;aAAd,WAAc,CAAd,sBAAc,CAAd,IAAc;YAAd,0BAAc;;QAJP,aAAQ,GAAR,QAAQ,CAAQ;IAKzB,CAAC;IAID,uBAAK,GAAL;QACI,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5C,CAAC;IAUO,oBAAE,GAAV,UAGE,CAAS;QACP,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAID,sBAAI,8BAAS;aAAb;YACI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QACzB,CAAC;aAED,UAGE,SAAiB;YACf,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC9B,CAAC;;;OAPA;IAQL,cAAC;AAAD,CAAC,AA5CD;AAuBmB,UAAE,GAAW,EAAE,CAAC;AAZ/B;IAAC,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,CAAC;oCAAA;AAKvB;IAAC,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,CAAC;kCAAA;AAQrB;eAAC,mBAAmB;eACnB,mBAAmB,CAAC,EAAE,CAAC;iCAAA;AAK1B;IAAC,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,CAAC;eAMpB,mBAAmB;eACnB,mBAAmB,CAAC,EAAE,CAAC;wCAPH;AAZvB;IAAC,kBAAkB;IAClB,kBAAkB,CAAC,EAAE,CAAC;yBAAA;AAxB3B;IAAC,eAAe;IACf,eAAe,CAAC,EAAE,CAAC;eAGb,mBAAmB;eACnB,mBAAmB,CAAC,EAAE,CAAC;eAGvB,mBAAmB;eACnB,mBAAmB,CAAC,EAAE,CAAC;WARV;AA6CnB"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt b/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt index 168204288569d..58b5eaefc7ca5 100644 --- a/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationDecorators.sourcemap.txt @@ -356,113 +356,164 @@ sourceFile:sourceMapValidationDecorators.ts >>> configurable: true >>> }); 1->^^^^^^^ -2 > ^^^^^^^^^^^^^^-> +2 > ^^^^^^^^^^^^^-> 1-> 1->Emitted(33, 8) Source(46, 6) + SourceIndex(0) --- ->>> Greeter.x1 = 10; +>>> return Greeter; 1->^^^^ -2 > ^^^^^^^^^^ -3 > ^^^ -4 > ^^ -5 > ^ +2 > ^^^^^^^^^^^^^^ +1-> + > + > set greetings( + > @ParameterDecorator1 + > @ParameterDecorator2(90) + > greetings: string) { + > this.greeting = greetings; + > } + > +2 > } +1->Emitted(34, 5) Source(54, 1) + SourceIndex(0) +2 >Emitted(34, 19) Source(54, 2) + SourceIndex(0) +--- +>>>}()); +1 > +2 >^ +3 > +4 > ^^^^^^^^^^^^^^^^-> +1 > +2 >} +3 > +1 >Emitted(35, 1) Source(54, 1) + SourceIndex(0) +2 >Emitted(35, 2) Source(54, 2) + SourceIndex(0) +3 >Emitted(35, 2) Source(10, 1) + SourceIndex(0) +--- +>>>Greeter.x1 = 10; 1-> -2 > x1 -3 > : number = -4 > 10 -5 > ; -1->Emitted(34, 5) Source(33, 20) + SourceIndex(0) -2 >Emitted(34, 15) Source(33, 22) + SourceIndex(0) -3 >Emitted(34, 18) Source(33, 33) + SourceIndex(0) -4 >Emitted(34, 20) Source(33, 35) + SourceIndex(0) -5 >Emitted(34, 21) Source(33, 36) + SourceIndex(0) ---- ->>> __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^-> +2 >^^^^^^^^^^ +3 > ^^^ +4 > ^^ +5 > ^ +1->class Greeter { + > constructor( + > @ParameterDecorator1 + > @ParameterDecorator2(20) + > public greeting: string, + > + > @ParameterDecorator1 + > @ParameterDecorator2(30) + > ...b: string[]) { + > } + > + > @PropertyDecorator1 + > @PropertyDecorator2(40) + > greet() { + > return "

" + this.greeting + "

"; + > } + > + > @PropertyDecorator1 + > @PropertyDecorator2(50) + > private x: string; + > + > @PropertyDecorator1 + > @PropertyDecorator2(60) + > private static +2 >x1 +3 > : number = +4 > 10 +5 > ; +1->Emitted(36, 1) Source(33, 20) + SourceIndex(0) +2 >Emitted(36, 11) Source(33, 22) + SourceIndex(0) +3 >Emitted(36, 14) Source(33, 33) + SourceIndex(0) +4 >Emitted(36, 16) Source(33, 35) + SourceIndex(0) +5 >Emitted(36, 17) Source(33, 36) + SourceIndex(0) +--- +>>>__decorate([ 1 > -1 >Emitted(35, 5) Source(21, 5) + SourceIndex(0) +2 >^^^^^^^^^^^^^^^^^^^^^^^^-> +1 > +1 >Emitted(37, 1) Source(21, 5) + SourceIndex(0) --- ->>> PropertyDecorator1, -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^^^^^-> +>>> PropertyDecorator1, +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^^^^^-> 1->@ -2 > PropertyDecorator1 -1->Emitted(36, 9) Source(21, 6) + SourceIndex(0) -2 >Emitted(36, 27) Source(21, 24) + SourceIndex(0) +2 > PropertyDecorator1 +1->Emitted(38, 5) Source(21, 6) + SourceIndex(0) +2 >Emitted(38, 23) Source(21, 24) + SourceIndex(0) --- ->>> PropertyDecorator2(40) -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^^^^^^^^^^^^-> +>>> PropertyDecorator2(40) +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^^^^^^^^^^^^-> 1-> > @ -2 > PropertyDecorator2 -3 > ( -4 > 40 -5 > ) -1->Emitted(37, 9) Source(22, 6) + SourceIndex(0) -2 >Emitted(37, 27) Source(22, 24) + SourceIndex(0) -3 >Emitted(37, 28) Source(22, 25) + SourceIndex(0) -4 >Emitted(37, 30) Source(22, 27) + SourceIndex(0) -5 >Emitted(37, 31) Source(22, 28) + SourceIndex(0) ---- ->>> ], Greeter.prototype, "greet", null); -1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 > PropertyDecorator2 +3 > ( +4 > 40 +5 > ) +1->Emitted(39, 5) Source(22, 6) + SourceIndex(0) +2 >Emitted(39, 23) Source(22, 24) + SourceIndex(0) +3 >Emitted(39, 24) Source(22, 25) + SourceIndex(0) +4 >Emitted(39, 26) Source(22, 27) + SourceIndex(0) +5 >Emitted(39, 27) Source(22, 28) + SourceIndex(0) +--- +>>>], Greeter.prototype, "greet", null); +1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> -1->Emitted(38, 41) Source(22, 28) + SourceIndex(0) +1->Emitted(40, 37) Source(22, 28) + SourceIndex(0) --- ->>> __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^-> +>>>__decorate([ +1 > +2 >^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > greet() { > return "

" + this.greeting + "

"; > } > > -1 >Emitted(39, 5) Source(27, 5) + SourceIndex(0) +1 >Emitted(41, 1) Source(27, 5) + SourceIndex(0) --- ->>> PropertyDecorator1, -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^^^^^-> +>>> PropertyDecorator1, +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^^^^^-> 1->@ -2 > PropertyDecorator1 -1->Emitted(40, 9) Source(27, 6) + SourceIndex(0) -2 >Emitted(40, 27) Source(27, 24) + SourceIndex(0) +2 > PropertyDecorator1 +1->Emitted(42, 5) Source(27, 6) + SourceIndex(0) +2 >Emitted(42, 23) Source(27, 24) + SourceIndex(0) --- ->>> PropertyDecorator2(50) -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^^^^^^^^^^-> +>>> PropertyDecorator2(50) +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^^^^^^^^^^-> 1-> > @ -2 > PropertyDecorator2 -3 > ( -4 > 50 -5 > ) -1->Emitted(41, 9) Source(28, 6) + SourceIndex(0) -2 >Emitted(41, 27) Source(28, 24) + SourceIndex(0) -3 >Emitted(41, 28) Source(28, 25) + SourceIndex(0) -4 >Emitted(41, 30) Source(28, 27) + SourceIndex(0) -5 >Emitted(41, 31) Source(28, 28) + SourceIndex(0) ---- ->>> ], Greeter.prototype, "x", void 0); -1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 > PropertyDecorator2 +3 > ( +4 > 50 +5 > ) +1->Emitted(43, 5) Source(28, 6) + SourceIndex(0) +2 >Emitted(43, 23) Source(28, 24) + SourceIndex(0) +3 >Emitted(43, 24) Source(28, 25) + SourceIndex(0) +4 >Emitted(43, 26) Source(28, 27) + SourceIndex(0) +5 >Emitted(43, 27) Source(28, 28) + SourceIndex(0) +--- +>>>], Greeter.prototype, "x", void 0); +1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> -1->Emitted(42, 39) Source(28, 28) + SourceIndex(0) +1->Emitted(44, 35) Source(28, 28) + SourceIndex(0) --- ->>> __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> +>>>__decorate([ +1 > +2 >^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > private x: string; > @@ -472,83 +523,83 @@ sourceFile:sourceMapValidationDecorators.ts > > private fn( > -1 >Emitted(43, 5) Source(36, 7) + SourceIndex(0) +1 >Emitted(45, 1) Source(36, 7) + SourceIndex(0) --- ->>> __param(0, ParameterDecorator1), -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^^^^^^-> +>>> __param(0, ParameterDecorator1), +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^^^^^^-> 1->@ -2 > ParameterDecorator1 -1->Emitted(44, 20) Source(36, 8) + SourceIndex(0) -2 >Emitted(44, 39) Source(36, 27) + SourceIndex(0) ---- ->>> __param(0, ParameterDecorator2(70)) -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ +2 > ParameterDecorator1 +1->Emitted(46, 16) Source(36, 8) + SourceIndex(0) +2 >Emitted(46, 35) Source(36, 27) + SourceIndex(0) +--- +>>> __param(0, ParameterDecorator2(70)) +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ 1-> > @ -2 > ParameterDecorator2 -3 > ( -4 > 70 -5 > ) -1->Emitted(45, 20) Source(37, 8) + SourceIndex(0) -2 >Emitted(45, 39) Source(37, 27) + SourceIndex(0) -3 >Emitted(45, 40) Source(37, 28) + SourceIndex(0) -4 >Emitted(45, 42) Source(37, 30) + SourceIndex(0) -5 >Emitted(45, 43) Source(37, 31) + SourceIndex(0) ---- ->>> ], Greeter.prototype, "fn", null); -1 >^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 > ParameterDecorator2 +3 > ( +4 > 70 +5 > ) +1->Emitted(47, 16) Source(37, 8) + SourceIndex(0) +2 >Emitted(47, 35) Source(37, 27) + SourceIndex(0) +3 >Emitted(47, 36) Source(37, 28) + SourceIndex(0) +4 >Emitted(47, 38) Source(37, 30) + SourceIndex(0) +5 >Emitted(47, 39) Source(37, 31) + SourceIndex(0) +--- +>>>], Greeter.prototype, "fn", null); +1 >^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1 > -1 >Emitted(46, 38) Source(37, 31) + SourceIndex(0) +1 >Emitted(48, 34) Source(37, 31) + SourceIndex(0) --- ->>> __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^-> +>>>__decorate([ +1 > +2 >^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > > x: number) { > return this.greeting; > } > > -1 >Emitted(47, 5) Source(42, 5) + SourceIndex(0) +1 >Emitted(49, 1) Source(42, 5) + SourceIndex(0) --- ->>> PropertyDecorator1, -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^^^^^^-> +>>> PropertyDecorator1, +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^^^^^^-> 1->@ -2 > PropertyDecorator1 -1->Emitted(48, 9) Source(42, 6) + SourceIndex(0) -2 >Emitted(48, 27) Source(42, 24) + SourceIndex(0) +2 > PropertyDecorator1 +1->Emitted(50, 5) Source(42, 6) + SourceIndex(0) +2 >Emitted(50, 23) Source(42, 24) + SourceIndex(0) --- ->>> PropertyDecorator2(80), -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^^^^^^^^^^^-> +>>> PropertyDecorator2(80), +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^^^^^^^^^^^-> 1-> > @ -2 > PropertyDecorator2 -3 > ( -4 > 80 -5 > ) -1->Emitted(49, 9) Source(43, 6) + SourceIndex(0) -2 >Emitted(49, 27) Source(43, 24) + SourceIndex(0) -3 >Emitted(49, 28) Source(43, 25) + SourceIndex(0) -4 >Emitted(49, 30) Source(43, 27) + SourceIndex(0) -5 >Emitted(49, 31) Source(43, 28) + SourceIndex(0) ---- ->>> __param(0, ParameterDecorator1), -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^^^^^^-> +2 > PropertyDecorator2 +3 > ( +4 > 80 +5 > ) +1->Emitted(51, 5) Source(43, 6) + SourceIndex(0) +2 >Emitted(51, 23) Source(43, 24) + SourceIndex(0) +3 >Emitted(51, 24) Source(43, 25) + SourceIndex(0) +4 >Emitted(51, 26) Source(43, 27) + SourceIndex(0) +5 >Emitted(51, 27) Source(43, 28) + SourceIndex(0) +--- +>>> __param(0, ParameterDecorator1), +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^^^^^^-> 1-> > get greetings() { > return this.greeting; @@ -556,176 +607,175 @@ sourceFile:sourceMapValidationDecorators.ts > > set greetings( > @ -2 > ParameterDecorator1 -1->Emitted(50, 20) Source(49, 8) + SourceIndex(0) -2 >Emitted(50, 39) Source(49, 27) + SourceIndex(0) ---- ->>> __param(0, ParameterDecorator2(90)) -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^^^^-> +2 > ParameterDecorator1 +1->Emitted(52, 16) Source(49, 8) + SourceIndex(0) +2 >Emitted(52, 35) Source(49, 27) + SourceIndex(0) +--- +>>> __param(0, ParameterDecorator2(90)) +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^^^^-> 1-> > @ -2 > ParameterDecorator2 -3 > ( -4 > 90 -5 > ) -1->Emitted(51, 20) Source(50, 8) + SourceIndex(0) -2 >Emitted(51, 39) Source(50, 27) + SourceIndex(0) -3 >Emitted(51, 40) Source(50, 28) + SourceIndex(0) -4 >Emitted(51, 42) Source(50, 30) + SourceIndex(0) -5 >Emitted(51, 43) Source(50, 31) + SourceIndex(0) ---- ->>> ], Greeter.prototype, "greetings", null); -1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 > ParameterDecorator2 +3 > ( +4 > 90 +5 > ) +1->Emitted(53, 16) Source(50, 8) + SourceIndex(0) +2 >Emitted(53, 35) Source(50, 27) + SourceIndex(0) +3 >Emitted(53, 36) Source(50, 28) + SourceIndex(0) +4 >Emitted(53, 38) Source(50, 30) + SourceIndex(0) +5 >Emitted(53, 39) Source(50, 31) + SourceIndex(0) +--- +>>>], Greeter.prototype, "greetings", null); +1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> -1->Emitted(52, 45) Source(43, 28) + SourceIndex(0) +1->Emitted(54, 41) Source(43, 28) + SourceIndex(0) --- ->>> __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^^^^-> +>>>__decorate([ +1 > +2 >^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > -1 >Emitted(53, 5) Source(31, 5) + SourceIndex(0) +1 >Emitted(55, 1) Source(31, 5) + SourceIndex(0) --- ->>> PropertyDecorator1, -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^^^^^-> +>>> PropertyDecorator1, +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^^^^^-> 1->@ -2 > PropertyDecorator1 -1->Emitted(54, 9) Source(31, 6) + SourceIndex(0) -2 >Emitted(54, 27) Source(31, 24) + SourceIndex(0) +2 > PropertyDecorator1 +1->Emitted(56, 5) Source(31, 6) + SourceIndex(0) +2 >Emitted(56, 23) Source(31, 24) + SourceIndex(0) --- ->>> PropertyDecorator2(60) -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^-> +>>> PropertyDecorator2(60) +1->^^^^ +2 > ^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^-> 1-> > @ -2 > PropertyDecorator2 -3 > ( -4 > 60 -5 > ) -1->Emitted(55, 9) Source(32, 6) + SourceIndex(0) -2 >Emitted(55, 27) Source(32, 24) + SourceIndex(0) -3 >Emitted(55, 28) Source(32, 25) + SourceIndex(0) -4 >Emitted(55, 30) Source(32, 27) + SourceIndex(0) -5 >Emitted(55, 31) Source(32, 28) + SourceIndex(0) ---- ->>> ], Greeter, "x1", void 0); -1->^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 > PropertyDecorator2 +3 > ( +4 > 60 +5 > ) +1->Emitted(57, 5) Source(32, 6) + SourceIndex(0) +2 >Emitted(57, 23) Source(32, 24) + SourceIndex(0) +3 >Emitted(57, 24) Source(32, 25) + SourceIndex(0) +4 >Emitted(57, 26) Source(32, 27) + SourceIndex(0) +5 >Emitted(57, 27) Source(32, 28) + SourceIndex(0) +--- +>>>], Greeter, "x1", void 0); +1->^^^^^^^^^^^^^^^^^^^^^^^^^ 1-> -1->Emitted(56, 30) Source(32, 28) + SourceIndex(0) +1->Emitted(58, 26) Source(32, 28) + SourceIndex(0) --- ->>> Greeter = __decorate([ -1 >^^^^ -2 > ^^^^^^^^^^^^^^^^^^^^^-> +>>>Greeter = __decorate([ +1 > +2 >^^^^^^^^^^^^^^^^^^^^^-> 1 > -1 >Emitted(57, 5) Source(8, 1) + SourceIndex(0) +1 >Emitted(59, 1) Source(8, 1) + SourceIndex(0) --- ->>> ClassDecorator1, -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^ -3 > ^^^^^^-> +>>> ClassDecorator1, +1->^^^^ +2 > ^^^^^^^^^^^^^^^ +3 > ^^^^^^-> 1->@ -2 > ClassDecorator1 -1->Emitted(58, 9) Source(8, 2) + SourceIndex(0) -2 >Emitted(58, 24) Source(8, 17) + SourceIndex(0) +2 > ClassDecorator1 +1->Emitted(60, 5) Source(8, 2) + SourceIndex(0) +2 >Emitted(60, 20) Source(8, 17) + SourceIndex(0) --- ->>> ClassDecorator2(10), -1->^^^^^^^^ -2 > ^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ -6 > ^^^^^^^^^^^^^^-> +>>> ClassDecorator2(10), +1->^^^^ +2 > ^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ +6 > ^^^^^^^^^^^^^^-> 1-> >@ -2 > ClassDecorator2 -3 > ( -4 > 10 -5 > ) -1->Emitted(59, 9) Source(9, 2) + SourceIndex(0) -2 >Emitted(59, 24) Source(9, 17) + SourceIndex(0) -3 >Emitted(59, 25) Source(9, 18) + SourceIndex(0) -4 >Emitted(59, 27) Source(9, 20) + SourceIndex(0) -5 >Emitted(59, 28) Source(9, 21) + SourceIndex(0) ---- ->>> __param(0, ParameterDecorator1), -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^^^^^^^-> +2 > ClassDecorator2 +3 > ( +4 > 10 +5 > ) +1->Emitted(61, 5) Source(9, 2) + SourceIndex(0) +2 >Emitted(61, 20) Source(9, 17) + SourceIndex(0) +3 >Emitted(61, 21) Source(9, 18) + SourceIndex(0) +4 >Emitted(61, 23) Source(9, 20) + SourceIndex(0) +5 >Emitted(61, 24) Source(9, 21) + SourceIndex(0) +--- +>>> __param(0, ParameterDecorator1), +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^^^^^^^-> 1-> >class Greeter { > constructor( > @ -2 > ParameterDecorator1 -1->Emitted(60, 20) Source(12, 8) + SourceIndex(0) -2 >Emitted(60, 39) Source(12, 27) + SourceIndex(0) ---- ->>> __param(0, ParameterDecorator2(20)), -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ +2 > ParameterDecorator1 +1->Emitted(62, 16) Source(12, 8) + SourceIndex(0) +2 >Emitted(62, 35) Source(12, 27) + SourceIndex(0) +--- +>>> __param(0, ParameterDecorator2(20)), +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ 1-> > @ -2 > ParameterDecorator2 -3 > ( -4 > 20 -5 > ) -1->Emitted(61, 20) Source(13, 8) + SourceIndex(0) -2 >Emitted(61, 39) Source(13, 27) + SourceIndex(0) -3 >Emitted(61, 40) Source(13, 28) + SourceIndex(0) -4 >Emitted(61, 42) Source(13, 30) + SourceIndex(0) -5 >Emitted(61, 43) Source(13, 31) + SourceIndex(0) ---- ->>> __param(1, ParameterDecorator1), -1 >^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^^^^^^-> +2 > ParameterDecorator2 +3 > ( +4 > 20 +5 > ) +1->Emitted(63, 16) Source(13, 8) + SourceIndex(0) +2 >Emitted(63, 35) Source(13, 27) + SourceIndex(0) +3 >Emitted(63, 36) Source(13, 28) + SourceIndex(0) +4 >Emitted(63, 38) Source(13, 30) + SourceIndex(0) +5 >Emitted(63, 39) Source(13, 31) + SourceIndex(0) +--- +>>> __param(1, ParameterDecorator1), +1 >^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^^^^^^-> 1 > > public greeting: string, > > @ -2 > ParameterDecorator1 -1 >Emitted(62, 20) Source(16, 8) + SourceIndex(0) -2 >Emitted(62, 39) Source(16, 27) + SourceIndex(0) ---- ->>> __param(1, ParameterDecorator2(30)) -1->^^^^^^^^^^^^^^^^^^^ -2 > ^^^^^^^^^^^^^^^^^^^ -3 > ^ -4 > ^^ -5 > ^ +2 > ParameterDecorator1 +1 >Emitted(64, 16) Source(16, 8) + SourceIndex(0) +2 >Emitted(64, 35) Source(16, 27) + SourceIndex(0) +--- +>>> __param(1, ParameterDecorator2(30)) +1->^^^^^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^ +3 > ^ +4 > ^^ +5 > ^ 1-> > @ -2 > ParameterDecorator2 -3 > ( -4 > 30 -5 > ) -1->Emitted(63, 20) Source(17, 8) + SourceIndex(0) -2 >Emitted(63, 39) Source(17, 27) + SourceIndex(0) -3 >Emitted(63, 40) Source(17, 28) + SourceIndex(0) -4 >Emitted(63, 42) Source(17, 30) + SourceIndex(0) -5 >Emitted(63, 43) Source(17, 31) + SourceIndex(0) ---- ->>> ], Greeter); -1 >^^^^^^^^^^^^^^^ -2 > ^^^^^-> +2 > ParameterDecorator2 +3 > ( +4 > 30 +5 > ) +1->Emitted(65, 16) Source(17, 8) + SourceIndex(0) +2 >Emitted(65, 35) Source(17, 27) + SourceIndex(0) +3 >Emitted(65, 36) Source(17, 28) + SourceIndex(0) +4 >Emitted(65, 38) Source(17, 30) + SourceIndex(0) +5 >Emitted(65, 39) Source(17, 31) + SourceIndex(0) +--- +>>>], Greeter); +1 >^^^^^^^^^^^ +2 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1 > -1 >Emitted(64, 16) Source(9, 21) + SourceIndex(0) +1 >Emitted(66, 12) Source(9, 21) + SourceIndex(0) --- ->>> return Greeter; -1->^^^^ -2 > ^^^^^^^^^^^^^^ +>>>//# sourceMappingURL=sourceMapValidationDecorators.js.map1-> +2 >^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> 1-> >class Greeter { > constructor( @@ -771,68 +821,6 @@ sourceFile:sourceMapValidationDecorators.ts > greetings: string) { > this.greeting = greetings; > } - > -2 > } -1->Emitted(65, 5) Source(54, 1) + SourceIndex(0) -2 >Emitted(65, 19) Source(54, 2) + SourceIndex(0) ---- ->>>}()); -1 > -2 >^ -3 > -4 > ^^^^ -5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> -1 > -2 >} -3 > -4 > class Greeter { - > constructor( - > @ParameterDecorator1 - > @ParameterDecorator2(20) - > public greeting: string, - > - > @ParameterDecorator1 - > @ParameterDecorator2(30) - > ...b: string[]) { - > } - > - > @PropertyDecorator1 - > @PropertyDecorator2(40) - > greet() { - > return "

" + this.greeting + "

"; - > } - > - > @PropertyDecorator1 - > @PropertyDecorator2(50) - > private x: string; - > - > @PropertyDecorator1 - > @PropertyDecorator2(60) - > private static x1: number = 10; - > - > private fn( - > @ParameterDecorator1 - > @ParameterDecorator2(70) - > x: number) { - > return this.greeting; - > } - > - > @PropertyDecorator1 - > @PropertyDecorator2(80) - > get greetings() { - > return this.greeting; - > } - > - > set greetings( - > @ParameterDecorator1 - > @ParameterDecorator2(90) - > greetings: string) { - > this.greeting = greetings; - > } - > } -1 >Emitted(66, 1) Source(54, 1) + SourceIndex(0) -2 >Emitted(66, 2) Source(54, 2) + SourceIndex(0) -3 >Emitted(66, 2) Source(10, 1) + SourceIndex(0) -4 >Emitted(66, 6) Source(54, 2) + SourceIndex(0) ---- ->>>//# sourceMappingURL=sourceMapValidationDecorators.js.map \ No newline at end of file + >} +1->Emitted(67, 1) Source(54, 2) + SourceIndex(0) +--- \ No newline at end of file diff --git a/tests/baselines/reference/staticClassProps.js b/tests/baselines/reference/staticClassProps.js index c808e4eb7fd81..8a61bb7400fe7 100644 --- a/tests/baselines/reference/staticClassProps.js +++ b/tests/baselines/reference/staticClassProps.js @@ -13,6 +13,6 @@ var C = (function () { function C() { } C.prototype.foo = function () { }; - C.z = 1; return C; }()); +C.z = 1; diff --git a/tests/baselines/reference/staticMemberAccessOffDerivedType1.js b/tests/baselines/reference/staticMemberAccessOffDerivedType1.js index a05ece1dbbbcc..1c76a2512208f 100644 --- a/tests/baselines/reference/staticMemberAccessOffDerivedType1.js +++ b/tests/baselines/reference/staticMemberAccessOffDerivedType1.js @@ -28,6 +28,6 @@ var P = (function (_super) { function P() { _super.apply(this, arguments); } - P.SomeNumber = P.GetNumber(); return P; }(SomeBase)); +P.SomeNumber = P.GetNumber(); diff --git a/tests/baselines/reference/staticMemberInitialization.js b/tests/baselines/reference/staticMemberInitialization.js index c21c29ed4f815..13a5c8c25c6aa 100644 --- a/tests/baselines/reference/staticMemberInitialization.js +++ b/tests/baselines/reference/staticMemberInitialization.js @@ -10,8 +10,8 @@ var r = C.x; var C = (function () { function C() { } - C.x = 1; return C; }()); +C.x = 1; var c = new C(); var r = C.x; diff --git a/tests/baselines/reference/staticMemberWithStringAndNumberNames.js b/tests/baselines/reference/staticMemberWithStringAndNumberNames.js index 2fdd64ea04b76..9d8846ba963f0 100644 --- a/tests/baselines/reference/staticMemberWithStringAndNumberNames.js +++ b/tests/baselines/reference/staticMemberWithStringAndNumberNames.js @@ -19,10 +19,10 @@ var C = (function () { this.x2 = C['0']; this.x3 = C[0]; } - C["foo"] = 0; - C[0] = 1; - C.s = C['foo']; - C.s2 = C['0']; - C.s3 = C[0]; return C; }()); +C["foo"] = 0; +C[0] = 1; +C.s = C['foo']; +C.s2 = C['0']; +C.s3 = C[0]; diff --git a/tests/baselines/reference/staticModifierAlreadySeen.js b/tests/baselines/reference/staticModifierAlreadySeen.js index 76f8b050d6f39..c37d4c0807ad3 100644 --- a/tests/baselines/reference/staticModifierAlreadySeen.js +++ b/tests/baselines/reference/staticModifierAlreadySeen.js @@ -9,6 +9,6 @@ var C = (function () { function C() { } C.bar = function () { }; - C.foo = 1; return C; }()); +C.foo = 1; diff --git a/tests/baselines/reference/staticPropSuper.js b/tests/baselines/reference/staticPropSuper.js index f4bc5ece8d1cd..c25c406746dfb 100644 --- a/tests/baselines/reference/staticPropSuper.js +++ b/tests/baselines/reference/staticPropSuper.js @@ -52,9 +52,9 @@ var B = (function (_super) { var x = 1; // should not error _super.call(this); } - B.s = 9; return B; }(A)); +B.s = 9; var C = (function (_super) { __extends(C, _super); function C() { diff --git a/tests/baselines/reference/statics.js b/tests/baselines/reference/statics.js index 3776c09c8ceae..d52a28208e6c9 100644 --- a/tests/baselines/reference/statics.js +++ b/tests/baselines/reference/statics.js @@ -45,11 +45,11 @@ var M; C.f = function (n) { return "wow: " + (n + C.y + C.pub + C.priv); }; - C.priv = 2; - C.pub = 3; - C.y = C.priv; return C; }()); + C.priv = 2; + C.pub = 3; + C.y = C.priv; M.C = C; var c = C.y; function f() { diff --git a/tests/baselines/reference/staticsInConstructorBodies.js b/tests/baselines/reference/staticsInConstructorBodies.js index 9bc3ed293251c..edd49456ef711 100644 --- a/tests/baselines/reference/staticsInConstructorBodies.js +++ b/tests/baselines/reference/staticsInConstructorBodies.js @@ -11,6 +11,6 @@ var C = (function () { function C() { } C.m1 = function () { }; // ERROR - C.p1 = 0; // ERROR return C; }()); +C.p1 = 0; // ERROR diff --git a/tests/baselines/reference/staticsNotInScopeInClodule.js b/tests/baselines/reference/staticsNotInScopeInClodule.js index 150ae8aca5b24..e10ed2b31d387 100644 --- a/tests/baselines/reference/staticsNotInScopeInClodule.js +++ b/tests/baselines/reference/staticsNotInScopeInClodule.js @@ -11,9 +11,9 @@ module Clod { var Clod = (function () { function Clod() { } - Clod.x = 10; return Clod; }()); +Clod.x = 10; var Clod; (function (Clod) { var p = x; // x isn't in scope here diff --git a/tests/baselines/reference/strictModeInConstructor.js b/tests/baselines/reference/strictModeInConstructor.js index 3b31586154856..30dbfa58d7026 100644 --- a/tests/baselines/reference/strictModeInConstructor.js +++ b/tests/baselines/reference/strictModeInConstructor.js @@ -105,18 +105,18 @@ var Bs = (function (_super) { "use strict"; // No error _super.call(this); } - Bs.s = 9; return Bs; }(A)); +Bs.s = 9; var Cs = (function (_super) { __extends(Cs, _super); function Cs() { _super.call(this); // No error "use strict"; } - Cs.s = 9; return Cs; }(A)); +Cs.s = 9; var Ds = (function (_super) { __extends(Ds, _super); function Ds() { @@ -124,6 +124,6 @@ var Ds = (function (_super) { _super.call(this); "use strict"; } - Ds.s = 9; return Ds; }(A)); +Ds.s = 9; diff --git a/tests/baselines/reference/superAccess.js b/tests/baselines/reference/superAccess.js index 37c6a9816a605..6e5cd9aca4476 100644 --- a/tests/baselines/reference/superAccess.js +++ b/tests/baselines/reference/superAccess.js @@ -24,9 +24,9 @@ var MyBase = (function () { this.S2 = "test"; this.f = function () { return 5; }; } - MyBase.S1 = 5; return MyBase; }()); +MyBase.S1 = 5; var MyDerived = (function (_super) { __extends(MyDerived, _super); function MyDerived() { diff --git a/tests/baselines/reference/superAccess2.js b/tests/baselines/reference/superAccess2.js index b27d695cb31bc..c72bf387c24b4 100644 --- a/tests/baselines/reference/superAccess2.js +++ b/tests/baselines/reference/superAccess2.js @@ -59,6 +59,6 @@ var Q = (function (_super) { _super.x.call(this); // error _super.y.call(this); }; - Q.yy = _super.; // error for static initializer accessing super return Q; }(P)); +Q.yy = _super.; // error for static initializer accessing super diff --git a/tests/baselines/reference/thisInArrowFunctionInStaticInitializer1.js b/tests/baselines/reference/thisInArrowFunctionInStaticInitializer1.js index 4b23326c7a3d8..07d65c726b354 100644 --- a/tests/baselines/reference/thisInArrowFunctionInStaticInitializer1.js +++ b/tests/baselines/reference/thisInArrowFunctionInStaticInitializer1.js @@ -14,9 +14,9 @@ var Vector = (function () { function Vector() { var _this = this; } - Vector.foo = function () { - // 'this' should not be available in a static initializer. - log(_this); - }; return Vector; }()); +Vector.foo = function () { + // 'this' should not be available in a static initializer. + log(_this); +}; diff --git a/tests/baselines/reference/thisInConstructorParameter2.js b/tests/baselines/reference/thisInConstructorParameter2.js index 7260ecafcb98c..ba2917c5a4e66 100644 --- a/tests/baselines/reference/thisInConstructorParameter2.js +++ b/tests/baselines/reference/thisInConstructorParameter2.js @@ -25,6 +25,6 @@ var P = (function () { if (zz === void 0) { zz = this; } zz.y; }; - P.y = this; return P; }()); +P.y = this; diff --git a/tests/baselines/reference/thisInInvalidContexts.js b/tests/baselines/reference/thisInInvalidContexts.js index 75ccd12c2889c..76eeef0139c76 100644 --- a/tests/baselines/reference/thisInInvalidContexts.js +++ b/tests/baselines/reference/thisInInvalidContexts.js @@ -58,9 +58,9 @@ var __extends = (this && this.__extends) || function (d, b) { var ErrClass1 = (function () { function ErrClass1() { } - ErrClass1.t = this; // Error return ErrClass1; }()); +ErrClass1.t = this; // Error var BaseErrClass = (function () { function BaseErrClass(t) { } diff --git a/tests/baselines/reference/thisInInvalidContextsExternalModule.js b/tests/baselines/reference/thisInInvalidContextsExternalModule.js index 2e7e6d8b47cca..634b5ef0a2024 100644 --- a/tests/baselines/reference/thisInInvalidContextsExternalModule.js +++ b/tests/baselines/reference/thisInInvalidContextsExternalModule.js @@ -59,9 +59,9 @@ var __extends = (this && this.__extends) || function (d, b) { var ErrClass1 = (function () { function ErrClass1() { } - ErrClass1.t = this; // Error return ErrClass1; }()); +ErrClass1.t = this; // Error var BaseErrClass = (function () { function BaseErrClass(t) { } diff --git a/tests/baselines/reference/thisInOuterClassBody.js b/tests/baselines/reference/thisInOuterClassBody.js index 40e4a2e2485da..40b0e2b78ae58 100644 --- a/tests/baselines/reference/thisInOuterClassBody.js +++ b/tests/baselines/reference/thisInOuterClassBody.js @@ -36,6 +36,6 @@ var Foo = (function () { var a = this.y; var b = this.x; }; - Foo.y = this; return Foo; }()); +Foo.y = this; diff --git a/tests/baselines/reference/thisInPropertyBoundDeclarations.js b/tests/baselines/reference/thisInPropertyBoundDeclarations.js index 0b378cec51aaf..f5967fbb5b2ad 100644 --- a/tests/baselines/reference/thisInPropertyBoundDeclarations.js +++ b/tests/baselines/reference/thisInPropertyBoundDeclarations.js @@ -74,13 +74,13 @@ var Bug = (function () { Bug.prototype.foo = function (name) { this.name = name; }; - Bug.func = [ - function (that, name) { - that.foo(name); - } - ]; return Bug; }()); +Bug.func = [ + function (that, name) { + that.foo(name); + } +]; // Valid use of this in a property bound decl var A = (function () { function A() { diff --git a/tests/baselines/reference/thisInStaticMethod1.js b/tests/baselines/reference/thisInStaticMethod1.js index a42415c0b62b1..1e39ded3b6171 100644 --- a/tests/baselines/reference/thisInStaticMethod1.js +++ b/tests/baselines/reference/thisInStaticMethod1.js @@ -14,7 +14,7 @@ var foo = (function () { foo.bar = function () { return this.x; }; - foo.x = 3; return foo; }()); +foo.x = 3; var x = foo.bar(); diff --git a/tests/baselines/reference/thisTypeErrors.js b/tests/baselines/reference/thisTypeErrors.js index f246b80f4f4f6..5811ec6b70922 100644 --- a/tests/baselines/reference/thisTypeErrors.js +++ b/tests/baselines/reference/thisTypeErrors.js @@ -75,9 +75,9 @@ var C2 = (function () { C2.foo = function (x) { return undefined; }; - C2.y = undefined; return C2; }()); +C2.y = undefined; var N1; (function (N1) { N1.y = this; diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js index d18181dd1dcd4..44b37cc3be568 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression1.js @@ -14,9 +14,11 @@ function foo(x) { }()); } return undefined; } -foo((function () { - function class_2() { - } - class_2.prop = "hello"; - return class_2; -}())).length; +foo((_a = (function () { + function class_2() { + } + return class_2; + }()), + _a.prop = "hello", + _a)).length; +var _a; diff --git a/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js index 66da2ffbff602..bd221a3013733 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js +++ b/tests/baselines/reference/typeArgumentInferenceWithClassExpression2.js @@ -16,9 +16,11 @@ function foo(x) { return undefined; } // Should not infer string because it is a static property -foo((function () { - function class_2() { - } - class_2.prop = "hello"; - return class_2; -}())).length; +foo((_a = (function () { + function class_2() { + } + return class_2; + }()), + _a.prop = "hello", + _a)).length; +var _a; diff --git a/tests/baselines/reference/typeOfPrototype.js b/tests/baselines/reference/typeOfPrototype.js index 3e8b31869361c..a0f076113e0c0 100644 --- a/tests/baselines/reference/typeOfPrototype.js +++ b/tests/baselines/reference/typeOfPrototype.js @@ -11,7 +11,7 @@ var Foo = (function () { function Foo() { this.bar = 3; } - Foo.bar = ''; return Foo; }()); +Foo.bar = ''; Foo.prototype.bar = undefined; // Should be OK diff --git a/tests/baselines/reference/typeOfThisInStaticMembers2.js b/tests/baselines/reference/typeOfThisInStaticMembers2.js index b01770446beea..886ea04e23db4 100644 --- a/tests/baselines/reference/typeOfThisInStaticMembers2.js +++ b/tests/baselines/reference/typeOfThisInStaticMembers2.js @@ -11,12 +11,12 @@ class C2 { var C = (function () { function C() { } - C.foo = this; // error return C; }()); +C.foo = this; // error var C2 = (function () { function C2() { } - C2.foo = this; // error return C2; }()); +C2.foo = this; // error diff --git a/tests/baselines/reference/typeQueryOnClass.js b/tests/baselines/reference/typeQueryOnClass.js index 85dff0de831e0..80623af5be827 100644 --- a/tests/baselines/reference/typeQueryOnClass.js +++ b/tests/baselines/reference/typeQueryOnClass.js @@ -99,10 +99,10 @@ var C = (function () { enumerable: true, configurable: true }); - C.sa = 1; - C.sb = function () { return 1; }; return C; }()); +C.sa = 1; +C.sb = function () { return 1; }; var c; // BUG 820454 var r1; diff --git a/tests/baselines/reference/unqualifiedCallToClassStatic1.js b/tests/baselines/reference/unqualifiedCallToClassStatic1.js index 6c78a737fe862..906e9d3795ff1 100644 --- a/tests/baselines/reference/unqualifiedCallToClassStatic1.js +++ b/tests/baselines/reference/unqualifiedCallToClassStatic1.js @@ -10,9 +10,9 @@ class Vector { var Vector = (function () { function Vector() { } - Vector.foo = function () { - // 'foo' cannot be called in an unqualified manner. - foo(); - }; return Vector; }()); +Vector.foo = function () { + // 'foo' cannot be called in an unqualified manner. + foo(); +}; diff --git a/tests/baselines/reference/witness.js b/tests/baselines/reference/witness.js index e0a4c35687325..56294a7cbb99b 100644 --- a/tests/baselines/reference/witness.js +++ b/tests/baselines/reference/witness.js @@ -262,9 +262,9 @@ var c2inst; var C3 = (function () { function C3() { } - C3.q = C3.q; return C3; }()); +C3.q = C3.q; var qq = C3.q; var qq; // Parentheses - tested a bunch above diff --git a/tests/cases/unittests/transpile.ts b/tests/cases/unittests/transpile.ts index 6f46bb53405c5..084b2b08eab08 100644 --- a/tests/cases/unittests/transpile.ts +++ b/tests/cases/unittests/transpile.ts @@ -2,26 +2,26 @@ module ts { describe("Transpile", () => { - + interface TranspileTestSettings { options?: TranspileOptions; expectedOutput?: string; expectedDiagnosticCodes?: number[]; } - + function checkDiagnostics(diagnostics: Diagnostic[], expectedDiagnosticCodes?: number[]) { if(!expectedDiagnosticCodes) { return; } - + for (let i = 0; i < expectedDiagnosticCodes.length; i++) { assert.equal(expectedDiagnosticCodes[i], diagnostics[i] && diagnostics[i].code, `Could not find expeced diagnostic.`); } - assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); + assert.equal(diagnostics.length, expectedDiagnosticCodes.length, "Resuting diagnostics count does not match expected"); } - + function test(input: string, testSettings: TranspileTestSettings): void { - + let transpileOptions: TranspileOptions = testSettings.options || {}; if (!transpileOptions.compilerOptions) { transpileOptions.compilerOptions = {}; @@ -30,43 +30,43 @@ module ts { // use \r\n as default new line transpileOptions.compilerOptions.newLine = ts.NewLineKind.CarriageReturnLineFeed; } - - let canUseOldTranspile = !transpileOptions.renamedDependencies; - + + let canUseOldTranspile = !transpileOptions.renamedDependencies; + transpileOptions.reportDiagnostics = true; let transpileModuleResult = transpileModule(input, transpileOptions); - + checkDiagnostics(transpileModuleResult.diagnostics, testSettings.expectedDiagnosticCodes); - + if (testSettings.expectedOutput !== undefined) { assert.equal(transpileModuleResult.outputText, testSettings.expectedOutput); } - + if (canUseOldTranspile) { let diagnostics: Diagnostic[] = []; - let transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName); + let transpileResult = transpile(input, transpileOptions.compilerOptions, transpileOptions.fileName, diagnostics, transpileOptions.moduleName); checkDiagnostics(diagnostics, testSettings.expectedDiagnosticCodes); if (testSettings.expectedOutput) { assert.equal(transpileResult, testSettings.expectedOutput); } } - + // check source maps if (!transpileOptions.compilerOptions) { transpileOptions.compilerOptions = {}; } - + if (!transpileOptions.fileName) { transpileOptions.fileName = transpileOptions.compilerOptions.jsx ? "file.tsx" : "file.ts"; } - + transpileOptions.compilerOptions.sourceMap = true; let transpileModuleResultWithSourceMap = transpileModule(input, transpileOptions); assert.isTrue(transpileModuleResultWithSourceMap.sourceMapText !== undefined); - + let expectedSourceMapFileName = removeFileExtension(getBaseFileName(normalizeSlashes(transpileOptions.fileName))) + ".js.map"; let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`; - + if (testSettings.expectedOutput !== undefined) { assert.equal(transpileModuleResultWithSourceMap.outputText, testSettings.expectedOutput + expectedSourceMappingUrlLine); } @@ -81,10 +81,10 @@ module ts { let suffix = getNewLineCharacter(transpileOptions.compilerOptions) + expectedSourceMappingUrlLine assert.isTrue(output.indexOf(suffix, output.length - suffix.length) !== -1); } - } + } } - + it("Generates correct compilerOptions diagnostics", () => { // Expecting 5047: "Option 'isolatedModules' can only be used when either option'--module' is provided or option 'target' is 'ES6' or higher." test(`var x = 0;`, { expectedDiagnosticCodes: [5047] }); @@ -97,7 +97,7 @@ module ts { it("Generates no diagnostics for missing file references", () => { test(`/// -var x = 0;`, +var x = 0;`, { options: { compilerOptions: { module: ModuleKind.CommonJS } } }); }); @@ -117,17 +117,17 @@ var x = 0;`, }); it("Generates module output", () => { - test(`var x = 0;`, - { - options: { compilerOptions: { module: ModuleKind.AMD } }, + test(`var x = 0;`, + { + options: { compilerOptions: { module: ModuleKind.AMD } }, expectedOutput: `define(["require", "exports"], function (require, exports) {\r\n "use strict";\r\n var x = 0;\r\n});\r\n` }); }); it("Uses correct newLine character", () => { - test(`var x = 0;`, - { - options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } }, + test(`var x = 0;`, + { + options: { compilerOptions: { module: ModuleKind.CommonJS, newLine: NewLineKind.LineFeed } }, expectedOutput: `"use strict";\nvar x = 0;\n` }); }); @@ -145,9 +145,9 @@ var x = 0;`, ` }\n` + ` }\n` + `});\n`; - test("var x = 1;", - { - options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" }, + test("var x = 1;", + { + options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, moduleName: "NamedModule" }, expectedOutput: output }) }); @@ -157,7 +157,7 @@ var x = 0;`, }); it("Rename dependencies - System", () => { - let input = + let input = `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);` @@ -177,15 +177,15 @@ var x = 0;`, ` }\n` + `});\n` - test(input, - { - options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, + test(input, + { + options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, expectedOutput: output }); }); it("Rename dependencies - AMD", () => { - let input = + let input = `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);` @@ -195,15 +195,15 @@ var x = 0;`, ` use(SomeName_1.foo);\n` + `});\n`; - test(input, - { - options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, + test(input, + { + options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, expectedOutput: output }); }); it("Rename dependencies - UMD", () => { - let input = + let input = `import {foo} from "SomeName";\n` + `declare function use(a: any);\n` + `use(foo);` @@ -221,15 +221,15 @@ var x = 0;`, ` use(SomeName_1.foo);\n` + `});\n`; - test(input, - { - options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, + test(input, + { + options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }, expectedOutput: output }); }); - + it("Transpile with emit decorators and emit metadata", () => { - let input = + let input = `import {db} from './db';\n` + `function someDecorator(target) {\n` + ` return target;\n` + @@ -245,26 +245,26 @@ var x = 0;`, `export {MyClass}; \n` let output = `"use strict";\n` + - `var db_1 = require(\'./db\');\n` + + `var db_1 = require(\'./db\');\n` + `function someDecorator(target) {\n` + ` return target;\n` + - `}\n` + - `var MyClass = (function () {\n` + - ` function MyClass(db) {\n` + - ` this.db = db;\n` + - ` this.db.doSomething();\n` + - ` }\n` + - ` MyClass = __decorate([\n` + - ` someDecorator, \n` + - ` __metadata(\'design:paramtypes\', [(typeof (_a = typeof db_1.db !== \'undefined\' && db_1.db) === \'function\' && _a) || Object])\n` + - ` ], MyClass);\n` + - ` return MyClass;\n` + - ` var _a;\n` + - `}());\n` + - `exports.MyClass = MyClass;\n`; - - test(input, - { + `}\n` + + `var MyClass = (function () {\n` + + ` function MyClass(db) {\n` + + ` this.db = db;\n` + + ` this.db.doSomething();\n` + + ` }\n` + + ` return MyClass;\n` + + `}());\n` + + `MyClass = __decorate([\n` + + ` someDecorator, \n` + + ` __metadata(\'design:paramtypes\', [(typeof (_a = typeof db_1.db !== \'undefined\' && db_1.db) === \'function\' && _a) || Object])\n` + + `], MyClass);\n` + + `exports.MyClass = MyClass;\n` + + `var _a;\n`; + + test(input, + { options: { compilerOptions: { module: ModuleKind.CommonJS, @@ -274,7 +274,7 @@ var x = 0;`, experimentalDecorators: true, target: ScriptTarget.ES5, } - }, + }, expectedOutput: output }); }); @@ -282,7 +282,7 @@ var x = 0;`, it("Supports backslashes in file name", () => { test("var x", { expectedOutput: `"use strict";\r\nvar x;\r\n`, options: { fileName: "a\\b.ts" }}); }); - + it("transpile file as 'tsx' if 'jsx' is specified", () => { let input = `var x =
`; let output = `"use strict";\nvar x = React.createElement("div", null);\n`;