Blame view
node_modules/eslint/lib/rules/no-this-before-super.js
4.62 KB
c39994410
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
/** * @fileoverview A rule to disallow using `this`/`super` before `super()`. * @author Toru Nagashima * @copyright 2015 Toru Nagashima. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { /** * Searches a class node that a node is belonging to. * @param {Node} node - A node to start searching. * @returns {ClassDeclaration|ClassExpression|null} the found class node, or `null`. */ function getClassInAncestor(node) { while (node) { if (node.type === "ClassDeclaration" || node.type === "ClassExpression") { return node; } node = node.parent; } /* istanbul ignore next */ return null; } /** * Checks whether or not a node is the null literal. * @param {Node} node - A node to check. * @returns {boolean} whether or not a node is the null literal. */ function isNullLiteral(node) { return node && node.type === "Literal" && node.value === null; } /** * Checks whether or not a node is the callee of a call expression. * @param {Node} node - A node to check. * @returns {boolean} whether or not a node is the callee of a call expression. */ function isCallee(node) { return node && node.parent.type === "CallExpression" && node.parent.callee === node; } /** * Checks whether or not the current traversal context is before `super()`. * @param {object} item - A checking context. * @returns {boolean} whether or not the current traversal context is before `super()`. */ function isBeforeSuperCalling(item) { return ( item && item.scope === context.getScope().variableScope.upper.variableScope && item.superCalled === false ); } var stack = []; return { /** * Start checking. * @param {MethodDefinition} node - A target node. * @returns {void} */ "MethodDefinition": function(node) { if (node.kind !== "constructor") { return; } stack.push({ thisOrSuperBeforeSuperCalled: [], superCalled: false, scope: context.getScope().variableScope }); }, /** * Treats the result of checking and reports invalid `this`/`super`. * @param {MethodDefinition} node - A target node. * @returns {void} */ "MethodDefinition:exit": function(node) { if (node.kind !== "constructor") { return; } var result = stack.pop(); // Skip if it has no extends or `extends null`. var classNode = getClassInAncestor(node); if (!classNode || !classNode.superClass || isNullLiteral(classNode.superClass)) { return; } // Reports. result.thisOrSuperBeforeSuperCalled.forEach(function(thisOrSuper) { var type = (thisOrSuper.type === "Super" ? "super" : "this"); context.report(thisOrSuper, "\"{{type}}\" is not allowed before super()", {type: type}); }); }, /** * Marks the node if is before `super()`. * @param {ThisExpression} node - A target node. * @returns {void} */ "ThisExpression": function(node) { var item = stack[stack.length - 1]; if (isBeforeSuperCalling(item)) { item.thisOrSuperBeforeSuperCalled.push(node); } }, /** * Marks the node if is before `super()`. (exclude `super()` itself) * @param {Super} node - A target node. * @returns {void} */ "Super": function(node) { var item = stack[stack.length - 1]; if (isBeforeSuperCalling(item) && isCallee(node) === false) { item.thisOrSuperBeforeSuperCalled.push(node); } }, /** * Marks `super()` called. * To catch `super(this.a);`, marks on `CallExpression:exit`. * @param {CallExpression} node - A target node. * @returns {void} */ "CallExpression:exit": function(node) { var item = stack[stack.length - 1]; if (isBeforeSuperCalling(item) && node.callee.type === "Super") { item.superCalled = true; } } }; }; module.exports.schema = []; |