]>
Commit | Line | Data |
---|---|---|
eb39fafa DC |
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 | */ | |
17 | function 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 | */ | |
28 | function 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 | ||
34eeec05 | 45 | /** @type {import('../shared/types').Rule} */ |
eb39fafa DC |
46 | module.exports = { |
47 | meta: { | |
48 | type: "suggestion", | |
49 | ||
50 | docs: { | |
8f9d1d4d | 51 | description: "Require or disallow initialization in variable declarations", |
eb39fafa | 52 | recommended: false, |
f2a92ac6 | 53 | url: "https://eslint.org/docs/latest/rules/init-declarations" |
eb39fafa DC |
54 | }, |
55 | ||
56 | schema: { | |
57 | anyOf: [ | |
58 | { | |
59 | type: "array", | |
60 | items: [ | |
61 | { | |
62 | enum: ["always"] | |
63 | } | |
64 | ], | |
65 | minItems: 0, | |
66 | maxItems: 1 | |
67 | }, | |
68 | { | |
69 | type: "array", | |
70 | items: [ | |
71 | { | |
72 | enum: ["never"] | |
73 | }, | |
74 | { | |
75 | type: "object", | |
76 | properties: { | |
77 | ignoreForLoopInit: { | |
78 | type: "boolean" | |
79 | } | |
80 | }, | |
81 | additionalProperties: false | |
82 | } | |
83 | ], | |
84 | minItems: 0, | |
85 | maxItems: 2 | |
86 | } | |
87 | ] | |
88 | }, | |
89 | messages: { | |
90 | initialized: "Variable '{{idName}}' should be initialized on declaration.", | |
91 | notInitialized: "Variable '{{idName}}' should not be initialized on declaration." | |
92 | } | |
93 | }, | |
94 | ||
95 | create(context) { | |
96 | ||
97 | const MODE_ALWAYS = "always", | |
98 | MODE_NEVER = "never"; | |
99 | ||
100 | const mode = context.options[0] || MODE_ALWAYS; | |
101 | const params = context.options[1] || {}; | |
102 | ||
103 | //-------------------------------------------------------------------------- | |
104 | // Public API | |
105 | //-------------------------------------------------------------------------- | |
106 | ||
107 | return { | |
108 | "VariableDeclaration:exit"(node) { | |
109 | ||
110 | const kind = node.kind, | |
111 | declarations = node.declarations; | |
112 | ||
113 | for (let i = 0; i < declarations.length; ++i) { | |
114 | const declaration = declarations[i], | |
115 | id = declaration.id, | |
116 | initialized = isInitialized(declaration), | |
117 | isIgnoredForLoop = params.ignoreForLoopInit && isForLoop(node.parent); | |
118 | let messageId = ""; | |
119 | ||
120 | if (mode === MODE_ALWAYS && !initialized) { | |
121 | messageId = "initialized"; | |
122 | } else if (mode === MODE_NEVER && kind !== "const" && initialized && !isIgnoredForLoop) { | |
123 | messageId = "notInitialized"; | |
124 | } | |
125 | ||
126 | if (id.type === "Identifier" && messageId) { | |
127 | context.report({ | |
128 | node: declaration, | |
129 | messageId, | |
130 | data: { | |
131 | idName: id.name | |
132 | } | |
133 | }); | |
134 | } | |
135 | } | |
136 | } | |
137 | }; | |
138 | } | |
139 | }; |