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

Fix: ignored nodes in indent rule (fixes #9392) #9393

Merged
merged 1 commit into from Oct 11, 2017
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
40 changes: 22 additions & 18 deletions lib/rules/indent.js
Expand Up @@ -235,10 +235,12 @@ class OffsetStorage {
/**
* @param {TokenInfo} tokenInfo a TokenInfo instance
* @param {number} indentSize The desired size of each indentation level
* @param {string} indentType The indentation character
*/
constructor(tokenInfo, indentSize) {
constructor(tokenInfo, indentSize, indentType) {
this._tokenInfo = tokenInfo;
this._indentSize = indentSize;
this._indentType = indentType;

this._tree = new BinarySearchTree();
this._tree.insert(0, { offset: 0, from: null, force: false });
Expand Down Expand Up @@ -408,7 +410,7 @@ class OffsetStorage {
/**
* Gets the desired indent of a token
* @param {Token} token The token
* @returns {number} The desired indent of the token
* @returns {string} The desired indent of the token
*/
getDesiredIndent(token) {
if (!this._desiredIndentCache.has(token)) {
Expand All @@ -417,7 +419,10 @@ class OffsetStorage {

// If the token is ignored, use the actual indent of the token as the desired indent.
// This ensures that no errors are reported for this token.
this._desiredIndentCache.set(token, this._tokenInfo.getTokenIndent(token).length / this._indentSize);
this._desiredIndentCache.set(
token,
this._tokenInfo.getTokenIndent(token)
);
} else if (this._lockedFirstTokens.has(token)) {
const firstToken = this._lockedFirstTokens.get(token);

Expand All @@ -428,17 +433,20 @@ class OffsetStorage {
this.getDesiredIndent(this._tokenInfo.getFirstTokenOfLine(firstToken)) +

// (space between the start of the first element's line and the first element)
(firstToken.loc.start.column - this._tokenInfo.getFirstTokenOfLine(firstToken).loc.start.column) / this._indentSize
this._indentType.repeat(firstToken.loc.start.column - this._tokenInfo.getFirstTokenOfLine(firstToken).loc.start.column)
);
} else {
const offsetInfo = this._getOffsetDescriptor(token);
const offset = (
offsetInfo.from &&
offsetInfo.from.loc.start.line === token.loc.start.line &&
!offsetInfo.force
) ? 0 : offsetInfo.offset;
) ? 0 : offsetInfo.offset * this._indentSize;

this._desiredIndentCache.set(token, offset + (offsetInfo.from ? this.getDesiredIndent(offsetInfo.from) : 0));
this._desiredIndentCache.set(
token,
(offsetInfo.from ? this.getDesiredIndent(offsetInfo.from) : "") + this._indentType.repeat(offset)
);
}
}
return this._desiredIndentCache.get(token);
Expand Down Expand Up @@ -655,7 +663,7 @@ module.exports = {

const sourceCode = context.getSourceCode();
const tokenInfo = new TokenInfo(sourceCode);
const offsets = new OffsetStorage(tokenInfo, indentSize);
const offsets = new OffsetStorage(tokenInfo, indentSize, indentType === "space" ? " " : "\t");
const parameterParens = new WeakSet();

/**
Expand Down Expand Up @@ -688,27 +696,24 @@ module.exports = {
/**
* Reports a given indent violation
* @param {Token} token Token violating the indent rule
* @param {int} neededIndentLevel Expected indentation level
* @param {int} gottenSpaces Actual number of indentation spaces for the token
* @param {int} gottenTabs Actual number of indentation tabs for the token
* @param {string} neededIndent Expected indentation string
* @returns {void}
*/
function report(token, neededIndentLevel) {
function report(token, neededIndent) {
const actualIndent = Array.from(tokenInfo.getTokenIndent(token));
const numSpaces = actualIndent.filter(char => char === " ").length;
const numTabs = actualIndent.filter(char => char === "\t").length;
const neededChars = neededIndentLevel * indentSize;

context.report({
node: token,
message: createErrorMessage(neededChars, numSpaces, numTabs),
message: createErrorMessage(neededIndent.length, numSpaces, numTabs),
loc: {
start: { line: token.loc.start.line, column: 0 },
end: { line: token.loc.start.line, column: token.loc.start.column }
},
fix(fixer) {
const range = [token.range[0] - token.loc.start.column, token.range[0]];
const newText = (indentType === "space" ? " " : "\t").repeat(neededChars);
const newText = neededIndent;

return fixer.replaceTextRange(range, newText);
}
Expand All @@ -718,14 +723,13 @@ module.exports = {
/**
* Checks if a token's indentation is correct
* @param {Token} token Token to examine
* @param {int} desiredIndentLevel needed indent level
* @param {string} desiredIndent Desired indentation of the string
* @returns {boolean} `true` if the token's indentation is correct
*/
function validateTokenIndent(token, desiredIndentLevel) {
function validateTokenIndent(token, desiredIndent) {
const indentation = tokenInfo.getTokenIndent(token);
const expectedChar = indentType === "space" ? " " : "\t";

return indentation === expectedChar.repeat(desiredIndentLevel * indentSize) ||
return indentation === desiredIndent ||

// To avoid conflicts with no-mixed-spaces-and-tabs, don't report mixed spaces and tabs.
indentation.includes(" ") && indentation.includes("\t");
Expand Down
26 changes: 26 additions & 0 deletions tests/lib/rules/indent.js
Expand Up @@ -4744,6 +4744,32 @@ ruleTester.run("indent", rule, {
</foo>
`,
options: [4, { ignoredNodes: ["JSXOpeningElement"] }]
},
{
code: unIndent`
{
\tvar x = 1,
\t y = 2;
}
`,
options: ["tab"]
},
{
code: unIndent`
var x = 1,
y = 2;
var z;
`,
options: ["tab", { ignoredNodes: ["VariableDeclarator"] }]
},
{
code: unIndent`
[
foo(),
bar
]
`,
options: ["tab", { ArrayExpression: "first", ignoredNodes: ["CallExpression"] }]
}
],

Expand Down