diff --git a/docs/rules/index.md b/docs/rules/index.md
index e718603f8..64bd7b81d 100644
--- a/docs/rules/index.md
+++ b/docs/rules/index.md
@@ -267,6 +267,7 @@ For example:
| [vue/prefer-prop-type-boolean-first](./prefer-prop-type-boolean-first.md) | enforce `Boolean` comes first in component prop types | :bulb: | :warning: |
| [vue/prefer-separate-static-class](./prefer-separate-static-class.md) | require static class names in template to be in a separate `class` attribute | :wrench: | :hammer: |
| [vue/prefer-true-attribute-shorthand](./prefer-true-attribute-shorthand.md) | require shorthand form attribute when `v-bind` value is `true` | :bulb: | :hammer: |
+| [vue/require-default-export](./require-default-export.md) | require components to be the default export | | :warning: |
| [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | :hammer: |
| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | :bulb: | :hammer: |
| [vue/require-explicit-slots](./require-explicit-slots.md) | require slots to be explicitly defined | | :warning: |
diff --git a/docs/rules/one-component-per-file.md b/docs/rules/one-component-per-file.md
index 6fbede339..5e6b37518 100644
--- a/docs/rules/one-component-per-file.md
+++ b/docs/rules/one-component-per-file.md
@@ -49,6 +49,10 @@ export default {
Nothing.
+## :couple: Related Rules
+
+- [vue/require-default-export](./require-default-export.md)
+
## :books: Further Reading
- [Style guide - Component files](https://vuejs.org/style-guide/rules-strongly-recommended.html#component-files)
diff --git a/docs/rules/require-default-export.md b/docs/rules/require-default-export.md
new file mode 100644
index 000000000..1760c25fa
--- /dev/null
+++ b/docs/rules/require-default-export.md
@@ -0,0 +1,57 @@
+---
+pageClass: rule-details
+sidebarDepth: 0
+title: vue/require-default-export
+description: require components to be the default export
+---
+
+# vue/require-default-export
+
+> require components to be the default export
+
+- :exclamation: _**This rule has not been released yet.**_
+
+## :book: Rule Details
+
+This rule reports when a Vue component does not have a default export, if the component is not defined as `
+```
+
+
+
+
+
+```vue
+
+
+```
+
+
+
+## :wrench: Options
+
+Nothing.
+
+## :couple: Related Rules
+
+- [vue/one-component-per-file](./one-component-per-file.md)
+
+## :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)
diff --git a/lib/index.js b/lib/index.js
index 956eeaa4b..f5b0986a8 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -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'),
diff --git a/lib/rules/require-default-export.js b/lib/rules/require-default-export.js
new file mode 100644
index 000000000..5c5402008
--- /dev/null
+++ b/lib/rules/require-default-export.js
@@ -0,0 +1,68 @@
+/**
+ * @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 components to be the default export',
+ categories: undefined,
+ url: 'https://eslint.vuejs.org/rules/require-default-export.html'
+ },
+ fixable: null,
+ schema: [],
+ messages: {
+ missing: 'Missing default export.',
+ mustBeDefaultExport: 'Component must be the 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
+ let hasDefinedComponent = false
+
+ return utils.compositingVisitors(
+ utils.defineVueVisitor(context, {
+ onVueObjectExit() {
+ hasDefinedComponent = true
+ }
+ }),
+
+ {
+ 'Program > ExportDefaultDeclaration'() {
+ hasDefaultExport = true
+ },
+
+ /**
+ * @param {Program} node
+ */
+ 'Program:exit'(node) {
+ if (!hasDefaultExport && node.body.length > 0) {
+ context.report({
+ loc: node.tokens[node.tokens.length - 1].loc,
+ messageId: hasDefinedComponent ? 'mustBeDefaultExport' : 'missing'
+ })
+ }
+ }
+ }
+ )
+ }
+}
diff --git a/tests/lib/rules/require-default-export.js b/tests/lib/rules/require-default-export.js
new file mode 100644
index 000000000..279af4a38
--- /dev/null
+++ b/tests/lib/rules/require-default-export.js
@@ -0,0 +1,190 @@
+/**
+ * @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: `
+ Without script
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `
+ },
+ {
+ filename: 'test.js',
+ code: `
+ const foo = 'foo';
+ export const bar = 'bar';
+ `
+ },
+ {
+ filename: 'test.js',
+ code: `
+ import {defineComponent} from 'vue';
+ defineComponent({});
+ `
+ }
+ ],
+ invalid: [
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'missing',
+ line: 4,
+ endLine: 4,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'missing',
+ line: 4,
+ endLine: 4,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'missing',
+ line: 6,
+ endLine: 6,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'missing',
+ line: 5,
+ endLine: 5,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'mustBeDefaultExport',
+ line: 6,
+ endLine: 6,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ errors: [
+ {
+ messageId: 'mustBeDefaultExport',
+ line: 6,
+ endLine: 6,
+ column: 7,
+ endColumn: 16
+ }
+ ]
+ }
+ ]
+})
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy