diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 660b19a587276..4540a4409d65b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3229,7 +3229,8 @@ namespace ts { // A ClassDeclaration is ES6 syntax. transformFlags = subtreeFlags | TransformFlags.AssertES2015; - // A class with a parameter property assignment or decorator is TypeScript syntax. + // A class with a parameter property assignment, property initializer, computed property name, or decorator is + // TypeScript syntax. // An exported declaration may be TypeScript syntax, but is handled by the visitor // for a namespace declaration. if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax) @@ -3246,7 +3247,8 @@ namespace ts { // A ClassExpression is ES6 syntax. let transformFlags = subtreeFlags | TransformFlags.AssertES2015; - // A class with a parameter property assignment or decorator is TypeScript syntax. + // A class with a parameter property assignment, property initializer, or decorator is + // TypeScript syntax. if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax || node.typeParameters) { transformFlags |= TransformFlags.AssertTypeScript; @@ -3336,6 +3338,7 @@ namespace ts { || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.typeParameters || node.type + || (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -3366,6 +3369,7 @@ namespace ts { if (node.decorators || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type + || (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly || !node.body) { transformFlags |= TransformFlags.AssertTypeScript; } @@ -3380,15 +3384,12 @@ namespace ts { } function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) { - let transformFlags = subtreeFlags | TransformFlags.ContainsClassFields; - - // Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax. - if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) { - transformFlags |= TransformFlags.AssertTypeScript; - } + // A PropertyDeclaration is TypeScript syntax. + let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript; - // Hoisted variables related to class properties should live within the TypeScript class wrapper. - if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) { + // If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor + // so that it handle the transformation. + if (node.initializer || isComputedPropertyName(node.name)) { transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax; } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index d520571e6dfc4..1c1df9bb0c210 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -44,7 +44,6 @@ namespace ts { addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory)); transformers.push(transformTypeScript); - transformers.push(transformClassFields); if (jsx === JsxEmit.React) { transformers.push(transformJsx); diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts deleted file mode 100644 index 575e1d1334696..0000000000000 --- a/src/compiler/transformers/classFields.ts +++ /dev/null @@ -1,491 +0,0 @@ -/*@internal*/ -namespace ts { - const enum ClassPropertySubstitutionFlags { - /** - * Enables substitutions for class expressions with static fields - * which have initializers that reference the class name. - */ - ClassAliases = 1 << 0, - } - /** - * Transforms ECMAScript Class Syntax. - * TypeScript parameter property syntax is transformed in the TypeScript transformer. - * For now, this transforms public field declarations using TypeScript class semantics - * (where the declarations get elided and initializers are transformed as assignments in the constructor). - * Eventually, this transform will change to the ECMAScript semantics (with Object.defineProperty). - */ - export function transformClassFields(context: TransformationContext) { - const { - hoistVariableDeclaration, - endLexicalEnvironment, - resumeLexicalEnvironment - } = context; - const resolver = context.getEmitResolver(); - - const previousOnSubstituteNode = context.onSubstituteNode; - context.onSubstituteNode = onSubstituteNode; - - let enabledSubstitutions: ClassPropertySubstitutionFlags; - - let classAliases: Identifier[]; - - /** - * Tracks what computed name expressions originating from elided names must be inlined - * at the next execution site, in document order - */ - let pendingExpressions: Expression[] | undefined; - - /** - * Tracks what computed name expression statements and static property initializers must be - * emitted at the next execution site, in document order (for decorated classes). - */ - let pendingStatements: Statement[] | undefined; - - return chainBundle(transformSourceFile); - - function transformSourceFile(node: SourceFile) { - if (node.isDeclarationFile) { - return node; - } - const visited = visitEachChild(node, visitor, context); - addEmitHelpers(visited, context.readEmitHelpers()); - return visited; - } - - function visitor(node: Node): VisitResult { - if (!(node.transformFlags & TransformFlags.ContainsClassFields)) return node; - - switch (node.kind) { - case SyntaxKind.ClassExpression: - return visitClassExpression(node as ClassExpression); - case SyntaxKind.ClassDeclaration: - return visitClassDeclaration(node as ClassDeclaration); - case SyntaxKind.VariableStatement: - return visitVariableStatement(node as VariableStatement); - } - return visitEachChild(node, visitor, context); - } - - /** - * Visits the members of a class that has fields. - * - * @param node The node to visit. - */ - function classElementVisitor(node: Node): VisitResult { - switch (node.kind) { - case SyntaxKind.Constructor: - // Constructors for classes using class fields are transformed in - // `visitClassDeclaration` or `visitClassExpression`. - return undefined; - - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.MethodDeclaration: - // Visit the name of the member (if it's a computed property name). - return visitEachChild(node, classElementVisitor, context); - - case SyntaxKind.PropertyDeclaration: - return visitPropertyDeclaration(node as PropertyDeclaration); - - case SyntaxKind.ComputedPropertyName: - return visitComputedPropertyName(node as ComputedPropertyName); - - default: - return node; - } - } - - function visitVariableStatement(node: VariableStatement) { - const savedPendingStatements = pendingStatements; - pendingStatements = []; - - const visitedNode = visitEachChild(node, visitor, context); - const statement = some(pendingStatements) ? - [visitedNode, ...pendingStatements] : - visitedNode; - - pendingStatements = savedPendingStatements; - return statement; - } - - function visitComputedPropertyName(name: ComputedPropertyName) { - let node = visitEachChild(name, visitor, context); - if (some(pendingExpressions)) { - const expressions = pendingExpressions; - expressions.push(name.expression); - pendingExpressions = []; - node = updateComputedPropertyName( - node, - inlineExpressions(expressions) - ); - } - return node; - } - - function visitPropertyDeclaration(node: PropertyDeclaration) { - Debug.assert(!some(node.decorators)); - // Create a temporary variable to store a computed property name (if necessary). - // If it's not inlineable, then we emit an expression after the class which assigns - // the property name to the temporary variable. - const expr = getPropertyNameExpressionIfNeeded(node.name, !!node.initializer); - if (expr && !isSimpleInlineableExpression(expr)) { - (pendingExpressions || (pendingExpressions = [])).push(expr); - } - return undefined; - } - - function visitClassDeclaration(node: ClassDeclaration) { - if (!forEach(node.members, isPropertyDeclaration)) { - return visitEachChild(node, visitor, context); - } - const savedPendingExpressions = pendingExpressions; - pendingExpressions = undefined; - - const extendsClauseElement = getEffectiveBaseTypeNode(node); - const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); - - const statements: Statement[] = [ - updateClassDeclaration( - node, - node.decorators, - node.modifiers, - node.name, - node.typeParameters, - node.heritageClauses, - transformClassMembers(node, isDerivedClass) - ) - ]; - - // Write any pending expressions from elided or moved computed property names - if (some(pendingExpressions)) { - statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!))); - } - pendingExpressions = savedPendingExpressions; - - // 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. - const staticProperties = getInitializedProperties(node, /*isStatic*/ true); - if (some(staticProperties)) { - addInitializedPropertyStatements(statements, staticProperties, getInternalName(node)); - } - - return statements; - } - - function visitClassExpression(node: ClassExpression): Expression { - if (!forEach(node.members, isPropertyDeclaration)) { - return visitEachChild(node, visitor, context); - } - const savedPendingExpressions = pendingExpressions; - pendingExpressions = undefined; - - // If this class expression is a transformation of a decorated class declaration, - // then we want to output the pendingExpressions as statements, not as inlined - // expressions with the class statement. - // - // In this case, we use pendingStatements to produce the same output as the - // class declaration transformation. The VariableStatement visitor will insert - // these statements after the class expression variable statement. - const isDecoratedClassDeclaration = isClassDeclaration(getOriginalNode(node)); - - const staticProperties = getInitializedProperties(node, /*isStatic*/ true); - const extendsClauseElement = getEffectiveBaseTypeNode(node); - const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword); - - const classExpression = updateClassExpression( - node, - node.modifiers, - node.name, - node.typeParameters, - visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node, isDerivedClass) - ); - - if (some(staticProperties) || some(pendingExpressions)) { - if (isDecoratedClassDeclaration) { - Debug.assertDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration."); - - // Write any pending expressions from elided or moved computed property names - if (pendingStatements && pendingExpressions && some(pendingExpressions)) { - pendingStatements.push(createExpressionStatement(inlineExpressions(pendingExpressions))); - } - pendingExpressions = savedPendingExpressions; - - if (pendingStatements && some(staticProperties)) { - addInitializedPropertyStatements(pendingStatements, staticProperties, getInternalName(node)); - } - return classExpression; - } - else { - const expressions: Expression[] = []; - const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference; - const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference); - if (isClassWithConstructorReference) { - // record an alias as the class name is not in scope for statics. - enableSubstitutionForClassAliases(); - const alias = getSynthesizedClone(temp); - alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; - classAliases[getOriginalNodeId(node)] = alias; - } - - // To preserve the behavior of the old emitter, we explicitly indent - // the body of a class with static initializers. - setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression)); - expressions.push(startOnNewLine(createAssignment(temp, classExpression))); - // Add any pending expressions leftover from elided or relocated computed property names - addRange(expressions, map(pendingExpressions, startOnNewLine)); - addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp)); - expressions.push(startOnNewLine(temp)); - - pendingExpressions = savedPendingExpressions; - return inlineExpressions(expressions); - } - } - - pendingExpressions = savedPendingExpressions; - return classExpression; - } - - function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { - const members: ClassElement[] = []; - const constructor = transformConstructor(node, isDerivedClass); - if (constructor) { - members.push(constructor); - } - addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); - return setTextRange(createNodeArray(members), /*location*/ node.members); - } - - function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { - const constructor = visitNode(getFirstConstructorWithBody(node), visitor, isConstructorDeclaration); - const containsPropertyInitializer = forEach(node.members, isInitializedProperty); - if (!containsPropertyInitializer) { - return constructor; - } - const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context); - const body = transformConstructorBody(node, constructor, isDerivedClass); - if (!body) { - return undefined; - } - return startOnNewLine( - setOriginalNode( - setTextRange( - createConstructor( - /*decorators*/ undefined, - /*modifiers*/ undefined, - parameters, - body - ), - constructor || node - ), - constructor - ) - ); - } - - function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { - const properties = getInitializedProperties(node, /*isStatic*/ false); - - // Only generate synthetic constructor when there are property initializers to move. - if (!constructor && !some(properties)) { - return visitFunctionBody(/*node*/ undefined, visitor, context); - } - - resumeLexicalEnvironment(); - - let indexOfFirstStatement = 0; - let statements: Statement[] = []; - - if (!constructor && isDerivedClass) { - // Add a synthetic `super` call: - // - // super(...arguments); - // - statements.push( - createExpressionStatement( - createCall( - createSuper(), - /*typeArguments*/ undefined, - [createSpread(createIdentifier("arguments"))] - ) - ) - ); - } - - if (constructor) { - indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor); - } - - // Add the property initializers. Transforms this: - // - // public x = 1; - // - // Into this: - // - // constructor() { - // this.x = 1; - // } - // - addInitializedPropertyStatements(statements, properties, createThis()); - - // Add existing statements, skipping the initial super call. - if (constructor) { - addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); - } - - statements = mergeLexicalEnvironment(statements, endLexicalEnvironment()); - - return setTextRange( - createBlock( - setTextRange( - createNodeArray(statements), - /*location*/ constructor ? constructor.body!.statements : node.members - ), - /*multiLine*/ true - ), - /*location*/ constructor ? constructor.body : undefined - ); - } - - /** - * Generates assignment statements for property initializers. - * - * @param properties An array of property declarations to transform. - * @param receiver The receiver on which each property should be assigned. - */ - function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { - for (const property of properties) { - const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); - setSourceMapRange(statement, moveRangePastModifiers(property)); - setCommentRange(statement, property); - setOriginalNode(statement, property); - statements.push(statement); - } - } - - /** - * Generates assignment expressions for property initializers. - * - * @param properties An array of property declarations to transform. - * @param receiver The receiver on which each property should be assigned. - */ - function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { - const expressions: Expression[] = []; - for (const property of properties) { - const expression = transformInitializedProperty(property, receiver); - startOnNewLine(expression); - setSourceMapRange(expression, moveRangePastModifiers(property)); - setCommentRange(expression, property); - setOriginalNode(expression, property); - expressions.push(expression); - } - - return expressions; - } - - /** - * Transforms a property initializer into an assignment statement. - * - * @param property The property declaration. - * @param receiver The object receiving the property assignment. - */ - function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) { - // We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name) - const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) - ? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name)) - : property.name; - const initializer = visitNode(property.initializer!, visitor, isExpression); - const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); - - return createAssignment(memberAccess, initializer); - } - - function enableSubstitutionForClassAliases() { - if ((enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) === 0) { - enabledSubstitutions |= ClassPropertySubstitutionFlags.ClassAliases; - - // We need to enable substitutions for identifiers. This allows us to - // substitute class names inside of a class declaration. - context.enableSubstitution(SyntaxKind.Identifier); - - // Keep track of class aliases. - classAliases = []; - } - } - - /** - * Hooks node substitutions. - * - * @param hint The context for the emitter. - * @param node The node to substitute. - */ - function onSubstituteNode(hint: EmitHint, node: Node) { - node = previousOnSubstituteNode(hint, node); - if (hint === EmitHint.Expression) { - return substituteExpression(node as Expression); - } - return node; - } - - function substituteExpression(node: Expression) { - switch (node.kind) { - case SyntaxKind.Identifier: - return substituteExpressionIdentifier(node as Identifier); - } - return node; - } - - function substituteExpressionIdentifier(node: Identifier): Expression { - return trySubstituteClassAlias(node) || node; - } - - function trySubstituteClassAlias(node: Identifier): Expression | undefined { - if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) { - if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) { - // 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. - // Also, when emitting statics for class expressions, we must substitute a class alias for - // constructor references in static property initializers. - const declaration = resolver.getReferencedValueDeclaration(node); - if (declaration) { - const classAlias = classAliases[declaration.id!]; // TODO: GH#18217 - if (classAlias) { - const clone = getSynthesizedClone(classAlias); - setSourceMapRange(clone, node); - setCommentRange(clone, node); - return clone; - } - } - } - } - - return undefined; - } - - - /** - * If the name is a computed property, this function transforms it, then either returns an expression which caches the - * value of the result or the expression itself if the value is either unused or safe to inline into multiple locations - * @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator) - */ - function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean): Expression | undefined { - if (isComputedPropertyName(name)) { - const expression = visitNode(name.expression, visitor, isExpression); - const innerExpression = skipPartiallyEmittedExpressions(expression); - const inlinable = isSimpleInlineableExpression(innerExpression); - const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); - if (!alreadyTransformed && !inlinable && shouldHoist) { - const generatedName = getGeneratedNameForNode(name); - hoistVariableDeclaration(generatedName); - return createAssignment(generatedName, expression); - } - return (inlinable || isIdentifier(innerExpression)) ? undefined : expression; - } - } - } - -} diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index adfe16c73f692..a70fb820e7950 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -64,7 +64,6 @@ namespace ts { let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock; let currentNameScope: ClassDeclaration | undefined; let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap | undefined; - let currentClassHasParameterProperties: boolean | undefined; /** * Keeps track of whether expression substitution has been enabled for specific edge cases. @@ -84,6 +83,12 @@ namespace ts { */ let applicableSubstitutions: TypeScriptSubstitutionFlags; + /** + * Tracks what computed name expressions originating from elided names must be inlined + * at the next execution site, in document order + */ + let pendingExpressions: Expression[] | undefined; + return transformSourceFileOrBundle; function transformSourceFileOrBundle(node: SourceFile | Bundle) { @@ -131,7 +136,6 @@ namespace ts { const savedCurrentScope = currentLexicalScope; const savedCurrentNameScope = currentNameScope; const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName; - const savedCurrentClassHasParameterProperties = currentClassHasParameterProperties; // Handle state changes before visiting a node. onBeforeVisitNode(node); @@ -145,7 +149,6 @@ namespace ts { currentLexicalScope = savedCurrentScope; currentNameScope = savedCurrentNameScope; - currentClassHasParameterProperties = savedCurrentClassHasParameterProperties; return visited; } @@ -318,9 +321,6 @@ namespace ts { return undefined; case SyntaxKind.PropertyDeclaration: - // Property declarations are not TypeScript syntax, but they must be visited - // for the decorator transformation. - return visitPropertyDeclaration(node as PropertyDeclaration); case SyntaxKind.IndexSignature: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -437,6 +437,7 @@ namespace ts { // - decorators // - optional `implements` heritage clause // - parameter property assignments in the constructor + // - property declarations // - index signatures // - method overload signatures return visitClassDeclaration(node); @@ -448,6 +449,7 @@ namespace ts { // - decorators // - optional `implements` heritage clause // - parameter property assignments in the constructor + // - property declarations // - index signatures // - method overload signatures return visitClassExpression(node); @@ -609,6 +611,10 @@ namespace ts { if (!isClassLikeDeclarationWithTypeScriptSyntax(node) && !(currentNamespace && hasModifier(node, ModifierFlags.Export))) { return visitEachChild(node, visitor, context); } + + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); const facts = getClassFacts(node, staticProperties); @@ -618,11 +624,25 @@ namespace ts { const name = node.name || (facts & ClassFacts.NeedsName ? getGeneratedNameForNode(node) : undefined); const classStatement = facts & ClassFacts.HasConstructorDecorators - ? createClassDeclarationHeadWithDecorators(node, name) + ? createClassDeclarationHeadWithDecorators(node, name, facts) : createClassDeclarationHeadWithoutDecorators(node, name, facts); let statements: Statement[] = [classStatement]; + // Write any pending expressions from elided or moved computed property names + if (some(pendingExpressions)) { + statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!))); + } + pendingExpressions = savedPendingExpressions; + + // 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. + if (facts & ClassFacts.HasStaticInitializedProperties) { + addInitializedPropertyStatements(statements, staticProperties, facts & ClassFacts.UseImmediatelyInvokedFunctionExpression ? getInternalName(node) : getLocalName(node)); + } // Write any decorators of the node. addClassElementDecorationStatements(statements, node, /*isStatic*/ false); @@ -725,7 +745,7 @@ namespace ts { name, /*typeParameters*/ undefined, visitNodes(node.heritageClauses, visitor, isHeritageClause), - transformClassMembers(node) + transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0) ); // To better align with the old emitter, we should not emit a trailing source map @@ -745,7 +765,7 @@ namespace ts { * 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. */ - function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined) { + function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined, facts: ClassFacts) { // When we emit an ES6 class that has a class decorator, we must tailor the // emit to certain specific cases. // @@ -840,7 +860,7 @@ namespace ts { // ${members} // } const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); - const members = transformClassMembers(node); + const members = transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0); const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members); setOriginalNode(classExpression, node); setTextRange(classExpression, location); @@ -868,19 +888,49 @@ namespace ts { return visitEachChild(node, visitor, context); } - const members = transformClassMembers(node); + const savedPendingExpressions = pendingExpressions; + pendingExpressions = undefined; + + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause); + const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword)); const classExpression = createClassExpression( /*modifiers*/ undefined, node.name, /*typeParameters*/ undefined, - node.heritageClauses, + heritageClauses, members ); setOriginalNode(classExpression, node); setTextRange(classExpression, node); + if (some(staticProperties) || some(pendingExpressions)) { + const expressions: Expression[] = []; + const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference; + const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference); + if (isClassWithConstructorReference) { + // record an alias as the class name is not in scope for statics. + enableSubstitutionForClassAliases(); + const alias = getSynthesizedClone(temp); + alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; + classAliases[getOriginalNodeId(node)] = alias; + } + + // To preserve the behavior of the old emitter, we explicitly indent + // the body of a class with static initializers. + setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression)); + expressions.push(startOnNewLine(createAssignment(temp, classExpression))); + // Add any pending expressions leftover from elided or relocated computed property names + addRange(expressions, map(pendingExpressions, startOnNewLine)); + pendingExpressions = savedPendingExpressions; + addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp)); + expressions.push(startOnNewLine(temp)); + return inlineExpressions(expressions); + } + + pendingExpressions = savedPendingExpressions; return classExpression; } @@ -888,81 +938,61 @@ namespace ts { * Transforms the members of a class. * * @param node The current class. + * @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. */ - function transformClassMembers(node: ClassDeclaration | ClassExpression) { + function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) { const members: ClassElement[] = []; - const existingMembers = visitNodes(node.members, classElementVisitor, isClassElement); + const constructor = transformConstructor(node, isDerivedClass); + if (constructor) { + members.push(constructor); + } + + addRange(members, visitNodes(node.members, classElementVisitor, isClassElement)); + return setTextRange(createNodeArray(members), /*location*/ node.members); + } + + /** + * Transforms (or creates) a constructor for a class. + * + * @param node The current class. + * @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. + */ + function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: 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 constructor = getFirstConstructorWithBody(node); - const parametersWithPropertyAssignments = - constructor && hasTypeScriptClassSyntax(constructor) - ? filter(constructor.parameters, isParameterPropertyDeclaration) - : undefined; - if (some(parametersWithPropertyAssignments) && constructor) { - currentClassHasParameterProperties = true; - - // Create property declarations for constructor parameter properties. - addRange( - members, - parametersWithPropertyAssignments.map(param => - createProperty( - /*decorators*/ undefined, - /*modifiers*/ undefined, - param.name, - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - /*initializer*/ undefined - ) - ) - ); + const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty); + const hasParameterPropertyAssignments = constructor && + constructor.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax && + forEach(constructor.parameters, isParameterWithPropertyAssignment); + + // 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); - const body = transformConstructorBody(node.members, constructor, parametersWithPropertyAssignments); - members.push(startOnNewLine( - setOriginalNode( - setTextRange( - createConstructor( + const parameters = transformConstructorParameters(constructor); + const body = transformConstructorBody(node, constructor, isDerivedClass); + + // constructor(${parameters}) { + // ${body} + // } + return startOnNewLine( + setOriginalNode( + setTextRange( + createConstructor( /*decorators*/ undefined, /*modifiers*/ undefined, - parameters, - body - ), - constructor + parameters, + body ), - constructor - ) - )); - addRange( - members, - visitNodes( - existingMembers, - member => { - if (isPropertyDeclaration(member) && !hasStaticModifier(member) && !!member.initializer) { - const updated = updateProperty( - member, - member.decorators, - member.modifiers, - member.name, - member.questionToken, - member.type, - /*initializer*/ undefined - ); - setCommentRange(updated, node); - setSourceMapRange(updated, node); - return updated; - } - return member; - }, - isClassElement - ) - ); - } - else { - if (constructor) { - members.push(visitEachChild(constructor, visitor, context)); - } - addRange(members, existingMembers); - } - return setTextRange(createNodeArray(members), /*location*/ node.members); + constructor || node + ), + constructor + ) + ); } /** @@ -971,7 +1001,7 @@ namespace ts { * * @param constructor The constructor declaration. */ - function transformConstructorParameters(constructor: ConstructorDeclaration) { + function transformConstructorParameters(constructor: ConstructorDeclaration | undefined) { // The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation: // If constructor is empty, then // If ClassHeritag_eopt is present and protoParent is not null, then @@ -992,54 +1022,70 @@ namespace ts { } /** - * Transforms (or creates) a constructor body for a class with parameter property assignments. + * 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 isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'. */ - function transformConstructorBody(members: NodeArray, constructor: ConstructorDeclaration, propertyAssignments: ReadonlyArray) { + function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) { let statements: Statement[] = []; let indexOfFirstStatement = 0; resumeLexicalEnvironment(); - indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor); + if (constructor) { + indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements); + + // 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); + addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); + } + else if (isDerivedClass) { + // Add a synthetic `super` call: + // + // super(...arguments); + // + statements.push( + createExpressionStatement( + createCall( + createSuper(), + /*typeArguments*/ undefined, + [createSpread(createIdentifier("arguments"))] + ) + ) + ); + } - // Add parameters with property assignments. Transforms this: + // Add the property initializers. Transforms this: // - // constructor (public x, public y) { - // } + // public x = 1; // // Into this: // - // constructor (x, y) { - // this.x = x; - // this.y = y; + // constructor() { + // this.x = 1; // } // - addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment)); - - // Get property initializers. - const classBodyProperties = members.filter(member => isPropertyDeclaration(member) && !hasStaticModifier(member) && !!member.initializer) as PropertyDeclaration[]; - addRange(statements, classBodyProperties.map( - prop => { - const name = prop.name; - const lhs = (!isComputedPropertyName(name) || isSimpleInlineableExpression(name.expression)) ? - createMemberAccessForPropertyName(createThis(), name, prop) : - createElementAccess(createThis(), getGeneratedNameForNode(name)); - const initializerNode = createExpressionStatement( - createAssignment(lhs, prop.initializer!) - ); - setOriginalNode(initializerNode, prop); - setTextRange(initializerNode, prop); - setCommentRange(initializerNode, prop); - setSourceMapRange(initializerNode, prop); - return initializerNode; - } - )); + const properties = getInitializedProperties(node, /*isStatic*/ false); + addInitializedPropertyStatements(statements, properties, createThis()); - // Add the existing statements, skipping the initial super call. - addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); + if (constructor) { + // The class already had a constructor, so we should add the existing statements, skipping the initial super call. + addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement)); + } // End the lexical environment. statements = mergeLexicalEnvironment(statements, endLexicalEnvironment()); @@ -1047,7 +1093,7 @@ namespace ts { createBlock( setTextRange( createNodeArray(statements), - /*location*/ constructor ? constructor.body!.statements : members + /*location*/ constructor ? constructor.body!.statements : node.members ), /*multiLine*/ true ), @@ -1055,16 +1101,61 @@ namespace ts { ); } + /** + * Adds super call and preceding prologue directives into the list of statements. + * + * @param ctor The constructor node. + * @returns index of the statement that follows super call + */ + function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[]): number { + if (ctor.body) { + const statements = ctor.body.statements; + // add prologue directives to the list (if any) + const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); + if (index === statements.length) { + // list contains nothing but prologue directives (or empty) - exit + return index; + } + + const statement = statements[index]; + if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((statement).expression)) { + result.push(visitNode(statement, visitor, isStatement)); + return index + 1; + } + + return index; + } + + return 0; + } + + /** + * Gets all parameters of a constructor that should be transformed into property assignments. + * + * @param node The constructor node. + */ + function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray { + 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.ParameterPropertyModifier) + && isIdentifier(parameter.name); + } + /** * Transforms a parameter into a property assignment statement. * * @param node The parameter declaration. */ - function transformParameterWithPropertyAssignment(node: ParameterPropertyDeclaration) { - const name = node.name; - if (!isIdentifier(name)) { - return undefined; - } + function transformParameterWithPropertyAssignment(node: ParameterDeclaration) { + Debug.assert(isIdentifier(node.name)); + const name = node.name as Identifier; const propertyName = getMutableClone(name); setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap); @@ -1093,6 +1184,99 @@ namespace ts { ); } + /** + * 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): ReadonlyArray { + 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 properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray, receiver: LeftHandSideExpression) { + for (const property of properties) { + const statement = createExpressionStatement(transformInitializedProperty(property, receiver)); + setSourceMapRange(statement, moveRangePastModifiers(property)); + setCommentRange(statement, property); + setOriginalNode(statement, property); + statements.push(statement); + } + } + + /** + * Generates assignment expressions for property initializers. + * + * @param properties An array of property declarations to transform. + * @param receiver The receiver on which each property should be assigned. + */ + function generateInitializedPropertyExpressions(properties: ReadonlyArray, receiver: LeftHandSideExpression) { + const expressions: Expression[] = []; + for (const property of properties) { + const expression = transformInitializedProperty(property, receiver); + startOnNewLine(expression); + setSourceMapRange(expression, moveRangePastModifiers(property)); + setCommentRange(expression, property); + setOriginalNode(expression, property); + expressions.push(expression); + } + + return expressions; + } + + /** + * Transforms a property initializer into an assignment statement. + * + * @param property The property declaration. + * @param receiver The object receiving the property assignment. + */ + function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) { + // We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name) + const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression) + ? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name)) + : property.name; + const initializer = visitNode(property.initializer!, visitor, isExpression); + const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); + + return createAssignment(memberAccess, initializer); + } + /** * Gets either the static or instance members of a class that are decorated, or have * parameters that are decorated. @@ -1960,6 +2144,16 @@ namespace ts { : createIdentifier("BigInt"); } + /** + * A simple inlinable expression is an expression which can be copied into multiple locations + * without risk of repeating any sideeffects and whose value could not possibly change between + * any such locations + */ + function isSimpleInlineableExpression(expression: Expression) { + return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || + isWellKnownSymbolSyntactically(expression); + } + /** * Gets an expression that represents a property name. For a computed property, a * name is generated for the node. @@ -1981,6 +2175,26 @@ namespace ts { } } + /** + * If the name is a computed property, this function transforms it, then either returns an expression which caches the + * value of the result or the expression itself if the value is either unused or safe to inline into multiple locations + * @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator) + * @param omitSimple Should expressions with no observable side-effects be elided? (ie, the expression is not hoisted for a decorator or initializer and is a literal) + */ + function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean, omitSimple: boolean): Expression | undefined { + if (isComputedPropertyName(name)) { + const expression = visitNode(name.expression, visitor, isExpression); + const innerExpression = skipPartiallyEmittedExpressions(expression); + const inlinable = isSimpleInlineableExpression(innerExpression); + if (!inlinable && shouldHoist) { + const generatedName = getGeneratedNameForNode(name); + hoistVariableDeclaration(generatedName); + return createAssignment(generatedName, expression); + } + return (omitSimple && (inlinable || isIdentifier(innerExpression))) ? undefined : expression; + } + } + /** * 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 @@ -1990,20 +2204,18 @@ namespace ts { */ function visitPropertyNameOfClassElement(member: ClassElement): PropertyName { const name = member.name!; - // Computed property names need to be transformed into a hoisted variable when they are used more than once. - // The names are used more than once when: - // - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments). - // - the property has a decorator. - if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || some(member.decorators))) { - const expression = visitNode(name.expression, visitor, isExpression); - const innerExpression = skipPartiallyEmittedExpressions(expression); - if (!isSimpleInlineableExpression(innerExpression)) { - const generatedName = getGeneratedNameForNode(name); - hoistVariableDeclaration(generatedName); - return updateComputedPropertyName(name, createAssignment(generatedName, expression)); + let expr = getPropertyNameExpressionIfNeeded(name, some(member.decorators), /*omitSimple*/ false); + if (expr) { // expr only exists if `name` is a computed property name + // Inline any pending expressions from previous elided or relocated computed property name expressions in order to preserve execution order + if (some(pendingExpressions)) { + expr = inlineExpressions([...pendingExpressions, expr]); + pendingExpressions.length = 0; } + return updateComputedPropertyName(name as ComputedPropertyName, expr); + } + else { + return name; } - return visitNode(name, visitor, isPropertyName); } /** @@ -2049,23 +2261,12 @@ namespace ts { return !nodeIsMissing(node.body); } - function visitPropertyDeclaration(node: PropertyDeclaration) { - const updated = updateProperty( - node, - /*decorators*/ undefined, - visitNodes(node.modifiers, visitor, isModifier), - visitPropertyNameOfClassElement(node), - /*questionOrExclamationToken*/ undefined, - /*type*/ undefined, - visitNode(node.initializer, visitor) - ); - if (updated !== node) { - // While we emit the source map for the node after skipping decorators and modifiers, - // we need to emit the comments for the original range. - setCommentRange(updated, node); - setSourceMapRange(updated, moveRangePastDecorators(node)); + function visitPropertyDeclaration(node: PropertyDeclaration): undefined { + const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true); + if (expr && !isSimpleInlineableExpression(expr)) { + (pendingExpressions || (pendingExpressions = [])).push(expr); } - return updated; + return undefined; } function visitConstructor(node: ConstructorDeclaration) { diff --git a/src/compiler/transformers/utilities.ts b/src/compiler/transformers/utilities.ts index f5f8a298a490b..09239d7765fd9 100644 --- a/src/compiler/transformers/utilities.ts +++ b/src/compiler/transformers/utilities.ts @@ -240,47 +240,6 @@ namespace ts { isIdentifier(expression); } - /** - * A simple inlinable expression is an expression which can be copied into multiple locations - * without risk of repeating any sideeffects and whose value could not possibly change between - * any such locations - */ - export function isSimpleInlineableExpression(expression: Expression) { - return !isIdentifier(expression) && isSimpleCopiableExpression(expression) || - isWellKnownSymbolSyntactically(expression); - } - - /** - * Adds super call and preceding prologue directives into the list of statements. - * - * @param ctor The constructor node. - * @param result The list of statements. - * @param visitor The visitor to apply to each node added to the result array. - * @returns index of the statement that follows super call - */ - export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number { - if (ctor.body) { - const statements = ctor.body.statements; - // add prologue directives to the list (if any) - const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor); - if (index === statements.length) { - // list contains nothing but prologue directives (or empty) - exit - return index; - } - - const statement = statements[index]; - if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((statement).expression)) { - result.push(visitNode(statement, visitor, isStatement)); - return index + 1; - } - - return index; - } - - return 0; - } - - /** * @param input Template string input strings * @param args Names which need to be made file-level unique @@ -296,43 +255,4 @@ namespace ts { return result; }; } - - /** - * 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. - */ - export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray { - 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. - */ - export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { - return isInitializedProperty(member) && hasStaticModifier(member); - } - - /** - * Gets a value indicating whether a class element is an instance property declaration with an initializer. - * - * @param member The class element node. - */ - export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { - return isInitializedProperty(member) && !hasStaticModifier(member); - } - - /** - * 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. - */ - export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } { - return member.kind === SyntaxKind.PropertyDeclaration - && (member).initializer !== undefined; - } } \ No newline at end of file diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index f5e16b0d127db..fdc0ff2969f7d 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -30,7 +30,6 @@ "transformers/utilities.ts", "transformers/destructuring.ts", "transformers/ts.ts", - "transformers/classFields.ts", "transformers/es2017.ts", "transformers/es2018.ts", "transformers/es2019.ts", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 31fb4984507fe..a7ee1c5745fb8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5197,7 +5197,6 @@ namespace ts { ContainsYield = 1 << 17, ContainsHoistedDeclarationOrCompletion = 1 << 18, ContainsDynamicImport = 1 << 19, - ContainsClassFields = 1 << 20, // Please leave this as 1 << 29. // It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system. diff --git a/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js b/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js index 970590c136b41..ab986aba1e88d 100644 --- a/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js +++ b/tests/baselines/reference/declarationEmitPrivateSymbolCausesVarDeclarationEmit2.js @@ -34,8 +34,8 @@ var C = /** @class */ (function () { } return C; }()); -exports.C = C; _a = a_1.x; +exports.C = C; //// [c.js] "use strict"; var __extends = (this && this.__extends) || (function () { @@ -64,8 +64,8 @@ var D = /** @class */ (function (_super) { } return D; }(b_1.C)); -exports.D = D; _a = a_1.x; +exports.D = D; //// [a.d.ts] diff --git a/tests/baselines/reference/decoratorsOnComputedProperties.js b/tests/baselines/reference/decoratorsOnComputedProperties.js index 3f0444b310aaa..2af6b460c0518 100644 --- a/tests/baselines/reference/decoratorsOnComputedProperties.js +++ b/tests/baselines/reference/decoratorsOnComputedProperties.js @@ -196,8 +196,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, 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; }; -var _a, _b, _c, _d; -var _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21; function x(o, k) { } let i = 0; function foo() { return ++i + ""; } @@ -210,11 +209,11 @@ class A { this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_f] = null; - this[_h] = null; + this[_b] = null; + this[_d] = null; } } -foo(), _e = foo(), _f = foo(), _g = fieldNameB, _h = fieldNameC; +foo(), _a = foo(), _b = foo(), _c = fieldNameB, _d = fieldNameC; __decorate([ x ], A.prototype, "property", void 0); @@ -229,42 +228,42 @@ __decorate([ ], A.prototype, Symbol.iterator, void 0); __decorate([ x -], A.prototype, _e, void 0); +], A.prototype, _a, void 0); __decorate([ x -], A.prototype, _f, void 0); +], A.prototype, _b, void 0); __decorate([ x -], A.prototype, _g, void 0); +], A.prototype, _c, void 0); __decorate([ x -], A.prototype, _h, void 0); -void (_a = class B { +], A.prototype, _d, void 0); +void (_j = class B { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_k] = null; - this[_m] = null; + this[_f] = null; + this[_h] = null; } }, foo(), - _j = foo(), - _k = foo(), - _l = fieldNameB, - _m = fieldNameC, - _a); + _e = foo(), + _f = foo(), + _g = fieldNameB, + _h = fieldNameC, + _j); class C { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_p] = null; - this[_r] = null; + this[_l] = null; + this[_o] = null; } - [(foo(), _o = foo(), _p = foo(), _q = fieldNameB, _r = fieldNameC, "some" + "method")]() { } + [(foo(), _k = foo(), _l = foo(), _m = fieldNameB, _o = fieldNameC, "some" + "method")]() { } } __decorate([ x @@ -280,26 +279,26 @@ __decorate([ ], C.prototype, Symbol.iterator, void 0); __decorate([ x -], C.prototype, _o, void 0); +], C.prototype, _k, void 0); __decorate([ x -], C.prototype, _p, void 0); +], C.prototype, _l, void 0); __decorate([ x -], C.prototype, _q, void 0); +], C.prototype, _m, void 0); __decorate([ x -], C.prototype, _r, void 0); +], C.prototype, _o, void 0); void class D { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_t] = null; - this[_v] = null; + this[_q] = null; + this[_s] = null; } - [(foo(), _s = foo(), _t = foo(), _u = fieldNameB, _v = fieldNameC, "some" + "method")]() { } + [(foo(), _p = foo(), _q = foo(), _r = fieldNameB, _s = fieldNameC, "some" + "method")]() { } }; class E { constructor() { @@ -307,12 +306,12 @@ class E { this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_x] = null; - this[_z] = null; + this[_u] = null; + this[_w] = null; } - [(foo(), _w = foo(), _x = foo(), "some" + "method")]() { } + [(foo(), _t = foo(), _u = foo(), "some" + "method")]() { } } -_y = fieldNameB, _z = fieldNameC; +_v = fieldNameB, _w = fieldNameC; __decorate([ x ], E.prototype, "property", void 0); @@ -327,43 +326,43 @@ __decorate([ ], E.prototype, Symbol.iterator, void 0); __decorate([ x -], E.prototype, _w, void 0); +], E.prototype, _t, void 0); __decorate([ x -], E.prototype, _x, void 0); +], E.prototype, _u, void 0); __decorate([ x -], E.prototype, _y, void 0); +], E.prototype, _v, void 0); __decorate([ x -], E.prototype, _z, void 0); -void (_b = class F { +], E.prototype, _w, void 0); +void (_1 = class F { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_1] = null; - this[_3] = null; + this[_y] = null; + this[_0] = null; } - [(foo(), _0 = foo(), _1 = foo(), "some" + "method")]() { } + [(foo(), _x = foo(), _y = foo(), "some" + "method")]() { } }, - _2 = fieldNameB, - _3 = fieldNameC, - _b); + _z = fieldNameB, + _0 = fieldNameC, + _1); class G { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; + this[_3] = null; this[_5] = null; - this[_7] = null; } - [(foo(), _4 = foo(), _5 = foo(), "some" + "method")]() { } - [(_6 = fieldNameB, "some" + "method2")]() { } + [(foo(), _2 = foo(), _3 = foo(), "some" + "method")]() { } + [(_4 = fieldNameB, "some" + "method2")]() { } } -_7 = fieldNameC; +_5 = fieldNameC; __decorate([ x ], G.prototype, "property", void 0); @@ -378,43 +377,43 @@ __decorate([ ], G.prototype, Symbol.iterator, void 0); __decorate([ x -], G.prototype, _4, void 0); +], G.prototype, _2, void 0); __decorate([ x -], G.prototype, _5, void 0); +], G.prototype, _3, void 0); __decorate([ x -], G.prototype, _6, void 0); +], G.prototype, _4, void 0); __decorate([ x -], G.prototype, _7, void 0); -void (_c = class H { +], G.prototype, _5, void 0); +void (_10 = class H { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; + this[_7] = null; this[_9] = null; - this[_11] = null; } - [(foo(), _8 = foo(), _9 = foo(), "some" + "method")]() { } - [(_10 = fieldNameB, "some" + "method2")]() { } + [(foo(), _6 = foo(), _7 = foo(), "some" + "method")]() { } + [(_8 = fieldNameB, "some" + "method2")]() { } }, - _11 = fieldNameC, - _c); + _9 = fieldNameC, + _10); class I { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_13] = null; - this[_16] = null; + this[_12] = null; + this[_15] = null; } - [(foo(), _12 = foo(), _13 = foo(), _14 = "some" + "method")]() { } - [(_15 = fieldNameB, "some" + "method2")]() { } + [(foo(), _11 = foo(), _12 = foo(), _13 = "some" + "method")]() { } + [(_14 = fieldNameB, "some" + "method2")]() { } } -_16 = fieldNameC; +_15 = fieldNameC; __decorate([ x ], I.prototype, "property", void 0); @@ -429,30 +428,30 @@ __decorate([ ], I.prototype, Symbol.iterator, void 0); __decorate([ x -], I.prototype, _12, void 0); +], I.prototype, _11, void 0); __decorate([ x -], I.prototype, _13, void 0); +], I.prototype, _12, void 0); __decorate([ x -], I.prototype, _14, null); +], I.prototype, _13, null); __decorate([ x -], I.prototype, _15, void 0); +], I.prototype, _14, void 0); __decorate([ x -], I.prototype, _16, void 0); -void (_d = class J { +], I.prototype, _15, void 0); +void (_21 = class J { constructor() { this["property2"] = 2; this[Symbol.iterator] = null; this["property4"] = 2; this[Symbol.match] = null; - this[_18] = null; - this[_21] = null; + this[_17] = null; + this[_20] = null; } - [(foo(), _17 = foo(), _18 = foo(), _19 = "some" + "method")]() { } - [(_20 = fieldNameB, "some" + "method2")]() { } + [(foo(), _16 = foo(), _17 = foo(), _18 = "some" + "method")]() { } + [(_19 = fieldNameB, "some" + "method2")]() { } }, - _21 = fieldNameC, - _d); + _20 = fieldNameC, + _21); diff --git a/tests/baselines/reference/systemModuleTargetES6.js b/tests/baselines/reference/systemModuleTargetES6.js index 0df2835683e82..943e57ff742ac 100644 --- a/tests/baselines/reference/systemModuleTargetES6.js +++ b/tests/baselines/reference/systemModuleTargetES6.js @@ -35,8 +35,8 @@ System.register([], function (exports_1, context_1) { MyClass2 = class MyClass2 { static getInstance() { return MyClass2.value; } }; - exports_1("MyClass2", MyClass2); MyClass2.value = 42; + exports_1("MyClass2", MyClass2); } }; }); diff --git a/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js b/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js index 872008368c682..21871ff230472 100644 --- a/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js +++ b/tests/baselines/reference/variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.js @@ -16,8 +16,8 @@ var Foo = /** @class */ (function () { } return Foo; }()); -exports.Foo = Foo; _a = key; +exports.Foo = Foo; //// [variableDeclarationDeclarationEmitUniqueSymbolPartialStatement.d.ts]