Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c360057

Browse files
⭐️New: Add vue/component-tags-order rule (#763)
* ⭐️New: Add `vue/component-tags-order` rule * Upgrade vue-eslint-parser@^7.0.0 * Use parserServices.getDocumentFragment
1 parent 8d7cadf commit c360057

File tree

5 files changed

+408
-0
lines changed

5 files changed

+408
-0
lines changed

‎docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ For example:
146146
| [vue/camelcase](./camelcase.md) | enforce camelcase naming convention | |
147147
| [vue/comma-dangle](./comma-dangle.md) | require or disallow trailing commas | :wrench: |
148148
| [vue/component-name-in-template-casing](./component-name-in-template-casing.md) | enforce specific casing for the component naming style in template | :wrench: |
149+
| [vue/component-tags-order](./component-tags-order.md) | enforce order of component top-level elements | |
149150
| [vue/dot-location](./dot-location.md) | enforce consistent newlines before and after dots | :wrench: |
150151
| [vue/eqeqeq](./eqeqeq.md) | require the use of `===` and `!==` | :wrench: |
151152
| [vue/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: |

‎docs/rules/component-tags-order.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
---
2+
pageClass: rule-details
3+
sidebarDepth: 0
4+
title: vue/component-tags-order
5+
description: enforce order of component top-level elements
6+
---
7+
# vue/component-tags-order
8+
> enforce order of component top-level elements
9+
10+
## :book: Rule Details
11+
12+
This rule warns about the order of the `<script>`, `<template>` & `<style>` tags.
13+
14+
## :wrench: Options
15+
16+
```json
17+
{
18+
"vue/component-tags-order": ["error", {
19+
"order": ["script", "template", "style"]
20+
}]
21+
}
22+
```
23+
24+
- `order` (`string[]`) ... The order of top-level element names. default `["script", "template", "style"]`.
25+
26+
### `{ "order": ["script", "template", "style"] }` (default)
27+
28+
<eslint-code-block :rules="{'vue/component-tags-order': ['error']}">
29+
30+
```vue
31+
<!-- ✓ GOOD -->
32+
<script>/* ... */</script>
33+
<template>...</template>
34+
<style>/* ... */</style>
35+
```
36+
37+
</eslint-code-block>
38+
39+
<eslint-code-block :rules="{'vue/component-tags-order': ['error']}">
40+
41+
```vue
42+
<!-- ✗ BAD -->
43+
<style>/* ... */</style>
44+
<script>/* ... */</script>
45+
<template>...</template>
46+
```
47+
48+
</eslint-code-block>
49+
50+
### `{ "order": ["template", "script", "style"] }`
51+
52+
<eslint-code-block :rules="{'vue/component-tags-order': ['error', { 'order': ['template', 'script', 'style'] }]}">
53+
54+
```vue
55+
<!-- ✓ GOOD -->
56+
<template>...</template>
57+
<script>/* ... */</script>
58+
<style>/* ... */</style>
59+
```
60+
61+
</eslint-code-block>
62+
63+
### `{ "order": ["docs", "template", "script", "style"] }`
64+
65+
<eslint-code-block :rules="{'vue/component-tags-order': ['error', { 'order': ['docs', 'template', 'script', 'style'] }]}">
66+
67+
```vue
68+
<!-- ✓ GOOD -->
69+
<docs> documents </docs>
70+
<template>...</template>
71+
<script>/* ... */</script>
72+
<style>/* ... */</style>
73+
```
74+
75+
</eslint-code-block>
76+
77+
<eslint-code-block :rules="{'vue/component-tags-order': ['error', { 'order': ['docs', 'template', 'script', 'style'] }]}">
78+
79+
```vue
80+
<!-- ✗ BAD -->
81+
<template>...</template>
82+
<script>/* ... */</script>
83+
<docs> documents </docs>
84+
<style>/* ... */</style>
85+
```
86+
87+
</eslint-code-block>
88+
89+
## :books: Further reading
90+
91+
- [Style guide - Single-file component top-level element order](https://vuejs.org/v2/style-guide/#Single-file-component-top-level-element-order-recommended)
92+
93+
## :mag: Implementation
94+
95+
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/component-tags-order.js)
96+
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/component-tags-order.js)

‎lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module.exports = {
1717
'comma-dangle': require('./rules/comma-dangle'),
1818
'comment-directive': require('./rules/comment-directive'),
1919
'component-name-in-template-casing': require('./rules/component-name-in-template-casing'),
20+
'component-tags-order': require('./rules/component-tags-order'),
2021
'dot-location': require('./rules/dot-location'),
2122
'eqeqeq': require('./rules/eqeqeq'),
2223
'html-closing-bracket-newline': require('./rules/html-closing-bracket-newline'),

‎lib/rules/component-tags-order.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @author Yosuke Ota
3+
* issue https://github.com/vuejs/eslint-plugin-vue/issues/140
4+
*/
5+
'use strict'
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
const utils = require('../utils')
12+
13+
const DEFAULT_ORDER = Object.freeze(['script', 'template', 'style'])
14+
15+
// ------------------------------------------------------------------------------
16+
// Rule Definition
17+
// ------------------------------------------------------------------------------
18+
19+
module.exports = {
20+
meta: {
21+
type: 'suggestion',
22+
docs: {
23+
description: 'enforce order of component top-level elements',
24+
category: undefined,
25+
url: 'https://eslint.vuejs.org/rules/component-tags-order.html'
26+
},
27+
fixable: null,
28+
schema: {
29+
type: 'array',
30+
properties: {
31+
order: {
32+
type: 'array'
33+
}
34+
}
35+
},
36+
messages: {
37+
unexpected: 'The <{{name}}> should be above the <{{firstUnorderedName}}> on line {{line}}.'
38+
}
39+
},
40+
create (context) {
41+
const order = (context.options[0] && context.options[0].order) || DEFAULT_ORDER
42+
const documentFragment = context.parserServices.getDocumentFragment && context.parserServices.getDocumentFragment()
43+
44+
function getTopLevelHTMLElements () {
45+
if (documentFragment) {
46+
return documentFragment.children
47+
}
48+
return []
49+
}
50+
51+
function report (element, firstUnorderedElement) {
52+
context.report({
53+
node: element,
54+
loc: element.loc,
55+
messageId: 'unexpected',
56+
data: {
57+
name: element.name,
58+
firstUnorderedName: firstUnorderedElement.name,
59+
line: firstUnorderedElement.loc.start.line
60+
}
61+
})
62+
}
63+
64+
return utils.defineTemplateBodyVisitor(
65+
context,
66+
{},
67+
{
68+
Program (node) {
69+
if (utils.hasInvalidEOF(node)) {
70+
return
71+
}
72+
const elements = getTopLevelHTMLElements()
73+
74+
elements.forEach((element, index) => {
75+
const expectedIndex = order.indexOf(element.name)
76+
if (expectedIndex < 0) {
77+
return
78+
}
79+
const firstUnordered = elements
80+
.slice(0, index)
81+
.filter(e => expectedIndex < order.indexOf(e.name))
82+
.sort(
83+
(e1, e2) => order.indexOf(e1.name) - order.indexOf(e2.name)
84+
)[0]
85+
if (firstUnordered) {
86+
report(element, firstUnordered)
87+
}
88+
})
89+
}
90+
}
91+
)
92+
}
93+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /