eslint-plugin-mpx 0.2.9 → 0.2.10-beta

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.
@@ -14,6 +14,7 @@ module.exports = {
14
14
  'mpx/valid-wx-elif': 'error',
15
15
  'mpx/valid-wx-model': 'error',
16
16
  // 'mpx/script-setup-uses-vars': 'error',
17
+ 'mpx/valid-initdata': 'error',
17
18
  'mpx/valid-setup-define-expose': 'error',
18
19
  'mpx/no-deprecated-mpx-createfunction': 'error',
19
20
  'mpx/no-deprecated-watch-second-param': 'error',
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ module.exports = {
32
32
  'valid-template-quote': require('./rules/valid-template-quote'),
33
33
  'valid-component-range': require('./rules/valid-component-range'),
34
34
  'valid-setup-define-expose': require('./rules/valid-setup-define-expose'),
35
+ 'valid-initdata': require('./rules/valid-initdata'),
35
36
  'no-deprecated-lifecycle': require('./rules/no-deprecated-lifecycle'),
36
37
  'no-deprecated-mpx-createfunction': require('./rules/no-deprecated-mpx-createfunction'),
37
38
  'no-deprecated-watch-second-param': require('./rules/no-deprecated-watch-second-param')
@@ -0,0 +1,270 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview initData检测
4
+ * @author jvzuojing
5
+ */
6
+ 'use strict'
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Rule Definition
10
+ //------------------------------------------------------------------------------
11
+ const utils = require('../utils')
12
+ function commonFunction(value, list) {
13
+ const props = value.properties
14
+ props.forEach((item) => {
15
+ if (
16
+ item.type === 'SpreadElement' &&
17
+ item.argument &&
18
+ item.argument.arguments &&
19
+ item.argument.arguments[0] &&
20
+ item.argument.arguments[0].elements
21
+ ) {
22
+ const args = item.argument.arguments[0].elements
23
+ args.forEach((item) => {
24
+ list.add(item.value)
25
+ })
26
+ } else {
27
+ list.add(item.key.name)
28
+ }
29
+ })
30
+ }
31
+ function handleInitData(current, propsSet, parentName) {
32
+ current.forEach((item) => {
33
+ const currentName = item.key.name
34
+ if (currentName) {
35
+ let name = currentName
36
+ if (parentName) {
37
+ name = `${parentName}.${currentName}`
38
+ }
39
+ propsSet.add(name)
40
+ }
41
+ if (item.value.type === 'ObjectExpression' && item.value.properties) {
42
+ let pre = currentName
43
+ if (parentName) {
44
+ pre = `${parentName}.${currentName}`
45
+ }
46
+ handleInitData(item.value.properties, propsSet, pre)
47
+ }
48
+ })
49
+ }
50
+
51
+ function checkInInitData(
52
+ computedSet,
53
+ propsSet,
54
+ context,
55
+ node,
56
+ nodeName,
57
+ hasInitData
58
+ ) {
59
+ if (hasInitData === 1 && nodeName) {
60
+ // 属性值存在 || 说明有兜底,跳过检测
61
+ if (nodeName.includes('||')) return
62
+ // 检测当前属性值在initData 和 computedSet 导出情况,computedSet 返回不会解构出来,做一个兼容
63
+ if (!propsSet.has(nodeName) && computedSet.has(nodeName.split('.')[0])) {
64
+ context.report({
65
+ node,
66
+ messageId: 'unexpected',
67
+ data: {
68
+ name: nodeName
69
+ }
70
+ })
71
+ }
72
+ }
73
+ }
74
+ function checkInitData(
75
+ computedSet,
76
+ propsSet,
77
+ hasInitData,
78
+ context,
79
+ node,
80
+ nodeName
81
+ ) {
82
+ if (
83
+ computedSet.has(nodeName) &&
84
+ !propsSet.has(nodeName) &&
85
+ hasInitData === 2
86
+ ) {
87
+ context.report({
88
+ node,
89
+ messageId: 'missingValue',
90
+ data: {
91
+ name: nodeName
92
+ }
93
+ })
94
+ }
95
+ }
96
+ /** @type {import('eslint').Rule.RuleModule} */
97
+ module.exports = {
98
+ meta: {
99
+ type: 'suggestion', // `problem`, `suggestion`, or `layout`
100
+ docs: {
101
+ description: 'initData检测',
102
+ recommended: false,
103
+ url: null // URL to the documentation page for this rule
104
+ },
105
+ fixable: null, // Or `code` or `whitespace`
106
+ schema: [], // Add a schema if the rule has options
107
+ messages: {
108
+ missingValue:
109
+ "Missing 'initData' but the data {{name}} used for property.",
110
+ unexpected:
111
+ "The data '{{name}}' isn't expose in initData but used for property."
112
+ }
113
+ },
114
+ create(context) {
115
+ // 收集一下initData的属性
116
+ const propsSet = new Set([])
117
+ // 收集computed属性
118
+ const computedSet = new Set([])
119
+ // 忽略的标签类型
120
+ const ignoreElementTypes = [
121
+ 'view',
122
+ 'text',
123
+ 'image',
124
+ 'audio',
125
+ 'video',
126
+ 'button',
127
+ 'input',
128
+ 'navigator',
129
+ 'icon',
130
+ 'picker',
131
+ 'picker-item',
132
+ 'block',
133
+ 'scroll-view',
134
+ 'swiper',
135
+ 'swiper-item',
136
+ 'label',
137
+ 'form',
138
+ 'checkbox',
139
+ 'checkbox-group',
140
+ 'radio',
141
+ 'radio-group',
142
+ 'switch'
143
+ ]
144
+ const ignoreAttributeTypes = [
145
+ 'wx:if',
146
+ 'wx:else',
147
+ 'bindtap',
148
+ 'catchtap',
149
+ 'wx:for',
150
+ 'wx:ref',
151
+ 'wx:key',
152
+ 'wx:for-item',
153
+ 'class',
154
+ 'style',
155
+ 'hover-class',
156
+ 'src'
157
+ ]
158
+ // 全局是否有initData 初始值:0 ,存在: 1,不存在: 2
159
+ let hasInitData = 0
160
+ return utils.defineTemplateBodyVisitor(
161
+ context,
162
+ {
163
+ // VExpressionContainer(node) {},
164
+ VAttribute(node) {
165
+ const parent = node.parent
166
+ if (!ignoreElementTypes.includes(parent.name)) {
167
+ if (
168
+ !ignoreAttributeTypes.includes(node.key.name) &&
169
+ node.value &&
170
+ node.value.value &&
171
+ node.value.value.startsWith('{{')
172
+ ) {
173
+ const reg = /(?<={{).*?(?=}})/
174
+ checkInInitData(
175
+ computedSet,
176
+ propsSet,
177
+ context,
178
+ node,
179
+ node.value.value.match(reg)[0],
180
+ hasInitData
181
+ )
182
+ checkInitData(
183
+ computedSet,
184
+ propsSet,
185
+ hasInitData,
186
+ context,
187
+ node,
188
+ node.value.value.match(reg)[0]
189
+ )
190
+ }
191
+ }
192
+ }
193
+ },
194
+ {
195
+ Program(node) {
196
+ if (!utils.isScriptSetup(context)) return
197
+ const body = node.body
198
+ if (body) {
199
+ body.forEach((item) => {
200
+ if (
201
+ item.type === 'ExpressionStatement' &&
202
+ item.expression &&
203
+ item.expression.type === 'CallExpression' &&
204
+ item.expression.callee.name === 'defineOptions' &&
205
+ item.expression.arguments
206
+ ) {
207
+ item.expression.arguments.forEach((sub) => {
208
+ if (sub.type === 'ObjectExpression' && sub.properties) {
209
+ sub.properties.forEach((val) => {
210
+ if (val.key.name === 'initData') {
211
+ hasInitData = 1
212
+ }
213
+ })
214
+ }
215
+ })
216
+ if (hasInitData === 0) {
217
+ hasInitData = 2
218
+ }
219
+ } else {
220
+ hasInitData = 2
221
+ }
222
+ })
223
+ }
224
+ },
225
+ CallExpression(node) {
226
+ if (utils.isScriptSetup(context)) {
227
+ // setup 直接收集 defineExpose 的值
228
+ if (node.callee.name === 'defineExpose') {
229
+ commonFunction(node.arguments[0], computedSet)
230
+ }
231
+ } else {
232
+ if (node.callee.name !== 'createComponent') return
233
+ const properties = node.arguments[0].properties
234
+ if (!properties) return
235
+ properties.forEach((element) => {
236
+ if (element.key.name === 'initData') {
237
+ hasInitData = 1
238
+ }
239
+ })
240
+ if (hasInitData === 0) {
241
+ hasInitData = 2
242
+ }
243
+ }
244
+ },
245
+ ObjectExpression(node) {
246
+ const parent = node.parent
247
+ if (parent && parent.type === 'CallExpression') {
248
+ if (parent.callee.name === 'defineOptions') {
249
+ if (node.properties && Array.isArray(node.properties)) {
250
+ node.properties.forEach((item) => {
251
+ if (item.key.name === 'initData') {
252
+ handleInitData(item.value.properties, propsSet)
253
+ }
254
+ })
255
+ }
256
+ }
257
+ }
258
+ },
259
+ Property(node) {
260
+ if (node.key.name === 'computed') {
261
+ commonFunction(node.value, computedSet)
262
+ }
263
+ if (node.key.name === 'initData') {
264
+ handleInitData(node.value.properties, propsSet)
265
+ }
266
+ }
267
+ }
268
+ )
269
+ }
270
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "eslint-plugin-mpx",
3
- "version": "0.2.9",
3
+ "version": "0.2.10-beta",
4
4
  "description": "Official ESLint plugin for Mpx.js",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
7
7
  "start": "npm run test:base -- --watch --growl",
8
8
  "test": "mocha \"tests/lib/**/*.js\" --reporter dot",
9
- "test:only": "mocha \"tests/lib/rules/valid-template-quote.js\" --reporter dot",
9
+ "test:only": "mocha \"tests/lib/rules/valid-initdata.js\" --reporter dot",
10
10
  "debug": "mocha --inspect \"tests/lib/**/*.js\" --reporter dot --timeout 60000",
11
11
  "cover": "npm run cover:test && npm run cover:report",
12
12
  "cover:test": "nyc npm run test -- --timeout 60000",