Skip to content

Commit

Permalink
Add .has method to context.access
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Feb 3, 2023
1 parent 3cf9ebd commit 8b7fd2b
Show file tree
Hide file tree
Showing 56 changed files with 258 additions and 97 deletions.
2 changes: 1 addition & 1 deletion packages/babel-helpers/src/helpers-generated.ts
Expand Up @@ -35,7 +35,7 @@ export default Object.freeze({
),
applyDecs2301: helper(
"7.20.0",
'function createAddInitializerMethod(initializers,decoratorFinishedRef){return function(initializer){assertNotFinished(decoratorFinishedRef,"addInitializer"),assertCallable(initializer,"An initializer"),initializers.push(initializer)}}function memberDec(dec,name,desc,initializers,kind,isStatic,isPrivate,value){var kindStr;switch(kind){case 1:kindStr="accessor";break;case 2:kindStr="method";break;case 3:kindStr="getter";break;case 4:kindStr="setter";break;default:kindStr="field"}var get,set,ctx={kind:kindStr,name:isPrivate?"#"+name:name,static:isStatic,private:isPrivate},decoratorFinishedRef={v:!1};if(0!==kind&&(ctx.addInitializer=createAddInitializerMethod(initializers,decoratorFinishedRef)),isPrivate||0!==kind&&2!==kind)if(2===kind)get=function(){return desc.value};else{var t=0===kind||1===kind;(t||3===kind)&&(get=function(target){return desc.get.call(target)}),(t||4===kind)&&(set=function(target,value){desc.set.call(target,value)})}else get=function(receiver){return receiver[name]},0===kind&&(set=function(receiver,v){receiver[name]=v});ctx.access=get&&set?{get:get,set:set}:get?{get:get}:{set:set};try{return dec(value,ctx)}finally{decoratorFinishedRef.v=!0}}function assertNotFinished(decoratorFinishedRef,fnName){if(decoratorFinishedRef.v)throw new Error("attempted to call "+fnName+" after decoration was finished")}function assertCallable(fn,hint){if("function"!=typeof fn)throw new TypeError(hint+" must be a function")}function assertValidReturnValue(kind,value){var type=typeof value;if(1===kind){if("object"!==type||null===value)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==value.get&&assertCallable(value.get,"accessor.get"),void 0!==value.set&&assertCallable(value.set,"accessor.set"),void 0!==value.init&&assertCallable(value.init,"accessor.init")}else if("function"!==type){var hint;throw hint=0===kind?"field":10===kind?"class":"method",new TypeError(hint+" decorators must return a function or void 0")}}function applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers){var desc,init,value,newValue,get,set,decs=decInfo[0];if(isPrivate?desc=0===kind||1===kind?{get:decInfo[3],set:decInfo[4]}:3===kind?{get:decInfo[3]}:4===kind?{set:decInfo[3]}:{value:decInfo[3]}:0!==kind&&(desc=Object.getOwnPropertyDescriptor(base,name)),1===kind?value={get:desc.get,set:desc.set}:2===kind?value=desc.value:3===kind?value=desc.get:4===kind&&(value=desc.set),"function"==typeof decs)void 0!==(newValue=memberDec(decs,name,desc,initializers,kind,isStatic,isPrivate,value))&&(assertValidReturnValue(kind,newValue),0===kind?init=newValue:1===kind?(init=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue);else for(var i=decs.length-1;i>=0;i--){var newInit;if(void 0!==(newValue=memberDec(decs[i],name,desc,initializers,kind,isStatic,isPrivate,value)))assertValidReturnValue(kind,newValue),0===kind?newInit=newValue:1===kind?(newInit=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue,void 0!==newInit&&(void 0===init?init=newInit:"function"==typeof init?init=[init,newInit]:init.push(newInit))}if(0===kind||1===kind){if(void 0===init)init=function(instance,init){return init};else if("function"!=typeof init){var ownInitializers=init;init=function(instance,init){for(var value=init,i=0;i<ownInitializers.length;i++)value=ownInitializers[i].call(instance,value);return value}}else{var originalInitializer=init;init=function(instance,init){return originalInitializer.call(instance,init)}}ret.push(init)}0!==kind&&(1===kind?(desc.get=value.get,desc.set=value.set):2===kind?desc.value=value:3===kind?desc.get=value:4===kind&&(desc.set=value),isPrivate?1===kind?(ret.push((function(instance,args){return value.get.call(instance,args)})),ret.push((function(instance,args){return value.set.call(instance,args)}))):2===kind?ret.push(value):ret.push((function(instance,args){return value.call(instance,args)})):Object.defineProperty(base,name,desc))}function applyMemberDecs(Class,decInfos){for(var protoInitializers,staticInitializers,ret=[],existingProtoNonFields=new Map,existingStaticNonFields=new Map,i=0;i<decInfos.length;i++){var decInfo=decInfos[i];if(Array.isArray(decInfo)){var base,initializers,kind=decInfo[1],name=decInfo[2],isPrivate=decInfo.length>3,isStatic=kind>=5;if(isStatic?(base=Class,0!==(kind-=5)&&(initializers=staticInitializers=staticInitializers||[])):(base=Class.prototype,0!==kind&&(initializers=protoInitializers=protoInitializers||[])),0!==kind&&!isPrivate){var existingNonFields=isStatic?existingStaticNonFields:existingProtoNonFields,existingKind=existingNonFields.get(name)||0;if(!0===existingKind||3===existingKind&&4!==kind||4===existingKind&&3!==kind)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);!existingKind&&kind>2?existingNonFields.set(name,kind):existingNonFields.set(name,!0)}applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers)}}return pushInitializers(ret,protoInitializers),pushInitializers(ret,staticInitializers),ret}function pushInitializers(ret,initializers){initializers&&ret.push((function(instance){for(var i=0;i<initializers.length;i++)initializers[i].call(instance);return instance}))}function applyClassDecs(targetClass,classDecs){if(classDecs.length>0){for(var initializers=[],newClass=targetClass,name=targetClass.name,i=classDecs.length-1;i>=0;i--){var decoratorFinishedRef={v:!1};try{var nextNewClass=classDecs[i](newClass,{kind:"class",name:name,addInitializer:createAddInitializerMethod(initializers,decoratorFinishedRef)})}finally{decoratorFinishedRef.v=!0}void 0!==nextNewClass&&(assertValidReturnValue(10,nextNewClass),newClass=nextNewClass)}return[newClass,function(){for(var i=0;i<initializers.length;i++)initializers[i].call(newClass)}]}}export default function applyDecs2301(targetClass,memberDecs,classDecs){return{e:applyMemberDecs(targetClass,memberDecs),get c(){return applyClassDecs(targetClass,classDecs)}}}',
'function createAddInitializerMethod(initializers,decoratorFinishedRef){return function(initializer){assertNotFinished(decoratorFinishedRef,"addInitializer"),assertCallable(initializer,"An initializer"),initializers.push(initializer)}}function memberDec(dec,name,desc,initializers,kind,isStatic,isPrivate,value,privateHas){var kindStr;switch(kind){case 1:kindStr="accessor";break;case 2:kindStr="method";break;case 3:kindStr="getter";break;case 4:kindStr="setter";break;default:kindStr="field"}var get,set,has,ctx={kind:kindStr,name:isPrivate?"#"+name:name,static:isStatic,private:isPrivate},decoratorFinishedRef={v:!1};if(0!==kind&&(ctx.addInitializer=createAddInitializerMethod(initializers,decoratorFinishedRef)),has=isPrivate?privateHas:function(receiver){return name in receiver},isPrivate||0!==kind&&2!==kind)if(2===kind)get=function(){return desc.value};else{var t=0===kind||1===kind;(t||3===kind)&&(get=function(target){return desc.get.call(target)}),(t||4===kind)&&(set=function(target,value){desc.set.call(target,value)})}else get=function(receiver){return receiver[name]},0===kind&&(set=function(receiver,v){receiver[name]=v});ctx.access=get&&set?{get:get,set:set,has:has}:get?{get:get,has:has}:{set:set,has:has};try{return dec(value,ctx)}finally{decoratorFinishedRef.v=!0}}function assertNotFinished(decoratorFinishedRef,fnName){if(decoratorFinishedRef.v)throw new Error("attempted to call "+fnName+" after decoration was finished")}function assertCallable(fn,hint){if("function"!=typeof fn)throw new TypeError(hint+" must be a function")}function assertValidReturnValue(kind,value){var type=typeof value;if(1===kind){if("object"!==type||null===value)throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");void 0!==value.get&&assertCallable(value.get,"accessor.get"),void 0!==value.set&&assertCallable(value.set,"accessor.set"),void 0!==value.init&&assertCallable(value.init,"accessor.init")}else if("function"!==type){var hint;throw hint=0===kind?"field":10===kind?"class":"method",new TypeError(hint+" decorators must return a function or void 0")}}function applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers){var desc,init,value,has,newValue,get,set,decs=decInfo[0];if(isPrivate?0===kind||1===kind?(desc={get:decInfo[3],set:decInfo[4]},has=decInfo[5]):(desc=3===kind?{get:decInfo[3]}:4===kind?{set:decInfo[3]}:{value:decInfo[3]},has=decInfo[4]):0!==kind&&(desc=Object.getOwnPropertyDescriptor(base,name)),1===kind?value={get:desc.get,set:desc.set}:2===kind?value=desc.value:3===kind?value=desc.get:4===kind&&(value=desc.set),"function"==typeof decs)void 0!==(newValue=memberDec(decs,name,desc,initializers,kind,isStatic,isPrivate,value,has))&&(assertValidReturnValue(kind,newValue),0===kind?init=newValue:1===kind?(init=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue);else for(var i=decs.length-1;i>=0;i--){var newInit;if(void 0!==(newValue=memberDec(decs[i],name,desc,initializers,kind,isStatic,isPrivate,value,has)))assertValidReturnValue(kind,newValue),0===kind?newInit=newValue:1===kind?(newInit=newValue.init,get=newValue.get||value.get,set=newValue.set||value.set,value={get:get,set:set}):value=newValue,void 0!==newInit&&(void 0===init?init=newInit:"function"==typeof init?init=[init,newInit]:init.push(newInit))}if(0===kind||1===kind){if(void 0===init)init=function(instance,init){return init};else if("function"!=typeof init){var ownInitializers=init;init=function(instance,init){for(var value=init,i=0;i<ownInitializers.length;i++)value=ownInitializers[i].call(instance,value);return value}}else{var originalInitializer=init;init=function(instance,init){return originalInitializer.call(instance,init)}}ret.push(init)}0!==kind&&(1===kind?(desc.get=value.get,desc.set=value.set):2===kind?desc.value=value:3===kind?desc.get=value:4===kind&&(desc.set=value),isPrivate?1===kind?(ret.push((function(instance,args){return value.get.call(instance,args)})),ret.push((function(instance,args){return value.set.call(instance,args)}))):2===kind?ret.push(value):ret.push((function(instance,args){return value.call(instance,args)})):Object.defineProperty(base,name,desc))}function applyMemberDecs(Class,decInfos){for(var protoInitializers,staticInitializers,ret=[],existingProtoNonFields=new Map,existingStaticNonFields=new Map,i=0;i<decInfos.length;i++){var decInfo=decInfos[i];if(Array.isArray(decInfo)){var base,initializers,kind=decInfo[1],name=decInfo[2],isPrivate=decInfo.length>3,isStatic=kind>=5;if(isStatic?(base=Class,0!==(kind-=5)&&(initializers=staticInitializers=staticInitializers||[])):(base=Class.prototype,0!==kind&&(initializers=protoInitializers=protoInitializers||[])),0!==kind&&!isPrivate){var existingNonFields=isStatic?existingStaticNonFields:existingProtoNonFields,existingKind=existingNonFields.get(name)||0;if(!0===existingKind||3===existingKind&&4!==kind||4===existingKind&&3!==kind)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);!existingKind&&kind>2?existingNonFields.set(name,kind):existingNonFields.set(name,!0)}applyMemberDec(ret,base,decInfo,name,kind,isStatic,isPrivate,initializers)}}return pushInitializers(ret,protoInitializers),pushInitializers(ret,staticInitializers),ret}function pushInitializers(ret,initializers){initializers&&ret.push((function(instance){for(var i=0;i<initializers.length;i++)initializers[i].call(instance);return instance}))}function applyClassDecs(targetClass,classDecs){if(classDecs.length>0){for(var initializers=[],newClass=targetClass,name=targetClass.name,i=classDecs.length-1;i>=0;i--){var decoratorFinishedRef={v:!1};try{var nextNewClass=classDecs[i](newClass,{kind:"class",name:name,addInitializer:createAddInitializerMethod(initializers,decoratorFinishedRef)})}finally{decoratorFinishedRef.v=!0}void 0!==nextNewClass&&(assertValidReturnValue(10,nextNewClass),newClass=nextNewClass)}return[newClass,function(){for(var i=0;i<initializers.length;i++)initializers[i].call(newClass)}]}}export default function applyDecs2301(targetClass,memberDecs,classDecs){return{e:applyMemberDecs(targetClass,memberDecs),get c(){return applyClassDecs(targetClass,classDecs)}}}',
),
asyncGeneratorDelegate: helper(
"7.0.0-beta.0",
Expand Down
51 changes: 34 additions & 17 deletions packages/babel-helpers/src/helpers/applyDecs2301.js
Expand Up @@ -34,7 +34,8 @@ function memberDec(
kind,
isStatic,
isPrivate,
value
value,
privateHas
) {
var kindStr;

Expand Down Expand Up @@ -71,7 +72,13 @@ function memberDec(
);
}

var get, set;
var get, set, has;
if (isPrivate) has = privateHas;
else {
has = function (receiver) {
return name in receiver;
};
}
if (!isPrivate && (kind === 0 /* FIELD */ || kind === 2) /* METHOD */) {
get = function (receiver) {
return receiver[name];
Expand Down Expand Up @@ -102,7 +109,11 @@ function memberDec(
}
}
ctx.access =
get && set ? { get: get, set: set } : get ? { get: get } : { set: set };
get && set
? { get: get, set: set, has: has }
: get
? { get: get, has: has }
: { set: set, has: has };

try {
return dec(value, ctx);
Expand Down Expand Up @@ -168,26 +179,30 @@ function applyMemberDec(
) {
var decs = decInfo[0];

var desc, init, value;
var desc, init, value, has;

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],
};
has = decInfo[5];
} else {
desc = {
value: decInfo[3],
};
if (kind === 3 /* GETTER */) {
desc = {
get: decInfo[3],
};
} else if (kind === 4 /* SETTER */) {
desc = {
set: decInfo[3],
};
} else {
desc = {
value: decInfo[3],
};
}
has = decInfo[4];
}
} else if (kind !== 0 /* FIELD */) {
desc = Object.getOwnPropertyDescriptor(base, name);
Expand Down Expand Up @@ -217,7 +232,8 @@ function applyMemberDec(
kind,
isStatic,
isPrivate,
value
value,
has
);

if (newValue !== void 0) {
Expand Down Expand Up @@ -247,7 +263,8 @@ function applyMemberDec(
kind,
isStatic,
isPrivate,
value
value,
has
);

if (newValue !== void 0) {
Expand Down
Expand Up @@ -231,31 +231,24 @@ function addProxyAccessorsFor(

function extractProxyAccessorsFor(
targetKey: t.PrivateName,
): t.FunctionExpression[] {
injectHas: boolean,
): (t.FunctionExpression | t.ArrowFunctionExpression)[] {
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"),
),
),
]),
),
];
template.expression.ast`
function () {
return this.${t.cloneNode(targetKey)};
}
` as t.FunctionExpression,
template.expression.ast`
function (value) {
this.${t.cloneNode(targetKey)} = value;
}
` as t.FunctionExpression,
injectHas &&
(template.expression.ast`
_ => ${t.cloneNode(targetKey)} in _
` as t.ArrowFunctionExpression),
].filter(Boolean);
}

const FIELD = 0;
Expand Down Expand Up @@ -299,7 +292,9 @@ interface DecoratorInfo {
// The name of the decorator
name: t.StringLiteral | t.Expression;

privateMethods: t.FunctionExpression | t.FunctionExpression[] | undefined;
privateMethods:
| (t.FunctionExpression | t.ArrowFunctionExpression)[]
| undefined;

// The names of local variables that will be used/returned from the decoration
locals: t.Identifier | t.Identifier[] | undefined;
Expand Down Expand Up @@ -496,6 +491,8 @@ function transformClass(
const classDecorators = path.node.decorators;
let hasElementDecorators = false;

const injectHasChecks = version === "2023-01";

const generateClassPrivateUid = createLazyPrivateUidGeneratorForClass(path);

// Iterate over the class to see if we need to decorate it, and also to
Expand Down Expand Up @@ -623,7 +620,9 @@ function transformClass(

if (hasDecorators) {
let locals: t.Identifier | t.Identifier[];
let privateMethods: t.FunctionExpression | t.FunctionExpression[];
let privateMethods: Array<
t.FunctionExpression | t.ArrowFunctionExpression
>;

if (kind === ACCESSOR) {
const { value } = element.node as t.ClassAccessorProperty;
Expand All @@ -646,7 +645,7 @@ function transformClass(
const [newPath] = element.replaceWith(newField);

if (isPrivate) {
privateMethods = extractProxyAccessorsFor(newId);
privateMethods = extractProxyAccessorsFor(newId, injectHasChecks);

const getId = newPath.scope.parent.generateDeclaredUidIdentifier(
`get_${name}`,
Expand Down Expand Up @@ -680,7 +679,7 @@ function transformClass(
locals = initId;

if (isPrivate) {
privateMethods = extractProxyAccessorsFor(key);
privateMethods = extractProxyAccessorsFor(key, injectHasChecks);
}
} else if (isPrivate) {
locals = element.scope.parent.generateDeclaredUidIdentifier(
Expand All @@ -704,12 +703,18 @@ function transformClass(
async: isAsync,
} = element.node as t.ClassPrivateMethod;

privateMethods = t.functionExpression(
undefined,
params.filter(isNotTsParameter),
body,
isAsync,
);
privateMethods = [
t.functionExpression(
undefined,
params.filter(isNotTsParameter),
body,
isAsync,
),
injectHasChecks &&
(template.expression.ast`
_ => ${t.cloneNode(key)} in _
` as t.ArrowFunctionExpression),
].filter(Boolean);

if (kind === GETTER || kind === SETTER) {
movePrivateAccessor(
Expand Down
Expand Up @@ -31,6 +31,10 @@ let foo = new Foo();
const aContext = foo['#aContext'];
const bContext = foo['#bContext'];

expect(aContext.access.has(foo)).toBe(true);
expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(foo))).toBe(false);

expect(aContext.access.get(foo)).toBe(2);
aContext.access.set(foo, 123);
expect(aContext.access.get(foo)).toBe(125);
Expand Down
Expand Up @@ -40,8 +40,8 @@ function _get_b2() {
return babelHelpers.classPrivateFieldGet(this, _A);
}, function (value) {
babelHelpers.classPrivateFieldSet(this, _A, value);
}], [dec, 1, "b", function () {
}, _ => _A.has(babelHelpers.checkInRHS(_))], [dec, 1, "b", function () {
return babelHelpers.classPrivateFieldGet(this, _B);
}, function (value) {
babelHelpers.classPrivateFieldSet(this, _B, value);
}]], []).e;
}, _ => _B.has(babelHelpers.checkInRHS(_))]], []).e;
Expand Up @@ -35,6 +35,12 @@ const aContext = foo['aContext'];
const bContext = foo['bContext'];
const cContext = foo['cContext'];

expect(aContext.access.has(foo)).toBe(true);
expect(aContext.access.has({})).toBe(false);
expect(aContext.access.has(Object.create(foo))).toBe(true);
expect(aContext.access.has({ a: 1 })).toBe(true);
expect(aContext.access.has(Object.create({ a: 1 }))).toBe(true);

expect(foo.a).toBe(2);
expect(aContext.access.get(foo)).toBe(2);
foo.a = 123;
Expand Down

0 comments on commit 8b7fd2b

Please sign in to comment.