source: imaps-frontend/node_modules/eslint/lib/rules/quote-props.js@ d565449

main
Last change on this file since d565449 was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/**
2 * @fileoverview Rule to flag non-quoted property names in object literals.
3 * @author Mathias Bynens <http://mathiasbynens.be/>
4 * @deprecated in ESLint v8.53.0
5 */
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const espree = require("espree");
13const astUtils = require("./utils/ast-utils");
14const keywords = require("./utils/keywords");
15
16//------------------------------------------------------------------------------
17// Rule Definition
18//------------------------------------------------------------------------------
19
20/** @type {import('../shared/types').Rule} */
21module.exports = {
22 meta: {
23 deprecated: true,
24 replacedBy: [],
25 type: "suggestion",
26
27 docs: {
28 description: "Require quotes around object literal property names",
29 recommended: false,
30 url: "https://eslint.org/docs/latest/rules/quote-props"
31 },
32
33 schema: {
34 anyOf: [
35 {
36 type: "array",
37 items: [
38 {
39 enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
40 }
41 ],
42 minItems: 0,
43 maxItems: 1
44 },
45 {
46 type: "array",
47 items: [
48 {
49 enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
50 },
51 {
52 type: "object",
53 properties: {
54 keywords: {
55 type: "boolean"
56 },
57 unnecessary: {
58 type: "boolean"
59 },
60 numbers: {
61 type: "boolean"
62 }
63 },
64 additionalProperties: false
65 }
66 ],
67 minItems: 0,
68 maxItems: 2
69 }
70 ]
71 },
72
73 fixable: "code",
74 messages: {
75 requireQuotesDueToReservedWord: "Properties should be quoted as '{{property}}' is a reserved word.",
76 inconsistentlyQuotedProperty: "Inconsistently quoted property '{{key}}' found.",
77 unnecessarilyQuotedProperty: "Unnecessarily quoted property '{{property}}' found.",
78 unquotedReservedProperty: "Unquoted reserved word '{{property}}' used as key.",
79 unquotedNumericProperty: "Unquoted number literal '{{property}}' used as key.",
80 unquotedPropertyFound: "Unquoted property '{{property}}' found.",
81 redundantQuoting: "Properties shouldn't be quoted as all quotes are redundant."
82 }
83 },
84
85 create(context) {
86
87 const MODE = context.options[0],
88 KEYWORDS = context.options[1] && context.options[1].keywords,
89 CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false,
90 NUMBERS = context.options[1] && context.options[1].numbers,
91
92 sourceCode = context.sourceCode;
93
94
95 /**
96 * Checks whether a certain string constitutes an ES3 token
97 * @param {string} tokenStr The string to be checked.
98 * @returns {boolean} `true` if it is an ES3 token.
99 */
100 function isKeyword(tokenStr) {
101 return keywords.includes(tokenStr);
102 }
103
104 /**
105 * Checks if an espree-tokenized key has redundant quotes (i.e. whether quotes are unnecessary)
106 * @param {string} rawKey The raw key value from the source
107 * @param {espreeTokens} tokens The espree-tokenized node key
108 * @param {boolean} [skipNumberLiterals=false] Indicates whether number literals should be checked
109 * @returns {boolean} Whether or not a key has redundant quotes.
110 * @private
111 */
112 function areQuotesRedundant(rawKey, tokens, skipNumberLiterals) {
113 return tokens.length === 1 && tokens[0].start === 0 && tokens[0].end === rawKey.length &&
114 (["Identifier", "Keyword", "Null", "Boolean"].includes(tokens[0].type) ||
115 (tokens[0].type === "Numeric" && !skipNumberLiterals && String(+tokens[0].value) === tokens[0].value));
116 }
117
118 /**
119 * Returns a string representation of a property node with quotes removed
120 * @param {ASTNode} key Key AST Node, which may or may not be quoted
121 * @returns {string} A replacement string for this property
122 */
123 function getUnquotedKey(key) {
124 return key.type === "Identifier" ? key.name : key.value;
125 }
126
127 /**
128 * Returns a string representation of a property node with quotes added
129 * @param {ASTNode} key Key AST Node, which may or may not be quoted
130 * @returns {string} A replacement string for this property
131 */
132 function getQuotedKey(key) {
133 if (key.type === "Literal" && typeof key.value === "string") {
134
135 // If the key is already a string literal, don't replace the quotes with double quotes.
136 return sourceCode.getText(key);
137 }
138
139 // Otherwise, the key is either an identifier or a number literal.
140 return `"${key.type === "Identifier" ? key.name : key.value}"`;
141 }
142
143 /**
144 * Ensures that a property's key is quoted only when necessary
145 * @param {ASTNode} node Property AST node
146 * @returns {void}
147 */
148 function checkUnnecessaryQuotes(node) {
149 const key = node.key;
150
151 if (node.method || node.computed || node.shorthand) {
152 return;
153 }
154
155 if (key.type === "Literal" && typeof key.value === "string") {
156 let tokens;
157
158 try {
159 tokens = espree.tokenize(key.value);
160 } catch {
161 return;
162 }
163
164 if (tokens.length !== 1) {
165 return;
166 }
167
168 const isKeywordToken = isKeyword(tokens[0].value);
169
170 if (isKeywordToken && KEYWORDS) {
171 return;
172 }
173
174 if (CHECK_UNNECESSARY && areQuotesRedundant(key.value, tokens, NUMBERS)) {
175 context.report({
176 node,
177 messageId: "unnecessarilyQuotedProperty",
178 data: { property: key.value },
179 fix: fixer => fixer.replaceText(key, getUnquotedKey(key))
180 });
181 }
182 } else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) {
183 context.report({
184 node,
185 messageId: "unquotedReservedProperty",
186 data: { property: key.name },
187 fix: fixer => fixer.replaceText(key, getQuotedKey(key))
188 });
189 } else if (NUMBERS && key.type === "Literal" && astUtils.isNumericLiteral(key)) {
190 context.report({
191 node,
192 messageId: "unquotedNumericProperty",
193 data: { property: key.value },
194 fix: fixer => fixer.replaceText(key, getQuotedKey(key))
195 });
196 }
197 }
198
199 /**
200 * Ensures that a property's key is quoted
201 * @param {ASTNode} node Property AST node
202 * @returns {void}
203 */
204 function checkOmittedQuotes(node) {
205 const key = node.key;
206
207 if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) {
208 context.report({
209 node,
210 messageId: "unquotedPropertyFound",
211 data: { property: key.name || key.value },
212 fix: fixer => fixer.replaceText(key, getQuotedKey(key))
213 });
214 }
215 }
216
217 /**
218 * Ensures that an object's keys are consistently quoted, optionally checks for redundancy of quotes
219 * @param {ASTNode} node Property AST node
220 * @param {boolean} checkQuotesRedundancy Whether to check quotes' redundancy
221 * @returns {void}
222 */
223 function checkConsistency(node, checkQuotesRedundancy) {
224 const quotedProps = [],
225 unquotedProps = [];
226 let keywordKeyName = null,
227 necessaryQuotes = false;
228
229 node.properties.forEach(property => {
230 const key = property.key;
231
232 if (!key || property.method || property.computed || property.shorthand) {
233 return;
234 }
235
236 if (key.type === "Literal" && typeof key.value === "string") {
237
238 quotedProps.push(property);
239
240 if (checkQuotesRedundancy) {
241 let tokens;
242
243 try {
244 tokens = espree.tokenize(key.value);
245 } catch {
246 necessaryQuotes = true;
247 return;
248 }
249
250 necessaryQuotes = necessaryQuotes || !areQuotesRedundant(key.value, tokens) || KEYWORDS && isKeyword(tokens[0].value);
251 }
252 } else if (KEYWORDS && checkQuotesRedundancy && key.type === "Identifier" && isKeyword(key.name)) {
253 unquotedProps.push(property);
254 necessaryQuotes = true;
255 keywordKeyName = key.name;
256 } else {
257 unquotedProps.push(property);
258 }
259 });
260
261 if (checkQuotesRedundancy && quotedProps.length && !necessaryQuotes) {
262 quotedProps.forEach(property => {
263 context.report({
264 node: property,
265 messageId: "redundantQuoting",
266 fix: fixer => fixer.replaceText(property.key, getUnquotedKey(property.key))
267 });
268 });
269 } else if (unquotedProps.length && keywordKeyName) {
270 unquotedProps.forEach(property => {
271 context.report({
272 node: property,
273 messageId: "requireQuotesDueToReservedWord",
274 data: { property: keywordKeyName },
275 fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
276 });
277 });
278 } else if (quotedProps.length && unquotedProps.length) {
279 unquotedProps.forEach(property => {
280 context.report({
281 node: property,
282 messageId: "inconsistentlyQuotedProperty",
283 data: { key: property.key.name || property.key.value },
284 fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
285 });
286 });
287 }
288 }
289
290 return {
291 Property(node) {
292 if (MODE === "always" || !MODE) {
293 checkOmittedQuotes(node);
294 }
295 if (MODE === "as-needed") {
296 checkUnnecessaryQuotes(node);
297 }
298 },
299 ObjectExpression(node) {
300 if (MODE === "consistent") {
301 checkConsistency(node, false);
302 }
303 if (MODE === "consistent-as-needed") {
304 checkConsistency(node, true);
305 }
306 }
307 };
308
309 }
310};
Note: See TracBrowser for help on using the repository browser.