Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 925190f

Browse files
mysticateamichalsnik
authored andcommitted
Fix: improve comment indentation (fixes #514) (#676)
* Fix: improve comment indentation (fixes #514) * πŸ“ fix JSDoc comment
1 parent c6bbd95 commit 925190f

File tree

2 files changed

+79
-37
lines changed

2 files changed

+79
-37
lines changed

β€Žlib/utils/indent-common.js

Lines changed: 71 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const KNOWN_NODES = new Set(['ArrayExpression', 'ArrayPattern', 'ArrowFunctionEx
1818
const LT_CHAR = /[\r\n\u2028\u2029]/
1919
const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
2020
const BLOCK_COMMENT_PREFIX = /^\s*\*/
21+
const ITERATION_OPTS = Object.freeze({ includeComments: true, filter: isNotWhitespace })
2122

2223
/**
2324
* Normalize options.
@@ -194,6 +195,15 @@ function isNotComment (token) {
194195
return token != null && token.type !== 'Block' && token.type !== 'Line' && token.type !== 'Shebang' && !token.type.endsWith('Comment')
195196
}
196197

198+
/**
199+
* Check whether the given node is not an empty text node.
200+
* @param {Node} node The node to check.
201+
* @returns {boolean} `false` if the token is empty text node.
202+
*/
203+
function isNotEmptyTextNode (node) {
204+
return !(node.type === 'VText' && node.value.trim() === '')
205+
}
206+
197207
/**
198208
* Get the last element.
199209
* @param {Array} xs The array to get the last element.
@@ -295,7 +305,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
295305
* @param {Token} token The token to set.
296306
* @returns {void}
297307
*/
298-
function setBaseline (token,hardTabAdditional) {
308+
function setBaseline (token) {
299309
const offsetInfo = offsets.get(token)
300310
if (offsetInfo != null) {
301311
offsetInfo.baseline = true
@@ -353,17 +363,21 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
353363
* The first node is offsetted from the given left token.
354364
* Rest nodes are adjusted to the first node.
355365
* @param {Node[]} nodeList The node to process.
356-
* @param {Node|null} leftToken The left parenthesis token.
357-
* @param {Node|null} rightToken The right parenthesis token.
366+
* @param {Node|Token|null} left The left parenthesis token.
367+
* @param {Node|Token|null} right The right parenthesis token.
358368
* @param {number} offset The offset to set.
359-
* @param {Node} [alignVertically=true] The flag to align vertically. If `false`, this doesn't align vertically even if the first node is not at beginning of line.
369+
* @param {boolean} [alignVertically=true] The flag to align vertically. If `false`, this doesn't align vertically even if the first node is not at beginning of line.
360370
* @returns {void}
361371
*/
362-
function processNodeList (nodeList, leftToken,rightToken, offset, alignVertically) {
372+
function processNodeList (nodeList, left,right, offset, alignVertically) {
363373
let t
374+
const leftToken = (left && tokenStore.getFirstToken(left)) || left
375+
const rightToken = (right && tokenStore.getFirstToken(right)) || right
364376

365377
if (nodeList.length >= 1) {
366-
let lastToken = leftToken
378+
let baseToken = null
379+
let lastToken = left
380+
const alignTokensBeforeBaseToken = []
367381
const alignTokens = []
368382

369383
for (let i = 0; i < nodeList.length; ++i) {
@@ -374,30 +388,50 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
374388
}
375389
const elementTokens = getFirstAndLastTokens(node, lastToken != null ? lastToken.range[1] : 0)
376390

377-
// Collect related tokens.
378-
// Commas between this and the previous, and the first token of this node.
391+
// Collect comma/comment tokens between the last token of the previous node and the first token of this node.
379392
if (lastToken != null) {
380393
t = lastToken
381-
while ((t = tokenStore.getTokenAfter(t)) != null && t.range[1] <= elementTokens.firstToken.range[0]) {
382-
alignTokens.push(t)
394+
while (
395+
(t = tokenStore.getTokenAfter(t, ITERATION_OPTS)) != null &&
396+
t.range[1] <= elementTokens.firstToken.range[0]
397+
) {
398+
if (baseToken == null) {
399+
alignTokensBeforeBaseToken.push(t)
400+
} else {
401+
alignTokens.push(t)
402+
}
383403
}
384404
}
385-
alignTokens.push(elementTokens.firstToken)
386405

387-
// Save the last token to find tokens between the next token.
406+
if (baseToken == null) {
407+
baseToken = elementTokens.firstToken
408+
} else {
409+
alignTokens.push(elementTokens.firstToken)
410+
}
411+
412+
// Save the last token to find tokens between this node and the next node.
388413
lastToken = elementTokens.lastToken
389414
}
390415

391-
// Check trailing commas.
416+
// Check trailing commas and comments.
392417
if (rightToken != null && lastToken != null) {
393418
t = lastToken
394-
while ((t = tokenStore.getTokenAfter(t)) != null && t.range[1] <= rightToken.range[0]) {
395-
alignTokens.push(t)
419+
while (
420+
(t = tokenStore.getTokenAfter(t, ITERATION_OPTS)) != null &&
421+
t.range[1] <= rightToken.range[0]
422+
) {
423+
if (baseToken == null) {
424+
alignTokensBeforeBaseToken.push(t)
425+
} else {
426+
alignTokens.push(t)
427+
}
396428
}
397429
}
398430

399431
// Set offsets.
400-
const baseToken = alignTokens.shift()
432+
if (leftToken != null) {
433+
setOffset(alignTokensBeforeBaseToken, offset, leftToken)
434+
}
401435
if (baseToken != null) {
402436
// Set offset to the first token.
403437
if (leftToken != null) {
@@ -409,7 +443,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
409443
setBaseline(baseToken)
410444
}
411445

412-
if (alignVertically === false) {
446+
if (alignVertically === false&&leftToken!=null) {
413447
// Align tokens relatively to the left token.
414448
setOffset(alignTokens, offset, leftToken)
415449
} else {
@@ -657,10 +691,10 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
657691
* Validate the given token with the pre-calculated expected indentation.
658692
* @param {Token} token The token to validate.
659693
* @param {number} expectedIndent The expected indentation.
660-
* @param {number|undefined} optionalExpectedIndent The optional expected indentation.
694+
* @param {number[]|undefined} optionalExpectedIndents The optional expected indentation.
661695
* @returns {void}
662696
*/
663-
function validateCore (token, expectedIndent, optionalExpectedIndent) {
697+
function validateCore (token, expectedIndent, optionalExpectedIndents) {
664698
const line = token.loc.start.line
665699
const indentText = getIndentText(token)
666700

@@ -692,7 +726,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
692726
}
693727
}
694728

695-
if (actualIndent !== expectedIndent && (optionalExpectedIndent ===undefined || actualIndent!==optionalExpectedIndent)) {
729+
if (actualIndent !== expectedIndent && (optionalExpectedIndents ==null || !optionalExpectedIndents.includes(actualIndent))) {
696730
context.report({
697731
loc: {
698732
start: { line, column: 0 },
@@ -716,7 +750,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
716750
* @param {Token|null} nextToken The next token of comments.
717751
* @param {number|undefined} nextExpectedIndent The expected indent of the next token.
718752
* @param {number|undefined} lastExpectedIndent The expected indent of the last token.
719-
* @returns {{primary:number|undefined,secondary:number|undefined}}
753+
* @returns {number[]}
720754
*/
721755
function getCommentExpectedIndents (nextToken, nextExpectedIndent, lastExpectedIndent) {
722756
if (typeof lastExpectedIndent === 'number' && isClosingToken(nextToken)) {
@@ -725,26 +759,23 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
725759
// <div>
726760
// <!-- comment -->
727761
// </div>
728-
return {
729-
primary: nextExpectedIndent + options.indentSize,
730-
secondary: undefined
731-
}
762+
return [nextExpectedIndent + options.indentSize, nextExpectedIndent]
732763
}
733764

734765
// For last comment. E.g.,
735766
// <div>
736767
// <div></div>
737768
// <!-- comment -->
738769
// </div>
739-
return {primary: lastExpectedIndent, secondary: nextExpectedIndent}
770+
return [lastExpectedIndent, nextExpectedIndent]
740771
}
741772

742773
// Adjust to next normally. E.g.,
743774
// <div>
744775
// <!-- comment -->
745776
// <div></div>
746777
// </div>
747-
return {primary: nextExpectedIndent,secondary: undefined}
778+
return [nextExpectedIndent]
748779
}
749780

750781
/**
@@ -815,11 +846,17 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
815846
// It allows the same indent level with the previous line.
816847
const lastOffsetInfo = offsets.get(lastToken)
817848
const lastExpectedIndent = lastOffsetInfo && lastOffsetInfo.expectedIndent
818-
const commentExpectedIndents = getCommentExpectedIndents(firstToken, expectedIndent, lastExpectedIndent)
849+
const commentOptionalExpectedIndents = getCommentExpectedIndents(firstToken, expectedIndent, lastExpectedIndent)
819850

820851
// Validate.
821852
for (const comment of comments) {
822-
validateCore(comment, commentExpectedIndents.primary, commentExpectedIndents.secondary)
853+
const commentExpectedIndents = getExpectedIndents([comment])
854+
const commentExpectedIndent =
855+
commentExpectedIndents
856+
? commentExpectedIndents.expectedIndent
857+
: commentOptionalExpectedIndents[0]
858+
859+
validateCore(comment, commentExpectedIndent, commentOptionalExpectedIndents)
823860
}
824861
validateCore(firstToken, expectedIndent)
825862
}
@@ -844,16 +881,14 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
844881
},
845882

846883
VElement (node) {
847-
const startTagToken = tokenStore.getFirstToken(node)
848-
const endTagToken = node.endTag && tokenStore.getFirstToken(node.endTag)
849-
850884
if (node.name !== 'pre') {
851-
const childTokens = node.children.map(n => tokenStore.getFirstToken(n))
852-
setOffset(childTokens, 1, startTagToken)
885+
processNodeList(node.children.filter(isNotEmptyTextNode), node.startTag, node.endTag, 1)
853886
} else {
887+
const startTagToken = tokenStore.getFirstToken(node)
888+
const endTagToken = node.endTag && tokenStore.getFirstToken(node.endTag)
889+
setOffset(endTagToken, 0, startTagToken)
854890
setPreformattedTokens(node)
855891
}
856-
setOffset(endTagToken, 0, startTagToken)
857892
},
858893

859894
VEndTag (node) {
@@ -1116,7 +1151,6 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
11161151

11171152
setOffset(leftParenToken, 1, forToken)
11181153
processNodeList([node.init, node.test, node.update], leftParenToken, rightParenToken, 1)
1119-
setOffset(rightParenToken, 0, leftParenToken)
11201154
processMaybeBlock(node.body, forToken)
11211155
},
11221156

@@ -1544,7 +1578,7 @@ module.exports.defineVisitor = function create (context, tokenStore, defaultOpti
15441578
let lastValidatedToken = null
15451579

15461580
// Validate indentation of tokens.
1547-
for (const token of tokenStore.getTokens(node, {includeComments: true,filter: isNotWhitespace})) {
1581+
for (const token of tokenStore.getTokens(node, ITERATION_OPTS)) {
15481582
if (tokensOnSameLine.length === 0 || tokensOnSameLine[0].loc.start.line === token.loc.start.line) {
15491583
// This is on the same line (or the first token).
15501584
tokensOnSameLine.push(token)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!--{}-->
2+
<template>
3+
<div>
4+
<input type="text"
5+
value="foo">
6+
<!-- comment -->
7+
</div>
8+
</template>

0 commit comments

Comments
(0)

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /