From 20d4b6dc82a53b78209d60ec7991987cdbcf8a18 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Thu, 10 Jan 2019 00:41:06 +0100 Subject: [PATCH] Normative: Name getter/setters as kind: "accessor" This doesn't change the expressiveness of decorators, but it is designed to feel more intuitive when programming. --- TABLE.md | 6 +++--- TAXONOMY.md | 8 ++++---- friend.js | 6 +++--- spec.html | 36 +++++++++++++++++++++++++----------- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/TABLE.md b/TABLE.md index 1520c80..1837451 100644 --- a/TABLE.md +++ b/TABLE.md @@ -2,7 +2,7 @@ | **parameter descriptor** | **`@decorator`
`class`** | **`@decorator`
`method()`** | **`@decorator`
`field`** | **`@decorator`
`get field()`
`set field()`**| |----------------------------|------------------------------------------|---------------------------------------------|------------------------------------------------------------------|-----------------------------------------------------| |`{` | | | | | -|` kind:` |`"class"` |`"method"` |`"field"` |`"method"` 4 | +|` kind:` |`"class"` |`"method"` |`"field"` |`"accessor"` 4 | |` elements:` |*Array of member descriptors* 1| - | - | - | |` key:` | - | *method name* |*property name* |*property name* | |` placement:` | - |`"prototype" \|\| "static"` |`"own" \|\| "static"` |`"prototype" \|\| "static"` | @@ -22,14 +22,14 @@ 3 when `kind` is `field`, don't include the value into the `value` and the value, if it exists, is returned by `initialize` function. -4 when the decorator is apply over a getter/setter `kind` is `method` and `get` or `set` has value. +4 when the decorator is apply over a getter/setter `kind` is `accessor` and `get` or `set` has value. 5 when `get` or `set` has value, the property descriptor doesn't include `writable` value. | **return descriptor (optional)** | **`class`** | **`method()`** | **`field`** | **`getter/setter`** | **Hooks** | |----------------------------------|-------------------------------------------|------------------------------------------|-----------------------------------------------------|------------------------------------------|------------------------------------------| |`{` | | | | | | -|` kind:` |`"class"` |`"method"` |`"field"` |`"method"` |`"hook"` 11 | +|` kind:` |`"class"` |`"method"` |`"field"` |`"accessor"` |`"hook"` 11 | |` elements:` |*Array of member descriptors* 6 | - | - | - | - | |` key:` | - | *method name* 8 |*field name* 8 |*field name* 8 | - | |` placement:` | - |`"prototype" \|\| "static" \|\| "own"` |`"prototype" \|\| "static" \|\| "own"` |`"prototype" \|\| "static" \|\| "own"` |`"prototype" \|\| "static" \|\| "own"` | diff --git a/TAXONOMY.md b/TAXONOMY.md index 8b02df7..f9a35eb 100644 --- a/TAXONOMY.md +++ b/TAXONOMY.md @@ -81,7 +81,7 @@ Decorator reification (from the existing decorator proposal): ```js { - kind: "method", + kind: "accessor", key: "foo", placement: "static", get: function foo() {}, @@ -168,7 +168,7 @@ Decorator reification (from the existing decorator proposal): ```js { - kind: "method", + kind: "accessor", key: "foo", placement: "prototype", get: function foo() {}, @@ -255,7 +255,7 @@ Decorator reification: ```js { - kind: "method", + kind: "accessor", key: decorators.PrivateName("foo"), placement: "static", get: function foo() {}, @@ -338,7 +338,7 @@ Decorator reification: ```js { - kind: "method", + kind: "accessor", key: decorators.PrivateName("foo"), placement: "own", get: function foo() {}, diff --git a/friend.js b/friend.js index 741ab9c..baebc8b 100644 --- a/friend.js +++ b/friend.js @@ -78,7 +78,7 @@ export function inherit(descriptor) { let superKey; let keyString = key.description; return { - kind: "method", + kind: "accessor", key, placement, get() { return superKey.get(this); }, @@ -207,7 +207,7 @@ export function abstract(descriptor) { return { key, - kind: "method", + kind: "accessor", placement: "own", get() { return internalKey.get(this); @@ -249,7 +249,7 @@ export function override(descriptor) { let internalKey; let keyString = key.description; return { - kind: "method", + kind: "accessor", key, placement, // All reads of the method read the underlying shared internal diff --git a/spec.html b/spec.html index 23d4558..f409dd6 100644 --- a/spec.html +++ b/spec.html @@ -171,7 +171,7 @@

The ElementDescriptor Specification Type

Field Name Value - [[Kind]] One of `"method"`, `"field"` or `"hook"` + [[Kind]] One of `"method"`, `"accessor"`, `"field"` or `"hook"` [[Key]] A Property Key or %PrivateName% object [[Descriptor]] A Property Descriptor [[Placement]] One of `"static"`, `"prototype"`, or `"own"` @@ -187,7 +187,7 @@

The ElementDescriptor Specification Type

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

@@ -429,7 +441,7 @@

CoalesceClassElements ( _elements_ )

1. Assert: _elements_ is a List of ElementDescriptor Records. 1. Let _newElements_ be an empty List. 1. For _element_ in _elements_, - 1. If _element_.[[Kind]] is `"method"` and _newElements_ contains a Record _other_ where _other_.[[Kind]] is `"method"`, _other_.[[Key]] is _element_.[[Key]], and _other_.[[Placement]] is _element_.[[Placement]], + 1. If _element_.[[Kind]] is `"method"` or `"accessor"`, and _newElements_ contains a Record _other_ where _other_.[[Kind]] is `"method"` or `"accessor"`, _other_.[[Key]] is _element_.[[Key]], and _other_.[[Placement]] is _element_.[[Placement]], 1. If IsDataDescriptor(_element_.[[Descriptor]]) is *true* or IsDataDescriptor(_other_.[[Descriptor]]) is *true*, then 1. Assert: _element_.[[Key]] is not a Private Name. 1. Assert: _element_.[[Descriptor]].[[Configurable]] is *true*, and _other_.[[Descriptor]].[[Configurable]] is *true*. @@ -454,7 +466,7 @@

InitializeInstanceElements ( _O_, _constructor_ )

1. Assert: Assert _constructor_ is an ECMAScript function object. 1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. 1. For each item _element_ in order from _elements_, - 1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"method"`, + 1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"method"` or `"accessor"`, 1. Perform ? DefineClassElement(_O_, _element_). 1. For each item _element_ in order from _elements_, 1. If _element_.[[Placement]] is `"own"` and _element_.[[Kind]] is `"field"`, @@ -477,7 +489,7 @@

InitializeClassElements(_F_, _proto_)

1. Let _elements_ be the value of _F_'s [[Elements]] internal slot. 1. For each item _element_ in order from _elements_, 1. Assert: If _element_.[[Placement]] is `"prototype"` or `"static"`, and if _element_.[[Kind]] is not `"hook"`, then _element_.[[Key]] is not a Private Name. - 1. If _element_.[[Kind]] is `"method"` and _element_.[[Placement]] is `"static"` or `"prototype"`, + 1. If _element_.[[Kind]] is `"method"` or `"accessor"` and _element_.[[Placement]] is `"static"` or `"prototype"`, 1. Let _receiver_ be _F_ if _element_.[[Placement]] is `"static"`, else let _receiver_ be _proto_. 1. Perform ? DefineClassElement(_receiver_, _element_). 1. For each item _element_ in order from _elements_, @@ -654,13 +666,13 @@

CreateIntrinsics ( _realmRec_ )

Decorator semantics

Decorator Functions

-

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

+

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

Element Descriptors

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


         interface ElementDescriptor {
-          kind: "method", "hook", or "field"
+          kind: "method", "accessor", "hook", or "field"
           key: String, Symbol or Private Name,
           placement: "static", "prototype", or "own"
           ...PropertyDescriptor,
@@ -826,14 +838,14 @@ 

FromElementDescriptors ( _elements_ )

FromElementDescriptor ( _element_ )

1. Assert: _element_ is an ElementDescriptor Record. - 1. If _element_.[[Kind]] is `"method"` or `"field"`, + 1. If _element_.[[Kind]] is `"method"`, `"accessor"`, or `"field"`, 1. Let _obj_ be ! FromPropertyDescriptor(_element_.[[Descriptor]])). 1. Otherwise, 1. Let _obj_ be ! ObjectCreate(%ObjectPrototype%). 1. Let _desc_ be PropertyDescriptor{ [[Value]]: `"Descriptor"`, [[Writable]]: *false*, [[Enumerable]]: *false*, [[Configurable]]: *true* }. 1. Perform ! DefinePropertyOrThrow(_obj_, @@toStringTag, _desc_). 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"kind"`, _element_.[[Kind]]). - 1. If _element_.[[Kind]] is `"method"` or `"field"`, + 1. If _element_.[[Kind]] is `"method"`, `"accessor"`, or `"field"`, 1. Let _key_ be _element_.[[Key]]. 1. If _key_ is a Private Name, set _key_ to ? PrivateNameObject(_key_). 1. Perform ! CreateDataPropertyOrThrow(_obj_, `"key"`, _key_). @@ -875,7 +887,7 @@

ToElementDescriptor ( _elementObject_ )

1. Assert: Type(_elementObject_) is Object. 1. Let _kind_ be ? ToString(? Get(_elementObject_, `"kind"`)). - 1. If _kind_ is not one of `"hook"`, `"method"`, or `"field"`, throw a *TypeError* exception. + 1. If _kind_ is not one of `"hook"`, `"method"`, `"accessor"` or `"field"`, throw a *TypeError* exception. 1. Let _key_ be ? Get(_elementObject_, `"key"`). 1. If _kind_ is `"hook"`, 1. If _key_ is not *undefined*, throw a *TypeError* exception. @@ -888,6 +900,8 @@

ToElementDescriptor ( _elementObject_ )

1. If _descriptor_ has an [[Enumerable]] field and _descriptor_.[[Enumerable]] is *true*, throw a *TypeError* exception. 1. If _descriptor_ has an [[Configurable]] field and _descriptor_.[[Configurable]] is *true*, throw a *TypeError* exception. 1. If _placement_ is `"prototype"`, throw a *TypeError* exception. + 1. If _kind_ is `"accessor"` or `"hook"` and IsDataDescriptor(_descriptor_) is *true*, throw a *TypeError* exception. + 1. If _kind_ is `"field"`, `"method"` or `"hook"`, and IsAccessorDescriptor(_descriptor_) is *true*, throw a *TypeError* exception. 1. If _kind_ is `"field"`, 1. If _descriptor_ has a [[Get]], [[Set]] or [[Value]] field, throw a *TypeError* exception. 1. Let _initialize_ be ? Get(_elementObject_, `"initialize"`). @@ -912,7 +926,7 @@

ToElementDescriptor ( _elementObject_ )

1. Let _elements_ be ? Get(_elementObject_, `"elements"`). 1. If _elements_ is not *undefined*, throw a *TypeError* exception. 1. Let _element_ be the ElementDescriptor { [[Kind]]: _kind_, [[Placement]]: _placement_ }. - 1. If _kind_ is `"method"` or `"field", + 1. If _kind_ is `"method"`, `"accessor"`, or `"field", 1. Set _element_.[[Key]] to _key_. 1. Set _element_.[[Descriptor]] to _descriptor_. 1. If _kind_ is `"field"`,