extjs-replace-callparent
Version:
Replace Ext JS `callParent` calls with direct method calls on parent class
167 lines (132 loc) • 7.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.default = initDefinitionFactory;
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Definition Module
*
* This file contains the code for finding the parent `Ext.define` or `Ext.override` definition for a `callParent` call.
*/
function initDefinitionFactory(t) {
function isCalleeExtDefine(callee) {
return t.isIdentifier(callee.property, { name: 'define' });
}
function isCalleeExtOverride(callee) {
return t.isIdentifier(callee.property, { name: 'override' });
}
function isDefinition(extNames) {
extNames = extNames || ['Ext'];
return function isDefinition(path) {
if (!path.isCallExpression()) {
return false;
}
var callee = path.node.callee;
return t.isMemberExpression(callee) && t.isIdentifier(callee.object) && extNames.includes(callee.object.name) && (isCalleeExtDefine(callee) || isCalleeExtOverride(callee));
};
}
function getProtoPropFromObjectExpression(objectExpression) {
return objectExpression.properties.find(function (prop) {
return t.isIdentifier(prop.key) && (prop.key.name === 'extend' || prop.key.name === 'override');
});
}
var returnStatementVisitor = {
ReturnStatement: function ReturnStatement(path, state) {
if (!path.findParent(function (p) {
return p.isFunctionExpression();
}) === state.functionExpression) {
return;
}
path.stop(); // we've found the return statement, stop traversal
var returnArg = path.get('argument');
if (!returnArg.isObjectExpression()) {
return;
}
state.returnArg = returnArg.node;
}
};
function getFunctionDefineReturnObjectExpression(functionExpression) {
var nestedVisitorState = { functionExpression: functionExpression, returnArg: null };
functionExpression.traverse(returnStatementVisitor, nestedVisitorState);
return nestedVisitorState.returnArg;
}
function getDefineProtoProp(bodyArg) {
if (bodyArg.isObjectExpression()) {
return getProtoPropFromObjectExpression(bodyArg.node);
} else if (bodyArg.isFunctionExpression()) {
var objectExpression = getFunctionDefineReturnObjectExpression(bodyArg);
if (!objectExpression) {
return;
}
return getProtoPropFromObjectExpression(objectExpression);
}
}
function buildMemberExpression(stringRef) {
return stringRef.split('.').reduce(function (last, next) {
return last ? t.memberExpression(last, t.identifier(next)) : t.identifier(next);
}, null);
}
function getPrototypeRef(prototypeValue) {
return t.isStringLiteral(prototypeValue) ? buildMemberExpression(prototypeValue.value) : prototypeValue;
}
var AbstractDefinition = function () {
function AbstractDefinition(path) {
_classCallCheck(this, AbstractDefinition);
this.path = path;
}
_createClass(AbstractDefinition, [{
key: 'prependVariableRef',
value: function prependVariableRef(value) {
var refVar = this.path.scope.generateUidIdentifier('o');
this.path.insertBefore(t.variableDeclaration('var', [t.variableDeclarator(refVar, value)]));
return refVar;
}
}]);
return AbstractDefinition;
}();
var DefineDefinition = function (_AbstractDefinition) {
_inherits(DefineDefinition, _AbstractDefinition);
function DefineDefinition(path) {
_classCallCheck(this, DefineDefinition);
var _this = _possibleConstructorReturn(this, (DefineDefinition.__proto__ || Object.getPrototypeOf(DefineDefinition)).call(this, path));
var bodyArg = path.get('arguments.1');
var protoProp = getDefineProtoProp(bodyArg);
_this.protoRef = protoProp ? getPrototypeRef(protoProp.value) : buildMemberExpression('Ext.Base');
_this.isOverride = protoProp && protoProp.key.name === 'override';
return _this;
}
return DefineDefinition;
}(AbstractDefinition);
var OverrideDefinition = function (_AbstractDefinition2) {
_inherits(OverrideDefinition, _AbstractDefinition2);
function OverrideDefinition(path) {
_classCallCheck(this, OverrideDefinition);
var _this2 = _possibleConstructorReturn(this, (OverrideDefinition.__proto__ || Object.getPrototypeOf(OverrideDefinition)).call(this, path));
var prototypeValue = path.get('arguments.0').node;
_this2.protoRef = getPrototypeRef(prototypeValue);
_this2.isOverride = true;
return _this2;
}
return OverrideDefinition;
}(AbstractDefinition);
/**
* Find the `Ext.define` or `Ext.override` definition
*
* If the `callParent` call is within an `Ext.define`, then a `DefineDefinition` is returned
* If the `callParent` call is within an `Ext.override`, then a `OverrideDefinition` is returned
*
* In either case, they expose `protoRef`, `isOverride` properties, and a `createPrependedVariableRef` method which
* is used for prepending the reference to the overriden method when the definition is overriding a class.
*/
return function findParentDefinition(childPath, extNames) {
var path = childPath.findParent(isDefinition(extNames));
if (!path) {
throw childPath.buildCodeFrameError("Unable to find 'Ext.define' or 'Ext.override' for this 'callParent'");
}
return isCalleeExtOverride(path.node.callee) ? new OverrideDefinition(path) : new DefineDefinition(path);
};
}