/** * @fileoverview A rule to control the style of variable initializations. * @author Colin Ihrig * @copyright 2015 Colin Ihrig. All rights reserved. */ "use strict"; //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ /** * Checks whether or not a given node is a for loop. * @param {ASTNode} block - A node to check. * @returns {boolean} `true` when the node is a for loop. */ function isForLoop(block) { return block.type === "ForInStatement" || block.type === "ForOfStatement" || block.type === "ForStatement"; } /** * Checks whether or not a given declarator node has its initializer. * @param {ASTNode} node - A declarator node to check. * @returns {boolean} `true` when the node has its initializer. */ function isInitialized(node) { var declaration = node.parent; var block = declaration.parent; if (isForLoop(block)) { if (block.type === "ForStatement") { return block.init === declaration; } return block.left === declaration; } return Boolean(node.init); } //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = function(context) { var MODE_ALWAYS = "always", MODE_NEVER = "never"; var mode = context.options[0] || MODE_ALWAYS; var params = context.options[1] || {}; //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- return { "VariableDeclaration:exit": function(node) { var kind = node.kind, declarations = node.declarations; for (var i = 0; i < declarations.length; ++i) { var declaration = declarations[i], id = declaration.id, initialized = isInitialized(declaration), isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); if (id.type !== "Identifier") { continue; } if (mode === MODE_ALWAYS && !initialized) { context.report(declaration, "Variable '" + id.name + "' should be initialized on declaration."); } else if (mode === MODE_NEVER && kind !== "const" && initialized && !isIgnoredForLoop) { context.report(declaration, "Variable '" + id.name + "' should not be initialized on declaration."); } } } }; }; module.exports.schema = { "anyOf": [ { "type": "array", "items": [ { "enum": ["always"] } ], "minItems": 0, "maxItems": 1 }, { "type": "array", "items": [ { "enum": ["never"] }, { "type": "object", "properties": { "ignoreForLoopInit": { "type": "boolean" } }, "additionalProperties": false } ], "minItems": 0, "maxItems": 2 } ] };