Skip to content

Commit

Permalink
[Fixes #293] Update indent rule (#301)
Browse files Browse the repository at this point in the history
* Update indent rule to handle properly multiline attributes lists

* Add test with errors

* Add alignAttributesVertically option

* Pass alignAttributesVertically explicitly to processNodeList

* Remove default argument value for Node 4 compatibility
  • Loading branch information
michalsnik committed Dec 31, 2017
1 parent 5c4896c commit e699f9c
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 55 deletions.
131 changes: 80 additions & 51 deletions docs/rules/html-indent.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,94 +23,123 @@ This rule enforces a consistent indentation style in `<template>`. The default s

```html
<template>
<div class="foo">
Hello.
</div>
<div class="foo">
Hello.
</div>
</template>
```

```html
<template>
<div class="foo">
Hello.
</div>
<div
id="a"
class="b"
:other-attr="{
aaa: 1,
bbb: 2
}"
@other-attr2="
foo();
bar();
"
>
{{
displayMessage
}}
</div>
<div class="foo">
Hello.
</div>
<div class="foo"
:foo="bar"
>
World.
</div>
<div
id="a"
class="b"
:other-attr="{
aaa: 1,
bbb: 2
}"
@other-attr2="
foo();
bar();
"
>
{{
displayMessage
}}
</div>
</template>
```

## :wrench: Options

```json
{
"vue/html-indent": ["error", type, {
"attribute": 1,
"closeBracket": 0,
"ignores": []
}]
"vue/html-indent": ["error", type, {
"attribute": 1,
"closeBracket": 0,
"alignAttributesVertically": true,
"ignores": []
}]
}
```

- `type` (`number | "tab"`) ... The type of indentation. Default is `2`. If this is a number, it's the number of spaces for one indent. If this is `"tab"`, it uses one tab for one indent.
- `attribute` (`integer`) ... The multiplier of indentation for attributes. Default is `1`.
- `closeBracket` (`integer`) ... The multiplier of indentation for right brackets. Default is `0`.
- `alignAttributesVertically` (`boolean`) ... Condition for whether attributes should be vertically aligned to the first attribute in multiline case or not. Default is `true`
- `ignores` (`string[]`) ... The selector to ignore nodes. The AST spec is [here](https://github.com/mysticatea/vue-eslint-parser/blob/master/docs/ast.md). You can use [esquery](https://github.com/estools/esquery#readme) to select nodes. Default is an empty array.

:+1: Examples of **correct** code for `{attribute: 1, closeBracket: 1}`:

```html
<template>
<div
id="a"
class="b"
other-attr=
"{longname: longvalue}"
other-attr2
="{longname: longvalue}"
>
Text
</div>
<div
id="a"
class="b"
other-attr=
"{longname: longvalue}"
other-attr2
="{longname: longvalue}"
>
Text
</div>
</template>
```

:+1: Examples of **correct** code for `{attribute: 2, closeBracket: 1}`:

```html
<template>
<div
id="a"
class="b"
other-attr=
"{longname: longvalue}"
other-attr2
="{longname: longvalue}"
>
Text
</div>
<div
id="a"
class="b"
other-attr=
"{longname: longvalue}"
other-attr2
="{longname: longvalue}"
>
Text
</div>
</template>
```

:+1: Examples of **correct** code for `{ignores: ["VAttribute"]}`:

```html
<template>
<div
id=""
class=""
/>
<div
id=""
class=""
/>
</template>
```

:+1: Examples of **correct** code for `{alignAttributesVertically: true}`:

```html
<template>
<div id=""
class=""
some-attr=""
/>
</template>
```

:+1: Examples of **correct** code for `{alignAttributesVertically: false}`:

```html
<template>
<div id=""
class=""
some-attr=""
/>
</template>
```
23 changes: 19 additions & 4 deletions lib/rules/html-indent.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function parseOptions (type, options) {
attribute: 1,
closeBracket: 0,
switchCase: 0,
alignAttributesVertically: true,
ignores: []
}

Expand All @@ -53,6 +54,9 @@ function parseOptions (type, options) {
if (Number.isSafeInteger(options.switchCase)) {
ret.switchCase = options.switchCase
}
if (options.alignAttributesVertically != null) {
ret.alignAttributesVertically = options.alignAttributesVertically
}
if (options.ignores != null) {
ret.ignores = options.ignores
}
Expand Down Expand Up @@ -304,8 +308,9 @@ function create (context) {
* @param {number} offset The offset to set.
* @returns {void}
*/
function processNodeList (nodeList, leftToken, rightToken, offset) {
function processNodeList (nodeList, leftToken, rightToken, offset, alignVertically) {
let t
alignVertically = alignVertically != null ? alignVertically : true

if (nodeList.length >= 1) {
let lastToken = leftToken
Expand Down Expand Up @@ -349,11 +354,20 @@ function create (context) {
setOffset(baseToken, offset, leftToken)
}

// Align the rest tokens to the first token.
// Set baseline
if (nodeList.some(isBeginningOfLine)) {
setBaseline(baseToken)
}
setOffset(alignTokens, 0, baseToken)

if (alignVertically) {
// Align the rest tokens to the first token.
setOffset(alignTokens, 0, baseToken)
} else {
// Align tokens relatively to passed root node
// So it's possible to force proper position for VAttributes
const rootNode = nodeList && nodeList[0].parent
setOffset(alignTokens, offset, template.getFirstToken(rootNode))
}
}
}

Expand Down Expand Up @@ -760,7 +774,7 @@ function create (context) {
const openToken = template.getFirstToken(node)
const closeToken = template.getLastToken(node)

processNodeList(node.attributes, openToken, null, options.attribute)
processNodeList(node.attributes, openToken, null, options.attribute, options.alignAttributesVertically)
if (closeToken != null && closeToken.type.endsWith('TagClose')) {
setOffset(closeToken, options.closeBracket, openToken)
}
Expand Down Expand Up @@ -1294,6 +1308,7 @@ module.exports = {
'attribute': { type: 'integer', minimum: 0 },
'closeBracket': { type: 'integer', minimum: 0 },
'switchCase': { type: 'integer', minimum: 0 },
'alignAttributesVertically': { type: 'boolean' },
'ignores': {
type: 'array',
items: {
Expand Down
126 changes: 126 additions & 0 deletions tests/lib/rules/html-indent.js
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,40 @@ tester.run('html-indent', rule, {
options: [4, { switchCase: 1 }]
},

// options.alignAttributesVertically
{
code: unIndent`
<template>
<div a="a"
b="b"
c=
"c"
d
="d"
e
f
=
></div>
</template>
`,
options: [2, {
alignAttributesVertically: false
}]
},
{
code: unIndent`
<template>
<div a="a"
:b="b"
c="c"
></div>
</template>
`,
options: [2, {
alignAttributesVertically: false
}]
},

// Comments
unIndent`
<template>
Expand Down Expand Up @@ -1467,6 +1501,28 @@ tester.run('html-indent', rule, {
"
/>
</template>
`,
unIndent`
<template>
<div a="a"
:b="b"
c="c"
></div>
</template>
`,
unIndent`
<template>
<div
a="a"
b="b"
></div>
</template>
`,
unIndent`
<template>
<div a="a" b="b">
</div>
</template>
`
],

Expand Down Expand Up @@ -1520,6 +1576,76 @@ tester.run('html-indent', rule, {
{ message: 'Expected indentation of 12 spaces but found 10 spaces.', line: 11 }
]
},
{
code: unIndent`
<template>
<div a="a"
b="b"
c=
"c"
>
Text
</div>
</template>
`,
output: unIndent`
<template>
<div a="a"
b="b"
c=
"c"
>
Text
</div>
</template>
`,
options: [2],
errors: [
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 2 },
{ message: 'Expected indentation of 7 spaces but found 8 spaces.', line: 3 },
{ message: 'Expected indentation of 7 spaces but found 8 spaces.', line: 4 },
{ message: 'Expected indentation of 9 spaces but found 12 spaces.', line: 5 },
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 6 },
{ message: 'Expected indentation of 4 spaces but found 8 spaces.', line: 7 },
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 8 }
]
},
{
code: unIndent`
<template>
<div a="a"
b="b"
c=
"c"
>
Text
</div>
</template>
`,
output: unIndent`
<template>
<div a="a"
b="b"
c=
"c"
>
Text
</div>
</template>
`,
options: [2, {
alignAttributesVertically: false
}],
errors: [
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 2 },
{ message: 'Expected indentation of 4 spaces but found 8 spaces.', line: 3 },
{ message: 'Expected indentation of 4 spaces but found 8 spaces.', line: 4 },
{ message: 'Expected indentation of 6 spaces but found 12 spaces.', line: 5 },
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 6 },
{ message: 'Expected indentation of 4 spaces but found 8 spaces.', line: 7 },
{ message: 'Expected indentation of 2 spaces but found 4 spaces.', line: 8 }
]
},

// VEndTag
{
Expand Down

0 comments on commit e699f9c

Please sign in to comment.