Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: max-len: ignoreStrings+ignoreTemplateLiterals (fixes #5805) #7049

Merged
merged 1 commit into from Sep 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
}
]
}
]
});