UNPKG

eslint-plugin-meteor

Version:
135 lines (121 loc) 4.2 kB
/** * @fileoverview Enforce check on all arguments passed to methods and publish functions * @author Dominik Ferber */ const { isMeteorCall, isFunction } = require('../util/ast'); // ----------------------------------------------------------------------------- // Rule Definition // ----------------------------------------------------------------------------- module.exports = { meta: { schema: [ { type: 'object', properties: { checkEquivalents: { type: 'array', items: { type: 'string', minLength: 1, }, }, }, additionalProperties: false, }, ], }, create: (context) => { const options = context.options[0]; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function isCheck(expression) { if (expression.callee.name === 'check') { // Require a second argument for literal check() return expression.arguments.length > 1; } else if (options && Array.isArray(options.checkEquivalents)) { // Allow any number of arguments for checkEquivalents return options.checkEquivalents.includes(expression.callee.name); } else { return false; } } function auditArgumentChecks(node) { if (!isFunction(node.type)) { return; } const checkedParams = []; function processCheckArgs(args) { if (args.length > 0 && args[0].type === 'Identifier') { checkedParams.push(args[0].name); } if (args.length > 0 && args[0].type === 'ArrayExpression') { args[0].elements.forEach((element) => { if (element.type === 'Identifier') checkedParams.push(element.name); }); } } // short-circuit if (node.params.length === 0) { return; } if (node.body.type === 'BlockStatement') { node.body.body.forEach((expression) => { if ( expression.type === 'ExpressionStatement' && expression.expression.type === 'CallExpression' && expression.expression.callee.type === 'Identifier' && isCheck(expression.expression) ) { processCheckArgs(expression.expression.arguments); } else if ( expression.type === 'ExpressionStatement' && expression.expression.type === 'AssignmentExpression' && expression.expression.right.type === 'CallExpression' && expression.expression.right.callee.type === 'Identifier' && isCheck(expression.expression.right) ) { processCheckArgs(expression.expression.right.arguments); } }); } node.params.forEach((param) => { if (param.type === 'Identifier') { if (checkedParams.indexOf(param.name) === -1) { context.report(param, `"${param.name}" is not checked`); } } else if ( // check params with default assignments param.type === 'AssignmentPattern' && param.left.type === 'Identifier' ) { if (checkedParams.indexOf(param.left.name) === -1) { context.report(param.left, `"${param.left.name}" is not checked`); } } }); } // --------------------------------------------------------------------------- // Public // --------------------------------------------------------------------------- return { CallExpression: (node) => { // publications if (isMeteorCall(node, 'publish') && node.arguments.length >= 2) { auditArgumentChecks(node.arguments[1]); return; } // method if ( isMeteorCall(node, 'methods') && node.arguments.length > 0 && node.arguments[0].type === 'ObjectExpression' ) { node.arguments[0].properties.forEach((property) => { auditArgumentChecks(property.value); }); } }, }; }, };