Move helpers from 'babel-plugin-proposal-decorators' to 'babel-helpers' (#7017)

This commit is contained in:
Peri Nikhil
2017-12-13 20:38:19 +05:30
committed by Nicolò Ribaudo
parent f5ef928586
commit 9cc0a26694
2 changed files with 86 additions and 139 deletions

View File

@@ -700,3 +700,70 @@ helpers.toPropertyKey = defineHelper(`
}
}
`);
/**
* Add a helper that will throw a useful error if the transform fails to detect the class
* property assignment, so users know something failed.
*/
helpers.initializerWarningHelper = defineHelper(`
export default function _initializerWarningHelper(descriptor, context){
throw new Error(
'Decorating class property failed. Please ensure that ' +
'proposal-class-properties is enabled and set to use loose mode. ' +
'To use proposal-class-properties in spec mode with decorators, wait for ' +
'the next major version of decorators in stage 2.'
);
}
`);
/**
* Add a helper to call as a replacement for class property definition.
*/
helpers.initializerDefineProperty = defineHelper(`
export default function _initializerDefineProperty(target, property, descriptor, context){
if (!descriptor) return;
Object.defineProperty(target, property, {
enumerable: descriptor.enumerable,
configurable: descriptor.configurable,
writable: descriptor.writable,
value: descriptor.initializer ? descriptor.initializer.call(context) : void 0,
});
}
`);
/**
* Add a helper to take an initial descriptor, apply some decorators to it, and optionally
* define the property.
*/
helpers.applyDecoratedDescriptor = defineHelper(`
export default function _applyDecoratedDescriptor(target, property, decorators, descriptor, context){
var desc = {};
Object['ke' + 'ys'](descriptor).forEach(function(key){
desc[key] = descriptor[key];
});
desc.enumerable = !!desc.enumerable;
desc.configurable = !!desc.configurable;
if ('value' in desc || desc.initializer){
desc.writable = true;
}
desc = decorators.slice().reverse().reduce(function(desc, decorator){
return decorator(target, property, desc) || desc;
}, desc);
if (context && desc.initializer !== void 0){
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
desc.initializer = undefined;
}
if (desc.initializer === void 0){
// This is a hack to avoid this being processed by 'transform-runtime'.
// See issue #9.
Object['define' + 'Property'](target, property, desc);
desc = null;
}
return desc;
}
`);

View File

@@ -26,116 +26,7 @@ const buildGetObjectInitializer = template(`
})
`);
const buildInitializerWarningHelper = template(`
function NAME(descriptor, context){
throw new Error(
'Decorating class property failed. Please ensure that ' +
'proposal-class-properties is enabled and set to use loose mode. ' +
'To use proposal-class-properties in spec mode with decorators, wait for ' +
'the next major version of decorators in stage 2.'
);
}
`);
const buildInitializerDefineProperty = template(`
function NAME(target, property, descriptor, context){
if (!descriptor) return;
Object.defineProperty(target, property, {
enumerable: descriptor.enumerable,
configurable: descriptor.configurable,
writable: descriptor.writable,
value: descriptor.initializer ? descriptor.initializer.call(context) : void 0,
});
}
`);
const buildApplyDecoratedDescriptor = template(`
function NAME(target, property, decorators, descriptor, context){
var desc = {};
Object['ke' + 'ys'](descriptor).forEach(function(key){
desc[key] = descriptor[key];
});
desc.enumerable = !!desc.enumerable;
desc.configurable = !!desc.configurable;
if ('value' in desc || desc.initializer){
desc.writable = true;
}
desc = decorators.slice().reverse().reduce(function(desc, decorator){
return decorator(target, property, desc) || desc;
}, desc);
if (context && desc.initializer !== void 0){
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
desc.initializer = undefined;
}
if (desc.initializer === void 0){
// This is a hack to avoid this being processed by 'transform-runtime'.
// See issue #9.
Object['define' + 'Property'](target, property, desc);
desc = null;
}
return desc;
}
`);
export default function() {
/**
* Add a helper to take an initial descriptor, apply some decorators to it, and optionally
* define the property.
*/
function ensureApplyDecoratedDescriptorHelper(path, state) {
if (!state.applyDecoratedDescriptor) {
state.applyDecoratedDescriptor = path.scope.generateUidIdentifier(
"applyDecoratedDescriptor",
);
const helper = buildApplyDecoratedDescriptor({
NAME: state.applyDecoratedDescriptor,
});
path.scope.getProgramParent().path.unshiftContainer("body", helper);
}
return state.applyDecoratedDescriptor;
}
/**
* Add a helper to call as a replacement for class property definition.
*/
function ensureInitializerDefineProp(path, state) {
if (!state.initializerDefineProp) {
state.initializerDefineProp = path.scope.generateUidIdentifier(
"initDefineProp",
);
const helper = buildInitializerDefineProperty({
NAME: state.initializerDefineProp,
});
path.scope.getProgramParent().path.unshiftContainer("body", helper);
}
return state.initializerDefineProp;
}
/**
* Add a helper that will throw a useful error if the transform fails to detect the class
* property assignment, so users know something failed.
*/
function ensureInitializerWarning(path, state) {
if (!state.initializerWarningHelper) {
state.initializerWarningHelper = path.scope.generateUidIdentifier(
"initializerWarningHelper",
);
const helper = buildInitializerWarningHelper({
NAME: state.initializerWarningHelper,
});
path.scope.getProgramParent().path.unshiftContainer("body", helper);
}
return state.initializerWarningHelper;
}
/**
* If the decorator expressions are non-identifiers, hoist them to before the class so we can be sure
* that they are evaluated in order.
@@ -260,35 +151,32 @@ export default function() {
t.blockStatement([t.returnStatement(node.value)]),
)
: t.nullLiteral();
node.value = t.callExpression(ensureInitializerWarning(path, state), [
descriptor,
t.thisExpression(),
]);
node.value = t.callExpression(
state.addHelper("initializerWarningHelper"),
[descriptor, t.thisExpression()],
);
acc = acc.concat([
t.assignmentExpression(
"=",
descriptor,
t.callExpression(
ensureApplyDecoratedDescriptorHelper(path, state),
[
target,
property,
t.arrayExpression(decorators.map(dec => dec.expression)),
t.objectExpression([
t.objectProperty(
t.identifier("enumerable"),
t.booleanLiteral(true),
),
t.objectProperty(t.identifier("initializer"), initializer),
]),
],
),
t.callExpression(state.addHelper("applyDecoratedDescriptor"), [
target,
property,
t.arrayExpression(decorators.map(dec => dec.expression)),
t.objectExpression([
t.objectProperty(
t.identifier("enumerable"),
t.booleanLiteral(true),
),
t.objectProperty(t.identifier("initializer"), initializer),
]),
]),
),
]);
} else {
acc = acc.concat(
t.callExpression(ensureApplyDecoratedDescriptorHelper(path, state), [
t.callExpression(state.addHelper("applyDecoratedDescriptor"), [
target,
property,
t.arrayExpression(decorators.map(dec => dec.expression)),
@@ -367,21 +255,13 @@ export default function() {
},
AssignmentExpression(path, state) {
if (!state.initializerWarningHelper) return;
if (!path.get("left").isMemberExpression()) return;
if (!path.get("left.property").isIdentifier()) return;
if (!path.get("right").isCallExpression()) return;
if (
!path
.get("right.callee")
.isIdentifier({ name: state.initializerWarningHelper.name })
) {
return;
}
if (!path.get("right.callee").isIdentifier()) return;
path.replaceWith(
t.callExpression(ensureInitializerDefineProp(path, state), [
t.callExpression(state.addHelper("initializerDefineProperty"), [
path.get("left.object").node,
t.stringLiteral(path.get("left.property").node.name),
path.get("right.arguments")[0].node,