@adyen/eslint-plugin-bento 2.10.0 → 2.12.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 +24 -0
- package/configs/vue-recommended.js +3 -0
- package/configs/vue-strict.js +3 -0
- package/index.js +3 -0
- package/package.json +2 -2
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/README.md +48 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/deprecation-bento-data-grid-cell-action-menu-item-handler.vue +63 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/eslint.config.js +26 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.integration.test.ts +24 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.js +232 -0
- package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.test.ts +116 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/README.md +50 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/deprecation-bento-date-range-picker-has-actions-prop.vue +10 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/eslint.config.js +29 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/deprecation-bento-date-range-picker-has-actions-prop.vue +11 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/eslint.config.js +29 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.integration.test.ts +47 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.js +205 -0
- package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.test.ts +176 -0
- package/rules/deprecation-country-custom-usage/README.md +151 -0
- package/rules/deprecation-country-custom-usage/__tests__/deprecation-country-custom-usage.vue +93 -0
- package/rules/deprecation-country-custom-usage/__tests__/eslint.config.js +25 -0
- package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.integration.test.ts +22 -0
- package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.js +569 -0
- package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.test.ts +380 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.12.0 (2026-05-12)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- added rule to deprecate `bento-date-range-picker` prop `has-actions` in eslint ([d594fcb72](https://github.com/Adyen/bento/commit/d594fcb72))
|
|
8
|
+
|
|
9
|
+
### ❤️ Thank You
|
|
10
|
+
|
|
11
|
+
- erice
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## 2.11.0 (2026-05-06)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- added deprecation rule for custom label in country components ([12d9fea55](https://github.com/Adyen/bento/commit/12d9fea55))
|
|
19
|
+
- added rule to deprecate `handler` in `bento-data-grid-cell-action` in eslint ([26074a326](https://github.com/Adyen/bento/commit/26074a326))
|
|
20
|
+
|
|
21
|
+
### ❤️ Thank You
|
|
22
|
+
|
|
23
|
+
- erice
|
|
24
|
+
- gerald
|
|
25
|
+
|
|
26
|
+
|
|
3
27
|
## 2.10.0 (2026-04-29)
|
|
4
28
|
|
|
5
29
|
### Features
|
|
@@ -11,10 +11,13 @@ module.exports = [
|
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
rules: {
|
|
14
|
+
'@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler': 'warn',
|
|
15
|
+
'@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop': 'warn',
|
|
14
16
|
'@adyen/bento/deprecation-input-filter-dropdown-options': 'warn',
|
|
15
17
|
'@adyen/bento/deprecation-bento-dropdown-size-prop': 'warn',
|
|
16
18
|
'@adyen/bento/deprecation-bento-timeline-item-variant-prop': 'warn',
|
|
17
19
|
'@adyen/bento/deprecation-bento-popover-modifiers-prop': 'warn',
|
|
20
|
+
'@adyen/bento/deprecation-country-custom-usage': 'warn',
|
|
18
21
|
'@adyen/bento/deprecation-components-error-prop': 'warn',
|
|
19
22
|
'@adyen/bento/deprecation-filter-bar-deprecated-props': 'warn',
|
|
20
23
|
'@adyen/bento/deprecation-components-has-error-prop': 'warn',
|
package/configs/vue-strict.js
CHANGED
|
@@ -11,10 +11,13 @@ module.exports = [
|
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
rules: {
|
|
14
|
+
'@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler': 'error',
|
|
15
|
+
'@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop': 'error',
|
|
14
16
|
'@adyen/bento/deprecation-input-filter-dropdown-options': 'error',
|
|
15
17
|
'@adyen/bento/deprecation-bento-dropdown-size-prop': 'error',
|
|
16
18
|
'@adyen/bento/deprecation-bento-timeline-item-variant-prop': 'error',
|
|
17
19
|
'@adyen/bento/deprecation-bento-popover-modifiers-prop': 'error',
|
|
20
|
+
'@adyen/bento/deprecation-country-custom-usage': 'error',
|
|
18
21
|
'@adyen/bento/deprecation-components-error-prop': 'error',
|
|
19
22
|
'@adyen/bento/deprecation-filter-bar-deprecated-props': 'error',
|
|
20
23
|
'@adyen/bento/deprecation-components-has-error-prop': 'error',
|
package/index.js
CHANGED
|
@@ -12,10 +12,13 @@ const plugin = {
|
|
|
12
12
|
tailwind: require('./configs/tailwind'),
|
|
13
13
|
},
|
|
14
14
|
rules: {
|
|
15
|
+
'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
|
+
'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'),
|
|
15
17
|
'deprecation-input-filter-dropdown-options': require('./rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options'),
|
|
16
18
|
'deprecation-bento-dropdown-size-prop': require('./rules/deprecation-bento-dropdown-size-prop/deprecation-bento-dropdown-size-prop'),
|
|
17
19
|
'deprecation-bento-timeline-item-variant-prop': require('./rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop'),
|
|
18
20
|
'deprecation-bento-popover-modifiers-prop': require('./rules/deprecation-bento-popover-modifiers-prop/deprecation-bento-popover-modifiers-prop'),
|
|
21
|
+
'deprecation-country-custom-usage': require('./rules/deprecation-country-custom-usage/deprecation-country-custom-usage'),
|
|
19
22
|
'deprecation-components-error-prop': require('./rules/deprecation-components-error-prop/deprecation-components-error-prop'),
|
|
20
23
|
'deprecation-filter-bar-deprecated-props': require('./rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props'),
|
|
21
24
|
'deprecation-components-has-error-prop': require('./rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adyen/eslint-plugin-bento",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Adyen Bento ESLint rules",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"eslint": "9.39.0",
|
|
38
38
|
"eslint-plugin-vue": "10.0.0",
|
|
39
39
|
"globals": "16.5.0",
|
|
40
|
-
"vitest": "^3.
|
|
40
|
+
"vitest": "^3.2.4",
|
|
41
41
|
"vue-eslint-parser": "10.1.3"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# deprecation-bento-data-grid-cell-action-menu-item-handler
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
The `handler` property on `BentoColumnCellActionMenuItem` objects (used in `menuData` arrays) is deprecated since
|
|
6
|
+
v2.0.0. Use `event` instead, which receives `(rowDataItem, columnKey)` parameters providing context about which row and
|
|
7
|
+
column triggered the action.
|
|
8
|
+
|
|
9
|
+
## Options
|
|
10
|
+
|
|
11
|
+
| Option | Type | Default | Description |
|
|
12
|
+
| :------------ | :-------- | :------ | :------------------- |
|
|
13
|
+
| **`autofix`** | `boolean` | `false` | Enables auto-fixing. |
|
|
14
|
+
|
|
15
|
+
## Rule Details
|
|
16
|
+
|
|
17
|
+
This rule detects `handler` properties on objects inside `menuData` arrays, both in `<template>` expressions and
|
|
18
|
+
`<script>` blocks.
|
|
19
|
+
|
|
20
|
+
### ❌ Incorrect
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
const cellActions = [
|
|
24
|
+
{
|
|
25
|
+
menuData: [
|
|
26
|
+
{
|
|
27
|
+
text: 'Cancel payment',
|
|
28
|
+
handler: () => cancelPayment(),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### ✅ Correct
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const cellActions = [
|
|
39
|
+
{
|
|
40
|
+
menuData: [
|
|
41
|
+
{
|
|
42
|
+
text: 'Cancel payment',
|
|
43
|
+
event: (rowDataItem, columnKey) => cancelPayment(rowDataItem),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<!-- Inline expression: should warn (2 handlers) -->
|
|
4
|
+
<bento-data-grid
|
|
5
|
+
:cell-actions="[
|
|
6
|
+
{
|
|
7
|
+
variant: 'more',
|
|
8
|
+
menuData: [
|
|
9
|
+
{
|
|
10
|
+
text: 'Cancel payment',
|
|
11
|
+
handler: () => {
|
|
12
|
+
return;
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
text: 'Transfer payment',
|
|
17
|
+
handler: () => {
|
|
18
|
+
return;
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
]"
|
|
24
|
+
:data="[]"
|
|
25
|
+
:columns="[]"
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
<!-- Identifier reference: should warn (1 handler) -->
|
|
29
|
+
<bento-data-grid :cell-actions="rowActions" :data="[]" :columns="[]" />
|
|
30
|
+
|
|
31
|
+
<!-- Non-data-grid component: should NOT warn -->
|
|
32
|
+
<test-component
|
|
33
|
+
:cell-actions="[
|
|
34
|
+
{
|
|
35
|
+
menuData: [
|
|
36
|
+
{
|
|
37
|
+
text: 'Action',
|
|
38
|
+
handler: () => {
|
|
39
|
+
return;
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
]"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
</template>
|
|
48
|
+
|
|
49
|
+
<script setup>
|
|
50
|
+
const rowActions = [
|
|
51
|
+
{
|
|
52
|
+
variant: 'more',
|
|
53
|
+
menuData: [
|
|
54
|
+
{
|
|
55
|
+
text: 'Refund',
|
|
56
|
+
handler: () => {
|
|
57
|
+
return;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
</script>
|
package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/eslint.config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// eslint.config.js
|
|
2
|
+
const { defineConfig } = require('eslint/config');
|
|
3
|
+
const vueParser = require('vue-eslint-parser');
|
|
4
|
+
const tsParser = require('@typescript-eslint/parser');
|
|
5
|
+
const adyenBento = require('@adyen/eslint-plugin-bento');
|
|
6
|
+
|
|
7
|
+
module.exports = defineConfig([
|
|
8
|
+
{
|
|
9
|
+
languageOptions: {
|
|
10
|
+
ecmaVersion: 'latest',
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
parser: vueParser,
|
|
13
|
+
parserOptions: {
|
|
14
|
+
parser: tsParser,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
plugins: {
|
|
18
|
+
'@adyen/bento': adyenBento,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
// Register the specific rule we are testing
|
|
22
|
+
'@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler': ['warn', { autofix: true }],
|
|
23
|
+
},
|
|
24
|
+
files: ['**/*.vue'],
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { execFileSyncEslintVueFiles } from '../../utils/exec-file-sync-eslint-vue-files';
|
|
3
|
+
|
|
4
|
+
describe('@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler', () => {
|
|
5
|
+
it('should lint with warning when handler is used in menuData', () => {
|
|
6
|
+
const eslintrc = path.resolve(__dirname, '__tests__', 'eslint.config.js');
|
|
7
|
+
const vueFile = path.resolve(
|
|
8
|
+
__dirname,
|
|
9
|
+
'__tests__',
|
|
10
|
+
'deprecation-bento-data-grid-cell-action-menu-item-handler.vue'
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const result = JSON.parse(execFileSyncEslintVueFiles(eslintrc, vueFile));
|
|
14
|
+
|
|
15
|
+
expect(result[0].warningCount).toBe(3);
|
|
16
|
+
|
|
17
|
+
expect(result[0].messages[0]).toMatchObject({
|
|
18
|
+
ruleId: '@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler',
|
|
19
|
+
severity: 1,
|
|
20
|
+
messageId: 'deprecation',
|
|
21
|
+
message: `The "handler" property is deprecated in bento-data-grid cell action menu items. Use "event" instead.`,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,232 @@
|
|
|
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 DATA_GRID_NAMES = new Set(['bento-data-grid', 'BentoDataGrid']);
|
|
11
|
+
const CELL_ACTION_PROPS = new Set(['cell-actions', 'cellActions', 'row-actions', 'rowActions']);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Reports a deprecated handler property and optionally fixes it by renaming to "event".
|
|
15
|
+
*/
|
|
16
|
+
function reportHandler(context, node, autofix) {
|
|
17
|
+
context.report({
|
|
18
|
+
node,
|
|
19
|
+
messageId: 'deprecation',
|
|
20
|
+
...(autofix && {
|
|
21
|
+
fix(fixer) {
|
|
22
|
+
return fixer.replaceText(node.key, 'event');
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Recursively walks an AST node looking for Property nodes with key "handler"
|
|
30
|
+
* that sit inside a "menuData" array. Reports each one found.
|
|
31
|
+
*/
|
|
32
|
+
function findHandlersInMenuData(astNode, context, autofix) {
|
|
33
|
+
if (!astNode || typeof astNode !== 'object') {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If this is a Property with key "menuData" whose value is an array,
|
|
38
|
+
// search that array for handler properties.
|
|
39
|
+
if (
|
|
40
|
+
astNode.type === 'Property' &&
|
|
41
|
+
astNode.key &&
|
|
42
|
+
(astNode.key.name === 'menuData' || astNode.key.value === 'menuData') &&
|
|
43
|
+
astNode.value &&
|
|
44
|
+
astNode.value.type === 'ArrayExpression'
|
|
45
|
+
) {
|
|
46
|
+
findHandlersInArray(astNode.value, context, autofix);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Recurse into child nodes
|
|
51
|
+
for (const key of Object.keys(astNode)) {
|
|
52
|
+
if (key === 'parent') {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const child = astNode[key];
|
|
56
|
+
if (Array.isArray(child)) {
|
|
57
|
+
child.forEach(item => findHandlersInMenuData(item, context, autofix));
|
|
58
|
+
} else if (child && typeof child === 'object' && child.type) {
|
|
59
|
+
findHandlersInMenuData(child, context, autofix);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Searches an ArrayExpression (the value of menuData) for object items with a "handler" property.
|
|
66
|
+
*/
|
|
67
|
+
function findHandlersInArray(arrayNode, context, autofix) {
|
|
68
|
+
for (const element of arrayNode.elements) {
|
|
69
|
+
if (!element || element.type !== 'ObjectExpression') {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
for (const prop of element.properties) {
|
|
73
|
+
if (prop.type === 'Property' && prop.key && prop.key.name === 'handler') {
|
|
74
|
+
reportHandler(context, prop, autofix);
|
|
75
|
+
}
|
|
76
|
+
// Also check nested items arrays (sub-menus)
|
|
77
|
+
if (
|
|
78
|
+
prop.type === 'Property' &&
|
|
79
|
+
prop.key &&
|
|
80
|
+
prop.key.name === 'items' &&
|
|
81
|
+
prop.value &&
|
|
82
|
+
prop.value.type === 'ArrayExpression'
|
|
83
|
+
) {
|
|
84
|
+
findHandlersInArray(prop.value, context, autofix);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Checks whether a Property node with key "handler" is inside a menuData context.
|
|
92
|
+
* Walks up the AST looking for an ArrayExpression whose parent Property has key "menuData".
|
|
93
|
+
*/
|
|
94
|
+
function isInsideMenuData(node) {
|
|
95
|
+
let current = node.parent;
|
|
96
|
+
|
|
97
|
+
while (current) {
|
|
98
|
+
if (current.type === 'ArrayExpression') {
|
|
99
|
+
const arrayParent = current.parent;
|
|
100
|
+
if (
|
|
101
|
+
arrayParent &&
|
|
102
|
+
arrayParent.type === 'Property' &&
|
|
103
|
+
arrayParent.key &&
|
|
104
|
+
(arrayParent.key.name === 'menuData' || arrayParent.key.value === 'menuData')
|
|
105
|
+
) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
current = current.parent;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Finds the VariableDeclarator ancestor of a node and returns its id name.
|
|
117
|
+
*/
|
|
118
|
+
function getDeclaratorName(node) {
|
|
119
|
+
let current = node.parent;
|
|
120
|
+
while (current) {
|
|
121
|
+
if (current.type === 'VariableDeclarator' && current.id && current.id.name) {
|
|
122
|
+
return current.id.name;
|
|
123
|
+
}
|
|
124
|
+
current = current.parent;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @type {RuleModule} */
|
|
130
|
+
module.exports = {
|
|
131
|
+
meta: {
|
|
132
|
+
type: 'suggestion',
|
|
133
|
+
docs: {
|
|
134
|
+
description:
|
|
135
|
+
'Deprecates usage of the "handler" property in bento-data-grid cell action menu items. Use "event" instead.',
|
|
136
|
+
category: 'Deprecations',
|
|
137
|
+
url: 'https://github.com/Adyen/bento/blob/main/packages/eslint/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/README.md',
|
|
138
|
+
recommended: true,
|
|
139
|
+
},
|
|
140
|
+
messages: {
|
|
141
|
+
deprecation: `The "handler" property is deprecated in bento-data-grid cell action menu items. Use "event" instead.`,
|
|
142
|
+
},
|
|
143
|
+
fixable: 'code',
|
|
144
|
+
schema: [
|
|
145
|
+
{
|
|
146
|
+
type: 'object',
|
|
147
|
+
properties: {
|
|
148
|
+
autofix: {
|
|
149
|
+
type: 'boolean',
|
|
150
|
+
default: false,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
additionalProperties: false,
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/** @param {RuleContext} context */
|
|
159
|
+
create(context) {
|
|
160
|
+
const options = context.options[0] || {};
|
|
161
|
+
const autofix = options.autofix === true;
|
|
162
|
+
|
|
163
|
+
// Identifiers referenced in :cell-actions / :row-actions on bento-data-grid
|
|
164
|
+
const boundIdentifiers = new Set();
|
|
165
|
+
// Handler nodes found in menuData in <script>, pending cross-reference
|
|
166
|
+
const pendingHandlers = [];
|
|
167
|
+
|
|
168
|
+
const visitors = VueUtils.defineTemplateBodyVisitor(
|
|
169
|
+
context,
|
|
170
|
+
{
|
|
171
|
+
/**
|
|
172
|
+
* Matches :cell-actions or :row-actions bindings on bento-data-grid elements.
|
|
173
|
+
* Handles inline expressions directly, and collects identifier names for
|
|
174
|
+
* the script visitor to resolve.
|
|
175
|
+
*/
|
|
176
|
+
'VAttribute[directive=true][key.name.name="bind"]'(node) {
|
|
177
|
+
const argName = node.key && node.key.argument && node.key.argument.name;
|
|
178
|
+
if (!argName || !CELL_ACTION_PROPS.has(argName)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const startTag = node.parent;
|
|
183
|
+
const element = startTag && startTag.parent;
|
|
184
|
+
if (!element || !DATA_GRID_NAMES.has(element.name)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const expr = node.value && node.value.expression ? node.value.expression : null;
|
|
189
|
+
if (!expr) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (expr.type === 'Identifier') {
|
|
194
|
+
// Collect identifier name for the script visitor to check
|
|
195
|
+
boundIdentifiers.add(expr.name);
|
|
196
|
+
} else {
|
|
197
|
+
// Inline expression — search directly
|
|
198
|
+
findHandlersInMenuData(expr, context, autofix);
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
// Script visitor (runs before template): collect handler nodes with their variable names
|
|
204
|
+
'Property[key.name="handler"]'(node) {
|
|
205
|
+
if (!isInsideMenuData(node)) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const varName = getDeclaratorName(node);
|
|
209
|
+
if (varName) {
|
|
210
|
+
pendingHandlers.push({ node, varName });
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Program:exit runs after both script and template visitors have completed,
|
|
217
|
+
// allowing us to cross-reference collected identifiers with pending handlers.
|
|
218
|
+
const originalProgramExit = visitors['Program:exit'];
|
|
219
|
+
visitors['Program:exit'] = function (node) {
|
|
220
|
+
if (originalProgramExit) {
|
|
221
|
+
originalProgramExit(node);
|
|
222
|
+
}
|
|
223
|
+
for (const { node: handlerNode, varName } of pendingHandlers) {
|
|
224
|
+
if (boundIdentifiers.has(varName)) {
|
|
225
|
+
reportHandler(context, handlerNode, autofix);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return visitors;
|
|
231
|
+
},
|
|
232
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint';
|
|
2
|
+
import vueParser from 'vue-eslint-parser';
|
|
3
|
+
import tsParser from '@typescript-eslint/parser';
|
|
4
|
+
import deprecationRule from './deprecation-bento-data-grid-cell-action-menu-item-handler';
|
|
5
|
+
|
|
6
|
+
const ruleTester = new RuleTester({
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 'latest',
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
parser: vueParser,
|
|
11
|
+
parserOptions: {
|
|
12
|
+
parser: tsParser,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('@adyen/bento/deprecation-bento-data-grid-cell-action-menu-item-handler', () => {
|
|
18
|
+
ruleTester.run('deprecation-bento-data-grid-cell-action-menu-item-handler', deprecationRule, {
|
|
19
|
+
valid: [
|
|
20
|
+
{
|
|
21
|
+
name: 'Valid: menuData with event instead of handler',
|
|
22
|
+
filename: 'test.vue',
|
|
23
|
+
code: `<template>
|
|
24
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Edit', event: fn }] }]" />
|
|
25
|
+
</template>`,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'Valid: handler in menuData on a non-data-grid component (template)',
|
|
29
|
+
filename: 'test.vue',
|
|
30
|
+
code: `<template>
|
|
31
|
+
<test-component :cell-actions="[{ menuData: [{ text: 'Edit', handler: fn }] }]" />
|
|
32
|
+
</template>`,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'Valid: handler outside of menuData context',
|
|
36
|
+
filename: 'test.vue',
|
|
37
|
+
code: `<script>const obj = { handler: () => {} };</script>`,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Valid: handler in unrelated array',
|
|
41
|
+
filename: 'test.vue',
|
|
42
|
+
code: `<script>const arr = [{ handler: () => {} }];</script>`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'Valid: menuData with event in script',
|
|
46
|
+
filename: 'test.vue',
|
|
47
|
+
code: `<script>
|
|
48
|
+
const actions = [{ menuData: [{ text: 'Edit', event: () => {} }] }];
|
|
49
|
+
</script>`,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Valid: handler in menuData in script not passed to bento-data-grid',
|
|
53
|
+
filename: 'test.vue',
|
|
54
|
+
code: `<template>
|
|
55
|
+
<test-component :cell-actions="actions" />
|
|
56
|
+
</template>
|
|
57
|
+
<script>
|
|
58
|
+
const actions = [{ menuData: [{ text: 'Cancel', handler: () => {} }] }];
|
|
59
|
+
</script>`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
invalid: [
|
|
63
|
+
{
|
|
64
|
+
name: 'Invalid: handler in menuData (template, no autofix)',
|
|
65
|
+
filename: 'test.vue',
|
|
66
|
+
code: `<template>
|
|
67
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Cancel', handler: fn }] }]" />
|
|
68
|
+
</template>`,
|
|
69
|
+
output: null,
|
|
70
|
+
errors: [{ messageId: 'deprecation' }],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'Invalid: handler in menuData (template, autofix renames to event)',
|
|
74
|
+
filename: 'test.vue',
|
|
75
|
+
code: `<template>
|
|
76
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Cancel', handler: fn }] }]" />
|
|
77
|
+
</template>`,
|
|
78
|
+
output: `<template>
|
|
79
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Cancel', event: fn }] }]" />
|
|
80
|
+
</template>`,
|
|
81
|
+
options: [{ autofix: true }],
|
|
82
|
+
errors: [{ messageId: 'deprecation' }],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'Invalid: handler resolved from script variable via identifier',
|
|
86
|
+
filename: 'test.vue',
|
|
87
|
+
code: `<template>
|
|
88
|
+
<bento-data-grid :cell-actions="actions" />
|
|
89
|
+
</template>
|
|
90
|
+
<script>
|
|
91
|
+
const actions = [{ menuData: [{ text: 'Cancel', handler: () => {} }] }];
|
|
92
|
+
</script>`,
|
|
93
|
+
output: `<template>
|
|
94
|
+
<bento-data-grid :cell-actions="actions" />
|
|
95
|
+
</template>
|
|
96
|
+
<script>
|
|
97
|
+
const actions = [{ menuData: [{ text: 'Cancel', event: () => {} }] }];
|
|
98
|
+
</script>`,
|
|
99
|
+
options: [{ autofix: true }],
|
|
100
|
+
errors: [{ messageId: 'deprecation' }],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'Invalid: multiple handlers in menuData (template, autofix)',
|
|
104
|
+
filename: 'test.vue',
|
|
105
|
+
code: `<template>
|
|
106
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Cancel', handler: a }, { text: 'Delete', handler: b }] }]" />
|
|
107
|
+
</template>`,
|
|
108
|
+
output: `<template>
|
|
109
|
+
<bento-data-grid :cell-actions="[{ menuData: [{ text: 'Cancel', event: a }, { text: 'Delete', event: b }] }]" />
|
|
110
|
+
</template>`,
|
|
111
|
+
options: [{ autofix: true }],
|
|
112
|
+
errors: [{ messageId: 'deprecation' }, { messageId: 'deprecation' }],
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# deprecation-bento-date-range-picker-has-actions-prop
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Manages the **temporary** `has-actions` prop on `bento-date-range-picker`.
|
|
6
|
+
|
|
7
|
+
The `has-actions` prop is a temporary opt-in flag for the new actions behavior. This rule helps teams adopt it during
|
|
8
|
+
the transition period, and later remove it once the behavior becomes the default.
|
|
9
|
+
|
|
10
|
+
## Options
|
|
11
|
+
|
|
12
|
+
| Option | Type | Default | Description |
|
|
13
|
+
| :------------ | :-------------------- | :------ | :------------------------------------------------------------- |
|
|
14
|
+
| **`action`** | `'add'` \| `'remove'` | `'add'` | `add` reports missing `has-actions`. `remove` reports present. |
|
|
15
|
+
| **`autofix`** | `boolean` | `false` | Enables auto-fixing. |
|
|
16
|
+
|
|
17
|
+
## Rule Details
|
|
18
|
+
|
|
19
|
+
### Action: `add` (default)
|
|
20
|
+
|
|
21
|
+
Reports `bento-date-range-picker` instances that are **missing** the `has-actions` prop.
|
|
22
|
+
|
|
23
|
+
#### ❌ Incorrect
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<bento-date-range-picker label="Pick" />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### ✅ Correct
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<bento-date-range-picker has-actions label="Pick" />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Action: `remove`
|
|
36
|
+
|
|
37
|
+
Reports `bento-date-range-picker` instances that **have** the `has-actions` prop, so it can be cleaned up once the
|
|
38
|
+
behavior becomes permanent.
|
|
39
|
+
|
|
40
|
+
#### ❌ Incorrect
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<bento-date-range-picker has-actions label="Pick" />
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
#### ✅ Correct
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<bento-date-range-picker label="Pick" />
|
|
50
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<!-- These should trigger the "add" action (missing has-actions) -->
|
|
4
|
+
<bento-date-range-picker label="Pick a date" />
|
|
5
|
+
<bento-date-range-picker label="Another picker" :min="minDate" />
|
|
6
|
+
<bento-date-range-picker v-model="value" />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup></script>
|