├── .editorconfig ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── README.md ├── decorators.html ├── figure-2.uxf ├── img ├── favicon.ico ├── figure-1.png ├── figure-1.svg └── figure-2.png ├── package.json ├── scripts ├── auto-deploy.sh └── github_deploy_key.enc ├── spec.html └── workingdocs ├── ES6-super-construct=proposal.md ├── callconstructor.md └── decorators.html /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | out/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | after_success: 2 | - ./scripts/auto-deploy.sh 3 | 4 | env: 5 | global: 6 | - secure: "UCSm2OZkCtH8EPSPjp8fujOyQrtHtPJi8DDdOyCSkUunSw9H+HiONwuh+J1Of77B9OUC1HTWE51tW75nsnaQik4GihXB+eah7ow3RLM14LoLoUz+PA84W8sDuuCbm37Kqtf4vnWKlAUhDeUZNyhGyIezdB22UaqWWir9KGdp4AE=" 7 | 8 | language: node_js 9 | 10 | node_js: 11 | - "5" 12 | 13 | sudo: false 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Contributing to ECMAScript 2 | There are a number of ways to contribute to ECMAScript. How to actually contribute depends on what you want to accomplish. In many cases, you may be required to execute a CLA with Ecma. See the final section named *Signing the CLA* for more information on this. 3 | 4 | Ecma TC39 accepts contributions from non-member individuals who have accepted the TC39 copyright and patent policies. Currently all ECMAScript related technical work is done by the TC39 RF TG (Royalty Free Task Group), for which the following IPR Policies apply: 5 | 6 | * [Ecma International RF Patent Policy](http://www.ecma-international.org/memento/Policies/Ecma_Royalty-Free_Patent_Policy_Extension_Option.htm) 7 | * [Ecma International Software Copyright Policy](http://www.ecma-international.org/memento/Policies/Ecma_Policy_on_Submission_Inclusion_and_Licensing_of_Software.htm) ([PDF](http://www.ecma-international.org/memento/Policies/Ecma_Policy_on_Submission_Inclusion_and_Licensing_of_Software.pdf)) 8 | 9 | #### Bug Reports & Bug Fixes 10 | File a bug or pull requests against the current text of ECMA262 in this repository. If the fix is trivial you may not need to sign the CLA. If your fix is involved, signing the CLA will be required. 11 | 12 | #### Feature Requests 13 | Feature requests for future versions of ECMAScript should not be made in this repository. To make a feature request, post to the [es-discuss mailing list](http://esdiscuss.org). Your goal will be to convince others that your proposal is a useful addition to the language and recruit TC39 members to help turn your request into a proposal and shepherd it into the language. 14 | 15 | #### Proposals 16 | If you have a new proposal you want to get into the language, you first need a TC39 champion. Head to [es-discuss](http://esdiscuss.org) to find one. If you already have a TC39 champion, send a pull request to add a link to your proposal to the Current Proposals list or the stage zero list. 17 | 18 | ### Signing the CLA 19 | If you wish to submit a proposal and are not a representative of a TC39 member, here are the steps you need to take: 20 | 21 | 1. Read the [TC39 process document](https://tc39.github.io/process-document/). 22 | 2. [Register as a TC39 contributor](http://www.ecma-international.org/memento/register_TC39_Royalty_Free_Task_Group.php) (it is not necessary to submit the contribution as attachment to the form) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Class and Property Decorators 2 | ==== 3 | 4 | This proposal is currently on Stage 2 5 | 6 | Champions: [Yehuda Katz](https://twitter.com/wycats) and [Brian Terlson](https://twitter.com/bterlson) 7 | 8 | This version of the proposal is subsumed by https://github.com/tc39/proposal-decorators 9 | -------------------------------------------------------------------------------- /decorators.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | title: Decorators 6 | stage: 2 7 | contributors: Yehuda Katz, Brian Terlson, Ecma International 8 |9 | 79 | 80 |
Decorators offer a convenient declarative syntax to modify the shape of class declarations. This capability can be used for myriad purposes including modifying the descriptor of the declared member (@nonconfigurable/@enumerable), adding metadata (as used by Angular), and more.
83 | 84 |As of this proposal, decorators can be attached to either classes or class members. An example of such a class might be:
88 | 89 |
91 | @frozen class Foo {
92 | @configurable(false) @enumerable(true) method() {}
93 | }
94 |
95 | Prior to the `class` keyword and prior to method definitions are a new |DecoratorList| production - essentially, a list of |Decorator| productions. The |Decorator| production is `@` followed by a sequence of dotted identifiers (no `[]` access is allowed due to grammar difficulties) and an argument list. Thus, `@foo.bar()` is valid, while `@foo().bar()` (and `@foo[bar]`) are syntax errors.
98 |The syntax here can be pretty much anything, but this proposal takes a maximally conservative approach. Square brackets can be made unambiguous with a clever cover grammar but the syntax is confusing and error-prone.
100 |Elements of the |DecoratorList| are evaluated in-order but their resulting decorator functions are evaluated in a bottom-up fashion. The value returned by a decorator becomes the input of the next decorator.
102 |There are a number of examples of real-world usage based on previous drafts of this proposal.
107 | 108 |The `core-decorators` library includes a number of standalone decorators that are intended to 110 | work in vanilla JavaScript code.
111 |An @deprecate decorator:
112 |
113 | import { deprecate } from 'core-decorators';
114 |
115 | class Person {
116 | @deprecate
117 | facepalm() {}
118 |
119 | @deprecate('We stopped facepalming')
120 | facepalmHard() {}
121 |
122 | @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' })
123 | facepalmHarder() {}
124 | }
125 |
126 | let person = new Person();
127 |
128 | person.facepalm();
129 | // DEPRECATION Person#facepalm: This function will be removed in future versions.
130 |
131 | person.facepalmHard();
132 | // DEPRECATION Person#facepalmHard: We stopped facepalming
133 |
134 | person.facepalmHarder();
135 | // DEPRECATION Person#facepalmHarder: We stopped facepalming
136 | //
137 | // See http://knowyourmeme.com/memes/facepalm for more details.
138 | //
139 |
140 | A throttling decorator:
141 |
142 | import { throttle } from 'core-decorators';
143 |
144 | class Editor {
145 |
146 | content = '';
147 |
148 | @throttle(500, { leading: false })
149 | updateContent(content) {
150 | this.content = content;
151 | }
152 | }
153 |
154 |
155 | A mixin class decorator:
156 | 157 |
158 | import { mixin } from 'core-decorators';
159 |
160 | const SingerMixin = {
161 | sing(sound) {
162 | alert(sound);
163 | }
164 | };
165 |
166 | const FlyMixin = {
167 | // All types of property descriptors are supported
168 | get speed() {},
169 | fly() {},
170 | land() {}
171 | };
172 |
173 | @mixin(SingerMixin, FlyMixin)
174 | class Bird {
175 | singMatingCall() {
176 | this.sing('tweet tweet');
177 | }
178 | }
179 |
180 | var bird = new Bird();
181 | bird.singMatingCall();
182 | // alerts "tweet tweet"
183 |
184 |
185 | A decorator using `console.time` to time a function:
186 | 187 |
188 | class Bird {
189 | @time('sing')
190 | sing() {
191 | }
192 | }
193 |
194 | var bird = new Bird();
195 | bird.sing(); // console.time label will be 'sing-0'
196 | bird.sing(); // console.time label will be 'sing-1'
197 |
198 | Several frameworks have also adopted decorators in various forms.
204 | 205 |
208 | var x = 1;
209 |
210 | import { computedFrom } from 'aurelia-framework';
211 |
212 | export class Welcome{
213 | firstName = 'John';
214 | lastName = 'Doe';
215 |
216 | @computedFrom('firstName', 'lastName')
217 | get fullName(){
218 | return `${this.firstName} ${this.lastName}`;
219 | }
220 | }
221 |
222 |
228 | import { customElement, useShadowDOM, bindable } from 'aurelia-framework';
229 |
230 | @customElement('nav-bar')
231 | export class NavBar {}
232 |
233 | @useShadowDOM
234 | @customElement('my-expander')
235 | export class Expander {
236 | @bindable isExpanded = false;
237 | @bindable header;
238 | }
239 |
240 |
245 | import Ember from 'ember';
246 | import computed from 'ember-computed-decorators';
247 |
248 | export default class extends Ember.Component {
249 | @computed('first', 'last')
250 | name(first, last) {
251 | return `${first} ${last}`;
252 | }
253 | };
254 |
255 |
260 | import Ember from 'ember';
261 | import computed, { readOnly } from 'ember-computed-decorators';
262 |
263 | export default class extends Ember.Component {
264 | @readOnly
265 | @computed('first', 'last')
266 | name(first, last) {
267 | return `${first} ${last}`;
268 | }
269 | };
270 |
271 |
276 | import DS from 'ember-data';
277 | import {
278 | attr,
279 | hasMany
280 | } from "ember-computed-decorators/ember-data";
281 |
282 | export default class extends DS.Model {
283 | @attr firstName,
284 | @hasMany users
285 | };
286 |
287 |
292 | import Ember from 'ember';
293 | import { alias } from 'ember-computed-decorators';
294 | export default class extends Ember.Component {
295 | person: {
296 | first: 'Joe'
297 | }
298 |
299 | @alias('person.first') firstName
300 | };
301 |
302 |
307 | import Ember from 'ember';
308 | import { intersect } from 'ember-computed-decorators';
309 |
310 | export default class extends Ember.Component {
311 | likes = [ 'tacos', 'puppies', 'pizza' ];
312 | foods = [ 'tacos', 'pizza' ];
313 |
314 | @intersect('likes', 'foods') favoriteFoods; // ['tacos', 'pizza']
315 | };
316 |
317 |
322 | @Component({
323 | selector: 'talk-cmp',
324 | directives: [FormattedRating, WatchButton, RateButton],
325 | templateUrl: 'talk_cmp.html'
326 | })
327 | class TalkCmp {
328 | @Input() talk: Talk;
329 | @Output() rate: EventEmitter;
330 | // ...
331 | }
332 |
333 | A decorator function is a function that takes and returns either a member 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.
399 |A member descriptor describes a member of a class or object literal and has the following shape:
402 |
403 | interface MemberDesciptor {
404 | kind: "property"
405 | key: string,
406 | isStatic: boolean,
407 | descriptor: PropertyDescriptor,
408 | extras?: MemberDescriptor[]
409 | finisher?: (klass): void;
410 | }
411 |
412 | A class descriptor describes a class and has the following shape:
416 |
417 | interface ClassDesciptor {
418 | kind: "class",
419 | constructor: Function,
420 | heritage: Object | null,
421 | elements: MemberDescriptor[]
422 | }
423 |
424 | With parameters _object_ and optional parameter _functionPrototype_.
With parameter _className_.
450 |constructor(... args){ super (...args);}
480 | using the syntactic grammar with the goal symbol |MethodDefinition[~Yield]|.
481 | 1. Else,
482 | 1. Let _constructor_ be the result of parsing the source text
483 | constructor( ){ }
484 | using the syntactic grammar with the goal symbol |MethodDefinition[~Yield]|.
485 | 1. Set the running execution context's LexicalEnvironment to _classScope_.
486 | 1. We need to make a decision about what validations we need on the _extras_ list, and when to apply it.
555 |At minimum, if one decorator marks a property as non-configurable, another decorator will not be allowed to modify it.
556 |There are several options:
557 |We would prefer to avoid the first option, because it is useful for users of decorators to know if they have caused a name conflict.
563 |Note: The second and third option are observably different in terms of timing.
564 |In terms of validations, we would prefer to disallow naming conflicts caused by extras, which would otherwise become confusing silent errors.
565 |We would also prefer to disallow, as a validation rule, a property made non-configurable by one decorator to be modified by a future one 566 | (rather than causing it to fail at application time).
567 |It seems important to allow decorators on a single element to be reordered flexibly, so that for example a @nonconfigurable
decorator could be applied before or after an @enumerable
decorator. On the other hand, decorators on separate elements that end up affecting class properties of the same name are almost always going to be bugs (analogous to name collisions arising from unhygienic macros). For both of these reasons, it seems important for a single element's decorators to be combined permissively, whereas the extras produced by distinct elements should be validated not to have conflicts.
With parameters _object_ and _enumerable_.
574 |With parameter _function_.
670 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.
672 |With parameter _function_.
678 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.
680 |With parameter _function_.
686 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.
688 |With parameter _elements_.
694 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.
703 |With parameter _element_.
708 |Future versions of the spec will create element descriptors with other [[Kind]]s.
735 |There is a decision-point about what validation rules should be applied to the merging that happens right before merging.
738 |With parameters _decorators_, _constructor_, _heritage_ and _elementDescriptors_.
743 |There is a decision-point about what validation rules should be applied to the merging.
766 |We also need to decide whether to produce an error if the returned constructor from a decorator has the wrong prototype. We think it 767 | should be an error.
768 |With parameter _element_.
774 |With parameter _descriptor_.
789 |Todo: Should probably add validations for having kind, static, and key fields.
802 |
80 | 2. If F's [[FunctionKind]] internal slot is "classConstructor"
, then
81 | a. If F's [[ConstructorCall]] internal slot is empty, throw a TypeError exception.
82 | b. Let callF be the value of F's [[ConstructorCall]] internal slot.
83 | 2.1 Else, let callF be F.
84 |
85 |
86 | Step 7 is replaced with:
87 |
88 | 89 | 7. Let result be OrdinaryCallEvaluateBody(callF, argumentsList). 90 |91 | 92 | Update the step reference in the NOTE. 93 | 94 | ### [9.2.9 MakeClassConstructor](http://ecma-international.org/ecma-262/6.0/#sec-makeclassconstructor) 95 | Between the existing steps 3 and 4 insert the following steps: 96 | 97 |
98 | 3.1 Set F's [[CallConstructor]] internal slot to empty. 99 |100 | 101 | 102 | ### [14.5 Class Definition Syntax](http://ecma-international.org/ecma-262/6.0/#sec-class-definitions) 103 | 104 | The definition for the production *ClassElement*[Yield] is replaced with: 105 | 106 |
107 | ClassElement[Yield] : 108 | MethodElement[?Yield] 109 |116 | 117 | ### [14.5.1 Early Errors](http://ecma-international.org/ecma-262/6.0/#sec-class-definitions-static-semantics-early-errors) 118 | 119 | Add the rules: 120 | 121 | 122 | ClassElementList : ClassElementList ClassElement 123 | 124 | * It is a Syntax Error if ClassElement is CallConstructor and ClassElementList Contains CallConstructor. 125 | 126 | CallConstructor :static
MethodElement[?Yield] 110 | CallConstructor 111 |;
112 | 113 | CallConstructor : 114 |call constructor (
StrictFormalParameters) {
FunctionBody}
115 |
call constructor (
StrictFormalParameters ) {
FunctionBody}
127 |
128 | * It is a Syntax Error if any element of the BoundNames of StrictFormalParameters also occurs in the LexicallyDeclaredNames of FunctionBody.
129 | * It is a Syntax Error if StrictFormalParameters Contains SuperCall.
130 | * It is a Syntax Error if FunctionBody Contains SuperCall.
131 |
132 |
133 | ### Add 14.5.x StaticSemantics: CallConstructorDefinition
134 |
135 | 136 | ClassElementList : ClassElement 137 | 1. If ClassElement is not CallConstructor , return empty. 138 | 2. Return ClassElement. 139 | 140 | ClassElementList : ClassElementList ClassElement 141 | 142 | 1. If ClassElement is CallConstructor , return ClassElement. 143 | 2. Return CallConstructorDefinition of ClassElementList. 144 |145 | 146 | ### [14.5.5 Static Semantics: ComputedPropertyContains](http://ecma-international.org/ecma-262/6.0/#sec-class-definitions-static-semantics-computedpropertycontains) 147 | 148 | Add the rule: 149 | 150 |
151 | ClassElement : CallConstructor 152 | 153 | 1. Return false. 154 |155 | 156 | ### [14.5.9 Static Semantics: IsStatic](http://ecma-international.org/ecma-262/6.0/#sec-static-semantics-isstatic) 157 | 158 | Add the rule: 159 | 160 |
161 | ClassElement : CallConstructor 162 | 163 | 1. Return false. 164 |165 | ### [14.5.10 Static Semantics: NonConstructorMethodDefinition](http://ecma-international.org/ecma-262/6.0/#sec-static-semantics-nonconstructormethoddefinitions) 166 | 167 | In the algorithm for the rule ClassElementList : ClassElement add the following new step between the existing steps 1 and 2: 168 |
169 | 1.1 If ClassElement is the production ClassElement : CallConstructor , return a new empty List. 170 |171 | 172 | In the algorithm for the rule ClassElementList : ClassElementList ClassElement add the following new step between the existing steps 2 and 3: 173 |
174 | 2.1 If ClassElement is the production ClassElement : CallConstructor , return list. 175 |176 | 177 | ### [14.5.12 Static Semantics: PropName](http://ecma-international.org/ecma-262/6.0/#sec-class-definitions-static-semantics-propname) 178 | 179 | Add the rule: 180 | 181 |
182 | ClassElement : CallConstructor 183 | 184 | 1. Return empty. 185 |186 | ### [14.5.14 Static Semantics: ClassDefinitionEvaluation](http://ecma-international.org/ecma-262/6.0/#sec-runtime-semantics-classdefinitionevaluation) 187 | Replace the existing steps 8 and 9 with: 188 | 189 |
190 | 8. If ClassBodyopt is not present, then 191 | a. Let constructor be empty. 192 | b. Let callConstructor be empty. 193 | 9. Else, 194 | a. Let constructor be ConstructorMethod of ClassBody. 195 | b. Let callConstructor be CallConstructorDefinition of ClassBody. 196 |197 | Between the existing steps 18 and 19 insert the following steps: 198 | 199 |
200 | 18.1 If callConstructor is not empty, then
201 | a. Let callF be FunctionCreate(Normal
, StrictFormalParameters, FunctionBody, classScope, true, functionPrototype).
202 | b. Set F's [[CallConstructor]] internal slot to callF.
203 |
204 |
205 | The following informative NOTE is added:
206 |
207 | NOTE The function object created as the value of callF is not observable to ECMAScript code. MakeMethod is not applied to that function object, because the F's [[HomeObject]] binding is used when invoking the [[CallConstructor]].
208 |
209 | ### Remarks
210 | The presence of a `call constructor` in a class body installs the call constructor function in the `[[CallConstructor]]` slot of the constructed class. The [[Call]] internal method of a class constructor invokes the [[CallConstructor]] function.
211 |
212 | The function object value of [[CallConstructor]] is not intended to be ovservable by ECMAScript code. If any features are added to ECMAScript that exposes the "current function" that such features should expose the constructor object and not the [[CallConstructor]] object.
213 |
214 | The presence of a `call constructor` in a superclass does not affect subclasses. This means that subclasses still have a throwing `[[Call]]`, unless they explicitly define their own `call constructor` (subclasses do not inherit calling behavior by default).
215 |
216 | As in methods, `super()` in a `call constructor` is a static error, future-proofing us for a potential context-sensitive `super()` proposal.
217 |
218 | ## Appendix: Date Utilities
219 |
220 | ```js
221 | import { clockGetTime } from "system/time";
222 | import Type, { OBJECT, STRING } from "language/type";
223 |
224 | // the spec makes these things implementation-defined
225 | import { parseDate } from "host";
226 |
227 | // see the next appendix
228 | import { InternalSlots } from "self-hosted";
229 |
230 | // define the private slot for Date, which contains a single field for the value in milliseconds
231 | export class DateValue {
232 | constructor(timeValue: number) {
233 | this.timeValue = timeValue;
234 | }
235 | }
236 |
237 | const PRIVATE_DATE_FIELDS = new InternalSlots(DateValue);
238 |
239 | export function privateDateState(date) {
240 | return PRIVATE_DATE_FIELDS.get(date);
241 | }
242 |
243 | export function initializeDate(date, ...args) {
244 | switch (args.length) {
245 | case 0:
246 | return initializeDateZeroArgs(date, clockGetTime());
247 | case 1:
248 | return initializeDateOneArg(date, args[0]);
249 | default:
250 | return initializeDateManyArgs(date, args);
251 | }
252 | }
253 |
254 | function initializeDateZeroArgs(date) {
255 | PRIVATE_DATE_FIELDS.initialize(date, clockGetTime());
256 | }
257 |
258 | function initializeDateOneArg(date, value) {
259 | let timeValue = do {
260 | if (Type(value) === OBJECT && DATE_SLOTS.has(value)) {
261 | DATE_SLOTS.get(value).timeValue;
262 | } else {
263 | let v = ToPrimitive(value);
264 | Type(v) === STRING ? parseDate(v) : ToNumber(v);
265 | }
266 | }
267 |
268 | DATE_SLOT.initialize(date, TimeClip(timeValue));
269 | }
270 |
271 | function initializeDateManyArgs(date, args) {
272 | // TODO
273 | }
274 |
275 | // re-export implementation-defined ToDateString
276 | export { ToDateString } from "host";
277 | ```
278 |
279 | ## Appendix: Self Hosting Utilities
280 |
281 | ```js
282 | class InternalSlots {
283 | constructor(SlotClass) {
284 | this._weakMap = new WeakMap();
285 | this._SlotClass = SlotClass;
286 | }
287 |
288 | initialize(obj, ...args) {
289 | let { _weakMap, _SlotClass } = this;
290 | _weakMap.set(obj, new _SlotClass(...args));
291 | }
292 |
293 | has(obj) {
294 | return this._weakMap.has(obj);
295 | }
296 |
297 | get(obj) {
298 | return this._weakMap.get(obj);
299 | }
300 | }
301 | ```
302 |
--------------------------------------------------------------------------------
/workingdocs/decorators.html:
--------------------------------------------------------------------------------
1 |
2 | With optional parameter _functionPrototype_.
5 |With parameters _object_ and _enumerable_.
22 |See
With parameter _element_.
109 |Future versions of the spec will create element descriptors with other [[Kind]]s.
131 |There is a decision-point about what validation rules should be applied to the merging that happens right before merging.
134 |With parameters _decorators_, _constructor_, _heritage_ and _elementDescriptors_.
140 |There is a decision-point about what validation rules should be applied to the merging.
160 |We also need to decide whether to produce an error if the returned constructor from a decorator has the wrong prototype. We think it 161 | should be an error.
162 |With parameter _element_.
168 |With parameter _descriptor_.
182 |A class definition is always strict mode code.
224 |It is a Syntax Error if |ClassHeritage| is not present and the following algorithm evaluates to *true*:
233 |Early Error rules ensure that there is only one method definition named `"constructor"` and that it is not an accessor property or generator definition.
301 |With parameter _symbol_.
308 |Static semantic rules that depend upon substructure generally do not look into class bodies except for |PropertyName| productions.
320 |With parameter _symbol_.
327 |With parameter _className_.
455 |constructor(... args){ super (...args);}
485 | using the syntactic grammar with the goal symbol |MethodDefinition|.
486 | 1. Else,
487 | 1. Let _constructor_ be the result of parsing the source text
488 | constructor( ){ }
489 | using the syntactic grammar with the goal symbol |MethodDefinition|.
490 | 1. Set the running execution context's LexicalEnvironment to _classScope_.
491 | 1. If |ClassBody?| is not present, let _methods_ be a new empty List.
492 | 1. Else, let _methods_ be NonConstructorMethodDefinitions of |ClassBody|.
493 | 1. Let _elements_ be a new empty List.
494 | 1. For each |ClassElement| _m_ in order from _methods_
495 | 1. Let _static_ be IsStatic of _m_.
496 | 1. Let _el_ be the result of performing PropertyDefinitionEvaluation for _m_.
497 | 1. If _el_ is an abrupt completion, then
498 | 1. Set the running execution context's LexicalEnvironment to _lex_.
499 | 1. Return Completion(_el_).
500 | 1. Else, let _descriptor_ be _descriptor_.[[value]].
501 | 1. Let _element_ be the Record{[[Kind]]: `"property"`, [[Static]]: _static_, [[Key]]: _descriptor_.[[Key]], [[Descriptor]]: _descriptor_.[[Descriptor]], [[Decorators]]: _el_.[[Decorators]]}.
502 | 1. Append _element_ to the end of _elements_.
503 | 1. Let _coalesced_ be the new List created by combining getters and setters with the same [[Key]]. If both a getter and setter with the same [[Key]] have a non-empty [[Decorators]], throw a new Error.
504 | 1. Let _elementDescriptors_ be a new empty List.
505 | 1. For each _element_ in order from _coalesced_
506 | 1. Let _decorated_ be ? DecorateElement(_element_).
507 | 1. Append _decorated_.[[Descriptor]] to the end of _elementDescriptors_.
508 | 1. For each _descriptor_ in order from _decorated_.[[Extras]].
509 | 1. Append _descriptor_ to the end of _elementDescriptors_.
510 | 1. Let _constructorInfo_ be the result of performing DefineMethod for _constructor_ with _constructorParent_ as the optional _functionPrototype_ argument.
511 | 1. Assert: _constructorInfo_ is not an abrupt completion.
512 | 1. Let _originalF_ be _constructorInfo_.[[Closure]].
513 | 1. Let _F_ be MakeUninitializedConstructor(_originalF_).
514 | 1. Let _result_ be ? DecorateClass(_F_, _constructorParent_, _elementDescriptors_).
515 | 1. Let _constructor_ be _result_.[[Constructor]].
516 | 1. Let _elements_ be _result_.[[Elements]].
517 | 1. If |ClassHeritage?| is present and _protoParent_ is not *null*, then set _constructor_'s [[ConstructorKind]] internal slot to `"derived"`.
518 | 1. Perform MakeConstructor(_constructor_, *false*, _proto_).
519 | 1. Perform MakeClassConstructor(_constructor_).
520 | 1. Perform CreateMethodProperty(_proto_, `"constructor"`, _constructor_).
521 | 1. For each _descriptor_ in order from _elements_
522 | 1. Assert: _descriptor_.[[Kind]] is `"property"`
523 | 1. If _descriptor_.[[Static]] is *false*, then
524 | 1. Let _status_ be DefinePropertyOrThrow(_proto_, _descriptor_.[[Key]], _descriptor_.[[Descriptor]])
525 | 1. Else,
526 | 1. Let _status_ be DefinePropertyOrThrow(_constructor_, _descriptor_.[[Key]], _descriptor_.[[Descriptor]])
527 | 1. If _status_ is an abrupt completion, then
528 | 1. Set the running execution context's LexicalEnvironment to _lex_.
529 | 1. Return Completion(_status_).
530 | 1. Perform MakeFunctionInitialized(_constructor_).
531 | 1. Perform MakeClassElementsInitialized(_elementDescriptors_).
532 | 1. Set the running execution context's LexicalEnvironment to _lex_.
533 | 1. If _className_ is not *undefined*, then
534 | 1. Perform _classScopeEnvRec_.InitializeBinding(_className_, _constructor_).
535 | 1. Let _finisher_ be GetFinisherFromDescriptors(_elementDescriptors_).
536 | 1. Call ? _finisher_(_constructor_).
537 | 1. Return _constructor_.
538 | We need to make a decision about what validations we need on the _extras_ list, and when to apply it.
541 |At minimum, if one decorator marks a property as non-configurable, another decorator will not be allowed to modify it.
542 |There are several options:
543 |We would prefer to avoid the first option, because it is useful for users of decorators to know if they have caused a name conflict.
549 |Note: The second and third option are observably different in terms of timing.
550 |In terms of validations, we would prefer to disallow naming conflicts caused by extras, which would otherwise become confusing silent errors.
551 |We would also prefer to disallow, as a validation rule, a property made non-configurable by one decorator to be modified by a future one 552 | (rather than causing it to fail at application time).
553 |It seems important to allow decorators on a single element to be reordered flexibly, so that for example a @nonconfigurable
decorator could be applied before or after an @enumerable
decorator. On the other hand, decorators on separate elements that end up affecting class properties of the same name are almost always going to be bugs (analogous to name collisions arising from unhygienic macros). For both of these reasons, it seems important for a single element's decorators to be combined permissively, whereas the extras produced by distinct elements should be validated not to have conflicts.
With parameter _function_.
560 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 562 | will be driven by implementation considerations.
563 |With parameter _function_.
569 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 571 | will be driven by implementation considerations.
572 |With parameter _function_.
578 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 580 | will be driven by implementation considerations.
581 |With parameter _elements_.
587 |The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 596 | will be driven by implementation considerations.
597 |With no parameters.
626 |With parameters _element_ and _classDefinition_.
633 |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.
666 |