@gitlab/eslint-plugin 19.3.0 → 19.4.0
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.
- package/CHANGELOG.md +8 -0
- package/docs/rules/vtu-no-wrapper-vm.md +53 -0
- package/docs/rules.md +1 -0
- package/lib/index.js +1 -0
- package/lib/rules/vtu-no-wrapper-vm.js +111 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# [19.4.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.3.0...v19.4.0) (2024-01-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **vtu-no-wrapper-vm:** Improve reporting with $nextTick ([0cb92b8](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/0cb92b870feeea8d889ceec68bb30145b584c823))
|
|
7
|
+
* **vtu-no-wrapper-vm:** Prevent saving off a reference to wrapper.vm ([96a59b0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/commit/96a59b066bed3cca5bc62dcfaeb7c26160eda92a))
|
|
8
|
+
|
|
1
9
|
# [19.3.0](https://gitlab.com/gitlab-org/frontend/eslint-plugin/compare/v19.2.0...v19.3.0) (2023-12-05)
|
|
2
10
|
|
|
3
11
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# @gitlab/vtu-no-wrapper-vm
|
|
2
|
+
|
|
3
|
+
Prevent direct access to `vm` internals for `@vue/test-utils` wrappers.
|
|
4
|
+
This is helpful for writing maintainable Vue tests.
|
|
5
|
+
|
|
6
|
+
See https://docs.gitlab.com/ee/development/testing_guide/frontend_testing.html#what-and-how-to-test
|
|
7
|
+
|
|
8
|
+
## Rule Details
|
|
9
|
+
|
|
10
|
+
### Examples of **incorrect** code for this rule
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
it('calls spy when foo-ed', () => {
|
|
14
|
+
// !! Direct access to `vm` properties !!
|
|
15
|
+
wrapper.vm.onFoo();
|
|
16
|
+
|
|
17
|
+
expect(spy).toHaveBeenCalled();
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Examples of **correct** code for this rule
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
it('calls spy when foo-ed', () => {
|
|
25
|
+
wrapper.find('button').trigger('click');
|
|
26
|
+
|
|
27
|
+
expect(spy).toHaveBeenCalled();
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Options
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"@gitlab/vtu-no-wrapper-vm": [
|
|
36
|
+
"error",
|
|
37
|
+
{
|
|
38
|
+
"allow": ["$emit"]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `allow` contains a list of allowable property names that can be directly
|
|
45
|
+
accessed under a vm.
|
|
46
|
+
|
|
47
|
+
## Related Rules
|
|
48
|
+
|
|
49
|
+
N/A.
|
|
50
|
+
|
|
51
|
+
## When Not To Use It
|
|
52
|
+
|
|
53
|
+
Don't use it if you don't want it.
|
package/docs/rules.md
CHANGED
|
@@ -9,6 +9,7 @@ Available rules:
|
|
|
9
9
|
- [require-i18n-strings](./rules/require-i18n-strings.md): Detect a string which has been hard coded and requires externalization.
|
|
10
10
|
- [require-valid-i18n-helpers](./rules/require-valid-i18n-helpers.md): Enforces valid usage of translation helpers in JavaScript.
|
|
11
11
|
- [vtu-no-explicit-wrapper-destroy](./rules/vtu-no-explicit-wrapper-destroy.md): Prevents redundant destroy calls and null asignment
|
|
12
|
+
- [vtu-no-wrapper-vm](./rules/vtu-no-wrapper-vm.md): Prevent direct access to `vm` internals for `@vue/test-utils` wrappers.
|
|
12
13
|
- [vue-no-data-toggle](./rules/vue-no-data-toggle.md): Restrict the use of `data-toggle` bootstrap behaviors within Vue templates
|
|
13
14
|
- [vue-no-new-non-primitive-in-template](./rules/vue-no-new-non-primitive-in-template.md): Prevents non-primitive values from being declared in templates
|
|
14
15
|
- [vue-prefer-dollar-scopedslots](./rules/vue-prefer-dollar-scopedslots.md): Prefer $scopedSlots over $slots for Vue 2.x.
|
package/lib/index.js
CHANGED
|
@@ -8,6 +8,7 @@ module.exports = {
|
|
|
8
8
|
'require-i18n-strings': require('./rules/require-i18n-strings.js'),
|
|
9
9
|
'require-valid-i18n-helpers': require('./rules/require-valid-i18n-helpers.js'),
|
|
10
10
|
'vtu-no-explicit-wrapper-destroy': require('./rules/vtu-no-explicit-wrapper-destroy.js'),
|
|
11
|
+
'vtu-no-wrapper-vm': require('./rules/vtu-no-wrapper-vm.js'),
|
|
11
12
|
'vue-no-data-toggle': require('./rules/vue-no-data-toggle.js'),
|
|
12
13
|
'vue-no-new-non-primitive-in-template': require('./rules/vue-no-new-non-primitive-in-template.js'),
|
|
13
14
|
'vue-prefer-dollar-scopedslots': require('./rules/vue-prefer-dollar-scopedslots.js'),
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// ------------------------------------------------------------------------------
|
|
2
|
+
// Requirements
|
|
3
|
+
// ------------------------------------------------------------------------------
|
|
4
|
+
const { DOCS_BASE_URL } = require('../constants');
|
|
5
|
+
|
|
6
|
+
// ------------------------------------------------------------------------------
|
|
7
|
+
// Helpers
|
|
8
|
+
// ------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
const getMemberName = (node) => {
|
|
11
|
+
if (node.type === 'Identifier') {
|
|
12
|
+
return node.name;
|
|
13
|
+
}
|
|
14
|
+
if (node.type === 'Literal') {
|
|
15
|
+
return node.value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const isMemberName = (node, name) => {
|
|
22
|
+
return getMemberName(node) === name;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const isVmReference = (node) => {
|
|
26
|
+
if (node.type === 'MemberExpression') {
|
|
27
|
+
return isMemberName(node.property, 'vm');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const isAllowableVmProperty = (node, allowable) => {
|
|
34
|
+
const name = getMemberName(node);
|
|
35
|
+
|
|
36
|
+
if (!name) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return allowable.has(name);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ------------------------------------------------------------------------------
|
|
44
|
+
// Rule Definition
|
|
45
|
+
// ------------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param {Set} allowable
|
|
50
|
+
*/
|
|
51
|
+
const getErrorMessage = (property, allowable) => {
|
|
52
|
+
if (getMemberName(property) === '$nextTick') {
|
|
53
|
+
return `Do not access \`vm\` internals directly. For \`$nextTick\`, import \`nextTick\` directly from the Vue package.`;
|
|
54
|
+
}
|
|
55
|
+
if (allowable.size) {
|
|
56
|
+
const part = Array.from(allowable).join(', ');
|
|
57
|
+
|
|
58
|
+
return `Do not access \`vm\` internals directly. Only the following properties are allowed: ${part}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 'Do not access `vm` internals directly.';
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = {
|
|
65
|
+
meta: {
|
|
66
|
+
type: 'error',
|
|
67
|
+
docs: {
|
|
68
|
+
description: 'Prevent direct access to `vm` internals for `@vue/test-utils` wrappers.',
|
|
69
|
+
category: undefined,
|
|
70
|
+
url: DOCS_BASE_URL + '/vtu-no-wrapper-vm.md',
|
|
71
|
+
},
|
|
72
|
+
schema: [
|
|
73
|
+
{
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
allow: {
|
|
77
|
+
type: 'array',
|
|
78
|
+
items: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
additionalProperties: false,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
create(context) {
|
|
88
|
+
const options = context.options[0] || {};
|
|
89
|
+
const allowable = new Set(options.allow);
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
AssignmentExpression(node) {
|
|
93
|
+
if (isVmReference(node.right)) {
|
|
94
|
+
context.report({
|
|
95
|
+
node: node.right,
|
|
96
|
+
message:
|
|
97
|
+
'Do not access `vm` internals directly or work around this by saving a reference to `vm`.',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
MemberExpression(node) {
|
|
102
|
+
if (isVmReference(node.object) && !isAllowableVmProperty(node.property, allowable)) {
|
|
103
|
+
context.report({
|
|
104
|
+
node,
|
|
105
|
+
message: getErrorMessage(node.property, allowable),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
};
|