├── .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 | 81 |

Introduction

82 |

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 | 85 |

Syntax

86 | 87 |

As of this proposal, decorators can be attached to either classes or class members. An example of such a class might be:

88 | 89 | 90 |

 91 |         @frozen class Foo {
 92 |           @configurable(false) @enumerable(true) method() {}
 93 |         }
 94 |       
95 |
96 | 97 |

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 | 99 |

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 |
101 |

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 |
103 | 104 | 105 |

Example Decorator Functions

106 |

There are a number of examples of real-world usage based on previous drafts of this proposal.

107 | 108 | 109 |

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 |
199 |
200 | 201 |

Frameworks

202 | 203 |

Several frameworks have also adopted decorators in various forms.

204 | 205 | 206 |
Aurelia @computedFrom decorator
207 |

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 |
223 | 224 | 225 | 226 |
Aurelia @customElement, @useShadowDOM, and @bindable decorators
227 |

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 |
241 | 242 | 243 |
Ember @computed decorator
244 |

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 |
256 | 257 | 258 |
Ember @readOnly decorator
259 |

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 |
272 | 273 | 274 |
Ember Data entity relationship decorators
275 |

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 |
288 | 289 | 290 |
Ember @alias decorator
291 |

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 |
303 | 304 | 305 |
Ember @intersect decorator
306 |

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 |
318 | 319 | 320 |
Angular & TypeScript
321 |

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 |
334 |
335 |
336 | 337 | 338 |

Syntax

339 | 340 | 341 |

New Productions

342 | 343 | 344 | DecoratorList[Yield] : 345 | DecoratorList[?Yield]? Decorator[?Yield] 346 | 347 | Decorator[Yield] : 348 | `@` DecoratorMemberExpression[?Yield] 349 | `@` DecoratorCallExpression[?Yield] 350 | 351 | DecoratorMemberExpression[Yield] : 352 | IdentifierReference[?Yield] 353 | DecoratorMemberExpression[?Yield] `.` IdentifierName 354 | 355 | DecoratorCallExpression[Yield] : 356 | DecoratorMemberExpression Arguments[?Yield] 357 | 358 |
359 | 360 | 361 |

Updated Productions

362 | 363 |

PropertyDefinition : MethodDefinition gets an optional |DecoratorList|.

364 | 365 | PropertyDefinition[Yield] : 366 | IdentifierReference[?Yield] 367 | CoverInitializedName[?Yield] 368 | PropertyName[?Yield] `:` AssignmentExpression[+In, ?Yield] 369 | DecoratorList[?Yield]? MethodDefinition[?Yield] 370 | 371 | 372 |

ClassDeclaration : `class` BindingIdentifier ClassTail and ClassDeclaration : [+Default] `class` ClassTail get an optional |DecoratorList|.

373 | 374 | ClassDeclaration[Yield, Default] : 375 | DecoratorList[?Yield]? `class` BindingIdentifier[?Yield] ClassTail[?Yield] 376 | [+Default] DecoratorList[?Yield]? `class` ClassTail[?Yield] 377 | 378 | 379 |

ClassExpression : `class` BindingIdentifier? ClassTail gets an optional |DecoratorList|.

380 | 381 | ClassExpression[Yield] : 382 | DecoratorList [?Yield]? `class` BindingIdentifier[?Yield]? ClassTail[?Yield] 383 | 384 | 385 |

ClassElement : MethodDefinition and ClassElement : `static` MethodDefinition gets an optional |DecoratorList|.

386 | 387 | ClassElement[Yield] : 388 | DecoratorList[?Yield]? MethodDefinition[?Yield] 389 | DecoratorList[?Yield]? `static` MethodDefinition[?Yield] 390 | 391 |
392 |
393 | 394 | 395 |

Semantics

396 | 397 |

Decorator Functions

398 |

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 | 400 |

Member Descriptors

401 |

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 |
413 | 414 |

Class Descriptors

415 |

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 |
425 |
426 | 427 |

Updated Operations

428 | 429 | 430 |

Runtime Semantics: DefineMethod

431 |

With parameters _object_ and optional parameter _functionPrototype_.

432 | MethodDefinition : PropertyName `(` StrictFormalParameters `)` `{` FunctionBody `}` 433 | 434 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 435 | 1. ReturnIfAbrupt(_propKey_). 436 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 437 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 438 | 1. If _functionPrototype_ was passed as a parameter, let _kind_ be ~Normal~; otherwise let _kind_ be ~Method~. 439 | 1. Let _closure_ be FunctionCreate(_kind_, |StrictFormalParameters|, |FunctionBody|, _scope_, _strict_). If _functionPrototype_ was passed as a parameter, then pass its value as the _prototype_ optional argument of FunctionCreate. 440 | 1. Perform MakeMethod(_closure_, _object_). 441 | 1. Return the Record{[[Key]]: _propKey_, [[Closure]]: _closure_}. 442 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 443 | 1. Return the Record{[[Key]]: _propKey_, [[Descriptor]]: _desc_}. 444 | 445 |
446 | 447 | 448 |

Runtime Semantics: ClassDefinitionEvaluation

449 |

With parameter _className_.

450 | ClassTail : ClassHeritage? `{` ClassBody? `}` 451 | 452 | 1. Let _lex_ be the LexicalEnvironment of the running execution context. 453 | 1. Let _classScope_ be NewDeclarativeEnvironment(_lex_). 454 | 1. Let _classScopeEnvRec_ be _classScope_'s EnvironmentRecord. 455 | 1. If _className_ is not *undefined*, then 456 | 1. Perform _classScopeEnvRec_.CreateImmutableBinding(_className_, *true*). 457 | 1. If |ClassHeritage_opt| is not present, then 458 | 1. Let _protoParent_ be the intrinsic object %ObjectPrototype%. 459 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 460 | 1. Else, 461 | 1. Set the running execution context's LexicalEnvironment to _classScope_. 462 | 1. Let _superclass_ be the result of evaluating |ClassHeritage|. 463 | 1. Set the running execution context's LexicalEnvironment to _lex_. 464 | 1. ReturnIfAbrupt(_superclass_). 465 | 1. If _superclass_ is *null*, then 466 | 1. Let _protoParent_ be *null*. 467 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 468 | 1. Else if IsConstructor(_superclass_) is *false*, throw a *TypeError* exception. 469 | 1. Else, 470 | 1. Let _protoParent_ be ? Get(_superclass_, `"prototype"`). 471 | 1. If Type(_protoParent_) is neither Object nor Null, throw a *TypeError* exception. 472 | 1. Let _constructorParent_ be _superclass_. 473 | 1. Let _proto_ be ObjectCreate(_protoParent_). 474 | 1. If |ClassBody_opt| is not present, let _constructor_ be ~empty~. 475 | 1. Else, let _constructor_ be ConstructorMethod of |ClassBody|. 476 | 1. If _constructor_ is ~empty~, then 477 | 1. If |ClassHeritage_opt| is present and _protoParent_ is not *null*, then 478 | 1. Let _constructor_ be the result of parsing the source text 479 |
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. Let _constructorInfo_ be the result of performing DefineMethod for _constructor_ with arguments _proto_ and _constructorParent_ as the optional _functionPrototype_ argument. 487 | 1. Assert: _constructorInfo_ is not an abrupt completion. 488 | 1. Let _F_ be _constructorInfo_.[[Closure]]. 489 | 1. If |ClassHeritage_opt| is present and _protoParent_ is not *null*, then set _F_.[[ConstructorKind]] to `"derived"`. 490 | 1. Perform MakeConstructor(_F_, *false*, _proto_). 491 | 1. Perform MakeClassConstructor(_F_). 492 | 1. Perform CreateMethodProperty(_proto_, `"constructor"`, _F_). 493 | 1. If |ClassBody_opt| is not present, let _methods_ be a new empty List. 494 | 1. Else, let _methods_ be NonConstructorMethodDefinitions of |ClassBody|. 495 | 1. For each |ClassElement| _m_ in order from _methods_ 496 | 1. If IsStatic of _m_ is *false*, then 497 | 1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _proto_ and *false*. 498 | 1. Else, 499 | 1. Let _status_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _F_ and *false*. 500 | 1. If _status_ is an abrupt completion, then 501 | 1. Set the running execution context's LexicalEnvironment to _lex_. 502 | 1. Return Completion(_status_). 503 | 1. Let _static_ be IsStatic of _m_. 504 | 1. If _m_'s |DecoratorList| is present, then let _decorators_ be the result of performing DecoratorListEvaluation of |DecoratorList|. 505 | 1. Else, let _decorators_ be a new empty List. 506 | 1. Let _finishers_ be a new empty List. 507 | 1. ReturnIfAbrupt(_decorators_). 508 | 1. Let _el_ be the result of performing PropertyDefinitionEvaluation for _m_ with arguments _proto_, *false*. 509 | 1. If _el_ is an abrupt completion, then 510 | 1. Set the running execution context's LexicalEnvironment to _lex_. 511 | 1. Return Completion(_el_). 512 | 1. Else, let _descriptor_ be _descriptor_.[[value]]. 513 | 1. Let _element_ be the Record{[[Kind]]: `"property"`, [[Static]]: _static_, [[Key]]: _descriptor_.[[Key]], [[Descriptor]]: _descriptor_.[[Descriptor]], [[Decorators]]: _decorators_}. 514 | 1. Append _element_ to the end of _elements_. 515 | 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. 516 | 1. Let _elementDescriptors_ be a new empty List. 517 | 1. For each _element_ in order from _coalesced_ 518 | 1. Let _decorated_ be ? DecorateElement(_element_). 519 | 1. Append _decorated_.[[Descriptor]] to the end of _elementDescriptors_. 520 | 1. Append all elements of _decorated_.[[Finishers]] to the end of _finishers_. 521 | 1. For each _descriptor_ in order from _decorated_.[[Extras]]. 522 | 1. Append _descriptor_ to the end of _elementDescriptors_. 523 | 1. Let _constructorInfo_ be the result of performing DefineMethod for _constructor_ with _constructorParent_ as the optional _functionPrototype_ argument. 524 | 1. Assert: _constructorInfo_ is not an abrupt completion. 525 | 1. Let _originalF_ be _constructorInfo_.[[Closure]]. 526 | 1. Let _F_ be MakeUninitializedConstructor(_originalF_). 527 | 1. Let _result_ be ? DecorateClass(_F_, _constructorParent_, _elementDescriptors_). 528 | 1. Append all elements of _result_.[[Finishers]] to the end of _finishers_. 529 | 1. Let _constructor_ be _result_.[[Constructor]]. 530 | 1. Let _elements_ be _result_.[[Elements]]. 531 | 1. If |ClassHeritage?| is present and _protoParent_ is not *null*, then set _constructor_'s [[ConstructorKind]] internal slot to `"derived"`. 532 | 1. Perform MakeConstructor(_constructor_, *false*, _proto_). 533 | 1. Perform MakeClassConstructor(_constructor_). 534 | 1. Perform CreateMethodProperty(_proto_, `"constructor"`, _constructor_). 535 | 1. For each _descriptor_ in order from _elements_, do 536 | 1. Assert: _descriptor_.[[Kind]] is `"property"` 537 | 1. If _descriptor_.[[Static]] is *false*, then 538 | 1. Let _status_ be DefinePropertyOrThrow(_proto_, _descriptor_.[[Key]], _descriptor_.[[Descriptor]]) 539 | 1. Else, 540 | 1. Let _status_ be DefinePropertyOrThrow(_constructor_, _descriptor_.[[Key]], _descriptor_.[[Descriptor]]) 541 | 1. If _status_ is an abrupt completion, then 542 | 1. Set the running execution context's LexicalEnvironment to _lex_. 543 | 1. Return Completion(_status_). 544 | 1. Perform MakeFunctionInitialized(_constructor_). 545 | 1. Perform MakeClassElementsInitialized(_elementDescriptors_). 546 | 1. Set the running execution context's LexicalEnvironment to _lex_. 547 | 1. If _className_ is not *undefined*, then 548 | 1. Perform _classScopeEnvRec_.InitializeBinding(_className_, _F__constructor_). 549 | 1. For each _finisher_ in order from _finishers_, do 550 | 1. Perform ? Call(_finisher_, *undefined*, « _constructor »). 551 | 1. Return _F__constructor_. 552 |
553 | 554 |

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 |
    558 |
  • Imperatively apply the extras, and let them naturally merge (or fail in the configurability case).
  • 559 |
  • Validate the extras as they are produced.
  • 560 |
  • Validate the entire list of extras right before they are applied.
  • 561 |
562 |

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.

568 |
569 |
570 | 571 | 572 |

Runtime Semantics: PropertyDefinitionEvaluation

573 |

With parameters _object_ and _enumerable_.

574 | 575 | The modifications to PropertyDefinitionEvaluation delays actually building the object by returning a record instead of doing the DefineProperty at this point. We also make any closures uninitialized. 576 | 577 | 578 | MethodDefinition : PropertyName `(` StrictFormalParameters `)` `{` FunctionBody `}` 579 | 580 | 1. Let _methodDef_ be DefineMethod of |MethodDefinition| with argument _object_. 581 | 1. ReturnIfAbrupt(_methodDef_). 582 | 1. Perform SetFunctionName(_methodDef_.[[Closure]], _methodDef_.[[Key]]). 583 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _methodDef_.[[Closure]], [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 584 | 1. Return ? DefinePropertyOrThrow(_object_, _methodDef_.[[Key]], _desc_). 585 | 1. Let _closure_ be MakeFunctionUninitialized(_methodDef_.[[Closure]]). 586 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 587 | 1. Return the Record{[[Key]]: _methodDef_.[[Key]], [[Desc]]: _desc_, [[Decorators]]: _decorators_}. 588 | 589 | MethodDefinition : `get` PropertyName `(` `)` `{` FunctionBody `}` 590 | 591 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 592 | 1. ReturnIfAbrupt(_propKey_). 593 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 594 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 595 | 1. Let _formalParameterList_ be the production FormalParameters : [empty]. 596 | 1. Let _closure_ be FunctionCreate(~Method~, _formalParameterList_, |FunctionBody|, _scope_, _strict_). 597 | 1. Perform MakeMethod(_closure_, _object_). 598 | 1. Perform SetFunctionName(_closure_, _propKey_, `"get"`). 599 | 1. Let _closure_ be MakeFunctionUninitialized(_closure_). 600 | 1. Let _desc_ be the PropertyDescriptor{[[Get]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 601 | 1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_). 602 | 1. Return the Record{[[Key]]: _propKey_, [[Desc]]: _desc_}. 603 | 604 | MethodDefinition : `set` PropertyName `(` PropertySetParameterList `)` `{` FunctionBody `}` 605 | 606 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 607 | 1. ReturnIfAbrupt(_propKey_). 608 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 609 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 610 | 1. Let _closure_ be FunctionCreate(~Method~, |PropertySetParameterList|, |FunctionBody|, _scope_, _strict_). 611 | 1. Perform MakeMethod(_closure_, _object_). 612 | 1. Perform SetFunctionName(_closure_, _propKey_, `"set"`). 613 | 1. Let _closure_ be MakeFunctionUninitialized(_closure_). 614 | 1. Let _desc_ be the PropertyDescriptor{[[Set]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 615 | 1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_). 616 | 1. Return the Record{[[Key]]: _propKey_, [[Desc]]: _desc_}. 617 | 618 | GeneratorMethod : `*` PropertyName `(` StrictFormalParameters `)` `{` GeneratorBody `}` 619 | 620 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 621 | 1. ReturnIfAbrupt(_propKey_). 622 | 1. If the function code for this |GeneratorMethod| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 623 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 624 | 1. Let _closure_ be GeneratorFunctionCreate(~Method~, |StrictFormalParameters|, |GeneratorBody|, _scope_, _strict_). 625 | 1. Perform MakeMethod(_closure_, _object_). 626 | 1. Let _prototype_ be ObjectCreate(%GeneratorPrototype%). 627 | 1. Perform DefinePropertyOrThrow(_closure_, `"prototype"`, PropertyDescriptor{[[Value]]: _prototype_, [[Writable]]: *true*, [[Enumerable]]: *false*, [[Configurable]]: *false*}). 628 | 1. Perform SetFunctionName(_closure_, _propKey_). 629 | 1. Let _closure_ be MakeFunctionUninitialized(_closure_). 630 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 631 | 1. Return ? DefinePropertyOrThrow(_object_, _propKey_, _desc_). 632 | 1. Return the Record{[[Key]]: _propKey_, [[Desc]]: _desc_}. 633 | 634 |
635 |
636 | 637 | 638 |

New Operations

639 | 640 |

Runtime Semantics: DecoratorEvaluation

641 | Decorator : `@` DecoratorMemberExpression[?Yield] 642 | 643 | 1. Let _ref be the result of evaluating |DecoratorMemberExpression|. 644 | 1. Let _value be ? GetValue(_ref_). 645 | 1. Return _value_. 646 | 647 | Decorator : `@` DecoratorCallExpression[?Yield] 648 | 649 | 1. Let _ref be the result of evaluating |DecoratorCallExpression|. 650 | 1. Let _value be ? GetValue(_ref_). 651 | 1. Return _value_. 652 | 653 |
654 | 655 | 656 |

Runtime Semantics: DecoratorListEvaluation

657 | DecoratorList : DecoratorList[?Yield]? Decorator[?Yield] 658 | 659 | 1. If |DecoratorList| is present, then let _leftValue_ be ? DecoratorListEvaluation(|DecoratorList|). 660 | 1. Else, let _leftValue_ be a new empty List. 661 | 1. Let _rightValue_ be ? DecoratorEvaluation(|Decorator|). 662 | 1. Append _rightValue_ to the end of _leftValue_. 663 | 1. Return _leftValue_. 664 | 665 |
666 | 667 | 668 |

Runtime Semantics: MakeFunctionUninitialized

669 |

With parameter _function_.

670 | 671 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.

672 |
673 |
674 | 675 | 676 |

Runtime Semantics: MakeFunctionInitialized

677 |

With parameter _function_.

678 | 679 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.

680 |
681 |
682 | 683 | 684 |

Runtime Semantics: IsUninitializedFunction

685 |

With parameter _function_.

686 | 687 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.

688 |
689 |
690 | 691 | 692 |

Runtime Semantics: MakeClassElementsInitialized

693 |

With parameter _elements_.

694 | 695 | 1. For each _element_ in order from _elements_ 696 | 1. Let _desc_ be _element_.[[Descriptor]]. 697 | 1. If _desc_ has a [[Set]] field, MakeFunctionInitialized(_desc_.[[Set]]). 698 | 1. If _desc_ has a [[Get]] field, MakeFunctionInitialized(_desc_.[[Get]]). 699 | 1. If _desc_ has a [[Value]] field, and IsUninitializedFunction(_desc_.[[Value]]) is *true*, MakeFunctionInitialized(_desc_.[[Value]]). 700 | 701 | 702 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics will be driven by implementation considerations.

703 |
704 |
705 | 706 |

DecorateElement

707 |

With parameter _element_.

708 | 709 | 1. Assert: _element_.[[Kind]] is `"property"`. 710 | 1. Let _extras_ be a new empty List. 711 | 1. Let _finishers_ be a new empty List. 712 | 1. Let _previousDescriptor_ be ? FromElementDescriptor(_element_). 713 | 1. For each _decorator_ in element_.[[Decorators]], in reverse list order do 714 | 1. Let _result_ be ? Call(_decorator_, *undefined*, « _previousDescriptor_ »). 715 | 1. Let _currentDescriptor_ be ? Get(_result_, *"descriptor"*). 716 | 1. Let _current_ be ? ToElementDescriptor(_result_). 717 | 1. If _current_.[[Finisher]] is not *undefined*, then 718 | 1. Append _current_.[[Finisher]] to the end of _finishers_. 719 | 1. Set _current_.[[Finisher]] to *undefined*. 720 | 1. Note: Finishers are not passed forward to the next decorator. 721 | 1. Let _previousDescriptor_ be ? FromElementDescriptor(_current_). 722 | 1. Let _extrasObject_ be ? Get(_result_, `"extras"`). 723 | 1. If _extrasObject_ is not *undefined*, then: 724 | 1. Let _iterator_ be ? GetIterator(_extrasObject_). 725 | 1. Repeat 726 | 1. Let _next_ be ? IteratorStep(_iterator_). 727 | 1. If _next_ is *false*, then break. 728 | 1. Let _nextValue_ be ? IteratorValue(_next_). 729 | 1. Append _nextValue_ to the end of _extras_. 730 | 1. Let _extras_ be the result of merging any _extras_ with the same [[Key]] and [[Static]]. 731 | 1. Return the Record {[[Descriptor]]: _previousDescriptor_, [[Extras]]: _extras_, [[Finishers]]: _finishers_}. 732 | 733 | 734 |

Future versions of the spec will create element descriptors with other [[Kind]]s.

735 |
736 | 737 |

There is a decision-point about what validation rules should be applied to the merging that happens right before merging.

738 |
739 |
740 | 741 |

DecorateClass

742 |

With parameters _decorators_, _constructor_, _heritage_ and _elementDescriptors_.

743 | 744 | 1. Let _elements_ be a new empty List. 745 | 1. Let _finishers_ be a new empty List. 746 | 1. Let _previousConstructor_ be _constructor_. 747 | 1. Let _previousDescriptors_ be _elementDescriptors_. 748 | 1. For each _decorator_ in _decorators_, in reverse list order do 749 | 1. Let _result_ be ? Call(_decorator_, *undefined*, « _previousConstructor_, _heritage_, _previousDescriptors_ »). 750 | 1. Let _previousConstructor_ be ? Get(_result_, `"constructor"`). 751 | 1. Let _finisher_ be ? Get(_result_, *"finisher"*). 752 | 1. If _finisher_ is not *undefined*, then append _finisher_ to the end of _finishers_. 753 | 1. Let _elementsObject_ be ? Get(_result_, `"elements"`). 754 | 1. If _elementsObject_ is not *undefined*, then 755 | 1. Let _iterator_ be ? GetIterator(_extrasObject_). 756 | 1. Repeat 757 | 1. Let _next_ be ? IteratorStep(_iterator_). 758 | 1. If _next_ is *false*, then break. 759 | 1. Let _nextValue_ be ? IteratorValue(_next_). 760 | 1. Append _nextValue_ to the end of _elements_. 761 | 1. Let _elements_ be the result of merging any _elements_ with the same [[Key]] and [[Static]]. 762 | 1. Return the Record {[[Constructor]]: _previousConstructor_, [[Elements]]: _elements_, [[Finishers]]: _finishers_}. 763 | 764 | 765 |

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 |
769 |
770 | 771 | 772 |

FromElementDescriptor

773 |

With parameter _element_.

774 | 775 | 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). 776 | 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"kind"`, _element_.[[Kind]]). 777 | 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"isStatic"`, _element_.[[Static]]). 778 | 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _element_.[[Key]]). 779 | 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"descriptor"`, ! FromPropertyDescriptor(_element_.[[Descriptor]])). 780 | 1. If _element_.[[Finisher]] is not *undefined*, then 781 | 1. Perform ! CreateDataPropertyOrThrow(_obj_, *"finisher"*, _element_.[[Finisher]]). 782 | 1. Return _obj_. 783 | 784 |
785 | 786 | 787 |

ToElementDescriptor

788 |

With parameter _descriptor_.

789 | 790 | 1. Let _kind_ be ? Get(_descriptor_, `"kind"`). 791 | 1. If _kind_ is not equal to the string value `"property"`, throw a TypeError exception. 792 | 1. Let _static_ be ToBoolean(? Get(_descriptor_, `"isStatic"`)). 793 | 1. Let _key_ be ? ToString(? Get(_descriptor_, `"key"`)). 794 | 1. Let _descriptor_ be ? ToPropertyDescriptor(? Get(_descriptor_, `"descriptor"`)). 795 | 1. Let _hasFinisher_ be ? HasProperty(_descriptor_, 'finisher'). 796 | 1. If _hasFinisher_ is *true*, let _finisher_ be ? Get(_descriptor_, *"key"*). 797 | 1. Else, let _finisher_ be *undefined*. 798 | 1. Return the Record {[[Kind]]: _kind_, [[Static]]: _static_, [[Key]]: _key_, [[Descriptor]]: _descriptor_, [[Finisher]]: _finisher_}. 799 | 800 | 801 |

Todo: Should probably add validations for having kind, static, and key fields.

802 |
803 |
804 |
805 |
806 | -------------------------------------------------------------------------------- /figure-2.uxf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 4 | 5 | UMLClass 6 | 7 | 390 8 | 70 9 | 160 10 | 30 11 | 12 | Object.prototype 13 | bg=#cceecc 14 | 15 | 16 | 17 | UMLNote 18 | 19 | 390 20 | 0 21 | 160 22 | 50 23 | 24 | [[Prototype]] of 25 | Object.prototype is null 26 | bg=#ffeeee 27 | 28 | 29 | 30 | UMLClass 31 | 32 | 390 33 | 140 34 | 160 35 | 100 36 | 37 | Function.prototype 38 | -- 39 | @@hasInstance() 40 | apply() 41 | bind() 42 | call() 43 | bg=#cceecc 44 | 45 | 46 | 47 | Relation 48 | 49 | 480 50 | 90 51 | 30 52 | 70 53 | 54 | lt=<<- 55 | 10.0;10.0;10.0;50.0 56 | 57 | 58 | UMLClass 59 | 60 | 390 61 | 270 62 | 160 63 | 60 64 | 65 | %Generator% 66 | -- 67 | @@toStringTag = 68 | "GeneratorFunction" 69 | 70 | bg=#cceecc 71 | 72 | 73 | 74 | Relation 75 | 76 | 480 77 | 230 78 | 30 79 | 60 80 | 81 | lt=<<- 82 | 10.0;10.0;10.0;40.0 83 | 84 | 85 | UMLClass 86 | 87 | 390 88 | 420 89 | 160 90 | 50 91 | 92 | <<callable>> 93 | function *g1() { yield; } 94 | 95 | 96 | 97 | Relation 98 | 99 | 480 100 | 320 101 | 30 102 | 120 103 | 104 | lt=<<- 105 | 10.0;10.0;10.0;100.0 106 | 107 | 108 | UMLClass 109 | 110 | 40 111 | 180 112 | 160 113 | 60 114 | 115 | <<constructor>> 116 | <<callable>> 117 | Function 118 | 119 | bg=#cceecc 120 | 121 | 122 | 123 | Relation 124 | 125 | 130 126 | 150 127 | 280 128 | 50 129 | 130 | lt=<<- 131 | 260.0;10.0;10.0;10.0;10.0;30.0 132 | 133 | 134 | UMLClass 135 | 136 | 40 137 | 270 138 | 160 139 | 60 140 | 141 | <<constructor>> 142 | <<callable>> 143 | %GeneratorFunction% 144 | 145 | bg=#cceecc 146 | 147 | 148 | 149 | Relation 150 | 151 | 130 152 | 230 153 | 30 154 | 60 155 | 156 | lt=<<- 157 | 10.0;10.0;10.0;40.0 158 | 159 | 160 | Relation 161 | 162 | 190 163 | 300 164 | 220 165 | 40 166 | 167 | lt=<-> 168 | m2=constructor 169 | m1=prototype 170 | 10.0;10.0;200.0;10.0 171 | 172 | 173 | UMLClass 174 | 175 | 740 176 | 190 177 | 160 178 | 50 179 | 180 | %IteratorPrototype% 181 | -- 182 | @@iterator() : object 183 | bg=#cceecc 184 | 185 | 186 | 187 | UMLClass 188 | 189 | 740 190 | 270 191 | 160 192 | 120 193 | 194 | %GeneratorPrototype% 195 | -- 196 | @@toStringTag = 197 | "Generator" 198 | -- 199 | next() : object 200 | return() 201 | throw() 202 | bg=#cceecc 203 | 204 | 205 | 206 | Relation 207 | 208 | 540 209 | 70 210 | 300 211 | 140 212 | 213 | lt=<<- 214 | 10.0;10.0;280.0;10.0;280.0;120.0 215 | 216 | 217 | UMLClass 218 | 219 | 740 220 | 420 221 | 160 222 | 30 223 | 224 | g1.prototype 225 | 226 | 227 | 228 | UMLClass 229 | 230 | 740 231 | 500 232 | 160 233 | 30 234 | 235 | g1() 236 | 237 | 238 | 239 | Relation 240 | 241 | 810 242 | 230 243 | 30 244 | 60 245 | 246 | lt=<<- 247 | 10.0;10.0;10.0;40.0 248 | 249 | 250 | Relation 251 | 252 | 810 253 | 380 254 | 30 255 | 60 256 | 257 | lt=<<- 258 | 10.0;10.0;10.0;40.0 259 | 260 | 261 | Relation 262 | 263 | 810 264 | 440 265 | 30 266 | 80 267 | 268 | lt=<<- 269 | 10.0;10.0;10.0;60.0 270 | 271 | 272 | Relation 273 | 274 | 540 275 | 430 276 | 220 277 | 40 278 | 279 | lt=-> 280 | m1=prototype 281 | 10.0;10.0;200.0;10.0 282 | 283 | 284 | Relation 285 | 286 | 540 287 | 450 288 | 220 289 | 70 290 | 291 | lt=<. 292 | 293 | 10.0;10.0;200.0;50.0 294 | 295 | 296 | Relation 297 | 298 | 190 299 | 310 300 | 220 301 | 130 302 | 303 | lt=<. 304 | 305 | 10.0;10.0;200.0;110.0 306 | 307 | 308 | UMLNote 309 | 310 | 570 311 | 200 312 | 150 313 | 90 314 | 315 | %Generator% is an 316 | ordinary object that 317 | serves as the abstract 318 | constructor of 319 | Generator instances. 320 | bg=#ffeeee 321 | 322 | 323 | 324 | Relation 325 | 326 | 540 327 | 230 328 | 50 329 | 60 330 | 331 | lt=. 332 | 10.0;40.0;30.0;10.0 333 | 334 | 335 | Relation 336 | 337 | 480 338 | 40 339 | 30 340 | 50 341 | 342 | lt=. 343 | 10.0;30.0;10.0;10.0 344 | 345 | 346 | Relation 347 | 348 | 540 349 | 300 350 | 220 351 | 40 352 | 353 | lt=<-> 354 | m2=constructor 355 | m1=prototype 356 | 10.0;10.0;200.0;10.0 357 | 358 | 359 | UMLNote 360 | 361 | 230 362 | 430 363 | 140 364 | 60 365 | 366 | A typical generator 367 | function. It is not a 368 | constructor. 369 | bg=#ffeeee 370 | 371 | 372 | 373 | Relation 374 | 375 | 360 376 | 440 377 | 50 378 | 30 379 | 380 | lt=. 381 | 10.0;10.0;30.0;10.0 382 | 383 | 384 | UMLNote 385 | 386 | 40 387 | 350 388 | 180 389 | 190 390 | 391 | %GeneratorFunction% 392 | and %Generator% do not 393 | have global names. 394 | 395 | %GeneratorFunction% is 396 | essentially a subclass of 397 | Function and is structured 398 | as if it were declared as: 399 | 400 | class extends Function { } 401 | bg=#ffeeeee 402 | 403 | 404 | 405 | Relation 406 | 407 | 130 408 | 320 409 | 30 410 | 50 411 | 412 | lt=. 413 | 10.0;10.0;10.0;30.0 414 | 415 | 416 | UMLNote 417 | 418 | 340 419 | 500 420 | 380 421 | 120 422 | 423 | Each Generator Function has an associated prototype 424 | that does not have a constructor property. Hence a 425 | generator instance does not expose access to its generator 426 | function. 427 | 428 | But the prototype may be used to add additional 429 | behavior to its generator function's instances. 430 | bg=#ffeeee 431 | 432 | 433 | 434 | Relation 435 | 436 | 710 437 | 510 438 | 50 439 | 30 440 | 441 | lt=. 442 | 10.0;10.0;30.0;10.0 443 | 444 | 445 | Text 446 | 447 | 350 448 | 380 449 | 90 450 | 30 451 | 452 | instanceof 453 | style=wordwrap 454 | 455 | 456 | 457 | Text 458 | 459 | 670 460 | 470 461 | 90 462 | 30 463 | 464 | instanceof 465 | style=wordwrap 466 | 467 | 468 | 469 | -------------------------------------------------------------------------------- /img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tc39/proposal-decorators-previous/f8c6dc86a74d71d2b32a371065bf6a480bf4652f/img/favicon.ico -------------------------------------------------------------------------------- /img/figure-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tc39/proposal-decorators-previous/f8c6dc86a74d71d2b32a371065bf6a480bf4652f/img/figure-1.png -------------------------------------------------------------------------------- /img/figure-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | q1 32 | q2 33 | cf 34 | 35 | 36 | 37 | 38 | 39 | 40 | implicit prototype link 41 | 42 | explicit prototype property 43 | 44 | 45 | 46 | CF 47 | 48 | prototype 49 | P1 50 | P2 51 | 52 | 53 | 54 | 55 | 56 | CF 57 | p 58 | CFP1 59 | 60 | 61 | 62 | 1 63 | 64 | 65 | 2 66 | 67 | 68 | 3 69 | 70 | 71 | 4 72 | 73 | 74 | 5 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /img/figure-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tc39/proposal-decorators-previous/f8c6dc86a74d71d2b32a371065bf6a480bf4652f/img/figure-2.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "ecma262", 4 | "version": "1.0.0", 5 | "description": "The ECMAScript specification", 6 | "scripts": { 7 | "build-es2016": "git remote remove origin && git remote add origin \"git@github.com:$TRAVIS_REPO_SLUG.git\" && git fetch --quiet origin && git checkout --quiet es2016 && mkdir \"out/2016\" && cp -R img \"out/2016\" && ecmarkup --verbose spec.html out/2016/index.html --css out/2016/ecmarkup.css --js out/2016/ecmarkup.js && git checkout --quiet test-travis", 8 | "build-master": "mkdir out && cp -R img out && ecmarkup --verbose spec.html out/index.html --css out/ecmarkup.css --js out/ecmarkup.js", 9 | "build": "npm run clean && npm run build-master", 10 | "build-travis": "npm run clean && npm run build-master && npm run build-es2016", 11 | "update-pages": "node node_modules/ecmarkup/bin/ecmarkup.js decorators.html _index.html && git checkout gh-pages && rm index.html && mv _index.html index.html && git add index.html && git commit -m \"update pages\" && git checkout master", 12 | "clean": "rm -rf out", 13 | "test": "exit 0", 14 | "watch": "npm run clean && mkdir out && cp -R img out && ecmarkup --watch --verbose spec.html out/index.html --css out/ecmarkup.css --js out/ecmarkup.js" 15 | }, 16 | "repository": "tc39/ecma262", 17 | "author": "ECMA TC39", 18 | "license": "SEE LICENSE IN https://tc39.github.io/ecma262/#sec-copyright-and-software-license", 19 | "homepage": "https://tc39.github.io/ecma262/", 20 | "dependencies": { 21 | "ecmarkup": "^3.11.0" 22 | }, 23 | "devDependencies": { 24 | "@alrra/travis-scripts": "^2.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/auto-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | declare -r PRIVATE_KEY_FILE_NAME='github_deploy_key' 4 | 5 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6 | 7 | # Decrypt the file containing the private key 8 | 9 | openssl aes-256-cbc \ 10 | -K $encrypted_1e2182e20f4c_key \ 11 | -iv $encrypted_1e2182e20f4c_iv \ 12 | -in "$(dirname "$BASH_SOURCE")/${PRIVATE_KEY_FILE_NAME}.enc" \ 13 | -out ~/.ssh/$PRIVATE_KEY_FILE_NAME -d 14 | 15 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16 | 17 | # Enable SSH authentication 18 | 19 | chmod 600 ~/.ssh/$PRIVATE_KEY_FILE_NAME 20 | echo "Host github.com" >> ~/.ssh/config 21 | echo " IdentityFile ~/.ssh/$PRIVATE_KEY_FILE_NAME" >> ~/.ssh/config 22 | 23 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 24 | 25 | # Update the content from the `gh-pages` branch 26 | 27 | $(npm bin)/update-branch --commands "npm run build-travis" \ 28 | --commit-message "Update gh-pages [skip ci]" \ 29 | --directory "out" \ 30 | --distribution-branch "gh-pages" \ 31 | --source-branch "master" 32 | -------------------------------------------------------------------------------- /scripts/github_deploy_key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tc39/proposal-decorators-previous/f8c6dc86a74d71d2b32a371065bf6a480bf4652f/scripts/github_deploy_key.enc -------------------------------------------------------------------------------- /workingdocs/ES6-super-construct=proposal.md: -------------------------------------------------------------------------------- 1 | This is the proposal presented and discussed at the Jan. 7, 2015 TC39 video conference call. This proposal would be applied to ES6 specification (except as noted). 2 | 3 | 4 | 1. [[Construct]] takes a new additional argument *originalConstructor* which is the constructor object `new` was actually 5 | applied to. That argument also is also reified as arguments to the `construct` proxy trap and in `Reflect.construct` 6 | 7 | 2. Built-in object allocation and initialization are merged into a single constructor function, just like in ES5. Note that allocation take place in a base constructor rather than the original constructor and uses 'originalConstructor' argument to determine the [[Prototype]] of the new instance. The subclass constructor determines what arguments are passed to the base constructor which may use those arguments in its allocation and initialization logic. 8 | 9 | * There is no [[CreateAction]] or similar separable allocation step. 10 | 11 | 3. ***When a constructor is invoked via ordinary [[Construct]] and the constructor body was not defined using a `class` definition 12 | that has an `extends` clause, then `this` is initialized to a newly allocated ordinary object whose [[Prototype]] is provided 13 | by the original constructor. 14 | * This is the way that `function` definition based constructors work today and must be maintained for legacy compatibility. 15 | * The same `this` initializaton rules are used by both `function` definitions and `class` declarations that don't have `extends` clauses. 16 | 17 | 4. When a constructor is invoked via ordinary [[Construct]], `this` is marked as uninitialized if the constructor body was 18 | defined using a `class` definition that has an `extends` clause. 19 | * If invoked via [[Call]], 'this' is initialized in the normal manner. 20 | 21 | 5. Any explicit reference to an uninitialized `this` throws a ReferenceError Exception 22 | 23 | 6. When `this` is in its uninitialized state, any expression in a constructor of the form `super()` accesses the 24 | [[Prototype]] of the active function and invokes [[Construct]] on it with the current *originalConstructor* value passed 25 | as the *originalConstructor* argument. Subsequent references to `this` produce the object value that was returned from the 26 | superclass constructor. 27 | * In other words, a `super` call delegates allocation and initial initialization steps to the super class constructor. 28 | 29 | 7. When `this` is in its initialized state, any expression of the form 'super()' throws a ReferenceError exception. 30 | Rather than using [[Call]] to invoke the super class constructor. 31 | 32 | 8. ** Within a constructor, `new.target` can be used, as if it was an identifier, to access the *originalConstructor* value. 33 | * `new.target` can be used to get information about the original constructor (such as its `prototype` property) 34 | that can be used to manually allocate the instance object. It can also be used to discriminate [[Construct]] vs. [[Call]] 35 | invocations. 36 | * An explicit return must be used to return such manually allocated objects 37 | 38 | 9. When a function implicitly returns from a [[Construct]] invocation, if its `this` binding is still uninitialized 39 | a ReferenceError is thrown. 40 | * This covers the case where a constructor with an `extends` clause does not invokes `super()`. 41 | 42 | 10. When a function explicitly returns a non-object from a [[Construct]] invocation and its `this` binding 43 | is still uninitialized a TypeError is thrown. 44 | 45 | 11. When a function explicitly returns a non-object from a [[Construct]] invocation but the `this` value has been initialized, 46 | the `this` value is returned as the value of [[Construct]] 47 | * This is required for ES1-5 compatability 48 | 49 | 12. If a `class` definition does not include an explicit constructor definition, it defaults to: `constructor(...args) {super(...args)};` if the `class` has a non-null `extends` clause. Otherwise it defaults to: `constructor() {};`. 50 | * If you define a constructor body then you inherit both the constructor argument signature and body from your superclass. 51 | 52 | ** There is agreement that this functionality is necessary. There is not yet consensus as to whether it can be deferred 53 | until ES7 and on the actual special form syntax used to access the value. 54 | 55 | *** For the details covered by this proposal, an `extends null` clause is considered to be equivalent to an absent `extends` clause. 56 | -------------------------------------------------------------------------------- /workingdocs/callconstructor.md: -------------------------------------------------------------------------------- 1 | # Call constructor proposal 2 | 3 | **Stage 2 Proposal** 4 | 5 | Champions: 6 | - Yehuda Katz 7 | - Allen Wirfs-Brock 8 | 9 | ## Motivation 10 | 11 | ### History 12 | 13 | ES5 constructors had a dual-purpose: they got invoked both when the constructor was `new`ed (`[[Construct]]`) and when it was called (`[[Call]]`). 14 | 15 | This made it possible to use a single constructor for both purposes, but required constructor writers to defend against consumers accidentally `[[Call]]`ing the constructor. 16 | 17 | ES6 classes do not support `[[Call]]`ing the constructor at all, which means that classes do not need to defend themselves against being inadvertantly `[[Call]]`ed. 18 | 19 | In ES6, if you want to implement a constructor that can be both `[[Call]]`ed and `[[Construct]]`ed, you can write the constructor as an ES5 function, and use `new.target` to differentiate between the two cases. 20 | 21 | ### Motivating Example 22 | 23 | The "callable constructor" pattern is very common in JavaScript itself, so I will use `Date` to illustrate how you can use an ES5 function to implement a reliable callable constructor in ES6. 24 | 25 | ```js 26 | // these functions are defined in the appendix 27 | import { initializeDate, ToDateString } from './date-implementation'; 28 | 29 | export function Date(...args) { 30 | if (new.target) { 31 | // [[Construct]] branch 32 | initializeDate(this, ...args); 33 | } else { 34 | // [[Call]] branch 35 | return ToDateString(clockGetTime()); 36 | } 37 | } 38 | ``` 39 | 40 | This works fine, but it has two problems: 41 | 42 | 1. It requires the use of ES5 function as constructors. In an ideal world, new classes would be written using class syntax. 43 | 2. It uses a meta-property, `new.target` to disambiguate the two paths, but its meaning is not apparent to those not familiar with the meta-property. 44 | 45 | This proposal proposes new syntax that allows you to express "callable constructor" in class syntax. 46 | 47 | Here's an implementation of the same `Date` class using the new proposed syntax: 48 | 49 | ```js 50 | import { initializeDate, ToDateString } from './date-implementation'; 51 | 52 | class Date { 53 | constructor(...args) { 54 | initializeDate(super(), ...args); 55 | } 56 | 57 | call constructor() { 58 | return ToDateString(clockGetTime()); 59 | } 60 | } 61 | ``` 62 | 63 | ## Specification 64 | 65 | The following changes and additions are relative the [ECMAScript 2015 Specification](http://ecma-international.org/ecma-262/6.0/) 66 | 67 | ### [9.2](http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects) [Table 27](http://ecma-international.org/ecma-262/6.0/#table-27) 68 | 69 | The following entry is added to Table 27 70 | 71 | | Internal Slot | Type | Description | 72 | | ------------------- | ------- | ---------------------------------------------------------------------------- | 73 | | [[ConstructorCall]] | Object or empty | The function object that is evaluated when a class constructor is invoked using [[Call]]. Only used when [[FunctionKind]] is `"classConstructor"`. | 74 | 75 | ### [9.2.1 [[Call]]](http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist) 76 | 77 | Step 2 is replaced with: 78 | 79 |
 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 |     static MethodElement[?Yield]
110 |     CallConstructor
111 |     ;
112 |     
113 | CallConstructor :
114 |     call constructor ( StrictFormalParameters ) { FunctionBody}
115 | 
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 : 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 | 3 |

Runtime Semantics: DefineMethod

4 |

With optional parameter _functionPrototype_.

5 | MethodDefinition : PropertyName `(` StrictFormalParameters `)` `{` FunctionBody `}` 6 | 7 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 8 | 1. ReturnIfAbrupt(_propKey_). 9 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 10 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 11 | 1. If _functionPrototype_ was passed as a parameter, let _kind_ be ~Normal~; otherwise let _kind_ be ~Method~. 12 | 1. Let _closure_ be FunctionCreate(_kind_, |StrictFormalParameters|, |FunctionBody|, _scope_, _strict_). If _functionPrototype_ was passed as a parameter, then pass its value as the _prototype_ optional argument of FunctionCreate. 13 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 14 | 1. Return the Record{[[Key]]: _propKey_, [[Descriptor]]: _desc_}. 15 | 16 |
17 | 18 | 19 | 20 |

Runtime Semantics: PropertyDefinitionEvaluation

21 |

With parameters _object_ and _enumerable_.

22 | 23 | MethodDefinition : DecoratorList[?Yield]? PropertyName `(` StrictFormalParameters `)` `{` FunctionBody `}` 24 | 25 | 1. Let _decorators_ be the result of DecoratorListEvaluation of |DecoratorList[?Yield]?|. 26 | 1. ReturnIfAbrupt(_decorators_). 27 | 1. Let _methodDef_ be DefineMethod of |MethodDefinition| with argument _object_. 28 | 1. ReturnIfAbrupt(_methodDef_). 29 | 1. Perform SetFunctionName(_methodDef_.[[Closure]], _methodDef_.[[Key]]). 30 | 1. Let _closure_ be MakeFunctionUninitialized(_methodDef_.[[Closure]]). 31 | 1. Let _desc_ be the PropertyDescriptor{[[Value]]: _closure_, [[Writable]]: *true*, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 32 | 1. Return the Record{[[Key]]: _methodDef_.[[Key]], [[Desc]]: _desc_, [[Decorators]]: _decorators_}. 33 | 34 | MethodDefinition : GeneratorMethod 35 |

See .

36 | MethodDefinition : DecoratorList[?Yield]? `get` PropertyName `(` `)` `{` FunctionBody `}` 37 | 38 | 1. Let _decorators_ be the result of DecoratorListEvaluation of |DecoratorList[?Yield]?|. 39 | 1. ReturnIfAbrupt(_decorators_). 40 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 41 | 1. ReturnIfAbrupt(_propKey_). 42 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 43 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 44 | 1. Let _formalParameterList_ be the production FormalParameters : [empty]. 45 | 1. Let _closure_ be FunctionCreate(~Method~, _formalParameterList_, |FunctionBody|, _scope_, _strict_). 46 | 1. Perform SetFunctionName(_closure_, _propKey_, `"get"`). 47 | 1. Let _closure_ be MakeFunctionUninitialized(_closure_). 48 | 1. Let _desc_ be the PropertyDescriptor{[[Get]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 49 | 1. Return the Record{[[Key]]: _methodDef_.[[Key]], [[Desc]]: _desc_, [[Decorators]]: _decorators_}. 50 | 51 | MethodDefinition : DecoratorList[?Yield]? `set` PropertyName `(` PropertySetParameterList `)` `{` FunctionBody `}` 52 | 53 | 1. Let _decorators_ be the result of DecoratorListEvaluation of |DecoratorList[?Yield]?|. 54 | 1. ReturnIfAbrupt(_decorators_). 55 | 1. Let _propKey_ be the result of evaluating |PropertyName|. 56 | 1. ReturnIfAbrupt(_propKey_). 57 | 1. If the function code for this |MethodDefinition| is strict mode code, let _strict_ be *true*. Otherwise let _strict_ be *false*. 58 | 1. Let _scope_ be the running execution context's LexicalEnvironment. 59 | 1. Let _closure_ be FunctionCreate(~Method~, |PropertySetParameterList|, |FunctionBody|, _scope_, _strict_). 60 | 1. Perform SetFunctionName(_closure_, _propKey_, `"set"`). 61 | 1. Let _closure_ be MakeFunctionUninitialized(_closure_). 62 | 1. Let _desc_ be the PropertyDescriptor{[[Set]]: _closure_, [[Enumerable]]: _enumerable_, [[Configurable]]: *true*}. 63 | 1. Return the Record{[[Key]]: _methodDef_.[[Key]], [[Desc]]: _desc_, [[Decorators]]: _decorators_}. 64 | 65 |
66 | 67 | 68 |

Decorator

69 |

Syntax

70 | 71 | Decorator[Yield] : 72 | `@` LeftHandSideExpression[?Yield] 73 | 74 | 75 | 76 |

Runtime Semantics: DecoratorEvaluation

77 | `@` LeftHandSideExpression[?Yield] 78 | 79 | 1. Let _left_ be the result of evaluating |LeftHandSideExpression[?Yield]|. 80 | 1. Let _leftValue_ be ? GetValue(_left_). 81 | 1. Return _leftValue_. 82 | 83 |
84 |
85 | 86 | 87 |

DecoratorList

88 |

Syntax

89 | 90 | DecoratorList[Yield] : 91 | DecoratorList[?Yield]? Decorator[?Yield] 92 | 93 | 94 |

Runtime Semantics: DecoratorListEvaluation

95 | DecoratorList[?Yield]? Decorator[?Yield] 96 | 97 | 1. If |DecoratorList[?Yield]?| is present, then let _leftValue_ be ? DecoratorListEvaluation(|DecoratorList[?Yield]?|). 98 | 1. Else, let _leftValue_ be a new empty List. 99 | 1. Let _right_ be ? DecoratorEvaluation(|Decorator[?Yield]|). 100 | 1. Append _right_ to the end of _leftValue_. 101 | 1. Return _leftValue_. 102 | 103 |
104 |
105 | 106 | 107 |

DecorateElement

108 |

With parameter _element_.

109 | 110 | 1. Assert: _element_.[[Kind]] is `"property"`. 111 | 1. Let _extras_ be a new empty List. 112 | 1. Let _previousDescriptor_ be ? FromElementDescriptor(_element_). 113 | 1. For each _decorator_ in element_.[[Decorators]], in reverse list order do 114 | 1. Let _result_ be ? Call(_decorator_, *undefined*, « _previousDescriptor_ »). 115 | 1. Let _currentDescriptor_ be ? Get(_result_, `"descriptor"`). 116 | 1. Let _current_ be ? ToElementDescriptor(_currentDescriptor_). 117 | 1. Let _previousDescriptor_ be ? FromElementDescriptor(_current_). 118 | 1. Let _extrasObject_ be ? Get(_result_, `"extras"`). 119 | 1. If _extrasObject_ is not *undefined*, then: 120 | 1. Let _iterator_ be ? GetIterator(_extrasObject_). 121 | 1. Repeat 122 | 1. Let _next_ be ? IteratorStep(_iterator_). 123 | 1. If _next_ is *false*, then break. 124 | 1. Let _nextValue_ be ? IteratorValue(_next_). 125 | 1. Append _nextValue_ to the end of _extras_. 126 | 1. Let _extras_ be the result of merging any _extras_ with the same [[Key]] and [[Static]]. 127 | 1. Return the Record {[[Descriptor]]: _previousDescriptor_, [[Extras]]: _extras_}. 128 | 129 | 130 |

Future versions of the spec will create element descriptors with other [[Kind]]s.

131 |
132 | 133 |

There is a decision-point about what validation rules should be applied to the merging that happens right before merging.

134 |
135 |
136 | 137 | 138 |

DecorateClass

139 |

With parameters _decorators_, _constructor_, _heritage_ and _elementDescriptors_.

140 | 141 | 1. Let _elements_ be a new empty List. 142 | 1. Let _previousConstructor_ be _constructor_. 143 | 1. Let _previousDescriptors_ be _elementDescriptors_. 144 | 1. For each _decorator_ in _decorators_, in reverse list order do 145 | 1. Let _result_ be ? Call(_decorator_, *undefined*, « _previousConstructor_, _heritage_, _previousDescriptors_ »). 146 | 1. Let _previousConstructor_ be ? Get(_result_, `"constructor"`). 147 | 1. Let _elementsObject_ be ? Get(_result_, `"elements"`). 148 | 1. If _elementsObject_ is not *undefined*, then: 149 | 1. Let _iterator_ be ? GetIterator(_extrasObject_). 150 | 1. Repeat 151 | 1. Let _next_ be ? IteratorStep(_iterator_). 152 | 1. If _next_ is *false*, then break. 153 | 1. Let _nextValue_ be ? IteratorValue(_next_). 154 | 1. Append _nextValue_ to the end of _elements_. 155 | 1. Let _elements_ be the result of merging any _elements_ with the same [[Key]] and [[Static]]. 156 | 1. Return the Record {[[Constructor]]: _previousConstructor_, [[Elements]]: _elements_}. 157 | 158 | 159 |

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 |
163 |
164 | 165 | 166 |

FromElementDescriptor

167 |

With parameter _element_.

168 | 169 | 1. Let _obj_ be ObjectCreate(%ObjectPrototype%). 170 | 1. Perform CreateDataProperty(_obj_, `"kind"`, _element_.[[Kind]]). 171 | 1. Perform CreateDataProperty(_obj_, `"isStatic"`, _element_.[[Static]]). 172 | 1. Perform CreateDataProperty(_obj_, `"key"`, _element_.[[Key]]). 173 | 1. Perform CreateDataProperty(_obj_, `"descriptor"`, FromPropertyDescriptor(_element_.[[Descriptor]])). 174 | 1. Assert: All of the above CreateDataProperty operations return *true*. 175 | 1. Return _obj_. 176 | 177 |
178 | 179 | 180 |

ToElementDescriptor

181 |

With parameter _descriptor_.

182 | 183 | 1. Let _kind_ be ? Get(_descriptor_, `"kind"`). 184 | 1. If _kind_ is not equal to the string value `"property"`, throw a TypeError exception. 185 | 1. Let _static_ be ToBoolean(? Get(_descriptor_, `"isStatic"`)). 186 | 1. Let _key_ be ? ToString(? Get(_descriptor_, `"key"`)). 187 | 1. Let _descriptor_ be ? ToPropertyDescriptor(? Get(_descriptor_, `"descriptor"`)). 188 | 1. Return the Record {[[Kind]]: _kind_, [[Static]]: _static_, [[Key]]: _key_, [[Descriptor]]: _descriptor_}. 189 | 190 |
191 | 192 | 193 | 194 |

Class Definitions

195 |

Syntax

196 | 197 | ClassDeclaration[Yield, Default] : 198 | DecoratorList[?Yield]? `class` BindingIdentifier[?Yield] ClassTail[?Yield] 199 | [+Default] DecoratorList[?Yield]? `class` ClassTail[?Yield] 200 | 201 | ClassExpression[Yield] : 202 | DecoratorList [?Yield]? `class` BindingIdentifier[?Yield]? ClassTail[?Yield] 203 | 204 | ClassTail[Yield] : 205 | ClassHeritage[?Yield]? `{` ClassBody[?Yield]? `}` 206 | 207 | ClassHeritage[Yield] : 208 | `extends` LeftHandSideExpression[?Yield] 209 | 210 | ClassBody[Yield] : 211 | ClassElementList[?Yield] 212 | 213 | ClassElementList[Yield] : 214 | ClassElement[?Yield] 215 | ClassElementList[?Yield] ClassElement[?Yield] 216 | 217 | ClassElement[Yield] : 218 | DecoratorList[?Yield]? MethodDefinition[?Yield] 219 | DecoratorList[?Yield]? `static` MethodDefinition[?Yield] 220 | `;` 221 | 222 | 223 |

A class definition is always strict mode code.

224 |
225 | 226 | 227 | 228 |

Static Semantics: Early Errors

229 | ClassTail : ClassHeritage? `{` ClassBody `}` 230 |
    231 |
  • 232 |

    It is a Syntax Error if |ClassHeritage| is not present and the following algorithm evaluates to *true*:

    233 | 234 | 1. Let _constructor_ be ConstructorMethod of |ClassBody|. 235 | 1. If _constructor_ is ~empty~, return *false*. 236 | 1. Return HasDirectSuper of _constructor_. 237 | 238 |
  • 239 |
240 | ClassBody : ClassElementList 241 |
    242 |
  • 243 | It is a Syntax Error if PrototypePropertyNameList of |ClassElementList| contains more than one occurrence of `"constructor"`. 244 |
  • 245 |
246 | ClassElement : MethodDefinition 247 |
    248 |
  • 249 | It is a Syntax Error if PropName of |MethodDefinition| is not `"constructor"` and HasDirectSuper of |MethodDefinition| is *true*. 250 |
  • 251 |
  • 252 | It is a Syntax Error if PropName of |MethodDefinition| is `"constructor"` and SpecialMethod of |MethodDefinition| is *true*. 253 |
  • 254 |
255 | ClassElement : `static` MethodDefinition 256 |
    257 |
  • 258 | It is a Syntax Error if HasDirectSuper of |MethodDefinition| is *true*. 259 |
  • 260 |
  • 261 | It is a Syntax Error if PropName of |MethodDefinition| is `"prototype"`. 262 |
  • 263 |
264 |
265 | 266 | 267 | 268 |

Static Semantics: BoundNames

269 | 270 | ClassDeclaration : `class` BindingIdentifier ClassTail 271 | 272 | 1. Return the BoundNames of |BindingIdentifier|. 273 | 274 | ClassDeclaration : `class` ClassTail 275 | 276 | 1. Return « `"*default*"` ». 277 | 278 |
279 | 280 | 281 | 282 |

Static Semantics: ConstructorMethod

283 | ClassElementList : ClassElement 284 | 285 | 1. If |ClassElement| is the production ClassElement : `;` , return ~empty~. 286 | 1. If IsStatic of |ClassElement| is *true*, return ~empty~. 287 | 1. If PropName of |ClassElement| is not `"constructor"`, return ~empty~. 288 | 1. Return |ClassElement|. 289 | 290 | ClassElementList : ClassElementList ClassElement 291 | 292 | 1. Let _head_ be ConstructorMethod of |ClassElementList|. 293 | 1. If _head_ is not ~empty~, return _head_. 294 | 1. If |ClassElement| is the production ClassElement : `;` , return ~empty~. 295 | 1. If IsStatic of |ClassElement| is *true*, return ~empty~. 296 | 1. If PropName of |ClassElement| is not `"constructor"`, return ~empty~. 297 | 1. Return |ClassElement|. 298 | 299 | 300 |

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 |
302 |
303 | 304 | 305 | 306 |

Static Semantics: Contains

307 |

With parameter _symbol_.

308 | 309 | ClassTail : ClassHeritage? `{` ClassBody `}` 310 | 311 | 1. If _symbol_ is |ClassBody|, return *true*. 312 | 1. If _symbol_ is |ClassHeritage|, then 313 | 1. If |ClassHeritage| is present, return *true*; otherwise return *false*. 314 | 1. Let _inHeritage_ be |ClassHeritage| Contains _symbol_. 315 | 1. If _inHeritage_ is *true*, return *true*. 316 | 1. Return the result of ComputedPropertyContains for |ClassBody| with argument _symbol_. 317 | 318 | 319 |

Static semantic rules that depend upon substructure generally do not look into class bodies except for |PropertyName| productions.

320 |
321 |
322 | 323 | 324 | 325 |

Static Semantics: ComputedPropertyContains

326 |

With parameter _symbol_.

327 | 328 | ClassElementList : ClassElementList ClassElement 329 | 330 | 1. Let _inList_ be the result of ComputedPropertyContains for |ClassElementList| with argument _symbol_. 331 | 1. If _inList_ is *true*, return *true*. 332 | 1. Return the result of ComputedPropertyContains for |ClassElement| with argument _symbol_. 333 | 334 | ClassElement : MethodDefinition 335 | 336 | 1. Return the result of ComputedPropertyContains for |MethodDefinition| with argument _symbol_. 337 | 338 | ClassElement : `static` MethodDefinition 339 | 340 | 1. Return the result of ComputedPropertyContains for |MethodDefinition| with argument _symbol_. 341 | 342 | ClassElement : `;` 343 | 344 | 1. Return *false*. 345 | 346 |
347 | 348 | 349 | 350 |

Static Semantics: HasName

351 | 352 | ClassExpression : `class` ClassTail 353 | 354 | 1. Return *false*. 355 | 356 | ClassExpression : `class` BindingIdentifier ClassTail 357 | 358 | 1. Return *true*. 359 | 360 |
361 | 362 | 363 | 364 |

Static Semantics: IsConstantDeclaration

365 | 366 | 367 | ClassDeclaration : `class` BindingIdentifier ClassTail 368 | 369 | ClassDeclaration : `class` ClassTail 370 | 371 | 372 | 1. Return *false*. 373 | 374 |
375 | 376 | 377 | 378 |

Static Semantics: IsFunctionDefinition

379 | 380 | ClassExpression : `class` BindingIdentifier? ClassTail 381 | 382 | 1. Return *true*. 383 | 384 |
385 | 386 | 387 | 388 |

Static Semantics: IsStatic

389 | ClassElement : MethodDefinition 390 | 391 | 1. Return *false*. 392 | 393 | ClassElement : `static` MethodDefinition 394 | 395 | 1. Return *true*. 396 | 397 | ClassElement : `;` 398 | 399 | 1. Return *false*. 400 | 401 |
402 | 403 | 404 | 405 |

Static Semantics: NonConstructorMethodDefinitions

406 | ClassElementList : ClassElement 407 | 408 | 1. If |ClassElement| is the production ClassElement : `;` , return a new empty List. 409 | 1. If IsStatic of |ClassElement| is *false* and PropName of |ClassElement| is `"constructor"`, return a new empty List. 410 | 1. Return a List containing |ClassElement|. 411 | 412 | ClassElementList : ClassElementList ClassElement 413 | 414 | 1. Let _list_ be NonConstructorMethodDefinitions of |ClassElementList|. 415 | 1. If |ClassElement| is the production ClassElement : `;` , return _list_. 416 | 1. If IsStatic of |ClassElement| is *false* and PropName of |ClassElement| is `"constructor"`, return _list_. 417 | 1. Append |ClassElement| to the end of _list_. 418 | 1. Return _list_. 419 | 420 |
421 | 422 | 423 | 424 |

Static Semantics: PrototypePropertyNameList

425 | ClassElementList : ClassElement 426 | 427 | 1. If PropName of |ClassElement| is ~empty~, return a new empty List. 428 | 1. If IsStatic of |ClassElement| is *true*, return a new empty List. 429 | 1. Return a List containing PropName of |ClassElement|. 430 | 431 | ClassElementList : ClassElementList ClassElement 432 | 433 | 1. Let _list_ be PrototypePropertyNameList of |ClassElementList|. 434 | 1. If PropName of |ClassElement| is ~empty~, return _list_. 435 | 1. If IsStatic of |ClassElement| is *true*, return _list_. 436 | 1. Append PropName of |ClassElement| to the end of _list_. 437 | 1. Return _list_. 438 | 439 |
440 | 441 | 442 | 443 |

Static Semantics: PropName

444 | 445 | ClassElement : `;` 446 | 447 | 1. Return ~empty~. 448 | 449 |
450 | 451 | 452 | 453 |

Runtime Semantics: ClassDefinitionEvaluation

454 |

With parameter _className_.

455 | ClassTail : ClassHeritage? `{` ClassBody? `}` 456 | 457 | 1. Let _lex_ be the LexicalEnvironment of the running execution context. 458 | 1. Let _classScope_ be NewDeclarativeEnvironment(_lex_). 459 | 1. Let _classScopeEnvRec_ be _classScope_'s EnvironmentRecord. 460 | 1. If _className_ is not *undefined*, then 461 | 1. Perform _classScopeEnvRec_.CreateImmutableBinding(_className_, *true*). 462 | 1. If |ClassHeritage?| is not present, then 463 | 1. Let _protoParent_ be the intrinsic object %ObjectPrototype%. 464 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 465 | 1. Else, 466 | 1. Set the running execution context's LexicalEnvironment to _classScope_. 467 | 1. Let _superclass_ be the result of evaluating |ClassHeritage|. 468 | 1. Set the running execution context's LexicalEnvironment to _lex_. 469 | 1. ReturnIfAbrupt(_superclass_). 470 | 1. If _superclass_ is *null*, then 471 | 1. Let _protoParent_ be *null*. 472 | 1. Let _constructorParent_ be the intrinsic object %FunctionPrototype%. 473 | 1. Else if IsConstructor(_superclass_) is *false*, throw a *TypeError* exception. 474 | 1. Else, 475 | 1. Let _protoParent_ be ? Get(_superclass_, `"prototype"`). 476 | 1. If Type(_protoParent_) is neither Object nor Null, throw a *TypeError* exception. 477 | 1. Let _constructorParent_ be _superclass_. 478 | 1. Let _proto_ be ObjectCreate(_protoParent_). 479 | 1. If |ClassBody?| is not present, let _constructor_ be ~empty~. 480 | 1. Else, let _constructor_ be ConstructorMethod of |ClassBody|. 481 | 1. If _constructor_ is ~empty~, then 482 | 1. If |ClassHeritage?| is present and _protoParent_ is not *null*, then 483 | 1. Let _constructor_ be the result of parsing the source text 484 |
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 |
539 | 540 |

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 |
    544 |
  • Imperatively apply the extras, and let them naturally merge (or fail in the configurability case).
  • 545 |
  • Validate the extras as they are produced.
  • 546 |
  • Validate the entire list of extras right before they are applied.
  • 547 |
548 |

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.

554 |
555 |
556 | 557 | 558 |

Runtime Semantics: MakeFunctionUninitialized

559 |

With parameter _function_.

560 | 561 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 562 | will be driven by implementation considerations.

563 |
564 |
565 | 566 | 567 |

Runtime Semantics: MakeFunctionInitialized

568 |

With parameter _function_.

569 | 570 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 571 | will be driven by implementation considerations.

572 |
573 |
574 | 575 | 576 |

Runtime Semantics: IsUninitializedFunction

577 |

With parameter _function_.

578 | 579 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 580 | will be driven by implementation considerations.

581 |
582 |
583 | 584 | 585 |

Runtime Semantics: MakeClassElementsInitialized

586 |

With parameter _elements_.

587 | 588 | 1. For each _element_ in order from _elements_ 589 | 1. Let _desc_ be _element_.[[Descriptor]]. 590 | 1. If _desc_ has a [[Set]] field, MakeFunctionInitialized(_desc_.[[Set]]). 591 | 1. If _desc_ has a [[Get]] field, MakeFunctionInitialized(_desc_.[[Get]]). 592 | 1. If _desc_ has a [[Value]] field, and IsUninitializedFunction(_desc_.[[Value]]) is *true*, MakeFunctionInitialized(_desc_.[[Value]]). 593 | 594 | 595 |

The semantics of functions leaked to JavaScript during decoration was contentious in Munich. The exact semantics 596 | will be driven by implementation considerations.

597 |
598 |
599 | 600 | 601 | 602 |

Runtime Semantics: BindingClassDeclarationEvaluation

603 | ClassDeclaration : `class` BindingIdentifier ClassTail 604 | 605 | 1. Let _className_ be StringValue of |BindingIdentifier|. 606 | 1. Let _value_ be the result of ClassDefinitionEvaluation of |ClassTail| with argument _className_. 607 | 1. ReturnIfAbrupt(_value_). 608 | 1. Let _hasNameProperty_ be ? HasOwnProperty(_value_, `"name"`). 609 | 1. If _hasNameProperty_ is *false*, perform SetFunctionName(_value_, _className_). 610 | 1. Let _env_ be the running execution context's LexicalEnvironment. 611 | 1. Perform ? InitializeBoundName(_className_, _value_, _env_). 612 | 1. Return _value_. 613 | 614 | ClassDeclaration : `class` ClassTail 615 | 616 | 1. Return the result of ClassDefinitionEvaluation of |ClassTail| with argument *undefined*. 617 | 618 | 619 |

ClassDeclaration : `class` ClassTail 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 .

620 |
621 |
622 | 623 | 624 |

Runtime Semantics: MakeClassDefinition

625 |

With no parameters.

626 | 627 | 628 |
629 | 630 | 631 |

Runtime Semantics: DecorateElement

632 |

With parameters _element_ and _classDefinition_.

633 | 634 | 1. If _element_.[[Kind]] is `"property"`: 635 | 1. 636 | 1. Otherwise, if _element_.[[Kind]] 637 | 638 |
639 | 640 | 641 | 642 |

Runtime Semantics: Evaluation

643 | ClassDeclaration : `class` BindingIdentifier ClassTail 644 | 645 | 1. Let _status_ be the result of BindingClassDeclarationEvaluation of this |ClassDeclaration|. 646 | 1. ReturnIfAbrupt(_status_). 647 | 1. Return NormalCompletion(~empty~). 648 | 649 | 650 |

ClassDeclaration : `class` ClassTail only occurs as part of an |ExportDeclaration| and is never directly evaluated.

651 |
652 | ClassExpression : `class` BindingIdentifier? ClassTail 653 | 654 | 1. If |BindingIdentifier_opt| is not present, let _className_ be *undefined*. 655 | 1. Else, let _className_ be StringValue of |BindingIdentifier|. 656 | 1. Let _value_ be the result of ClassDefinitionEvaluation of |ClassTail| with argument _className_. 657 | 1. ReturnIfAbrupt(_value_). 658 | 1. If _className_ is not *undefined*, then 659 | 1. Let _hasNameProperty_ be ? HasOwnProperty(_value_, `"name"`). 660 | 1. If _hasNameProperty_ is *false*, then 661 | 1. Perform SetFunctionName(_value_, _className_). 662 | 1. Return NormalCompletion(_value_). 663 | 664 | 665 |

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 |
667 |
668 |
--------------------------------------------------------------------------------