massive update, probably broken
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / dot-notation.js
1 /**
2  * @fileoverview Rule to warn about using dot notation instead of square bracket notation when possible.
3  * @author Josh Perez
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12 const keywords = require("./utils/keywords");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
19
20 // `null` literal must be handled separately.
21 const literalTypesToCheck = new Set(["string", "boolean"]);
22
23 module.exports = {
24     meta: {
25         type: "suggestion",
26
27         docs: {
28             description: "enforce dot notation whenever possible",
29             category: "Best Practices",
30             recommended: false,
31             url: "https://eslint.org/docs/rules/dot-notation"
32         },
33
34         schema: [
35             {
36                 type: "object",
37                 properties: {
38                     allowKeywords: {
39                         type: "boolean",
40                         default: true
41                     },
42                     allowPattern: {
43                         type: "string",
44                         default: ""
45                     }
46                 },
47                 additionalProperties: false
48             }
49         ],
50
51         fixable: "code",
52
53         messages: {
54             useDot: "[{{key}}] is better written in dot notation.",
55             useBrackets: ".{{key}} is a syntax error."
56         }
57     },
58
59     create(context) {
60         const options = context.options[0] || {};
61         const allowKeywords = options.allowKeywords === void 0 || options.allowKeywords;
62         const sourceCode = context.getSourceCode();
63
64         let allowPattern;
65
66         if (options.allowPattern) {
67             allowPattern = new RegExp(options.allowPattern, "u");
68         }
69
70         /**
71          * Check if the property is valid dot notation
72          * @param {ASTNode} node The dot notation node
73          * @param {string} value Value which is to be checked
74          * @returns {void}
75          */
76         function checkComputedProperty(node, value) {
77             if (
78                 validIdentifier.test(value) &&
79                 (allowKeywords || keywords.indexOf(String(value)) === -1) &&
80                 !(allowPattern && allowPattern.test(value))
81             ) {
82                 const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
83
84                 context.report({
85                     node: node.property,
86                     messageId: "useDot",
87                     data: {
88                         key: formattedValue
89                     },
90                     *fix(fixer) {
91                         const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
92                         const rightBracket = sourceCode.getLastToken(node);
93                         const nextToken = sourceCode.getTokenAfter(node);
94
95                         // Don't perform any fixes if there are comments inside the brackets.
96                         if (sourceCode.commentsExistBetween(leftBracket, rightBracket)) {
97                             return;
98                         }
99
100                         // Replace the brackets by an identifier.
101                         if (!node.optional) {
102                             yield fixer.insertTextBefore(
103                                 leftBracket,
104                                 astUtils.isDecimalInteger(node.object) ? " ." : "."
105                             );
106                         }
107                         yield fixer.replaceTextRange(
108                             [leftBracket.range[0], rightBracket.range[1]],
109                             value
110                         );
111
112                         // Insert a space after the property if it will be connected to the next token.
113                         if (
114                             nextToken &&
115                             rightBracket.range[1] === nextToken.range[0] &&
116                             !astUtils.canTokensBeAdjacent(String(value), nextToken)
117                         ) {
118                             yield fixer.insertTextAfter(node, " ");
119                         }
120                     }
121                 });
122             }
123         }
124
125         return {
126             MemberExpression(node) {
127                 if (
128                     node.computed &&
129                     node.property.type === "Literal" &&
130                     (literalTypesToCheck.has(typeof node.property.value) || astUtils.isNullLiteral(node.property))
131                 ) {
132                     checkComputedProperty(node, node.property.value);
133                 }
134                 if (
135                     node.computed &&
136                     node.property.type === "TemplateLiteral" &&
137                     node.property.expressions.length === 0
138                 ) {
139                     checkComputedProperty(node, node.property.quasis[0].value.cooked);
140                 }
141                 if (
142                     !allowKeywords &&
143                     !node.computed &&
144                     keywords.indexOf(String(node.property.name)) !== -1
145                 ) {
146                     context.report({
147                         node: node.property,
148                         messageId: "useBrackets",
149                         data: {
150                             key: node.property.name
151                         },
152                         *fix(fixer) {
153                             const dotToken = sourceCode.getTokenBefore(node.property);
154
155                             // A statement that starts with `let[` is parsed as a destructuring variable declaration, not a MemberExpression.
156                             if (node.object.type === "Identifier" && node.object.name === "let" && !node.optional) {
157                                 return;
158                             }
159
160                             // Don't perform any fixes if there are comments between the dot and the property name.
161                             if (sourceCode.commentsExistBetween(dotToken, node.property)) {
162                                 return;
163                             }
164
165                             // Replace the identifier to brackets.
166                             if (!node.optional) {
167                                 yield fixer.remove(dotToken);
168                             }
169                             yield fixer.replaceText(node.property, `["${node.property.name}"]`);
170                         }
171                     });
172                 }
173             }
174         };
175     }
176 };