forked from daren.hsu/line_push
update
This commit is contained in:
+396
@@ -0,0 +1,396 @@
|
||||
These are notes about the implementation of the 2021-12 decorators transform.
|
||||
The implementation's goals are (in descending order):
|
||||
|
||||
1. Being accurate to the actual proposal (e.g. not defining additional
|
||||
properties unless required, matching semantics exactly, etc.). This includes
|
||||
being able to work properly with private fields and methods.
|
||||
2. Transpiling to a very minimal and minifiable output. This transform will
|
||||
affect each and every decorated class, so ensuring that the output is not 10x
|
||||
the size of the original is important.
|
||||
3. Having good runtime performance. Decoration output has the potential to
|
||||
drastically impact startup performance, since it runs whenever a decorated
|
||||
class is defined. In addition, every instance of a decorated class may be
|
||||
impacted for certain types of decorators.
|
||||
|
||||
All of these goals come somewhat at the expense of readability and can make the
|
||||
implementation difficult to understand, so these notes are meant to document the
|
||||
motivations behind the design.
|
||||
|
||||
## Overview
|
||||
|
||||
Given a simple decorated class like this one:
|
||||
|
||||
```js
|
||||
@dec
|
||||
class Class {
|
||||
@dec a = 123;
|
||||
|
||||
@dec static #b() {
|
||||
console.log('foo');
|
||||
}
|
||||
|
||||
[someVal]() {}
|
||||
|
||||
@dec
|
||||
@dec2
|
||||
accessor #c = 456;
|
||||
}
|
||||
```
|
||||
|
||||
It's output would be something like the following:
|
||||
|
||||
```js
|
||||
import { applyDecs } from '@babel/helpers';
|
||||
|
||||
let _initInstance, _initClass, _initStatic, _init_a, _call_b, _computedKey, _init_c, _get_c, _set_c;
|
||||
|
||||
let _dec = dec,
|
||||
_dec2 = dec,
|
||||
_computedKey = someVal,
|
||||
_dec3 = dec,
|
||||
_dec4 = dec2;
|
||||
|
||||
let _Class;
|
||||
class Class {
|
||||
static {
|
||||
[
|
||||
_init_a,
|
||||
_call_b,
|
||||
_init_c,
|
||||
_get_c,
|
||||
_set_c,
|
||||
_Class,
|
||||
_initClass,
|
||||
_initProto,
|
||||
_initStatic,
|
||||
] = _applyDecs(Class,
|
||||
[
|
||||
[_dec, 0, "a"],
|
||||
[
|
||||
_dec2,
|
||||
7,
|
||||
"b",
|
||||
function () {
|
||||
console.log('foo');
|
||||
}
|
||||
],
|
||||
[
|
||||
[_dec4, _dec5],
|
||||
1,
|
||||
"c",
|
||||
function () {
|
||||
return this.#a;
|
||||
},
|
||||
function (value) {
|
||||
this.#a = value;
|
||||
}
|
||||
]
|
||||
],
|
||||
[dec]
|
||||
);
|
||||
|
||||
_initStatic(Class);
|
||||
}
|
||||
|
||||
a = (initInstance(this), _init_a(this, 123));
|
||||
|
||||
static #b(...args) {
|
||||
_call_b(this, args);
|
||||
}
|
||||
|
||||
[_computedKey]() {}
|
||||
|
||||
#a = _init_c(this, 123);
|
||||
get #c() {
|
||||
return _get_c(this);
|
||||
}
|
||||
set #c(v) {
|
||||
_set_c(this, v);
|
||||
}
|
||||
|
||||
static {
|
||||
initClass(C);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let's break this output down a bit:
|
||||
|
||||
```js
|
||||
let initInstance, initClass, _init_a, _call_b, _init_c, _get_c, _set_c;
|
||||
```
|
||||
|
||||
First, we need to setup some local variables outside of the class. These are
|
||||
for:
|
||||
|
||||
- Decorated class field/accessor initializers
|
||||
- Extra initializer functions added by `addInitializers`
|
||||
- Private class methods
|
||||
|
||||
These are essentially all values that cannot be defined on the class itself via
|
||||
`Object.defineProperty`, so we have to insert them into the class manually,
|
||||
ahead of time and populate them when we run our decorators.
|
||||
|
||||
```js
|
||||
let _dec = dec,
|
||||
_dec2 = dec,
|
||||
_computedKey = someVal,
|
||||
_dec3 = dec,
|
||||
_dec4 = dec2;
|
||||
```
|
||||
|
||||
Next up, we define and evaluate the decorator expressions. The reason we
|
||||
do this _before_ defining the class is because we must interleave decorator
|
||||
expressions with computed property key expressions, since computed properties
|
||||
and decorators can run arbitrary code which can modify the runtime of subsequent
|
||||
decorators or computed property keys.
|
||||
|
||||
```js
|
||||
let _Class;
|
||||
class Class {
|
||||
```
|
||||
|
||||
This class is being decorated directly, which means that the decorator may
|
||||
replace the class itself. Class bindings are not mutable, so we need to create a
|
||||
new `let` variable for the decorated class.
|
||||
|
||||
|
||||
```js
|
||||
static {
|
||||
[
|
||||
_init_a,
|
||||
_call_b,
|
||||
_init_c,
|
||||
_get_c,
|
||||
_set_c,
|
||||
_Class,
|
||||
_initClass,
|
||||
_initProto,
|
||||
_initStatic,
|
||||
] = _applyDecs(Class,
|
||||
[
|
||||
[_dec, 0, "a"],
|
||||
[
|
||||
_dec2,
|
||||
7,
|
||||
"b",
|
||||
function () {
|
||||
console.log('foo');
|
||||
}
|
||||
],
|
||||
[
|
||||
[_dec4, _dec5],
|
||||
1,
|
||||
"c",
|
||||
function () {
|
||||
return this.#a;
|
||||
},
|
||||
function (value) {
|
||||
this.#a = value;
|
||||
}
|
||||
]
|
||||
],
|
||||
[dec]
|
||||
);
|
||||
|
||||
_initStatic(Class);
|
||||
}
|
||||
```
|
||||
|
||||
Next, we immediately define a `static` block which actually applies the
|
||||
decorators. This is important because we must apply the decorators _after_ the
|
||||
class prototype has been fully setup, but _before_ static fields are run, since
|
||||
static fields should only see the decorated version of the class.
|
||||
|
||||
We apply the decorators to class elements and the class itself, and the
|
||||
application returns an array of values that are used to populate all of the
|
||||
local variables we defined earlier. The array's order is fully deterministic, so
|
||||
we can assign the values based on an index we can calculate ahead of time.
|
||||
|
||||
Another important thing to note here is that we're passing some functions here.
|
||||
These are for private methods and accessors, which cannot be replaced directly
|
||||
so we have to extract their code so it can be decorated. Because we define these
|
||||
within the static block, they can access any private identifiers which were
|
||||
defined within the class, so it's not an issue that we're extracting the method
|
||||
logic here.
|
||||
|
||||
We'll come back to `applyDecs` in a bit to dig into what its format is exactly,
|
||||
but now let's dig into the new definitions of our class elements.
|
||||
|
||||
```js
|
||||
a = (_initInstance(this), _init_a(this, 123));
|
||||
```
|
||||
|
||||
Alright, so previously this was a simple class field. Since it's the first field
|
||||
on the class, we've updated it to immediately call `initInstance` in its
|
||||
initializer. This calls any initializers added with `addInitializer` for all of
|
||||
the per-class values (methods and accessors), which should all be setup on the
|
||||
instance before class fields are assigned. Then, it calls `_init_a` to get the
|
||||
initial value of the field, which allows initializers returned from the
|
||||
decorator to intercept and decorate it. It's important that the initial value
|
||||
is used/defined _within_ the class body, because initializers can now refer to
|
||||
private class fields, e.g. `a = this.#b` is a valid field initializer and would
|
||||
become `a = _init_a(this, this.#b)`, which would also be valid. We cannot
|
||||
extract initializer code, or any other code, from the class body because of
|
||||
this.
|
||||
|
||||
Overall, this decoration is pretty straightforward other than the fact that we
|
||||
have to reference `_init_a` externally.
|
||||
|
||||
```js
|
||||
static #b(...args) {
|
||||
_call_b(this, args);
|
||||
}
|
||||
```
|
||||
|
||||
Next up, we have a private static class method `#b`. This one is a bit more
|
||||
complex, as our definition has been broken out into 2 parts:
|
||||
|
||||
1. `static #b`: This is the method itself, which being a private method we
|
||||
cannot overwrite with `defineProperty`. We also can't convert it into a
|
||||
private field because that would change its semantics (would make it
|
||||
writable). So, we instead have it proxy to the locally scoped `_call_b`
|
||||
variable, which will be populated with the fully decorated method.
|
||||
2. The definition of the method, kept in `_call_b`. As we mentioned above, the
|
||||
original method's code is moved during the decoration process, and the wrapped
|
||||
version is populated in `_call_b` and called whenever the private method is
|
||||
called.
|
||||
|
||||
```js
|
||||
[_computedKey]() {}
|
||||
```
|
||||
|
||||
Next is the undecorated method with a computed key. This uses the previously
|
||||
calculated and stored computed key.
|
||||
|
||||
```js
|
||||
#a = _init_c(this, 123);
|
||||
get #c() {
|
||||
return _get_c(this);
|
||||
}
|
||||
set #c(v) {
|
||||
_set_c(this, v);
|
||||
}
|
||||
```
|
||||
|
||||
Next up, we have the output for `accessor #c`. This is the most complicated
|
||||
case, since we have to transpile the decorators, the `accessor` keyword, and
|
||||
target a private field. Breaking it down piece by piece:
|
||||
|
||||
```js
|
||||
#a = _init_c(this, 123);
|
||||
```
|
||||
|
||||
`accessor #c` desugars to a getter and setter which are backed by a new private
|
||||
field, `#a`. Like before, the name of this field doesn't really matter, we'll
|
||||
just generate a short, unique name. We call the decorated initializer for `#c`
|
||||
and return that value to assign to the field.
|
||||
|
||||
```js
|
||||
get #c() {
|
||||
return _get_c(this);
|
||||
}
|
||||
set #c(v) {
|
||||
_set_c(this, v);
|
||||
}
|
||||
```
|
||||
|
||||
Next, we have the getter and setter for `#c` itself. These methods defer to
|
||||
the `_get_c` and `_set_c` local variables, which will be the decorated versions
|
||||
of the two getter functions that we passed for decoration in the static block
|
||||
above. Those two functions are essentially just accessors for the private `#a`
|
||||
field, but the decorator may add additional logic to them.
|
||||
|
||||
```js
|
||||
static {
|
||||
_initClass(_Class);
|
||||
}
|
||||
```
|
||||
|
||||
Finally, we call `_initClass` in another static block, running any class and
|
||||
static method initializers on the final class. This is done in a static block
|
||||
for convenience with class expressions, but it could run immediately after the
|
||||
class is defined.
|
||||
|
||||
Ok, so now that we understand the general output, let's go back to `applyDecs`:
|
||||
|
||||
```js
|
||||
[
|
||||
_init_a,
|
||||
_call_b,
|
||||
_init_c,
|
||||
_get_c,
|
||||
_set_c,
|
||||
_Class,
|
||||
_initClass,
|
||||
_initProto,
|
||||
_initStatic,
|
||||
] = _applyDecs(Class,
|
||||
[
|
||||
[_dec, 0, "a"],
|
||||
[
|
||||
_dec2,
|
||||
7,
|
||||
"b",
|
||||
function () {
|
||||
console.log('foo');
|
||||
}
|
||||
],
|
||||
[
|
||||
[_dec4, _dec5],
|
||||
1,
|
||||
"c",
|
||||
function () {
|
||||
return this.#a;
|
||||
},
|
||||
function (value) {
|
||||
this.#a = value;
|
||||
}
|
||||
]
|
||||
],
|
||||
[dec]
|
||||
);
|
||||
```
|
||||
|
||||
`applyDecs` takes all of the decorators for the class and applies them. It
|
||||
receives the following arguments:
|
||||
|
||||
1. The class itself
|
||||
2. Decorators to apply to class elements
|
||||
3. Decorators to apply to the class itself
|
||||
|
||||
The format of the data is designed to be as minimal as possible. Here's an
|
||||
annotated version of the member descriptors:
|
||||
|
||||
```js
|
||||
[
|
||||
// List of decorators to apply to the field. Array if multiple decorators,
|
||||
// otherwise just the single decorator itself.
|
||||
dec,
|
||||
|
||||
// The type of the decorator, represented as an enum. Static-ness is also
|
||||
// encoded by adding 5 to the values
|
||||
// 0 === FIELD
|
||||
// 1 === ACCESSOR
|
||||
// 2 === METHOD
|
||||
// 3 === GETTER
|
||||
// 4 === SETTER
|
||||
// 5 === FIELD + STATIC
|
||||
// 6 === ACCESSOR + STATIC
|
||||
// 7 === METHOD + STATIC
|
||||
// 8 === GETTER + STATIC
|
||||
// 9 === SETTER + STATIC
|
||||
1,
|
||||
|
||||
// The name of the member
|
||||
'y',
|
||||
|
||||
// Optional fourth and fifth values, these are functions passed for private
|
||||
// decorators
|
||||
function() {}
|
||||
],
|
||||
```
|
||||
|
||||
Static and prototype decorators are all described like this. For class
|
||||
decorators, it's just the list of decorators since no other context
|
||||
is necessary.
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
> Compile class and object decorators to ES5
|
||||
|
||||
See our website [@babel/plugin-proposal-decorators](https://babeljs.io/docs/en/next/babel-plugin-proposal-decorators.html) for more information.
|
||||
See our website [@babel/plugin-proposal-decorators](https://babeljs.io/docs/en/babel-plugin-proposal-decorators) for more information.
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
+19
-50
@@ -7,72 +7,41 @@ exports.default = void 0;
|
||||
|
||||
var _helperPluginUtils = require("@babel/helper-plugin-utils");
|
||||
|
||||
var _pluginSyntaxDecorators = _interopRequireDefault(require("@babel/plugin-syntax-decorators"));
|
||||
var _pluginSyntaxDecorators = require("@babel/plugin-syntax-decorators");
|
||||
|
||||
var _helperCreateClassFeaturesPlugin = require("@babel/helper-create-class-features-plugin");
|
||||
|
||||
var _transformerLegacy = _interopRequireDefault(require("./transformer-legacy"));
|
||||
var _transformerLegacy = require("./transformer-legacy");
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
var _transformer = require("./transformer-2021-12");
|
||||
|
||||
var _default = (0, _helperPluginUtils.declare)((api, options) => {
|
||||
api.assertVersion(7);
|
||||
{
|
||||
var {
|
||||
legacy
|
||||
} = options;
|
||||
}
|
||||
const {
|
||||
legacy = false
|
||||
version
|
||||
} = options;
|
||||
|
||||
if (typeof legacy !== "boolean") {
|
||||
throw new Error("'legacy' must be a boolean.");
|
||||
}
|
||||
|
||||
const {
|
||||
decoratorsBeforeExport
|
||||
} = options;
|
||||
|
||||
if (decoratorsBeforeExport === undefined) {
|
||||
if (!legacy) {
|
||||
throw new Error("The decorators plugin requires a 'decoratorsBeforeExport' option," + " whose value must be a boolean. If you want to use the legacy" + " decorators semantics, you can set the 'legacy: true' option.");
|
||||
}
|
||||
} else {
|
||||
if (legacy) {
|
||||
throw new Error("'decoratorsBeforeExport' can't be used with legacy decorators.");
|
||||
}
|
||||
|
||||
if (typeof decoratorsBeforeExport !== "boolean") {
|
||||
throw new Error("'decoratorsBeforeExport' must be a boolean.");
|
||||
}
|
||||
}
|
||||
|
||||
if (legacy) {
|
||||
if (legacy || version === "legacy") {
|
||||
return {
|
||||
name: "proposal-decorators",
|
||||
inherits: _pluginSyntaxDecorators.default,
|
||||
|
||||
manipulateOptions({
|
||||
generatorOpts
|
||||
}) {
|
||||
generatorOpts.decoratorsBeforeExport = decoratorsBeforeExport;
|
||||
},
|
||||
|
||||
visitor: _transformerLegacy.default
|
||||
};
|
||||
} else if (version === "2021-12") {
|
||||
return (0, _transformer.default)(api, options);
|
||||
} else {
|
||||
return (0, _helperCreateClassFeaturesPlugin.createClassFeaturePlugin)({
|
||||
name: "proposal-decorators",
|
||||
api,
|
||||
feature: _helperCreateClassFeaturesPlugin.FEATURES.decorators,
|
||||
inherits: _pluginSyntaxDecorators.default
|
||||
});
|
||||
}
|
||||
|
||||
return (0, _helperCreateClassFeaturesPlugin.createClassFeaturePlugin)({
|
||||
name: "proposal-decorators",
|
||||
feature: _helperCreateClassFeaturesPlugin.FEATURES.decorators,
|
||||
|
||||
manipulateOptions({
|
||||
generatorOpts,
|
||||
parserOpts
|
||||
}) {
|
||||
parserOpts.plugins.push(["decorators", {
|
||||
decoratorsBeforeExport
|
||||
}]);
|
||||
generatorOpts.decoratorsBeforeExport = decoratorsBeforeExport;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
exports.default = _default;
|
||||
+645
@@ -0,0 +1,645 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = _default;
|
||||
|
||||
var _core = require("@babel/core");
|
||||
|
||||
var _pluginSyntaxDecorators = require("@babel/plugin-syntax-decorators");
|
||||
|
||||
var _helperReplaceSupers = require("@babel/helper-replace-supers");
|
||||
|
||||
var _helperSplitExportDeclaration = require("@babel/helper-split-export-declaration");
|
||||
|
||||
function incrementId(id, idx = id.length - 1) {
|
||||
if (idx === -1) {
|
||||
id.unshift(65);
|
||||
return;
|
||||
}
|
||||
|
||||
const current = id[idx];
|
||||
|
||||
if (current === 90) {
|
||||
id[idx] = 97;
|
||||
} else if (current === 122) {
|
||||
id[idx] = 65;
|
||||
incrementId(id, idx - 1);
|
||||
} else {
|
||||
id[idx] = current + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function createPrivateUidGeneratorForClass(classPath) {
|
||||
const currentPrivateId = [];
|
||||
const privateNames = new Set();
|
||||
classPath.traverse({
|
||||
PrivateName(path) {
|
||||
privateNames.add(path.node.id.name);
|
||||
}
|
||||
|
||||
});
|
||||
return () => {
|
||||
let reifiedId;
|
||||
|
||||
do {
|
||||
incrementId(currentPrivateId);
|
||||
reifiedId = String.fromCharCode(...currentPrivateId);
|
||||
} while (privateNames.has(reifiedId));
|
||||
|
||||
return _core.types.privateName(_core.types.identifier(reifiedId));
|
||||
};
|
||||
}
|
||||
|
||||
function createLazyPrivateUidGeneratorForClass(classPath) {
|
||||
let generator;
|
||||
return () => {
|
||||
if (!generator) {
|
||||
generator = createPrivateUidGeneratorForClass(classPath);
|
||||
}
|
||||
|
||||
return generator();
|
||||
};
|
||||
}
|
||||
|
||||
function replaceClassWithVar(path) {
|
||||
if (path.type === "ClassDeclaration") {
|
||||
const varId = path.scope.generateUidIdentifierBasedOnNode(path.node.id);
|
||||
|
||||
const classId = _core.types.identifier(path.node.id.name);
|
||||
|
||||
path.scope.rename(classId.name, varId.name);
|
||||
path.insertBefore(_core.types.variableDeclaration("let", [_core.types.variableDeclarator(varId)]));
|
||||
path.get("id").replaceWith(classId);
|
||||
return [_core.types.cloneNode(varId), path];
|
||||
} else {
|
||||
let className;
|
||||
let varId;
|
||||
|
||||
if (path.node.id) {
|
||||
className = path.node.id.name;
|
||||
varId = path.scope.parent.generateDeclaredUidIdentifier(className);
|
||||
path.scope.rename(className, varId.name);
|
||||
} else if (path.parentPath.node.type === "VariableDeclarator" && path.parentPath.node.id.type === "Identifier") {
|
||||
className = path.parentPath.node.id.name;
|
||||
varId = path.scope.parent.generateDeclaredUidIdentifier(className);
|
||||
} else {
|
||||
varId = path.scope.parent.generateDeclaredUidIdentifier("decorated_class");
|
||||
}
|
||||
|
||||
const newClassExpr = _core.types.classExpression(className && _core.types.identifier(className), path.node.superClass, path.node.body);
|
||||
|
||||
const [newPath] = path.replaceWith(_core.types.sequenceExpression([newClassExpr, varId]));
|
||||
return [_core.types.cloneNode(varId), newPath.get("expressions.0")];
|
||||
}
|
||||
}
|
||||
|
||||
function generateClassProperty(key, value, isStatic) {
|
||||
if (key.type === "PrivateName") {
|
||||
return _core.types.classPrivateProperty(key, value, undefined, isStatic);
|
||||
} else {
|
||||
return _core.types.classProperty(key, value, undefined, undefined, isStatic);
|
||||
}
|
||||
}
|
||||
|
||||
function addProxyAccessorsFor(element, originalKey, targetKey, isComputed = false) {
|
||||
const {
|
||||
static: isStatic
|
||||
} = element.node;
|
||||
|
||||
const getterBody = _core.types.blockStatement([_core.types.returnStatement(_core.types.memberExpression(_core.types.thisExpression(), _core.types.cloneNode(targetKey)))]);
|
||||
|
||||
const setterBody = _core.types.blockStatement([_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.memberExpression(_core.types.thisExpression(), _core.types.cloneNode(targetKey)), _core.types.identifier("v")))]);
|
||||
|
||||
let getter, setter;
|
||||
|
||||
if (originalKey.type === "PrivateName") {
|
||||
getter = _core.types.classPrivateMethod("get", _core.types.cloneNode(originalKey), [], getterBody, isStatic);
|
||||
setter = _core.types.classPrivateMethod("set", _core.types.cloneNode(originalKey), [_core.types.identifier("v")], setterBody, isStatic);
|
||||
} else {
|
||||
getter = _core.types.classMethod("get", _core.types.cloneNode(originalKey), [], getterBody, isComputed, isStatic);
|
||||
setter = _core.types.classMethod("set", _core.types.cloneNode(originalKey), [_core.types.identifier("v")], setterBody, isComputed, isStatic);
|
||||
}
|
||||
|
||||
element.insertAfter(setter);
|
||||
element.insertAfter(getter);
|
||||
}
|
||||
|
||||
function extractProxyAccessorsFor(targetKey) {
|
||||
return [_core.types.functionExpression(undefined, [], _core.types.blockStatement([_core.types.returnStatement(_core.types.memberExpression(_core.types.thisExpression(), _core.types.cloneNode(targetKey)))])), _core.types.functionExpression(undefined, [_core.types.identifier("value")], _core.types.blockStatement([_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.memberExpression(_core.types.thisExpression(), _core.types.cloneNode(targetKey)), _core.types.identifier("value")))]))];
|
||||
}
|
||||
|
||||
const FIELD = 0;
|
||||
const ACCESSOR = 1;
|
||||
const METHOD = 2;
|
||||
const GETTER = 3;
|
||||
const SETTER = 4;
|
||||
const STATIC = 5;
|
||||
|
||||
function getElementKind(element) {
|
||||
switch (element.node.type) {
|
||||
case "ClassProperty":
|
||||
case "ClassPrivateProperty":
|
||||
return FIELD;
|
||||
|
||||
case "ClassAccessorProperty":
|
||||
return ACCESSOR;
|
||||
|
||||
case "ClassMethod":
|
||||
case "ClassPrivateMethod":
|
||||
if (element.node.kind === "get") {
|
||||
return GETTER;
|
||||
} else if (element.node.kind === "set") {
|
||||
return SETTER;
|
||||
} else {
|
||||
return METHOD;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function isDecoratorInfo(info) {
|
||||
return "decorators" in info;
|
||||
}
|
||||
|
||||
function filteredOrderedDecoratorInfo(info) {
|
||||
const filtered = info.filter(isDecoratorInfo);
|
||||
return [...filtered.filter(el => el.isStatic && el.kind >= ACCESSOR && el.kind <= SETTER), ...filtered.filter(el => !el.isStatic && el.kind >= ACCESSOR && el.kind <= SETTER), ...filtered.filter(el => el.isStatic && el.kind === FIELD), ...filtered.filter(el => !el.isStatic && el.kind === FIELD)];
|
||||
}
|
||||
|
||||
function generateDecorationExprs(info) {
|
||||
return _core.types.arrayExpression(filteredOrderedDecoratorInfo(info).map(el => {
|
||||
const decs = el.decorators.length > 1 ? _core.types.arrayExpression(el.decorators) : el.decorators[0];
|
||||
const kind = el.isStatic ? el.kind + STATIC : el.kind;
|
||||
const decInfo = [decs, _core.types.numericLiteral(kind), el.name];
|
||||
const {
|
||||
privateMethods
|
||||
} = el;
|
||||
|
||||
if (Array.isArray(privateMethods)) {
|
||||
decInfo.push(...privateMethods);
|
||||
} else if (privateMethods) {
|
||||
decInfo.push(privateMethods);
|
||||
}
|
||||
|
||||
return _core.types.arrayExpression(decInfo);
|
||||
}));
|
||||
}
|
||||
|
||||
function extractElementLocalAssignments(decorationInfo) {
|
||||
const localIds = [];
|
||||
|
||||
for (const el of filteredOrderedDecoratorInfo(decorationInfo)) {
|
||||
const {
|
||||
locals
|
||||
} = el;
|
||||
|
||||
if (Array.isArray(locals)) {
|
||||
localIds.push(...locals);
|
||||
} else if (locals !== undefined) {
|
||||
localIds.push(locals);
|
||||
}
|
||||
}
|
||||
|
||||
return localIds;
|
||||
}
|
||||
|
||||
function addCallAccessorsFor(element, key, getId, setId) {
|
||||
element.insertAfter(_core.types.classPrivateMethod("get", _core.types.cloneNode(key), [], _core.types.blockStatement([_core.types.returnStatement(_core.types.callExpression(_core.types.cloneNode(getId), [_core.types.thisExpression()]))])));
|
||||
element.insertAfter(_core.types.classPrivateMethod("set", _core.types.cloneNode(key), [_core.types.identifier("v")], _core.types.blockStatement([_core.types.expressionStatement(_core.types.callExpression(_core.types.cloneNode(setId), [_core.types.thisExpression(), _core.types.identifier("v")]))])));
|
||||
}
|
||||
|
||||
function isNotTsParameter(node) {
|
||||
return node.type !== "TSParameterProperty";
|
||||
}
|
||||
|
||||
function movePrivateAccessor(element, key, methodLocalVar, isStatic) {
|
||||
let params;
|
||||
let block;
|
||||
|
||||
if (element.node.kind === "set") {
|
||||
params = [_core.types.identifier("v")];
|
||||
block = [_core.types.expressionStatement(_core.types.callExpression(methodLocalVar, [_core.types.thisExpression(), _core.types.identifier("v")]))];
|
||||
} else {
|
||||
params = [];
|
||||
block = [_core.types.returnStatement(_core.types.callExpression(methodLocalVar, [_core.types.thisExpression()]))];
|
||||
}
|
||||
|
||||
element.replaceWith(_core.types.classPrivateMethod(element.node.kind, _core.types.cloneNode(key), params, _core.types.blockStatement(block), isStatic));
|
||||
}
|
||||
|
||||
function isClassDecoratableElementPath(path) {
|
||||
const {
|
||||
type
|
||||
} = path;
|
||||
return type !== "TSDeclareMethod" && type !== "TSIndexSignature" && type !== "StaticBlock";
|
||||
}
|
||||
|
||||
function staticBlockToIIFE(block) {
|
||||
return _core.types.callExpression(_core.types.arrowFunctionExpression([], _core.types.blockStatement(block.body)), []);
|
||||
}
|
||||
|
||||
function maybeSequenceExpression(exprs) {
|
||||
if (exprs.length === 0) return _core.types.unaryExpression("void", _core.types.numericLiteral(0));
|
||||
if (exprs.length === 1) return exprs[0];
|
||||
return _core.types.sequenceExpression(exprs);
|
||||
}
|
||||
|
||||
function transformClass(path, state, constantSuper) {
|
||||
const body = path.get("body.body");
|
||||
const classDecorators = path.node.decorators;
|
||||
let hasElementDecorators = false;
|
||||
const generateClassPrivateUid = createLazyPrivateUidGeneratorForClass(path);
|
||||
|
||||
for (const element of body) {
|
||||
if (!isClassDecoratableElementPath(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.node.decorators && element.node.decorators.length > 0) {
|
||||
hasElementDecorators = true;
|
||||
} else if (element.node.type === "ClassAccessorProperty") {
|
||||
const {
|
||||
key,
|
||||
value,
|
||||
static: isStatic,
|
||||
computed
|
||||
} = element.node;
|
||||
const newId = generateClassPrivateUid();
|
||||
const valueNode = value ? _core.types.cloneNode(value) : undefined;
|
||||
const newField = generateClassProperty(newId, valueNode, isStatic);
|
||||
const [newPath] = element.replaceWith(newField);
|
||||
addProxyAccessorsFor(newPath, key, newId, computed);
|
||||
}
|
||||
}
|
||||
|
||||
if (!classDecorators && !hasElementDecorators) return;
|
||||
const elementDecoratorInfo = [];
|
||||
let firstFieldPath;
|
||||
let constructorPath;
|
||||
let requiresProtoInit = false;
|
||||
let requiresStaticInit = false;
|
||||
const decoratedPrivateMethods = new Set();
|
||||
let protoInitLocal, staticInitLocal, classInitLocal, classLocal;
|
||||
const assignments = [];
|
||||
const scopeParent = path.scope.parent;
|
||||
|
||||
const memoiseExpression = (expression, hint) => {
|
||||
const localEvaluatedId = scopeParent.generateDeclaredUidIdentifier(hint);
|
||||
assignments.push(_core.types.assignmentExpression("=", localEvaluatedId, expression));
|
||||
return _core.types.cloneNode(localEvaluatedId);
|
||||
};
|
||||
|
||||
if (classDecorators) {
|
||||
classInitLocal = scopeParent.generateDeclaredUidIdentifier("initClass");
|
||||
const [localId, classPath] = replaceClassWithVar(path);
|
||||
path = classPath;
|
||||
classLocal = localId;
|
||||
path.node.decorators = null;
|
||||
|
||||
for (const classDecorator of classDecorators) {
|
||||
if (!scopeParent.isStatic(classDecorator.expression)) {
|
||||
classDecorator.expression = memoiseExpression(classDecorator.expression, "dec");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!path.node.id) {
|
||||
path.node.id = path.scope.generateUidIdentifier("Class");
|
||||
}
|
||||
|
||||
classLocal = _core.types.cloneNode(path.node.id);
|
||||
}
|
||||
|
||||
if (hasElementDecorators) {
|
||||
for (const element of body) {
|
||||
if (!isClassDecoratableElementPath(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const {
|
||||
node
|
||||
} = element;
|
||||
const decorators = element.get("decorators");
|
||||
const hasDecorators = Array.isArray(decorators) && decorators.length > 0;
|
||||
|
||||
if (hasDecorators) {
|
||||
for (const decoratorPath of decorators) {
|
||||
if (!scopeParent.isStatic(decoratorPath.node.expression)) {
|
||||
decoratorPath.node.expression = memoiseExpression(decoratorPath.node.expression, "dec");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isComputed = "computed" in element.node && element.node.computed === true;
|
||||
|
||||
if (isComputed) {
|
||||
if (!scopeParent.isStatic(node.key)) {
|
||||
node.key = memoiseExpression(node.key, "computedKey");
|
||||
}
|
||||
}
|
||||
|
||||
const kind = getElementKind(element);
|
||||
const {
|
||||
key
|
||||
} = node;
|
||||
const isPrivate = key.type === "PrivateName";
|
||||
const isStatic = !!element.node.static;
|
||||
let name = "computedKey";
|
||||
|
||||
if (isPrivate) {
|
||||
name = key.id.name;
|
||||
} else if (!isComputed && key.type === "Identifier") {
|
||||
name = key.name;
|
||||
}
|
||||
|
||||
if (element.isClassMethod({
|
||||
kind: "constructor"
|
||||
})) {
|
||||
constructorPath = element;
|
||||
}
|
||||
|
||||
if (hasDecorators) {
|
||||
let locals;
|
||||
let privateMethods;
|
||||
|
||||
if (kind === ACCESSOR) {
|
||||
const {
|
||||
value
|
||||
} = element.node;
|
||||
const params = [_core.types.thisExpression()];
|
||||
|
||||
if (value) {
|
||||
params.push(_core.types.cloneNode(value));
|
||||
}
|
||||
|
||||
const newId = generateClassPrivateUid();
|
||||
const newFieldInitId = element.scope.parent.generateDeclaredUidIdentifier(`init_${name}`);
|
||||
|
||||
const newValue = _core.types.callExpression(_core.types.cloneNode(newFieldInitId), params);
|
||||
|
||||
const newField = generateClassProperty(newId, newValue, isStatic);
|
||||
const [newPath] = element.replaceWith(newField);
|
||||
|
||||
if (isPrivate) {
|
||||
privateMethods = extractProxyAccessorsFor(newId);
|
||||
const getId = newPath.scope.parent.generateDeclaredUidIdentifier(`get_${name}`);
|
||||
const setId = newPath.scope.parent.generateDeclaredUidIdentifier(`set_${name}`);
|
||||
addCallAccessorsFor(newPath, key, getId, setId);
|
||||
locals = [newFieldInitId, getId, setId];
|
||||
} else {
|
||||
addProxyAccessorsFor(newPath, key, newId, isComputed);
|
||||
locals = newFieldInitId;
|
||||
}
|
||||
} else if (kind === FIELD) {
|
||||
const initId = element.scope.parent.generateDeclaredUidIdentifier(`init_${name}`);
|
||||
const valuePath = element.get("value");
|
||||
valuePath.replaceWith(_core.types.callExpression(_core.types.cloneNode(initId), [_core.types.thisExpression(), valuePath.node].filter(v => v)));
|
||||
locals = initId;
|
||||
|
||||
if (isPrivate) {
|
||||
privateMethods = extractProxyAccessorsFor(key);
|
||||
}
|
||||
} else if (isPrivate) {
|
||||
locals = element.scope.parent.generateDeclaredUidIdentifier(`call_${name}`);
|
||||
const replaceSupers = new _helperReplaceSupers.default({
|
||||
constantSuper,
|
||||
methodPath: element,
|
||||
objectRef: classLocal,
|
||||
superRef: path.node.superClass,
|
||||
file: state,
|
||||
refToPreserve: classLocal
|
||||
});
|
||||
replaceSupers.replace();
|
||||
const {
|
||||
params,
|
||||
body,
|
||||
async: isAsync
|
||||
} = element.node;
|
||||
privateMethods = _core.types.functionExpression(undefined, params.filter(isNotTsParameter), body, isAsync);
|
||||
|
||||
if (kind === GETTER || kind === SETTER) {
|
||||
movePrivateAccessor(element, _core.types.cloneNode(key), _core.types.cloneNode(locals), isStatic);
|
||||
} else {
|
||||
const node = element.node;
|
||||
path.node.body.body.unshift(_core.types.classPrivateProperty(key, _core.types.cloneNode(locals), [], node.static));
|
||||
decoratedPrivateMethods.add(key.id.name);
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let nameExpr;
|
||||
|
||||
if (isComputed) {
|
||||
nameExpr = _core.types.cloneNode(key);
|
||||
} else if (key.type === "PrivateName") {
|
||||
nameExpr = _core.types.stringLiteral(key.id.name);
|
||||
} else if (key.type === "Identifier") {
|
||||
nameExpr = _core.types.stringLiteral(key.name);
|
||||
} else {
|
||||
nameExpr = _core.types.cloneNode(key);
|
||||
}
|
||||
|
||||
elementDecoratorInfo.push({
|
||||
kind,
|
||||
decorators: decorators.map(d => d.node.expression),
|
||||
name: nameExpr,
|
||||
isStatic,
|
||||
privateMethods,
|
||||
locals
|
||||
});
|
||||
|
||||
if (kind !== FIELD) {
|
||||
if (isStatic) {
|
||||
requiresStaticInit = true;
|
||||
} else {
|
||||
requiresProtoInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.node) {
|
||||
element.node.decorators = null;
|
||||
}
|
||||
|
||||
if (!firstFieldPath && (kind === FIELD || kind === ACCESSOR)) {
|
||||
firstFieldPath = element;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const elementDecorations = generateDecorationExprs(elementDecoratorInfo);
|
||||
|
||||
const classDecorations = _core.types.arrayExpression((classDecorators || []).map(d => d.expression));
|
||||
|
||||
const locals = extractElementLocalAssignments(elementDecoratorInfo);
|
||||
|
||||
if (requiresProtoInit) {
|
||||
protoInitLocal = scopeParent.generateDeclaredUidIdentifier("initProto");
|
||||
locals.push(protoInitLocal);
|
||||
|
||||
const protoInitCall = _core.types.callExpression(_core.types.cloneNode(protoInitLocal), [_core.types.thisExpression()]);
|
||||
|
||||
if (firstFieldPath) {
|
||||
const value = firstFieldPath.get("value");
|
||||
const body = [protoInitCall];
|
||||
|
||||
if (value.node) {
|
||||
body.push(value.node);
|
||||
}
|
||||
|
||||
value.replaceWith(_core.types.sequenceExpression(body));
|
||||
} else if (constructorPath) {
|
||||
if (path.node.superClass) {
|
||||
path.traverse({
|
||||
CallExpression: {
|
||||
exit(path) {
|
||||
if (!path.get("callee").isSuper()) return;
|
||||
path.replaceWith(_core.types.callExpression(_core.types.cloneNode(protoInitLocal), [path.node]));
|
||||
path.skip();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
constructorPath.node.body.body.unshift(_core.types.expressionStatement(protoInitCall));
|
||||
}
|
||||
} else {
|
||||
const body = [_core.types.expressionStatement(protoInitCall)];
|
||||
|
||||
if (path.node.superClass) {
|
||||
body.unshift(_core.types.expressionStatement(_core.types.callExpression(_core.types.super(), [_core.types.spreadElement(_core.types.identifier("args"))])));
|
||||
}
|
||||
|
||||
path.node.body.body.unshift(_core.types.classMethod("constructor", _core.types.identifier("constructor"), [_core.types.restElement(_core.types.identifier("args"))], _core.types.blockStatement(body)));
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresStaticInit) {
|
||||
staticInitLocal = scopeParent.generateDeclaredUidIdentifier("initStatic");
|
||||
locals.push(staticInitLocal);
|
||||
}
|
||||
|
||||
if (decoratedPrivateMethods.size > 0) {
|
||||
path.traverse({
|
||||
PrivateName(path) {
|
||||
if (!decoratedPrivateMethods.has(path.node.id.name)) return;
|
||||
const parentPath = path.parentPath;
|
||||
const parentParentPath = parentPath.parentPath;
|
||||
|
||||
if (parentParentPath.node.type === "AssignmentExpression" && parentParentPath.node.left === parentPath.node || parentParentPath.node.type === "UpdateExpression" || parentParentPath.node.type === "RestElement" || parentParentPath.node.type === "ArrayPattern" || parentParentPath.node.type === "ObjectProperty" && parentParentPath.node.value === parentPath.node && parentParentPath.parentPath.type === "ObjectPattern" || parentParentPath.node.type === "ForOfStatement" && parentParentPath.node.left === parentPath.node) {
|
||||
throw path.buildCodeFrameError(`Decorated private methods are not updatable, but "#${path.node.id.name}" is updated via this expression.`);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
let classInitInjected = false;
|
||||
|
||||
const classInitCall = classInitLocal && _core.types.callExpression(_core.types.cloneNode(classInitLocal), []);
|
||||
|
||||
const originalClass = path.node;
|
||||
|
||||
if (classDecorators) {
|
||||
locals.push(classLocal, classInitLocal);
|
||||
const statics = [];
|
||||
let staticBlocks = [];
|
||||
path.get("body.body").forEach(element => {
|
||||
if (element.isStaticBlock()) {
|
||||
staticBlocks.push(element.node);
|
||||
element.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
const isProperty = element.isClassProperty() || element.isClassPrivateProperty();
|
||||
|
||||
if ((isProperty || element.isClassPrivateMethod()) && element.node.static) {
|
||||
if (isProperty && staticBlocks.length > 0) {
|
||||
const allValues = staticBlocks.map(staticBlockToIIFE);
|
||||
if (element.node.value) allValues.push(element.node.value);
|
||||
element.node.value = maybeSequenceExpression(allValues);
|
||||
staticBlocks = [];
|
||||
}
|
||||
|
||||
element.node.static = false;
|
||||
statics.push(element.node);
|
||||
element.remove();
|
||||
}
|
||||
});
|
||||
|
||||
if (statics.length > 0 || staticBlocks.length > 0) {
|
||||
const staticsClass = _core.template.expression.ast`
|
||||
class extends ${state.addHelper("identity")} {}
|
||||
`;
|
||||
staticsClass.body.body = [_core.types.staticBlock([_core.types.toStatement(path.node, false)]), ...statics];
|
||||
const constructorBody = [];
|
||||
|
||||
const newExpr = _core.types.newExpression(staticsClass, []);
|
||||
|
||||
if (staticBlocks.length > 0) {
|
||||
constructorBody.push(...staticBlocks.map(staticBlockToIIFE));
|
||||
}
|
||||
|
||||
if (classInitCall) {
|
||||
classInitInjected = true;
|
||||
constructorBody.push(classInitCall);
|
||||
}
|
||||
|
||||
if (constructorBody.length > 0) {
|
||||
constructorBody.unshift(_core.types.callExpression(_core.types.super(), [_core.types.cloneNode(classLocal)]));
|
||||
staticsClass.body.body.push(_core.types.classMethod("constructor", _core.types.identifier("constructor"), [], _core.types.blockStatement([_core.types.expressionStatement(_core.types.sequenceExpression(constructorBody))])));
|
||||
} else {
|
||||
newExpr.arguments.push(_core.types.cloneNode(classLocal));
|
||||
}
|
||||
|
||||
path.replaceWith(newExpr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!classInitInjected && classInitCall) {
|
||||
path.node.body.body.push(_core.types.staticBlock([_core.types.expressionStatement(classInitCall)]));
|
||||
}
|
||||
|
||||
originalClass.body.body.unshift(_core.types.staticBlock([_core.types.expressionStatement(_core.types.assignmentExpression("=", _core.types.arrayPattern(locals), _core.types.callExpression(state.addHelper("applyDecs"), [_core.types.thisExpression(), elementDecorations, classDecorations]))), requiresStaticInit && _core.types.expressionStatement(_core.types.callExpression(_core.types.cloneNode(staticInitLocal), [_core.types.thisExpression()]))].filter(Boolean)));
|
||||
path.insertBefore(assignments.map(expr => _core.types.expressionStatement(expr)));
|
||||
path.scope.crawl();
|
||||
return path;
|
||||
}
|
||||
|
||||
function _default({
|
||||
assertVersion,
|
||||
assumption
|
||||
}, {
|
||||
loose
|
||||
}) {
|
||||
var _assumption;
|
||||
|
||||
assertVersion("^7.16.0");
|
||||
const VISITED = new WeakSet();
|
||||
const constantSuper = (_assumption = assumption("constantSuper")) != null ? _assumption : loose;
|
||||
return {
|
||||
name: "proposal-decorators",
|
||||
inherits: _pluginSyntaxDecorators.default,
|
||||
visitor: {
|
||||
"ExportNamedDeclaration|ExportDefaultDeclaration"(path) {
|
||||
var _declaration$decorato;
|
||||
|
||||
const {
|
||||
declaration
|
||||
} = path.node;
|
||||
|
||||
if ((declaration == null ? void 0 : declaration.type) === "ClassDeclaration" && ((_declaration$decorato = declaration.decorators) == null ? void 0 : _declaration$decorato.length) > 0) {
|
||||
(0, _helperSplitExportDeclaration.default)(path);
|
||||
}
|
||||
},
|
||||
|
||||
Class(path, state) {
|
||||
if (VISITED.has(path)) return;
|
||||
const newPath = transformClass(path, state, constantSuper);
|
||||
if (newPath) VISITED.add(newPath);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
+16
-9
@@ -7,9 +7,10 @@ exports.default = void 0;
|
||||
|
||||
var _core = require("@babel/core");
|
||||
|
||||
const buildClassDecorator = (0, _core.template)(`
|
||||
const buildClassDecorator = _core.template.statement(`
|
||||
DECORATOR(CLASS_REF = INNER) || CLASS_REF;
|
||||
`);
|
||||
|
||||
const buildClassPrototype = (0, _core.template)(`
|
||||
CLASS_REF.prototype;
|
||||
`);
|
||||
@@ -29,7 +30,7 @@ const buildGetObjectInitializer = (0, _core.template)(`
|
||||
const WARNING_CALLS = new WeakSet();
|
||||
|
||||
function applyEnsureOrdering(path) {
|
||||
const decorators = (path.isClass() ? [path].concat(path.get("body.body")) : path.get("properties")).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []);
|
||||
const decorators = (path.isClass() ? [path, ...path.get("body.body")] : path.get("properties")).reduce((acc, prop) => acc.concat(prop.node.decorators || []), []);
|
||||
const identDecorators = decorators.filter(decorator => !_core.types.isIdentifier(decorator.expression));
|
||||
if (identDecorators.length === 0) return;
|
||||
return _core.types.sequenceExpression(identDecorators.map(decorator => {
|
||||
@@ -72,14 +73,19 @@ function hasMethodDecorators(body) {
|
||||
|
||||
function applyObjectDecorators(path, state) {
|
||||
if (!hasMethodDecorators(path.node.properties)) return;
|
||||
return applyTargetDecorators(path, state, path.node.properties);
|
||||
return applyTargetDecorators(path, state, path.node.properties.filter(prop => prop.type !== "SpreadElement"));
|
||||
}
|
||||
|
||||
function applyTargetDecorators(path, state, decoratedProps) {
|
||||
const name = path.scope.generateDeclaredUidIdentifier(path.isClass() ? "class" : "obj");
|
||||
const exprs = decoratedProps.reduce(function (acc, node) {
|
||||
const decorators = node.decorators || [];
|
||||
node.decorators = null;
|
||||
let decorators = [];
|
||||
|
||||
if (node.decorators != null) {
|
||||
decorators = node.decorators;
|
||||
node.decorators = null;
|
||||
}
|
||||
|
||||
if (decorators.length === 0) return acc;
|
||||
|
||||
if (node.computed) {
|
||||
@@ -98,9 +104,9 @@ function applyTargetDecorators(path, state, decoratedProps) {
|
||||
const initializer = node.value ? _core.types.functionExpression(null, [], _core.types.blockStatement([_core.types.returnStatement(node.value)])) : _core.types.nullLiteral();
|
||||
node.value = _core.types.callExpression(state.addHelper("initializerWarningHelper"), [descriptor, _core.types.thisExpression()]);
|
||||
WARNING_CALLS.add(node.value);
|
||||
acc = acc.concat([_core.types.assignmentExpression("=", descriptor, _core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.objectExpression([_core.types.objectProperty(_core.types.identifier("configurable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("enumerable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("writable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("initializer"), initializer)])]))]);
|
||||
acc.push(_core.types.assignmentExpression("=", _core.types.cloneNode(descriptor), _core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.objectExpression([_core.types.objectProperty(_core.types.identifier("configurable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("enumerable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("writable"), _core.types.booleanLiteral(true)), _core.types.objectProperty(_core.types.identifier("initializer"), initializer)])])));
|
||||
} else {
|
||||
acc = acc.concat(_core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.isObjectProperty(node) || _core.types.isClassProperty(node, {
|
||||
acc.push(_core.types.callExpression(state.addHelper("applyDecoratedDescriptor"), [_core.types.cloneNode(target), _core.types.cloneNode(property), _core.types.arrayExpression(decorators.map(dec => _core.types.cloneNode(dec.expression))), _core.types.isObjectProperty(node) || _core.types.isClassProperty(node, {
|
||||
static: true
|
||||
}) ? buildGetObjectInitializer({
|
||||
TEMP: path.scope.generateDeclaredUidIdentifier("init"),
|
||||
@@ -129,7 +135,7 @@ function decoratedClassToExpression({
|
||||
return _core.types.variableDeclaration("let", [_core.types.variableDeclarator(ref, _core.types.toExpression(node))]);
|
||||
}
|
||||
|
||||
var _default = {
|
||||
const visitor = {
|
||||
ExportDefaultDeclaration(path) {
|
||||
const decl = path.get("declaration");
|
||||
if (!decl.isClassDeclaration()) return;
|
||||
@@ -153,7 +159,7 @@ var _default = {
|
||||
},
|
||||
|
||||
ClassExpression(path, state) {
|
||||
const decoratedClass = applyEnsureOrdering(path) || applyClassDecorators(path, state) || applyMethodDecorators(path, state);
|
||||
const decoratedClass = applyEnsureOrdering(path) || applyClassDecorators(path) || applyMethodDecorators(path, state);
|
||||
if (decoratedClass) path.replaceWith(decoratedClass);
|
||||
},
|
||||
|
||||
@@ -179,4 +185,5 @@ var _default = {
|
||||
}
|
||||
|
||||
};
|
||||
var _default = visitor;
|
||||
exports.default = _default;
|
||||
+32
-22
@@ -1,59 +1,68 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"@babel/plugin-proposal-decorators@7.10.4",
|
||||
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
|
||||
"@babel/plugin-proposal-decorators@7.18.6",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "@babel/plugin-proposal-decorators@7.10.4",
|
||||
"_id": "@babel/plugin-proposal-decorators@7.10.4",
|
||||
"_from": "@babel/plugin-proposal-decorators@7.18.6",
|
||||
"_id": "@babel/plugin-proposal-decorators@7.18.6",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-JHTWjQngOPv+ZQQqOGv2x6sCCr4IYWy7S1/VH6BE9ZfkoLrdQ2GpEP3tfb5M++G9PwvqjhY8VC/C3tXm+/eHvA==",
|
||||
"_integrity": "sha512-gAdhsjaYmiZVxx5vTMiRfj31nB7LhwBJFMSLzeDxc7X4tKLixup0+k9ughn0RcpBrv9E3PBaXJW7jF5TCihAOg==",
|
||||
"_location": "/@babel/plugin-proposal-decorators",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "@babel/plugin-proposal-decorators@7.10.4",
|
||||
"raw": "@babel/plugin-proposal-decorators@7.18.6",
|
||||
"name": "@babel/plugin-proposal-decorators",
|
||||
"escapedName": "@babel%2fplugin-proposal-decorators",
|
||||
"scope": "@babel",
|
||||
"rawSpec": "7.10.4",
|
||||
"rawSpec": "7.18.6",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "7.10.4"
|
||||
"fetchSpec": "7.18.6"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@nuxt/babel-preset-app"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.4.tgz",
|
||||
"_spec": "7.10.4",
|
||||
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
|
||||
"_resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.6.tgz",
|
||||
"_spec": "7.18.6",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Logan Smyth",
|
||||
"email": "loganfsmyth@gmail.com"
|
||||
"name": "The Babel Team",
|
||||
"url": "https://babel.dev/team"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/babel/babel/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "^7.10.4",
|
||||
"@babel/helper-plugin-utils": "^7.10.4",
|
||||
"@babel/plugin-syntax-decorators": "^7.10.4"
|
||||
"@babel/helper-create-class-features-plugin": "^7.18.6",
|
||||
"@babel/helper-plugin-utils": "^7.18.6",
|
||||
"@babel/helper-replace-supers": "^7.18.6",
|
||||
"@babel/helper-split-export-declaration": "^7.18.6",
|
||||
"@babel/plugin-syntax-decorators": "^7.18.6"
|
||||
},
|
||||
"description": "Compile class and object decorators to ES5",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.4",
|
||||
"@babel/helper-plugin-test-runner": "^7.10.4"
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/helper-plugin-test-runner": "^7.18.6",
|
||||
"@babel/traverse": "^7.18.6",
|
||||
"@types/charcodes": "^0.2.0",
|
||||
"babel-plugin-polyfill-es-shims": "^0.6.1",
|
||||
"charcodes": "^0.2.0",
|
||||
"object.getownpropertydescriptors": "^2.1.1"
|
||||
},
|
||||
"gitHead": "7fd40d86a0d03ff0e9c3ea16b29689945433d4df",
|
||||
"homepage": "https://github.com/babel/babel#readme",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"homepage": "https://babel.dev/docs/en/next/babel-plugin-proposal-decorators",
|
||||
"keywords": [
|
||||
"babel",
|
||||
"babel-plugin",
|
||||
"decorators"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"main": "./lib/index.js",
|
||||
"name": "@babel/plugin-proposal-decorators",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
@@ -66,5 +75,6 @@
|
||||
"url": "git+https://github.com/babel/babel.git",
|
||||
"directory": "packages/babel-plugin-proposal-decorators"
|
||||
},
|
||||
"version": "7.10.4"
|
||||
"type": "commonjs",
|
||||
"version": "7.18.6"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user