@adyen/eslint-plugin-bento 2.23.0 → 2.24.1
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 +23 -0
- package/README.md +31 -15
- package/configs/vue-recommended.js +15 -0
- package/configs/vue-strict.js +15 -0
- package/index.js +3 -0
- package/package.json +1 -1
- package/rules/deprecation-bento-tag-variant-enum/README.md +69 -0
- package/rules/deprecation-bento-tag-variant-enum/deprecation-bento-tag-variant-enum.js +167 -0
- package/rules/vue-no-redundant-dialog-v-if/README.md +55 -0
- package/rules/vue-no-redundant-dialog-v-if/vue-no-redundant-dialog-v-if.js +150 -0
- package/rules/vue-no-use-bento-translation-overrides/README.md +14 -0
- package/rules/vue-no-use-bento-translation-overrides/vue-no-use-bento-translation-overrides.js +93 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/deprecation-bento-data-grid-cell-action-menu-item-handler.vue +0 -63
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.integration.test.ts +0 -24
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.test.ts +0 -116
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/deprecation-bento-date-range-picker-has-actions-prop.vue +0 -10
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/eslint.config.js +0 -29
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/deprecation-bento-date-range-picker-has-actions-prop.vue +0 -11
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/eslint.config.js +0 -29
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.integration.test.ts +0 -47
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.test.ts +0 -176
- package/rules/deprecation-bento-dropdown-size-prop/__tests__/deprecation-bento-dropdown-size-prop.vue +0 -9
- package/rules/deprecation-bento-dropdown-size-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-bento-dropdown-size-prop/deprecation-bento-dropdown-size-prop.integration.test.ts +0 -33
- package/rules/deprecation-bento-dropdown-size-prop/deprecation-bento-dropdown-size-prop.test.ts +0 -101
- package/rules/deprecation-bento-popover-modifiers-prop/__tests__/deprecation-bento-popover-modifiers-prop.vue +0 -9
- package/rules/deprecation-bento-popover-modifiers-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-bento-popover-modifiers-prop/deprecation-bento-popover-modifiers-prop.integration.test.ts +0 -24
- package/rules/deprecation-bento-popover-modifiers-prop/deprecation-bento-popover-modifiers-prop.test.ts +0 -109
- package/rules/deprecation-bento-timeline-item-variant-prop/__tests__/deprecation-bento-timeline-item-variant-prop.vue +0 -9
- package/rules/deprecation-bento-timeline-item-variant-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.integration.test.ts +0 -35
- package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.test.ts +0 -141
- package/rules/deprecation-components-aria-label-prop/__tests__/deprecation-components-aria-label-prop.vue +0 -25
- package/rules/deprecation-components-aria-label-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-components-aria-label-prop/deprecation-components-aria-label-prop.integration.test.ts +0 -36
- package/rules/deprecation-components-aria-label-prop/deprecation-components-aria-label-prop.test.ts +0 -194
- package/rules/deprecation-components-error-prop/__tests__/deprecation-components-error-prop.vue +0 -17
- package/rules/deprecation-components-error-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-components-error-prop/deprecation-components-error-prop.integration.test.ts +0 -41
- package/rules/deprecation-components-error-prop/deprecation-components-error-prop.test.ts +0 -153
- package/rules/deprecation-components-has-error-prop/__tests__/deprecation-components-has-error-prop.vue +0 -13
- package/rules/deprecation-components-has-error-prop/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.integration.test.ts +0 -37
- package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.test.ts +0 -122
- package/rules/deprecation-components-input-emit/__tests__/deprecation-components-input-emit.vue +0 -22
- package/rules/deprecation-components-input-emit/__tests__/eslint.config.js +0 -25
- package/rules/deprecation-components-input-emit/deprecation-components-input-emit.integration.test.ts +0 -43
- package/rules/deprecation-components-input-emit/deprecation-components-input-emit.test.ts +0 -320
- package/rules/deprecation-components-value-prop/__tests__/deprecation-components-value-prop.vue +0 -69
- package/rules/deprecation-components-value-prop/__tests__/eslint.config.js +0 -25
- package/rules/deprecation-components-value-prop/deprecation-components-value-prop.integration.test.ts +0 -37
- package/rules/deprecation-components-value-prop/deprecation-components-value-prop.test.ts +0 -480
- package/rules/deprecation-country-custom-usage/__tests__/deprecation-country-custom-usage.vue +0 -93
- package/rules/deprecation-country-custom-usage/__tests__/eslint.config.js +0 -25
- package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.integration.test.ts +0 -22
- package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.test.ts +0 -380
- package/rules/deprecation-currency-default-slot/__tests__/deprecation-currency-default-slot.vue +0 -7
- package/rules/deprecation-currency-default-slot/__tests__/eslint.config.js +0 -24
- package/rules/deprecation-currency-default-slot/deprecation-currency-default-slot.integration.test.ts +0 -29
- package/rules/deprecation-currency-default-slot/deprecation-currency-default-slot.test.ts +0 -136
- package/rules/deprecation-filter-bar-deprecated-props/__tests__/deprecation-filter-bar-deprecated-props.vue +0 -62
- package/rules/deprecation-filter-bar-deprecated-props/__tests__/eslint.config.js +0 -25
- package/rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props.integration.test.ts +0 -22
- package/rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props.test.ts +0 -492
- package/rules/deprecation-input-filter-dropdown-options/__tests__/deprecation-input-filter-dropdown-options.vue +0 -46
- package/rules/deprecation-input-filter-dropdown-options/__tests__/eslint.config.js +0 -26
- package/rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options.integration.test.ts +0 -27
- package/rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options.test.ts +0 -392
- package/rules/deprecation-tag-default-slot/__tests__/deprecation-tag-default-slot.vue +0 -5
- package/rules/deprecation-tag-default-slot/__tests__/eslint.config.js +0 -24
- package/rules/deprecation-tag-default-slot/deprecation-tag-default-slot.integration.test.ts +0 -29
- package/rules/deprecation-tag-default-slot/deprecation-tag-default-slot.test.ts +0 -163
- package/rules/tailwind-v3-to-bento/__tests__/eslint.config.js +0 -24
- package/rules/tailwind-v3-to-bento/__tests__/tailwind-v3-to-bento.vue +0 -15
- package/rules/tailwind-v3-to-bento/tailwind-v3-to-bento.integration.test.ts +0 -29
- package/rules/tailwind-v3-to-bento/tailwind-v3-to-bento.test.ts +0 -403
- package/rules/vue-old-spacer-tokens/__tests__/eslint.config.js +0 -24
- package/rules/vue-old-spacer-tokens/__tests__/vue-old-spacer-tokens.vue +0 -5
- package/rules/vue-old-spacer-tokens/vue-old-spacer-tokens.integration.test.ts +0 -29
- package/rules/vue-old-spacer-tokens/vue-old-spacer-tokens.test.ts +0 -77
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.24.1 (2026-09-09)
|
|
4
|
+
|
|
5
|
+
This was a version bump only for eslint to align it with other projects, there were no code changes.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## 2.24.0 (2026-09-09)
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
- added `useBentoTranslationOverrides` composable to override translated strings in vue 3 ([e0cb22fc0](https://github.com/Adyen/bento/commit/e0cb22fc0))
|
|
13
|
+
- added rule to deprecate `bento-tag` white variant ([20867ed09](https://github.com/Adyen/bento/commit/20867ed09))
|
|
14
|
+
|
|
15
|
+
### Miscellaneous Chores
|
|
16
|
+
|
|
17
|
+
- added `vue-prefer-no-redundant-v-if-for-dialog` eslint rule ([f21cf44a6](https://github.com/Adyen/bento/commit/f21cf44a6))
|
|
18
|
+
|
|
19
|
+
### ❤️ Thank You
|
|
20
|
+
|
|
21
|
+
- erice
|
|
22
|
+
- gerald
|
|
23
|
+
- mafalda
|
|
24
|
+
|
|
25
|
+
|
|
3
26
|
## 2.23.0 (2026-08-17)
|
|
4
27
|
|
|
5
28
|
### Features
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ npm install --save-dev eslint@9 vue-eslint-parser@10 @adyen/eslint-plugin-bento@
|
|
|
19
19
|
|
|
20
20
|
### Flat config recommended (`eslint.config.js`)
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Deprecation rules are set to `warn`. Restricted APIs remain errors.
|
|
23
23
|
|
|
24
24
|
```javascript
|
|
25
25
|
const { defineConfig } = require('eslint/config');
|
|
@@ -97,6 +97,12 @@ module.exports = defineConfig([
|
|
|
97
97
|
|
|
98
98
|
## Rules
|
|
99
99
|
|
|
100
|
+
### `@adyen/bento/vue-no-use-bento-translation-overrides`
|
|
101
|
+
|
|
102
|
+
Disallow importing the restricted `useBentoTranslationOverrides` composable without approval from the Bento team. This
|
|
103
|
+
API is only intended for teams building SDKs or component libraries for external customers and must not be used in Adyen
|
|
104
|
+
products.
|
|
105
|
+
|
|
100
106
|
### `@adyen/bento/vue-old-spacer-tokens`
|
|
101
107
|
|
|
102
108
|
Disallow the use of ADL space utility classes in favor of Bento _spacer_ utility classes.
|
|
@@ -109,6 +115,12 @@ Disallow the use of the `default` slot in `bento-currency` instances.
|
|
|
109
115
|
|
|
110
116
|
Disallow the use of the `default` slot in `bento-tag` instances.
|
|
111
117
|
|
|
118
|
+
### `@adyen/bento/vue-no-redundant-dialog-v-if`
|
|
119
|
+
|
|
120
|
+
Disallow a `v-if` that duplicates the `is-open` binding on `bento-modal`, `bento-modal-fullscreen` and
|
|
121
|
+
`bento-sidepanel`. These components render a native `<dialog>`, so the `v-if` only unmounts them before their closing
|
|
122
|
+
animation can run. Reported with an IDE suggestion to remove the directive, not an autofix.
|
|
123
|
+
|
|
112
124
|
### `@adyen/bento/tailwind-v3-to-bento`
|
|
113
125
|
|
|
114
126
|
Replace Tailwind CSS v3 utility classes with Bento design token equivalents. Covers spacing, border radius, border
|
|
@@ -119,23 +131,27 @@ warning — use the `bento-typography` component instead.
|
|
|
119
131
|
|
|
120
132
|
### Recommended (`vue-recommended`)
|
|
121
133
|
|
|
122
|
-
| Rule
|
|
123
|
-
|
|
|
124
|
-
| `@adyen/bento/deprecation-components-input-emit`
|
|
125
|
-
| `@adyen/bento/deprecation-components-value-prop`
|
|
126
|
-
| `@adyen/bento/deprecation-currency-default-slot`
|
|
127
|
-
| `@adyen/bento/deprecation-tag-default-slot`
|
|
128
|
-
| `@adyen/bento/vue-
|
|
134
|
+
| Rule | Severity |
|
|
135
|
+
| ----------------------------------------------------- | -------- |
|
|
136
|
+
| `@adyen/bento/deprecation-components-input-emit` | `warn` |
|
|
137
|
+
| `@adyen/bento/deprecation-components-value-prop` | `warn` |
|
|
138
|
+
| `@adyen/bento/deprecation-currency-default-slot` | `warn` |
|
|
139
|
+
| `@adyen/bento/deprecation-tag-default-slot` | `warn` |
|
|
140
|
+
| `@adyen/bento/vue-no-use-bento-translation-overrides` | `error` |
|
|
141
|
+
| `@adyen/bento/vue-no-redundant-dialog-v-if` | `warn` |
|
|
142
|
+
| `@adyen/bento/vue-old-spacer-tokens` | `warn` |
|
|
129
143
|
|
|
130
144
|
### Strict (`vue-strict`)
|
|
131
145
|
|
|
132
|
-
| Rule
|
|
133
|
-
|
|
|
134
|
-
| `@adyen/bento/deprecation-components-input-emit`
|
|
135
|
-
| `@adyen/bento/deprecation-components-value-prop`
|
|
136
|
-
| `@adyen/bento/deprecation-currency-default-slot`
|
|
137
|
-
| `@adyen/bento/deprecation-tag-default-slot`
|
|
138
|
-
| `@adyen/bento/vue-
|
|
146
|
+
| Rule | Severity |
|
|
147
|
+
| ----------------------------------------------------- | -------- |
|
|
148
|
+
| `@adyen/bento/deprecation-components-input-emit` | `error` |
|
|
149
|
+
| `@adyen/bento/deprecation-components-value-prop` | `error` |
|
|
150
|
+
| `@adyen/bento/deprecation-currency-default-slot` | `error` |
|
|
151
|
+
| `@adyen/bento/deprecation-tag-default-slot` | `error` |
|
|
152
|
+
| `@adyen/bento/vue-no-use-bento-translation-overrides` | `error` |
|
|
153
|
+
| `@adyen/bento/vue-no-redundant-dialog-v-if` | `error` |
|
|
154
|
+
| `@adyen/bento/vue-old-spacer-tokens` | `error` |
|
|
139
155
|
|
|
140
156
|
### Tailwind (`tailwind`)
|
|
141
157
|
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
/** @type {import('eslint').Linter.Config[]} */
|
|
2
2
|
module.exports = [
|
|
3
|
+
{
|
|
4
|
+
name: '@bento/adyen/recommended-restricted-apis',
|
|
5
|
+
files: ['*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}', '**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
|
|
6
|
+
plugins: {
|
|
7
|
+
get '@adyen/bento'() {
|
|
8
|
+
return require('../index');
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
'@adyen/bento/vue-no-use-bento-translation-overrides': 'error',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
3
15
|
{
|
|
4
16
|
name: '@bento/adyen/recommended',
|
|
5
17
|
files: ['*.vue', '**/*.vue'],
|
|
@@ -12,6 +24,7 @@ module.exports = [
|
|
|
12
24
|
},
|
|
13
25
|
},
|
|
14
26
|
rules: {
|
|
27
|
+
'@adyen/bento/deprecation-bento-tag-variant-enum': 'warn',
|
|
15
28
|
'@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler': 'warn',
|
|
16
29
|
'@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop': 'warn',
|
|
17
30
|
'@adyen/bento/deprecation-input-filter-dropdown-options': 'warn',
|
|
@@ -27,6 +40,8 @@ module.exports = [
|
|
|
27
40
|
'@adyen/bento/deprecation-components-value-prop': 'warn',
|
|
28
41
|
'@adyen/bento/deprecation-currency-default-slot': 'warn',
|
|
29
42
|
'@adyen/bento/deprecation-tag-default-slot': 'warn',
|
|
43
|
+
'@adyen/bento/vue-no-use-bento-translation-overrides': 'error',
|
|
44
|
+
'@adyen/bento/vue-no-redundant-dialog-v-if': 'warn',
|
|
30
45
|
'@adyen/bento/vue-old-spacer-tokens': 'warn',
|
|
31
46
|
},
|
|
32
47
|
},
|
package/configs/vue-strict.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
/** @type {import('eslint').Linter.Config[]} */
|
|
2
2
|
module.exports = [
|
|
3
|
+
{
|
|
4
|
+
name: '@bento/adyen/strict-restricted-apis',
|
|
5
|
+
files: ['*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}', '**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}'],
|
|
6
|
+
plugins: {
|
|
7
|
+
get '@adyen/bento'() {
|
|
8
|
+
return require('../index');
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
rules: {
|
|
12
|
+
'@adyen/bento/vue-no-use-bento-translation-overrides': 'error',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
3
15
|
{
|
|
4
16
|
name: '@bento/adyen/strict',
|
|
5
17
|
files: ['*.vue', '**/*.vue'],
|
|
@@ -12,6 +24,7 @@ module.exports = [
|
|
|
12
24
|
},
|
|
13
25
|
},
|
|
14
26
|
rules: {
|
|
27
|
+
'@adyen/bento/deprecation-bento-tag-variant-enum': 'error',
|
|
15
28
|
'@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler': 'error',
|
|
16
29
|
'@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop': ['error', { action: 'remove' }],
|
|
17
30
|
'@adyen/bento/deprecation-input-filter-dropdown-options': 'error',
|
|
@@ -27,6 +40,8 @@ module.exports = [
|
|
|
27
40
|
'@adyen/bento/deprecation-components-value-prop': 'error',
|
|
28
41
|
'@adyen/bento/deprecation-currency-default-slot': 'error',
|
|
29
42
|
'@adyen/bento/deprecation-tag-default-slot': 'error',
|
|
43
|
+
'@adyen/bento/vue-no-use-bento-translation-overrides': 'error',
|
|
44
|
+
'@adyen/bento/vue-no-redundant-dialog-v-if': 'error',
|
|
30
45
|
'@adyen/bento/vue-old-spacer-tokens': 'error',
|
|
31
46
|
},
|
|
32
47
|
},
|
package/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const plugin = {
|
|
|
12
12
|
tailwind: require('./configs/tailwind'),
|
|
13
13
|
},
|
|
14
14
|
rules: {
|
|
15
|
+
'deprecation-bento-tag-variant-enum': require('./rules/deprecation-bento-tag-variant-enum/deprecation-bento-tag-variant-enum'),
|
|
15
16
|
'deprecation-bento-data-grid-cell-action-menu-item-handler': require('./rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler'),
|
|
16
17
|
'deprecation-bento-date-range-picker-has-actions-prop': require('./rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop'),
|
|
17
18
|
'deprecation-input-filter-dropdown-options': require('./rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options'),
|
|
@@ -27,6 +28,8 @@ const plugin = {
|
|
|
27
28
|
'deprecation-components-value-prop': require('./rules/deprecation-components-value-prop/deprecation-components-value-prop'),
|
|
28
29
|
'deprecation-currency-default-slot': require('./rules/deprecation-currency-default-slot/deprecation-currency-default-slot'),
|
|
29
30
|
'deprecation-tag-default-slot': require('./rules/deprecation-tag-default-slot/deprecation-tag-default-slot'),
|
|
31
|
+
'vue-no-use-bento-translation-overrides': require('./rules/vue-no-use-bento-translation-overrides/vue-no-use-bento-translation-overrides'),
|
|
32
|
+
'vue-no-redundant-dialog-v-if': require('./rules/vue-no-redundant-dialog-v-if/vue-no-redundant-dialog-v-if'),
|
|
30
33
|
'vue-old-spacer-tokens': require('./rules/vue-old-spacer-tokens/vue-old-spacer-tokens'),
|
|
31
34
|
'tailwind-v3-to-bento': require('./rules/tailwind-v3-to-bento/tailwind-v3-to-bento'),
|
|
32
35
|
},
|
package/package.json
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# deprecation-bento-tag-variant-enum
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
The white `bento-tag` variant and the `BentoTagVariant.WHITE` enum member are deprecated. Use the `grey` variant or the
|
|
6
|
+
`'grey'` string literal instead.
|
|
7
|
+
|
|
8
|
+
## Rule details
|
|
9
|
+
|
|
10
|
+
The rule reports and can autofix the following usages:
|
|
11
|
+
|
|
12
|
+
- `BentoTagVariant.WHITE` in scripts and template expressions.
|
|
13
|
+
- Static `variant="white"` attributes on `bento-tag` and `BentoTag`.
|
|
14
|
+
- Named bindings such as `:variant="'white'"` and `v-bind:variant="'white'"`.
|
|
15
|
+
- Object bindings such as `v-bind="{ variant: 'white' }"`.
|
|
16
|
+
- `BentoTagProps` object literals whose `variant` is `'white'` or `BentoTagVariant.WHITE`.
|
|
17
|
+
|
|
18
|
+
The rule does not report `variant="white"` on unrelated components or other `BentoTagVariant` members. Values that can
|
|
19
|
+
only be determined at runtime cannot be safely autofixed.
|
|
20
|
+
|
|
21
|
+
## Incorrect
|
|
22
|
+
|
|
23
|
+
```vue
|
|
24
|
+
<template>
|
|
25
|
+
<bento-tag variant="white" />
|
|
26
|
+
<bento-tag :variant="'white'" />
|
|
27
|
+
<bento-tag v-bind="{ variant: 'white' }" />
|
|
28
|
+
<bento-tag :variant="BentoTagVariant.WHITE" />
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script setup lang="ts">
|
|
32
|
+
import { type BentoTagProps, BentoTagVariant } from '@adyen/bento-vue2';
|
|
33
|
+
|
|
34
|
+
const tagProps: BentoTagProps = { variant: 'white' };
|
|
35
|
+
const enumTagProps: BentoTagProps = { variant: BentoTagVariant.WHITE };
|
|
36
|
+
</script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Correct
|
|
40
|
+
|
|
41
|
+
```vue
|
|
42
|
+
<template>
|
|
43
|
+
<bento-tag variant="grey" />
|
|
44
|
+
<bento-tag :variant="'grey'" />
|
|
45
|
+
<bento-tag v-bind="{ variant: 'grey' }" />
|
|
46
|
+
</template>
|
|
47
|
+
|
|
48
|
+
<script setup lang="ts">
|
|
49
|
+
import type { BentoTagProps } from '@adyen/bento-vue2';
|
|
50
|
+
|
|
51
|
+
const tagProps: BentoTagProps = { variant: 'grey' };
|
|
52
|
+
</script>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
The rule is enabled as a warning in the recommended Bento Vue config and as an error in the strict config.
|
|
58
|
+
|
|
59
|
+
To enable autofix explicitly:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
export default [
|
|
63
|
+
{
|
|
64
|
+
rules: {
|
|
65
|
+
'@adyen/bento/deprecation-bento-tag-variant-enum': ['warn', { autofix: true }],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
```
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('eslint').Rule.RuleContext} RuleContext
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('eslint-plugin-vue/lib/utils').RuleModule} RuleModule
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const VueUtils = require('eslint-plugin-vue/lib/utils');
|
|
9
|
+
|
|
10
|
+
const findWhiteVariantProperty = properties =>
|
|
11
|
+
properties.find(
|
|
12
|
+
property =>
|
|
13
|
+
property.type === 'Property' &&
|
|
14
|
+
!property.computed &&
|
|
15
|
+
((property.key.type === 'Identifier' && property.key.name === 'variant') ||
|
|
16
|
+
(property.key.type === 'Literal' && property.key.value === 'variant')) &&
|
|
17
|
+
property.value.type === 'Literal' &&
|
|
18
|
+
property.value.value === 'white'
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
/** @type {RuleModule} */
|
|
22
|
+
module.exports = {
|
|
23
|
+
meta: {
|
|
24
|
+
type: 'suggestion',
|
|
25
|
+
docs: {
|
|
26
|
+
description: 'Deprecates the white bento-tag variant and BentoTagVariant.WHITE',
|
|
27
|
+
category: 'Deprecations',
|
|
28
|
+
url: 'https://github.com/Adyen/bento/blob/main/packages/eslint/rules/deprecation-bento-tag-variant-enum/README.md',
|
|
29
|
+
recommended: true,
|
|
30
|
+
},
|
|
31
|
+
messages: {
|
|
32
|
+
deprecationWithReplacement: `The "{{name}}" enum member is deprecated. Please use "{{replacement}}" instead.`,
|
|
33
|
+
whiteVariant: `The "white" bento-tag variant is deprecated. Please use "grey" instead.`,
|
|
34
|
+
},
|
|
35
|
+
fixable: 'code',
|
|
36
|
+
schema: [
|
|
37
|
+
{
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
autofix: {
|
|
41
|
+
type: 'boolean',
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
additionalProperties: false,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/** @param {RuleContext} context */
|
|
51
|
+
create(context) {
|
|
52
|
+
const options = context.options[0] || {};
|
|
53
|
+
const autofix = options.autofix === true;
|
|
54
|
+
|
|
55
|
+
const REPLACEMENT_MAP = {
|
|
56
|
+
WHITE: "'grey'",
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const enumName = 'BentoTagVariant';
|
|
60
|
+
|
|
61
|
+
const visitor = {
|
|
62
|
+
[`MemberExpression[object.name="${enumName}"]`](node) {
|
|
63
|
+
if (node.computed && node.property.type !== 'Literal') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const memberName = node.computed ? node.property.value : node.property.name;
|
|
68
|
+
const replacement = REPLACEMENT_MAP[memberName];
|
|
69
|
+
if (replacement) {
|
|
70
|
+
context.report({
|
|
71
|
+
node,
|
|
72
|
+
messageId: 'deprecationWithReplacement',
|
|
73
|
+
data: { name: `${enumName}.${memberName}`, replacement },
|
|
74
|
+
...(autofix && {
|
|
75
|
+
fix(fixer) {
|
|
76
|
+
return fixer.replaceText(node, replacement);
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
VariableDeclarator(node) {
|
|
83
|
+
const typeName = node.id?.typeAnnotation?.typeAnnotation?.typeName;
|
|
84
|
+
if (
|
|
85
|
+
typeName?.type !== 'Identifier' ||
|
|
86
|
+
typeName.name !== 'BentoTagProps' ||
|
|
87
|
+
node.init?.type !== 'ObjectExpression'
|
|
88
|
+
) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const variantProperty = findWhiteVariantProperty(node.init.properties);
|
|
93
|
+
if (variantProperty?.type !== 'Property') {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
context.report({
|
|
98
|
+
node: variantProperty.value,
|
|
99
|
+
messageId: 'whiteVariant',
|
|
100
|
+
...(autofix && {
|
|
101
|
+
fix(fixer) {
|
|
102
|
+
return fixer.replaceText(variantProperty.value, "'grey'");
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
[`VElement:matches([name="bento-tag"], [name="BentoTag"]) > VStartTag > VAttribute[directive=false][key.name="variant"]`](
|
|
108
|
+
node
|
|
109
|
+
) {
|
|
110
|
+
if (node.value?.value !== 'white') {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
context.report({
|
|
115
|
+
node,
|
|
116
|
+
messageId: 'whiteVariant',
|
|
117
|
+
...(autofix && {
|
|
118
|
+
fix(fixer) {
|
|
119
|
+
return fixer.replaceText(node, 'variant="grey"');
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
[`VElement:matches([name="bento-tag"], [name="BentoTag"]) > VStartTag > VAttribute[directive=true][key.name.name="bind"][key.argument.name="variant"]`](
|
|
125
|
+
node
|
|
126
|
+
) {
|
|
127
|
+
const expression = node.value?.expression;
|
|
128
|
+
if (expression?.type !== 'Literal' || expression.value !== 'white') {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
context.report({
|
|
133
|
+
node,
|
|
134
|
+
messageId: 'whiteVariant',
|
|
135
|
+
...(autofix && {
|
|
136
|
+
fix(fixer) {
|
|
137
|
+
return fixer.replaceText(expression, "'grey'");
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
[`VElement:matches([name="bento-tag"], [name="BentoTag"]) > VStartTag > VAttribute[directive=true][key.name.name="bind"]`](
|
|
143
|
+
node
|
|
144
|
+
) {
|
|
145
|
+
if (node.key.argument || node.value?.expression?.type !== 'ObjectExpression') {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const variantProperty = findWhiteVariantProperty(node.value.expression.properties);
|
|
150
|
+
if (variantProperty?.type !== 'Property') {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
context.report({
|
|
155
|
+
node: variantProperty.value,
|
|
156
|
+
messageId: 'whiteVariant',
|
|
157
|
+
...(autofix && {
|
|
158
|
+
fix(fixer) {
|
|
159
|
+
return fixer.replaceText(variantProperty.value, "'grey'");
|
|
160
|
+
},
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
return VueUtils.defineTemplateBodyVisitor(context, visitor, visitor);
|
|
166
|
+
},
|
|
167
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @adyen/bento/vue-no-redundant-dialog-v-if
|
|
2
|
+
|
|
3
|
+
> Disallow a redundant `v-if` next to `is-open` on components rendering a native dialog
|
|
4
|
+
|
|
5
|
+
- This rule is included in the `vue-recommended` (`warn`) and `vue-strict` (`error`) configurations
|
|
6
|
+
- 💡 This rule provides an IDE suggestion (not an autofix), so `--fix` leaves the code untouched
|
|
7
|
+
|
|
8
|
+
The following components render a native HTML `<dialog>` element:
|
|
9
|
+
|
|
10
|
+
- `bento-modal`
|
|
11
|
+
- `bento-modal-fullscreen`
|
|
12
|
+
- `bento-sidepanel`
|
|
13
|
+
|
|
14
|
+
A closed `<dialog>` is hidden by the browser and its content is not rendered, so `is-open` alone is enough to control
|
|
15
|
+
visibility. Pairing it with a `v-if` on the same value unmounts the component the moment it closes, which cancels the
|
|
16
|
+
closing animation.
|
|
17
|
+
|
|
18
|
+
This rule only reports a `v-if` whose expression is identical to the `is-open` binding, because that is the only case
|
|
19
|
+
where removing the directive provably keeps the same behaviour. A `v-if` driven by another condition (for example
|
|
20
|
+
`v-if="hasPermission"`) is left alone, as is an element whose `v-if` is followed by a `v-else` or `v-else-if` branch.
|
|
21
|
+
|
|
22
|
+
## ✗ BAD
|
|
23
|
+
|
|
24
|
+
<!-- prettier-ignore -->
|
|
25
|
+
```html
|
|
26
|
+
<template>
|
|
27
|
+
<bento-modal v-if="isOpen" :is-open="isOpen" />
|
|
28
|
+
|
|
29
|
+
<bento-modal-fullscreen v-if="isOpen" :is-open="isOpen" />
|
|
30
|
+
|
|
31
|
+
<bento-sidepanel v-if="isOpen" :is-open="isOpen" />
|
|
32
|
+
</template>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## ✓ Good
|
|
36
|
+
|
|
37
|
+
<!-- prettier-ignore -->
|
|
38
|
+
```html
|
|
39
|
+
<template>
|
|
40
|
+
<bento-modal :is-open="isOpen" />
|
|
41
|
+
|
|
42
|
+
<bento-modal-fullscreen :is-open="isOpen" />
|
|
43
|
+
|
|
44
|
+
<bento-sidepanel :is-open="isOpen" />
|
|
45
|
+
</template>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A `v-if` on an unrelated condition is still valid, since it does not duplicate `is-open`:
|
|
49
|
+
|
|
50
|
+
<!-- prettier-ignore -->
|
|
51
|
+
```html
|
|
52
|
+
<template>
|
|
53
|
+
<bento-modal v-if="hasPermission" :is-open="isOpen" />
|
|
54
|
+
</template>
|
|
55
|
+
```
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('eslint').Rule.RuleContext} RuleContext
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('vue-eslint-parser').AST.VDirective} VDirective
|
|
6
|
+
* @typedef {import('vue-eslint-parser').AST.VElement} VElement
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('eslint-plugin-vue/lib/utils').RuleModule} RuleModule
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const VueUtils = require('eslint-plugin-vue/lib/utils');
|
|
13
|
+
|
|
14
|
+
// Components rendering a native "<dialog>" element, which is hidden by the browser while closed
|
|
15
|
+
const DIALOG_COMPONENTS = ['bento-modal', 'bento-modal-fullscreen', 'bento-sidepanel'];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Normalizes a tag or attribute name so "BentoModal" and "bento-modal" are treated alike.
|
|
19
|
+
* @param {string} name
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
function toKebabCase(name) {
|
|
23
|
+
return name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Collapses whitespace so expressions spanning several lines can be compared.
|
|
28
|
+
* @param {string} expression
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function normalizeExpression(expression) {
|
|
32
|
+
return expression.replace(/\s+/g, ' ').trim();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Finds a directive by name, e.g. "if" for "v-if" or "bind" for ":is-open".
|
|
37
|
+
* @param {VElement} node
|
|
38
|
+
* @param {string} directiveName
|
|
39
|
+
* @returns {VDirective | undefined}
|
|
40
|
+
*/
|
|
41
|
+
function findDirective(node, directiveName) {
|
|
42
|
+
return node.startTag.attributes.find(attribute => attribute.directive && attribute.key.name.name === directiveName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Finds the "is-open" binding, either as ":is-open" or as "v-bind:isOpen".
|
|
47
|
+
* @param {VElement} node
|
|
48
|
+
* @returns {VDirective | undefined}
|
|
49
|
+
*/
|
|
50
|
+
function findIsOpenBinding(node) {
|
|
51
|
+
return node.startTag.attributes.find(
|
|
52
|
+
attribute =>
|
|
53
|
+
attribute.directive &&
|
|
54
|
+
attribute.key.name.name === 'bind' &&
|
|
55
|
+
attribute.key.argument &&
|
|
56
|
+
attribute.key.argument.type === 'VIdentifier' &&
|
|
57
|
+
toKebabCase(attribute.key.argument.rawName) === 'is-open'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Checks whether the element right after the given one relies on its "v-if",
|
|
63
|
+
* in which case removing the directive would break the template.
|
|
64
|
+
* @param {VElement} node
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
function hasElseBranch(node) {
|
|
68
|
+
const siblings = node.parent.children;
|
|
69
|
+
const nextElement = siblings.slice(siblings.indexOf(node) + 1).find(sibling => sibling.type === 'VElement');
|
|
70
|
+
|
|
71
|
+
if (!nextElement) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return !!(findDirective(nextElement, 'else') || findDirective(nextElement, 'else-if'));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @type {RuleModule} */
|
|
79
|
+
module.exports = {
|
|
80
|
+
meta: {
|
|
81
|
+
type: 'suggestion',
|
|
82
|
+
docs: {
|
|
83
|
+
description: 'Disallow a redundant "v-if" next to "is-open" on components rendering a native dialog',
|
|
84
|
+
category: 'Best Practices',
|
|
85
|
+
url: 'https://github.com/Adyen/bento/blob/main/packages/eslint/rules/vue-no-redundant-dialog-v-if/README.md',
|
|
86
|
+
recommended: true,
|
|
87
|
+
},
|
|
88
|
+
messages: {
|
|
89
|
+
redundantVIf: `"v-if" is redundant on "{{ component }}" and unmounts it before the closing animation can run. The underlying "<dialog>" element stays hidden while closed, so "is-open" alone controls its visibility.`,
|
|
90
|
+
suggestRemoveVIf: `Remove the redundant "v-if" directive`,
|
|
91
|
+
},
|
|
92
|
+
hasSuggestions: true,
|
|
93
|
+
schema: [],
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/** @param {RuleContext} context */
|
|
97
|
+
create(context) {
|
|
98
|
+
const sourceCode = context.sourceCode;
|
|
99
|
+
const template =
|
|
100
|
+
sourceCode.parserServices.getTemplateBodyTokenStore &&
|
|
101
|
+
sourceCode.parserServices.getTemplateBodyTokenStore();
|
|
102
|
+
|
|
103
|
+
return VueUtils.defineTemplateBodyVisitor(context, {
|
|
104
|
+
/** @param {VElement} node */
|
|
105
|
+
VElement(node) {
|
|
106
|
+
if (!DIALOG_COMPONENTS.includes(toKebabCase(node.rawName))) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const vIf = findDirective(node, 'if');
|
|
111
|
+
const isOpen = findIsOpenBinding(node);
|
|
112
|
+
const vIfExpression = vIf && vIf.value && vIf.value.expression;
|
|
113
|
+
const isOpenExpression = isOpen && isOpen.value && isOpen.value.expression;
|
|
114
|
+
|
|
115
|
+
if (!vIfExpression || !isOpenExpression) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Only a "v-if" driven by the very same value as "is-open" is provably redundant
|
|
120
|
+
if (
|
|
121
|
+
normalizeExpression(sourceCode.getText(vIfExpression)) !==
|
|
122
|
+
normalizeExpression(sourceCode.getText(isOpenExpression))
|
|
123
|
+
) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (hasElseBranch(node)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
context.report({
|
|
132
|
+
node: vIf,
|
|
133
|
+
messageId: 'redundantVIf',
|
|
134
|
+
data: { component: toKebabCase(node.rawName) },
|
|
135
|
+
suggest: [
|
|
136
|
+
{
|
|
137
|
+
messageId: 'suggestRemoveVIf',
|
|
138
|
+
fix(fixer) {
|
|
139
|
+
// Removing from the previous token takes the leading whitespace
|
|
140
|
+
// or line break with it, keeping the start tag tidy
|
|
141
|
+
const tokenBefore = template.getTokenBefore(vIf);
|
|
142
|
+
return fixer.removeRange([tokenBefore.range[1], vIf.range[1]]);
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Disallow unapproved translation overrides
|
|
2
|
+
|
|
3
|
+
The `@adyen/bento/vue-no-use-bento-translation-overrides` rule prevents importing `useBentoTranslationOverrides` from
|
|
4
|
+
`@adyen/bento-vue3`.
|
|
5
|
+
|
|
6
|
+
This restricted composable is only intended for teams building SDKs or component libraries for external customers. It
|
|
7
|
+
must not be used in Adyen products. Teams must request approval from the Bento team before using it.
|
|
8
|
+
|
|
9
|
+
After approval, suppress the rule only around the approved import and include the reason:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// eslint-disable-next-line @adyen/bento/vue-no-use-bento-translation-overrides -- Approved by the Bento team for the customer SDK.
|
|
13
|
+
import { useBentoTranslationOverrides } from '@adyen/bento-vue3';
|
|
14
|
+
```
|