UNPKG

eslint-plugin-lit

Version:
131 lines (130 loc) 4.23 kB
/** * @fileoverview Disallows property changes in the `update` lifecycle method * @author James Garbutt <https://github.com/43081j> */ import { getPropertyMap, isLitClass } from '../util.js'; const superUpdateQuery = 'CallExpression' + '[callee.object.type = "Super"]' + '[callee.property.name = "update"]'; //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ export const rule = { meta: { docs: { description: 'Disallows property changes in the `update` lifecycle method', recommended: false, url: 'https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-property-change-update.md' }, schema: [], messages: { propertyChange: 'Properties should not be changed in the update lifecycle method as' + ' they will not trigger re-renders' } }, create(context) { // variables should be defined here let propertyMap = null; let inUpdate = false; let superSeen = false; //---------------------------------------------------------------------- // Helpers //---------------------------------------------------------------------- /** * Class entered * * @param {ESTree.Class} node Node entered * @return {void} */ function classEnter(node) { if (!isLitClass(node)) { return; } const props = getPropertyMap(node); if (props) { propertyMap = props; } } /** * Class exited * * @return {void} */ function classExit() { propertyMap = null; } /** * Method entered * * @param {ESTree.MethodDefinition} node Node entered * @return {void} */ function methodEnter(node) { if (!propertyMap || node.static === true || node.kind !== 'method' || node.key.type !== 'Identifier' || node.key.name !== 'update') { return; } inUpdate = true; } /** * Method exited * * @return {void} */ function methodExit() { inUpdate = false; superSeen = false; } /** * Assignment expression entered * * @param {ESTree.AssignmentExpression} node Node entered * @return {void} */ function assignmentFound(node) { if (!superSeen || !propertyMap || !inUpdate || node.left.type !== 'MemberExpression' || node.left.object.type !== 'ThisExpression' || node.left.property.type !== 'Identifier') { return; } const hasProp = propertyMap.has(node.left.property.name); if (!hasProp) { return; } context.report({ node: node, messageId: 'propertyChange' }); } /** * `super.update()` call found * * @return {void} */ function superUpdateFound() { if (!inUpdate) { return; } superSeen = true; } //---------------------------------------------------------------------- // Public //---------------------------------------------------------------------- return { ClassExpression: (node) => classEnter(node), ClassDeclaration: (node) => classEnter(node), 'ClassExpression:exit': classExit, 'ClassDeclaration:exit': classExit, MethodDefinition: (node) => methodEnter(node), 'MethodDefinition:exit': methodExit, AssignmentExpression: (node) => assignmentFound(node), [superUpdateQuery]: () => superUpdateFound() }; } };