diff --git a/docs/rules/define-macros-order.md b/docs/rules/define-macros-order.md
index 5d8dda56c..6dbe5ef07 100644
--- a/docs/rules/define-macros-order.md
+++ b/docs/rules/define-macros-order.md
@@ -2,20 +2,20 @@
pageClass: rule-details
sidebarDepth: 0
title: vue/define-macros-order
-description: enforce order of `defineEmits` and `defineProps` compiler macros
+description: enforce order of compiler macros (`defineProps`, `defineEmits`, etc.)
since: v8.7.0
---
# vue/define-macros-order
-> enforce order of `defineEmits` and `defineProps` compiler macros
+> enforce order of compiler macros (`defineProps`, `defineEmits`, etc.)
- :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.
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
## :book: Rule Details
-This rule reports the `defineProps` and `defineEmits` compiler macros when they are not the first statements in `
+```
+
+
+
+
+
+```vue
+
+
+```
+
+
+
### `{ "defineExposeLast": true }`
diff --git a/docs/rules/index.md b/docs/rules/index.md
index 113ff416b..16a195125 100644
--- a/docs/rules/index.md
+++ b/docs/rules/index.md
@@ -213,7 +213,7 @@ For example:
| [vue/component-options-name-casing](./component-options-name-casing.md) | enforce the casing of component name in `components` options | :wrench::bulb: | :hammer: |
| [vue/custom-event-name-casing](./custom-event-name-casing.md) | enforce specific casing for custom event name | | :hammer: |
| [vue/define-emits-declaration](./define-emits-declaration.md) | enforce declaration style of `defineEmits` | | :hammer: |
-| [vue/define-macros-order](./define-macros-order.md) | enforce order of `defineEmits` and `defineProps` compiler macros | :wrench::bulb: | :lipstick: |
+| [vue/define-macros-order](./define-macros-order.md) | enforce order of compiler macros (`defineProps`, `defineEmits`, etc.) | :wrench::bulb: | :lipstick: |
| [vue/define-props-declaration](./define-props-declaration.md) | enforce declaration style of `defineProps` | | :hammer: |
| [vue/enforce-style-attribute](./enforce-style-attribute.md) | enforce or forbid the use of the `scoped` and `module` attributes in SFC top level style tags | | :hammer: |
| [vue/html-button-has-type](./html-button-has-type.md) | disallow usage of button without an explicit type attribute | | :hammer: |
diff --git a/lib/rules/define-macros-order.js b/lib/rules/define-macros-order.js
index f24c58af7..920b5c294 100644
--- a/lib/rules/define-macros-order.js
+++ b/lib/rules/define-macros-order.js
@@ -11,13 +11,15 @@ const MACROS_PROPS = 'defineProps'
const MACROS_OPTIONS = 'defineOptions'
const MACROS_SLOTS = 'defineSlots'
const MACROS_MODEL = 'defineModel'
-const ORDER_SCHEMA = [
+const MACROS_EXPOSE = 'defineExpose'
+const KNOWN_MACROS = new Set([
MACROS_EMITS,
MACROS_PROPS,
MACROS_OPTIONS,
MACROS_SLOTS,
- MACROS_MODEL
-]
+ MACROS_MODEL,
+ MACROS_EXPOSE
+])
const DEFAULT_ORDER = [MACROS_PROPS, MACROS_EMITS]
/**
@@ -109,6 +111,12 @@ function create(context) {
/** @type {ASTNode} */
let defineExposeNode
+ if (order.includes(MACROS_EXPOSE) && defineExposeLast) {
+ throw new Error(
+ "`defineExpose` macro can't be in the `order` array if `defineExposeLast` is true."
+ )
+ }
+
return utils.compositingVisitors(
utils.defineScriptSetupVisitor(context, {
onDefinePropsExit(node) {
@@ -130,6 +138,20 @@ function create(context) {
},
onDefineExposeExit(node) {
defineExposeNode = getDefineMacrosStatement(node)
+ },
+
+ /** @param {CallExpression} node */
+ 'Program > ExpressionStatement > CallExpression, Program > VariableDeclaration > VariableDeclarator > CallExpression'(
+ node
+ ) {
+ if (
+ node.callee &&
+ node.callee.type === 'Identifier' &&
+ order.includes(node.callee.name) &&
+ !KNOWN_MACROS.has(node.callee.name)
+ ) {
+ macrosNodes.set(node.callee.name, [getDefineMacrosStatement(node)])
+ }
}
}),
{
@@ -333,7 +355,7 @@ module.exports = {
type: 'layout',
docs: {
description:
- 'enforce order of `defineEmits` and `defineProps` compiler macros',
+ 'enforce order of compiler macros (`defineProps`, `defineEmits`, etc.)',
categories: undefined,
url: 'https://eslint.vuejs.org/rules/define-macros-order.html'
},
@@ -346,7 +368,8 @@ module.exports = {
order: {
type: 'array',
items: {
- enum: ORDER_SCHEMA
+ type: 'string',
+ minLength: 1
},
uniqueItems: true,
additionalItems: false
diff --git a/tests/lib/rules/define-macros-order.js b/tests/lib/rules/define-macros-order.js
index 3aa2e434d..72b359866 100644
--- a/tests/lib/rules/define-macros-order.js
+++ b/tests/lib/rules/define-macros-order.js
@@ -195,6 +195,65 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: [
+ {
+ order: ['definePage', 'defineModel', 'defineEmits']
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: [
+ {
+ order: ['definePage', 'defineModel', 'defineEmits']
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: [
+ {
+ order: ['definePage', 'defineModel', 'defineEmits']
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `
@@ -254,6 +313,22 @@ tester.run('define-macros-order', rule, {
order: ['defineModel', 'defineSlots']
}
]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ options: [
+ {
+ order: ['definePage', 'defineModel']
+ }
+ ]
}
],
invalid: [
@@ -382,6 +457,40 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [{ order: ['definePage', 'defineProps'] }],
+ errors: [
+ {
+ message: message('definePage'),
+ line: 8
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `
@@ -425,6 +534,61 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [
+ { order: ['definePage', 'defineCustom', 'defineProps', 'defineEmits'] }
+ ],
+ languageOptions: {
+ parserOptions: {
+ parser: require.resolve('@typescript-eslint/parser')
+ }
+ },
+ errors: [
+ {
+ message: message('definePage'),
+ line: 15
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `
@@ -537,6 +701,25 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [{ order: ['definePage', 'defineProps'] }],
+ errors: [
+ {
+ message: message('definePage'),
+ line: 3
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `
@@ -633,6 +816,54 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [{ order: ['defineCustom', 'definePage'] }],
+ errors: [
+ {
+ message: message('defineCustom'),
+ line: 5
+ }
+ ]
+ },
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [{ order: ['defineCustom', 'definePage'] }],
+ errors: [
+ {
+ message: message('defineCustom'),
+ line: 5
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `
@@ -895,6 +1126,44 @@ tester.run('define-macros-order', rule, {
}
]
},
+ {
+ filename: 'test.vue',
+ code: `
+
+ `,
+ output: `
+
+ `,
+ options: [
+ {
+ order: [
+ 'defineSomething',
+ 'defineCustom',
+ 'defineModel',
+ 'defineOptions',
+ 'definePage'
+ ]
+ }
+ ],
+ errors: [
+ {
+ message: message('defineSomething'),
+ line: 5
+ }
+ ]
+ },
{
filename: 'test.vue',
code: `