@adyen/eslint-plugin-bento 2.14.0 → 2.16.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.
Files changed (19) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/package.json +1 -1
  3. package/rules/deprecation-bento-timeline-item-variant-prop/README.md +13 -5
  4. package/rules/deprecation-bento-timeline-item-variant-prop/__tests__/deprecation-bento-timeline-item-variant-prop.vue +2 -2
  5. package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.integration.test.ts +6 -2
  6. package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.js +61 -12
  7. package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.test.ts +87 -12
  8. package/rules/deprecation-components-error-prop/README.md +143 -7
  9. package/rules/deprecation-components-error-prop/__tests__/eslint.config.js +1 -1
  10. package/rules/deprecation-components-error-prop/deprecation-components-error-prop.integration.test.ts +14 -10
  11. package/rules/deprecation-components-error-prop/deprecation-components-error-prop.js +20 -30
  12. package/rules/deprecation-components-error-prop/deprecation-components-error-prop.test.ts +69 -36
  13. package/rules/deprecation-components-has-error-prop/README.md +107 -6
  14. package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.integration.test.ts +10 -2
  15. package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.js +18 -24
  16. package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.test.ts +58 -69
  17. package/rules/deprecation-components-input-emit/README.md +170 -3
  18. package/rules/deprecation-components-input-emit/deprecation-components-input-emit.integration.test.ts +9 -1
  19. package/rules/deprecation-components-input-emit/deprecation-components-input-emit.js +9 -1
@@ -46,74 +46,107 @@ describe('@adyen/bento/deprecation-components-error-prop', () => {
46
46
  },
47
47
  ],
48
48
  invalid: [
49
- {
50
- name: 'Invalid: autofix disabled (explicit false)',
51
- filename: 'test.vue',
52
- code: `<template><bento-dropdown error="val" /></template>`,
53
- output: null,
54
- options: [{ autofix: false }],
55
- errors: [{ messageId: 'deprecation' }],
56
- },
57
- {
58
- name: 'Invalid: autofix disabled (no options)',
59
- filename: 'test.vue',
60
- code: `<template><bento-dropdown :error="val" /></template>`,
61
- output: null,
62
- errors: [{ messageId: 'deprecation' }],
63
- },
64
49
  // bento-dropdown: Static
65
50
  {
66
51
  name: 'Invalid: Static prop on bento-dropdown',
67
52
  filename: 'test.vue',
68
53
  code: `<template><bento-dropdown error="val" /></template>`,
69
- output: `<template><bento-dropdown error-message="val" /></template>`,
70
- options: [{ autofix: true }],
71
- errors: [{ messageId: 'deprecation' }],
54
+ errors: [
55
+ {
56
+ messageId: 'deprecation',
57
+ suggestions: [
58
+ {
59
+ messageId: 'suggestReplace',
60
+ output: `<template><bento-dropdown error-message="val" /></template>`,
61
+ },
62
+ ],
63
+ },
64
+ ],
72
65
  },
73
- // bento-dropdown: Shorthand
66
+ // bento-dropdown: Dynamic
74
67
  {
75
68
  name: 'Invalid: Dynamic prop on bento-dropdown',
76
69
  filename: 'test.vue',
77
70
  code: `<template><bento-dropdown :error="val" /></template>`,
78
- output: `<template><bento-dropdown :error-message="val" /></template>`,
79
- options: [{ autofix: true }],
80
- errors: [{ messageId: 'deprecation' }],
71
+ errors: [
72
+ {
73
+ messageId: 'deprecation',
74
+ suggestions: [
75
+ {
76
+ messageId: 'suggestReplace',
77
+ output: `<template><bento-dropdown :error-message="val" /></template>`,
78
+ },
79
+ ],
80
+ },
81
+ ],
81
82
  },
82
83
  // bento-input-field: Static
83
84
  {
84
85
  name: 'Invalid: Static prop on bento-input-field',
85
86
  filename: 'test.vue',
86
87
  code: `<template><bento-input-field error="val" /></template>`,
87
- output: `<template><bento-input-field error-message="val" /></template>`,
88
- options: [{ autofix: true }],
89
- errors: [{ messageId: 'deprecation' }],
88
+ errors: [
89
+ {
90
+ messageId: 'deprecation',
91
+ suggestions: [
92
+ {
93
+ messageId: 'suggestReplace',
94
+ output: `<template><bento-input-field error-message="val" /></template>`,
95
+ },
96
+ ],
97
+ },
98
+ ],
90
99
  },
91
- // bento-input-field: Shorthand
100
+ // bento-input-field: Dynamic
92
101
  {
93
102
  name: 'Invalid: Dynamic prop on bento-input-field',
94
103
  filename: 'test.vue',
95
104
  code: `<template><bento-input-field :error="val" /></template>`,
96
- output: `<template><bento-input-field :error-message="val" /></template>`,
97
- options: [{ autofix: true }],
98
- errors: [{ messageId: 'deprecation' }],
105
+ errors: [
106
+ {
107
+ messageId: 'deprecation',
108
+ suggestions: [
109
+ {
110
+ messageId: 'suggestReplace',
111
+ output: `<template><bento-input-field :error-message="val" /></template>`,
112
+ },
113
+ ],
114
+ },
115
+ ],
99
116
  },
100
117
  // bento-input-field-phone-number: Static
101
118
  {
102
119
  name: 'Invalid: Static prop on bento-input-field-phone-number',
103
120
  filename: 'test.vue',
104
121
  code: `<template><bento-input-field-phone-number error="val" /></template>`,
105
- output: `<template><bento-input-field-phone-number error-message="val" /></template>`,
106
- options: [{ autofix: true }],
107
- errors: [{ messageId: 'deprecation' }],
122
+ errors: [
123
+ {
124
+ messageId: 'deprecation',
125
+ suggestions: [
126
+ {
127
+ messageId: 'suggestReplace',
128
+ output: `<template><bento-input-field-phone-number error-message="val" /></template>`,
129
+ },
130
+ ],
131
+ },
132
+ ],
108
133
  },
109
- // bento-input-field-phone-number: Shorthand
134
+ // bento-input-field-phone-number: Dynamic
110
135
  {
111
136
  name: 'Invalid: Dynamic prop on bento-input-field-phone-number',
112
137
  filename: 'test.vue',
113
138
  code: `<template><bento-input-field-phone-number :error="val" /></template>`,
114
- output: `<template><bento-input-field-phone-number :error-message="val" /></template>`,
115
- options: [{ autofix: true }],
116
- errors: [{ messageId: 'deprecation' }],
139
+ errors: [
140
+ {
141
+ messageId: 'deprecation',
142
+ suggestions: [
143
+ {
144
+ messageId: 'suggestReplace',
145
+ output: `<template><bento-input-field-phone-number :error-message="val" /></template>`,
146
+ },
147
+ ],
148
+ },
149
+ ],
117
150
  },
118
151
  ],
119
152
  });
@@ -7,28 +7,129 @@ The `hasError` prop in the following components is deprecated:
7
7
  - `bento-checkbox-group`
8
8
  - `bento-radio-group`
9
9
 
10
- Please use `errorMessage` instead.
10
+ Please use `error-message` instead.
11
+
12
+ > **Note:** The `has-error` prop is a `boolean` that only toggles error styling, while `error-message` is a `string`
13
+ > that both displays a message and applies error styling. A direct rename is not type-safe — you must also update the
14
+ > bound value from a boolean to an error message string.
15
+
16
+ | Deprecated prop | Replacement prop | Type change |
17
+ | --------------- | ---------------- | -------------------- |
18
+ | `has-error` | `error-message` | `boolean` → `string` |
11
19
 
12
20
  ## Rule Details
13
21
 
14
- This rule reports usages of the deprecated item.
22
+ This rule reports usages of the deprecated `has-error` prop and provides an IDE suggestion (not an autofix) to rename
23
+ it.
15
24
 
16
25
  ### ❌ Incorrect
17
26
 
18
27
  ```html
19
- <bento-checkbox-group has-error="value" /> <bento-checkbox-group :has-error="value" />
28
+ <!-- Static boolean -->
29
+ <bento-checkbox-group :has-error="true" :items="items" label="Permissions" />
30
+
31
+ <!-- Dynamic binding -->
32
+ <bento-checkbox-group :has-error="hasError" :items="items" label="Permissions" />
20
33
  ```
21
34
 
22
35
  ```html
23
- <bento-radio-group has-error="value" /> <bento-radio-group :has-error="value" />
36
+ <bento-radio-group :has-error="true" :items="items" label="Priority" />
37
+
38
+ <bento-radio-group :has-error="hasError" :items="items" label="Priority" />
24
39
  ```
25
40
 
26
41
  ### ✅ Correct
27
42
 
28
43
  ```html
29
- <bento-checkbox-group errorMessage="value" />
44
+ <!-- Group-level error: pass a string message to error-message -->
45
+ <bento-checkbox-group error-message="Select at least one option" :items="items" label="Permissions" />
46
+
47
+ <!-- Dynamic error message driven by validation -->
48
+ <bento-checkbox-group :error-message="errorMessage" :items="items" label="Permissions" />
49
+ ```
50
+
51
+ ```html
52
+ <bento-radio-group error-message="Please select an option" :items="items" label="Priority" />
53
+
54
+ <bento-radio-group :error-message="errorMessage" :items="items" label="Priority" />
30
55
  ```
31
56
 
57
+ ## Migration Examples
58
+
59
+ ### Before — static boolean
60
+
61
+ ```html
62
+ <template>
63
+ <bento-checkbox-group :has-error="true" :items="items" label="Toppings" />
64
+ </template>
65
+ ```
66
+
67
+ ### After — static error message
68
+
69
+ ```html
70
+ <template>
71
+ <bento-checkbox-group error-message="Select at least one topping" :items="items" label="Toppings" />
72
+ </template>
73
+ ```
74
+
75
+ ### Before — dynamic validation
76
+
32
77
  ```html
33
- <bento-radio-group errorMessage="value" />
78
+ <template>
79
+ <bento-checkbox-group :has-error="hasError" :items="items" label="Toppings" />
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ const hasError = ref(false);
84
+
85
+ const validate = () => {
86
+ hasError.value = selectedToppings.value.length === 0;
87
+ };
88
+ </script>
89
+ ```
90
+
91
+ ### After — dynamic validation with error message
92
+
93
+ ```html
94
+ <template>
95
+ <bento-checkbox-group :error-message="errorMessage" :items="items" label="Toppings" />
96
+ </template>
97
+
98
+ <script setup lang="ts">
99
+ const errorMessage = ref<string | null>(null);
100
+
101
+ const validate = () => {
102
+ errorMessage.value = selectedToppings.value.length === 0 ? 'Select at least one topping' : null;
103
+ };
104
+ </script>
105
+ ```
106
+
107
+ ### Before — item-level `hasError`
108
+
109
+ ```html
110
+ <template>
111
+ <bento-checkbox-group :items="items" label="Permissions" />
112
+ </template>
113
+
114
+ <script setup lang="ts">
115
+ const items = [
116
+ { value: 'read', label: 'Read', hasError: true },
117
+ { value: 'write', label: 'Write' },
118
+ ];
119
+ </script>
120
+ ```
121
+
122
+ ### After — item-level `errorMessage`
123
+
124
+ ```html
125
+ <template>
126
+ <bento-checkbox-group :items="items" label="Permissions" />
127
+ </template>
128
+
129
+ <script setup lang="ts">
130
+ const items = [
131
+ { value: 'read', label: 'Read', errorMessage: 'Read permission is required' },
132
+ { value: 'write', label: 'Write' },
133
+ ];
134
+ </script>
34
135
  ```
@@ -20,10 +20,18 @@ describe('@adyen/bento/deprecation-components-has-error-prop', () => {
20
20
  severity: 1,
21
21
 
22
22
  messageId: 'deprecation',
23
- message: `The "has-error" prop is deprecated. Please use "error-message" instead.`,
23
+ message: `The "has-error" prop is deprecated. Use "error-message" instead. Note that "has-error" accepted a boolean, but "error-message" expects a string, so update the value to an error message.`,
24
+ suggestions: expect.arrayContaining([
25
+ expect.objectContaining({
26
+ messageId: 'suggestReplace',
27
+ fix: expect.objectContaining({
28
+ text: expect.stringContaining('error-message'),
29
+ }),
30
+ }),
31
+ ]),
24
32
  });
25
33
 
26
- // Without autofix option, no fix should be present
34
+ // The rule should provide a suggestion, not an autofix, because the replacement changes the expected value type.
27
35
  expect(result[0].messages[0].fix).toBeUndefined();
28
36
  });
29
37
  });
@@ -18,27 +18,15 @@ module.exports = {
18
18
  recommended: true,
19
19
  },
20
20
  messages: {
21
- deprecation: `The "has-error" prop is deprecated. Please use "error-message" instead.`,
21
+ deprecation: `The "has-error" prop is deprecated. Use "error-message" instead. Note that "has-error" accepted a boolean, but "error-message" expects a string, so update the value to an error message.`,
22
+ suggestReplace: `Replace "has-error" with "error-message". Remember to update the value from a boolean to a string error message.`,
22
23
  },
23
- fixable: 'code',
24
- schema: [
25
- {
26
- type: 'object',
27
- properties: {
28
- autofix: {
29
- type: 'boolean',
30
- default: false,
31
- },
32
- },
33
- additionalProperties: false,
34
- },
35
- ],
24
+ hasSuggestions: true,
25
+ schema: [],
36
26
  },
37
27
 
38
28
  /** @param {RuleContext} context */
39
29
  create(context) {
40
- const options = context.options[0] || {};
41
- const autofix = options.autofix === true;
42
30
  /* ------------------------------------------------ */
43
31
  /* CASE 2: PROP DEPRECATION (Multiple Components) */
44
32
  /* ------------------------------------------------ */
@@ -50,11 +38,14 @@ module.exports = {
50
38
  context.report({
51
39
  node,
52
40
  messageId: 'deprecation',
53
- ...(autofix && {
54
- fix(fixer) {
55
- return fixer.replaceText(node.key, 'error-message');
41
+ suggest: [
42
+ {
43
+ messageId: 'suggestReplace',
44
+ fix(fixer) {
45
+ return fixer.replaceText(node.key, 'error-message');
46
+ },
56
47
  },
57
- }),
48
+ ],
58
49
  });
59
50
  },
60
51
 
@@ -65,11 +56,14 @@ module.exports = {
65
56
  context.report({
66
57
  node,
67
58
  messageId: 'deprecation',
68
- ...(autofix && {
69
- fix(fixer) {
70
- return fixer.replaceText(node.key.argument, 'error-message');
59
+ suggest: [
60
+ {
61
+ messageId: 'suggestReplace',
62
+ fix(fixer) {
63
+ return fixer.replaceText(node.key.argument, 'error-message');
64
+ },
71
65
  },
72
- }),
66
+ ],
73
67
  });
74
68
  },
75
69
  });
@@ -37,96 +37,85 @@ describe('@adyen/bento/deprecation-components-has-error-prop', () => {
37
37
  },
38
38
  ],
39
39
  invalid: [
40
- // bento-checkbox-group: Static
41
40
  {
42
41
  name: 'Invalid: Static prop on bento-checkbox-group',
43
42
  filename: 'test.vue',
44
43
  code: `<template><bento-checkbox-group has-error="val" /></template>`,
45
- errors: [{ messageId: 'deprecation' }],
44
+ errors: [
45
+ {
46
+ messageId: 'deprecation',
47
+ suggestions: [
48
+ {
49
+ messageId: 'suggestReplace',
50
+ output: `<template><bento-checkbox-group error-message="val" /></template>`,
51
+ },
52
+ ],
53
+ },
54
+ ],
46
55
  },
47
- // bento-checkbox-group: Shorthand
48
56
  {
49
- name: 'Invalid: Dynamic prop on bento-checkbox-group',
57
+ name: 'Invalid: Dynamic shorthand prop on bento-checkbox-group',
50
58
  filename: 'test.vue',
51
59
  code: `<template><bento-checkbox-group :has-error="val" /></template>`,
52
- errors: [{ messageId: 'deprecation' }],
60
+ errors: [
61
+ {
62
+ messageId: 'deprecation',
63
+ suggestions: [
64
+ {
65
+ messageId: 'suggestReplace',
66
+ output: `<template><bento-checkbox-group :error-message="val" /></template>`,
67
+ },
68
+ ],
69
+ },
70
+ ],
53
71
  },
54
- // bento-radio-group: Static
55
72
  {
56
73
  name: 'Invalid: Static prop on bento-radio-group',
57
74
  filename: 'test.vue',
58
75
  code: `<template><bento-radio-group has-error="val" /></template>`,
59
- errors: [{ messageId: 'deprecation' }],
76
+ errors: [
77
+ {
78
+ messageId: 'deprecation',
79
+ suggestions: [
80
+ {
81
+ messageId: 'suggestReplace',
82
+ output: `<template><bento-radio-group error-message="val" /></template>`,
83
+ },
84
+ ],
85
+ },
86
+ ],
60
87
  },
61
- // bento-radio-group: Shorthand
62
88
  {
63
- name: 'Invalid: Dynamic prop on bento-radio-group',
89
+ name: 'Invalid: Dynamic shorthand prop on bento-radio-group',
64
90
  filename: 'test.vue',
65
91
  code: `<template><bento-radio-group :has-error="val" /></template>`,
66
- errors: [{ messageId: 'deprecation' }],
92
+ errors: [
93
+ {
94
+ messageId: 'deprecation',
95
+ suggestions: [
96
+ {
97
+ messageId: 'suggestReplace',
98
+ output: `<template><bento-radio-group :error-message="val" /></template>`,
99
+ },
100
+ ],
101
+ },
102
+ ],
67
103
  },
68
- ],
69
- });
70
-
71
- /* ------------------------------------------------ */
72
- /* AUTOFIX TESTS */
73
- /* ------------------------------------------------ */
74
- ruleTester.run('deprecation-components-has-error-prop (autofix enabled)', deprecationComponentsHasErrorProp, {
75
- valid: [
76
104
  {
77
- name: 'Valid: error-message prop on bento-checkbox-group (autofix enabled)',
105
+ name: 'Invalid: Dynamic longhand prop on bento-radio-group',
78
106
  filename: 'test.vue',
79
- options: [{ autofix: true }],
80
- code: `<template><bento-checkbox-group error-message="val" /></template>`,
81
- },
82
- ],
83
- invalid: [
84
- {
85
- name: 'Autofix: static prop on bento-checkbox-group',
86
- filename: 'test.vue',
87
- options: [{ autofix: true }],
88
- code: `<template><bento-checkbox-group has-error="val" /></template>`,
89
- output: `<template><bento-checkbox-group error-message="val" /></template>`,
90
- errors: [{ messageId: 'deprecation' }],
91
- },
92
- {
93
- name: 'Autofix: dynamic prop on bento-checkbox-group',
94
- filename: 'test.vue',
95
- options: [{ autofix: true }],
96
- code: `<template><bento-checkbox-group :has-error="val" /></template>`,
97
- output: `<template><bento-checkbox-group :error-message="val" /></template>`,
98
- errors: [{ messageId: 'deprecation' }],
99
- },
100
- {
101
- name: 'Autofix: static prop on bento-radio-group',
102
- filename: 'test.vue',
103
- options: [{ autofix: true }],
104
- code: `<template><bento-radio-group has-error="val" /></template>`,
105
- output: `<template><bento-radio-group error-message="val" /></template>`,
106
- errors: [{ messageId: 'deprecation' }],
107
- },
108
- {
109
- name: 'Autofix: dynamic prop on bento-radio-group',
110
- filename: 'test.vue',
111
- options: [{ autofix: true }],
112
- code: `<template><bento-radio-group :has-error="val" /></template>`,
113
- output: `<template><bento-radio-group :error-message="val" /></template>`,
114
- errors: [{ messageId: 'deprecation' }],
115
- },
116
- {
117
- name: 'Autofix: v-bind longhand on bento-radio-group',
118
- filename: 'test.vue',
119
- options: [{ autofix: true }],
120
107
  code: `<template><bento-radio-group v-bind:has-error="val" /></template>`,
121
- output: `<template><bento-radio-group v-bind:error-message="val" /></template>`,
122
- errors: [{ messageId: 'deprecation' }],
123
- },
124
- {
125
- name: 'Autofix: does not fix when autofix is false',
126
- filename: 'test.vue',
127
- options: [{ autofix: false }],
128
- code: `<template><bento-checkbox-group has-error="val" /></template>`,
129
- errors: [{ messageId: 'deprecation' }],
108
+ errors: [
109
+ {
110
+ messageId: 'deprecation',
111
+ suggestions: [
112
+ {
113
+ messageId: 'suggestReplace',
114
+ output: `<template><bento-radio-group v-bind:error-message="val" /></template>`,
115
+ },
116
+ ],
117
+ },
118
+ ],
130
119
  },
131
120
  ],
132
121
  });