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.
|
|
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-
|
|
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",
|