Skip to content

Commit

Permalink
Update: merge no-reserved-keys into quote-props (fixes eslint#1539)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrvidal committed Jul 3, 2015
1 parent 07aac75 commit 58eaf3f
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 122 deletions.
2 changes: 1 addition & 1 deletion docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The following rules point out areas where you might have made mistakes.
* [no-negated-in-lhs](no-negated-in-lhs.md) - disallow negation of the left operand of an `in` expression
* [no-obj-calls](no-obj-calls.md) - disallow the use of object properties of the global object (`Math` and `JSON`) as functions
* [no-regex-spaces](no-regex-spaces.md) - disallow multiple spaces in a regular expression literal
* [no-reserved-keys](no-reserved-keys.md) - disallow reserved words being used as object literal keys (off by default)
* [no-reserved-keys](no-reserved-keys.md) - **(deprecated)** disallow reserved words being used as object literal keys (off by default)
* [no-sparse-arrays](no-sparse-arrays.md) - disallow sparse arrays
* [no-unreachable](no-unreachable.md) - disallow unreachable statements after a return, throw, continue, or break statement
* [use-isnan](use-isnan.md) - disallow comparisons with the value `NaN`
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/no-reserved-keys.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Disallow Use of Reserved Words as Keys (no-reserved-keys)

**Deprecation notice**: This rule is deprecated and has been superseded by the [quote-props](quote-props.md) rule, when configured with `{keywords: true}`. It will be removed in ESLint v1.0.

ECMAScript 3 described as series of keywords and reserved words, such as `if` and `public`, that are used or intended to be used for a core language feature. The specification also indicated that these keywords and reserved words could not be used as object property names without being enclosed in strings. An error occurs in an ECMAScript 3 environment when you use a keyword or reserved word in an object literal. For example:

```js
Expand Down
71 changes: 34 additions & 37 deletions docs/rules/quote-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ var object2 = {
};
```

In many cases, it doesn't matter if you choose to use an identifier instead of a string or vice-versa. There are, however, some occasions when you must use quotes:
In many cases, it doesn't matter if you choose to use an identifier instead of a string or vice-versa. Even so, you might decide to enforce a consistent style in your code.

There are, however, some occasions when you must use quotes:

1. If you are using an ECMAScript 3 JavaScript engine (such as IE8) and you want to use a keyword (such as `if`) as a property name. This restriction was removed in ECMAScript 5.
2. You want to use a non-identifier character in your property name, such as having a property with a space like `"one two"`.

Sometimes the choice to use quotes is purely stylistic and sometimes it's functional. Here's another example:
Another example where quotes do matter is when using numeric literals as property keys:

```js
var object = {
Expand All @@ -32,8 +34,6 @@ This may look alright at first sight, but this code in fact throws a syntax erro

This rule aims to enforce use of quotes in property names and as such will flag any properties that don't use quotes.

### Options

There are two behaviors for this rule: `"always"` (default) and `"as-needed"`. You can define these options in your configuration as:

```json
Expand All @@ -42,37 +42,7 @@ There are two behaviors for this rule: `"always"` (default) and `"as-needed"`. Y
}
```

When configured with `"always"` as the first option (the default), quoting for all properties will be enforced. Some believe that ensuring property names in object literals are always wrapped in quotes is generally a good idea, since [depending on the property name you may need to quote them anyway](https://mathiasbynens.be/notes/javascript-properties). Consider this example:

```js
var object = {
foo: "bar",
baz: 42,
"qux-lorem": true
};
```

Here, the properties `foo` and `baz` are not wrapped in quotes, but `qux-lorem` is, because it doesn’t work without the quotes. This is rather inconsistent. Instead, you may prefer to quote property names consistently:

```js
var object = {
"foo": "bar",
"baz": 42,
"qux-lorem": true
};
```

or, if you prefer single quotes:

```js
var object = {
'foo': 'bar',
'baz': 42,
'qux-lorem': true
};
```

When configured with `"always"` (the default), the following patterns are considered warnings:
When configured with `"always"` as the first option (the default), quoting for all properties will be enforced. The following patterns are considered warnings:

```js
var object = {
Expand Down Expand Up @@ -104,7 +74,7 @@ var object3 = {
};
```

When configured with `"as-needed"` as the first option (the default), the following patterns are considered warnings:
When configured with `"as-needed"` as the first option, quotes will be enforced when they are strictly required, and unnecessary quotes will cause warnings. The following patterns are considered warnings:

```js
var object = {
Expand All @@ -126,6 +96,7 @@ var object1 = {
var object2 = {
foo: 'bar',
baz: 42,
true: 0,
'qux-lorem': true
};

Expand All @@ -136,6 +107,32 @@ var object3 = {
};
```


### Options

When the `"as-needed"` mode is selected, an additional `keywords` option can be provided. This flag indicates whether language keywords can be used unquoted as properties. By default it is set to `false`.

```json
{
"quote-props": [2, "as-needed", {keywords: true}]
}
```

When `keywords` is set to `true`, the following patterns become warnings:

```
var x = {
while: 1,
volatile: "foo"
};
```

## When Not To Use It

If you don't care if property names are consistently wrapped in quotes or not, turn this rule off.
If you don't care if property names are consistently wrapped in quotes or not, and you don't target legacy ES3 environments, turn this rule off.

## Further Reading

* [Reserved words as property names](http://kangax.github.io/compat-table/es5/#Reserved_words_as_property_names)
* [Unquoted property names / object keys in JavaScript](https://mathiasbynens.be/notes/javascript-properties)
62 changes: 1 addition & 61 deletions lib/rules/dot-notation.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,67 +9,7 @@
//------------------------------------------------------------------------------

var validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
var keywords = [
"this",
"function",
"if",
"return",
"var",
"else",
"for",
"new",
"in",
"typeof",
"while",
"case",
"break",
"try",
"catch",
"delete",
"throw",
"switch",
"continue",
"default",
"instanceof",
"do",
"void",
"finally",
"with",
"debugger",
"implements",
"interface",
"package",
"private",
"protected",
"public",
"static",
"class",
"enum",
"export",
"extends",
"import",
"super",
"true",
"false",
"null",
"abstract",
"boolean",
"byte",
"char",
"const",
"double",
"final",
"float",
"goto",
"int",
"long",
"native",
"short",
"synchronized",
"throws",
"transient",
"volatile"
];
var keywords = require("../util/keywords");

module.exports = function(context) {
var options = context.options[0] || {};
Expand Down
56 changes: 47 additions & 9 deletions lib/rules/quote-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,33 @@
// Requirements
//------------------------------------------------------------------------------

var espree = require("espree");
var espree = require("espree"),
keywords = require("../util/keywords");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

var MODE = context.options[0];
var MODE = context.options[0],
KEYWORDS = context.options[1] && context.options[1].keywords,

MESSAGES = {
UNNECESSARY: "Unnecessarily quoted property `{{property}}` found.",
UNQUOTED: "Unquoted property `{{property}}` found.",
RESERVED: "Unquoted reserved word `{{property}}` used as key."
};


/**
* 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;
}

/**
* Ensures that a property's key is quoted only when necessary
Expand All @@ -26,6 +44,7 @@ module.exports = function(context) {
*/
function asNeeded(node) {
var key = node.key,
isKeywordToken,
tokens;

if (key.type === "Literal" && typeof key.value === "string") {
Expand All @@ -35,12 +54,22 @@ module.exports = function(context) {
return;
}

if (tokens.length === 1 &&
(["Identifier", "Null", "Boolean"].indexOf(tokens[0].type) >= 0 ||
(tokens[0].type === "Numeric" && "" + +tokens[0].value === tokens[0].value))
) {
context.report(node, "Unnecessarily quoted property `{{value}}` found.", key);
if (tokens.length !== 1) {
return;
}

isKeywordToken = isKeyword(tokens[0].value);

if (isKeywordToken && KEYWORDS) {
return;
}

if (tokens[0].type === "Identifier" || isKeywordToken ||
(tokens[0].type === "Numeric" && "" + +tokens[0].value === tokens[0].value)) {
context.report(node, MESSAGES.UNNECESSARY, {property: key.value});
}
} else if (KEYWORDS && key.type === "Identifier" && isKeyword(key.name)) {
context.report(node, MESSAGES.RESERVED, {property: key.name});
}
}

Expand All @@ -53,8 +82,8 @@ module.exports = function(context) {
var key = node.key;

if (!node.method && !(key.type === "Literal" && typeof key.value === "string")) {
context.report(node, "Unquoted property `{{key}}` found.", {
key: key.name || key.value
context.report(node, MESSAGES.UNQUOTED, {
property: key.name || key.value
});
}
}
Expand All @@ -68,5 +97,14 @@ module.exports = function(context) {
module.exports.schema = [
{
"enum": ["always", "as-needed"]
},
{
"type": "object",
"properties": {
"keywords": {
"type": "boolean"
}
},
"additionalProperties": false
}
];
63 changes: 63 additions & 0 deletions lib/util/keywords.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"use strict";

module.exports = [
"abstract",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"double",
"else",
"enum",
"export",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"var",
"void",
"volatile",
"while",
"with"
];

0 comments on commit 58eaf3f

Please sign in to comment.