Skip to content

Commit

Permalink
Change the indent rule so that the union type has the same indent as …
Browse files Browse the repository at this point in the history
…the binary expression. (#1527)
  • Loading branch information
ota-meshi committed Jul 2, 2021
1 parent 49d34c9 commit 5d1f772
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 17 deletions.
2 changes: 2 additions & 0 deletions lib/utils/indent-common.js
Expand Up @@ -1824,6 +1824,8 @@ module.exports.defineVisitor = function create(
let firstToken = tokenStore.getFirstToken(node)

while (
leftToken &&
rightToken &&
isOpeningParenToken(leftToken) &&
isClosingParenToken(rightToken)
) {
Expand Down
87 changes: 70 additions & 17 deletions lib/utils/indent-ts.js
Expand Up @@ -19,6 +19,7 @@ const {
* @typedef { { type: string } & HasLocation } MaybeNode
*/
/**
* @typedef {import('@typescript-eslint/types').TSESTree.Node} TSESTreeNode
* @typedef {import('@typescript-eslint/types').TSESTree.ClassExpression} ClassExpression
* @typedef {import('@typescript-eslint/types').TSESTree.ClassDeclaration} ClassDeclaration
* @typedef {import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} TSTypeAliasDeclaration
Expand Down Expand Up @@ -125,6 +126,48 @@ function defineVisitor({
processSemicolons,
getFirstAndLastTokens
}) {
/**
* Check whether a given token is the first token of:
*
* - A parameter of TSTypeParameterInstantiation
* - An element of TSTupleType
*
* @param {Token} token The token to check.
* @param {TSUnionType | TSIntersectionType} belongingNode The node that the token is belonging to.
* @returns {boolean} `true` if the token is the first token of an element.
*/
function isBeginningOfElement(token, belongingNode) {
/** @type {TSESTreeNode | null} */
let node = belongingNode

while (node != null && node.parent != null) {
/** @type {TSESTreeNode} */
const parent = node.parent
if (parent.type === 'TSTypeParameterInstantiation') {
return (
parent.params.length >= 2 &&
parent.params.some(
(param) =>
getFirstAndLastTokens(param).firstToken.range[0] ===
token.range[0]
)
)
}
if (parent.type === 'TSTupleType') {
return parent.elementTypes.some(
(element) =>
element != null &&
getFirstAndLastTokens(element).firstToken.range[0] ===
token.range[0]
)
}

node = parent
}

return false
}

return {
// Support TypeScript
/** @param {ClassDeclaration | ClassExpression} node */
Expand Down Expand Up @@ -463,16 +506,34 @@ function defineVisitor({
// A | B
// A & B
const firstToken = tokenStore.getFirstToken(node)
const types = [...node.types]
if (getFirstAndLastTokens(types[0]).firstToken === firstToken) {
types.shift()

const prevToken = tokenStore.getTokenBefore(firstToken)
const shouldIndent =
prevToken == null ||
prevToken.loc.end.line === firstToken.loc.start.line ||
isBeginningOfElement(firstToken, node)
const offset = shouldIndent ? 1 : 0

const typeTokensList = node.types.map(getFirstAndLastTokens)
const typeTokens = typeTokensList.shift()
if (!typeTokens) {
return
}
let lastToken
if (typeTokens.firstToken === firstToken) {
lastToken = typeTokens.lastToken
} else {
typeTokensList.unshift(typeTokens)
lastToken = firstToken
}
for (const typeTokens of typeTokensList) {
setOffset(
tokenStore.getTokensBetween(lastToken, typeTokens.firstToken),
offset,
firstToken
)
setOffset(typeTokens.firstToken, offset, firstToken)
}
processNodeList(
types,
firstToken,
null,
isBeginningOfLine(firstToken) ? 0 : 1
)
},
TSParenthesizedType(node) {
// (T)
Expand Down Expand Up @@ -1253,12 +1314,4 @@ function defineVisitor({
// ----------------------------------------------------------------------
TSLiteralType() {}
}
/**
* Check whether the given node or token is the beginning of a line.
* @param {MaybeNode} node
*/
function isBeginningOfLine(node) {
const prevToken = tokenStore.getTokenBefore(node, { includeComments: true })
return !prevToken || prevToken.loc.end.line < node.loc.start.line
}
}
21 changes: 21 additions & 0 deletions tests/fixtures/script-indent/ts-union-intersection-02.vue
@@ -0,0 +1,21 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script lang="ts">
type T =
a
| b
type U =
| a
| b
type V =
a
& b
type W =
& a
& b
type X =
&
(
a
| b
)
</script>
19 changes: 19 additions & 0 deletions tests/fixtures/script-indent/ts-union-intersection-03.vue
@@ -0,0 +1,19 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script lang="ts">
type T = a
| b
| c
type U = | a
| b
| c
type V = a
|
b
|
c
const a = a
|
b
|
c
</script>
17 changes: 17 additions & 0 deletions tests/fixtures/script-indent/ts-union-intersection-04.vue
@@ -0,0 +1,17 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script lang="ts">
type T = U< a
| b
| c
>
type T = U<
| a
| b
| c
>
type T = U<
& a
& b
& c
>
</script>
19 changes: 19 additions & 0 deletions tests/fixtures/script-indent/ts-union-intersection-05.vue
@@ -0,0 +1,19 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script lang="ts">
type T = U<
a
| b
| c,
a
| b
| c
>
type T = U<
a
& b
& c,
a
& b
& c
>
</script>
27 changes: 27 additions & 0 deletions tests/fixtures/script-indent/ts-union-intersection-06.vue
@@ -0,0 +1,27 @@
<!--{"parserOptions": {"parser":"@typescript-eslint/parser"}}-->
<script lang="ts">
type T = [
a
| b
| c
]
type U = [
| a
| b
| c
]
type T2 = [ a
| b
| c,
a
| b
| c
]
type U2 = [ | a
| b
| c,
| a
| b
| c
]
</script>

0 comments on commit 5d1f772

Please sign in to comment.