Skip to content

Commit

Permalink
fix: always wrap attributes when a multi-line attribute exists (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-8 committed Sep 29, 2023
1 parent cf695bd commit 3236fa1
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 22 deletions.
39 changes: 30 additions & 9 deletions src/rules/__snapshots__/consistent-attribute-lines.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`consistent-attribute-lines > invalid > <div
baz foo bar="2">Text</div> 1`] = `
"<div
baz
exports[`consistent-attribute-lines > invalid > <div
baz foo bar="2">Text</div> 1`] = `
"<div
baz
foo
bar=\\"2\\">Text</div>"
`;
exports[`consistent-attribute-lines > invalid > <div baz
foo
bar="2">Text</div> 1`] = `"<div baz foo bar=\\"2\\">Text</div>"`;
foo
bar="2">Text</div> 1`] = `"<div baz foo bar=\\"2\\">Text</div>"`;
exports[`consistent-attribute-lines > invalid > <div baz foo
bar="2">Text</div> 1`] = `"<div baz foo bar=\\"2\\">Text</div>"`;
exports[`consistent-attribute-lines > invalid > <div baz foo
bar="2">Text</div> 1`] = `"<div baz foo bar=\\"2\\">Text</div>"`;
exports[`consistent-attribute-lines > invalid > <div foo
bar /> 1`] = `"<div foo bar />"`;
bar /> 1`] = `"<div foo bar />"`;
exports[`consistent-attribute-lines > invalid > <div foo use:baz={{
setting: 'value',
}} /> 1`] = `
"<div
foo
use:baz={{
setting: 'value',
}} />"
`;
exports[`consistent-attribute-lines > invalid > <div foo use:baz={{
setting: 'value',
}} use:box /> 1`] = `
"<div
foo
use:baz={{
setting: 'value',
}}
use:box />"
`;
32 changes: 23 additions & 9 deletions src/rules/consistent-attribute-lines.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,40 @@ const valids: string[] = [

`<div baz foo bar="2">Text</div>`,

`<div
`<div
baz
foo
foo
bar="2">Text</div>`,

`<div
foo
use:baz={{
setting: 'value',
}} />`,
]

// See snapshot for fixed code
const invalids = [
`<div baz
foo
bar="2">Text</div>`,
foo
bar="2">Text</div>`,

`<div baz foo
bar="2">Text</div>`,
`<div baz foo
bar="2">Text</div>`,

`<div
baz foo bar="2">Text</div>`,
`<div
baz foo bar="2">Text</div>`,

`<div foo
bar />`,
bar />`,

`<div foo use:baz={{
setting: 'value',
}} />`,

`<div foo use:baz={{
setting: 'value',
}} use:box />`,
]

const ruleTester: RuleTester = new RuleTester({
Expand Down
45 changes: 41 additions & 4 deletions src/rules/consistent-attribute-lines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { AST } from 'svelte-eslint-parser'
import { createEslintRule } from '../utils'

export const RULE_NAME = 'consistent-attribute-lines'
export type MessageIds = 'attributeShouldWrap' | 'attributeShouldNotWrap'
export type MessageIds = 'attributeShouldWrap' | 'attributeShouldNotWrap' | 'wrapWhenMultiline'
export type Options = []

export default createEslintRule<Options, MessageIds>({
Expand All @@ -17,6 +17,7 @@ export default createEslintRule<Options, MessageIds>({
messages: {
attributeShouldWrap: 'Attribute should be on its own line to match the first attribute',
attributeShouldNotWrap: 'Attribute should be on the same line as the tag to match the first attribute',
wrapWhenMultiline: 'Attributes should be on their own line when a multiline attribute is present',
},
fixable: 'whitespace',
},
Expand All @@ -28,6 +29,42 @@ export default createEslintRule<Options, MessageIds>({
return

const startLine = node.loc.start.line
const hasMultilineAttr = node.attributes.some((attr) => {
const attrStartLine = attr.loc.start.line
const attrEndLine = attr.loc.end.line
return attrStartLine !== attrEndLine
})

if (hasMultilineAttr) {
node.attributes.forEach((attr, index) => {
// check if each attribute is on its own line
const prevAttr = node.attributes[index - 1]
const prevLine = prevAttr?.loc.end.line || startLine
const attrLine = attr.loc.start.line
if (prevLine !== attrLine)
return

context.report({
// @ts-expect-error - type conversion from SvelteAttribute to node not handled
node: attr,
loc: {
start: {
...attr.loc.start,
line: attr.loc.start.line - 1,
},
end: attr.loc.start,
},
messageId: 'wrapWhenMultiline',
*fix(fixer) {
const from = attr.range[0] - 1
const to = attr.range[0]
yield fixer.replaceTextRange([from, to], '\n')
},
})
})
return
}

const [firstAttr] = node.attributes
const firstAttrLine = firstAttr.loc.start.line
const isInline = startLine === firstAttrLine
Expand Down Expand Up @@ -60,10 +97,10 @@ export default createEslintRule<Options, MessageIds>({
})
}
else {
node.attributes.forEach((attr, idx) => {
if (idx === 0)
node.attributes.forEach((attr, index) => {
if (index === 0)
return
const prevAttr = node.attributes[idx - 1]
const prevAttr = node.attributes[index - 1]
const prevAttrLine = prevAttr.loc.end.line
const attrLine = attr.loc.start.line
if (prevAttrLine !== attrLine)
Expand Down

0 comments on commit 3236fa1

Please sign in to comment.