Skip to content

Commit

Permalink
Update: allow template literals (fixes #5234)
Browse files Browse the repository at this point in the history
  • Loading branch information
BarryThePenguin committed Apr 13, 2016
1 parent 25b376c commit fb3c2eb
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 22 deletions.
37 changes: 27 additions & 10 deletions docs/rules/quotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,20 @@ This rule is aimed at ensuring consistency of string quotes and as such will rep
The rule configuration takes up to two options:

1. The first option is `"double"`, `"single"` or `"backtick"` for double-quotes, single-quotes or backticks respectively. The default is `"double"`.
1. The second option is the `"avoid-escape"` flag. When using `"avoid-escape"`, this rule will not report a problem when a string is using single-quotes or double-quotes so long as the string contains a quote that would have to be escaped otherwise. For example, if you specify `"double"` and `"avoid-escape"`, the string `'He said, "hi!"'` is not considered a problem because using double quotes for that string would require escaping the double quotes inside of the string. This option is off by default.

When using `"single"` or `"double"`, template literals that don't contain a substitution, don't contain a line break and aren't tagged templates, are flagged as problems, even with the `"avoid-escape"` option.
1. The second option takes two options:
1. `"avoidEscape"`: When using `"avoidEscape"`, this rule will not report a problem when a string is using single-quotes or double-quotes so long as the string contains a quote that would have to be escaped otherwise. For example, if you specify `"double"` and `"avoidEscape"`, the string `'He said, "hi!"'` is not considered a problem because using double quotes for that string would require escaping the double quotes inside of the string. This option is off by default.
1. `"allowTemplateLiterals"`: when using `"allowTemplateLiterals"`, this rule will not report a problem when a string is using backticks and option one is either `"double"` or `"single"`.

When using `"single"` or `"double"`, template literals that don't contain a substitution, don't contain a line break and aren't tagged templates, are flagged as problems, even with the `"avoidEscape"` option. However they are not problems when `"allowTemplateLiterals"` is used.

Configuration looks like this:

```js
[2, "single", "avoid-escape"]
[2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}]
```

**Deprecation notice**: The `avoid-escape` option is a deprecated syntax and you should use the object form instead.

The following patterns are considered problems:

```js
Expand All @@ -51,14 +54,14 @@ var unescaped = "a string containing 'single' quotes";
```

```js
/*eslint quotes: ["error", "double", "avoid-escape"]*/
/*eslint quotes: ["error", "double", {"avoidEscape": true}]*/

var single = 'single';
var single = `single`;
```

```js
/*eslint quotes: ["error", "single", "avoid-escape"]*/
/*eslint quotes: ["error", "single", {"avoidEscape": true}]*/

var double = "double";
var double = `double`;
Expand All @@ -73,7 +76,7 @@ var unescaped = 'a string containing `backticks`';
```

```js
/*eslint quotes: ["error", "backtick", "avoid-escape"]*/
/*eslint quotes: ["error", "backtick", {"avoidEscape": true}]*/

var single = 'single';
var double = "double";
Expand All @@ -99,17 +102,31 @@ var backtick = `back${x}tick`; // backticks are allowed due to substitution
```

```js
/*eslint quotes: ["error", "double", "avoid-escape"]*/
/*eslint quotes: ["error", "double", {"avoidEscape": true}]*/

var single = 'a string containing "double" quotes';
```

```js
/*eslint quotes: ["error", "single", "avoid-escape"]*/
/*eslint quotes: ["error", "single", {"avoidEscape": true}]*/

var double = "a string containing 'single' quotes";
```

```js
/*eslint quotes: ["error", "double", {"allowTemplateLiterals": true}]*/

var single = 'single';
var single = `single`;
```

```js
/*eslint quotes: ["error", "single", {"allowTemplateLiterals": true}]*/

var double = "double";
var double = `double`;
```

```js
/*eslint quotes: ["error", "backtick"]*/
/*eslint-env es6*/
Expand All @@ -118,7 +135,7 @@ var backtick = `backtick`;
```

```js
/*eslint quotes: ["error", "backtick", "avoid-escape"]*/
/*eslint quotes: ["error", "backtick", {"avoidEscape": true}]*/

var double = "a string containing `backtick` quotes"
```
Expand Down
29 changes: 26 additions & 3 deletions lib/rules/quotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,16 @@ module.exports = function(context) {

var quoteOption = context.options[0],
settings = QUOTE_SETTINGS[quoteOption || "double"],
avoidEscape = context.options[1] === AVOID_ESCAPE,
options = context.options[1],
avoidEscape = options && options.avoidEscape === true,
allowTemplateLiterals = options && options.allowTemplateLiterals === true,
sourceCode = context.getSourceCode();

// deprecated
if (options === AVOID_ESCAPE) {
avoidEscape = true;
}

/**
* Determines if a given node is part of JSX syntax.
* @param {ASTNode} node The node to check.
Expand Down Expand Up @@ -197,7 +204,7 @@ module.exports = function(context) {
"TemplateLiteral": function(node) {

// If backticks are expected or it's a tagged template, then this shouldn't throw an errors
if (quoteOption === "backtick" || node.parent.type === "TaggedTemplateExpression") {
if (allowTemplateLiterals || quoteOption === "backtick" || node.parent.type === "TaggedTemplateExpression") {
return;
}

Expand All @@ -222,6 +229,22 @@ module.exports.schema = [
"enum": ["single", "double", "backtick"]
},
{
"enum": ["avoid-escape"]
"anyOf": [
{
"enum": ["avoid-escape"]
},
{
"type": "object",
"properties": {
"avoidEscape": {
"type": "boolean"
},
"allowTemplateLiterals": {
"type": "boolean"
}
},
"additionalProperties": false
}
]
}
];
35 changes: 26 additions & 9 deletions tests/lib/rules/quotes.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ ruleTester.run("quotes", rule, {
{ code: "var foo = \"bar\";", options: ["double"] },
{ code: "var foo = 1;", options: ["single"] },
{ code: "var foo = 1;", options: ["double"] },
{ code: "var foo = \"'\";", options: ["single", "avoid-escape"] },
{ code: "var foo = '\"';", options: ["double", "avoid-escape"] },
{ code: "var foo = \"'\";", options: ["single", { avoidEscape: true }] },
{ code: "var foo = '\"';", options: ["double", { avoidEscape: true }] },
{ code: "var foo = <div>Hello world</div>;", options: ["single"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = <div id=\"foo\"></div>;", options: ["single"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = <div>Hello world</div>;", options: ["double"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = <div>Hello world</div>;", options: ["double", "avoid-escape"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = <div>Hello world</div>;", options: ["double", { avoidEscape: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = `bar`;", options: ["backtick"], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = `bar 'baz'`;", options: ["backtick"], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = `bar \"baz\"`;", options: ["backtick"], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = 1;", options: ["backtick"]},
{ code: "var foo = \"a string containing `backtick` quotes\";", options: ["backtick", "avoid-escape"] },
{ code: "var foo = \"a string containing `backtick` quotes\";", options: ["backtick", { avoidEscape: true }] },
{ code: "var foo = <div id=\"foo\"></div>;", options: ["backtick"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } } },
{ code: "var foo = <div>Hello world</div>;", options: ["backtick"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } }},

Expand All @@ -43,6 +43,11 @@ ruleTester.run("quotes", rule, {
{ code: "var foo = `back${x}tick`;", options: ["double"], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = tag`backtick`;", options: ["double"], parserOptions: { ecmaVersion: 6 }},

// Backticks are also okay if allowTemplateLiterals
{ code: "var foo = `bar 'foo' baz` + 'bar';", options: ["single", { allowTemplateLiterals: true }], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = `bar 'foo' baz` + \"bar\";", options: ["double", { allowTemplateLiterals: true }], parserOptions: { ecmaVersion: 6 }},
{ code: "var foo = `bar 'foo' baz` + `bar`;", options: ["backtick", { allowTemplateLiterals: true }], parserOptions: { ecmaVersion: 6 }},

// `backtick` should not warn the directive prologues.
{ code: "\"use strict\"; var foo = `backtick`;", options: ["backtick"], parserOptions: { ecmaVersion: 6 }},
{ code: "\"use strict\"; 'use strong'; \"use asm\"; var foo = `backtick`;", options: ["backtick"], parserOptions: { ecmaVersion: 6 }},
Expand Down Expand Up @@ -111,19 +116,31 @@ ruleTester.run("quotes", rule, {
{
code: "var foo = \"bar\";",
output: "var foo = 'bar';",
options: ["single", "avoid-escape"],
options: ["single", { avoidEscape: true }],
errors: [{ message: "Strings must use singlequote.", type: "Literal" }]
},
{
code: "var foo = 'bar';",
output: "var foo = \"bar\";",
options: ["double", "avoid-escape"],
options: ["double", { avoidEscape: true }],
errors: [{ message: "Strings must use doublequote.", type: "Literal" }]
},
{
code: "var foo = '\\\\';",
output: "var foo = \"\\\\\";",
options: ["double", "avoid-escape"],
options: ["double", { avoidEscape: true }],
errors: [{ message: "Strings must use doublequote.", type: "Literal" }]
},
{
code: "var foo = \"bar\";",
output: "var foo = 'bar';",
options: ["single", { allowTemplateLiterals: true }],
errors: [{ message: "Strings must use singlequote.", type: "Literal" }]
},
{
code: "var foo = 'bar';",
output: "var foo = \"bar\";",
options: ["double", { allowTemplateLiterals: true }],
errors: [{ message: "Strings must use doublequote.", type: "Literal" }]
},
{
Expand All @@ -147,13 +164,13 @@ ruleTester.run("quotes", rule, {
{
code: "var foo = \"bar\";",
output: "var foo = `bar`;",
options: ["backtick", "avoid-escape"],
options: ["backtick", { avoidEscape: true }],
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},
{
code: "var foo = 'bar';",
output: "var foo = `bar`;",
options: ["backtick", "avoid-escape"],
options: ["backtick", { avoidEscape: true }],
errors: [{ message: "Strings must use backtick.", type: "Literal" }]
},

Expand Down

0 comments on commit fb3c2eb

Please sign in to comment.