babel-plugin-class-properties-default-value
Version:
The plugin for transform properties of class **which has parent class**.
145 lines (127 loc) • 4.19 kB
JavaScript
;
/**
* @file: index
* @author: Cuttle Cong
* @date: 2017/11/29
* @description:
*/
var t = require('babel-core').types;
function isConstType(type) {
switch (type) {
// X
case 'Identifier':
case 'StringLiteral':
case 'NumericLiteral':
// function () {}
case 'FunctionExpression':
case 'ArrowFunctionExpression':
// <A/>
case 'JSXElement':
return true;
}
return false;
}
var findThisExpressionObject = {
'FunctionExpression|ArrowFunctionExpression': function FunctionExpressionArrowFunctionExpression(path) {
path.skip();
},
ThisExpression: function ThisExpression(path, opt) {
opt.result = path;
path.stop();
}
};
function getCondPath() {
var condType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'in';
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var refNode = t.memberExpression(t.thisExpression(), t.identifier(data.name), data.computed);
switch (condType) {
// typeof this.a !== 'undefined' ? this.a : 2;
case 'typeofUndefined':
var typeOfThisVal = t.unaryExpression('typeof', refNode, true);
return t.conditionalExpression(t.binaryExpression('!==', typeOfThisVal, t.stringLiteral('undefined')), refNode, data.valueNode);
// this.hasOwnProperty('a') ? this.a : 2;
case 'hasOwnProperty':
var hasOwnPropertyExpr = t.unaryExpression('typeof', refNode, true);
return t.conditionalExpression(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('hasOwnProperty'), false), [data.computed ? t.identifier(data.name) : t.stringLiteral(data.name)]), refNode, data.valueNode);
// 'a' in this ? this.a : 2;
case 'in':
return t.conditionalExpression(t.binaryExpression('in', data.computed ? t.identifier(data.name) : t.stringLiteral(data.name), t.thisExpression()), refNode, data.valueNode);
default:
throw new Error('[ERROR]: not include condType in (in/typeofUndefined/hasOwnProperty): ' + condType);
}
}
var classMethodTraverseObject = {
ClassProperty: function ClassProperty(path, opt) {
opt = Object.assign({
effectDecorator: false,
effectThisExpr: false,
onlyEffectConst: false,
// ignorePrivate: false,
condType: 'typeofUndefined'
}, opt);
path.skip();
if (path.node.static) {
return;
}
if (
// effectDecorator
!opt.effectDecorator && path.node.decorators && !!path.node.decorators.length) {
return;
}
var keyName = path.node.key.name;
var valuePath = path.get('value');
if (isConstType(valuePath.type)) {
valuePath.replaceWith(getCondPath(opt.condType, {
computed: path.node.computed,
valueNode: valuePath.node,
name: keyName
}));
} else {
var resultObj = { result: null };
var hasThisExpression = void 0;
if (opt.onlyEffectConst) {
return;
}
// effectThisExpr
if (opt.effectThisExpr) {
hasThisExpression = false;
} else {
if (valuePath.type === 'ThisExpression') {
hasThisExpression = true;
} else {
valuePath.traverse(findThisExpressionObject, resultObj);
hasThisExpression = !!resultObj.result;
}
}
// we think you want to regard it as an constant
// when without ThisExpr
if (!hasThisExpression) {
valuePath.replaceWith(getCondPath(opt.condType, {
computed: path.node.computed,
valueNode: valuePath.node,
name: keyName
}));
}
// console.error(keyName, hasThisExpression, valuePath.type)
}
}
};
module.exports = function (babel) {
return {
inherits: require('babel-plugin-syntax-class-properties'),
visitor: {
/*ClassDeclaration*/
Class: function Class(path, data) {
// class Son { ... }
// can't skip transform class properties
// path.skip()
if (!path.node.superClass) {
return;
}
// Son extends Parent
// ClassBody
path.get('body').traverse(classMethodTraverseObject, data.opts);
}
}
};
};