@babel/plugin-proposal-decorators 7.19.6 → 7.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/CONTRIB.md +0 -396
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babel/plugin-proposal-decorators",
3
- "version": "7.19.6",
3
+ "version": "7.20.0",
4
4
  "author": "The Babel Team (https://babel.dev/team)",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -32,7 +32,7 @@
32
32
  "devDependencies": {
33
33
  "@babel/core": "^7.19.6",
34
34
  "@babel/helper-plugin-test-runner": "^7.18.6",
35
- "@babel/traverse": "^7.19.6",
35
+ "@babel/traverse": "^7.20.0",
36
36
  "@types/charcodes": "^0.2.0",
37
37
  "array.prototype.concat": "^1.0.2",
38
38
  "babel-plugin-polyfill-es-shims": "^0.7.1",
package/CONTRIB.md DELETED
@@ -1,396 +0,0 @@
1
- These are notes about the implementation of the 2021-12 decorators transform.
2
- The implementation's goals are (in descending order):
3
-
4
- 1. Being accurate to the actual proposal (e.g. not defining additional
5
- properties unless required, matching semantics exactly, etc.). This includes
6
- being able to work properly with private fields and methods.
7
- 2. Transpiling to a very minimal and minifiable output. This transform will
8
- affect each and every decorated class, so ensuring that the output is not 10x
9
- the size of the original is important.
10
- 3. Having good runtime performance. Decoration output has the potential to
11
- drastically impact startup performance, since it runs whenever a decorated
12
- class is defined. In addition, every instance of a decorated class may be
13
- impacted for certain types of decorators.
14
-
15
- All of these goals come somewhat at the expense of readability and can make the
16
- implementation difficult to understand, so these notes are meant to document the
17
- motivations behind the design.
18
-
19
- ## Overview
20
-
21
- Given a simple decorated class like this one:
22
-
23
- ```js
24
- @dec
25
- class Class {
26
- @dec a = 123;
27
-
28
- @dec static #b() {
29
- console.log('foo');
30
- }
31
-
32
- [someVal]() {}
33
-
34
- @dec
35
- @dec2
36
- accessor #c = 456;
37
- }
38
- ```
39
-
40
- It's output would be something like the following:
41
-
42
- ```js
43
- import { applyDecs } from '@babel/helpers';
44
-
45
- let _initInstance, _initClass, _initStatic, _init_a, _call_b, _computedKey, _init_c, _get_c, _set_c;
46
-
47
- let _dec = dec,
48
- _dec2 = dec,
49
- _computedKey = someVal,
50
- _dec3 = dec,
51
- _dec4 = dec2;
52
-
53
- let _Class;
54
- class Class {
55
- static {
56
- [
57
- _init_a,
58
- _call_b,
59
- _init_c,
60
- _get_c,
61
- _set_c,
62
- _Class,
63
- _initClass,
64
- _initProto,
65
- _initStatic,
66
- ] = _applyDecs(Class,
67
- [
68
- [_dec, 0, "a"],
69
- [
70
- _dec2,
71
- 7,
72
- "b",
73
- function () {
74
- console.log('foo');
75
- }
76
- ],
77
- [
78
- [_dec4, _dec5],
79
- 1,
80
- "c",
81
- function () {
82
- return this.#a;
83
- },
84
- function (value) {
85
- this.#a = value;
86
- }
87
- ]
88
- ],
89
- [dec]
90
- );
91
-
92
- _initStatic(Class);
93
- }
94
-
95
- a = (initInstance(this), _init_a(this, 123));
96
-
97
- static #b(...args) {
98
- _call_b(this, args);
99
- }
100
-
101
- [_computedKey]() {}
102
-
103
- #a = _init_c(this, 123);
104
- get #c() {
105
- return _get_c(this);
106
- }
107
- set #c(v) {
108
- _set_c(this, v);
109
- }
110
-
111
- static {
112
- initClass(C);
113
- }
114
- }
115
- ```
116
-
117
- Let's break this output down a bit:
118
-
119
- ```js
120
- let initInstance, initClass, _init_a, _call_b, _init_c, _get_c, _set_c;
121
- ```
122
-
123
- First, we need to setup some local variables outside of the class. These are
124
- for:
125
-
126
- - Decorated class field/accessor initializers
127
- - Extra initializer functions added by `addInitializers`
128
- - Private class methods
129
-
130
- These are essentially all values that cannot be defined on the class itself via
131
- `Object.defineProperty`, so we have to insert them into the class manually,
132
- ahead of time and populate them when we run our decorators.
133
-
134
- ```js
135
- let _dec = dec,
136
- _dec2 = dec,
137
- _computedKey = someVal,
138
- _dec3 = dec,
139
- _dec4 = dec2;
140
- ```
141
-
142
- Next up, we define and evaluate the decorator expressions. The reason we
143
- do this _before_ defining the class is because we must interleave decorator
144
- expressions with computed property key expressions, since computed properties
145
- and decorators can run arbitrary code which can modify the runtime of subsequent
146
- decorators or computed property keys.
147
-
148
- ```js
149
- let _Class;
150
- class Class {
151
- ```
152
-
153
- This class is being decorated directly, which means that the decorator may
154
- replace the class itself. Class bindings are not mutable, so we need to create a
155
- new `let` variable for the decorated class.
156
-
157
-
158
- ```js
159
- static {
160
- [
161
- _init_a,
162
- _call_b,
163
- _init_c,
164
- _get_c,
165
- _set_c,
166
- _Class,
167
- _initClass,
168
- _initProto,
169
- _initStatic,
170
- ] = _applyDecs(Class,
171
- [
172
- [_dec, 0, "a"],
173
- [
174
- _dec2,
175
- 7,
176
- "b",
177
- function () {
178
- console.log('foo');
179
- }
180
- ],
181
- [
182
- [_dec4, _dec5],
183
- 1,
184
- "c",
185
- function () {
186
- return this.#a;
187
- },
188
- function (value) {
189
- this.#a = value;
190
- }
191
- ]
192
- ],
193
- [dec]
194
- );
195
-
196
- _initStatic(Class);
197
- }
198
- ```
199
-
200
- Next, we immediately define a `static` block which actually applies the
201
- decorators. This is important because we must apply the decorators _after_ the
202
- class prototype has been fully setup, but _before_ static fields are run, since
203
- static fields should only see the decorated version of the class.
204
-
205
- We apply the decorators to class elements and the class itself, and the
206
- application returns an array of values that are used to populate all of the
207
- local variables we defined earlier. The array's order is fully deterministic, so
208
- we can assign the values based on an index we can calculate ahead of time.
209
-
210
- Another important thing to note here is that we're passing some functions here.
211
- These are for private methods and accessors, which cannot be replaced directly
212
- so we have to extract their code so it can be decorated. Because we define these
213
- within the static block, they can access any private identifiers which were
214
- defined within the class, so it's not an issue that we're extracting the method
215
- logic here.
216
-
217
- We'll come back to `applyDecs` in a bit to dig into what its format is exactly,
218
- but now let's dig into the new definitions of our class elements.
219
-
220
- ```js
221
- a = (_initInstance(this), _init_a(this, 123));
222
- ```
223
-
224
- Alright, so previously this was a simple class field. Since it's the first field
225
- on the class, we've updated it to immediately call `initInstance` in its
226
- initializer. This calls any initializers added with `addInitializer` for all of
227
- the per-class values (methods and accessors), which should all be setup on the
228
- instance before class fields are assigned. Then, it calls `_init_a` to get the
229
- initial value of the field, which allows initializers returned from the
230
- decorator to intercept and decorate it. It's important that the initial value
231
- is used/defined _within_ the class body, because initializers can now refer to
232
- private class fields, e.g. `a = this.#b` is a valid field initializer and would
233
- become `a = _init_a(this, this.#b)`, which would also be valid. We cannot
234
- extract initializer code, or any other code, from the class body because of
235
- this.
236
-
237
- Overall, this decoration is pretty straightforward other than the fact that we
238
- have to reference `_init_a` externally.
239
-
240
- ```js
241
- static #b(...args) {
242
- _call_b(this, args);
243
- }
244
- ```
245
-
246
- Next up, we have a private static class method `#b`. This one is a bit more
247
- complex, as our definition has been broken out into 2 parts:
248
-
249
- 1. `static #b`: This is the method itself, which being a private method we
250
- cannot overwrite with `defineProperty`. We also can't convert it into a
251
- private field because that would change its semantics (would make it
252
- writable). So, we instead have it proxy to the locally scoped `_call_b`
253
- variable, which will be populated with the fully decorated method.
254
- 2. The definition of the method, kept in `_call_b`. As we mentioned above, the
255
- original method's code is moved during the decoration process, and the wrapped
256
- version is populated in `_call_b` and called whenever the private method is
257
- called.
258
-
259
- ```js
260
- [_computedKey]() {}
261
- ```
262
-
263
- Next is the undecorated method with a computed key. This uses the previously
264
- calculated and stored computed key.
265
-
266
- ```js
267
- #a = _init_c(this, 123);
268
- get #c() {
269
- return _get_c(this);
270
- }
271
- set #c(v) {
272
- _set_c(this, v);
273
- }
274
- ```
275
-
276
- Next up, we have the output for `accessor #c`. This is the most complicated
277
- case, since we have to transpile the decorators, the `accessor` keyword, and
278
- target a private field. Breaking it down piece by piece:
279
-
280
- ```js
281
- #a = _init_c(this, 123);
282
- ```
283
-
284
- `accessor #c` desugars to a getter and setter which are backed by a new private
285
- field, `#a`. Like before, the name of this field doesn't really matter, we'll
286
- just generate a short, unique name. We call the decorated initializer for `#c`
287
- and return that value to assign to the field.
288
-
289
- ```js
290
- get #c() {
291
- return _get_c(this);
292
- }
293
- set #c(v) {
294
- _set_c(this, v);
295
- }
296
- ```
297
-
298
- Next, we have the getter and setter for `#c` itself. These methods defer to
299
- the `_get_c` and `_set_c` local variables, which will be the decorated versions
300
- of the two getter functions that we passed for decoration in the static block
301
- above. Those two functions are essentially just accessors for the private `#a`
302
- field, but the decorator may add additional logic to them.
303
-
304
- ```js
305
- static {
306
- _initClass(_Class);
307
- }
308
- ```
309
-
310
- Finally, we call `_initClass` in another static block, running any class and
311
- static method initializers on the final class. This is done in a static block
312
- for convenience with class expressions, but it could run immediately after the
313
- class is defined.
314
-
315
- Ok, so now that we understand the general output, let's go back to `applyDecs`:
316
-
317
- ```js
318
- [
319
- _init_a,
320
- _call_b,
321
- _init_c,
322
- _get_c,
323
- _set_c,
324
- _Class,
325
- _initClass,
326
- _initProto,
327
- _initStatic,
328
- ] = _applyDecs(Class,
329
- [
330
- [_dec, 0, "a"],
331
- [
332
- _dec2,
333
- 7,
334
- "b",
335
- function () {
336
- console.log('foo');
337
- }
338
- ],
339
- [
340
- [_dec4, _dec5],
341
- 1,
342
- "c",
343
- function () {
344
- return this.#a;
345
- },
346
- function (value) {
347
- this.#a = value;
348
- }
349
- ]
350
- ],
351
- [dec]
352
- );
353
- ```
354
-
355
- `applyDecs` takes all of the decorators for the class and applies them. It
356
- receives the following arguments:
357
-
358
- 1. The class itself
359
- 2. Decorators to apply to class elements
360
- 3. Decorators to apply to the class itself
361
-
362
- The format of the data is designed to be as minimal as possible. Here's an
363
- annotated version of the member descriptors:
364
-
365
- ```js
366
- [
367
- // List of decorators to apply to the field. Array if multiple decorators,
368
- // otherwise just the single decorator itself.
369
- dec,
370
-
371
- // The type of the decorator, represented as an enum. Static-ness is also
372
- // encoded by adding 5 to the values
373
- // 0 === FIELD
374
- // 1 === ACCESSOR
375
- // 2 === METHOD
376
- // 3 === GETTER
377
- // 4 === SETTER
378
- // 5 === FIELD + STATIC
379
- // 6 === ACCESSOR + STATIC
380
- // 7 === METHOD + STATIC
381
- // 8 === GETTER + STATIC
382
- // 9 === SETTER + STATIC
383
- 1,
384
-
385
- // The name of the member
386
- 'y',
387
-
388
- // Optional fourth and fifth values, these are functions passed for private
389
- // decorators
390
- function() {}
391
- ],
392
- ```
393
-
394
- Static and prototype decorators are all described like this. For class
395
- decorators, it's just the list of decorators since no other context
396
- is necessary.