Skip to content

Commit

Permalink
New: max-len: ignoreStrings+ignoreTemplateLiterals (fixes #5805) (
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb authored and ilyavolodin committed Sep 8, 2016
1 parent 538d258 commit 6d97c18
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 1 deletion.
22 changes: 22 additions & 0 deletions docs/rules/max-len.md
Expand Up @@ -23,6 +23,8 @@ This rule has a number or object option:
* `"ignoreComments": true` ignores all trailing comments and comments on their own line
* `"ignoreTrailingComments": true` ignores only trailing comments
* `"ignoreUrls": true` ignores lines that contain a URL
* `"ignoreStrings": true` ignores lines that contain a double-quoted or single-quoted string
* `"ignoreTemplateLiterals": true` ignores lines that contain a template literal

### code

Expand Down Expand Up @@ -111,6 +113,26 @@ Examples of **correct** code for this rule with the `{ "ignoreUrls": true }` opt
var url = 'https://www.example.com/really/really/really/really/really/really/really/long';
```

### ignoreStrings

Examples of **correct** code for this rule with the `{ "ignoreStrings": true }` option:

```js
/*eslint max-len: ["error", { "ignoreStrings": true }]*/

var longString = 'this is a really really really really really long string!';
```

### ignoreTemplateLiterals

Examples of **correct** code for this rule with the `{ "ignoreTemplateLiterals": true }` option:

```js
/*eslint max-len: ["error", { "ignoreTemplateLiterals": true }]*/

var longTemplateLiteral = `this is a really really really really really long template literal!`;
```

### ignorePattern

Examples of **correct** code for this rule with the `{ "ignorePattern": true }` option:
Expand Down
72 changes: 71 additions & 1 deletion lib/rules/max-len.js
Expand Up @@ -30,9 +30,15 @@ const OPTIONS_SCHEMA = {
ignoreComments: {
type: "boolean"
},
ignoreStrings: {
type: "boolean"
},
ignoreUrls: {
type: "boolean"
},
ignoreTemplateLiterals: {
type: "boolean"
},
ignoreTrailingComments: {
type: "boolean"
}
Expand Down Expand Up @@ -121,6 +127,8 @@ module.exports = {
const maxLength = options.code || 80,
tabWidth = options.tabWidth || 4,
ignoreComments = options.ignoreComments || false,
ignoreStrings = options.ignoreStrings || false,
ignoreTemplateLiterals = options.ignoreTemplateLiterals || false,
ignoreTrailingComments = options.ignoreTrailingComments || options.ignoreComments || false,
ignoreUrls = options.ignoreUrls || false,
maxCommentLength = options.comments;
Expand Down Expand Up @@ -179,6 +187,59 @@ module.exports = {
return line.slice(0, comment.loc.start.column).replace(/\s+$/, "");
}

/**
* Ensure that an array exists at [key] on `object`, and add `value` to it.
*
* @param {Object} object the object to mutate
* @param {string} key the object's key
* @param {*} value the value to add
* @returns {void}
* @private
*/
function ensureArrayAndPush(object, key, value) {
if (!Array.isArray(object[key])) {
object[key] = [];
}
object[key].push(value);
}

/**
* Retrieves an array containing all strings (" or ') in the source code.
*
* @returns {ASTNode[]} An array of string nodes.
*/
function getAllStrings() {
return sourceCode.ast.tokens.filter(function(token) {
return token.type === "String";
});
}

/**
* Retrieves an array containing all template literals in the source code.
*
* @returns {ASTNode[]} An array of template literal nodes.
*/
function getAllTemplateLiterals() {
return sourceCode.ast.tokens.filter(function(token) {
return token.type === "Template";
});
}


/**
* A reducer to group an AST node by line number, both start and end.
*
* @param {Object} acc the accumulator
* @param {ASTNode} node the AST node in question
* @returns {Object} the modified accumulator
* @private
*/
function groupByLineNumber(acc, node) {
ensureArrayAndPush(acc, node.loc.start.line, node);
ensureArrayAndPush(acc, node.loc.end.line, node);
return acc;
}

/**
* Check the program for max length
* @param {ASTNode} node Node to examine
Expand All @@ -196,6 +257,12 @@ module.exports = {
// we iterate over comments in parallel with the lines
let commentsIndex = 0;

const strings = getAllStrings(sourceCode);
const stringsByLine = strings.reduce(groupByLineNumber, {});

const templateLiterals = getAllTemplateLiterals(sourceCode);
const templateLiteralsByLine = templateLiterals.reduce(groupByLineNumber, {});

lines.forEach(function(line, i) {

// i is zero-indexed, line numbers are one-indexed
Expand Down Expand Up @@ -229,7 +296,10 @@ module.exports = {
}
}
if (ignorePattern && ignorePattern.test(line) ||
ignoreUrls && URL_REGEXP.test(line)) {
ignoreUrls && URL_REGEXP.test(line) ||
ignoreStrings && stringsByLine[lineNumber] ||
ignoreTemplateLiterals && templateLiteralsByLine[lineNumber]
) {

// ignore this line
return;
Expand Down
84 changes: 84 additions & 0 deletions tests/lib/rules/max-len.js
Expand Up @@ -15,6 +15,8 @@ const rule = require("../../../lib/rules/max-len"),
// Tests
//------------------------------------------------------------------------------

const parserOptions = { ecmaVersion: 6 };

const ruleTester = new RuleTester();

ruleTester.run("max-len", rule, {
Expand Down Expand Up @@ -85,6 +87,30 @@ ruleTester.run("max-len", rule, {
options: [40, 4, {ignoreComments: true, ignoreTrailingComments: false}]
},

// ignoreStrings and ignoreTemplateLiterals options
{
code: "var foo = veryLongIdentifier;\nvar bar = 'this is a very long string';",
options: [29, 4, { ignoreStrings: true }]
},
{
code: "var foo = veryLongIdentifier;\nvar bar = \"this is a very long string\";",
options: [29, 4, { ignoreStrings: true }]
},
{
code: "var str = \"this is a very long string\\\nwith continuation\";",
options: [29, 4, { ignoreStrings: true }]
},
{
code: "var foo = veryLongIdentifier;\nvar bar = `this is a very long string`;",
options: [29, 4, { ignoreTemplateLiterals: true }],
parserOptions
},
{
code: "var foo = veryLongIdentifier;\nvar bar = `this is a very long string\nand this is another line that is very long`;",
options: [29, 4, { ignoreTemplateLiterals: true }],
parserOptions
},

// check indented comment lines - https://github.com/eslint/eslint/issues/6322
{
code: "function foo() {\n" +
Expand Down Expand Up @@ -409,6 +435,64 @@ ruleTester.run("max-len", rule, {
column: 1
}
]
},

// ignoreStrings and ignoreTemplateLiterals options
{
code: "var foo = veryLongIdentifier;\nvar bar = 'this is a very long string';",
options: [29, { ignoreStrings: false, ignoreTemplateLiterals: true }],
errors: [
{
message: "Line 2 exceeds the maximum line length of 29.",
type: "Program",
line: 2,
column: 1
}
]
},
{
code: "var foo = veryLongIdentifier;\nvar bar = \"this is a very long string\";",
options: [29, { ignoreStrings: false, ignoreTemplateLiterals: true }],
errors: [
{
message: "Line 2 exceeds the maximum line length of 29.",
type: "Program",
line: 2,
column: 1
}
]
},
{
code: "var foo = veryLongIdentifier;\nvar bar = `this is a very long string`;",
options: [29, { ignoreStrings: false, ignoreTemplateLiterals: false }],
parserOptions,
errors: [
{
message: "Line 2 exceeds the maximum line length of 29.",
type: "Program",
line: 2,
column: 1
}
]
},
{
code: "var foo = veryLongIdentifier;\nvar bar = `this is a very long string\nand this is another line that is very long`;",
options: [29, { ignoreStrings: false, ignoreTemplateLiterals: false }],
parserOptions,
errors: [
{
message: "Line 2 exceeds the maximum line length of 29.",
type: "Program",
line: 2,
column: 1
},
{
message: "Line 3 exceeds the maximum line length of 29.",
type: "Program",
line: 3,
column: 1
}
]
}
]
});

0 comments on commit 6d97c18

Please sign in to comment.