Adds the 2021-12 transform for decorators
Implements the 2021-12 transform for the decorators proposal, with support for the `accessor` keyword.
This commit is contained in:
parent
3f3ce5f668
commit
3f7644823d
@ -80,7 +80,10 @@ function extractElementDescriptor(
|
||||
const properties: t.ObjectExpression["properties"] = [
|
||||
prop("kind", t.stringLiteral(t.isClassMethod(node) ? node.kind : "field")),
|
||||
prop("decorators", takeDecorators(node as Decorable)),
|
||||
prop("static", node.static && t.booleanLiteral(true)),
|
||||
prop(
|
||||
"static",
|
||||
!t.isStaticBlock(node) && node.static && t.booleanLiteral(true),
|
||||
),
|
||||
prop("key", getKey(node)),
|
||||
].filter(Boolean);
|
||||
|
||||
|
||||
@ -911,7 +911,7 @@ function replaceThisContext(
|
||||
getSuperRef,
|
||||
getObjectRef() {
|
||||
state.needsClassRef = true;
|
||||
return isStaticBlock || path.node.static
|
||||
return t.isStaticBlock(path.node) || path.node.static
|
||||
? ref
|
||||
: t.memberExpression(ref, t.identifier("prototype"));
|
||||
},
|
||||
@ -931,7 +931,8 @@ function replaceThisContext(
|
||||
export type PropNode =
|
||||
| t.ClassProperty
|
||||
| t.ClassPrivateMethod
|
||||
| t.ClassPrivateProperty;
|
||||
| t.ClassPrivateProperty
|
||||
| t.StaticBlock;
|
||||
export type PropPath = NodePath<PropNode>;
|
||||
|
||||
export function buildFieldsInitNodes(
|
||||
@ -963,7 +964,7 @@ export function buildFieldsInitNodes(
|
||||
for (const prop of props) {
|
||||
prop.isClassProperty() && ts.assertFieldTransformed(prop);
|
||||
|
||||
const isStatic = prop.node.static;
|
||||
const isStatic = !t.isStaticBlock(prop.node) && prop.node.static;
|
||||
const isInstance = !isStatic;
|
||||
const isPrivate = prop.isPrivate();
|
||||
const isPublic = !isPrivate;
|
||||
|
||||
@ -170,7 +170,7 @@ export function createClassFeaturePlugin({
|
||||
path.isPrivate() ||
|
||||
path.isStaticBlock?.()
|
||||
) {
|
||||
props.push(path);
|
||||
props.push(path as PropPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -246,7 +246,7 @@ export function createClassFeaturePlugin({
|
||||
(referenceVisitor, state) => {
|
||||
if (isDecorated) return;
|
||||
for (const prop of props) {
|
||||
if (prop.node.static) continue;
|
||||
if (t.isStaticBlock(prop.node) || prop.node.static) continue;
|
||||
prop.traverse(referenceVisitor, state);
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
728
packages/babel-helpers/src/helpers/applyDecs.js
Normal file
728
packages/babel-helpers/src/helpers/applyDecs.js
Normal file
@ -0,0 +1,728 @@
|
||||
/* @minVersion 7.16.6 */
|
||||
|
||||
/**
|
||||
Enums are used in this file, but not assigned to vars to avoid non-hoistable values
|
||||
|
||||
CONSTRUCTOR = 0;
|
||||
PUBLIC = 1;
|
||||
PRIVATE = 2;
|
||||
|
||||
FIELD = 0;
|
||||
ACCESSOR = 1;
|
||||
METHOD = 2;
|
||||
GETTER = 3;
|
||||
SETTER = 4;
|
||||
|
||||
STATIC = 5;
|
||||
*/
|
||||
|
||||
function createMetadataMethodsForProperty(metadataMap, kind, property) {
|
||||
return {
|
||||
getMetadata(key) {
|
||||
if (typeof key !== "symbol") {
|
||||
throw new TypeError("Metadata keys must be symbols, received: " + key);
|
||||
}
|
||||
|
||||
var metadataForKey = metadataMap[key];
|
||||
|
||||
if (metadataForKey === undefined) return undefined;
|
||||
|
||||
if (kind === 1 /* PUBLIC */) {
|
||||
var pub = metadataForKey.public;
|
||||
if (pub !== undefined) {
|
||||
return pub[property];
|
||||
}
|
||||
} else if (kind === 2 /* PRIVATE */) {
|
||||
var priv = metadataForKey.private;
|
||||
if (priv !== undefined) {
|
||||
return priv.get(property);
|
||||
}
|
||||
} else if (Object.hasOwnProperty.call(metadataForKey, "constructor")) {
|
||||
return metadataForKey.constructor;
|
||||
}
|
||||
},
|
||||
setMetadata(key, value) {
|
||||
if (typeof key !== "symbol") {
|
||||
throw new TypeError("Metadata keys must be symbols, received: " + key);
|
||||
}
|
||||
|
||||
var metadataForKey = metadataMap[key];
|
||||
|
||||
if (metadataForKey === undefined) {
|
||||
metadataForKey = metadataMap[key] = {};
|
||||
}
|
||||
|
||||
if (kind === 1 /* PUBLIC */) {
|
||||
var pub = metadataForKey.public;
|
||||
|
||||
if (pub === undefined) {
|
||||
pub = metadataForKey.public = Object.create(null);
|
||||
}
|
||||
|
||||
pub[property] = value;
|
||||
} else if (kind === 2 /* PRIVATE */) {
|
||||
var priv = metadataForKey.priv;
|
||||
|
||||
if (priv === undefined) {
|
||||
priv = metadataForKey.private = new Map();
|
||||
}
|
||||
|
||||
priv.set(property, value);
|
||||
} else {
|
||||
metadataForKey.constructor = value;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function convertMetadataMapToFinal(obj, metadataMap) {
|
||||
var parentMetadataMap = obj[Symbol.metadata];
|
||||
var metadataKeys = Object.getOwnPropertySymbols(metadataMap);
|
||||
|
||||
if (metadataKeys.length === 0) return;
|
||||
|
||||
for (var i = 0; i < metadataKeys.length; i++) {
|
||||
var key = metadataKeys[i];
|
||||
var metaForKey = metadataMap[key];
|
||||
var parentMetaForKey = parentMetadataMap ? parentMetadataMap[key] : null;
|
||||
|
||||
var pub = metaForKey.public;
|
||||
var parentPub = parentMetaForKey ? parentMetaForKey.public : null;
|
||||
|
||||
if (pub && parentPub) {
|
||||
Object.setPrototypeOf(pub, parentPub);
|
||||
}
|
||||
|
||||
var priv = metaForKey.private;
|
||||
|
||||
if (priv) {
|
||||
var privArr = Array.from(priv.values());
|
||||
var parentPriv = parentMetaForKey ? parentMetaForKey.private : null;
|
||||
|
||||
if (parentPriv) {
|
||||
privArr = privArr.concat(parentPriv);
|
||||
}
|
||||
|
||||
metaForKey.private = privArr;
|
||||
}
|
||||
|
||||
if (parentMetaForKey) {
|
||||
Object.setPrototypeOf(metaForKey, parentMetaForKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentMetadataMap) {
|
||||
Object.setPrototypeOf(metadataMap, parentMetadataMap);
|
||||
}
|
||||
|
||||
obj[Symbol.metadata] = metadataMap;
|
||||
}
|
||||
|
||||
function createAddInitializerMethod(initializers) {
|
||||
return function addInitializer(initializer) {
|
||||
assertValidInitializer(initializer);
|
||||
initializers.push(initializer);
|
||||
};
|
||||
}
|
||||
|
||||
function memberDecCtx(
|
||||
base,
|
||||
name,
|
||||
desc,
|
||||
metadataMap,
|
||||
initializers,
|
||||
kind,
|
||||
isStatic,
|
||||
isPrivate
|
||||
) {
|
||||
var kindStr;
|
||||
|
||||
switch (kind) {
|
||||
case 1 /* ACCESSOR */:
|
||||
kindStr = "accessor";
|
||||
break;
|
||||
case 2 /* METHOD */:
|
||||
kindStr = "method";
|
||||
break;
|
||||
case 3 /* GETTER */:
|
||||
kindStr = "getter";
|
||||
break;
|
||||
case 4 /* SETTER */:
|
||||
kindStr = "setter";
|
||||
break;
|
||||
default:
|
||||
kindStr = "field";
|
||||
}
|
||||
|
||||
var ctx = {
|
||||
kind: kindStr,
|
||||
name: isPrivate ? "#" + name : name,
|
||||
isStatic: isStatic,
|
||||
isPrivate: isPrivate,
|
||||
};
|
||||
|
||||
if (kind !== 0 /* FIELD */) {
|
||||
ctx.addInitializer = createAddInitializerMethod(initializers);
|
||||
}
|
||||
|
||||
var metadataKind, metadataName;
|
||||
|
||||
if (isPrivate) {
|
||||
metadataKind = 2 /* PRIVATE */;
|
||||
metadataName = Symbol(name);
|
||||
|
||||
var access = {};
|
||||
|
||||
if (kind === 0 /* FIELD */) {
|
||||
access.get = desc.get;
|
||||
access.set = desc.set;
|
||||
} else if (kind === 2 /* METHOD */) {
|
||||
access.get = function () {
|
||||
return desc.value;
|
||||
};
|
||||
} else {
|
||||
// replace with values that will go through the final getter and setter
|
||||
if (kind === 1 /* ACCESSOR */ || kind === 3 /* GETTER */) {
|
||||
access.get = function () {
|
||||
return desc.get.call(this);
|
||||
};
|
||||
}
|
||||
|
||||
if (kind === 1 /* ACCESSOR */ || kind === 4 /* SETTER */) {
|
||||
access.set = function (v) {
|
||||
desc.set.call(this, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ctx.access = access;
|
||||
} else {
|
||||
metadataKind = 1 /* PUBLIC */;
|
||||
metadataName = name;
|
||||
}
|
||||
|
||||
return Object.assign(
|
||||
ctx,
|
||||
createMetadataMethodsForProperty(metadataMap, metadataKind, metadataName)
|
||||
);
|
||||
}
|
||||
|
||||
function assertValidInitializer(initializer) {
|
||||
if (typeof initializer !== "function") {
|
||||
throw new Error("initializers must be functions");
|
||||
}
|
||||
}
|
||||
|
||||
function assertValidReturnValue(kind, value) {
|
||||
var type = typeof value;
|
||||
|
||||
if (kind === 1 /* ACCESSOR */) {
|
||||
if (type !== "object" || value === null) {
|
||||
throw new Error(
|
||||
"accessor decorators must return an object with get, set, or initializer properties or undefined"
|
||||
);
|
||||
}
|
||||
} else if (type !== "function") {
|
||||
if (kind === 0 /* FIELD */) {
|
||||
throw new Error(
|
||||
"field decorators must return a initializer function or undefined"
|
||||
);
|
||||
} else {
|
||||
throw new Error("method decorators must return a function or undefined");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyMemberDec(
|
||||
ret,
|
||||
base,
|
||||
decInfo,
|
||||
name,
|
||||
kind,
|
||||
isStatic,
|
||||
isPrivate,
|
||||
metadataMap,
|
||||
initializers
|
||||
) {
|
||||
var decs = decInfo[0];
|
||||
|
||||
var desc, initializer, value;
|
||||
|
||||
if (isPrivate) {
|
||||
if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) {
|
||||
desc = {
|
||||
get: decInfo[3],
|
||||
set: decInfo[4],
|
||||
};
|
||||
} else if (kind === 3 /* GETTER */) {
|
||||
desc = {
|
||||
get: decInfo[3],
|
||||
};
|
||||
} else if (kind === 4 /* SETTER */) {
|
||||
desc = {
|
||||
set: decInfo[3],
|
||||
};
|
||||
} else {
|
||||
desc = {
|
||||
value: decInfo[3],
|
||||
};
|
||||
}
|
||||
} else if (kind !== 0 /* FIELD */) {
|
||||
desc = Object.getOwnPropertyDescriptor(base, name);
|
||||
}
|
||||
|
||||
if (kind === 1 /* ACCESSOR */) {
|
||||
value = {
|
||||
get: desc.get,
|
||||
set: desc.set,
|
||||
};
|
||||
} else if (kind === 2 /* METHOD */) {
|
||||
value = desc.value;
|
||||
} else if (kind === 3 /* GETTER */) {
|
||||
value = desc.get;
|
||||
} else if (kind === 4 /* SETTER */) {
|
||||
value = desc.set;
|
||||
}
|
||||
|
||||
var ctx = memberDecCtx(
|
||||
base,
|
||||
name,
|
||||
desc,
|
||||
metadataMap,
|
||||
initializers,
|
||||
kind,
|
||||
isStatic,
|
||||
isPrivate
|
||||
);
|
||||
|
||||
var newValue, get, set;
|
||||
|
||||
if (typeof decs === "function") {
|
||||
newValue = decs(value, ctx);
|
||||
|
||||
if (newValue !== undefined) {
|
||||
assertValidReturnValue(kind, newValue);
|
||||
|
||||
if (kind === 0 /* FIELD */) {
|
||||
initializer = newValue;
|
||||
} else if (kind === 1 /* ACCESSOR */) {
|
||||
initializer = newValue.initializer;
|
||||
|
||||
get = newValue.get || value.get;
|
||||
set = newValue.set || value.set;
|
||||
|
||||
value = { get: get, set: set };
|
||||
} else {
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < decs.length; i++) {
|
||||
var dec = decs[i];
|
||||
|
||||
newValue = dec(value, ctx);
|
||||
|
||||
if (newValue !== undefined) {
|
||||
assertValidReturnValue(kind, newValue);
|
||||
var newInit;
|
||||
|
||||
if (kind === 0 /* FIELD */) {
|
||||
newInit = newValue;
|
||||
} else if (kind === 1 /* ACCESSOR */) {
|
||||
newInit = newValue.initializer;
|
||||
|
||||
get = newValue.get || value.get;
|
||||
set = newValue.set || value.set;
|
||||
|
||||
value = { get: get, set: set };
|
||||
} else {
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
if (newInit !== undefined) {
|
||||
if (initializer === undefined) {
|
||||
initializer = newInit;
|
||||
} else if (typeof initializer === "function") {
|
||||
initializer = [initializer, newInit];
|
||||
} else {
|
||||
initializer.push(newInit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) {
|
||||
if (initializer === undefined) {
|
||||
// If the initializer was undefined, sub in a dummy initializer
|
||||
initializer = function (instance, init) {
|
||||
return init;
|
||||
};
|
||||
} else if (typeof initializer !== "function") {
|
||||
var ownInitializers = initializer;
|
||||
|
||||
initializer = function (instance, init) {
|
||||
var value = init;
|
||||
|
||||
for (var i = 0; i < ownInitializers.length; i++) {
|
||||
value = ownInitializers[i].call(instance, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
} else {
|
||||
var originalInitializer = initializer;
|
||||
|
||||
initializer = function (instance, init) {
|
||||
return originalInitializer.call(instance, init);
|
||||
};
|
||||
}
|
||||
|
||||
ret.push(initializer);
|
||||
}
|
||||
|
||||
if (kind !== 0 /* FIELD */) {
|
||||
if (kind === 1 /* ACCESSOR */) {
|
||||
desc.get = value.get;
|
||||
desc.set = value.set;
|
||||
} else if (kind === 2 /* METHOD */) {
|
||||
desc.value = value;
|
||||
} else if (kind === 3 /* GETTER */) {
|
||||
desc.get = value;
|
||||
} else if (kind === 4 /* SETTER */) {
|
||||
desc.set = value;
|
||||
}
|
||||
|
||||
if (isPrivate) {
|
||||
if (kind === 1 /* ACCESSOR */) {
|
||||
ret.push(function (instance, args) {
|
||||
return value.get.call(instance, args);
|
||||
});
|
||||
ret.push(function (instance, args) {
|
||||
return value.set.call(instance, args);
|
||||
});
|
||||
} else if (kind === 2 /* METHOD */) {
|
||||
ret.push(value);
|
||||
} else {
|
||||
ret.push(function (instance, args) {
|
||||
return value.call(instance, args);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Object.defineProperty(base, name, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyMemberDecs(
|
||||
ret,
|
||||
Class,
|
||||
protoMetadataMap,
|
||||
staticMetadataMap,
|
||||
decInfos
|
||||
) {
|
||||
var protoInitializers;
|
||||
var staticInitializers;
|
||||
|
||||
var existingProtoNonFields = new Map();
|
||||
var existingStaticNonFields = new Map();
|
||||
|
||||
for (var i = 0; i < decInfos.length; i++) {
|
||||
var decInfo = decInfos[i];
|
||||
|
||||
// skip computed property names
|
||||
if (!Array.isArray(decInfo)) continue;
|
||||
|
||||
var kind = decInfo[1];
|
||||
var name = decInfo[2];
|
||||
var isPrivate = decInfo.length > 3;
|
||||
|
||||
var isStatic = kind >= 5; /* STATIC */
|
||||
var base;
|
||||
var metadataMap;
|
||||
var initializers;
|
||||
|
||||
if (isStatic) {
|
||||
base = Class;
|
||||
metadataMap = staticMetadataMap;
|
||||
kind = kind - 5 /* STATIC */;
|
||||
|
||||
if (!staticInitializers) {
|
||||
staticInitializers = [];
|
||||
}
|
||||
|
||||
initializers = staticInitializers;
|
||||
} else {
|
||||
base = Class.prototype;
|
||||
metadataMap = protoMetadataMap;
|
||||
|
||||
if (!protoInitializers) {
|
||||
protoInitializers = [];
|
||||
}
|
||||
|
||||
initializers = protoInitializers;
|
||||
}
|
||||
|
||||
if (kind !== 0 /* FIELD */ && !isPrivate) {
|
||||
var existingNonFields = isStatic
|
||||
? existingStaticNonFields
|
||||
: existingProtoNonFields;
|
||||
|
||||
var existingKind = existingNonFields.get(name) || 0;
|
||||
|
||||
if (
|
||||
existingKind === true ||
|
||||
(existingKind === 3 /* GETTER */ && kind !== 4) /* SETTER */ ||
|
||||
(existingKind === 4 /* SETTER */ && kind !== 3) /* GETTER */
|
||||
) {
|
||||
throw new Error(
|
||||
"Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " +
|
||||
name
|
||||
);
|
||||
} else if (!existingKind && kind > 2 /* METHOD */) {
|
||||
existingNonFields.set(name, kind);
|
||||
} else {
|
||||
existingNonFields.set(name, true);
|
||||
}
|
||||
}
|
||||
|
||||
applyMemberDec(
|
||||
ret,
|
||||
base,
|
||||
decInfo,
|
||||
name,
|
||||
kind,
|
||||
isStatic,
|
||||
isPrivate,
|
||||
metadataMap,
|
||||
initializers
|
||||
);
|
||||
}
|
||||
|
||||
if (protoInitializers) {
|
||||
pushInitializers(ret, protoInitializers);
|
||||
}
|
||||
|
||||
if (staticInitializers) {
|
||||
pushInitializers(ret, staticInitializers);
|
||||
}
|
||||
}
|
||||
|
||||
function pushInitializers(ret, initializers) {
|
||||
if (initializers.length > 0) {
|
||||
// Slice the array, which means that `addInitializer` can no longer add
|
||||
// additional initializers to the array
|
||||
initializers = initializers.slice();
|
||||
|
||||
ret.push(function (instance) {
|
||||
for (var i = 0; i < initializers.length; i++) {
|
||||
initializers[i].call(instance, instance);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ret.push(function () {});
|
||||
}
|
||||
}
|
||||
|
||||
function applyClassDecs(ret, targetClass, metadataMap, classDecs) {
|
||||
var initializers = [];
|
||||
var newClass = targetClass;
|
||||
|
||||
var name = targetClass.name;
|
||||
var ctx = Object.assign(
|
||||
{
|
||||
kind: "class",
|
||||
name: name,
|
||||
addInitializer: createAddInitializerMethod(initializers),
|
||||
},
|
||||
createMetadataMethodsForProperty(metadataMap, 0 /* CONSTRUCTOR */, name)
|
||||
);
|
||||
|
||||
for (var i = 0; i < classDecs.length; i++) {
|
||||
newClass = classDecs[i](newClass, ctx) || newClass;
|
||||
}
|
||||
|
||||
ret.push(newClass);
|
||||
|
||||
if (initializers.length > 0) {
|
||||
ret.push(function () {
|
||||
for (var i = 0; i < initializers.length; i++) {
|
||||
initializers[i].call(newClass, newClass);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
ret.push(function () {});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Basic usage:
|
||||
|
||||
applyDecs(
|
||||
Class,
|
||||
[
|
||||
// member decorators
|
||||
[
|
||||
dec, // dec or array of decs
|
||||
0, // kind of value being decorated
|
||||
'prop', // name of public prop on class containing the value being decorated,
|
||||
'#p', // the name of the private property (if is private, undefined otherwise),
|
||||
]
|
||||
],
|
||||
[
|
||||
// class decorators
|
||||
dec1, dec2
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
Fully transpiled example:
|
||||
|
||||
```js
|
||||
@dec
|
||||
class Class {
|
||||
@dec
|
||||
a = 123;
|
||||
|
||||
@dec
|
||||
#a = 123;
|
||||
|
||||
@dec
|
||||
@dec2
|
||||
accessor b = 123;
|
||||
|
||||
@dec
|
||||
accessor #b = 123;
|
||||
|
||||
@dec
|
||||
c() { console.log('c'); }
|
||||
|
||||
@dec
|
||||
#c() { console.log('privC'); }
|
||||
|
||||
@dec
|
||||
get d() { console.log('d'); }
|
||||
|
||||
@dec
|
||||
get #d() { console.log('privD'); }
|
||||
|
||||
@dec
|
||||
set e(v) { console.log('e'); }
|
||||
|
||||
@dec
|
||||
set #e(v) { console.log('privE'); }
|
||||
}
|
||||
|
||||
|
||||
// becomes
|
||||
let initializeInstance;
|
||||
let initializeClass;
|
||||
|
||||
let initA;
|
||||
let initPrivA;
|
||||
|
||||
let initB;
|
||||
let initPrivB, getPrivB, setPrivB;
|
||||
|
||||
let privC;
|
||||
let privD;
|
||||
let privE;
|
||||
|
||||
let Class;
|
||||
class _Class {
|
||||
static {
|
||||
let ret = applyDecs(
|
||||
this,
|
||||
[
|
||||
[dec, 0, 'a'],
|
||||
[dec, 0, 'a', (i) => i.#a, (i, v) => i.#a = v],
|
||||
[[dec, dec2], 1, 'b'],
|
||||
[dec, 1, 'b', (i) => i.#privBData, (i, v) => i.#privBData = v],
|
||||
[dec, 2, 'c'],
|
||||
[dec, 2, 'c', () => console.log('privC')],
|
||||
[dec, 3, 'd'],
|
||||
[dec, 3, 'd', () => console.log('privD')],
|
||||
[dec, 4, 'e'],
|
||||
[dec, 4, 'e', () => console.log('privE')],
|
||||
],
|
||||
[
|
||||
dec
|
||||
]
|
||||
)
|
||||
|
||||
initA = ret[0];
|
||||
|
||||
initPrivA = ret[1];
|
||||
|
||||
initB = ret[2];
|
||||
|
||||
initPrivB = ret[3];
|
||||
getPrivB = ret[4];
|
||||
setPrivB = ret[5];
|
||||
|
||||
privC = ret[6];
|
||||
|
||||
privD = ret[7];
|
||||
|
||||
privE = ret[8];
|
||||
|
||||
initializeInstance = ret[9];
|
||||
|
||||
Class = ret[10]
|
||||
|
||||
initializeClass = ret[11];
|
||||
}
|
||||
|
||||
a = (initializeInstance(this), initA(this, 123));
|
||||
|
||||
#a = initPrivA(this, 123);
|
||||
|
||||
#bData = initB(this, 123);
|
||||
get b() { return this.#bData }
|
||||
set b(v) { this.#bData = v }
|
||||
|
||||
#privBData = initPrivB(this, 123);
|
||||
get #b() { return getPrivB(this); }
|
||||
set #b(v) { setPrivB(this, v); }
|
||||
|
||||
c() { console.log('c'); }
|
||||
|
||||
#c(...args) { return privC(this, ...args) }
|
||||
|
||||
get d() { console.log('d'); }
|
||||
|
||||
get #d() { return privD(this); }
|
||||
|
||||
set e(v) { console.log('e'); }
|
||||
|
||||
set #e(v) { privE(this, v); }
|
||||
}
|
||||
|
||||
initializeClass(Class);
|
||||
*/
|
||||
export default function applyDecs(targetClass, memberDecs, classDecs) {
|
||||
var ret = [];
|
||||
var staticMetadataMap = {};
|
||||
|
||||
if (memberDecs) {
|
||||
var protoMetadataMap = {};
|
||||
|
||||
applyMemberDecs(
|
||||
ret,
|
||||
targetClass,
|
||||
protoMetadataMap,
|
||||
staticMetadataMap,
|
||||
memberDecs
|
||||
);
|
||||
|
||||
convertMetadataMapToFinal(targetClass.prototype, protoMetadataMap);
|
||||
}
|
||||
|
||||
if (classDecs) {
|
||||
applyClassDecs(ret, targetClass, staticMetadataMap, classDecs);
|
||||
}
|
||||
|
||||
convertMetadataMapToFinal(targetClass, staticMetadataMap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
374
packages/babel-plugin-proposal-decorators/CONTRIB.md
Normal file
374
packages/babel-plugin-proposal-decorators/CONTRIB.md
Normal file
@ -0,0 +1,374 @@
|
||||
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, initA, callB, computedKey, initC, getC, setC;
|
||||
|
||||
const elementDecs = [
|
||||
[dec, 0, 'a'],
|
||||
[dec, 7, 'x', '#b']
|
||||
(computedKey = someVal, null)
|
||||
[[dec, dec2], 1, 'y', '#c']
|
||||
];
|
||||
|
||||
const classDecs = [dec];
|
||||
|
||||
let Class;
|
||||
class _Class {
|
||||
static {
|
||||
let ret = applyDecs(
|
||||
this,
|
||||
elementDecs,
|
||||
[dec]
|
||||
);
|
||||
|
||||
initA = ret[0];
|
||||
callB = ret[1];
|
||||
initC = ret[2];
|
||||
getC = ret[3];
|
||||
setC = ret[4];
|
||||
initInstance = ret[5];
|
||||
Class = ret[6];
|
||||
initClass = ret[7];
|
||||
}
|
||||
|
||||
a = (initInstance(this), initA(this, 123));
|
||||
|
||||
static #b(...args) {
|
||||
callB(this, args);
|
||||
}
|
||||
static x() {
|
||||
console.log('foo');
|
||||
}
|
||||
|
||||
[computedKey]() {}
|
||||
|
||||
#y = initC(this, 123);
|
||||
get y() {
|
||||
return this.#y;
|
||||
}
|
||||
set y(v) {
|
||||
this.#y = v;
|
||||
}
|
||||
get #c() {
|
||||
return getC(this);
|
||||
}
|
||||
set #c(v) {
|
||||
setC(this, v);
|
||||
}
|
||||
|
||||
static {
|
||||
initClass(C);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Let's break this output down a bit:
|
||||
|
||||
```js
|
||||
let initInstance, initClass, initA, callB, initC, getC, setC;
|
||||
```
|
||||
|
||||
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
|
||||
const elementDecs = [
|
||||
[dec, 0, 'a'],
|
||||
[dec, 7, 'x', '#b']
|
||||
(computedKey = someVal, null)
|
||||
[[dec, dec2], 1, 'y', '#c']
|
||||
];
|
||||
|
||||
const classDecs = [dec];
|
||||
```
|
||||
|
||||
Next up, we define and evaluate the decorator member 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 {
|
||||
let ret = applyDecs(
|
||||
this,
|
||||
elementDecs,
|
||||
classDecs
|
||||
);
|
||||
|
||||
initA = ret[0];
|
||||
callB = ret[1];
|
||||
initC = ret[2];
|
||||
getC = ret[3];
|
||||
setC = ret[4];
|
||||
initInstance = ret[5];
|
||||
Class = ret[6];
|
||||
initClass = ret[7];
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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), initA(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 `initA` 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 = initA(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 `initA` externally.
|
||||
|
||||
```js
|
||||
static #b(...args) {
|
||||
callB(this, args);
|
||||
}
|
||||
static x() {
|
||||
console.log('foo');
|
||||
}
|
||||
```
|
||||
|
||||
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 `callB`
|
||||
variable, which will be populated with the fully decorated method.
|
||||
2. `static x`: This contains the _code_ of the original method. Once again, this
|
||||
code cannot be removed from the class body because it may reference private
|
||||
identifiers. However, we have moved the code to a _public_ method, which means
|
||||
we can now read its value using `Object.getOwnPropertyDescriptor`. Decorators
|
||||
use this to get the initial implementation of the method, which can then be
|
||||
wrapped with decorator code/logic. They then `delete` this temporary property,
|
||||
which is necessary because no additional elements should be added to a class
|
||||
definition.
|
||||
|
||||
The name for this method is unimportant, but because public method names
|
||||
cannot be minified and we also need to pass the name into `applyDecs`, we
|
||||
generate as small of a unique identifier as possible here, starting with 1
|
||||
char names which are not taken and growing until we find one that is free.
|
||||
|
||||
```js
|
||||
[computedKey]() {}
|
||||
```
|
||||
|
||||
Next is the undecorated method with a computed key. This uses the previously
|
||||
calculated and stored computed key.
|
||||
|
||||
```js
|
||||
#y = initC(this, 123);
|
||||
get y() {
|
||||
return this.#y;
|
||||
}
|
||||
set y(v) {
|
||||
this.#y = v;
|
||||
}
|
||||
get #c() {
|
||||
return getC(this);
|
||||
}
|
||||
set #c(v) {
|
||||
setC(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
|
||||
#y = initC(this, 123);
|
||||
```
|
||||
|
||||
`accessor #c` desugars to a getter and setter which are backed by a new private
|
||||
field, `#y`. 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 y() {
|
||||
return this.#y;
|
||||
}
|
||||
set y(v) {
|
||||
this.#y = v;
|
||||
}
|
||||
```
|
||||
|
||||
Next we have a getter and setter named `y` which provide access to the backing
|
||||
storage for the accessor. These are the base getter/setter for the accessor,
|
||||
which the decorator will get via `Object.getOwnPropertyDescriptor`. They will be
|
||||
deleted from the class fully, so again the name is not important here, just
|
||||
needs to be short.
|
||||
|
||||
```js
|
||||
get #c() {
|
||||
return getC(this);
|
||||
}
|
||||
set #c(v) {
|
||||
setC(this, v);
|
||||
}
|
||||
```
|
||||
|
||||
Next, we have the getter and setter for `#c` itself. These methods defer to
|
||||
the `getC` and `setC` local variables, which will be the decorated versions of
|
||||
the `get y` and `set y` methods from the previous step.
|
||||
|
||||
```js
|
||||
static {
|
||||
initClass(C);
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
const elementDecs = [
|
||||
[dec, 0, 'a'],
|
||||
[dec, 7, 'x', '#b']
|
||||
(computedKey = someVal, null)
|
||||
[[dec, dec2], 1, 'y', '#c']
|
||||
];
|
||||
|
||||
const classDecs = [dec];
|
||||
|
||||
// ...
|
||||
|
||||
let ret = applyDecs(
|
||||
this,
|
||||
elementDecs,
|
||||
classDecs
|
||||
);
|
||||
```
|
||||
|
||||
`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 public property that can be used to access the value.
|
||||
// For public members this is the actual name, for private members this is
|
||||
// the name of the public property which can be used to access the value
|
||||
// (see descriptions of #b and #c above)
|
||||
'y',
|
||||
|
||||
// Optional fourth value, this is the spelling of the private element's name,
|
||||
// which signals that the element is private to `applyDecs` and is used in the
|
||||
// decorator's context object
|
||||
'#c'
|
||||
],
|
||||
```
|
||||
|
||||
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.
|
||||
@ -22,7 +22,9 @@
|
||||
"dependencies": {
|
||||
"@babel/helper-create-class-features-plugin": "workspace:^",
|
||||
"@babel/helper-plugin-utils": "workspace:^",
|
||||
"@babel/plugin-syntax-decorators": "workspace:^"
|
||||
"@babel/helper-replace-supers": "workspace:^",
|
||||
"@babel/plugin-syntax-decorators": "workspace:^",
|
||||
"charcodes": "^0.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
FEATURES,
|
||||
} from "@babel/helper-create-class-features-plugin";
|
||||
import legacyVisitor from "./transformer-legacy";
|
||||
import transformer2021_12 from "./transformer-2021-12";
|
||||
|
||||
export default declare((api, options) => {
|
||||
api.assertVersion(7);
|
||||
@ -16,7 +17,7 @@ export default declare((api, options) => {
|
||||
throw new Error("'legacy' must be a boolean.");
|
||||
}
|
||||
|
||||
const { decoratorsBeforeExport } = options;
|
||||
const { decoratorsBeforeExport, version } = options;
|
||||
if (decoratorsBeforeExport === undefined) {
|
||||
if (!legacy) {
|
||||
throw new Error(
|
||||
@ -37,6 +38,10 @@ export default declare((api, options) => {
|
||||
}
|
||||
|
||||
if (legacy) {
|
||||
if (version !== undefined) {
|
||||
throw new Error("'version' can't be used with legacy decorators");
|
||||
}
|
||||
|
||||
return {
|
||||
name: "proposal-decorators",
|
||||
inherits: syntaxDecorators,
|
||||
@ -47,6 +52,12 @@ export default declare((api, options) => {
|
||||
};
|
||||
}
|
||||
|
||||
if (version === "2021-12") {
|
||||
return transformer2021_12(api, options);
|
||||
} else if (!(version === "2018-09" || version === undefined)) {
|
||||
throw new Error("Unsupported decorators version: " + version);
|
||||
}
|
||||
|
||||
return createClassFeaturePlugin({
|
||||
name: "proposal-decorators",
|
||||
|
||||
|
||||
@ -0,0 +1,987 @@
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import { types as t } from "@babel/core";
|
||||
import syntaxDecorators from "@babel/plugin-syntax-decorators";
|
||||
import ReplaceSupers from "@babel/helper-replace-supers";
|
||||
import * as charCodes from "charcodes";
|
||||
|
||||
type ClassDecoratableElement =
|
||||
| t.ClassMethod
|
||||
| t.ClassPrivateMethod
|
||||
| t.ClassProperty
|
||||
| t.ClassPrivateProperty
|
||||
| t.ClassAccessorProperty;
|
||||
|
||||
type ClassElement =
|
||||
| ClassDecoratableElement
|
||||
| t.TSDeclareMethod
|
||||
| t.TSIndexSignature
|
||||
| t.StaticBlock;
|
||||
|
||||
type classUidGenerator = <B extends boolean>(
|
||||
isPrivate: B,
|
||||
) => B extends true ? t.PrivateName : t.Identifier;
|
||||
|
||||
function incrementId(id: number[], idx = id.length - 1): void {
|
||||
// If index is -1, id needs an additional character, unshift A
|
||||
if (idx === -1) {
|
||||
id.unshift(charCodes.uppercaseA);
|
||||
return;
|
||||
}
|
||||
|
||||
const current = id[idx];
|
||||
|
||||
if (current === charCodes.uppercaseZ) {
|
||||
// if current is Z, skip to a
|
||||
id[idx] = charCodes.lowercaseA;
|
||||
} else if (current === charCodes.lowercaseZ) {
|
||||
// if current is z, reset to A and carry the 1
|
||||
id[idx] = charCodes.uppercaseA;
|
||||
incrementId(id, idx - 1);
|
||||
} else {
|
||||
// else, increment by one
|
||||
id[idx] = current + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new element name that is unique to the given class. This can be
|
||||
* used to create extra class fields and methods for the implementation, while
|
||||
* keeping the length of those names as small as possible. This is important for
|
||||
* minification purposes, since public names cannot be safely renamed/minified.
|
||||
*
|
||||
* Names are split into two namespaces, public and private. Static and non-static
|
||||
* names are shared in the same namespace, because this is true for private names
|
||||
* (you cannot have #x and static #x in the same class) and it's not worth the
|
||||
* extra complexity for public names.
|
||||
*/
|
||||
function createUidGeneratorForClass(
|
||||
body: NodePath<ClassElement>[],
|
||||
): (isPrivate: boolean) => t.Identifier | t.PrivateName {
|
||||
let currentPublicId: number[], currentPrivateId: number[];
|
||||
|
||||
const publicNames = new Set<string>();
|
||||
const privateNames = new Set<string>();
|
||||
|
||||
for (const element of body) {
|
||||
if (
|
||||
element.node.type === "TSIndexSignature" ||
|
||||
element.node.type === "StaticBlock"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { key } = element.node;
|
||||
|
||||
if (key.type === "PrivateName") {
|
||||
privateNames.add(key.id.name);
|
||||
} else if (key.type === "Identifier") {
|
||||
publicNames.add(key.name);
|
||||
}
|
||||
}
|
||||
|
||||
return (isPrivate: boolean): t.Identifier | t.PrivateName => {
|
||||
let currentId: number[], names: Set<String>;
|
||||
|
||||
if (isPrivate) {
|
||||
if (!currentPrivateId) {
|
||||
currentPrivateId = [charCodes.uppercaseA];
|
||||
}
|
||||
|
||||
currentId = currentPrivateId;
|
||||
names = privateNames;
|
||||
} else {
|
||||
if (!currentPublicId) {
|
||||
currentPublicId = [charCodes.uppercaseA];
|
||||
}
|
||||
|
||||
currentId = currentPublicId;
|
||||
names = publicNames;
|
||||
}
|
||||
|
||||
let reifiedId = String.fromCharCode(...currentId);
|
||||
|
||||
while (names.has(reifiedId)) {
|
||||
incrementId(currentId);
|
||||
reifiedId = String.fromCharCode(...currentId);
|
||||
}
|
||||
|
||||
incrementId(currentId);
|
||||
|
||||
if (isPrivate) {
|
||||
return t.privateName(t.identifier(reifiedId));
|
||||
} else {
|
||||
return t.identifier(reifiedId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the above generator function so that it's run lazily the first time
|
||||
* it's actually required. Several types of decoration do not require this, so it
|
||||
* saves iterating the class elements an additional time and allocating the space
|
||||
* for the Sets of element names.
|
||||
*/
|
||||
function createLazyUidGeneratorForClass(
|
||||
body: NodePath<ClassElement>[],
|
||||
): classUidGenerator {
|
||||
let generator: (isPrivate: boolean) => t.Identifier | t.PrivateName;
|
||||
|
||||
const lazyGenerator = (isPrivate: boolean): t.Identifier | t.PrivateName => {
|
||||
if (!generator) {
|
||||
generator = createUidGeneratorForClass(body);
|
||||
}
|
||||
|
||||
return generator(isPrivate);
|
||||
};
|
||||
|
||||
return lazyGenerator as unknown as classUidGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a class definition and replaces it with an equivalent class declaration
|
||||
* which is then assigned to a local variable. This allows us to reassign the
|
||||
* local variable with the decorated version of the class. The class definition
|
||||
* retains its original name so that `toString` is not affected, other
|
||||
* references to the class are renamed instead.
|
||||
*/
|
||||
function replaceClassWithVar(
|
||||
path: NodePath<t.ClassDeclaration | t.ClassExpression>,
|
||||
): [t.Identifier, NodePath<t.ClassDeclaration | t.ClassExpression>] {
|
||||
if (path.type === "ClassDeclaration") {
|
||||
const varId = path.scope.generateUidIdentifierBasedOnNode(path.node.id);
|
||||
const classId = t.identifier(path.node.id.name);
|
||||
|
||||
path.scope.rename(classId.name, varId.name);
|
||||
|
||||
path.insertBefore(
|
||||
t.variableDeclaration("let", [t.variableDeclarator(varId)]),
|
||||
);
|
||||
path.get("id").replaceWith(classId);
|
||||
|
||||
return [t.cloneNode(varId), path];
|
||||
} else {
|
||||
let className: string;
|
||||
let varId: t.Identifier;
|
||||
|
||||
if (path.node.id) {
|
||||
className = path.node.id.name;
|
||||
varId = generateLocalVarId(path, 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 = generateLocalVarId(path, className);
|
||||
} else {
|
||||
varId = generateLocalVarId(path, "decorated_class");
|
||||
}
|
||||
|
||||
const newClassExpr = t.classExpression(
|
||||
className && t.identifier(className),
|
||||
path.node.superClass,
|
||||
path.node.body,
|
||||
);
|
||||
|
||||
const [newPath] = path.replaceWith(
|
||||
t.sequenceExpression([newClassExpr, varId]),
|
||||
);
|
||||
|
||||
return [t.cloneNode(varId), newPath.get("expressions.0")];
|
||||
}
|
||||
}
|
||||
|
||||
function generateClassProperty(
|
||||
key: t.PrivateName | t.Identifier,
|
||||
value: t.Expression | undefined,
|
||||
isStatic: boolean,
|
||||
): t.ClassPrivateProperty | t.ClassProperty {
|
||||
if (key.type === "PrivateName") {
|
||||
return t.classPrivateProperty(key, value, undefined, isStatic);
|
||||
} else {
|
||||
return t.classProperty(key, value, undefined, undefined, isStatic);
|
||||
}
|
||||
}
|
||||
|
||||
function addProxyAccessorsFor(
|
||||
element: NodePath<ClassDecoratableElement>,
|
||||
originalKey: t.PrivateName | t.Expression,
|
||||
targetKey: t.PrivateName,
|
||||
isComputed = false,
|
||||
): void {
|
||||
const { static: isStatic } = element.node;
|
||||
|
||||
const getterBody = t.blockStatement([
|
||||
t.returnStatement(
|
||||
t.memberExpression(t.thisExpression(), t.cloneNode(targetKey)),
|
||||
),
|
||||
]);
|
||||
|
||||
const setterBody = t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(t.thisExpression(), t.cloneNode(targetKey)),
|
||||
t.identifier("v"),
|
||||
),
|
||||
),
|
||||
]);
|
||||
|
||||
let getter: t.ClassMethod | t.ClassPrivateMethod,
|
||||
setter: t.ClassMethod | t.ClassPrivateMethod;
|
||||
|
||||
if (originalKey.type === "PrivateName") {
|
||||
getter = t.classPrivateMethod(
|
||||
"get",
|
||||
t.cloneNode(originalKey),
|
||||
[],
|
||||
getterBody,
|
||||
isStatic,
|
||||
);
|
||||
setter = t.classPrivateMethod(
|
||||
"set",
|
||||
t.cloneNode(originalKey),
|
||||
[t.identifier("v")],
|
||||
setterBody,
|
||||
isStatic,
|
||||
);
|
||||
} else {
|
||||
getter = t.classMethod(
|
||||
"get",
|
||||
t.cloneNode(originalKey),
|
||||
[],
|
||||
getterBody,
|
||||
isComputed,
|
||||
isStatic,
|
||||
);
|
||||
setter = t.classMethod(
|
||||
"set",
|
||||
t.cloneNode(originalKey),
|
||||
[t.identifier("v")],
|
||||
setterBody,
|
||||
isComputed,
|
||||
isStatic,
|
||||
);
|
||||
}
|
||||
|
||||
element.insertAfter(setter);
|
||||
element.insertAfter(getter);
|
||||
}
|
||||
|
||||
function extractProxyAccessorsFor(
|
||||
targetKey: t.PrivateName,
|
||||
): t.FunctionExpression[] {
|
||||
return [
|
||||
t.functionExpression(
|
||||
undefined,
|
||||
[],
|
||||
t.blockStatement([
|
||||
t.returnStatement(
|
||||
t.memberExpression(t.thisExpression(), t.cloneNode(targetKey)),
|
||||
),
|
||||
]),
|
||||
),
|
||||
t.functionExpression(
|
||||
undefined,
|
||||
[t.identifier("value")],
|
||||
t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(t.thisExpression(), t.cloneNode(targetKey)),
|
||||
t.identifier("value"),
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
const FIELD = 0;
|
||||
const ACCESSOR = 1;
|
||||
const METHOD = 2;
|
||||
const GETTER = 3;
|
||||
const SETTER = 4;
|
||||
|
||||
const STATIC = 5;
|
||||
|
||||
function getElementKind(element: NodePath<ClassDecoratableElement>): number {
|
||||
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 generateLocalVarId(path: NodePath, name: string): t.Identifier {
|
||||
const varId = path.scope.generateUidIdentifier(name);
|
||||
path.scope.parent.push({ id: varId });
|
||||
return t.cloneNode(varId);
|
||||
}
|
||||
|
||||
// Information about the decorators applied to an element
|
||||
interface DecoratorInfo {
|
||||
// The expressions of the decorators themselves
|
||||
decorators: t.Expression[];
|
||||
|
||||
// The kind of the decorated value, matches the kind value passed to applyDecs
|
||||
kind: number;
|
||||
|
||||
// whether or not the field is static
|
||||
isStatic: boolean;
|
||||
|
||||
// The name of the decorator
|
||||
name: t.StringLiteral | t.Expression;
|
||||
|
||||
privateMethods: t.FunctionExpression | t.FunctionExpression[] | undefined;
|
||||
|
||||
// The names of local variables that will be used/returned from the decoration
|
||||
locals: t.Identifier | t.Identifier[] | undefined;
|
||||
}
|
||||
|
||||
// Information about a computed property key. These must be evaluated
|
||||
// interspersed with decorator expressions, which is why they get added to the
|
||||
// array of DecoratorInfos later on.
|
||||
interface ComputedPropInfo {
|
||||
localComputedNameId: t.Identifier;
|
||||
keyNode: t.Expression;
|
||||
}
|
||||
|
||||
function isDecoratorInfo(
|
||||
info: DecoratorInfo | ComputedPropInfo,
|
||||
): info is DecoratorInfo {
|
||||
return "decorators" in info;
|
||||
}
|
||||
|
||||
function generateDecorationExprs(
|
||||
info: (DecoratorInfo | ComputedPropInfo)[],
|
||||
): t.ArrayExpression {
|
||||
return t.arrayExpression(
|
||||
info.filter(isDecoratorInfo).map(el => {
|
||||
const decs =
|
||||
el.decorators.length > 1
|
||||
? t.arrayExpression(el.decorators)
|
||||
: el.decorators[0];
|
||||
|
||||
const kind = el.isStatic ? el.kind + STATIC : el.kind;
|
||||
|
||||
const decInfo = [decs, t.numericLiteral(kind), el.name];
|
||||
|
||||
const { privateMethods } = el;
|
||||
|
||||
if (Array.isArray(privateMethods)) {
|
||||
decInfo.push(...privateMethods);
|
||||
} else if (privateMethods) {
|
||||
decInfo.push(privateMethods);
|
||||
}
|
||||
|
||||
return t.arrayExpression(decInfo);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function extractElementLocalAssignments(
|
||||
decorationInfo: (DecoratorInfo | ComputedPropInfo)[],
|
||||
) {
|
||||
const locals: t.Identifier[] = [];
|
||||
|
||||
for (const el of decorationInfo) {
|
||||
if ("locals" in el && el.locals) {
|
||||
if (Array.isArray(el.locals)) {
|
||||
locals.push(...el.locals);
|
||||
} else {
|
||||
locals.push(el.locals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return locals;
|
||||
}
|
||||
|
||||
function addCallAccessorsFor(
|
||||
element: NodePath,
|
||||
key: t.PrivateName,
|
||||
getId: t.Identifier,
|
||||
setId: t.Identifier,
|
||||
) {
|
||||
element.insertAfter(
|
||||
t.classPrivateMethod(
|
||||
"get",
|
||||
t.cloneNode(key),
|
||||
[],
|
||||
t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.cloneNode(getId), [t.thisExpression()]),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
element.insertAfter(
|
||||
t.classPrivateMethod(
|
||||
"set",
|
||||
t.cloneNode(key),
|
||||
[t.identifier("v")],
|
||||
t.blockStatement([
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.cloneNode(setId), [
|
||||
t.thisExpression(),
|
||||
t.identifier("v"),
|
||||
]),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function isNotTsParameter(
|
||||
node: t.Identifier | t.Pattern | t.RestElement | t.TSParameterProperty,
|
||||
): node is t.Identifier | t.Pattern | t.RestElement {
|
||||
return node.type !== "TSParameterProperty";
|
||||
}
|
||||
|
||||
function movePrivateAccessor(
|
||||
element: NodePath<t.ClassPrivateMethod>,
|
||||
key: t.PrivateName,
|
||||
methodLocalVar: t.Identifier,
|
||||
isStatic: boolean,
|
||||
) {
|
||||
let params: (t.Identifier | t.RestElement)[];
|
||||
let block: t.Statement[];
|
||||
|
||||
if (element.node.kind === "set") {
|
||||
params = [t.identifier("v")];
|
||||
block = [
|
||||
t.expressionStatement(
|
||||
t.callExpression(methodLocalVar, [
|
||||
t.thisExpression(),
|
||||
t.identifier("v"),
|
||||
]),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
params = [];
|
||||
block = [
|
||||
t.returnStatement(t.callExpression(methodLocalVar, [t.thisExpression()])),
|
||||
];
|
||||
}
|
||||
|
||||
element.replaceWith(
|
||||
t.classPrivateMethod(
|
||||
element.node.kind,
|
||||
t.cloneNode(key),
|
||||
params,
|
||||
t.blockStatement(block),
|
||||
isStatic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function isClassDecoratableElementPath(
|
||||
path: NodePath<ClassElement>,
|
||||
): path is NodePath<ClassDecoratableElement> {
|
||||
const { type } = path;
|
||||
|
||||
return (
|
||||
type !== "TSDeclareMethod" &&
|
||||
type !== "TSIndexSignature" &&
|
||||
type !== "StaticBlock"
|
||||
);
|
||||
}
|
||||
|
||||
function transformClass(
|
||||
path: NodePath<t.ClassExpression | t.ClassDeclaration>,
|
||||
state: any,
|
||||
constantSuper: boolean,
|
||||
): NodePath {
|
||||
const body = path.get("body.body");
|
||||
|
||||
const classDecorators = path.node.decorators;
|
||||
let hasElementDecorators = false;
|
||||
|
||||
const generateClassUid = createLazyUidGeneratorForClass(body);
|
||||
|
||||
// Iterate over the class to see if we need to decorate it, and also to
|
||||
// transform simple auto accessors which are not decorated
|
||||
for (const element of body) {
|
||||
if (!isClassDecoratableElementPath(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.node.decorators) {
|
||||
hasElementDecorators = true;
|
||||
} else if (element.node.type === "ClassAccessorProperty") {
|
||||
const { key, value, static: isStatic } = element.node;
|
||||
|
||||
const newId = generateClassUid(true);
|
||||
|
||||
const valueNode = value ? t.cloneNode(value) : undefined;
|
||||
|
||||
const newField = generateClassProperty(newId, valueNode, isStatic);
|
||||
|
||||
const [newPath] = element.replaceWith(newField);
|
||||
addProxyAccessorsFor(newPath, key, newId, element.node.computed);
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing is decorated, return
|
||||
if (!classDecorators && !hasElementDecorators) return;
|
||||
|
||||
const elementDecoratorInfo: (DecoratorInfo | ComputedPropInfo)[] = [];
|
||||
|
||||
let firstFieldPath:
|
||||
| NodePath<t.ClassProperty | t.ClassPrivateProperty>
|
||||
| undefined;
|
||||
let constructorPath: NodePath<t.ClassMethod> | undefined;
|
||||
let requiresProtoInit = false;
|
||||
let requiresStaticInit = false;
|
||||
let hasComputedProps = false;
|
||||
const decoratedPrivateMethods = new Set<string>();
|
||||
|
||||
let protoInitLocal: t.Identifier,
|
||||
staticInitLocal: t.Identifier,
|
||||
classInitLocal: t.Identifier,
|
||||
classLocal: t.Identifier;
|
||||
|
||||
if (classDecorators) {
|
||||
classInitLocal = generateLocalVarId(path, "initClass");
|
||||
|
||||
const [localId, classPath] = replaceClassWithVar(path);
|
||||
path = classPath;
|
||||
classLocal = localId;
|
||||
|
||||
path.node.decorators = null;
|
||||
} else {
|
||||
if (!path.node.id) {
|
||||
path.node.id = path.scope.generateUidIdentifier("Class");
|
||||
}
|
||||
classLocal = t.cloneNode(path.node.id);
|
||||
}
|
||||
|
||||
if (hasElementDecorators) {
|
||||
for (const element of body) {
|
||||
if (!isClassDecoratableElementPath(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let { key } = element.node;
|
||||
const kind = getElementKind(element);
|
||||
const decorators = element.get("decorators");
|
||||
|
||||
const isPrivate = key.type === "PrivateName";
|
||||
const isComputed =
|
||||
"computed" in element.node && element.node.computed === true;
|
||||
const isStatic = !!element.node.static;
|
||||
|
||||
let name = "computedKey";
|
||||
|
||||
if (isPrivate) {
|
||||
name = (key as t.PrivateName).id.name;
|
||||
} else if (key.type === "Identifier") {
|
||||
name = key.name;
|
||||
}
|
||||
|
||||
if (
|
||||
element.node.type === "ClassMethod" &&
|
||||
element.node.kind === "constructor"
|
||||
) {
|
||||
constructorPath = element as NodePath<t.ClassMethod>;
|
||||
}
|
||||
|
||||
if (isComputed) {
|
||||
const keyPath = element.get("key");
|
||||
const localComputedNameId = generateLocalVarId(keyPath, name);
|
||||
keyPath.replaceWith(localComputedNameId);
|
||||
|
||||
elementDecoratorInfo.push({
|
||||
localComputedNameId: t.cloneNode(localComputedNameId),
|
||||
keyNode: t.cloneNode(key as t.Expression),
|
||||
});
|
||||
|
||||
key = localComputedNameId;
|
||||
hasComputedProps = true;
|
||||
}
|
||||
|
||||
if (Array.isArray(decorators)) {
|
||||
let locals: t.Identifier | t.Identifier[];
|
||||
let privateMethods: t.FunctionExpression | t.FunctionExpression[];
|
||||
|
||||
if (kind === ACCESSOR) {
|
||||
const { value } = element.node as t.ClassAccessorProperty;
|
||||
|
||||
const params: t.Expression[] = [t.thisExpression()];
|
||||
|
||||
if (value) {
|
||||
params.push(t.cloneNode(value));
|
||||
}
|
||||
|
||||
const newId = generateClassUid(true);
|
||||
const newFieldInitId = generateLocalVarId(element, `init_${name}`);
|
||||
const newValue = t.callExpression(
|
||||
t.cloneNode(newFieldInitId),
|
||||
params,
|
||||
);
|
||||
|
||||
const newField = generateClassProperty(newId, newValue, isStatic);
|
||||
const [newPath] = element.replaceWith(newField);
|
||||
|
||||
if (isPrivate) {
|
||||
privateMethods = extractProxyAccessorsFor(newId);
|
||||
|
||||
const getId = generateLocalVarId(newPath, `get_${name}`);
|
||||
const setId = generateLocalVarId(newPath, `set_${name}`);
|
||||
|
||||
addCallAccessorsFor(newPath, key as t.PrivateName, getId, setId);
|
||||
|
||||
locals = [newFieldInitId, getId, setId];
|
||||
} else {
|
||||
addProxyAccessorsFor(newPath, key, newId, isComputed);
|
||||
locals = newFieldInitId;
|
||||
}
|
||||
} else if (kind === FIELD) {
|
||||
const initId = generateLocalVarId(element, `init_${name}`);
|
||||
const valuePath = (
|
||||
element as NodePath<t.ClassProperty | t.ClassPrivateProperty>
|
||||
).get("value");
|
||||
|
||||
valuePath.replaceWith(
|
||||
t.callExpression(
|
||||
t.cloneNode(initId),
|
||||
[t.thisExpression(), valuePath.node].filter(v => v),
|
||||
),
|
||||
);
|
||||
|
||||
locals = initId;
|
||||
|
||||
if (isPrivate) {
|
||||
privateMethods = extractProxyAccessorsFor(key as t.PrivateName);
|
||||
}
|
||||
} else if (isPrivate) {
|
||||
locals = generateLocalVarId(element, `call_${name}`);
|
||||
|
||||
const replaceSupers = new ReplaceSupers({
|
||||
constantSuper,
|
||||
methodPath: element,
|
||||
objectRef: classLocal,
|
||||
superRef: path.node.superClass,
|
||||
file: state,
|
||||
refToPreserve: classLocal,
|
||||
});
|
||||
|
||||
replaceSupers.replace();
|
||||
|
||||
const {
|
||||
params,
|
||||
body,
|
||||
async: isAsync,
|
||||
} = element.node as t.ClassPrivateMethod;
|
||||
|
||||
privateMethods = t.functionExpression(
|
||||
undefined,
|
||||
params.filter(isNotTsParameter),
|
||||
body,
|
||||
isAsync,
|
||||
);
|
||||
|
||||
if (kind === GETTER || kind === SETTER) {
|
||||
movePrivateAccessor(
|
||||
element as NodePath<t.ClassPrivateMethod>,
|
||||
t.cloneNode(key as t.PrivateName),
|
||||
t.cloneNode(locals),
|
||||
isStatic,
|
||||
);
|
||||
} else {
|
||||
const node = element.node as t.ClassPrivateMethod;
|
||||
|
||||
// Unshift
|
||||
path.node.body.body.unshift(
|
||||
t.classPrivateProperty(
|
||||
key as t.PrivateName,
|
||||
t.cloneNode(locals),
|
||||
[],
|
||||
node.static,
|
||||
),
|
||||
);
|
||||
|
||||
decoratedPrivateMethods.add((key as t.PrivateName).id.name);
|
||||
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
|
||||
let nameExpr: t.Expression;
|
||||
|
||||
if (isComputed) {
|
||||
nameExpr = t.cloneNode(key as t.Expression);
|
||||
} else if (key.type === "PrivateName") {
|
||||
nameExpr = t.stringLiteral(key.id.name);
|
||||
} else if (key.type === "Identifier") {
|
||||
nameExpr = t.stringLiteral(key.name);
|
||||
} else {
|
||||
nameExpr = t.cloneNode(key as t.Expression);
|
||||
}
|
||||
|
||||
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 as NodePath<
|
||||
t.ClassProperty | t.ClassPrivateProperty
|
||||
>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasComputedProps) {
|
||||
const assignments: t.AssignmentExpression[] = [];
|
||||
|
||||
for (const info of elementDecoratorInfo) {
|
||||
if (isDecoratorInfo(info)) {
|
||||
const { decorators } = info;
|
||||
const newDecorators: t.Identifier[] = [];
|
||||
|
||||
for (const decorator of decorators) {
|
||||
const localComputedNameId = generateLocalVarId(path, "dec");
|
||||
assignments.push(
|
||||
t.assignmentExpression("=", localComputedNameId, decorator),
|
||||
);
|
||||
newDecorators.push(t.cloneNode(localComputedNameId));
|
||||
}
|
||||
|
||||
info.decorators = newDecorators;
|
||||
} else {
|
||||
assignments.push(
|
||||
t.assignmentExpression("=", info.localComputedNameId, info.keyNode),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
path.insertBefore(assignments);
|
||||
}
|
||||
|
||||
const elementDecorations = generateDecorationExprs(elementDecoratorInfo);
|
||||
const classDecorations = t.arrayExpression(
|
||||
(classDecorators || []).map(d => d.expression),
|
||||
);
|
||||
|
||||
const locals: t.Identifier[] =
|
||||
extractElementLocalAssignments(elementDecoratorInfo);
|
||||
|
||||
if (classDecorators) {
|
||||
locals.push(classLocal, classInitLocal);
|
||||
}
|
||||
|
||||
if (requiresProtoInit) {
|
||||
protoInitLocal = generateLocalVarId(path, "initProto");
|
||||
locals.push(protoInitLocal);
|
||||
|
||||
const protoInitCall = t.callExpression(t.cloneNode(protoInitLocal), [
|
||||
t.thisExpression(),
|
||||
]);
|
||||
|
||||
if (firstFieldPath) {
|
||||
const value = firstFieldPath.get("value");
|
||||
const body: t.Expression[] = [protoInitCall];
|
||||
|
||||
if (value.node) {
|
||||
body.push(value.node);
|
||||
}
|
||||
|
||||
value.replaceWith(t.sequenceExpression(body));
|
||||
} else if (constructorPath) {
|
||||
if (path.node.superClass) {
|
||||
let found = false;
|
||||
|
||||
path.traverse({
|
||||
Super(path) {
|
||||
const { parentPath } = path;
|
||||
|
||||
if (found || parentPath.node.type !== "CallExpression") return;
|
||||
|
||||
found = true;
|
||||
|
||||
const prop = generateLocalVarId(path, "super");
|
||||
parentPath.replaceWith(
|
||||
t.sequenceExpression([
|
||||
t.assignmentExpression("=", t.cloneNode(prop), parentPath.node),
|
||||
protoInitCall,
|
||||
t.cloneNode(prop),
|
||||
]),
|
||||
);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
constructorPath.node.body.body.unshift(
|
||||
t.expressionStatement(protoInitCall),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const body: t.Statement[] = [t.expressionStatement(protoInitCall)];
|
||||
|
||||
if (path.node.superClass) {
|
||||
body.unshift(
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.super(), [
|
||||
t.spreadElement(t.identifier("args")),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
path.node.body.body.unshift(
|
||||
t.classMethod(
|
||||
"constructor",
|
||||
t.identifier("constructor"),
|
||||
[t.restElement(t.identifier("args"))],
|
||||
t.blockStatement(body),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresStaticInit) {
|
||||
staticInitLocal = generateLocalVarId(path, "initStatic");
|
||||
locals.push(staticInitLocal);
|
||||
}
|
||||
|
||||
const staticBlock = t.staticBlock(
|
||||
[
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
"=",
|
||||
t.arrayPattern(locals),
|
||||
t.callExpression(state.addHelper("applyDecs"), [
|
||||
t.thisExpression(),
|
||||
elementDecorations,
|
||||
classDecorations,
|
||||
]),
|
||||
),
|
||||
),
|
||||
requiresStaticInit &&
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.cloneNode(staticInitLocal), [t.thisExpression()]),
|
||||
),
|
||||
].filter(v => v),
|
||||
);
|
||||
|
||||
path.node.body.body.unshift(staticBlock as unknown as ClassElement);
|
||||
|
||||
if (classInitLocal) {
|
||||
path.node.body.body.push(
|
||||
t.staticBlock([
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.cloneNode(classInitLocal), []),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
// this.bar().#x = 123;
|
||||
(parentParentPath.node.type === "AssignmentExpression" &&
|
||||
parentParentPath.node.left === parentPath.node) ||
|
||||
// this.#x++;
|
||||
parentParentPath.node.type === "UpdateExpression" ||
|
||||
// ([...this.#x] = foo);
|
||||
parentParentPath.node.type === "RestElement" ||
|
||||
// ([this.#x] = foo);
|
||||
parentParentPath.node.type === "ArrayPattern" ||
|
||||
// ({ a: this.#x } = bar);
|
||||
(parentParentPath.node.type === "ObjectProperty" &&
|
||||
parentParentPath.node.value === parentPath.node &&
|
||||
parentParentPath.parentPath.type === "ObjectPattern") ||
|
||||
// for (this.#x of []);
|
||||
(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.`,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Recrawl the scope to make sure new identifiers are properly synced
|
||||
path.scope.crawl();
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
export default function (
|
||||
{ assertVersion, assumption },
|
||||
{ decoratorsBeforeExport, loose },
|
||||
) {
|
||||
assertVersion("^7.16.0");
|
||||
|
||||
const VISITED = new WeakSet<NodePath>();
|
||||
const constantSuper = assumption("constantSuper") ?? loose;
|
||||
|
||||
return {
|
||||
name: "proposal-decorators",
|
||||
inherits: syntaxDecorators,
|
||||
manipulateOptions({ generatorOpts }) {
|
||||
generatorOpts.decoratorsBeforeExport = decoratorsBeforeExport;
|
||||
},
|
||||
|
||||
visitor: {
|
||||
ClassDeclaration(path: NodePath<t.ClassDeclaration>, state: any) {
|
||||
if (VISITED.has(path)) return;
|
||||
|
||||
const newPath = transformClass(path, state, constantSuper);
|
||||
|
||||
if (newPath) {
|
||||
VISITED.add(newPath);
|
||||
}
|
||||
},
|
||||
|
||||
ClassExpression(path: NodePath<t.ClassExpression>, state: any) {
|
||||
if (VISITED.has(path)) return;
|
||||
|
||||
const newPath = transformClass(path, state, constantSuper);
|
||||
|
||||
if (newPath) {
|
||||
VISITED.add(newPath);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
54
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/exec.js
vendored
Normal file
54
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/exec.js
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
function dec({ get, set }, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return {
|
||||
get() {
|
||||
return get.call(this) + 1;
|
||||
},
|
||||
|
||||
set(v) {
|
||||
set.call(this, v + 1);
|
||||
},
|
||||
|
||||
initializer(v) {
|
||||
return v ? v : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
accessor #a;
|
||||
|
||||
@dec
|
||||
accessor #b = 123;
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['#aContext'];
|
||||
const bContext = foo['#bContext'];
|
||||
|
||||
expect(aContext.access.get.call(foo)).toBe(2);
|
||||
aContext.access.set.call(foo, 123);
|
||||
expect(aContext.access.get.call(foo)).toBe(125);
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('accessor');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.access.get.call(foo)).toBe(124);
|
||||
bContext.access.set.call(foo, 123);
|
||||
expect(bContext.access.get.call(foo)).toBe(125);
|
||||
expect(bContext.name).toBe('#b');
|
||||
expect(bContext.kind).toBe('accessor');
|
||||
expect(bContext.isStatic).toBe(false);
|
||||
expect(bContext.isPrivate).toBe(true);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/input.js
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/input.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
@dec
|
||||
accessor #a;
|
||||
|
||||
@dec
|
||||
accessor #b = 123;
|
||||
}
|
||||
59
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/output.js
vendored
Normal file
59
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/private/output.js
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto;
|
||||
|
||||
var _A = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _B = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _b = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _b, {
|
||||
get: _get_b2,
|
||||
set: _set_b2
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
get: _get_a2,
|
||||
set: _set_a2
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _A, {
|
||||
writable: true,
|
||||
value: (_initProto(this), _init_a(this))
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _B, {
|
||||
writable: true,
|
||||
value: _init_b(this, 123)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _set_a2(v) {
|
||||
_set_a(this, v);
|
||||
}
|
||||
|
||||
function _get_a2() {
|
||||
_get_a(this);
|
||||
}
|
||||
|
||||
function _set_b2(v) {
|
||||
_set_b(this, v);
|
||||
}
|
||||
|
||||
function _get_b2() {
|
||||
_get_b(this);
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initProto] = babelHelpers.applyDecs(Foo, [[dec, 1, "a", function () {
|
||||
return babelHelpers.classPrivateFieldGet(this, _A);
|
||||
}, function (value) {
|
||||
babelHelpers.classPrivateFieldSet(this, _A, value);
|
||||
}], [dec, 1, "b", function () {
|
||||
return babelHelpers.classPrivateFieldGet(this, _B);
|
||||
}, function (value) {
|
||||
babelHelpers.classPrivateFieldSet(this, _B, value);
|
||||
}]], []);
|
||||
})();
|
||||
75
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/exec.js
vendored
Normal file
75
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/exec.js
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
function dec({ get, set }, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return {
|
||||
get() {
|
||||
return get.call(this) + 1;
|
||||
},
|
||||
|
||||
set(v) {
|
||||
set.call(this, v + 1);
|
||||
},
|
||||
|
||||
initializer(v) {
|
||||
return v ? v : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
accessor a;
|
||||
|
||||
@dec
|
||||
accessor b = 123;
|
||||
|
||||
@dec
|
||||
accessor ['c'] = 456;
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['aContext'];
|
||||
const bContext = foo['bContext'];
|
||||
const cContext = foo['cContext'];
|
||||
|
||||
expect(foo.a).toBe(2);
|
||||
foo.a = 123;
|
||||
expect(foo.a).toBe(125);
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('accessor');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('a')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('a')).toBe(true);
|
||||
|
||||
expect(foo.b).toBe(124);
|
||||
foo.b = 123;
|
||||
expect(foo.b).toBe(125);
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('accessor');
|
||||
expect(bContext.isStatic).toBe(false);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('b')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('b')).toBe(true);
|
||||
|
||||
expect(foo.c).toBe(457);
|
||||
foo.c = 456;
|
||||
expect(foo.c).toBe(458);
|
||||
expect(cContext.name).toBe('c');
|
||||
expect(cContext.kind).toBe('accessor');
|
||||
expect(cContext.isStatic).toBe(false);
|
||||
expect(cContext.isPrivate).toBe(false);
|
||||
expect(typeof cContext.addInitializer).toBe('function');
|
||||
expect(typeof cContext.setMetadata).toBe('function');
|
||||
expect(typeof cContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('c')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('c')).toBe(true);
|
||||
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/input.js
vendored
Normal file
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/input.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
@dec
|
||||
accessor a;
|
||||
|
||||
@dec
|
||||
accessor b = 123;
|
||||
|
||||
@dec
|
||||
accessor ['c'] = 456;
|
||||
}
|
||||
58
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/output.js
vendored
Normal file
58
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/public/output.js
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initProto;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'c'
|
||||
_dec3 = dec
|
||||
|
||||
var _A = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _B = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _C = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _A, {
|
||||
writable: true,
|
||||
value: (_initProto(this), _init_a(this))
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _B, {
|
||||
writable: true,
|
||||
value: _init_b(this, 123)
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _C, {
|
||||
writable: true,
|
||||
value: _init_computedKey(this, 456)
|
||||
});
|
||||
}
|
||||
|
||||
get a() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _A);
|
||||
}
|
||||
|
||||
set a(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _A, v);
|
||||
}
|
||||
|
||||
get b() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _B);
|
||||
}
|
||||
|
||||
set b(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _B, v);
|
||||
}
|
||||
|
||||
get [_computedKey]() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _C);
|
||||
}
|
||||
|
||||
set [_computedKey](v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _C, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b, _init_computedKey, _initProto] = babelHelpers.applyDecs(Foo, [[_dec, 1, "a"], [_dec2, 1, "b"], [_dec3, 1, _computedKey]], []);
|
||||
})();
|
||||
52
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-private/exec.js
vendored
Normal file
52
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-private/exec.js
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
function dec({ get, set }, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return {
|
||||
get() {
|
||||
return get.call(this) + 1;
|
||||
},
|
||||
|
||||
set(v) {
|
||||
set.call(this, v + 1);
|
||||
},
|
||||
|
||||
initializer(v) {
|
||||
return v ? v : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
static accessor #a;
|
||||
|
||||
@dec
|
||||
static accessor #b = 123;
|
||||
}
|
||||
|
||||
const aContext = Foo['#aContext'];
|
||||
const bContext = Foo['#bContext'];
|
||||
|
||||
expect(aContext.access.get.call(Foo)).toBe(2);
|
||||
aContext.access.set.call(Foo, 123);
|
||||
expect(aContext.access.get.call(Foo)).toBe(125);
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('accessor');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.access.get.call(Foo)).toBe(124);
|
||||
bContext.access.set.call(Foo, 123);
|
||||
expect(bContext.access.get.call(Foo)).toBe(125);
|
||||
expect(bContext.name).toBe('#b');
|
||||
expect(bContext.kind).toBe('accessor');
|
||||
expect(bContext.isStatic).toBe(true);
|
||||
expect(bContext.isPrivate).toBe(true);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
@dec
|
||||
static accessor #a;
|
||||
|
||||
@dec
|
||||
static accessor #b = 123;
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
var _init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic;
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _b = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _b, {
|
||||
get: _get_b2,
|
||||
set: _set_b2
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
get: _get_a2,
|
||||
set: _set_a2
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _set_a2(v) {
|
||||
_set_a(this, v);
|
||||
}
|
||||
|
||||
function _get_a2() {
|
||||
_get_a(this);
|
||||
}
|
||||
|
||||
function _set_b2(v) {
|
||||
_set_b(this, v);
|
||||
}
|
||||
|
||||
function _get_b2() {
|
||||
_get_b(this);
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _get_a, _set_a, _init_b, _get_b, _set_b, _initStatic] = babelHelpers.applyDecs(Foo, [[dec, 6, "a", function () {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _A);
|
||||
}, function (value) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _A, value);
|
||||
}], [dec, 6, "b", function () {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _B);
|
||||
}, function (value) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _B, value);
|
||||
}]], []);
|
||||
|
||||
_initStatic(Foo);
|
||||
})();
|
||||
|
||||
var _A = {
|
||||
writable: true,
|
||||
value: _init_a(Foo)
|
||||
};
|
||||
var _B = {
|
||||
writable: true,
|
||||
value: _init_b(Foo, 123)
|
||||
};
|
||||
70
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-public/exec.js
vendored
Normal file
70
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-public/exec.js
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
function dec({ get, set }, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return {
|
||||
get() {
|
||||
return get.call(this) + 1;
|
||||
},
|
||||
|
||||
set(v) {
|
||||
set.call(this, v + 1);
|
||||
},
|
||||
|
||||
initializer(v) {
|
||||
return v ? v : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
static accessor a;
|
||||
|
||||
@dec
|
||||
static accessor b = 123;
|
||||
|
||||
@dec
|
||||
static accessor ['c'] = 456;
|
||||
}
|
||||
|
||||
const aContext = Foo['aContext'];
|
||||
const bContext = Foo['bContext'];
|
||||
const cContext = Foo['cContext'];
|
||||
|
||||
expect(Foo.a).toBe(2);
|
||||
Foo.a = 123;
|
||||
expect(Foo.a).toBe(125);
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('accessor');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('a')).toBe(true);
|
||||
|
||||
expect(Foo.b).toBe(124);
|
||||
Foo.b = 123;
|
||||
expect(Foo.b).toBe(125);
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('accessor');
|
||||
expect(bContext.isStatic).toBe(true);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('b')).toBe(true);
|
||||
|
||||
expect(Foo.c).toBe(457);
|
||||
Foo.c = 456;
|
||||
expect(Foo.c).toBe(458);
|
||||
expect(cContext.name).toBe('c');
|
||||
expect(cContext.kind).toBe('accessor');
|
||||
expect(cContext.isStatic).toBe(true);
|
||||
expect(cContext.isPrivate).toBe(false);
|
||||
expect(typeof cContext.addInitializer).toBe('function');
|
||||
expect(typeof cContext.setMetadata).toBe('function');
|
||||
expect(typeof cContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('c')).toBe(true);
|
||||
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-public/input.js
vendored
Normal file
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-accessors/static-public/input.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
@dec
|
||||
static accessor a;
|
||||
|
||||
@dec
|
||||
static accessor b = 123;
|
||||
|
||||
@dec
|
||||
static accessor ['c'] = 456;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3, _initStatic;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'c'
|
||||
_dec3 = dec
|
||||
|
||||
class Foo {
|
||||
static get a() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _A);
|
||||
}
|
||||
|
||||
static set a(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _A, v);
|
||||
}
|
||||
|
||||
static get b() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _B);
|
||||
}
|
||||
|
||||
static set b(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _B, v);
|
||||
}
|
||||
|
||||
static get [_computedKey]() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _C);
|
||||
}
|
||||
|
||||
static set [_computedKey](v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _C, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b, _init_computedKey, _initStatic] = babelHelpers.applyDecs(Foo, [[_dec, 6, "a"], [_dec2, 6, "b"], [_dec3, 6, _computedKey]], []);
|
||||
|
||||
_initStatic(Foo);
|
||||
})();
|
||||
|
||||
var _A = {
|
||||
writable: true,
|
||||
value: _init_a(Foo)
|
||||
};
|
||||
var _B = {
|
||||
writable: true,
|
||||
value: _init_b(Foo, 123)
|
||||
};
|
||||
var _C = {
|
||||
writable: true,
|
||||
value: _init_computedKey(Foo, 456)
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
class Foo {
|
||||
accessor #a;
|
||||
|
||||
accessor #b = 123;
|
||||
|
||||
getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
|
||||
getB() {
|
||||
return this.#b;
|
||||
}
|
||||
|
||||
setB(v) {
|
||||
this.#b = v;
|
||||
}
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
expect(foo.getA()).toBe(undefined);
|
||||
foo.setA(123)
|
||||
expect(foo.getA()).toBe(123);
|
||||
|
||||
expect(foo.getB()).toBe(123);
|
||||
foo.setB(456)
|
||||
expect(foo.getB()).toBe(456);
|
||||
@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
accessor #a;
|
||||
|
||||
accessor #b = 123;
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
var _A = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _B = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _b = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _b, {
|
||||
get: _get_b,
|
||||
set: _set_b
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
get: _get_a,
|
||||
set: _set_a
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _A, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _B, {
|
||||
writable: true,
|
||||
value: 123
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _get_a() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _A);
|
||||
}
|
||||
|
||||
function _set_a(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _A, v);
|
||||
}
|
||||
|
||||
function _get_b() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _B);
|
||||
}
|
||||
|
||||
function _set_b(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _B, v);
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
class Foo {
|
||||
accessor a;
|
||||
|
||||
accessor b = 123;
|
||||
|
||||
accessor ['c'] = 456;
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
expect(foo.a).toBe(undefined);
|
||||
foo.a = 123;
|
||||
expect(foo.a).toBe(123);
|
||||
expect(foo.hasOwnProperty('a')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('a')).toBe(true);
|
||||
|
||||
expect(foo.b).toBe(123);
|
||||
foo.b = 456
|
||||
expect(foo.b).toBe(456);
|
||||
expect(foo.hasOwnProperty('b')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('b')).toBe(true);
|
||||
|
||||
expect(foo.c).toBe(456);
|
||||
foo.c = 789
|
||||
expect(foo.c).toBe(789);
|
||||
expect(foo.hasOwnProperty('c')).toBe(false);
|
||||
expect(Foo.prototype.hasOwnProperty('c')).toBe(true);
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
accessor a;
|
||||
|
||||
accessor b = 123;
|
||||
|
||||
accessor ['c'] = 456;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
var _A = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _B = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _C = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _A, {
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _B, {
|
||||
writable: true,
|
||||
value: 123
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _C, {
|
||||
writable: true,
|
||||
value: 456
|
||||
});
|
||||
}
|
||||
|
||||
get a() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _A);
|
||||
}
|
||||
|
||||
set a(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _A, v);
|
||||
}
|
||||
|
||||
get b() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _B);
|
||||
}
|
||||
|
||||
set b(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _B, v);
|
||||
}
|
||||
|
||||
get 'c'() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _C);
|
||||
}
|
||||
|
||||
set 'c'(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _C, v);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
class Foo {
|
||||
static accessor #a;
|
||||
|
||||
static accessor #b = 123;
|
||||
|
||||
static getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
static setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
|
||||
static getB() {
|
||||
return this.#b;
|
||||
}
|
||||
|
||||
static setB(v) {
|
||||
this.#b = v;
|
||||
}
|
||||
}
|
||||
|
||||
expect(Foo.getA()).toBe(undefined);
|
||||
Foo.setA(123)
|
||||
expect(Foo.getA()).toBe(123);
|
||||
|
||||
expect(Foo.getB()).toBe(123);
|
||||
Foo.setB(456)
|
||||
expect(Foo.getB()).toBe(456);
|
||||
@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
static accessor #a;
|
||||
|
||||
static accessor #b = 123;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
class Foo {}
|
||||
|
||||
function _get_a() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _A);
|
||||
}
|
||||
|
||||
function _set_a(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _A, v);
|
||||
}
|
||||
|
||||
function _get_b() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _B);
|
||||
}
|
||||
|
||||
function _set_b(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _B, v);
|
||||
}
|
||||
|
||||
var _b = {
|
||||
get: _get_b,
|
||||
set: _set_b
|
||||
};
|
||||
var _a = {
|
||||
get: _get_a,
|
||||
set: _set_a
|
||||
};
|
||||
var _A = {
|
||||
writable: true,
|
||||
value: void 0
|
||||
};
|
||||
var _B = {
|
||||
writable: true,
|
||||
value: 123
|
||||
};
|
||||
@ -0,0 +1,22 @@
|
||||
class Foo {
|
||||
static accessor a;
|
||||
|
||||
static accessor b = 123;
|
||||
|
||||
static accessor ['c'] = 456;
|
||||
}
|
||||
|
||||
expect(Foo.a).toBe(undefined);
|
||||
Foo.a = 123;
|
||||
expect(Foo.a).toBe(123);
|
||||
expect(Foo.hasOwnProperty('a')).toBe(true);
|
||||
|
||||
expect(Foo.b).toBe(123);
|
||||
Foo.b = 456
|
||||
expect(Foo.b).toBe(456);
|
||||
expect(Foo.hasOwnProperty('b')).toBe(true);
|
||||
|
||||
expect(Foo.c).toBe(456);
|
||||
Foo.c = 789
|
||||
expect(Foo.c).toBe(789);
|
||||
expect(Foo.hasOwnProperty('c')).toBe(true);
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
static accessor a;
|
||||
|
||||
static accessor b = 123;
|
||||
|
||||
static accessor ['c'] = 456;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
class Foo {
|
||||
static get a() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _A);
|
||||
}
|
||||
|
||||
static set a(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _A, v);
|
||||
}
|
||||
|
||||
static get b() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _B);
|
||||
}
|
||||
|
||||
static set b(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _B, v);
|
||||
}
|
||||
|
||||
static get 'c'() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _C);
|
||||
}
|
||||
|
||||
static set 'c'(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _C, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _A = {
|
||||
writable: true,
|
||||
value: void 0
|
||||
};
|
||||
var _B = {
|
||||
writable: true,
|
||||
value: 123
|
||||
};
|
||||
var _C = {
|
||||
writable: true,
|
||||
value: 456
|
||||
};
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/expressions/input.js
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/expressions/input.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
const A = @dec class A {}
|
||||
const B = @dec class C {}
|
||||
const D = @dec class {}
|
||||
const E = (@dec class {}, 123);
|
||||
const F = [@dec class G {}, @dec class {}];
|
||||
const H = @dec class extends I {};
|
||||
const J = @dec class K extends L {};
|
||||
|
||||
function classFactory() {
|
||||
return @dec class {}
|
||||
}
|
||||
51
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/expressions/output.js
vendored
Normal file
51
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/expressions/output.js
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
var _initClass, _A, _class, _temp, _initClass2, _C, _class2, _temp2, _initClass3, _D, _class3, _temp3, _initClass4, _decorated_class, _class4, _temp4, _initClass5, _G, _class5, _temp5, _initClass6, _decorated_class2, _class6, _temp6, _initClass7, _H, _class7, _temp7, _initClass8, _K, _class8, _temp8;
|
||||
|
||||
const A = ((_temp = _class = class A {}, (() => {
|
||||
[_A, _initClass] = babelHelpers.applyDecs(_class, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass();
|
||||
})(), _temp), _A);
|
||||
const B = ((_temp2 = _class2 = class C {}, (() => {
|
||||
[_C, _initClass2] = babelHelpers.applyDecs(_class2, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass2();
|
||||
})(), _temp2), _C);
|
||||
const D = ((_temp3 = _class3 = class D {}, (() => {
|
||||
[_D, _initClass3] = babelHelpers.applyDecs(_class3, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass3();
|
||||
})(), _temp3), _D);
|
||||
const E = (((_temp4 = _class4 = class {}, (() => {
|
||||
[_decorated_class, _initClass4] = babelHelpers.applyDecs(_class4, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass4();
|
||||
})(), _temp4), _decorated_class), 123);
|
||||
const F = [((_temp5 = _class5 = class G {}, (() => {
|
||||
[_G, _initClass5] = babelHelpers.applyDecs(_class5, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass5();
|
||||
})(), _temp5), _G), ((_temp6 = _class6 = class {}, (() => {
|
||||
[_decorated_class2, _initClass6] = babelHelpers.applyDecs(_class6, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass6();
|
||||
})(), _temp6), _decorated_class2)];
|
||||
const H = ((_temp7 = _class7 = class H extends I {}, (() => {
|
||||
[_H, _initClass7] = babelHelpers.applyDecs(_class7, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass7();
|
||||
})(), _temp7), _H);
|
||||
const J = ((_temp8 = _class8 = class K extends L {}, (() => {
|
||||
[_K, _initClass8] = babelHelpers.applyDecs(_class8, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass8();
|
||||
})(), _temp8), _K);
|
||||
|
||||
function classFactory() {
|
||||
var _initClass9, _decorated_class3, _class9, _temp9;
|
||||
|
||||
return (_temp9 = _class9 = class {}, (() => {
|
||||
[_decorated_class3, _initClass9] = babelHelpers.applyDecs(_class9, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass9();
|
||||
})(), _temp9), _decorated_class3;
|
||||
}
|
||||
18
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/exec.js
vendored
Normal file
18
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/exec.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
let count = 0;
|
||||
|
||||
function dec1(Klass) {
|
||||
expect(++count).toBe(1);
|
||||
expect(Klass.name).toBe('Bar');
|
||||
}
|
||||
|
||||
@dec1
|
||||
class Bar {}
|
||||
|
||||
function dec2(Klass) {
|
||||
expect(++count).toBe(2);
|
||||
expect(Klass.name).toBe('Foo');
|
||||
expect(Object.getPrototypeOf(Klass)).toBe(Bar);
|
||||
}
|
||||
|
||||
@dec2
|
||||
class Foo extends Bar {}
|
||||
5
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/input.js
vendored
Normal file
5
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/input.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
@dec1
|
||||
class Bar {}
|
||||
|
||||
@dec2
|
||||
class Foo extends Bar {}
|
||||
25
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/output.js
vendored
Normal file
25
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/inheritance/output.js
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
var _initClass, _initClass2;
|
||||
|
||||
let _Bar;
|
||||
|
||||
class Bar {}
|
||||
|
||||
(() => {
|
||||
[_Bar, _initClass] = babelHelpers.applyDecs(Bar, [], [dec1]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
_initClass();
|
||||
})();
|
||||
|
||||
let _Foo;
|
||||
|
||||
class Foo extends _Bar {}
|
||||
|
||||
(() => {
|
||||
[_Foo, _initClass2] = babelHelpers.applyDecs(Foo, [], [dec2]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
_initClass2();
|
||||
})();
|
||||
41
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/exec.js
vendored
Normal file
41
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/exec.js
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
function dec1(Foo, { addInitializer }) {
|
||||
expect(Foo.field).toBe(undefined);
|
||||
addInitializer(() => {
|
||||
Foo.initField = 123;
|
||||
});
|
||||
}
|
||||
|
||||
@dec1
|
||||
class Foo {
|
||||
static {
|
||||
expect(this.initField).toBe(undefined);
|
||||
}
|
||||
|
||||
static field = 123;
|
||||
}
|
||||
|
||||
expect(Foo.initField).toBe(123);
|
||||
expect(Foo.field).toBe(123);
|
||||
|
||||
function dec2(Bar, { addInitializer }) {
|
||||
expect(Bar.field).toBe(123);
|
||||
expect(Bar.otherField).toBe(undefined);
|
||||
expect(Bar.initField).toBe(123);
|
||||
addInitializer(() => {
|
||||
Bar.initField = 456;
|
||||
});
|
||||
}
|
||||
|
||||
@dec2
|
||||
class Bar extends Foo {
|
||||
static {
|
||||
expect(this.initField).toBe(123);
|
||||
this.otherField = 456;
|
||||
}
|
||||
|
||||
static field = 456;
|
||||
}
|
||||
|
||||
expect(Bar.initField).toBe(456);
|
||||
expect(Bar.field).toBe(456);
|
||||
expect(Bar.otherField).toBe(456);
|
||||
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/input.js
vendored
Normal file
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/input.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
@dec
|
||||
class Foo {
|
||||
static field = 123;
|
||||
}
|
||||
|
||||
@dec
|
||||
class Bar extends Foo {
|
||||
static {
|
||||
this.otherField = 456;
|
||||
}
|
||||
|
||||
static field = 123;
|
||||
}
|
||||
33
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/output.js
vendored
Normal file
33
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/initializers/output.js
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
var _initClass, _initClass2;
|
||||
|
||||
let _Foo;
|
||||
|
||||
class Foo {}
|
||||
|
||||
(() => {
|
||||
[_Foo, _initClass] = babelHelpers.applyDecs(Foo, [], [dec]);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "field", 123);
|
||||
|
||||
(() => {
|
||||
_initClass();
|
||||
})();
|
||||
|
||||
let _Bar;
|
||||
|
||||
class Bar extends _Foo {}
|
||||
|
||||
(() => {
|
||||
[_Bar, _initClass2] = babelHelpers.applyDecs(Bar, [], [dec]);
|
||||
})();
|
||||
|
||||
(() => {
|
||||
Bar.otherField = 456;
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Bar, "field", 123);
|
||||
|
||||
(() => {
|
||||
_initClass2();
|
||||
})();
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
let replaced;
|
||||
|
||||
function dec(Klass) {
|
||||
replaced = class extends Klass {};
|
||||
|
||||
return replaced;
|
||||
}
|
||||
|
||||
const Foo = @dec class Bar {
|
||||
static bar = new Bar();
|
||||
};
|
||||
|
||||
const foo = new Foo();
|
||||
|
||||
expect(Foo).toBe(replaced);
|
||||
expect(Foo.bar).toBeInstanceOf(replaced);
|
||||
expect(foo).toBeInstanceOf(replaced);
|
||||
@ -0,0 +1,6 @@
|
||||
const Foo = @dec class Bar {
|
||||
bar = new Bar();
|
||||
};
|
||||
|
||||
const foo = new Foo();
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
var _initClass, _Bar, _class, _temp;
|
||||
|
||||
const Foo = ((_temp = _class = class Bar {
|
||||
constructor() {
|
||||
babelHelpers.defineProperty(this, "bar", new _Bar());
|
||||
}
|
||||
|
||||
}, (() => {
|
||||
[_Bar, _initClass] = babelHelpers.applyDecs(_class, [], [dec]);
|
||||
})(), (() => {
|
||||
_initClass();
|
||||
})(), _temp), _Bar);
|
||||
const foo = new Foo();
|
||||
19
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/exec.js
vendored
Normal file
19
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/exec.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
let replaced;
|
||||
|
||||
function dec(Klass) {
|
||||
replaced = class extends Klass {};
|
||||
|
||||
return replaced;
|
||||
}
|
||||
|
||||
@dec
|
||||
class Foo {
|
||||
static foo = new Foo();
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
|
||||
expect(Foo).toBe(replaced);
|
||||
expect(Foo.foo).toBeInstanceOf(replaced);
|
||||
expect(foo).toBeInstanceOf(replaced);
|
||||
6
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/input.js
vendored
Normal file
6
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/input.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
@dec
|
||||
class Foo {
|
||||
static foo = new Foo();
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
17
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/output.js
vendored
Normal file
17
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-classes/replacement/output.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
var _initClass;
|
||||
|
||||
let _Foo;
|
||||
|
||||
class Foo {}
|
||||
|
||||
(() => {
|
||||
[_Foo, _initClass] = babelHelpers.applyDecs(Foo, [], [dec]);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "foo", new _Foo());
|
||||
|
||||
(() => {
|
||||
_initClass();
|
||||
})();
|
||||
|
||||
const foo = new _Foo();
|
||||
@ -0,0 +1,33 @@
|
||||
var i = 0;
|
||||
|
||||
function getKey() {
|
||||
return (i++).toString();
|
||||
}
|
||||
|
||||
let elements = [];
|
||||
|
||||
function dec(fn, context) {
|
||||
elements.push({ fn, context });
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
[getKey()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
[getKey()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
expect(elements).toHaveLength(2);
|
||||
|
||||
expect(elements[0].context.name).toBe("0");
|
||||
expect(elements[0].fn()).toBe(1);
|
||||
|
||||
expect(elements[1].context.name).toBe("1");
|
||||
expect(elements[1].fn()).toBe(2);
|
||||
|
||||
expect(i).toBe(2);
|
||||
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
@dec
|
||||
[getKey()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
[getKey()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
var _computedKey, _computedKey2, _dec, _dec2, _initProto;
|
||||
|
||||
_computedKey = getKey()
|
||||
_dec = dec
|
||||
_computedKey2 = getKey()
|
||||
_dec2 = dec
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
[_computedKey]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[_computedKey2]() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initProto] = babelHelpers.applyDecs(Foo, [[_dec, 2, _computedKey], [_dec2, 2, _computedKey2]], []);
|
||||
})();
|
||||
@ -0,0 +1,29 @@
|
||||
expect(() => {
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
|
||||
function getKeyI() {
|
||||
return (i++).toString();
|
||||
}
|
||||
function getKeyJ() {
|
||||
return (j++).toString();
|
||||
}
|
||||
|
||||
let elements = [];
|
||||
|
||||
function dec(fn, context) {
|
||||
elements.push({ fn, context });
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
[getKeyI()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
[getKeyJ()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}).toThrow("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: 0")
|
||||
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
@dec
|
||||
[getKeyI()]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
[getKeyJ()]() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
var _computedKey, _computedKey2, _dec, _dec2, _initProto;
|
||||
|
||||
_computedKey = getKeyI()
|
||||
_dec = dec
|
||||
_computedKey2 = getKeyJ()
|
||||
_dec2 = dec
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
[_computedKey]() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
[_computedKey2]() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initProto] = babelHelpers.applyDecs(Foo, [[_dec, 2, _computedKey], [_dec2, 2, _computedKey2]], []);
|
||||
})();
|
||||
@ -0,0 +1,23 @@
|
||||
let elements = [];
|
||||
|
||||
function dec(val, context) {
|
||||
elements.push({ val, context });
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
a = 123;
|
||||
|
||||
@dec
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
expect(elements).toHaveLength(2);
|
||||
|
||||
expect(elements[0].context.name).toBe("a");
|
||||
expect(elements[0].val).toBe(undefined);
|
||||
|
||||
expect(elements[1].context.name).toBe("a");
|
||||
expect(elements[1].val()).toBe(1);
|
||||
@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
@dec
|
||||
a = 123;
|
||||
|
||||
@dec
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
var _init_a, _initProto;
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.defineProperty(this, "a", (_initProto(this), _init_a(this, 123)));
|
||||
}
|
||||
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _initProto] = babelHelpers.applyDecs(Foo, [[dec, 0, "a"], [dec, 2, "a"]], []);
|
||||
})();
|
||||
@ -0,0 +1,19 @@
|
||||
expect(() => {
|
||||
let elements = [];
|
||||
|
||||
function dec(val, context) {
|
||||
elements.push({ val, context });
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
a() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}).toThrow("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: a")
|
||||
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
@dec
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@dec
|
||||
a() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
var _initProto;
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
a() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initProto] = babelHelpers.applyDecs(Foo, [[dec, 2, "a"], [dec, 2, "a"]], []);
|
||||
})();
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-duplicated-keys/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-duplicated-keys/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
41
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/exec.js
vendored
Normal file
41
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/exec.js
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
function dec(_v, context) {
|
||||
return function (v) {
|
||||
this[context.name + 'Context'] = context;
|
||||
return (v || 1) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
#a;
|
||||
|
||||
@dec
|
||||
#b = 123;
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['#aContext'];
|
||||
const bContext = foo['#bContext'];
|
||||
|
||||
expect(aContext.access.get.call(foo)).toBe(2);
|
||||
aContext.access.set.call(foo, 123);
|
||||
expect(aContext.access.get.call(foo)).toBe(123);
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('field');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.access.get.call(foo)).toBe(124);
|
||||
bContext.access.set.call(foo, 123);
|
||||
expect(bContext.access.get.call(foo)).toBe(123);
|
||||
expect(bContext.name).toBe('#b');
|
||||
expect(bContext.kind).toBe('field');
|
||||
expect(bContext.isStatic).toBe(false);
|
||||
expect(bContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
7
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/input.js
vendored
Normal file
7
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/input.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
@dec
|
||||
#a;
|
||||
|
||||
@dec
|
||||
#b = 123;
|
||||
}
|
||||
31
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/output.js
vendored
Normal file
31
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/private/output.js
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
var _init_a, _init_b;
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
var _b = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
writable: true,
|
||||
value: _init_a(this)
|
||||
});
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _b, {
|
||||
writable: true,
|
||||
value: _init_b(this, 123)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b] = babelHelpers.applyDecs(Foo, [[dec, 0, "a", function () {
|
||||
return babelHelpers.classPrivateFieldGet(this, _a);
|
||||
}, function (value) {
|
||||
babelHelpers.classPrivateFieldSet(this, _a, value);
|
||||
}], [dec, 0, "b", function () {
|
||||
return babelHelpers.classPrivateFieldGet(this, _b);
|
||||
}, function (value) {
|
||||
babelHelpers.classPrivateFieldSet(this, _b, value);
|
||||
}]], []);
|
||||
})();
|
||||
62
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/exec.js
vendored
Normal file
62
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/exec.js
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
function dec(_v, context) {
|
||||
return function (v) {
|
||||
this[context.name + 'Context'] = context;
|
||||
return (v || 1) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
a;
|
||||
|
||||
@dec
|
||||
b = 123;
|
||||
|
||||
@dec
|
||||
['c'] = 456;
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['aContext'];
|
||||
const bContext = foo['bContext'];
|
||||
const cContext = foo['cContext'];
|
||||
|
||||
expect(foo.a).toBe(2);
|
||||
foo.a = 123;
|
||||
expect(foo.a).toBe(123);
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('field');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('a')).toBe(true);
|
||||
expect(Foo.prototype.hasOwnProperty('a')).toBe(false);
|
||||
|
||||
expect(foo.b).toBe(124);
|
||||
foo.b = 123;
|
||||
expect(foo.b).toBe(123);
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('field');
|
||||
expect(bContext.isStatic).toBe(false);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('undefined');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('b')).toBe(true);
|
||||
expect(Foo.prototype.hasOwnProperty('b')).toBe(false);
|
||||
|
||||
expect(foo.c).toBe(457);
|
||||
foo.c = 456;
|
||||
expect(foo.c).toBe(456);
|
||||
expect(cContext.name).toBe('c');
|
||||
expect(cContext.kind).toBe('field');
|
||||
expect(cContext.isStatic).toBe(false);
|
||||
expect(cContext.isPrivate).toBe(false);
|
||||
expect(typeof cContext.addInitializer).toBe('undefined');
|
||||
expect(typeof cContext.setMetadata).toBe('function');
|
||||
expect(typeof cContext.getMetadata).toBe('function');
|
||||
expect(foo.hasOwnProperty('c')).toBe(true);
|
||||
expect(Foo.prototype.hasOwnProperty('c')).toBe(false);
|
||||
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/input.js
vendored
Normal file
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/input.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
@dec
|
||||
a;
|
||||
|
||||
@dec
|
||||
b = 123;
|
||||
|
||||
@dec
|
||||
['c'] = 456;
|
||||
}
|
||||
19
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/output.js
vendored
Normal file
19
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/public/output.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'c'
|
||||
_dec3 = dec
|
||||
|
||||
class Foo {
|
||||
constructor() {
|
||||
babelHelpers.defineProperty(this, "a", _init_a(this));
|
||||
babelHelpers.defineProperty(this, "b", _init_b(this, 123));
|
||||
babelHelpers.defineProperty(this, _computedKey, _init_computedKey(this, 456));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b, _init_computedKey] = babelHelpers.applyDecs(Foo, [[_dec, 0, "a"], [_dec2, 0, "b"], [_dec3, 0, _computedKey]], []);
|
||||
})();
|
||||
39
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-private/exec.js
vendored
Normal file
39
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-private/exec.js
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
function dec(_v, context) {
|
||||
return function (v) {
|
||||
this[context.name + 'Context'] = context;
|
||||
return (v || 1) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
static #a;
|
||||
|
||||
@dec
|
||||
static #b = 123;
|
||||
}
|
||||
|
||||
const aContext = Foo['#aContext'];
|
||||
const bContext = Foo['#bContext'];
|
||||
|
||||
expect(aContext.access.get.call(Foo)).toBe(2);
|
||||
aContext.access.set.call(Foo, 123);
|
||||
expect(aContext.access.get.call(Foo)).toBe(123);
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('field');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.access.get.call(Foo)).toBe(124);
|
||||
bContext.access.set.call(Foo, 123);
|
||||
expect(bContext.access.get.call(Foo)).toBe(123);
|
||||
expect(bContext.name).toBe('#b');
|
||||
expect(bContext.kind).toBe('field');
|
||||
expect(bContext.isStatic).toBe(true);
|
||||
expect(bContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
@dec
|
||||
static #a;
|
||||
|
||||
@dec
|
||||
static #b = 123;
|
||||
}
|
||||
24
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-private/output.js
vendored
Normal file
24
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-private/output.js
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
var _init_a, _init_b;
|
||||
|
||||
class Foo {}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b] = babelHelpers.applyDecs(Foo, [[dec, 5, "a", function () {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _a);
|
||||
}, function (value) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _a, value);
|
||||
}], [dec, 5, "b", function () {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _b);
|
||||
}, function (value) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _b, value);
|
||||
}]], []);
|
||||
})();
|
||||
|
||||
var _a = {
|
||||
writable: true,
|
||||
value: _init_a(Foo)
|
||||
};
|
||||
var _b = {
|
||||
writable: true,
|
||||
value: _init_b(Foo, 123)
|
||||
};
|
||||
57
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/exec.js
vendored
Normal file
57
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/exec.js
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
function dec(_v, context) {
|
||||
return function (v) {
|
||||
this[context.name + 'Context'] = context;
|
||||
return (v || 1) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
@dec
|
||||
static a;
|
||||
|
||||
@dec
|
||||
static b = 123;
|
||||
|
||||
@dec
|
||||
static ['c'] = 456;
|
||||
}
|
||||
|
||||
const aContext = Foo['aContext'];
|
||||
const bContext = Foo['bContext'];
|
||||
const cContext = Foo['cContext'];
|
||||
|
||||
expect(Foo.a).toBe(2);
|
||||
Foo.a = 123;
|
||||
expect(Foo.a).toBe(123);
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('field');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('undefined');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('a')).toBe(true);
|
||||
|
||||
expect(Foo.b).toBe(124);
|
||||
Foo.b = 123;
|
||||
expect(Foo.b).toBe(123);
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('field');
|
||||
expect(bContext.isStatic).toBe(true);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('undefined');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('b')).toBe(true);
|
||||
|
||||
expect(Foo.c).toBe(457);
|
||||
Foo.c = 456;
|
||||
expect(Foo.c).toBe(456);
|
||||
expect(cContext.name).toBe('c');
|
||||
expect(cContext.kind).toBe('field');
|
||||
expect(cContext.isStatic).toBe(true);
|
||||
expect(cContext.isPrivate).toBe(false);
|
||||
expect(typeof cContext.addInitializer).toBe('undefined');
|
||||
expect(typeof cContext.setMetadata).toBe('function');
|
||||
expect(typeof cContext.getMetadata).toBe('function');
|
||||
expect(Foo.hasOwnProperty('c')).toBe(true);
|
||||
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/input.js
vendored
Normal file
10
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/input.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
class Foo {
|
||||
@dec
|
||||
static a;
|
||||
|
||||
@dec
|
||||
static b = 123;
|
||||
|
||||
@dec
|
||||
static ['c'] = 456;
|
||||
}
|
||||
16
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/output.js
vendored
Normal file
16
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-fields/static-public/output.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
var _init_a, _init_b, _computedKey, _init_computedKey, _dec, _dec2, _dec3;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'c'
|
||||
_dec3 = dec
|
||||
|
||||
class Foo {}
|
||||
|
||||
(() => {
|
||||
[_init_a, _init_b, _init_computedKey] = babelHelpers.applyDecs(Foo, [[_dec, 5, "a"], [_dec2, 5, "b"], [_dec3, 5, _computedKey]], []);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "a", _init_a(Foo));
|
||||
babelHelpers.defineProperty(Foo, "b", _init_b(Foo, 123));
|
||||
babelHelpers.defineProperty(Foo, _computedKey, _init_computedKey(Foo, 456));
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters-and-setters/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters-and-setters/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
function dec(value, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + '_' + context.kind + 'Context'] = context;
|
||||
});
|
||||
|
||||
if (context.kind === 'getter') {
|
||||
return function () {
|
||||
return value.call(this) + 1;
|
||||
}
|
||||
} else {
|
||||
return function (v) {
|
||||
return value.call(this, v + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set #a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const a_getterContext = foo['#a_getterContext'];
|
||||
const a_setterContext = foo['#a_setterContext'];
|
||||
|
||||
expect(a_getterContext.access.get.call(foo)).toBe(2);
|
||||
expect(foo.getA()).toBe(2);
|
||||
a_setterContext.access.set.call(foo, 123);
|
||||
expect(a_getterContext.access.get.call(foo)).toBe(125);
|
||||
expect(foo.getA()).toBe(125);
|
||||
foo.setA(456);
|
||||
expect(a_getterContext.access.get.call(foo)).toBe(458);
|
||||
expect(foo.getA()).toBe(458);
|
||||
|
||||
expect(a_getterContext.name).toBe('#a');
|
||||
expect(a_getterContext.kind).toBe('getter');
|
||||
expect(a_getterContext.isStatic).toBe(false);
|
||||
expect(a_getterContext.isPrivate).toBe(true);
|
||||
expect(typeof a_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(a_setterContext.name).toBe('#a');
|
||||
expect(a_setterContext.kind).toBe('setter');
|
||||
expect(a_setterContext.isStatic).toBe(false);
|
||||
expect(a_setterContext.isPrivate).toBe(true);
|
||||
expect(typeof a_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_setterContext.getMetadata).toBe('function');
|
||||
@ -0,0 +1,21 @@
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set #a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
var _call_a, _call_a2, _initProto;
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
get: _get_a,
|
||||
set: _set_a
|
||||
});
|
||||
babelHelpers.defineProperty(this, "value", 1);
|
||||
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
getA() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _a);
|
||||
}
|
||||
|
||||
setA(v) {
|
||||
babelHelpers.classPrivateFieldSet(this, _a, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _get_a() {
|
||||
return _call_a(this);
|
||||
}
|
||||
|
||||
function _set_a(v) {
|
||||
_call_a2(this, v);
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_call_a, _call_a2, _initProto] = babelHelpers.applyDecs(Foo, [[dec, 3, "a", function () {
|
||||
return this.value;
|
||||
}], [dec, 4, "a", function (v) {
|
||||
this.value = v;
|
||||
}]], []);
|
||||
})();
|
||||
@ -0,0 +1,88 @@
|
||||
function dec(value, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + '_' + context.kind + 'Context'] = context;
|
||||
});
|
||||
|
||||
if (context.kind === 'getter') {
|
||||
return function () {
|
||||
return value.call(this) + 1;
|
||||
}
|
||||
} else {
|
||||
return function (v) {
|
||||
return value.call(this, v + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
@dec
|
||||
get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set ['b'](v) {
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const a_getterContext = foo['a_getterContext'];
|
||||
const a_setterContext = foo['a_setterContext'];
|
||||
|
||||
const b_getterContext = foo['b_getterContext'];
|
||||
const b_setterContext = foo['b_setterContext'];
|
||||
|
||||
expect(foo.a).toBe(2);
|
||||
expect(foo.b).toBe(2);
|
||||
foo.a = 123;
|
||||
expect(foo.a).toBe(125);
|
||||
expect(foo.b).toBe(125);
|
||||
foo.b = 456;
|
||||
expect(foo.a).toBe(458);
|
||||
expect(foo.b).toBe(458);
|
||||
|
||||
expect(a_getterContext.name).toBe('a');
|
||||
expect(a_getterContext.kind).toBe('getter');
|
||||
expect(a_getterContext.isStatic).toBe(false);
|
||||
expect(a_getterContext.isPrivate).toBe(false);
|
||||
expect(typeof a_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(a_setterContext.name).toBe('a');
|
||||
expect(a_setterContext.kind).toBe('setter');
|
||||
expect(a_setterContext.isStatic).toBe(false);
|
||||
expect(a_setterContext.isPrivate).toBe(false);
|
||||
expect(typeof a_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_setterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(b_getterContext.name).toBe('b');
|
||||
expect(b_getterContext.kind).toBe('getter');
|
||||
expect(b_getterContext.isStatic).toBe(false);
|
||||
expect(b_getterContext.isPrivate).toBe(false);
|
||||
expect(typeof b_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof b_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof b_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(b_setterContext.name).toBe('b');
|
||||
expect(b_setterContext.kind).toBe('setter');
|
||||
expect(b_setterContext.isStatic).toBe(false);
|
||||
expect(b_setterContext.isPrivate).toBe(false);
|
||||
expect(typeof b_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof b_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof b_setterContext.getMetadata).toBe('function');
|
||||
@ -0,0 +1,23 @@
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
@dec
|
||||
get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
set ['b'](v) {
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
var _computedKey, _computedKey2, _dec, _dec2, _dec3, _dec4, _initProto;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'b'
|
||||
_dec3 = dec
|
||||
_computedKey2 = 'b'
|
||||
_dec4 = dec
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
babelHelpers.defineProperty(this, "value", 1);
|
||||
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
get [_computedKey]() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
set [_computedKey2](v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initProto] = babelHelpers.applyDecs(Foo, [[_dec, 3, "a"], [_dec2, 4, "a"], [_dec3, 3, _computedKey], [_dec4, 4, _computedKey2]], []);
|
||||
})();
|
||||
@ -0,0 +1,65 @@
|
||||
function dec(value, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + '_' + context.kind + 'Context'] = context;
|
||||
});
|
||||
|
||||
if (context.kind === 'getter') {
|
||||
return function () {
|
||||
return value.call(this) + 1;
|
||||
}
|
||||
} else {
|
||||
return function (v) {
|
||||
return value.call(this, v + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set #a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
static getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
static setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
}
|
||||
|
||||
const a_getterContext = Foo['#a_getterContext'];
|
||||
const a_setterContext = Foo['#a_setterContext'];
|
||||
|
||||
expect(a_getterContext.access.get.call(Foo)).toBe(2);
|
||||
expect(Foo.getA()).toBe(2);
|
||||
a_setterContext.access.set.call(Foo, 123);
|
||||
expect(a_getterContext.access.get.call(Foo)).toBe(125);
|
||||
expect(Foo.getA()).toBe(125);
|
||||
Foo.setA(456);
|
||||
expect(a_getterContext.access.get.call(Foo)).toBe(458);
|
||||
expect(Foo.getA()).toBe(458);
|
||||
|
||||
expect(a_getterContext.name).toBe('#a');
|
||||
expect(a_getterContext.kind).toBe('getter');
|
||||
expect(a_getterContext.isStatic).toBe(true);
|
||||
expect(a_getterContext.isPrivate).toBe(true);
|
||||
expect(typeof a_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(a_setterContext.name).toBe('#a');
|
||||
expect(a_setterContext.kind).toBe('setter');
|
||||
expect(a_setterContext.isStatic).toBe(true);
|
||||
expect(a_setterContext.isPrivate).toBe(true);
|
||||
expect(typeof a_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_setterContext.getMetadata).toBe('function');
|
||||
@ -0,0 +1,21 @@
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set #a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
static getA() {
|
||||
return this.#a;
|
||||
}
|
||||
|
||||
static setA(v) {
|
||||
this.#a = v;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
var _call_a, _call_a2, _initStatic;
|
||||
|
||||
class Foo {
|
||||
static getA() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _a);
|
||||
}
|
||||
|
||||
static setA(v) {
|
||||
babelHelpers.classStaticPrivateFieldSpecSet(this, Foo, _a, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _get_a() {
|
||||
return _call_a(this);
|
||||
}
|
||||
|
||||
function _set_a(v) {
|
||||
_call_a2(this, v);
|
||||
}
|
||||
|
||||
var _a = {
|
||||
get: _get_a,
|
||||
set: _set_a
|
||||
};
|
||||
|
||||
(() => {
|
||||
[_call_a, _call_a2, _initStatic] = babelHelpers.applyDecs(Foo, [[dec, 8, "a", function () {
|
||||
return this.value;
|
||||
}], [dec, 9, "a", function (v) {
|
||||
this.value = v;
|
||||
}]], []);
|
||||
|
||||
_initStatic(Foo);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "value", 1);
|
||||
@ -0,0 +1,87 @@
|
||||
function dec(value, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + '_' + context.kind + 'Context'] = context;
|
||||
});
|
||||
|
||||
if (context.kind === 'getter') {
|
||||
return function () {
|
||||
return value.call(this) + 1;
|
||||
}
|
||||
} else {
|
||||
return function (v) {
|
||||
return value.call(this, v + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
@dec
|
||||
static get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set ['b'](v) {
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
|
||||
const a_getterContext = Foo['a_getterContext'];
|
||||
const a_setterContext = Foo['a_setterContext'];
|
||||
|
||||
const b_getterContext = Foo['b_getterContext'];
|
||||
const b_setterContext = Foo['b_setterContext'];
|
||||
|
||||
expect(Foo.a).toBe(2);
|
||||
expect(Foo.b).toBe(2);
|
||||
Foo.a = 123;
|
||||
expect(Foo.a).toBe(125);
|
||||
expect(Foo.b).toBe(125);
|
||||
Foo.b = 456;
|
||||
expect(Foo.a).toBe(458);
|
||||
expect(Foo.b).toBe(458);
|
||||
|
||||
expect(a_getterContext.name).toBe('a');
|
||||
expect(a_getterContext.kind).toBe('getter');
|
||||
expect(a_getterContext.isStatic).toBe(true);
|
||||
expect(a_getterContext.isPrivate).toBe(false);
|
||||
expect(typeof a_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(a_setterContext.name).toBe('a');
|
||||
expect(a_setterContext.kind).toBe('setter');
|
||||
expect(a_setterContext.isStatic).toBe(true);
|
||||
expect(a_setterContext.isPrivate).toBe(false);
|
||||
expect(typeof a_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof a_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof a_setterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(b_getterContext.name).toBe('b');
|
||||
expect(b_getterContext.kind).toBe('getter');
|
||||
expect(b_getterContext.isStatic).toBe(true);
|
||||
expect(b_getterContext.isPrivate).toBe(false);
|
||||
expect(typeof b_getterContext.addInitializer).toBe('function');
|
||||
expect(typeof b_getterContext.setMetadata).toBe('function');
|
||||
expect(typeof b_getterContext.getMetadata).toBe('function');
|
||||
|
||||
expect(b_setterContext.name).toBe('b');
|
||||
expect(b_setterContext.kind).toBe('setter');
|
||||
expect(b_setterContext.isStatic).toBe(true);
|
||||
expect(b_setterContext.isPrivate).toBe(false);
|
||||
expect(typeof b_setterContext.addInitializer).toBe('function');
|
||||
expect(typeof b_setterContext.setMetadata).toBe('function');
|
||||
expect(typeof b_setterContext.getMetadata).toBe('function');
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
@dec
|
||||
static get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static set ['b'](v) {
|
||||
this.value = v;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
var _computedKey, _computedKey2, _dec, _dec2, _dec3, _dec4, _initStatic;
|
||||
|
||||
_dec = dec
|
||||
_dec2 = dec
|
||||
_computedKey = 'b'
|
||||
_dec3 = dec
|
||||
_computedKey2 = 'b'
|
||||
_dec4 = dec
|
||||
|
||||
class Foo {
|
||||
static get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
static set a(v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
static get [_computedKey]() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
static set [_computedKey2](v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initStatic] = babelHelpers.applyDecs(Foo, [[_dec, 8, "a"], [_dec2, 9, "a"], [_dec3, 8, _computedKey], [_dec4, 9, _computedKey2]], []);
|
||||
|
||||
_initStatic(Foo);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "value", 1);
|
||||
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/options.json
vendored
Normal file
11
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/options.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"proposal-decorators",
|
||||
{ "version": "2021-12", "decoratorsBeforeExport": false }
|
||||
],
|
||||
"proposal-class-properties",
|
||||
"proposal-private-methods",
|
||||
"proposal-class-static-block"
|
||||
]
|
||||
}
|
||||
39
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/exec.js
vendored
Normal file
39
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/exec.js
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
function dec(get, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return function () {
|
||||
return get.call(this) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getA() {
|
||||
return this.#a;
|
||||
}
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['#aContext'];
|
||||
|
||||
expect(aContext.access.get.call(foo)).toBe(2);
|
||||
expect(foo.getA()).toBe(2);
|
||||
foo.value = 123;
|
||||
expect(aContext.access.get.call(foo)).toBe(124);
|
||||
expect(foo.getA()).toBe(124);
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('getter');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
12
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/input.js
vendored
Normal file
12
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/input.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
getA() {
|
||||
return this.#a;
|
||||
}
|
||||
}
|
||||
30
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/output.js
vendored
Normal file
30
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/private/output.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
var _call_a, _initProto;
|
||||
|
||||
var _a = /*#__PURE__*/new WeakMap();
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
babelHelpers.classPrivateFieldInitSpec(this, _a, {
|
||||
get: _get_a,
|
||||
set: void 0
|
||||
});
|
||||
babelHelpers.defineProperty(this, "value", 1);
|
||||
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
getA() {
|
||||
return babelHelpers.classPrivateFieldGet(this, _a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _get_a() {
|
||||
return _call_a(this);
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_call_a, _initProto] = babelHelpers.applyDecs(Foo, [[dec, 3, "a", function () {
|
||||
return this.value;
|
||||
}]], []);
|
||||
})();
|
||||
50
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/exec.js
vendored
Normal file
50
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/exec.js
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
function dec(get, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return function () {
|
||||
return get.call(this) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
let foo = new Foo();
|
||||
|
||||
const aContext = foo['aContext'];
|
||||
const bContext = foo['bContext'];
|
||||
|
||||
expect(foo.a).toBe(2);
|
||||
expect(foo.b).toBe(2);
|
||||
foo.value = 123;
|
||||
expect(foo.a).toBe(124);
|
||||
expect(foo.b).toBe(124);
|
||||
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('getter');
|
||||
expect(aContext.isStatic).toBe(false);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('getter');
|
||||
expect(bContext.isStatic).toBe(false);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/input.js
vendored
Normal file
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/input.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
class Foo {
|
||||
value = 1;
|
||||
|
||||
@dec
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
26
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/output.js
vendored
Normal file
26
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/public/output.js
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
var _computedKey, _dec, _dec2, _initProto;
|
||||
|
||||
_dec = dec
|
||||
_computedKey = 'b'
|
||||
_dec2 = dec
|
||||
|
||||
class Foo {
|
||||
constructor(...args) {
|
||||
babelHelpers.defineProperty(this, "value", 1);
|
||||
|
||||
_initProto(this);
|
||||
}
|
||||
|
||||
get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
get [_computedKey]() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(() => {
|
||||
[_initProto] = babelHelpers.applyDecs(Foo, [[_dec, 3, "a"], [_dec2, 3, _computedKey]], []);
|
||||
})();
|
||||
38
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/exec.js
vendored
Normal file
38
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/exec.js
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
function dec(get, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return function () {
|
||||
return get.call(this) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
static getA() {
|
||||
return this.#a;
|
||||
}
|
||||
}
|
||||
|
||||
const aContext = Foo['#aContext'];
|
||||
|
||||
expect(aContext.access.get.call(Foo)).toBe(2);
|
||||
expect(Foo.getA()).toBe(2);
|
||||
Foo.value = 123;
|
||||
expect(aContext.access.get.call(Foo)).toBe(124);
|
||||
expect(Foo.getA()).toBe(124);
|
||||
|
||||
expect(aContext.name).toBe('#a');
|
||||
expect(aContext.kind).toBe('getter');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(true);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
12
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/input.js
vendored
Normal file
12
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/input.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get #a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
static getA() {
|
||||
return this.#a;
|
||||
}
|
||||
}
|
||||
27
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/output.js
vendored
Normal file
27
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-private/output.js
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
var _call_a, _initStatic;
|
||||
|
||||
class Foo {
|
||||
static getA() {
|
||||
return babelHelpers.classStaticPrivateFieldSpecGet(this, Foo, _a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function _get_a() {
|
||||
return _call_a(this);
|
||||
}
|
||||
|
||||
var _a = {
|
||||
get: _get_a,
|
||||
set: void 0
|
||||
};
|
||||
|
||||
(() => {
|
||||
[_call_a, _initStatic] = babelHelpers.applyDecs(Foo, [[dec, 8, "a", function () {
|
||||
return this.value;
|
||||
}]], []);
|
||||
|
||||
_initStatic(Foo);
|
||||
})();
|
||||
|
||||
babelHelpers.defineProperty(Foo, "value", 1);
|
||||
48
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-public/exec.js
vendored
Normal file
48
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-public/exec.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
function dec(get, context) {
|
||||
context.addInitializer((instance) => {
|
||||
instance[context.name + 'Context'] = context;
|
||||
});
|
||||
|
||||
return function () {
|
||||
return get.call(this) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
const aContext = Foo['aContext'];
|
||||
const bContext = Foo['bContext'];
|
||||
|
||||
expect(Foo.a).toBe(2);
|
||||
expect(Foo.b).toBe(2);
|
||||
Foo.value = 123;
|
||||
expect(Foo.a).toBe(124);
|
||||
expect(Foo.b).toBe(124);
|
||||
|
||||
expect(aContext.name).toBe('a');
|
||||
expect(aContext.kind).toBe('getter');
|
||||
expect(aContext.isStatic).toBe(true);
|
||||
expect(aContext.isPrivate).toBe(false);
|
||||
expect(typeof aContext.addInitializer).toBe('function');
|
||||
expect(typeof aContext.setMetadata).toBe('function');
|
||||
expect(typeof aContext.getMetadata).toBe('function');
|
||||
|
||||
expect(bContext.name).toBe('b');
|
||||
expect(bContext.kind).toBe('getter');
|
||||
expect(bContext.isStatic).toBe(true);
|
||||
expect(bContext.isPrivate).toBe(false);
|
||||
expect(typeof bContext.addInitializer).toBe('function');
|
||||
expect(typeof bContext.setMetadata).toBe('function');
|
||||
expect(typeof bContext.getMetadata).toBe('function');
|
||||
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-public/input.js
vendored
Normal file
13
packages/babel-plugin-proposal-decorators/test/fixtures/2021-12-getters/static-public/input.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
class Foo {
|
||||
static value = 1;
|
||||
|
||||
@dec
|
||||
static get a() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@dec
|
||||
static get ['b']() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user