UNPKG

babel-plugin-class-properties-default-value

Version:
145 lines (127 loc) 4.19 kB
'use strict'; /** * @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); } } }; };