eslint-plugin-mpx 0.2.19 → 0.2.20-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/lib/configs/flat/base.js +22 -0
  2. package/lib/configs/flat/composition-api-essential.js +24 -0
  3. package/lib/configs/flat/mpx-essential.js +30 -0
  4. package/lib/index.js +7 -2
  5. package/lib/meta.js +3 -0
  6. package/lib/processor.js +24 -14
  7. package/lib/rules/comment-directive.js +16 -15
  8. package/lib/rules/component-tags-order.js +8 -7
  9. package/lib/rules/eqeqeq.js +2 -1
  10. package/lib/rules/html-end-tags.js +5 -2
  11. package/lib/rules/no-arrow-functions-in-watch.js +5 -2
  12. package/lib/rules/no-async-in-computed-properties.js +17 -14
  13. package/lib/rules/no-deprecated-lifecycle.js +2 -2
  14. package/lib/rules/no-deprecated-mpx-createfunction.js +9 -6
  15. package/lib/rules/no-deprecated-watch-second-param.js +9 -6
  16. package/lib/rules/no-dupe-keys.js +10 -4
  17. package/lib/rules/no-dupe-wx-elif.js +10 -7
  18. package/lib/rules/no-duplicate-attributes.js +5 -3
  19. package/lib/rules/no-parsing-error.js +6 -2
  20. package/lib/rules/no-reserved-keys.js +12 -6
  21. package/lib/rules/no-side-effects-in-computed-properties.js +8 -6
  22. package/lib/rules/return-in-computed-property.js +7 -5
  23. package/lib/rules/script-indent.js +6 -3
  24. package/lib/rules/script-setup-uses-vars.js +4 -2
  25. package/lib/rules/syntaxes/slot-attribute.js +1 -0
  26. package/lib/rules/syntaxes/slot-scope-attribute.js +1 -0
  27. package/lib/rules/syntaxes/v-slot.js +3 -2
  28. package/lib/rules/valid-attribute-value.js +10 -5
  29. package/lib/rules/valid-component-range.js +21 -15
  30. package/lib/rules/valid-initdata.js +39 -36
  31. package/lib/rules/valid-properties.js +8 -5
  32. package/lib/rules/valid-setup-define-expose.js +35 -13
  33. package/lib/rules/valid-swiper-item-style.js +7 -4
  34. package/lib/rules/valid-template-quote.js +6 -3
  35. package/lib/rules/valid-wx-elif.js +18 -10
  36. package/lib/rules/valid-wx-else.js +18 -10
  37. package/lib/rules/valid-wx-if.js +14 -8
  38. package/lib/rules/valid-wx-key.js +27 -14
  39. package/lib/utils/casing.js +7 -7
  40. package/lib/utils/indent-common.js +32 -32
  41. package/lib/utils/index.js +92 -84
  42. package/lib/utils/regexp.js +2 -2
  43. package/lib/utils/scope.js +30 -0
  44. package/package.json +15 -14
  45. package/lib/.DS_Store +0 -0
@@ -49,7 +49,6 @@ module.exports = {
49
49
  url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/no-duplicate-attributes.html'
50
50
  },
51
51
  fixable: null,
52
-
53
52
  schema: [
54
53
  {
55
54
  type: 'object',
@@ -62,7 +61,10 @@ module.exports = {
62
61
  }
63
62
  }
64
63
  }
65
- ]
64
+ ],
65
+ messages: {
66
+ name: "Duplicate attribute '{{name}}'."
67
+ }
66
68
  },
67
69
  /** @param {RuleContext} context */
68
70
  create(context) {
@@ -93,7 +95,7 @@ module.exports = {
93
95
  context.report({
94
96
  node,
95
97
  loc: node.loc,
96
- message: "Duplicate attribute '{{name}}'.",
98
+ messageId: 'name',
97
99
  data: { name }
98
100
  })
99
101
  }
@@ -67,13 +67,17 @@ module.exports = {
67
67
  schema: [
68
68
  {
69
69
  type: 'object',
70
+ // eslint-disable-next-line unicorn/no-array-reduce
70
71
  properties: Object.keys(DEFAULT_OPTIONS).reduce((ret, code) => {
71
72
  ret[code] = { type: 'boolean' }
72
73
  return ret
73
74
  }, /** @type { { [key: string]: { type: 'boolean' } } } */ ({})),
74
75
  additionalProperties: false
75
76
  }
76
- ]
77
+ ],
78
+ messages: {
79
+ msg: 'Parsing error: {{message}}.'
80
+ }
77
81
  },
78
82
  /**
79
83
  * @param {RuleContext} context - The rule context.
@@ -97,7 +101,7 @@ module.exports = {
97
101
  context.report({
98
102
  node,
99
103
  loc: { line: error.lineNumber, column: error.column },
100
- message: 'Parsing error: {{message}}.',
104
+ messageId: 'msg',
101
105
  data: {
102
106
  message: error.message.endsWith('.')
103
107
  ? error.message.slice(0, -1)
@@ -40,13 +40,20 @@ module.exports = {
40
40
  },
41
41
  additionalProperties: false
42
42
  }
43
- ]
43
+ ],
44
+ messages: {
45
+ reserved: "Key '{{name}}' is reserved.",
46
+ group: "Keys starting with with '_' are reserved in '{{name}}' group."
47
+ }
44
48
  },
45
49
  /** @param {RuleContext} context */
46
50
  create(context) {
47
51
  const options = context.options[0] || {}
48
- const reservedKeys = new Set(RESERVED_KEYS.concat(options.reserved || []))
49
- const groups = new Set(GROUP_NAMES.concat(options.groups || []))
52
+ const reservedKeys = new Set([
53
+ ...RESERVED_KEYS,
54
+ ...(options.reserved || [])
55
+ ])
56
+ const groups = new Set([...GROUP_NAMES, ...(options.groups || [])])
50
57
 
51
58
  // ----------------------------------------------------------------------
52
59
  // Public
@@ -58,8 +65,7 @@ module.exports = {
58
65
  if (o.groupName === 'data' && o.name[0] === '_') {
59
66
  context.report({
60
67
  node: o.node,
61
- message:
62
- "Keys starting with with '_' are reserved in '{{name}}' group.",
68
+ messageId: 'group',
63
69
  data: {
64
70
  name: o.name
65
71
  }
@@ -67,7 +73,7 @@ module.exports = {
67
73
  } else if (reservedKeys.has(o.name)) {
68
74
  context.report({
69
75
  node: o.node,
70
- message: "Key '{{name}}' is reserved.",
76
+ messageId: 'reserved',
71
77
  data: {
72
78
  name: o.name
73
79
  }
@@ -24,7 +24,10 @@ module.exports = {
24
24
  url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/no-side-effects-in-computed-properties.html'
25
25
  },
26
26
  fixable: null,
27
- schema: []
27
+ schema: [],
28
+ messages: {
29
+ property: 'Unexpected side effect in "{{key}}" computed property.'
30
+ }
28
31
  },
29
32
  /** @param {RuleContext} context */
30
33
  create(context) {
@@ -74,14 +77,13 @@ module.exports = {
74
77
  const targetBody = scopeStack.body
75
78
  const computedProperty = /** @type {ComponentComputedProperty[]} */ (
76
79
  computedPropertiesMap.get(vueNode)
77
- ).find((cp) => {
78
- return (
80
+ ).find(
81
+ (cp) =>
79
82
  cp.value &&
80
83
  node.loc.start.line >= cp.value.loc.start.line &&
81
84
  node.loc.end.line <= cp.value.loc.end.line &&
82
85
  targetBody === cp.value
83
- )
84
- })
86
+ )
85
87
  if (!computedProperty) {
86
88
  return
87
89
  }
@@ -98,7 +100,7 @@ module.exports = {
98
100
  if (invalid) {
99
101
  context.report({
100
102
  node: invalid.node,
101
- message: 'Unexpected side effect in "{{key}}" computed property.',
103
+ messageId: 'property',
102
104
  data: { key: computedProperty.key || 'Unknown' }
103
105
  })
104
106
  }
@@ -34,7 +34,10 @@ module.exports = {
34
34
  },
35
35
  additionalProperties: false
36
36
  }
37
- ]
37
+ ],
38
+ messages: {
39
+ returnValue: 'Expected to return a value in "{{name}}" computed property.'
40
+ }
38
41
  },
39
42
  /** @param {RuleContext} context */
40
43
  create(context) {
@@ -64,18 +67,17 @@ module.exports = {
64
67
  utils.executeOnFunctionsWithoutReturn(
65
68
  treatUndefinedAsUnspecified,
66
69
  (node) => {
67
- computedProperties.forEach((cp) => {
70
+ for (const cp of computedProperties) {
68
71
  if (cp.value && cp.value.parent === node) {
69
72
  context.report({
70
73
  node,
71
- message:
72
- 'Expected to return a value in "{{name}}" computed property.',
74
+ messageId: 'returnValue',
73
75
  data: {
74
76
  name: cp.key || 'Unknown'
75
77
  }
76
78
  })
77
79
  }
78
- })
80
+ }
79
81
  }
80
82
  )
81
83
  )
@@ -11,8 +11,9 @@ module.exports = {
11
11
  docs: {
12
12
  description: 'enforce consistent indentation in `<script>`',
13
13
  categories: undefined,
14
- url: ''
14
+ url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/script-indent.html'
15
15
  },
16
+ // eslint-disable-next-line eslint-plugin/require-meta-fixable
16
17
  fixable: 'whitespace',
17
18
  schema: [
18
19
  {
@@ -29,7 +30,7 @@ module.exports = {
29
30
  allOf: [
30
31
  { type: 'string' },
31
32
  { not: { type: 'string', pattern: ':exit$' } },
32
- { not: { type: 'string', pattern: '^\\s*$' } }
33
+ { not: { type: 'string', pattern: String.raw`^\s*$` } }
33
34
  ]
34
35
  },
35
36
  uniqueItems: true,
@@ -38,7 +39,9 @@ module.exports = {
38
39
  },
39
40
  additionalProperties: false
40
41
  }
41
- ]
42
+ ],
43
+ // eslint-disable-next-line eslint-plugin/prefer-message-ids
44
+ messages: {}
42
45
  },
43
46
  /** @param {RuleContext} context */
44
47
  create(context) {
@@ -22,10 +22,12 @@ module.exports = {
22
22
  description:
23
23
  'prevent `<script setup>` variables used in `<template>` to be marked as unused', // eslint-disable-line eslint-plugin/require-meta-docs-description
24
24
  categories: undefined,
25
- url: 'https://eslint.vuejs.org/rules/script-setup-uses-vars.html'
25
+ url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/script-setup-uses-vars.html'
26
26
  },
27
27
  deprecated: true,
28
- schema: []
28
+ schema: [],
29
+ // eslint-disable-next-line eslint-plugin/prefer-message-ids
30
+ messages: {}
29
31
  },
30
32
  /**
31
33
  * @param {RuleContext} context - The rule context.
@@ -15,6 +15,7 @@ module.exports = {
15
15
  * @param {VAttribute} slotAttr node of `slot`
16
16
  * @returns {boolean} `true` if the given node can convert to the `v-slot`
17
17
  */
18
+ // eslint-disable-next-line unicorn/consistent-function-scoping
18
19
  function canConvertFromSlotToVSlot(slotAttr) {
19
20
  if (slotAttr.parent.parent.name !== 'template') {
20
21
  return false
@@ -20,6 +20,7 @@ module.exports = {
20
20
  * @param {VStartTag} startTag node of `<element v-slot ... >`
21
21
  * @returns {boolean} `true` if the given node can convert to the `v-slot`
22
22
  */
23
+ // eslint-disable-next-line unicorn/consistent-function-scoping
23
24
  function canConvertToVSlot(startTag) {
24
25
  if (startTag.parent.name !== 'template') {
25
26
  return false
@@ -14,6 +14,7 @@ module.exports = {
14
14
  * @param {VDirective} vSlotAttr node of `v-slot`
15
15
  * @returns {boolean} `true` if the given node can convert to the `slot`
16
16
  */
17
+ // eslint-disable-next-line unicorn/consistent-function-scoping
17
18
  function canConvertToSlot(vSlotAttr) {
18
19
  if (vSlotAttr.parent.parent.name !== 'template') {
19
20
  return false
@@ -28,7 +29,7 @@ module.exports = {
28
29
  */
29
30
  function fixVSlotToSlot(fixer, vSlotAttr) {
30
31
  const key = vSlotAttr.key
31
- if (key.modifiers.length) {
32
+ if (key.modifiers.length > 0) {
32
33
  // unknown modifiers
33
34
  return null
34
35
  }
@@ -54,7 +55,7 @@ module.exports = {
54
55
  if (scopedValueNode) {
55
56
  attrs.push(`slot-scope=${sourceCode.getText(scopedValueNode)}`)
56
57
  }
57
- if (!attrs.length) {
58
+ if (attrs.length === 0) {
58
59
  attrs.push('slot') // useless
59
60
  }
60
61
  return fixer.replaceText(vSlotAttr, attrs.join(' '))
@@ -23,8 +23,12 @@ module.exports = {
23
23
  categories: ['mpx-essential'],
24
24
  url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/valid-attribute-value.html'
25
25
  },
26
- fixable: 'code',
27
- schema: []
26
+ fixable: null,
27
+ schema: [],
28
+ messages: {
29
+ requireValue: "'{{value}}' attribute expression require valid value.",
30
+ requireAttribute: "'{{value}}' directive require that attribute value."
31
+ }
28
32
  },
29
33
  /** @param {RuleContext} context */
30
34
  create(context) {
@@ -40,18 +44,19 @@ module.exports = {
40
44
  context.report({
41
45
  node,
42
46
  loc: node.loc,
43
- message: "'{{value}}' attribute expression require valid value.",
47
+ messageId: 'requireValue',
44
48
  data: {
45
49
  value: sourceCode.getText(node)
46
50
  }
47
51
  })
48
52
  } else if (node.directive) {
49
53
  // 若为指令,继续判断是否为空值
50
- if (utils.isEmptyValueDirective(node, context)) {
54
+ const isEmpty = utils.isEmptyValueDirective(node, context)
55
+ if (isEmpty) {
51
56
  context.report({
52
57
  node,
53
58
  loc: node.loc,
54
- message: "'{{value}}' directive require that attribute value.",
59
+ messageId: 'requireAttribute',
55
60
  data: {
56
61
  value: sourceCode.getText(node)
57
62
  }
@@ -19,12 +19,19 @@ module.exports = {
19
19
  meta: {
20
20
  type: 'problem',
21
21
  docs: {
22
- description: '强制 component 添加 range 范围',
22
+ description: 'require 强制 component 添加 range 范围',
23
23
  categories: ['mpx-essential'],
24
24
  url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/valid-component-range.html'
25
25
  },
26
26
  fixable: null,
27
- schema: []
27
+ schema: [],
28
+ messages: {
29
+ elementRequire: "'component' element require 'is' attribute.",
30
+ elementRange: "'component' element require 'range' for backup.",
31
+ elementScope:
32
+ "'component' element require 'range' attribute to set the scope.",
33
+ componentRequire: "'component' attribute '{{key}}' require valid value."
34
+ }
28
35
  },
29
36
  /** @param {RuleContext} context */
30
37
  create(context) {
@@ -38,37 +45,36 @@ module.exports = {
38
45
  return context.report({
39
46
  node,
40
47
  loc: node.loc,
41
- message: "'component' element require 'is' attribute."
48
+ messageId: 'elementRequire'
42
49
  })
43
- } else if (!rangeNode.length) {
44
- context.report({
45
- node,
46
- loc: node.loc,
47
- message:
48
- "'component' element require 'range' attribute to set the scope."
49
- })
50
- } else {
50
+ } else if (rangeNode.length > 0) {
51
51
  // 最好有个兜底range
52
52
  if (!utils.getAttribute(node, 'range')) {
53
53
  context.report({
54
54
  node,
55
55
  loc: node.loc,
56
- message: "'component' element require 'range' for backup."
56
+ messageId: 'elementRange'
57
57
  })
58
58
  }
59
+ } else {
60
+ context.report({
61
+ node,
62
+ loc: node.loc,
63
+ messageId: 'elementScope'
64
+ })
59
65
  }
60
- ;[isNode, ...rangeNode].forEach((keyNode) => {
66
+ for (const keyNode of [isNode, ...rangeNode]) {
61
67
  if (keyNode && (!keyNode.value || !keyNode.value.value)) {
62
68
  context.report({
63
69
  node,
64
70
  loc: node.loc,
65
- message: "'component' attribute '{{key}}' require valid value.",
71
+ messageId: 'componentRequire',
66
72
  data: {
67
73
  key: keyNode.key.name
68
74
  }
69
75
  })
70
76
  }
71
- })
77
+ }
72
78
  }
73
79
  })
74
80
  }
@@ -11,7 +11,7 @@
11
11
  const utils = require('../utils')
12
12
  function commonFunction(value, list) {
13
13
  const props = value.properties
14
- props.forEach((item) => {
14
+ for (const item of props) {
15
15
  if (
16
16
  item.type === 'SpreadElement' &&
17
17
  item.argument &&
@@ -26,24 +26,24 @@ function commonFunction(value, list) {
26
26
  if (item.argument.arguments.arguments) {
27
27
  const elements = item.argument.arguments.arguments.elements
28
28
  if (elements) {
29
- elements.forEach((row) => {
29
+ for (const row of elements) {
30
30
  if (row.type === 'ArrayExpression') {
31
31
  args = row.elements
32
32
  }
33
- })
33
+ }
34
34
  }
35
35
  }
36
36
  }
37
- args.forEach((item) => {
37
+ for (const item of args) {
38
38
  list.add(item.value)
39
- })
39
+ }
40
40
  } else {
41
41
  list.add(item.key.name)
42
42
  }
43
- })
43
+ }
44
44
  }
45
45
  function handleInitData(current, propsSet, parentName) {
46
- current.forEach((item) => {
46
+ for (const item of current) {
47
47
  const currentName = item.key.name
48
48
  if (currentName) {
49
49
  let name = currentName
@@ -59,7 +59,7 @@ function handleInitData(current, propsSet, parentName) {
59
59
  }
60
60
  handleInitData(item.value.properties, propsSet, pre)
61
61
  }
62
- })
62
+ }
63
63
  }
64
64
 
65
65
  function checkInInitData(
@@ -112,9 +112,10 @@ module.exports = {
112
112
  meta: {
113
113
  type: 'suggestion', // `problem`, `suggestion`, or `layout`
114
114
  docs: {
115
- description: 'initData检测',
115
+ description: 'require initData检测',
116
116
  recommended: false,
117
- url: null // URL to the documentation page for this rule
117
+ categories: ['mpx-essential', 'composition-api-essential'],
118
+ url: 'https://mpx-ecology.github.io/eslint-plugin-mpx/rules/valid-initdata.html' // URL to the documentation page for this rule
118
119
  },
119
120
  fixable: null, // Or `code` or `whitespace`
120
121
  schema: [], // Add a schema if the rule has options
@@ -131,7 +132,7 @@ module.exports = {
131
132
  // 收集computed属性
132
133
  const computedSet = new Set([])
133
134
  // 忽略的标签类型
134
- const ignoreElementTypes = [
135
+ const ignoreElementTypes = new Set([
135
136
  'view',
136
137
  'text',
137
138
  'image',
@@ -154,8 +155,8 @@ module.exports = {
154
155
  'radio',
155
156
  'radio-group',
156
157
  'switch'
157
- ]
158
- const ignoreAttributeTypes = [
158
+ ])
159
+ const ignoreAttributeTypes = new Set([
159
160
  'wx:if',
160
161
  'wx:else',
161
162
  'bindtap',
@@ -168,7 +169,7 @@ module.exports = {
168
169
  'style',
169
170
  'hover-class',
170
171
  'src'
171
- ]
172
+ ])
172
173
  // 全局是否有initData 初始值:0 ,存在: 1,不存在: 2
173
174
  let hasInitData = 0
174
175
  return utils.defineTemplateBodyVisitor(
@@ -177,13 +178,13 @@ module.exports = {
177
178
  // VExpressionContainer(node) {},
178
179
  VAttribute(node) {
179
180
  const parent = node.parent
180
- if (!ignoreElementTypes.includes(parent.name)) {
181
- if (
182
- !ignoreAttributeTypes.includes(node.key.name) &&
181
+ if (!ignoreElementTypes.has(parent.name)) {
182
+ const isattr =
183
+ !ignoreAttributeTypes.has(node.key.name) &&
183
184
  node.value &&
184
185
  node.value.value &&
185
186
  node.value.value.startsWith('{{')
186
- ) {
187
+ if (isattr) {
187
188
  const reg = /(?<={{).*?(?=}})/
188
189
  checkInInitData(
189
190
  computedSet,
@@ -210,7 +211,7 @@ module.exports = {
210
211
  if (!utils.isScriptSetup(context)) return
211
212
  const body = node.body
212
213
  if (body) {
213
- body.forEach((item) => {
214
+ for (const item of body) {
214
215
  if (
215
216
  item.type === 'ExpressionStatement' &&
216
217
  item.expression &&
@@ -218,15 +219,15 @@ module.exports = {
218
219
  item.expression.callee.name === 'defineOptions' &&
219
220
  item.expression.arguments
220
221
  ) {
221
- item.expression.arguments.forEach((sub) => {
222
+ for (const sub of item.expression.arguments) {
222
223
  if (sub.type === 'ObjectExpression' && sub.properties) {
223
- sub.properties.forEach((val) => {
224
+ for (const val of sub.properties) {
224
225
  if (val.key.name === 'initData') {
225
226
  hasInitData = 1
226
227
  }
227
- })
228
+ }
228
229
  }
229
- })
230
+ }
230
231
  if (hasInitData === 0) {
231
232
  hasInitData = 2
232
233
  }
@@ -235,7 +236,7 @@ module.exports = {
235
236
  hasInitData = 2
236
237
  }
237
238
  }
238
- })
239
+ }
239
240
  }
240
241
  },
241
242
  CallExpression(node) {
@@ -248,11 +249,11 @@ module.exports = {
248
249
  if (node.callee.name !== 'createComponent') return
249
250
  const properties = node.arguments[0].properties
250
251
  if (!properties) return
251
- properties.forEach((element) => {
252
+ for (const element of properties) {
252
253
  if (element.key.name === 'initData') {
253
254
  hasInitData = 1
254
255
  }
255
- })
256
+ }
256
257
  if (hasInitData === 0) {
257
258
  hasInitData = 2
258
259
  }
@@ -260,14 +261,16 @@ module.exports = {
260
261
  },
261
262
  ObjectExpression(node) {
262
263
  const parent = node.parent
263
- if (parent && parent.type === 'CallExpression') {
264
- if (parent.callee.name === 'defineOptions') {
265
- if (node.properties && Array.isArray(node.properties)) {
266
- node.properties.forEach((item) => {
267
- if (item.key.name === 'initData') {
268
- handleInitData(item.value.properties, propsSet)
269
- }
270
- })
264
+ const isinit =
265
+ parent &&
266
+ parent.type === 'CallExpression' &&
267
+ parent.callee.name === 'defineOptions' &&
268
+ node.properties &&
269
+ Array.isArray(node.properties)
270
+ if (isinit) {
271
+ for (const item of node.properties) {
272
+ if (item.key.name === 'initData') {
273
+ handleInitData(item.value.properties, propsSet)
271
274
  }
272
275
  }
273
276
  }
@@ -277,10 +280,10 @@ module.exports = {
277
280
  commonFunction(node.value, computedSet)
278
281
  }
279
282
  if (node.key.name === 'initData') {
280
- if (
283
+ const isCreate =
281
284
  node.parent.parent.callee &&
282
285
  node.parent.parent.callee.name === 'createComponent'
283
- ) {
286
+ if (isCreate) {
284
287
  handleInitData(node.value.properties, propsSet)
285
288
  }
286
289
  }
@@ -47,7 +47,7 @@ function validProp(node, context, allowKeys) {
47
47
  })
48
48
  }
49
49
  if (node.value.type === 'ObjectExpression') {
50
- if (!node.value.properties.length) {
50
+ if (node.value.properties.length === 0) {
51
51
  return context.report({
52
52
  node: node.value,
53
53
  message: "The value of '{{propName}}' cannot be empty object.",
@@ -57,8 +57,8 @@ function validProp(node, context, allowKeys) {
57
57
  })
58
58
  }
59
59
  let hasType = 0
60
- node.value.properties.forEach((item) => {
61
- if (item.type !== 'Property') return
60
+ for (const item of node.value.properties) {
61
+ if (item.type !== 'Property') continue
62
62
  const keyName = sourceCode.getText(item.key)
63
63
  if (!allowKeys.includes(keyName)) {
64
64
  context.report({
@@ -72,7 +72,7 @@ function validProp(node, context, allowKeys) {
72
72
  } else if (keyName === 'type') {
73
73
  hasType = 1
74
74
  }
75
- })
75
+ }
76
76
  if (!hasType) {
77
77
  context.report({
78
78
  node: node.value,
@@ -113,7 +113,9 @@ module.exports = {
113
113
  }
114
114
  }
115
115
  }
116
- ]
116
+ ],
117
+ // eslint-disable-next-line eslint-plugin/prefer-message-ids
118
+ messages: {}
117
119
  },
118
120
  /** @param {RuleContext} context */
119
121
  create(context) {
@@ -125,6 +127,7 @@ module.exports = {
125
127
  // Public
126
128
  // ----------------------------------------------------------------------
127
129
 
130
+ // eslint-disable-next-line unicorn/prefer-ternary
128
131
  if (isScriptSetup) {
129
132
  return utils.defineTemplateBodyVisitor(
130
133
  context,