| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 | 
							- /**
 
-  * @fileoverview Rule to flag non-quoted property names in object literals.
 
-  * @author Mathias Bynens <http://mathiasbynens.be/>
 
-  */
 
- "use strict";
 
- //------------------------------------------------------------------------------
 
- // Requirements
 
- //------------------------------------------------------------------------------
 
- const espree = require("espree"),
 
-     keywords = require("../util/keywords");
 
- //------------------------------------------------------------------------------
 
- // Rule Definition
 
- //------------------------------------------------------------------------------
 
- module.exports = {
 
-     meta: {
 
-         docs: {
 
-             description: "require quotes around object literal property names",
 
-             category: "Stylistic Issues",
 
-             recommended: false,
 
-             url: "https://eslint.org/docs/rules/quote-props"
 
-         },
 
-         schema: {
 
-             anyOf: [
 
-                 {
 
-                     type: "array",
 
-                     items: [
 
-                         {
 
-                             enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
 
-                         }
 
-                     ],
 
-                     minItems: 0,
 
-                     maxItems: 1
 
-                 },
 
-                 {
 
-                     type: "array",
 
-                     items: [
 
-                         {
 
-                             enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
 
-                         },
 
-                         {
 
-                             type: "object",
 
-                             properties: {
 
-                                 keywords: {
 
-                                     type: "boolean"
 
-                                 },
 
-                                 unnecessary: {
 
-                                     type: "boolean"
 
-                                 },
 
-                                 numbers: {
 
-                                     type: "boolean"
 
-                                 }
 
-                             },
 
-                             additionalProperties: false
 
-                         }
 
-                     ],
 
-                     minItems: 0,
 
-                     maxItems: 2
 
-                 }
 
-             ]
 
-         },
 
-         fixable: "code"
 
-     },
 
-     create(context) {
 
-         const MODE = context.options[0],
 
-             KEYWORDS = context.options[1] && context.options[1].keywords,
 
-             CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false,
 
-             NUMBERS = context.options[1] && context.options[1].numbers,
 
-             MESSAGE_UNNECESSARY = "Unnecessarily quoted property '{{property}}' found.",
 
-             MESSAGE_UNQUOTED = "Unquoted property '{{property}}' found.",
 
-             MESSAGE_NUMERIC = "Unquoted number literal '{{property}}' used as key.",
 
-             MESSAGE_RESERVED = "Unquoted reserved word '{{property}}' used as key.",
 
-             sourceCode = context.getSourceCode();
 
-         /**
 
-          * Checks whether a certain string constitutes an ES3 token
 
-          * @param   {string} tokenStr - The string to be checked.
 
-          * @returns {boolean} `true` if it is an ES3 token.
 
-          */
 
-         function isKeyword(tokenStr) {
 
-             return keywords.indexOf(tokenStr) >= 0;
 
-         }
 
-         /**
 
-          * Checks if an espree-tokenized key has redundant quotes (i.e. whether quotes are unnecessary)
 
-          * @param   {string} rawKey The raw key value from the source
 
-          * @param   {espreeTokens} tokens The espree-tokenized node key
 
-          * @param   {boolean} [skipNumberLiterals=false] Indicates whether number literals should be checked
 
-          * @returns {boolean} Whether or not a key has redundant quotes.
 
-          * @private
 
-          */
 
-         function areQuotesRedundant(rawKey, tokens, skipNumberLiterals) {
 
-             return tokens.length === 1 && tokens[0].start === 0 && tokens[0].end === rawKey.length &&
 
-                 (["Identifier", "Keyword", "Null", "Boolean"].indexOf(tokens[0].type) >= 0 ||
 
-                 (tokens[0].type === "Numeric" && !skipNumberLiterals && String(+tokens[0].value) === tokens[0].value));
 
-         }
 
-         /**
 
-          * Returns a string representation of a property node with quotes removed
 
-          * @param {ASTNode} key Key AST Node, which may or may not be quoted
 
-          * @returns {string} A replacement string for this property
 
-          */
 
-         function getUnquotedKey(key) {
 
-             return key.type === "Identifier" ? key.name : key.value;
 
-         }
 
-         /**
 
-          * Returns a string representation of a property node with quotes added
 
-          * @param {ASTNode} key Key AST Node, which may or may not be quoted
 
-          * @returns {string} A replacement string for this property
 
-          */
 
-         function getQuotedKey(key) {
 
-             if (key.type === "Literal" && typeof key.value === "string") {
 
-                 // If the key is already a string literal, don't replace the quotes with double quotes.
 
-                 return sourceCode.getText(key);
 
-             }
 
-             // Otherwise, the key is either an identifier or a number literal.
 
-             return `"${key.type === "Identifier" ? key.name : key.value}"`;
 
-         }
 
-         /**
 
-          * Ensures that a property's key is quoted only when necessary
 
-          * @param   {ASTNode} node Property AST node
 
-          * @returns {void}
 
-          */
 
-         function checkUnnecessaryQuotes(node) {
 
-             const key = node.key;
 
-             if (node.method || node.computed || node.shorthand) {
 
-                 return;
 
-             }
 
-             if (key.type === "Literal" && typeof key.value === "string") {
 
-                 let tokens;
 
-                 try {
 
-                     tokens = espree.tokenize(key.value);
 
-                 } catch (e) {
 
-                     return;
 
-                 }
 
-                 if (tokens.length !== 1) {
 
-                     return;
 
-                 }
 
-                 const isKeywordToken = isKeyword(tokens[0].value);
 
-                 if (isKeywordToken && KEYWORDS) {
 
-                     return;
 
-                 }
 
-                 if (CHECK_UNNECESSARY && areQuotesRedundant(key.value, tokens, NUMBERS)) {
 
-                     context.report({
 
-                         node,
 
-                         message: MESSAGE_UNNECESSARY,
 
-                         data: { property: key.value },
 
-                         fix: fixer => fixer.replaceText(key, getUnquotedKey(key))
 
-                     });
 
-                 }
 
-             } else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) {
 
-                 context.report({
 
-                     node,
 
-                     message: MESSAGE_RESERVED,
 
-                     data: { property: key.name },
 
-                     fix: fixer => fixer.replaceText(key, getQuotedKey(key))
 
-                 });
 
-             } else if (NUMBERS && key.type === "Literal" && typeof key.value === "number") {
 
-                 context.report({
 
-                     node,
 
-                     message: MESSAGE_NUMERIC,
 
-                     data: { property: key.value },
 
-                     fix: fixer => fixer.replaceText(key, getQuotedKey(key))
 
-                 });
 
-             }
 
-         }
 
-         /**
 
-          * Ensures that a property's key is quoted
 
-          * @param   {ASTNode} node Property AST node
 
-          * @returns {void}
 
-          */
 
-         function checkOmittedQuotes(node) {
 
-             const key = node.key;
 
-             if (!node.method && !node.computed && !node.shorthand && !(key.type === "Literal" && typeof key.value === "string")) {
 
-                 context.report({
 
-                     node,
 
-                     message: MESSAGE_UNQUOTED,
 
-                     data: { property: key.name || key.value },
 
-                     fix: fixer => fixer.replaceText(key, getQuotedKey(key))
 
-                 });
 
-             }
 
-         }
 
-         /**
 
-          * Ensures that an object's keys are consistently quoted, optionally checks for redundancy of quotes
 
-          * @param   {ASTNode} node Property AST node
 
-          * @param   {boolean} checkQuotesRedundancy Whether to check quotes' redundancy
 
-          * @returns {void}
 
-          */
 
-         function checkConsistency(node, checkQuotesRedundancy) {
 
-             const quotedProps = [],
 
-                 unquotedProps = [];
 
-             let keywordKeyName = null,
 
-                 necessaryQuotes = false;
 
-             node.properties.forEach(property => {
 
-                 const key = property.key;
 
-                 if (!key || property.method || property.computed || property.shorthand) {
 
-                     return;
 
-                 }
 
-                 if (key.type === "Literal" && typeof key.value === "string") {
 
-                     quotedProps.push(property);
 
-                     if (checkQuotesRedundancy) {
 
-                         let tokens;
 
-                         try {
 
-                             tokens = espree.tokenize(key.value);
 
-                         } catch (e) {
 
-                             necessaryQuotes = true;
 
-                             return;
 
-                         }
 
-                         necessaryQuotes = necessaryQuotes || !areQuotesRedundant(key.value, tokens) || KEYWORDS && isKeyword(tokens[0].value);
 
-                     }
 
-                 } else if (KEYWORDS && checkQuotesRedundancy && key.type === "Identifier" && isKeyword(key.name)) {
 
-                     unquotedProps.push(property);
 
-                     necessaryQuotes = true;
 
-                     keywordKeyName = key.name;
 
-                 } else {
 
-                     unquotedProps.push(property);
 
-                 }
 
-             });
 
-             if (checkQuotesRedundancy && quotedProps.length && !necessaryQuotes) {
 
-                 quotedProps.forEach(property => {
 
-                     context.report({
 
-                         node: property,
 
-                         message: "Properties shouldn't be quoted as all quotes are redundant.",
 
-                         fix: fixer => fixer.replaceText(property.key, getUnquotedKey(property.key))
 
-                     });
 
-                 });
 
-             } else if (unquotedProps.length && keywordKeyName) {
 
-                 unquotedProps.forEach(property => {
 
-                     context.report({
 
-                         node: property,
 
-                         message: "Properties should be quoted as '{{property}}' is a reserved word.",
 
-                         data: { property: keywordKeyName },
 
-                         fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
 
-                     });
 
-                 });
 
-             } else if (quotedProps.length && unquotedProps.length) {
 
-                 unquotedProps.forEach(property => {
 
-                     context.report({
 
-                         node: property,
 
-                         message: "Inconsistently quoted property '{{key}}' found.",
 
-                         data: { key: property.key.name || property.key.value },
 
-                         fix: fixer => fixer.replaceText(property.key, getQuotedKey(property.key))
 
-                     });
 
-                 });
 
-             }
 
-         }
 
-         return {
 
-             Property(node) {
 
-                 if (MODE === "always" || !MODE) {
 
-                     checkOmittedQuotes(node);
 
-                 }
 
-                 if (MODE === "as-needed") {
 
-                     checkUnnecessaryQuotes(node);
 
-                 }
 
-             },
 
-             ObjectExpression(node) {
 
-                 if (MODE === "consistent") {
 
-                     checkConsistency(node, false);
 
-                 }
 
-                 if (MODE === "consistent-as-needed") {
 
-                     checkConsistency(node, true);
 
-                 }
 
-             }
 
-         };
 
-     }
 
- };
 
 
  |