Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / prefer-destructuring.js
1 /**
2  * @fileoverview Prefer destructuring from arrays and objects
3  * @author Alex LaFroscia
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Rule Definition
9 //------------------------------------------------------------------------------
10
11 module.exports = {
12     meta: {
13         type: "suggestion",
14
15         docs: {
16             description: "require destructuring from arrays and/or objects",
17             category: "ECMAScript 6",
18             recommended: false,
19             url: "https://eslint.org/docs/rules/prefer-destructuring"
20         },
21
22         fixable: "code",
23
24         schema: [
25             {
26
27                 /*
28                  * old support {array: Boolean, object: Boolean}
29                  * new support {VariableDeclarator: {}, AssignmentExpression: {}}
30                  */
31                 oneOf: [
32                     {
33                         type: "object",
34                         properties: {
35                             VariableDeclarator: {
36                                 type: "object",
37                                 properties: {
38                                     array: {
39                                         type: "boolean"
40                                     },
41                                     object: {
42                                         type: "boolean"
43                                     }
44                                 },
45                                 additionalProperties: false
46                             },
47                             AssignmentExpression: {
48                                 type: "object",
49                                 properties: {
50                                     array: {
51                                         type: "boolean"
52                                     },
53                                     object: {
54                                         type: "boolean"
55                                     }
56                                 },
57                                 additionalProperties: false
58                             }
59                         },
60                         additionalProperties: false
61                     },
62                     {
63                         type: "object",
64                         properties: {
65                             array: {
66                                 type: "boolean"
67                             },
68                             object: {
69                                 type: "boolean"
70                             }
71                         },
72                         additionalProperties: false
73                     }
74                 ]
75             },
76             {
77                 type: "object",
78                 properties: {
79                     enforceForRenamedProperties: {
80                         type: "boolean"
81                     }
82                 },
83                 additionalProperties: false
84             }
85         ]
86     },
87     create(context) {
88
89         const enabledTypes = context.options[0];
90         const enforceForRenamedProperties = context.options[1] && context.options[1].enforceForRenamedProperties;
91         let normalizedOptions = {
92             VariableDeclarator: { array: true, object: true },
93             AssignmentExpression: { array: true, object: true }
94         };
95
96         if (enabledTypes) {
97             normalizedOptions = typeof enabledTypes.array !== "undefined" || typeof enabledTypes.object !== "undefined"
98                 ? { VariableDeclarator: enabledTypes, AssignmentExpression: enabledTypes }
99                 : enabledTypes;
100         }
101
102         //--------------------------------------------------------------------------
103         // Helpers
104         //--------------------------------------------------------------------------
105
106         // eslint-disable-next-line jsdoc/require-description
107         /**
108          * @param {string} nodeType "AssignmentExpression" or "VariableDeclarator"
109          * @param {string} destructuringType "array" or "object"
110          * @returns {boolean} `true` if the destructuring type should be checked for the given node
111          */
112         function shouldCheck(nodeType, destructuringType) {
113             return normalizedOptions &&
114                 normalizedOptions[nodeType] &&
115                 normalizedOptions[nodeType][destructuringType];
116         }
117
118         /**
119          * Determines if the given node is accessing an array index
120          *
121          * This is used to differentiate array index access from object property
122          * access.
123          * @param {ASTNode} node the node to evaluate
124          * @returns {boolean} whether or not the node is an integer
125          */
126         function isArrayIndexAccess(node) {
127             return Number.isInteger(node.property.value);
128         }
129
130         /**
131          * Report that the given node should use destructuring
132          * @param {ASTNode} reportNode the node to report
133          * @param {string} type the type of destructuring that should have been done
134          * @param {Function|null} fix the fix function or null to pass to context.report
135          * @returns {void}
136          */
137         function report(reportNode, type, fix) {
138             context.report({
139                 node: reportNode,
140                 message: "Use {{type}} destructuring.",
141                 data: { type },
142                 fix
143             });
144         }
145
146         /**
147          * Determines if a node should be fixed into object destructuring
148          *
149          * The fixer only fixes the simplest case of object destructuring,
150          * like: `let x = a.x`;
151          *
152          * Assignment expression is not fixed.
153          * Array destructuring is not fixed.
154          * Renamed property is not fixed.
155          * @param {ASTNode} node the the node to evaluate
156          * @returns {boolean} whether or not the node should be fixed
157          */
158         function shouldFix(node) {
159             return node.type === "VariableDeclarator" &&
160                 node.id.type === "Identifier" &&
161                 node.init.type === "MemberExpression" &&
162                 node.id.name === node.init.property.name;
163         }
164
165         /**
166          * Fix a node into object destructuring.
167          * This function only handles the simplest case of object destructuring,
168          * see {@link shouldFix}.
169          * @param {SourceCodeFixer} fixer the fixer object
170          * @param {ASTNode} node the node to be fixed.
171          * @returns {Object} a fix for the node
172          */
173         function fixIntoObjectDestructuring(fixer, node) {
174             const rightNode = node.init;
175             const sourceCode = context.getSourceCode();
176
177             return fixer.replaceText(
178                 node,
179                 `{${rightNode.property.name}} = ${sourceCode.getText(rightNode.object)}`
180             );
181         }
182
183         /**
184          * Check that the `prefer-destructuring` rules are followed based on the
185          * given left- and right-hand side of the assignment.
186          *
187          * Pulled out into a separate method so that VariableDeclarators and
188          * AssignmentExpressions can share the same verification logic.
189          * @param {ASTNode} leftNode the left-hand side of the assignment
190          * @param {ASTNode} rightNode the right-hand side of the assignment
191          * @param {ASTNode} reportNode the node to report the error on
192          * @returns {void}
193          */
194         function performCheck(leftNode, rightNode, reportNode) {
195             if (rightNode.type !== "MemberExpression" || rightNode.object.type === "Super") {
196                 return;
197             }
198
199             if (isArrayIndexAccess(rightNode)) {
200                 if (shouldCheck(reportNode.type, "array")) {
201                     report(reportNode, "array", null);
202                 }
203                 return;
204             }
205
206             const fix = shouldFix(reportNode)
207                 ? fixer => fixIntoObjectDestructuring(fixer, reportNode)
208                 : null;
209
210             if (shouldCheck(reportNode.type, "object") && enforceForRenamedProperties) {
211                 report(reportNode, "object", fix);
212                 return;
213             }
214
215             if (shouldCheck(reportNode.type, "object")) {
216                 const property = rightNode.property;
217
218                 if (
219                     (property.type === "Literal" && leftNode.name === property.value) ||
220                     (property.type === "Identifier" && leftNode.name === property.name && !rightNode.computed)
221                 ) {
222                     report(reportNode, "object", fix);
223                 }
224             }
225         }
226
227         /**
228          * Check if a given variable declarator is coming from an property access
229          * that should be using destructuring instead
230          * @param {ASTNode} node the variable declarator to check
231          * @returns {void}
232          */
233         function checkVariableDeclarator(node) {
234
235             // Skip if variable is declared without assignment
236             if (!node.init) {
237                 return;
238             }
239
240             // We only care about member expressions past this point
241             if (node.init.type !== "MemberExpression") {
242                 return;
243             }
244
245             performCheck(node.id, node.init, node);
246         }
247
248         /**
249          * Run the `prefer-destructuring` check on an AssignmentExpression
250          * @param {ASTNode} node the AssignmentExpression node
251          * @returns {void}
252          */
253         function checkAssigmentExpression(node) {
254             if (node.operator === "=") {
255                 performCheck(node.left, node.right, node);
256             }
257         }
258
259         //--------------------------------------------------------------------------
260         // Public
261         //--------------------------------------------------------------------------
262
263         return {
264             VariableDeclarator: checkVariableDeclarator,
265             AssignmentExpression: checkAssigmentExpression
266         };
267     }
268 };