-
-
Notifications
You must be signed in to change notification settings - Fork 681
Create padding-line-between-tags
rule
#1966
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 27 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
2ba27ac
Create space-between-siblings rule
dev1437 b530e82
Fix lint
dev1437 36b4c2d
Change how options are initialised
dev1437 3567a1b
Fill in name
dev1437 2469a38
Remove block
dev1437 a597c4c
Update test
dev1437 aa94054
Tidy up test and examples
dev1437 dcc83e2
Change message
dev1437 07252a0
Add test for flat tag
dev1437 bb6f4f2
Add never functionality
dev1437 abbae10
Add tests for never and update previous tests for new schema
dev1437 4589a3d
Linting
dev1437 52fbe43
Update docs
dev1437 d417713
Rename to padding-line-between-tags
dev1437 74abc89
Change schema to array of objects
dev1437 84f793c
Change messages
dev1437 fb1899a
Allow for blank lines to be specified on each tag
dev1437 acbf506
Update tests
dev1437 4f84411
Linting
dev1437 adc23c0
Update docs
dev1437 3b885b0
Add another test
dev1437 a04b8a3
Lint
dev1437 6b0620d
Clean up doc
dev1437 e210bc9
Clean up tests
dev1437 95c563a
Change type
dev1437 9c57ee5
Fix doc
dev1437 bd9c128
Update docs/rules/padding-line-between-tags.md
dev1437 38fccaa
Ignore top level
dev1437 d17ec54
Remove testing stuff
dev1437 cfa916f
Simplify logic and make last configuration apply
dev1437 e152ceb
Add test for last configuration applying
dev1437 40be55c
Update docs
dev1437 b5fd572
Add newlines between siblings on same line
dev1437 e6094bd
Update docs
dev1437 8f9fb7f
Merge branch 'rule/space-between-siblings' of github.com:dev1437/esli…
dev1437 261ed4d
Lint
dev1437 5688564
Fix doc
dev1437 1c621c4
Fix spaces on line diff = 0
dev1437 a3f314f
Remove only space between tags
dev1437 b94e599
Append text backwards
dev1437 8bbbeed
Uncomment tests
dev1437 93ea378
Linting
dev1437 19d365b
Fix loop and add test
dev1437 b05e3ea
Add another test
dev1437 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
--- | ||
pageClass: rule-details | ||
sidebarDepth: 0 | ||
title: vue/padding-line-between-tags | ||
description: Require or disallow newlines between sibling tags in template | ||
--- | ||
# vue/padding-line-between-tags | ||
|
||
> Require or disallow newlines between sibling tags in template | ||
|
||
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge> | ||
- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. | ||
|
||
## :book: Rule Details | ||
|
||
This rule requires or disallows newlines between sibling HTML tags. | ||
|
||
<eslint-code-block fix :rules="{'vue/padding-line-between-tags': ['error']}"> | ||
|
||
```vue | ||
<template> | ||
<div> | ||
<!-- ✓ GOOD: --> | ||
<div></div> | ||
|
||
<div> | ||
</div> | ||
|
||
<div /> | ||
<!-- ✗ BAD: --> | ||
<div></div> | ||
<div> | ||
</div> | ||
<div /> | ||
</div> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
## :wrench: Options | ||
|
||
```json | ||
{ | ||
"vue/padding-line-between-tags": ["error", [ | ||
{ "blankLine": "always", "prev": "*", "next": "*" } | ||
]] | ||
} | ||
``` | ||
|
||
This rule requires blank lines between each sibling HTML tag by default. | ||
|
||
A configuration is an object which has 3 properties; blankLine, prev and next. For example, { blankLine: "always", prev: "br", next: "div" } means “one or more blank lines are required between a br tag and a div tag.” You can supply any number of configurations. | ||
ota-meshi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- `blankLine` is one of the following: | ||
- `always` requires one or more blank lines. | ||
- `never` disallows blank lines. | ||
- `prev` any tag name without brackets. | ||
- `next` any tag name without brackets. | ||
|
||
### Disallow blank lines between all tags | ||
|
||
`{ blankLine: 'never', prev: '*', next: '*' }` | ||
|
||
<eslint-code-block fix :rules="{'vue/padding-line-between-tags': ['error', [ | ||
{ blankLine: 'never', prev: '*', next: '*' } | ||
]]}"> | ||
|
||
```vue | ||
<template> | ||
<div> | ||
<div></div> | ||
<div> | ||
</div> | ||
<div /> | ||
</div> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
### Require newlines after `<br>` | ||
|
||
`{ blankLine: 'always', prev: 'br', next: '*' }` | ||
|
||
<eslint-code-block fix :rules="{'vue/padding-line-between-tags': ['error', [ | ||
{ blankLine: 'always', prev: 'br', next: '*' } | ||
]]}"> | ||
|
||
```vue | ||
<template> | ||
<div> | ||
<ul> | ||
<li> | ||
</li> | ||
<br /> | ||
|
||
<li> | ||
</li> | ||
</ul> | ||
</div> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
### Require newlines before `<br>` | ||
|
||
`{ blankLine: 'always', prev: '*', next: 'br' }` | ||
|
||
<eslint-code-block fix :rules="{'vue/padding-line-between-tags': ['error', [ | ||
{ blankLine: 'always', prev: '*', next: 'br' } | ||
]]}"> | ||
|
||
```vue | ||
<template> | ||
<div> | ||
<ul> | ||
<li> | ||
</li> | ||
|
||
<br /> | ||
<li> | ||
</li> | ||
</ul> | ||
</div> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
### Require newlines between `<br>` and `<img>` | ||
|
||
`{ blankLine: 'always', prev: 'br', next: 'img' }` | ||
|
||
<eslint-code-block fix :rules="{'vue/padding-line-between-tags': ['error', [ | ||
{ blankLine: 'always', prev: 'br', next: 'img' } | ||
]]}"> | ||
|
||
```vue | ||
<template> | ||
<div> | ||
<ul> | ||
<li> | ||
</li> | ||
<br /> | ||
|
||
<img /> | ||
<li> | ||
</li> | ||
</ul> | ||
</div> | ||
</template> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
## :mag: Implementation | ||
|
||
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/padding-line-between-tags.js) | ||
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/padding-line-between-tags.js) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
/** | ||
* @author dev1437 | ||
* See LICENSE file in root directory for full license. | ||
*/ | ||
'use strict' | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Requirements | ||
// ------------------------------------------------------------------------------ | ||
|
||
const utils = require('../utils') | ||
|
||
/** | ||
* Split the source code into multiple lines based on the line delimiters. | ||
* Copied from padding-line-between-blocks | ||
* @param {string} text Source code as a string. | ||
* @returns {string[]} Array of source code lines. | ||
*/ | ||
function splitLines(text) { | ||
return text.split(/\r\n|[\r\n\u2028\u2029]/gu) | ||
} | ||
|
||
/** | ||
* @param {RuleContext} context | ||
* @param {VElement} tag | ||
* @param {VElement} sibling | ||
*/ | ||
function insertNewLine(context, tag, sibling) { | ||
context.report({ | ||
messageId: 'always', | ||
loc: sibling.loc, | ||
// @ts-ignore | ||
fix(fixer) { | ||
return fixer.insertTextAfter(tag, '\n') | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* @param {RuleContext} context | ||
* @param {VEndTag | VStartTag} endTag | ||
* @param {VElement} sibling | ||
*/ | ||
function removeExcessLines(context, endTag, sibling) { | ||
context.report({ | ||
messageId: 'never', | ||
loc: sibling.loc, | ||
// @ts-ignore | ||
fix(fixer) { | ||
const start = endTag.range[1] | ||
const end = sibling.range[0] | ||
const paddingText = context.getSourceCode().text.slice(start, end) | ||
const lastSpaces = splitLines(paddingText).pop() | ||
return fixer.replaceTextRange([start, end], `\n${lastSpaces}`) | ||
dev1437 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}) | ||
} | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
/** | ||
* @param {RuleContext} context | ||
*/ | ||
function checkNewline(context) { | ||
/** @type {Array<{blankLine: "always" | "never", prev: string, next: string}>} */ | ||
const options = context.options[0] || [ | ||
{ blankLine: 'always', prev: '*', next: '*' } | ||
] | ||
|
||
/** @type {Map<string, string[]>} */ | ||
const alwaysBlankLine = new Map() | ||
/** @type {Map<string, string[]>} */ | ||
const neverBlankLine = new Map() | ||
|
||
for (const option of options) { | ||
if (option.blankLine === 'always') { | ||
const tagValue = alwaysBlankLine.get(option.prev) | ||
if (tagValue) { | ||
alwaysBlankLine.set(option.prev, [...tagValue, option.next]) | ||
} else { | ||
alwaysBlankLine.set(option.prev, [option.next]) | ||
} | ||
} else { | ||
const tagValue = neverBlankLine.get(option.prev) | ||
if (tagValue) { | ||
neverBlankLine.set(option.prev, [...tagValue, option.next]) | ||
} else { | ||
neverBlankLine.set(option.prev, [option.next]) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @param {VElement} block | ||
*/ | ||
return (block) => { | ||
const endTag = block.endTag || block.startTag | ||
const lowerSiblings = block.parent.children | ||
.filter( | ||
(element) => | ||
element.type === 'VElement' && element.range !== block.range | ||
) | ||
.filter((sibling) => sibling.range[0] - endTag.range[1] > 0) | ||
|
||
if (lowerSiblings.length === 0) { | ||
return | ||
} | ||
|
||
const closestSibling = lowerSiblings[0] | ||
|
||
const element = /** @type {VElement} */ (closestSibling) | ||
const lineDifference = element.loc.start.line - endTag.loc.end.line | ||
|
||
if ( | ||
neverBlankLine.has('*') && | ||
// @ts-ignore | ||
(neverBlankLine.get('*').includes('*') || | ||
// @ts-ignore | ||
neverBlankLine.get('*').includes(element.name)) | ||
) { | ||
if ( | ||
alwaysBlankLine.has(block.name) && | ||
// @ts-ignore | ||
(alwaysBlankLine.get(block.name).includes('*') || | ||
// @ts-ignore | ||
alwaysBlankLine.get(block.name).includes(element.name)) | ||
) { | ||
if (lineDifference === 1) { | ||
insertNewLine(context, block, element) | ||
} | ||
} else if (lineDifference > 1) { | ||
removeExcessLines(context, endTag, element) | ||
} | ||
} else if ( | ||
alwaysBlankLine.has('*') && | ||
// @ts-ignore | ||
(alwaysBlankLine.get('*').includes('*') || | ||
// @ts-ignore | ||
alwaysBlankLine.get('*').includes(element.name)) | ||
) { | ||
if ( | ||
neverBlankLine.has(block.name) && | ||
// @ts-ignore | ||
(neverBlankLine.get(block.name).includes('*') || | ||
// @ts-ignore | ||
neverBlankLine.get(block.name).includes(element.name)) | ||
) { | ||
if (lineDifference > 1) { | ||
removeExcessLines(context, endTag, element) | ||
} | ||
} else if (lineDifference === 1) { | ||
insertNewLine(context, block, element) | ||
} | ||
} else { | ||
if ( | ||
neverBlankLine.has(block.name) && | ||
// @ts-ignore | ||
(neverBlankLine.get(block.name).includes('*') || | ||
// @ts-ignore | ||
neverBlankLine.get(block.name).includes(element.name)) | ||
) { | ||
if (lineDifference > 1) { | ||
removeExcessLines(context, endTag, element) | ||
} | ||
} else if ( | ||
alwaysBlankLine.has(block.name) && | ||
// @ts-ignore | ||
(alwaysBlankLine.get(block.name).includes('*') || | ||
// @ts-ignore | ||
alwaysBlankLine.get(block.name).includes(element.name)) && | ||
lineDifference === 1 | ||
) { | ||
insertNewLine(context, block, element) | ||
} | ||
} | ||
} | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
type: 'layout', | ||
docs: { | ||
description: | ||
'require or disallow newlines between sibling tags in template', | ||
categories: undefined, | ||
url: 'https://eslint.vuejs.org/rules/padding-line-between-tags.html' | ||
}, | ||
fixable: 'whitespace', | ||
schema: [ | ||
{ | ||
type: 'array', | ||
items: { | ||
type: 'object', | ||
properties: { | ||
blankLine: { enum: ['always', 'never'] }, | ||
prev: { type: 'string' }, | ||
next: { type: 'string' } | ||
}, | ||
additionalProperties: false, | ||
required: ['blankLine', 'prev', 'next'] | ||
} | ||
} | ||
], | ||
messages: { | ||
never: 'Unexpected blank line before this tag.', | ||
always: 'Expected blank line before this tag.' | ||
} | ||
}, | ||
/** @param {RuleContext} context */ | ||
create(context) { | ||
return utils.defineTemplateBodyVisitor(context, { | ||
VElement: checkNewline(context) | ||
}) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.