Skip to content
Merged
1 change: 1 addition & 0 deletions docs/rules/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Rules in this category are enabled for all presets provided by eslint-plugin-vue
| [vue/no-watch-after-await](./no-watch-after-await.md) | disallow asynchronously registered `watch` | | :three::hammer: |
| [vue/prefer-import-from-vue](./prefer-import-from-vue.md) | enforce import from 'vue' instead of import from '@vue/*' | :wrench: | :three::hammer: |
| [vue/require-component-is](./require-component-is.md) | require `v-bind:is` of `<component>` elements | | :three::two::warning: |
| [vue/require-default-export](./require-default-export.md) | require default export | | :three::two::warning: |
| [vue/require-prop-type-constructor](./require-prop-type-constructor.md) | require prop type to be a constructor | :wrench: | :three::two::hammer: |
| [vue/require-render-return](./require-render-return.md) | enforce render function to always return value | | :three::two::warning: |
| [vue/require-slots-as-functions](./require-slots-as-functions.md) | enforce properties of `$slots` to be used as a function | | :three::warning: |
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/object-curly-newline.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ This rule was introduced in eslint-plugin-vue v7.0.0
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/object-curly-newline.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/object-curly-newline.js)

<sup>Taken with ❤️ [from ESLint Stylistic](https://eslint.style/rules/js/object-curly-newline)</sup>
<sup>Taken with ❤️ [from ESLint Stylistic](https://eslint.style/rules/ts/object-curly-newline)</sup>
2 changes: 1 addition & 1 deletion docs/rules/object-property-newline.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ This rule was introduced in eslint-plugin-vue v7.0.0
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/object-property-newline.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/object-property-newline.js)

<sup>Taken with ❤️ [from ESLint Stylistic](https://eslint.style/rules/js/object-property-newline)</sup>
<sup>Taken with ❤️ [from ESLint Stylistic](https://eslint.style/rules/ts/object-property-newline)</sup>
54 changes: 54 additions & 0 deletions docs/rules/require-default-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
pageClass: rule-details
sidebarDepth: 0
title: vue/require-default-export
description: require default export
---

# vue/require-default-export

> require default export

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> _**This rule has not been released yet.**_ </badge>
- :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `*.configs["flat/essential"]`, `"plugin:vue/essential"`, `*.configs["flat/vue2-essential"]`, `"plugin:vue/vue3-strongly-recommended"`, `*.configs["flat/strongly-recommended"]`, `"plugin:vue/strongly-recommended"`, `*.configs["flat/vue2-strongly-recommended"]`, `"plugin:vue/vue3-recommended"`, `*.configs["flat/recommended"]`, `"plugin:vue/recommended"` and `*.configs["flat/vue2-recommended"]`.

## :book: Rule Details

This rule reports when a Vue component does not have a default export, if the component is not defined as `<script setup>`.

<eslint-code-block :rules="{'vue/require-default-export': ['error']}">

```vue
<!-- ✗ BAD -->
<script>
const foo = 'foo';
</script>
```

</eslint-code-block>

<eslint-code-block :rules="{'vue/require-default-export': ['error']}">

```vue
<!-- ✓ GOOD -->
<script>
export default {
data() {
return {
foo: 'foo'
};
}
};
</script>
```

</eslint-code-block>

## :wrench: Options

Nothing.

## :mag: Implementation

- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-default-export.js)
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-default-export.js)
1 change: 1 addition & 0 deletions lib/configs/flat/vue2-essential.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module.exports = [
'vue/no-v-model-argument': 'error',
'vue/no-v-text-v-html-on-component': 'error',
'vue/require-component-is': 'error',
'vue/require-default-export': 'error',
'vue/require-prop-type-constructor': 'error',
'vue/require-render-return': 'error',
'vue/require-v-for-key': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/configs/flat/vue3-essential.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ module.exports = [
'vue/no-watch-after-await': 'error',
'vue/prefer-import-from-vue': 'error',
'vue/require-component-is': 'error',
'vue/require-default-export': 'error',
'vue/require-prop-type-constructor': 'error',
'vue/require-render-return': 'error',
'vue/require-slots-as-functions': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/configs/vue2-essential.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module.exports = {
'vue/no-v-model-argument': 'error',
'vue/no-v-text-v-html-on-component': 'error',
'vue/require-component-is': 'error',
'vue/require-default-export': 'error',
'vue/require-prop-type-constructor': 'error',
'vue/require-render-return': 'error',
'vue/require-v-for-key': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/configs/vue3-essential.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module.exports = {
'vue/no-watch-after-await': 'error',
'vue/prefer-import-from-vue': 'error',
'vue/require-component-is': 'error',
'vue/require-default-export': 'error',
'vue/require-prop-type-constructor': 'error',
'vue/require-render-return': 'error',
'vue/require-slots-as-functions': 'error',
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ const plugin = {
'prop-name-casing': require('./rules/prop-name-casing'),
'quote-props': require('./rules/quote-props'),
'require-component-is': require('./rules/require-component-is'),
'require-default-export': require('./rules/require-default-export'),
'require-default-prop': require('./rules/require-default-prop'),
'require-direct-export': require('./rules/require-direct-export'),
'require-emit-validator': require('./rules/require-emit-validator'),
Expand Down
58 changes: 58 additions & 0 deletions lib/rules/require-default-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @author ItMaga
* See LICENSE file in root directory for full license.
*/
'use strict'

const utils = require('../utils')

module.exports = {
meta: {
type: 'problem',
docs: {
description: 'require default export',
categories: ['vue3-essential', 'vue2-essential'],
url: 'https://eslint.vuejs.org/rules/require-default-export.html'
},
fixable: null,
schema: [],
messages: {
missing: 'Missing default export.'
}
},
/** @param {RuleContext} context */
create(context) {
const sourceCode = context.getSourceCode()
const documentFragment = sourceCode.parserServices.getDocumentFragment?.()

const hasScript =
documentFragment &&
documentFragment.children.some(
(e) => utils.isVElement(e) && e.name === 'script'
)

if (utils.isScriptSetup(context) || !hasScript) {
return {}
}

let hasDefaultExport = false

return {
'Program > ExportDefaultDeclaration'() {
hasDefaultExport = true
},

/**
* @param {Program} node
*/
'Program:exit'(node) {
if (!hasDefaultExport && node.body.length > 0) {
context.report({
loc: { line: 1, column: 0 },
messageId: 'missing'
})
}
}
}
}
}
142 changes: 142 additions & 0 deletions tests/lib/rules/require-default-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* @author ItMaga
* See LICENSE file in root directory for full license.
*/
'use strict'

const RuleTester = require('../../eslint-compat').RuleTester
const rule = require('../../../lib/rules/require-default-export')

const tester = new RuleTester({
languageOptions: {
parser: require('vue-eslint-parser'),
ecmaVersion: 2020,
sourceType: 'module'
}
})

tester.run('require-default-export', rule, {
valid: [
{
filename: 'test.vue',
code: `
<template>Without script</template>
`
},
{
filename: 'test.vue',
code: `
<script>
import { ref } from 'vue';

export default {}
</script>
`
},
{
filename: 'test.vue',
code: `
<script setup>
const foo = 'foo';
</script>
`
},
{
filename: 'test.vue',
code: `
<script>
const component = {};

export default component;
</script>
`
},
{
filename: 'test.vue',
code: `
<script>
import {defineComponent} from 'vue';

export default defineComponent({});
</script>
`
}
],
invalid: [
{
filename: 'test.vue',
code: `
<script>
const foo = 'foo';
</script>
`,
errors: [
{
messageId: 'missing',
line: 1
}
]
},
{
filename: 'test.vue',
code: `
<script>
export const foo = 'foo';
</script>
`,
errors: [
{
messageId: 'missing',
line: 1
}
]
},
{
filename: 'test.vue',
code: `
<script>
const foo = 'foo';

export { foo };
</script>
`,
errors: [
{
messageId: 'missing',
line: 1
}
]
},
{
filename: 'test.vue',
code: `
<script>
export const foo = 'foo';
export const bar = 'bar';
</script>
`,
errors: [
{
messageId: 'missing',
line: 1
}
]
},
{
filename: 'test.vue',
code: `
<script>
import { defineComponent } from 'vue';

export const component = defineComponent({});
</script>
`,
errors: [
{
messageId: 'missing',
line: 1
}
]
}
]
})