UNPKG

4.43 kBJavaScriptView Raw
1/**
2 * @fileoverview A rule to control the style of variable initializations.
3 * @author Colin Ihrig
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Helpers
10//------------------------------------------------------------------------------
11
12/**
13 * Checks whether or not a given node is a for loop.
14 * @param {ASTNode} block - A node to check.
15 * @returns {boolean} `true` when the node is a for loop.
16 */
17function isForLoop(block) {
18 return block.type === "ForInStatement" ||
19 block.type === "ForOfStatement" ||
20 block.type === "ForStatement";
21}
22
23/**
24 * Checks whether or not a given declarator node has its initializer.
25 * @param {ASTNode} node - A declarator node to check.
26 * @returns {boolean} `true` when the node has its initializer.
27 */
28function isInitialized(node) {
29 const declaration = node.parent;
30 const block = declaration.parent;
31
32 if (isForLoop(block)) {
33 if (block.type === "ForStatement") {
34 return block.init === declaration;
35 }
36 return block.left === declaration;
37 }
38 return Boolean(node.init);
39}
40
41//------------------------------------------------------------------------------
42// Rule Definition
43//------------------------------------------------------------------------------
44
45module.exports = {
46 meta: {
47 docs: {
48 description: "require or disallow initialization in variable declarations",
49 category: "Variables",
50 recommended: false
51 },
52
53 schema: {
54 anyOf: [
55 {
56 type: "array",
57 items: [
58 {
59 enum: ["always"]
60 }
61 ],
62 minItems: 0,
63 maxItems: 1
64 },
65 {
66 type: "array",
67 items: [
68 {
69 enum: ["never"]
70 },
71 {
72 type: "object",
73 properties: {
74 ignoreForLoopInit: {
75 type: "boolean"
76 }
77 },
78 additionalProperties: false
79 }
80 ],
81 minItems: 0,
82 maxItems: 2
83 }
84 ]
85 }
86 },
87
88 create(context) {
89
90 const MODE_ALWAYS = "always",
91 MODE_NEVER = "never";
92
93 const mode = context.options[0] || MODE_ALWAYS;
94 const params = context.options[1] || {};
95
96 //--------------------------------------------------------------------------
97 // Public API
98 //--------------------------------------------------------------------------
99
100 return {
101 "VariableDeclaration:exit"(node) {
102
103 const kind = node.kind,
104 declarations = node.declarations;
105
106 for (let i = 0; i < declarations.length; ++i) {
107 const declaration = declarations[i],
108 id = declaration.id,
109 initialized = isInitialized(declaration),
110 isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent);
111
112 if (id.type !== "Identifier") {
113 continue;
114 }
115
116 if (mode === MODE_ALWAYS && !initialized) {
117 context.report({
118 node: declaration,
119 message: "Variable '{{idName}}' should be initialized on declaration.",
120 data: {
121 idName: id.name
122 }
123 });
124 } else if (mode === MODE_NEVER && kind !== "const" && initialized && !isIgnoredForLoop) {
125 context.report({
126 node: declaration,
127 message: "Variable '{{idName}}' should not be initialized on declaration.",
128 data: {
129 idName: id.name
130 }
131 });
132 }
133 }
134 }
135 };
136 }
137};