Skip to content
2 changes: 1 addition & 1 deletion docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ For example:
| [vue/no-deprecated-delete-set](./no-deprecated-delete-set.md) | disallow using deprecated `$delete` and `$set` (in Vue.js 3.0.0+) | | :warning: |
| [vue/no-deprecated-model-definition](./no-deprecated-model-definition.md) | disallow deprecated `model` definition (in Vue.js 3.0.0+) | :bulb: | :warning: |
| [vue/no-duplicate-attr-inheritance](./no-duplicate-attr-inheritance.md) | enforce `inheritAttrs` to be set to `false` when using `v-bind="$attrs"` | | :hammer: |
| [vue/no-empty-component-block](./no-empty-component-block.md) | disallow the `<template>` `<script>` `<style>` block to be empty | | :hammer: |
| [vue/no-empty-component-block](./no-empty-component-block.md) | disallow the `<template>` `<script>` `<style>` block to be empty | :wrench: | :hammer: |
| [vue/no-multiple-objects-in-class](./no-multiple-objects-in-class.md) | disallow to pass multiple objects into array to class | | :hammer: |
| [vue/no-potential-component-option-typo](./no-potential-component-option-typo.md) | disallow a potential typo in your component property | :bulb: | :hammer: |
| [vue/no-ref-object-reactivity-loss](./no-ref-object-reactivity-loss.md) | disallow usages of ref objects that can lead to loss of reactivity | | :warning: |
Expand Down
4 changes: 3 additions & 1 deletion docs/rules/no-empty-component-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ since: v7.0.0

> disallow the `<template>` `<script>` `<style>` block to be empty

- :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 disallows the `<template>` `<script>` `<style>` block to be empty.

This rule also checks block what has attribute `src`.
See [Vue Single-File Component (SFC) Spec](https://vue-loader.vuejs.org/spec.html#src-imports).

<eslint-code-block :rules="{'vue/no-empty-component-block': ['error']}">
<eslint-code-block fix :rules="{'vue/no-empty-component-block': ['error']}">

```vue
<!-- ✓ GOOD -->
Expand Down
41 changes: 39 additions & 2 deletions lib/rules/no-empty-component-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,16 @@ module.exports = {
categories: undefined,
url: 'https://eslint.vuejs.org/rules/no-empty-component-block.html'
},
fixable: null,
schema: [],
fixable: 'code',
schema: [
{
type: 'object',
properties: {
autofix: { type: 'boolean' }
},
additionalProperties: false
}
],
messages: {
unexpected: '`<{{ blockName }}>` is empty. Empty block is not allowed.'
}
Expand All @@ -66,10 +74,16 @@ module.exports = {
return {}
}

const options = context.options[0]
const autofix = options?.autofix === true

const componentBlocks = documentFragment.children.filter(isVElement)

return {
Program() {
/** @type {VElement[]} */
const emptyBlocks = []

for (const componentBlock of componentBlocks) {
if (
componentBlock.name !== 'template' &&
Expand All @@ -85,6 +99,29 @@ module.exports = {
isValueOnlyWhiteSpacesOrLineBreaks(componentBlock) ||
componentBlock.children.length === 0
) {
emptyBlocks.push(componentBlock)
}
}

if (emptyBlocks.length === 0) return

if (autofix) {
const firstEmptyBlock = emptyBlocks[0]
context.report({
node: firstEmptyBlock,
loc: firstEmptyBlock.loc,
messageId: 'unexpected',
data: {
blockName: firstEmptyBlock.name
},
*fix(fixer) {
for (const componentBlock of emptyBlocks) {
yield fixer.remove(componentBlock)
}
}
})
} else {
for (const componentBlock of emptyBlocks) {
context.report({
node: componentBlock,
loc: componentBlock.loc,
Expand Down
69 changes: 68 additions & 1 deletion tests/lib/rules/no-empty-component-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@ tester.run('no-empty-component-block', rule, {
`<template src="./template.html" /><script src="./script.js" />`,
`<template src="./template.html"></template><script src="./script.js"></script><style src="./style.css"></style>`,
`<template src="./template.html" /><script src="./script.js" /><style src="./style.css" />`,
`var a = 1`
`var a = 1`,
// options
{
code: '<template><p>foo</p></template>',
options: [{ autofix: true }]
}
],
invalid: [
{
code: `<template></template>`,
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -35,6 +41,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: `<template> </template>`,
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -44,6 +51,7 @@ tester.run('no-empty-component-block', rule, {
{
code: `<template>
</template>`,
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -52,6 +60,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -60,6 +69,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template src="" />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -68,6 +78,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template></template><script></script>',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -79,6 +90,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template /><script />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -90,6 +102,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template src="" /><script src="" />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -101,6 +114,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template></template><script></script><style></style>',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -115,6 +129,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template /><script /><style />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -129,6 +144,7 @@ tester.run('no-empty-component-block', rule, {
},
{
code: '<template src="" /><script src="" /><style src="" />',
output: null,
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
Expand All @@ -140,6 +156,57 @@ tester.run('no-empty-component-block', rule, {
message: '`<style>` is empty. Empty block is not allowed.'
}
]
},
// autofix
{
code: `<template></template>`,
output: '',
options: [{ autofix: true }],
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
}
]
},
{
code: '<template></template><script></script><style></style>',
output: '',
options: [{ autofix: true }],
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
}
]
},
{
code: '<template /><script /><style />',
output: '',
options: [{ autofix: true }],
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
}
]
},
{
code: '<template src="" /><script src="" /><style src="" />',
output: '',
options: [{ autofix: true }],
errors: [
{
message: '`<template>` is empty. Empty block is not allowed.'
}
]
},
{
code: '<template><p></p></template><script src="" /><style src="" />',
output: '<template><p></p></template>',
options: [{ autofix: true }],
errors: [
{
message: '`<script>` is empty. Empty block is not allowed.'
}
]
}
]
})
Loading