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"] = [
|
const properties: t.ObjectExpression["properties"] = [
|
||||||
prop("kind", t.stringLiteral(t.isClassMethod(node) ? node.kind : "field")),
|
prop("kind", t.stringLiteral(t.isClassMethod(node) ? node.kind : "field")),
|
||||||
prop("decorators", takeDecorators(node as Decorable)),
|
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)),
|
prop("key", getKey(node)),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
|
|||||||
@ -911,7 +911,7 @@ function replaceThisContext(
|
|||||||
getSuperRef,
|
getSuperRef,
|
||||||
getObjectRef() {
|
getObjectRef() {
|
||||||
state.needsClassRef = true;
|
state.needsClassRef = true;
|
||||||
return isStaticBlock || path.node.static
|
return t.isStaticBlock(path.node) || path.node.static
|
||||||
? ref
|
? ref
|
||||||
: t.memberExpression(ref, t.identifier("prototype"));
|
: t.memberExpression(ref, t.identifier("prototype"));
|
||||||
},
|
},
|
||||||
@ -931,7 +931,8 @@ function replaceThisContext(
|
|||||||
export type PropNode =
|
export type PropNode =
|
||||||
| t.ClassProperty
|
| t.ClassProperty
|
||||||
| t.ClassPrivateMethod
|
| t.ClassPrivateMethod
|
||||||
| t.ClassPrivateProperty;
|
| t.ClassPrivateProperty
|
||||||
|
| t.StaticBlock;
|
||||||
export type PropPath = NodePath<PropNode>;
|
export type PropPath = NodePath<PropNode>;
|
||||||
|
|
||||||
export function buildFieldsInitNodes(
|
export function buildFieldsInitNodes(
|
||||||
@ -963,7 +964,7 @@ export function buildFieldsInitNodes(
|
|||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
prop.isClassProperty() && ts.assertFieldTransformed(prop);
|
prop.isClassProperty() && ts.assertFieldTransformed(prop);
|
||||||
|
|
||||||
const isStatic = prop.node.static;
|
const isStatic = !t.isStaticBlock(prop.node) && prop.node.static;
|
||||||
const isInstance = !isStatic;
|
const isInstance = !isStatic;
|
||||||
const isPrivate = prop.isPrivate();
|
const isPrivate = prop.isPrivate();
|
||||||
const isPublic = !isPrivate;
|
const isPublic = !isPrivate;
|
||||||
|
|||||||
@ -170,7 +170,7 @@ export function createClassFeaturePlugin({
|
|||||||
path.isPrivate() ||
|
path.isPrivate() ||
|
||||||
path.isStaticBlock?.()
|
path.isStaticBlock?.()
|
||||||
) {
|
) {
|
||||||
props.push(path);
|
props.push(path as PropPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ export function createClassFeaturePlugin({
|
|||||||
(referenceVisitor, state) => {
|
(referenceVisitor, state) => {
|
||||||
if (isDecorated) return;
|
if (isDecorated) return;
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
if (prop.node.static) continue;
|
if (t.isStaticBlock(prop.node) || prop.node.static) continue;
|
||||||
prop.traverse(referenceVisitor, state);
|
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": {
|
"dependencies": {
|
||||||
"@babel/helper-create-class-features-plugin": "workspace:^",
|
"@babel/helper-create-class-features-plugin": "workspace:^",
|
||||||
"@babel/helper-plugin-utils": "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": {
|
"peerDependencies": {
|
||||||
"@babel/core": "^7.0.0-0"
|
"@babel/core": "^7.0.0-0"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
FEATURES,
|
FEATURES,
|
||||||
} from "@babel/helper-create-class-features-plugin";
|
} from "@babel/helper-create-class-features-plugin";
|
||||||
import legacyVisitor from "./transformer-legacy";
|
import legacyVisitor from "./transformer-legacy";
|
||||||
|
import transformer2021_12 from "./transformer-2021-12";
|
||||||
|
|
||||||
export default declare((api, options) => {
|
export default declare((api, options) => {
|
||||||
api.assertVersion(7);
|
api.assertVersion(7);
|
||||||
@ -16,7 +17,7 @@ export default declare((api, options) => {
|
|||||||
throw new Error("'legacy' must be a boolean.");
|
throw new Error("'legacy' must be a boolean.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { decoratorsBeforeExport } = options;
|
const { decoratorsBeforeExport, version } = options;
|
||||||
if (decoratorsBeforeExport === undefined) {
|
if (decoratorsBeforeExport === undefined) {
|
||||||
if (!legacy) {
|
if (!legacy) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -37,6 +38,10 @@ export default declare((api, options) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (legacy) {
|
if (legacy) {
|
||||||
|
if (version !== undefined) {
|
||||||
|
throw new Error("'version' can't be used with legacy decorators");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "proposal-decorators",
|
name: "proposal-decorators",
|
||||||
inherits: syntaxDecorators,
|
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({
|
return createClassFeaturePlugin({
|
||||||
name: "proposal-decorators",
|
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