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