Skip to content

Commit 1038e01

Browse files
committed
Update rule macro order for custom macros
See #2499
1 parent f5cb93d commit 1038e01

File tree

4 files changed

+259
-8
lines changed

4 files changed

+259
-8
lines changed

docs/rules/define-macros-order.md

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ since: v8.7.0
88

99
# vue/define-macros-order
1010

11-
> enforce order of `defineEmits` and `defineProps` compiler macros
11+
> Enforce order of compiler macros (`defineProps`, `defineEmits`, etc.)
1212
1313
- :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.
1414
- :bulb: Some problems reported by this rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
1515

1616
## :book: Rule Details
1717

18-
This rule reports the `defineProps` and `defineEmits` compiler macros when they are not the first statements in `<script setup>` (after any potential import statements or type definitions) or when they are not in the correct order.
18+
This rule reports compiler macros (like `defineProps` or `defineEmits` but also custom ones) when they are not the first statements in `<script setup>` (after any potential import statements or type definitions) or when they are not in the correct order.
1919

2020
## :wrench: Options
2121

@@ -28,7 +28,7 @@ This rule reports the `defineProps` and `defineEmits` compiler macros when they
2828
}
2929
```
3030

31-
- `order` (`string[]`) ... The order of defineEmits and defineProps macros. You can also add `"defineOptions"`, `"defineSlots"`, and `"defineModel"`.
31+
- `order` (`string[]`) ... The order in which the macros should appear. The default is `["defineProps", "defineEmits"]`.
3232
- `defineExposeLast` (`boolean`) ... Force `defineExpose` at the end.
3333

3434
### `{ "order": ["defineProps", "defineEmits"] }` (default)
@@ -118,6 +118,39 @@ const slots = defineSlots()
118118

119119
</eslint-code-block>
120120

121+
### `{ "order": ["definePage", "defineModel", "defineCustom", "defineEmits", "defineSlots"] }`
122+
123+
<eslint-code-block fix :rules="{'vue/define-macros-order': ['error', {order: ['definePage', 'defineModel', 'defineCustom', 'defineEmits', 'defineSlots']}]}">
124+
125+
```vue
126+
<!-- ✓ GOOD -->
127+
<script setup>
128+
definePage()
129+
const model = defineModel()
130+
defineCustom()
131+
defineEmits(/* ... */)
132+
const slots = defineSlots()
133+
</script>
134+
```
135+
136+
</eslint-code-block>
137+
138+
<eslint-code-block fix :rules="{'vue/define-macros-order': ['error', {order: ['definePage', 'defineModel', 'defineCustom', 'defineEmits', 'defineSlots']}]}">
139+
140+
```vue
141+
<!-- ✗ BAD -->
142+
<script setup>
143+
defineEmits(/* ... */)
144+
const slots = defineSlots()
145+
defineProps(/* ... */)
146+
defineCustom({/* ... */})
147+
const model = defineModel()
148+
definePage()
149+
</script>
150+
```
151+
152+
</eslint-code-block>
153+
121154
### `{ "defineExposeLast": true }`
122155

123156
<eslint-code-block fix :rules="{'vue/define-macros-order': ['error', {defineExposeLast: true}]}">

lib/rules/define-macros-order.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ const MACROS_PROPS = 'defineProps'
1111
const MACROS_OPTIONS = 'defineOptions'
1212
const MACROS_SLOTS = 'defineSlots'
1313
const MACROS_MODEL = 'defineModel'
14-
const ORDER_SCHEMA = [
14+
const ORDER_SCHEMA = new Set([
1515
MACROS_EMITS,
1616
MACROS_PROPS,
1717
MACROS_OPTIONS,
1818
MACROS_SLOTS,
1919
MACROS_MODEL
20-
]
20+
])
2121
const DEFAULT_ORDER = [MACROS_PROPS, MACROS_EMITS]
2222

2323
/**
@@ -130,6 +130,18 @@ function create(context) {
130130
},
131131
onDefineExposeExit(node) {
132132
defineExposeNode = getDefineMacrosStatement(node)
133+
},
134+
135+
'CallExpression:exit'(node) {
136+
// check if the node is a macro in the order
137+
if (
138+
node.callee &&
139+
node.callee.type === 'Identifier' &&
140+
order.includes(node.callee.name) &&
141+
!ORDER_SCHEMA.has(node.callee.name)
142+
) {
143+
macrosNodes.set(node.callee.name, [getDefineMacrosStatement(node)])
144+
}
133145
}
134146
}),
135147
{
@@ -345,9 +357,9 @@ module.exports = {
345357
properties: {
346358
order: {
347359
type: 'array',
348-
items: {
349-
enum: ORDER_SCHEMA
350-
},
360+
// items: {
361+
// enum: ORDER_SCHEMA
362+
// },
351363
uniqueItems: true,
352364
additionalItems: false
353365
},

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"start": "npm run test:base -- --watch --growl",
99
"test:base": "mocha \"tests/lib/**/*.js\" --reporter dot",
1010
"test": "nyc npm run test:base -- \"tests/integrations/*.js\" --timeout 60000",
11+
"test:define-macros-order": "mocha \"tests/lib/rules/define-macros-order.js\" --timeout 60000",
1112
"test:integrations": "mocha \"tests/integrations/*.js\" --timeout 60000",
1213
"debug": "mocha --inspect \"tests/lib/**/*.js\" --reporter dot --timeout 60000",
1314
"cover": "npm run cover:test && npm run cover:report",

tests/lib/rules/define-macros-order.js

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,25 @@ tester.run('define-macros-order', rule, {
195195
}
196196
]
197197
},
198+
{
199+
filename: 'test.vue',
200+
code: `
201+
<script setup>
202+
import Foo from 'foo'
203+
/** Page */
204+
definePage()
205+
/** model */
206+
const model = defineModel()
207+
/** emits */
208+
defineEmits(['update:foo'])
209+
</script>
210+
`,
211+
options: [
212+
{
213+
order: ['definePage', 'defineModel', 'defineEmits']
214+
}
215+
]
216+
},
198217
{
199218
filename: 'test.vue',
200219
code: `
@@ -254,6 +273,22 @@ tester.run('define-macros-order', rule, {
254273
order: ['defineModel', 'defineSlots']
255274
}
256275
]
276+
},
277+
{
278+
filename: 'test.vue',
279+
code: `
280+
<script setup>
281+
const page = definePage()
282+
283+
const first = defineModel('first')
284+
const second = defineModel('second')
285+
</script>
286+
`,
287+
options: [
288+
{
289+
order: ['definePage', 'defineModel']
290+
}
291+
]
257292
}
258293
],
259294
invalid: [
@@ -382,6 +417,40 @@ tester.run('define-macros-order', rule, {
382417
}
383418
]
384419
},
420+
{
421+
filename: 'test.vue',
422+
code: `
423+
<script setup>
424+
console.log('test1')
425+
const props = defineProps({
426+
test: Boolean
427+
})
428+
console.log('test2')
429+
const page = definePage({
430+
name: 'hello'
431+
})
432+
</script>
433+
`,
434+
output: `
435+
<script setup>
436+
const page = definePage({
437+
name: 'hello'
438+
})
439+
const props = defineProps({
440+
test: Boolean
441+
})
442+
console.log('test1')
443+
console.log('test2')
444+
</script>
445+
`,
446+
options: [{ order: ['definePage', 'defineProps'] }],
447+
errors: [
448+
{
449+
message: message('definePage'),
450+
line: 8
451+
}
452+
]
453+
},
385454
{
386455
filename: 'test.vue',
387456
code: `
@@ -425,6 +494,61 @@ tester.run('define-macros-order', rule, {
425494
}
426495
]
427496
},
497+
{
498+
filename: 'test.vue',
499+
code: `
500+
<script lang="ts" setup>
501+
interface Props {
502+
msg?: string
503+
labels?: string[]
504+
}
505+
506+
const props = defineProps<{
507+
msg?: string
508+
labels?: string[]
509+
}>()
510+
defineCustom()
511+
const emit = defineEmits<{(e: 'update:test'): void}>()
512+
513+
const page = definePage({
514+
name: 'hello'
515+
})
516+
</script>
517+
`,
518+
output: `
519+
<script lang="ts" setup>
520+
interface Props {
521+
msg?: string
522+
labels?: string[]
523+
}
524+
525+
const page = definePage({
526+
name: 'hello'
527+
})
528+
defineCustom()
529+
const props = defineProps<{
530+
msg?: string
531+
labels?: string[]
532+
}>()
533+
const emit = defineEmits<{(e: 'update:test'): void}>()
534+
535+
</script>
536+
`,
537+
options: [
538+
{ order: ['definePage', 'defineCustom', 'defineProps', 'defineEmits'] }
539+
],
540+
languageOptions: {
541+
parserOptions: {
542+
parser: require.resolve('@typescript-eslint/parser')
543+
}
544+
},
545+
errors: [
546+
{
547+
message: message('definePage'),
548+
line: 15
549+
}
550+
]
551+
},
428552
{
429553
filename: 'test.vue',
430554
code: `
@@ -537,6 +661,25 @@ tester.run('define-macros-order', rule, {
537661
}
538662
]
539663
},
664+
{
665+
filename: 'test.vue',
666+
code: `
667+
<script setup>
668+
const props = defineProps({ test: Boolean });definePage({name: 'hello'})
669+
</script>
670+
`,
671+
output: `
672+
<script setup>
673+
definePage({name: 'hello'});const props = defineProps({ test: Boolean }); </script>
674+
`,
675+
options: [{ order: ['definePage', 'defineProps'] }],
676+
errors: [
677+
{
678+
message: message('definePage'),
679+
line: 3
680+
}
681+
]
682+
},
540683
{
541684
filename: 'test.vue',
542685
code: `
@@ -633,6 +776,30 @@ tester.run('define-macros-order', rule, {
633776
}
634777
]
635778
},
779+
{
780+
filename: 'test.vue',
781+
code: `
782+
<script setup>
783+
definePage({name: 'hello'})
784+
console.log('test1')
785+
defineCustom({ test: Boolean })
786+
</script>
787+
`,
788+
output: `
789+
<script setup>
790+
defineCustom({ test: Boolean })
791+
definePage({name: 'hello'})
792+
console.log('test1')
793+
</script>
794+
`,
795+
options: [{ order: ['defineCustom', 'definePage'] }],
796+
errors: [
797+
{
798+
message: message('defineCustom'),
799+
line: 5
800+
}
801+
]
802+
},
636803
{
637804
filename: 'test.vue',
638805
code: `
@@ -895,6 +1062,44 @@ tester.run('define-macros-order', rule, {
8951062
}
8961063
]
8971064
},
1065+
{
1066+
filename: 'test.vue',
1067+
code: `
1068+
<script setup>
1069+
defineOptions({})
1070+
defineCustom('second')
1071+
const something = defineSomething('first')
1072+
definePage()
1073+
const model = defineModel('second')
1074+
</script>
1075+
`,
1076+
output: `
1077+
<script setup>
1078+
const something = defineSomething('first')
1079+
defineCustom('second')
1080+
const model = defineModel('second')
1081+
defineOptions({})
1082+
definePage()
1083+
</script>
1084+
`,
1085+
options: [
1086+
{
1087+
order: [
1088+
'defineSomething',
1089+
'defineCustom',
1090+
'defineModel',
1091+
'defineOptions',
1092+
'definePage'
1093+
]
1094+
}
1095+
],
1096+
errors: [
1097+
{
1098+
message: message('defineSomething'),
1099+
line: 5
1100+
}
1101+
]
1102+
},
8981103
{
8991104
filename: 'test.vue',
9001105
code: `

0 commit comments

Comments
 (0)