diff --git a/lib/utils/indent-common.js b/lib/utils/indent-common.js index 8ec6bbe41..5d80b83bb 100644 --- a/lib/utils/indent-common.js +++ b/lib/utils/indent-common.js @@ -1824,6 +1824,8 @@ module.exports.defineVisitor = function create( let firstToken = tokenStore.getFirstToken(node) while ( + leftToken && + rightToken && isOpeningParenToken(leftToken) && isClosingParenToken(rightToken) ) { diff --git a/lib/utils/indent-ts.js b/lib/utils/indent-ts.js index 4801ab211..9afcdb34f 100644 --- a/lib/utils/indent-ts.js +++ b/lib/utils/indent-ts.js @@ -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 @@ -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 */ @@ -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) @@ -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 - } } diff --git a/tests/fixtures/script-indent/ts-union-intersection-02.vue b/tests/fixtures/script-indent/ts-union-intersection-02.vue new file mode 100644 index 000000000..04b722218 --- /dev/null +++ b/tests/fixtures/script-indent/ts-union-intersection-02.vue @@ -0,0 +1,21 @@ + + diff --git a/tests/fixtures/script-indent/ts-union-intersection-03.vue b/tests/fixtures/script-indent/ts-union-intersection-03.vue new file mode 100644 index 000000000..78928f2e5 --- /dev/null +++ b/tests/fixtures/script-indent/ts-union-intersection-03.vue @@ -0,0 +1,19 @@ + + diff --git a/tests/fixtures/script-indent/ts-union-intersection-04.vue b/tests/fixtures/script-indent/ts-union-intersection-04.vue new file mode 100644 index 000000000..7396edc48 --- /dev/null +++ b/tests/fixtures/script-indent/ts-union-intersection-04.vue @@ -0,0 +1,17 @@ + + diff --git a/tests/fixtures/script-indent/ts-union-intersection-05.vue b/tests/fixtures/script-indent/ts-union-intersection-05.vue new file mode 100644 index 000000000..d6013535a --- /dev/null +++ b/tests/fixtures/script-indent/ts-union-intersection-05.vue @@ -0,0 +1,19 @@ + + diff --git a/tests/fixtures/script-indent/ts-union-intersection-06.vue b/tests/fixtures/script-indent/ts-union-intersection-06.vue new file mode 100644 index 000000000..a363a2847 --- /dev/null +++ b/tests/fixtures/script-indent/ts-union-intersection-06.vue @@ -0,0 +1,27 @@ + +