From 76aa8fcf43c610fa237743960b0350f2d9d0e198 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Mon, 4 Dec 2017 19:19:38 +0900 Subject: [PATCH] Fix: html-indent about comments (fixes #241) --- lib/rules/html-indent.js | 44 ++++++++++++--- tests/lib/rules/html-indent.js | 97 ++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 6 deletions(-) diff --git a/lib/rules/html-indent.js b/lib/rules/html-indent.js index b4a41d572..412d9779f 100644 --- a/lib/rules/html-indent.js +++ b/lib/rules/html-indent.js @@ -198,6 +198,26 @@ function isBeginningOfLine (node, index, nodes) { return false } +/** + * Check whether a given token is a closing token which triggers unindent. + * @param {Token} token The token to check. + * @returns {boolean} `true` if the token is a closing token. + */ +function isClosingToken (token) { + return token != null && ( + token.type === 'HTMLEndTagOpen' || + token.type === 'VExpressionEnd' || + ( + token.type === 'Punctuator' && + ( + token.value === ')' || + token.value === '}' || + token.value === ']' + ) + ) + ) +} + /** * Creates AST event handlers for html-indent. * @@ -504,9 +524,10 @@ function create (context) { * Validate the given token with the pre-calculated expected indentation. * @param {Token} token The token to validate. * @param {number} expectedIndent The expected indentation. + * @param {number|undefined} optionalExpectedIndent The optional expected indentation. * @returns {void} */ - function validateCore (token, expectedIndent) { + function validateCore (token, expectedIndent, optionalExpectedIndent) { const line = token.loc.start.line const actualIndent = token.loc.start.column const indentText = getIndentText(token) @@ -530,7 +551,7 @@ function create (context) { } } - if (actualIndent !== expectedIndent) { + if (actualIndent !== expectedIndent && (optionalExpectedIndent === undefined || actualIndent !== optionalExpectedIndent)) { context.report({ loc: { start: { line, column: 0 }, @@ -553,9 +574,10 @@ function create (context) { * Validate indentation of the line that the given tokens are on. * @param {Token[]} tokens The tokens on the same line to validate. * @param {Token[]} comments The comments which are on the immediately previous lines of the tokens. + * @param {Token|null} lastToken The last validated token. Comments can adjust to the token. * @returns {void} */ - function validate (tokens, comments) { + function validate (tokens, comments, lastToken) { // Calculate and save expected indentation. const firstToken = tokens[0] const actualIndent = firstToken.loc.start.column @@ -604,9 +626,17 @@ function create (context) { } } + // Calculate the expected indents for comments. + // It allows the same indent level with the previous line. + const lastOffsetInfo = offsets.get(lastToken) + const lastExpectedIndent = lastOffsetInfo && lastOffsetInfo.expectedIndent + const commentExpectedIndents = (typeof lastExpectedIndent === 'number' && isClosingToken(firstToken)) + ? { primary: lastExpectedIndent, secondary: expectedIndent } + : { primary: expectedIndent, secondary: undefined } + // Validate. for (const comment of comments) { - validateCore(comment, expectedIndent) + validateCore(comment, commentExpectedIndents.primary, commentExpectedIndents.secondary) } validateCore(firstToken, expectedIndent) } @@ -1142,6 +1172,7 @@ function create (context) { let tokensOnSameLine = [] let isBesideMultilineToken = false let first = true + let lastValidatedToken = null // Validate indentation of tokens. for (const token of template.getTokens(node, { includeComments: true, filter: isNotWhitespace })) { @@ -1168,7 +1199,8 @@ function create (context) { } } - validate(tokensOnSameLine, comments) + validate(tokensOnSameLine, comments, lastValidatedToken) + lastValidatedToken = tokensOnSameLine[0] } isBesideMultilineToken = last(tokensOnSameLine).loc.end.line === token.loc.start.line tokensOnSameLine = [token] @@ -1176,7 +1208,7 @@ function create (context) { } } if (tokensOnSameLine.length >= 1 && tokensOnSameLine.some(isNotComment)) { - validate(tokensOnSameLine, comments) + validate(tokensOnSameLine, comments, lastValidatedToken) } } })) diff --git a/tests/lib/rules/html-indent.js b/tests/lib/rules/html-indent.js index a426dbf97..4998eb1d6 100644 --- a/tests/lib/rules/html-indent.js +++ b/tests/lib/rules/html-indent.js @@ -1290,6 +1290,46 @@ tester.run('html-indent', rule, { }} `, + unIndent` + + `, + unIndent` + + `, + unIndent` + + `, + unIndent` + + `, // Ignores { @@ -4246,6 +4286,63 @@ tester.run('html-indent', rule, { { message: 'Expected indentation of 4 spaces but found 2 spaces.', line: 6 } ] }, + { + code: unIndent` + + `, + output: unIndent` + + `, + errors: [ + { message: 'Expected indentation of 2 spaces but found 0 spaces.', line: 2 }, + { message: 'Expected indentation of 4 spaces but found 0 spaces.', line: 3 }, + { message: 'Expected indentation of 4 spaces but found 0 spaces.', line: 4 }, + { message: 'Expected indentation of 4 spaces but found 0 spaces.', line: 5 }, + { message: 'Expected indentation of 2 spaces but found 0 spaces.', line: 6 } + ] + }, + { + code: unIndent` + + `, + output: unIndent` + + `, + errors: [ + { message: 'Expected indentation of 2 spaces but found 0 spaces.', line: 2 }, + { message: 'Expected indentation of 4 spaces but found 0 spaces.', line: 3 }, + { message: 'Expected indentation of 4 spaces but found 0 spaces.', line: 4 }, + { message: 'Expected indentation of 2 spaces but found 0 spaces.', line: 7 } + ] + }, // Ignores {