@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 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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/eslint-plugin",
3
- "version": "19.3.0",
3
+ "version": "19.4.0",
4
4
  "description": "GitLab package for our custom eslint rules",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {