Stage 2 Draft / January 18, 2019

Decorators proposal

Introduction

This proposal adds decorators to JavaScript. It incorporates features needed to make decorators work with the class fields and private methods. See the explainer for an overview.

This document is phrased as a diff against the previous private methods proposal, which is in turn a diff against the class fields proposal.

1Syntax

1.1New Productions

DecoratorList[Yield, Await]:DecoratorList[?Yield, ?Await]optDecorator[?Yield, ?Await] Decorator[Yield, Await]:@DecoratorMemberExpression[?Yield, ?Await] @DecoratorCallExpression[?Yield, ?Await] DecoratorMemberExpression[Yield, Await]:IdentifierReference[?Yield, ?Await] DecoratorMemberExpression[?Yield, ?Await].IdentifierName (Expression[+In, ?Yield, ?Await]) DecoratorCallExpression[Yield, Await]:DecoratorMemberExpressionArguments[?Yield, ?Await]

1.2Updated Productions

ClassElement[Yield, Await]:DecoratorList[?Yield, ?Await]optMethodDefinition[?Yield, ?Await] DecoratorList[?Yield, ?Await]optstaticMethodDefinition[?Yield, ?Await] DecoratorList[?Yield, ?Await]optFieldDefinition[?Yield, ?Await]; DecoratorList[?Yield, ?Await]optstaticFieldDefinition[?Yield, ?Await]; ClassDeclaration[Yield, Await, Default]:DecoratorList[?Yield, ?Await]optclassBindingIdentifier[?Yield, ?Await]ClassTail[?Yield, ?Await] [+Default]DecoratorList[?Yield, ?Await]optclassClassTail[?Yield, ?Await] ClassExpression[Yield, Await]:DecoratorList[?Yield, ?Await]optclassBindingIdentifier[?Yield, ?Await]optClassTail[?Yield, ?Await] ExportDeclaration:export*FromClause; exportExportClauseFromClause; exportExportClause; exportVariableStatement[~Yield, ~Await] exportDeclaration[~Yield, ~Await] exportdefaultHoistableDeclaration[~Yield, ~Await, +Default] exportdefaultClassDeclaration[~Yield, ~Await, +Default] exportdefault[lookahead ∉ { function, async [no LineTerminator here] function, class, @ }]AssignmentExpression[+In, ~Yield, ~Await];

1.3Static Semantics: Early Errors

DecoratorList[Yield, Await]:MethodDefinition[?Yield, ?Await]

2New ECMAScript Specification Types

2.1Classes Specification Types

2.1.1The ElementDescriptor Specification Type

The ElementDescriptor is a Record used to represent class elements at runtime. Values of the ElementDescriptor type are Record values whose fields are defined as by Table 1. Unless otherwise specified, every field is always present.

Table 1: ElementDescriptor fields
Field Name Value
[[Kind]] One of "method", "accessor", "field", or "hook"
[[Key]] A Property Key or %PrivateName% object
[[Descriptor]] A Property Descriptor
[[Placement]] One of "static", "prototype", or "own"
[[Initializer]] A function or empty. This field can be absent.
[[Start]] A function. This field can be absent.
[[Replace]] A function. This field can be absent.
[[Finish]] A function. This field can be absent.
[[Decorators]] A List of ECMAScript language values. This field can be absent.

In addition, given an ElementDescriptor element, the following conditions are always respected:

  • If element.[[Kind]] is "method" or "accessor", then
    • element.[[Initializer]] is absent.
    • element.[[Start]] is absent.
    • element.[[Replace]] is absent.
    • element.[[Finish]] is absent.
  • If element.[[Kind]] is "field", then
    • element.[[Initializer]] is present.
    • element.[[Start]] is absent.
    • element.[[Replace]] is absent.
    • element.[[Finish]] is absent.
    • element.[[Descriptor]]'s [[Get]], [[Set]], and [[Value]] slots are absent.
  • If element.[[Key]] is a Private Name, then
    • element.[[Placement]] is "own" or "static".
    • element.[[Descriptor]].[[Enumerable]] is false.
    • element.[[Descriptor]].[[Configurable]] is false.
    • element.[[Start]] is absent.
    • element.[[Replace]] is absent.
    • element.[[Finish]] is absent.
  • If element.[[Kind]] is `"hook", then
    • element.[[Key]] absent.
    • element.[[Descriptor]] is absent.
    • element.[[Initializer]] is absent.
    • At least one of element.[[Start]], element.[[Replace]], and element.[[Finish]] is present.
    • element.[[Replace]] and element.[[Finish]] are not both present.
    • element.[[Decorators]] is absent.
  • If element.[[Kind]] is "method", then
  • If element.[[Kind]] is "accessor", then

3Class algorithms

3.1Runtime Semantics: ClassDefinitionEvaluation

With parameters className and decorators.

ClassTail:ClassHeritageopt{ClassBodyopt}
  1. Let lex be the LexicalEnvironment of the running execution context.
  2. Let classScope be NewDeclarativeEnvironment(lex).
  3. Let classScopeEnvRec be classScope's EnvironmentRecord.
  4. If className is not undefined, then
    1. Perform classScopeEnvRec.CreateImmutableBinding(className, true).
  5. Let outerPrivateEnvironment be the PrivateNameEnvironment of the running execution context.
  6. Let classPrivateEnvironment be NewDeclarativeEnvironment(outerPrivateEnvironment).
  7. Let classPrivateEnvRec be classPrivateEnvironment's EnvironmentRecord.
  8. If ClassBodyopt is present, then
    1. For each element dn of the PrivateBoundNames of ClassBodyopt,
      1. Perform classPrivateEnvRec.CreateImmutableBinding(dn, true).
  9. If ClassHeritageopt is not present, then
    1. Let protoParent be the intrinsic object %ObjectPrototype%.
    2. Let constructorParent be the intrinsic object %FunctionPrototype%.
  10. Else,
    1. Set the running execution context's LexicalEnvironment to classScope.
    2. Let superclass be the result of evaluating ClassHeritage.
    3. Set the running execution context's LexicalEnvironment to lex.
    4. ReturnIfAbrupt(superclass).
    5. If superclass is null, then
      1. Let protoParent be null.
      2. Let constructorParent be the intrinsic object %FunctionPrototype%.
    6. Else if IsConstructor(superclass) is false, throw a TypeError exception.
    7. Else,
      1. Let protoParent be ? Get(superclass, "prototype").
      2. If Type(protoParent) is neither Object nor Null, throw a TypeError exception.
      3. Let constructorParent be superclass.
  11. Let proto be ObjectCreate(protoParent).
  12. If ClassBodyopt is not present, let constructor be empty.
  13. Else, let constructor be ConstructorMethod of ClassBody.
  14. If constructor is empty, then
    1. If ClassHeritageopt is present and protoParent is not null, then
      1. Let constructor be the result of parsing the source text
        constructor(... args){ super (...args);}
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
    2. Else,
      1. Let constructor be the result of parsing the source text
        constructor( ){ }
        using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
  15. Set the running execution context's LexicalEnvironment to classScope.
  16. Set the running execution context's PrivateNameEnvironment to classPrivateEnvironment.
  17. Let constructorInfo be the result of performing DefineMethod for constructor with arguments proto and constructorParent as the optional functionPrototype argument.
  18. Assert: constructorInfo is not an abrupt completion.
  19. Let F be constructorInfo.[[Closure]].
  20. If ClassHeritageopt is present and protoParent is not null, then set F.[[ConstructorKind]] to "derived".
  21. Perform MakeConstructor(F, false, proto).
  22. Perform MakeClassConstructor(F).
  23. Perform CreateMethodProperty(proto, "constructor", F).
  24. If ClassBodyopt is not present, let methodselements be a new empty List.
  25. Else, let methodsdefinitions be NonConstructorMethodDefinitionsNonConstructorElementDefinitions of ClassBody. NOTE: Simply renaming this internal algorithm will be enough; it includes fields.
  26. Let elements be a new empty List.
  27. For each ClassElement md in order from methodsdefinitions,
    1. If IsStatic of m is false, then
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto and false.
    2. Else,
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.
    3. Let newElement be the result of performing ClassElementEvaluation for d with arguments F, true, and empty.
    4. If statusnewElement is an abrupt completion, then
      1. Set the running execution context's LexicalEnvironment to lex.
      2. Set the running execution context's PrivateNameEnvironment to outerPrivateEnvironment.
      3. Return Completion(status).
    5. Append newElement to elements
  28. Set elements to CoalesceClassElements(elements).
  29. If decorators is not provided, let decorators be a new empty List.
  30. Let decorated be ? DecorateClass(elements, decorators).
  31. Perform ? AssignPrivateNames(decorated.[[Elements]]).
  32. Set the running execution context's LexicalEnvironment to lex.
  33. Set the running execution context's PrivateNameEnvironment to outerPrivateEnvironment.
  34. If className is not undefined, then
    1. Perform classScopeEnvRec.InitializeBinding(className, F).
  35. Set the value of F's [[Elements]] internal slot to decorated.[[Elements]].
  36. Return ? InitializeClassElements(F, proto).
  37. Return F.

3.2DefaultMethodDescriptor ( key, closure, enumerable, placement )

  1. Perform SetFunctionName(closure, key).
  2. If key is a Private Name,
    1. Set enumerable to false.
    2. Let configurable be false.
    3. Let writable be false.
    4. If placement is "prototype", set placement to "own".
  3. Else,
    1. Let configurable be true.
    2. Let writable be true.
  4. Let desc be the PropertyDescriptor{[[Value]]: closure, [[Writable]]: writable, [[Enumerable]]: enumerable, [[Configurable]]: configurable}.
  5. Return the ElementDescriptor { [[Kind]]: "method", [[Key]]: key, [[Descriptor]]: desc, [[Placement]]: placement }

3.3Runtime Semantics: ClassElementEvaluation

With parameters homeObject, enumerable, and placement.

ClassElementEvaluation returns an ElementDescriptor Record.

ClassElement:DecoratorListoptMethodDefinition
  1. If DecoratorList is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Let element be ? ClassElementEvaluation of MethodDefinition with arguments ! Get(homeObject, "prototype"), enumerable, and "prototype".
  3. If DecoratorList is present, set element.[[Decorators]] to decorators.
  4. Return element.
ClassElement:DecoratorListoptstaticMethodDefinition
  1. If DecoratorList is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Let element be ? ClassElementEvaluation of MethodDefinition with arguments homeObject, enumerable, and "static".
  3. If DecoratorList is present, set element.[[Decorators]] to decorators.
  4. Return elements.
ClassElement:DecoratorListoptstaticFieldDefinition;
  1. If DecoratorList is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Let element be ? ClassFieldDefinitionEvaluation of FieldDefinition with parameters "static" and homeObject.
  3. If DecoratorList is present, set element.[[Decorators]] to decorators.
  4. Return element.
ClassElement:DecoratorListoptFieldDefinition;
  1. If DecoratorList is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Let element be ? ClassFieldDefinitionEvaluation of FieldDefinition with parameters "own" and ! Get(homeObject, "prototype").
  3. If DecoratorList is present, set element.[[Decorators]] to decorators.
  4. Return element.
ClassElement:MethodDefinition
  1. Return ClassElementEvaluation of MethodDefinition with arguments ! Get(homeObject, "prototype"), enumerable, and "prototype".
ClassElement:staticMethodDefinition
  1. Return ClassElementEvaluation of MethodDefinition with arguments homeObject, enumerable, and "static".
MethodDefinition:ClassElementName(UniqueFormalParameters){FunctionBody}
  1. Let methodDef be DefineMethod of MethodDefinition with argument homeObject.
  2. ReturnIfAbrupt(methodDef).
  3. Perform SetFunctionName(methodDef.[[Closure]], methodDef.[[Key]]).
  4. Let desc be the PropertyDescriptor{[[Value]]: methodDef.[[Closure]], [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  5. Return ? DefinePropertyOrThrow(homeObject, methodDef.[[Key]], desc).DefaultMethodDescriptor(methodDef.[[Key]], methodDef.[[Closure]], enumerable, placement).
MethodDefinition:getClassElementName(){FunctionBody}
  1. Let key be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(key).
  3. If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let formalParameterList be an instance of the production FormalParameters:[empty] .
  6. Let closure be FunctionCreate(Method, formalParameterList, FunctionBody, scope, strict).
  7. Perform MakeMethod(closure, homeObject).
  8. Perform SetFunctionName(closure, key, "get").
  9. Let desc be the PropertyDescriptor{[[Get]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  10. Return ? DefinePropertyOrThrow(homeObject, propKey, desc).
  11. If key is a Private Name,
    1. Set enumerable to false.
    2. Let configurable be false.
    3. If placement is "prototype", set placement to "own".
  12. Else,
    1. Let configurable be true.
  13. Let desc be the PropertyDescriptor{[[Get]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: configurable}.
  14. Return the ElementDescriptor { [[Kind]]: "method", [[Key]]: key, [[Descriptor]]: desc, [[Placement]]: placement }
MethodDefinition:setClassElementName(PropertySetParameterList){FunctionBody}
  1. Let key be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(key).
  3. If the function code for this MethodDefinition is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be FunctionCreate(Method, PropertySetParameterList, FunctionBody, scope, strict).
  6. Perform MakeMethod(closure, homeObject).
  7. Perform SetFunctionName(closure, key, "set").
  8. Let desc be the PropertyDescriptor{[[Set]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  9. Return ? DefinePropertyOrThrow(homeObject, propKey, desc).
  10. If key is a Private Name,
    1. Set enumerable to false.
    2. Let configurable be false.
    3. If placement is "prototype", set placement to "own".
  11. Else,
    1. Let configurable be true.
  12. Let desc be the PropertyDescriptor{[[Set]]: closure, [[Enumerable]]: enumerable, [[Configurable]]: configurable}.
  13. Return the ElementDescriptor { [[Kind]]: "method", [[Key]]: key, [[Descriptor]]: desc, [[Placement]]: placement }
GeneratorMethod:*ClassElementName(UniqueFormalParameters){GeneratorBody}
  1. Let key be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(key).
  3. If the function code for this GeneratorMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be GeneratorFunctionCreate(Method, UniqueFormalParameters, GeneratorBody, scope, strict).
  6. Perform MakeMethod(closure, homeObject).
  7. Let prototype be ObjectCreate(%GeneratorPrototype%).
  8. Perform DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor{[[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  9. Perform SetFunctionName(closure, propKey).
  10. Let desc be the PropertyDescriptor{[[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  11. Return ? DefinePropertyOrThrow(homeObject, propKey, desc).
  12. Return DefaultMethodDescriptor(key, closure, enumerable, placement).
AsyncMethod:async[no LineTerminator here]ClassElementName(UniqueFormalParameters){AsyncFunctionBody}
  1. Let key be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(key).
  3. If the function code for this AsyncMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the LexicalEnvironment of the running execution context.
  5. Let closure be ! AsyncFunctionCreate(Method, UniqueFormalParameters, AsyncFunctionBody, scope, strict).
  6. Perform ! MakeMethod(closure, homeObject).
  7. Perform ! SetFunctionName(closure, key).
  8. Let desc be the PropertyDescriptor{[[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true}.
  9. Return ? DefinePropertyOrThrow(homeObject, propKey, desc).
  10. Return DefaultMethodDescriptor(key, closure, enumerable, placement).
AsyncGeneratorMethod:async[no LineTerminator here]*ClassElementName(UniqueFormalParameters){AsyncGeneratorBody}
  1. Let key be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(key).
  3. If the function code for this AsyncGeneratorMethod is strict mode code, let strict be true. Otherwise let strict be false.
  4. Let scope be the running execution context's LexicalEnvironment.
  5. Let closure be ! AsyncGeneratorFunctionCreate(Method, UniqueFormalParameters, AsyncGeneratorBody, scope, strict).
  6. Perform ! MakeMethod(closure, object).
  7. Let prototype be ! ObjectCreate(%AsyncGeneratorPrototype%).
  8. Perform ! DefinePropertyOrThrow(closure, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  9. Perform ! SetFunctionName(closure, propKey).
  10. Let desc be PropertyDescriptor { [[Value]]: closure, [[Writable]]: true, [[Enumerable]]: enumerable, [[Configurable]]: true }.
  11. Return ? DefinePropertyOrThrow(object, propKey, desc).
  12. Return DefaultMethodDescriptor(key, closure, enumerable, placement).

3.4Runtime Semantics: ClassFieldDefinitionEvaluation

With parameters placement and homeObject.

FieldDefinition:ClassElementNameInitializeropt
  1. Let fieldName be the result of evaluating ClassElementName.
  2. ReturnIfAbrupt(fieldName).
  3. If Initializeropt is present,
    1. Let lex be the Lexical Environment of the running execution context.
    2. Let formalParameterList be an instance of the production FormalParameters:[empty] .
    3. Let initializer be FunctionCreate(Method, formalParameterList, Initializer, lex, true).
    4. Perform MakeMethod(initializer, homeObject).
  4. Else,
    1. Let initializer be empty.
  5. If key is a Private Name,
    1. Let enumerable be false.
    2. Let configurable be false.
    3. Let writable be false.
  6. Else,
    1. Let enumerable be true.
    2. Let configurable be true.
    3. Let writable be true.
  7. Let desc be the PropertyDescriptor{[[Value]]: initializer, [[Writable]]: writable, [[Enumerable]]: enumerable, [[Configurable]]: configurable}.
  8. Return an ElementDescriptor { [[Kind]]: "field", [[Key]]: fieldName, [[Initializer]]: initializer, [[Descriptor]]: desc [[Placement]]: placement, }.

3.5Runtime Semantics: BindingClassDeclarationEvaluation

ClassDeclaration:DecoratorListoptclassBindingIdentifierClassTail
  1. If DecoratorListopt is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Otherwise, let decorators be a new empty List.
  3. Let className be StringValue of BindingIdentifier.
  4. Let value be the result of ClassDefinitionEvaluation of ClassTail with arguments className and _decorators.
  5. ReturnIfAbrupt(value).
  6. Let hasNameProperty be ? HasOwnProperty(value, "name").
  7. If hasNameProperty is false, perform SetFunctionName(value, className).
  8. Let env be the running execution context's LexicalEnvironment.
  9. Perform ? InitializeBoundName(className, value, env).
  10. Return value.
ClassDeclaration:DecoratorListoptclassClassTail
  1. If DecoratorList is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Otherwise, let decorators be a new empty List.
  3. Return the result of ClassDefinitionEvaluation of ClassTail with arguments undefined and decorators.
Note

ClassDeclaration:classClassTail only occurs as part of an ExportDeclaration and the setting of a name property and establishing its binding are handled as part of the evaluation action for that production. See 15.2.3.9.

3.6Runtime Semantics: Evaluation

ClassDeclaration:DecoratorListoptclassBindingIdentifierClassTail
  1. Perform ? BindingClassDeclarationEvaluation of this ClassDeclaration.
  2. Return NormalCompletion(empty).
Note 1

ClassDeclaration:classClassTail only occurs as part of an ExportDeclaration and is never directly evaluated.

ClassExpression:DecoratorListoptclassBindingIdentifieroptClassTail
  1. If DecoratorListopt is present, let decorators be the result of performing DecoratorListEvaluation of DecoratorList.
  2. Otherwise, let decorators be a new empty List.
  3. If BindingIdentifieropt is not present, let className be undefined.
  4. Else, let className be StringValue of BindingIdentifier.
  5. Let value be the result of ClassDefinitionEvaluation of ClassTail with argument className and decorators.
  6. ReturnIfAbrupt(value).
  7. If className is not undefined, then
    1. Let hasNameProperty be ? HasOwnProperty(value, "name").
    2. If hasNameProperty is false, then
      1. Perform SetFunctionName(value, className).
  8. Return NormalCompletion(value).
Note 2

If the class definition included a name static method then that method is not over-written with a name data property for the class name.

3.7CoalesceGetterSetter ( element, other )

  1. Assert: element and other are both ElementDescriptor Records.
  2. Assert: IsAccessorDescriptor(other.[[Descriptor]]) and IsAccessorDescriptor(element.[[Descriptor]]) are both true,
  3. If element.[[Descriptor]] has a [[Get]] field,
    1. Set other.[[Descriptor]].[[Get]] to element.[[Descriptor]].[[Get]].
  4. Otherwise,
    1. Assert: element.[[Descriptor]] has a [[Set]] field.
    2. Set other.[[Descriptor]].[[Set]] to element.[[Descriptor]].[[Set]].

3.8CoalesceClassElements ( elements )

  1. Assert: elements is a List of ElementDescriptor Records.
  2. Let newElements be an empty List.
  3. For element in elements,
    1. If element.[[Kind]] is "method" or "accessor", and newElements contains a Record other where other.[[Kind]] is "method" or "accessor", other.[[Key]] is element.[[Key]], and other.[[Placement]] is element.[[Placement]],
      1. If IsDataDescriptor(element.[[Descriptor]]) is true or IsDataDescriptor(other.[[Descriptor]]) is true, then
        1. Assert: element.[[Key]] is not a Private Name.
        2. Assert: element.[[Descriptor]].[[Configurable]] is true, and other.[[Descriptor]].[[Configurable]] is true.
        3. If element.[[Decorators]] is present or other.[[Decorators]] is present, throw a TypeError exception.
        4. Set other.[[Descriptor]] to element.[[Descriptor]].
      2. Else,
        1. If element.[[Decorators]] is present,
          1. If other.[[Decorators]] is present, throw a TypeError exception.
          2. Set other.[[Decorators]] to element.[[Decorators]].
        2. Perform ! CoalesceGetterSetter(element, other).
    2. Otherwise, append element to newElements.
  4. Return newElements.
Note
In the case of public class elements, coalescing corresponds in semantics to ValidateAndApplyPropertyDescriptor. Note that this algorithm only coalesces method and accessor declarations, and it leaves field declarations as is.

3.9DefineField(receiver, descriptor)

  1. Assert: Type(receiver) is Object.
  2. Assert: descriptor is an ElementDescriptor Record.
  3. Let key be descriptor.[[Key]].
  4. Let initializer be fieldRecord.[[Initializer]].
  5. If initializer is not empty, then
    1. Let initValue be ? Call(initializer, receiver).
  6. Else, let initValue be undefined.
  7. Assert: IsDataDescriptor(descriptor) is true.
  8. Let dataDescriptor be a PropertyDescriptor with the fields of descriptor, but with the [[Value]] field set to initValue.
  9. If fieldName is a Private Record,
    1. Perform ? PrivateFieldDefine(key, receiver, dataDescriptor).
  10. Else,
    1. Assert: IsPropertyKey(fieldName) is true.
    2. Perform ? DefinePropertyOrThrow(receiver, key, dataDescriptor).
  11. Return.

3.10PrivateFieldDefine (P, O, desc)

  1. Assert: P is a Private Name value.
  2. Assert: desc is a Property Descriptor.
  3. If O is not an object, throw a TypeError exception.
  4. Let entry be PrivateFieldFind(P, O).
  5. If entry is not empty, throw a TypeError exception.
  6. Append { [[PrivateName]]: P, [[PrivateFieldDescriptor]]: desc } to O.[[PrivateFieldDescriptors]].

3.11InitializeInstanceElements ( O, constructor )

  1. Assert: Type ( O ) is Object.
  2. Assert: Assert constructor is an ECMAScript function object.
  3. Let elements be the value of F's [[Elements]] internal slot.
  4. If constructor.[[PrivateBrand]] is not undefined,
    1. Perform ? PrivateBrandAdd(O, constructor.[[PrivateBrand]]).
  5. For each item element in order from elements,
    1. If element.[[Placement]] is "own", element.[[Kind]] is "method" or "accessor", and element.[[Key]] is a Property Key,
      1. Perform ? DefinePropertyOrThrow(O, element.[[Key]], element.[[Descriptor]]).
  6. For each item element in order from elements,
    1. If element.[[Placement]] is "own" and element.[[Kind]] is "field",
      1. Perform ? DefineField(O, element).
    2. If element.[[Kind]] is "hook" and element.[[Placement]] is "own",
      1. Let res be ? Call(element.[[Start]], O).
      2. If res is not undefined, throw a TypeError exception.
  7. Return.

3.12InitializeClassElements(F, proto)

  1. Assert: Type(F) is Object and Type(proto) is Object.
  2. Assert: F is an ECMAScript function object.
  3. Assert: proto is ! Get(F, "prototype").
  4. Let elements be the value of F's [[Elements]] internal slot.
  5. If elements contains an element such that element.[[Placement]] is "static", element has a [[Key]] field, and element.[[Key]] is a Private Name,
    1. Perform ? PrivateBrandAdd(F, F).
  6. For each item element in order from elements,
    1. If element.[[Kind]] is "method" or "accessor", element.[[Placement]] is "static" or "prototype", and element.[[Key]] is not a Private Name,
      1. Let receiver be F if element.[[Placement]] is "static", else let receiver be proto.
      2. Perform ? DefinePropertyOrThrow(receiver, element.[[Key]], element.[[Descriptor]]).
  7. For each item element in order from elements,
    1. If element.[[Kind]] is "field" and element.[[Placement]] is "static" or "prototype",
      1. Assert: element.[[Descriptor]] does not have a [[Value]], [[Get]] or [[Set]] slot.
      2. Let receiver be F if element.[[Placement]] is "static", else let receiver be proto.
      3. Perform ? DefineField(receiver, element).
    2. If element.[[Placement]] is "prototype" or "static" and element.[[Kind]] is "hook",
      1. Let receiver be F if element.[[Placement]] is "static", else let receiver be proto.
      2. Let res be ? Call(element.[[Start]], receiver).
      3. If res is not undefined, throw a TypeError exception.
  8. For each item element in order from elements,
    1. If element.[[Placement]] is "prototype" or "static", element.[[Kind]] is "hook",
      1. If element has a [[Replace]] field,
        1. Assert: element.[[Placement]] is "static".
        2. Let newConstructor be Call( element.[[Replace]], undefined, « F »).
        3. If IsConstructor(newConstructor) is false, throw a TypeError exception.
        4. Set F to newConstructor.
      2. If element has a [[Finish]] field,
        1. Let receiver be F if element.[[Placement]] is "static", else let receiver be proto.
        2. Let res be ? Call(element.[[Finish]], receiver).
        3. If res is not undefined, throw a TypeError exception.
  9. Return F.
Editor's Note
Brands, methods and accessors are added before initializers so that all methods are visible from all initializers

3.13AssignPrivateNames ( elements )

  1. For each element of elements,
    1. If element has a [[Key]] field and element.[[Key]] is a Private Name,
      1. Let name be element.[[Key]].
      2. Let attributes be name's associated [[Attributes]] record.
      3. If attributes does not have a [[Kind]] field, throw a TypeError exception.
      4. If element.[[Kind]] is "field",
        1. Set attributes.[[Kind]] to field.
      5. Otherwise, if element.[[Kind]] is "method",
        1. Set attributes.[[Kind]] to method.
      6. Otherwise, element.[[Kind]] is "accessor",
        1. Set attributes.[[Kind]] to accessor.
      7. Set attributes.[[Descriptor]] to element.[[Descriptor]].

4Private Names and references

Editor's Note
This section refers to Private Name values, as defined in the class fields proposal.

Each PrivateName value immutably holds a mutable record called [[Attributes]], initially empty, which may have the following fields added to it:

Table 2: Fields of the [[Attributes]] record
Field Type For which types is it present Description
[[Kind]] field, method or accessor All Indicates what the private name is used for.
[[Brand]] an ECMAScript value method or accessor The "original" class of the private method or accessor; checked for in the [[PrivateBrands]] internal slot of instances before access is provided.
[[Descriptor]] PropertyDescriptor field, method, or accessor A property descriptor for the private field, method, or accessor, including the getter/setter for accessors and the value for methods. For fields, the descriptor determines whether it is writable.
[[Value]] Function method The value of the private method.
[[Get]] Function accessor The getter for a private accessor.
[[Set]] Function accessor The setter for a private accessor.

4.1PrivateFieldGet (P, O )

  1. Assert: P is a Private Name value.
  2. If O is not an object, throw a TypeError exception.
  3. Let attributes be P's associated [[Attributes]] record.
  4. If attributes.[[Kind]] is field,
    1. Let entry be PrivateFieldFind(P, O).
    2. If entry is empty, throw a TypeError exception.
    3. Return entry.[[PrivateFieldValue]].
  5. Perform ? PrivateBrandCheck(O, P).
  6. If descriptor.[[Type]] is method,
    1. If attributes.[[Descriptor]].[[Writable]] is true,
      1. Let entry be PrivateFieldFind(P, O).
      2. If entry is not empty,
        1. Return entry.[[PrivateFieldValue]].
    2. Return attributes.[[Descriptor]].[[Value]].
  7. Otherwise, attributes.[[Kind]] is accessor,
    1. If attributes.[[Descriptor]] does not have a [[Get]] field, throw a TypeError exception.
    2. Let getter be _attributes.[[Descriptor]].[[Get]].
    3. Return ? Call(getter, O).

4.2PrivateFieldSet (P, O, value )

  1. Assert: P is a Private Name value.
  2. If O is not an object, throw a TypeError exception.
  3. Let attributes be P's associated [[Attributes]] record.
  4. If _attributes.[[Descriptor]].[[Kind]] is field,
    1. If attributes.[[Descriptor]].[[Writable]] is false, throw a TypeError exception.
    2. Let entry be PrivateFieldFind(P, O).
    3. If entry is empty, throw a TypeError exception.
    4. Set entry.[[PrivateFieldValue]] to value.
    5. Return.
  5. If attributes.[[Kind]] is method,
    1. If attributes.[[Descriptor]].[[Writable]] is false,
      1. Throw a TypeError exception.
    2. Otherwise,
      1. Let entry be PrivateFieldFind(P, O).
      2. If entry is empty,
        1. Append { [[PrivateRecord]]: P, [[PrivateFieldValue]]: value } to O.[[PrivateFieldValues]].
      3. Otherwise,
        1. Set entry.[[PrivateFieldValue]] to value.
      4. Return.
  6. Otherwise, attribute.[[Kind]] is accessor,
    1. If O.[[PrivateFieldBrands]] does not contain attributes.[[Brand]], throw a TypeError exception.
    2. If attributes.[[Descriptor]] does not have a [[Set]] field, throw a TypeError exception.
    3. Let setter be attributes.[[Descriptor]].[[Set]].
    4. Perform ? Call(setter, O, value).
    5. Return.

4.3Private Name Objects

4.3.1The %PrivateName% Constructor

The Private Name constructor is the %PrivateName% intrinsic object. The %PrivateName% intrinsic does not have a global name or appear as a property of the global object.

The PrivateName object is deeply frozen, in the sense that it is frozen, all objects reachable from it are frozen, and PrivateName instances are frozen as well. See the logic in CreateIntrinsics for details.

4.3.1.1%PrivateName% ( )

When %PrivateName% is called, the following steps are taken:

  1. Throw a TypeError exception.
Note
New PrivateName instances can be created by decorating private class elements.

4.3.1.2PrivateNameObject ( name )

When PrivateNameObject is called with Private Name name, the following steps are taken:

  1. Let O be ? ObjectCreate(%PrivateNamePrototype%, « [[PrivateNameData]] »).
  2. Set O.[[PrivateNameData]] to name.
  3. Perform ! SetIntegrityLevel(O, "frozen").
  4. Return O.

4.3.1.3Properties of the %PrivateNamePrototype% Object

The %PrivateNamePrototype% object is an ordinary object. It is not a %PrivateName% instance and does not have a [[PrivateNameData]] internal slot.

4.3.1.3.1%PrivateName%.prototype.constructor

The initial value of PrivateName.prototype.constructor is the intrinsic object %PrivateName%.

4.3.1.3.2%PrivateName%.prototype.get ( object )

When invoked, the following steps are taken:

  1. Let O be the this value.
  2. Let pn be ? GetPrivateName(O).
  3. If Type(object) is not Object, throw a TypeError exception.
  4. Return ? PrivateFieldGet(pn, object).

4.3.1.3.3%PrivateName%.prototype.set ( object, value )

%PrivateNameSet% is a per-realm built-in function object. When invoked, the following steps are taken:

  1. Let O be the this value.
  2. Let pn be ? GetPrivateName(O).
  3. If Type(object) is not Object, throw a TypeError exception.
  4. Return ? PrivateFieldSet(pn, object, value).

4.3.1.3.4get %PrivateName%.prototype.description ( )

The following steps are taken:

  1. Let O be the this value.
  2. Let pn be ? GetPrivateName(O).
  3. Let desc be pn's [[Description]] value.
  4. If desc is undefined, return the empty string.
  5. Otherwise, return desc.

4.3.1.3.5%PrivateName%.prototype.toString ( )

The following steps are taken:

  1. Throw a TypeError exception.
Note
Because conversion to a string throws, ToPropertyKey applied to a %PrivateName% object throws as well. This property is important to ensure that Private Names are not incorrectly used by decorators using property access, rather than with their get and set methods.

4.3.1.3.6PrivateName.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "PrivateName".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

4.3.1.3.7GetPrivateName ( O )

  1. If Type(O) is not Object, throw a TypeError exception.
  2. If O does not have a [[PrivateNameData]] internal slot, throw a TypeError exception.
  3. Return O.[[PrivateNameData]].

4.3.1.4Properties of PrivateName Instances

PrivateName instances are ordinary objects that inherit properties from the PrivateName prototype object. PrivateName instances have a [[PrivateNameData]] internal slot. The [[PrivateNameData]] internal slot is the Private Name value represented by this Private Name object.

4.4CreateIntrinsics ( realmRec )

The abstract operation CreateIntrinsics with argument realmRec performs the following steps:

  1. Let intrinsics be a new Record.
  2. Set realmRec.[[Intrinsics]] to intrinsics.
  3. Let objProto be ObjectCreate(null).
  4. Set intrinsics.[[%ObjectPrototype%]] to objProto.
  5. Let throwerSteps be the algorithm steps specified in 9.2.7.1 for the %ThrowTypeError% function.
  6. Let thrower be CreateBuiltinFunction(throwerSteps, « », realmRec, null).
  7. Set intrinsics.[[%ThrowTypeError%]] to thrower.
  8. Let noSteps be an empty sequence of algorithm steps.
  9. Let funcProto be CreateBuiltinFunction(noSteps, « », realmRec, objProto).
  10. Set intrinsics.[[%FunctionPrototype%]] to funcProto.
  11. Call thrower.[[SetPrototypeOf]](funcProto).
  12. Perform AddRestrictedFunctionProperties(funcProto, realmRec).
  13. Set fields of intrinsics with the values listed in Table 7 that have not already been handled above. The field names are the names listed in column one of the table. The value of each field is a new object value fully and recursively populated with property values as defined by the specification of each object in clauses 18-26. All object property values are newly created object values. All values that are built-in function objects are created by performing CreateBuiltinFunction(<steps>, <slots>, realmRec, <prototype>) where <steps> is the definition of that function provided by this specification, <slots> is a list of the names, if any, of the function's specified internal slots, and <prototype> is the specified value of the function's [[Prototype]] internal slot. The creation of the intrinsics and their properties must be ordered to avoid any dependencies upon objects that have not yet been created.
  14. For each property of %PrivateNamePrototype%, do
    1. Let desc be the data property descriptor for this property.
    2. If desc has a [[Get]], [[Set]], or [[Value]] field, then for each value value of such fields,
      1. Perform ! SetIntegrityLevel(value, "frozen").
  15. Perform ! SetIntegrityLevel(%PrivateNamePrototype%, "frozen").
  16. Assert: The only own property of %PrivateName% is the "prototype" property, whose [[Value]] is %PrivateNamePrototype%.
  17. Perform ! SetIntegrityLevel(%PrivateName%, "frozen").
  18. Return intrinsics.

5Decorator semantics

5.1Decorator Functions

A decorator function is a function that takes and returns either a element descriptor or a class descriptor. The body of a decorator function modifies and returns the descriptor it receives to change the semantics of the decorated entity. Descriptor types can be differentiated by their kind property, which is either "method", "accessor", "field", or "class". Descriptors also have a @@toStringTag property which has the value "Descriptor"; this property helps differentiate them from other objects.

5.1.1Element Descriptors

An element descriptor describes an element of a class or object literal and has the following shape:

interface ElementDescriptor {
  kind: "method", "accessor", "hook", or "field"
  key: String, Symbol or Private Name,
  placement: "static", "prototype", or "own"
  ...PropertyDescriptor,
  initializer?: Function
  extras?: ElementDescriptor[]
  start?: (any): undefined;
  finish?: (klass): undefined;
  replace?: (klass): constructor;
}
The start, finish, replace and extra fields are only present when returning from user code, and are not given as an argument to them, or logically part of the descriptor.

5.1.2Class Descriptors

A class descriptor describes a class and has the following shape:

interface ClassDescriptor {
  kind: "class"
  elements: ElementDescriptor[]
  finish?: (klass): undefined;
  replace?: (klass): constructor;
}

5.2Runtime Semantics: DecoratorEvaluation

Decorator:@DecoratorMemberExpression[?Yield]
  1. Let expr be the MemberExpression that is covered by DecoratorMemberExpression.
  2. Let ref be the result of evaluating expr.
  3. Let value be ? GetValue(ref).
  4. Return value.
Decorator:@DecoratorCallExpression[?Yield]
  1. Let expr be the result of reparsing DecoratorCallExpression as a CallMemberExpression.
  2. Let ref be the result of evaluating expr.
  3. Let value be ? GetValue(ref).
  4. Return value.

5.3Runtime Semantics: DecoratorListEvaluation

DecoratorList:DecoratorList[?Yield]optDecorator[?Yield]
  1. If DecoratorList is present, then let leftValue be ? DecoratorListEvaluation(DecoratorList).
  2. Else, let leftValue be a new empty List.
  3. Let rightValue be ? DecoratorEvaluation(Decorator).
  4. Append rightValue to the end of leftValue.
  5. Return leftValue.

5.4DecorateClass ( elements, decorators )

  1. Let newElements be a new empty List.
  2. Let placements be the Record { [[StaticKeys]]: « », [[PrototypeKeys]]: « », [[OwnKeys]]: « » }.
  3. For each element in elements, do
    1. Perform ? AddElementPlacement(element, placements, true).
  4. For each element in elements, do
    1. Let elements be ? DecorateElement(element, placements).
    2. Concatenate elements onto newElements.
  5. Return ? DecorateConstructor(newElements, decorators).

5.5DecorateElement ( element, placements )

With parameters element, a Class Element, and placements:

  1. Let extras be a new empty List.
  2. If element has a [[Decorators]] field, then for each decorator in element.[[Decorators]], in reverse list order do
    1. If element.[[Kind]] is "hook", throw a TypeError.
    2. Perform RemoveElementPlacement(element, placements).
    3. Let elementObject be ? FromElementDescriptor(element).
    4. Let elementExtrasObject be ? Call(decorator, undefined, « elementObject »).
    5. If elementExtrasObject is undefined,
      1. Let elementExtrasObject be elementObject.
    6. Otherwise, set elementExtrasObject to ? ToObject(elementExtrasObject).
    7. Let elementExtras be ? ToElementExtras(elementExtrasObject).
    8. Let element be elementExtras.[[Element]].
    9. Perform ? AddElementPlacement(element, placements).
    10. Let newExtras be elementExtras.[[Extras]]
    11. If newExtras is not undefined, then
      1. For each extra of newExtras, do
        1. Perform ? AddElementPlacement(extra, placements).
      2. Concatenate newExtras onto extras.
  3. Append element to the start of extras.
  4. Return extras.

5.6DecorateConstructor ( elements, decorators )

With parameters elements, a List of Class Elements, and decorators, a List of decorator functions.

  1. For each decorator in decorators, in reverse list order do
    1. Let obj be FromClassDescriptor(elements).
    2. Let result be ? Call(decorator, undefined, « obj »).
    3. If result is undefined, let result be obj.
    4. Otherwise, set result to ? ToObject(result).
    5. Let newElements be ? ToClassDescriptor(result).
    6. If newElements is not undefined,
      1. Set elements to newElements.
      2. If there are two class elements a and b in elements such that all of the following are true:
        1. a.[[Kind]] is not "hook"
        2. b.[[Kind]] is not "hook"
        3. a.[[Key]] is b.[[Key]]
        4. a.[[Placement]] is b.[[Placement]]
      3. Then, throw a TypeError exception.
  2. Return the elements.

5.7AddElementPlacement (element, placements [, silent])

  1. If element does not have a [[Key]] field, return.
  2. If element.[[Placement]] is "own", then
    1. Let keys be placements.[[OwnKeys]].
  3. Else if element.[[Placement]] is "static", then
    1. Let keys be placements.[[StaticKeys]].
  4. Else,
    1. Assert: element.[[Placement]] is "prototype".
    2. Let keys be placements.[[PrototypeKeys]].
  5. If element.[[Key]] is an element of keys, then
    1. If silent is not present or is false, throw a TypeError exception.
  6. Otherwise, append element.[[Key]] to keys.

5.8RemoveElementPlacement (element, placements)

  1. If element does not have a [[Key]] field, return.
  2. If element.[[Placement]] is "own", then
    1. Let keys be placements.[[OwnKeys]].
  3. Else if element.[[Placement]] is "static", then
    1. Let keys be placements.[[StaticKeys]].
  4. Else,
    1. Assert: element.[[Placement]] is "prototype".
    2. Let keys be placements.[[PrototypeKeys]].
  5. Assert: element.[[Key]] is an element of keys.
  6. Remove element.[[Key]] from keys.

5.9FromElementDescriptors ( elements )

  1. Assert: elements is a List of ElementDescriptor Records.
  2. Let elementObjects be a new empty List.
  3. For each element in elements, do
    1. Append ! FromElementDescriptor(element) to elementObjects.
  4. Return ! CreateArrayFromList(elementObjects).

5.10FromElementDescriptor ( element )

  1. Assert: element is an ElementDescriptor Record.
  2. Let obj be ! ObjectCreate(%ObjectPrototype%).
  3. Let desc be PropertyDescriptor{ [[Value]]: "Descriptor", [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
  4. Perform ! DefinePropertyOrThrow(obj, @@toStringTag, desc).
  5. Perform ! CreateDataPropertyOrThrow(obj, "kind", element.[[Kind]]).
  6. If element has a [[Descriptor]] field,
    1. If element.[[Descriptor]] has a [[Value]] field, then
      1. Perform ! CreateDataProperty(obj, "method", element.[[Descriptor]].[[Value]]).
    2. If element.[[Descriptor]] has a [[Writable]] field, then
      1. Perform ! CreateDataProperty(obj, "writable", element.[[Descriptor]].[[Writable]]).
    3. If element.[[Descriptor]] has a [[Get]] field, then
      1. Perform ! CreateDataProperty(obj, "get", element.[[Descriptor]].[[Get]]).
    4. If element.[[Descriptor]] has a [[Set]] field, then
      1. Perform ! CreateDataProperty(obj, "set", element.[[Descriptor]].[[Set]]).
    5. If element.[[Descriptor]] has an [[Enumerable]] field, then
      1. Perform ! CreateDataProperty(obj, "enumerable", element.[[Descriptor]].[[Enumerable]]).
    6. If element.[[Descriptor]] has a [[Configurable]] field, then
      1. Perform ! CreateDataProperty(obj, "configurable", element.[[Descriptor]].[[Configurable]]).
  7. If element.[[Kind]] is "method", "accessor", or "field",
    1. Let key be element.[[Key]].
    2. If key is a Private Name, set key to ? PrivateNameObject(key).
    3. Perform ! CreateDataPropertyOrThrow(obj, "key", key).
  1. Perform ! CreateDataPropertyOrThrow(obj, "placement", element.[[Placement]]).
  2. If element.[[Kind]] is "field",
    1. Let initialize be element.[[Initializer]].
    2. If initialize is empty, set initialize to undefined.
    3. Perform ! CreateDataPropertyOrThrow(obj, "initialize", initialize).
  3. If element.[[Kind]] is "hook",
    1. Let start be element.[[Start]].
    2. Assert: start is not empty.
    3. Perform ! CreateDataPropertyOrThrow(obj, "start", start).
  4. Return obj.

5.11ToElementDescriptors ( elementObjects )

  1. Assert: elementObject is an ECMAScript language value.
  2. If elementObjects is undefined, return undefined.
  3. Let elements be a new empty List.
  4. Let iteratorRecord be ? GetIterator(elementObjects).
  5. Repeat,
    1. Let next be ? IteratorStep(iteratorRecord).
    2. If next is false, return elements.
    3. Let elementsObject be ? ToObject(? IteratorValue(next)).
    4. Let element be ? ToElementDescriptor(elementObject).
    5. Let extras be ? Get(elementObject, "extras").
    6. If extras is not undefined, throw a TypeError exception.
    7. Append element to elements.
  6. If the above steps contained an abrupt completion status outside of IteratorStep, return ? IteratorClose(iteratorRecord, status).

5.12ToDecoratorPropertyDescriptor ( elementObject )

  1. Let desc be a new Property Descriptor that initially has no fields.
  2. Let hasEnumerable be ? HasProperty(Obj, "enumerable").
  3. If hasEnumerable is true, then
    1. Let enumerable be ToBoolean(? Get(Obj, "enumerable")).
    2. Set desc.[[Enumerable]] to enumerable.
  4. Let hasConfigurable be ? HasProperty(Obj, "configurable").
  5. If hasConfigurable is true, then
    1. Let configurable be ToBoolean(? Get(Obj, "configurable")).
    2. Set desc.[[Configurable]] to configurable.
  6. Let hasValue be ? HasProperty(Obj, "method").
  7. If hasValue is true, then
    1. Let value be ? Get(Obj, "method").
    2. If IsCallable(value) is false, throw a TypeError exception.
    3. Set desc.[[Value]] to value.
  8. Let hasWritable be ? HasProperty(Obj, "writable").
  9. If hasWritable is true, then
    1. Let writable be ToBoolean(? Get(Obj, "writable")).
    2. Set desc.[[Writable]] to writable.
  10. Let hasGet be ? HasProperty(Obj, "get").
  11. If hasGet is true, then
    1. Let getter be ? Get(Obj, "get").
    2. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception.
    3. Set desc.[[Get]] to getter.
  12. Let hasSet be ? HasProperty(Obj, "set").
  13. If hasSet is true, then
    1. Let setter be ? Get(Obj, "set").
    2. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception.
    3. Set desc.[[Set]] to setter.
  14. If desc.[[Get]] is present or desc.[[Set]] is present, then
    1. If desc.[[Value]] is present or desc.[[Writable]] is present, throw a TypeError exception.
  15. Return CompletePropertyDescriptor(desc).

5.13ToElementDescriptor ( elementObject )

With parameter elementObject, returns an ElementDescriptor.

  1. Assert: Type(elementObject) is Object.
  2. Let kind be ? ToString(? Get(elementObject, "kind")).
  3. If kind is not one of "hook", "method", "accessor", or "field", throw a TypeError exception.
  4. Let key be ? Get(elementObject, "key").
  5. If kind is "hook",
    1. If key is not undefined, throw a TypeError exception.
  6. If key has a [[PrivateNameData]] internal slot, set key to key.[[PrivateNameData]].
  7. Otherwise, set key to ? ToPropertyKey(key).
  8. Let placement be ? ToString(? Get(elementObject, "placement")).
  9. If placement is not one of "static", "prototype", or "own", throw a TypeError exception.
  10. Let descriptor be ? ToDecoratorPropertyDescriptor(elementObject)
  11. If key is a Private Name,
    1. If descriptor has an [[Enumerable]] field and descriptor.[[Enumerable]] is true, throw a TypeError exception.
    2. If descriptor has an [[Configurable]] field and descriptor.[[Configurable]] is true, throw a TypeError exception.
    3. If placement is "prototype", throw a TypeError exception.
  12. If kind is "accessor" or "hook" and IsDataDescriptor(descriptor) is true, throw a TypeError exception.
  13. If kind is "field", "method" or "hook", and IsAccessorDescriptor(descriptor) is true, throw a TypeError exception.
  14. If kind is "field" and descriptor has a [[Value]] field, throw a TypeError exception.
  15. Let initialize be ? Get(elementObject, "initialize").
  16. If initialize is not undefined and IsCallable(initialize) is false, throw a TypeError.
  17. If kind is not "field",
    1. If initializer is not undefined, throw a TypeError exception.
  18. Let start be ? Get(elementObject, "start").
  19. If start is not undefined and IsCallable(start) is false, throw a TypeError.
  20. If kind is not "hook",
    1. If start is not undefined, throw a TypeError exception.
  21. Let replace be ? Get(elementObject, "replace").
  22. If replace is not undefined and IsCallable(replace) is false, throw a TypeError.
  23. If kind is not "hook",
    1. If replace is not undefined, throw a TypeError exception.
  24. Let finish be ? Get(elementObject, "finish").
  25. If finish is not undefined and IsCallable(finish) is false, throw a TypeError.
  26. If kind is not "hook",
    1. If finish is not undefined, throw a TypeError exception.
  27. If kind is "hook",
    1. If start, replace and finish are all undefined, throw a TypeError exception.
    2. If neither replace nor finish are undefined, throw a TypeError exception.
  28. Let elements be ? Get(elementObject, "elements").
  29. If elements is not undefined, throw a TypeError exception.
  30. Let element be the ElementDescriptor { [[Kind]]: kind, [[Placement]]: placement }.
  31. If kind is "method", "accessor", or `"field",
    1. Set element.[[Key]] to key.
    2. Set element.[[Descriptor]] to descriptor.
  32. If kind is "field",
    1. Set element.[[Initializer]] to initialize.
  33. If kind is "hook",
    1. If start is not undefined, set element.[[Start]] to start.
    2. If replace is not undefined, set element.[[Replace]] to replace.
    3. If finish is not undefined, set element.[[Finish]] to replace.
  34. Return element.

5.14ToElementExtras ( elementObject )

With parameter elementObject, returns a Record containing three values: { [[Element]]: ElementDescriptor, [[Extras]]: an iterable of other Element Descriptors }.

  1. Assert: Type(elementObject) is Object.
  2. Let element be ? ToElementDescriptor(elementObject).
  3. Let extrasObject be ? Get(elementObject, "extras").
  4. Let extras be ? ToElementDescriptors(extrasObject).
  5. Return the Record { [[Element]]: element, [[Extras]]: extras }.

5.15FromClassDescriptor ( elements )

  1. Assert: elements is a List of ElementDescriptor Records.
  2. Let elementsObjects be FromElementDescriptors(elements).
  3. Let obj be ! ObjectCreate(%ObjectPrototype%).
  4. Let desc be PropertyDescriptor{ [[Value]]: "Descriptor", [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
  5. Perform ! DefinePropertyOrThrow(obj, @@toStringTag, desc).
  6. Perform ! CreateDataPropertyOrThrow(obj, "kind", "class").
  7. Perform ! CreateDataPropertyOrThrow(obj, "elements", elementsObjects).
  8. Return obj.

5.16ToClassDescriptor ( classDescriptor )

  1. Let kind be ? ToString(? Get(classDescriptor, "kind").
  2. If kind is not "class", throw a TypeError exception.
  3. Let key be ? Get(classDescriptor, "key").
  4. If key is not undefined, throw a TypeError exception.
  5. Let placement be ? Get(classDescriptor, "placement").
  6. If placement is not undefined, throw a TypeError exception.
  7. Let descriptor be ? ToPropertyDescriptor(classDescriptor).
  8. If descriptor has any fields, throw a TypeError exception.
  9. Let initialize be ? Get(classDescriptor, "initialize").
  10. If initialize is not undefined, throw a TypeError exception.
  11. Let start be ? Get(classDescriptor, "start").
  12. If start is not undefined, throw a TypeError exception.
  13. Let extras be ? Get(classDescriptor, "extras").
  14. If extras is not undefined, throw a TypeError exception.
  15. Let elementsObject be ? ToObject(? Get(classDescriptor, "elements")).
  16. Return ? ToElementDescriptors(elementsObject).

6Strict Mode Code

An ECMAScript Script syntactic unit may be processed using either unrestricted or strict mode syntax and semantics. Code is interpreted as strict mode code in the following situations:

ECMAScript code that is not strict mode code is called non-strict code.

7Non-ECMAScript Functions

An ECMAScript implementation may support the evaluation of function exotic objects whose evaluative behaviour is expressed in some implementation-defined form of executable code other than via ECMAScript code. Whether a function object is an ECMAScript code function or a non-ECMAScript function is not semantically observable from the perspective of an ECMAScript code function that calls or is called by such a non-ECMAScript function.

ACopyright & Software License

Copyright Notice

© 2019 Daniel Ehrenberg, Jeff Morrison, Kevin Smith, Kevin Gibbons, Yehuda Katz, Brian Terlson

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.