@adyen/eslint-plugin-bento 2.22.0 → 2.24.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 (85) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +31 -15
  3. package/configs/vue-recommended.js +16 -0
  4. package/configs/vue-strict.js +17 -1
  5. package/index.js +3 -0
  6. package/package.json +3 -3
  7. package/rules/deprecation-bento-tag-variant-enum/README.md +69 -0
  8. package/rules/deprecation-bento-tag-variant-enum/deprecation-bento-tag-variant-enum.js +167 -0
  9. package/rules/deprecation-filter-bar-deprecated-props/README.md +7 -0
  10. package/rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props.js +14 -3
  11. package/rules/vue-no-redundant-dialog-v-if/README.md +55 -0
  12. package/rules/vue-no-redundant-dialog-v-if/vue-no-redundant-dialog-v-if.js +150 -0
  13. package/rules/vue-no-use-bento-translation-overrides/README.md +14 -0
  14. package/rules/vue-no-use-bento-translation-overrides/vue-no-use-bento-translation-overrides.js +93 -0
  15. package/utils/component-slot-migration.js +22 -4
  16. package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/deprecation-bento-data-grid-cell-action-menu-item-handler.vue +0 -63
  17. package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/__tests__/eslint.config.js +0 -26
  18. 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
  19. package/rules/deprecation-bento-data-grid-cell-action-menu-item-handler/deprecation-bento-data-grid-cell-action-menu-item-handler.test.ts +0 -116
  20. package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/deprecation-bento-date-range-picker-has-actions-prop.vue +0 -10
  21. package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/eslint.config.js +0 -29
  22. package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/deprecation-bento-date-range-picker-has-actions-prop.vue +0 -11
  23. package/rules/deprecation-bento-date-range-picker-has-actions-prop/__tests__/remove/eslint.config.js +0 -29
  24. package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.integration.test.ts +0 -47
  25. package/rules/deprecation-bento-date-range-picker-has-actions-prop/deprecation-bento-date-range-picker-has-actions-prop.test.ts +0 -176
  26. package/rules/deprecation-bento-dropdown-size-prop/__tests__/deprecation-bento-dropdown-size-prop.vue +0 -9
  27. package/rules/deprecation-bento-dropdown-size-prop/__tests__/eslint.config.js +0 -26
  28. package/rules/deprecation-bento-dropdown-size-prop/deprecation-bento-dropdown-size-prop.integration.test.ts +0 -33
  29. package/rules/deprecation-bento-dropdown-size-prop/deprecation-bento-dropdown-size-prop.test.ts +0 -101
  30. package/rules/deprecation-bento-popover-modifiers-prop/__tests__/deprecation-bento-popover-modifiers-prop.vue +0 -9
  31. package/rules/deprecation-bento-popover-modifiers-prop/__tests__/eslint.config.js +0 -26
  32. package/rules/deprecation-bento-popover-modifiers-prop/deprecation-bento-popover-modifiers-prop.integration.test.ts +0 -24
  33. package/rules/deprecation-bento-popover-modifiers-prop/deprecation-bento-popover-modifiers-prop.test.ts +0 -109
  34. package/rules/deprecation-bento-timeline-item-variant-prop/__tests__/deprecation-bento-timeline-item-variant-prop.vue +0 -9
  35. package/rules/deprecation-bento-timeline-item-variant-prop/__tests__/eslint.config.js +0 -26
  36. package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.integration.test.ts +0 -35
  37. package/rules/deprecation-bento-timeline-item-variant-prop/deprecation-bento-timeline-item-variant-prop.test.ts +0 -141
  38. package/rules/deprecation-components-aria-label-prop/__tests__/deprecation-components-aria-label-prop.vue +0 -25
  39. package/rules/deprecation-components-aria-label-prop/__tests__/eslint.config.js +0 -26
  40. package/rules/deprecation-components-aria-label-prop/deprecation-components-aria-label-prop.integration.test.ts +0 -36
  41. package/rules/deprecation-components-aria-label-prop/deprecation-components-aria-label-prop.test.ts +0 -194
  42. package/rules/deprecation-components-error-prop/__tests__/deprecation-components-error-prop.vue +0 -17
  43. package/rules/deprecation-components-error-prop/__tests__/eslint.config.js +0 -26
  44. package/rules/deprecation-components-error-prop/deprecation-components-error-prop.integration.test.ts +0 -41
  45. package/rules/deprecation-components-error-prop/deprecation-components-error-prop.test.ts +0 -153
  46. package/rules/deprecation-components-has-error-prop/__tests__/deprecation-components-has-error-prop.vue +0 -13
  47. package/rules/deprecation-components-has-error-prop/__tests__/eslint.config.js +0 -26
  48. package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.integration.test.ts +0 -37
  49. package/rules/deprecation-components-has-error-prop/deprecation-components-has-error-prop.test.ts +0 -122
  50. package/rules/deprecation-components-input-emit/__tests__/deprecation-components-input-emit.vue +0 -22
  51. package/rules/deprecation-components-input-emit/__tests__/eslint.config.js +0 -25
  52. package/rules/deprecation-components-input-emit/deprecation-components-input-emit.integration.test.ts +0 -43
  53. package/rules/deprecation-components-input-emit/deprecation-components-input-emit.test.ts +0 -320
  54. package/rules/deprecation-components-value-prop/__tests__/deprecation-components-value-prop.vue +0 -69
  55. package/rules/deprecation-components-value-prop/__tests__/eslint.config.js +0 -25
  56. package/rules/deprecation-components-value-prop/deprecation-components-value-prop.integration.test.ts +0 -37
  57. package/rules/deprecation-components-value-prop/deprecation-components-value-prop.test.ts +0 -480
  58. package/rules/deprecation-country-custom-usage/__tests__/deprecation-country-custom-usage.vue +0 -93
  59. package/rules/deprecation-country-custom-usage/__tests__/eslint.config.js +0 -25
  60. package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.integration.test.ts +0 -22
  61. package/rules/deprecation-country-custom-usage/deprecation-country-custom-usage.test.ts +0 -380
  62. package/rules/deprecation-currency-default-slot/__tests__/deprecation-currency-default-slot.vue +0 -7
  63. package/rules/deprecation-currency-default-slot/__tests__/eslint.config.js +0 -24
  64. package/rules/deprecation-currency-default-slot/deprecation-currency-default-slot.integration.test.ts +0 -29
  65. package/rules/deprecation-currency-default-slot/deprecation-currency-default-slot.test.ts +0 -136
  66. package/rules/deprecation-filter-bar-deprecated-props/__tests__/deprecation-filter-bar-deprecated-props.vue +0 -62
  67. package/rules/deprecation-filter-bar-deprecated-props/__tests__/eslint.config.js +0 -25
  68. package/rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props.integration.test.ts +0 -22
  69. package/rules/deprecation-filter-bar-deprecated-props/deprecation-filter-bar-deprecated-props.test.ts +0 -467
  70. package/rules/deprecation-input-filter-dropdown-options/__tests__/deprecation-input-filter-dropdown-options.vue +0 -46
  71. package/rules/deprecation-input-filter-dropdown-options/__tests__/eslint.config.js +0 -26
  72. package/rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options.integration.test.ts +0 -27
  73. package/rules/deprecation-input-filter-dropdown-options/deprecation-input-filter-dropdown-options.test.ts +0 -392
  74. package/rules/deprecation-tag-default-slot/__tests__/deprecation-tag-default-slot.vue +0 -5
  75. package/rules/deprecation-tag-default-slot/__tests__/eslint.config.js +0 -24
  76. package/rules/deprecation-tag-default-slot/deprecation-tag-default-slot.integration.test.ts +0 -29
  77. package/rules/deprecation-tag-default-slot/deprecation-tag-default-slot.test.ts +0 -145
  78. package/rules/tailwind-v3-to-bento/__tests__/eslint.config.js +0 -24
  79. package/rules/tailwind-v3-to-bento/__tests__/tailwind-v3-to-bento.vue +0 -15
  80. package/rules/tailwind-v3-to-bento/tailwind-v3-to-bento.integration.test.ts +0 -29
  81. package/rules/tailwind-v3-to-bento/tailwind-v3-to-bento.test.ts +0 -403
  82. package/rules/vue-old-spacer-tokens/__tests__/eslint.config.js +0 -24
  83. package/rules/vue-old-spacer-tokens/__tests__/vue-old-spacer-tokens.vue +0 -5
  84. package/rules/vue-old-spacer-tokens/vue-old-spacer-tokens.integration.test.ts +0 -29
  85. package/rules/vue-old-spacer-tokens/vue-old-spacer-tokens.test.ts +0 -77
@@ -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
+ ```
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @typedef {import('eslint').Rule.RuleContext} RuleContext
3
+ */
4
+ /**
5
+ * @typedef {import('eslint').Rule.RuleModule} RuleModule
6
+ */
7
+
8
+ const BENTO_VUE3_PACKAGE = '@adyen/bento-vue3';
9
+ const RESTRICTED_COMPOSABLE = 'useBentoTranslationOverrides';
10
+
11
+ /** @type {RuleModule} */
12
+ module.exports = {
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: `Restricts use of ${RESTRICTED_COMPOSABLE} to approved customer-facing SDKs and component libraries.`,
17
+ category: 'Restrictions',
18
+ url: 'https://github.com/Adyen/bento/blob/main/packages/eslint/rules/vue-no-use-bento-translation-overrides/README.md',
19
+ recommended: true,
20
+ },
21
+ messages: {
22
+ restricted:
23
+ '`useBentoTranslationOverrides` is restricted to teams building SDKs or component libraries for external customers and must not be used in Adyen products. Request approval from the Bento team before using this composable.',
24
+ },
25
+ schema: [],
26
+ },
27
+
28
+ /** @param {RuleContext} context */
29
+ create(context) {
30
+ const namespaceImports = new Set();
31
+
32
+ const getImportedName = specifier => {
33
+ if (specifier.type !== 'ImportSpecifier' && specifier.type !== 'ExportSpecifier') {
34
+ return null;
35
+ }
36
+
37
+ const imported = specifier.type === 'ImportSpecifier' ? specifier.imported : specifier.local;
38
+ return imported.type === 'Identifier' ? imported.name : imported.value;
39
+ };
40
+
41
+ const reportRestrictedSpecifier = specifier => {
42
+ if (getImportedName(specifier) === RESTRICTED_COMPOSABLE) {
43
+ context.report({
44
+ node: specifier,
45
+ messageId: 'restricted',
46
+ });
47
+ }
48
+ };
49
+
50
+ return {
51
+ ImportDeclaration(node) {
52
+ if (node.source.value !== BENTO_VUE3_PACKAGE) {
53
+ return;
54
+ }
55
+
56
+ for (const specifier of node.specifiers) {
57
+ if (specifier.type === 'ImportNamespaceSpecifier') {
58
+ namespaceImports.add(specifier.local.name);
59
+ } else {
60
+ reportRestrictedSpecifier(specifier);
61
+ }
62
+ }
63
+ },
64
+ ExportNamedDeclaration(node) {
65
+ if (node.source?.value !== BENTO_VUE3_PACKAGE) {
66
+ return;
67
+ }
68
+
69
+ node.specifiers.forEach(reportRestrictedSpecifier);
70
+ },
71
+ MemberExpression(node) {
72
+ if (node.object.type !== 'Identifier' || !namespaceImports.has(node.object.name)) {
73
+ return;
74
+ }
75
+
76
+ const propertyName = node.computed
77
+ ? node.property.type === 'Literal'
78
+ ? node.property.value
79
+ : null
80
+ : node.property.type === 'Identifier'
81
+ ? node.property.name
82
+ : null;
83
+
84
+ if (propertyName === RESTRICTED_COMPOSABLE) {
85
+ context.report({
86
+ node,
87
+ messageId: 'restricted',
88
+ });
89
+ }
90
+ },
91
+ };
92
+ },
93
+ };
@@ -6,6 +6,7 @@ const j = require('jscodeshift');
6
6
  */
7
7
 
8
8
  /**
9
+ * @typedef {import('vue-eslint-parser').AST.VElement} VElement
9
10
  * @typedef {import('vue-eslint-parser').AST.VText} VText
10
11
  * @typedef {import('vue-eslint-parser').AST.VExpressionContainer} VExpressionContainer
11
12
  */
@@ -26,10 +27,23 @@ module.exports = {
26
27
  */
27
28
  componentSlotMigration({ propertyName, context, template, alwaysExpression = false }) {
28
29
  return node => {
29
- if (!node.children.length) {
30
- return;
30
+ /**
31
+ * @param {VElement | VText | VExpressionContainer} child
32
+ * @returns {boolean}
33
+ */
34
+ function isNamedSlot(child) {
35
+ return (
36
+ child.type === 'VElement' &&
37
+ child.name === 'template' &&
38
+ child.startTag.attributes.some(
39
+ attribute => attribute.directive && attribute.key.name.name === 'slot'
40
+ )
41
+ );
31
42
  }
32
43
 
44
+ // Named slots are not default slot content and should not trigger migration.
45
+ const contentNodes = node.children.filter(child => !isNamedSlot(child));
46
+
33
47
  // Turned true if one of the children is an expression
34
48
  let hasExpression = false;
35
49
 
@@ -72,7 +86,11 @@ module.exports = {
72
86
 
73
87
  // Remove empty nodes
74
88
  /** @type { Array<VText | VExpressionContainer> } */
75
- const filteredNodes = node.children.filter(removeEmptyVTextNodes);
89
+ const filteredNodes = contentNodes.filter(removeEmptyVTextNodes);
90
+
91
+ if (!filteredNodes.length) {
92
+ return;
93
+ }
76
94
 
77
95
  // Get all content and concat
78
96
  const slotContent = (() => {
@@ -80,7 +98,7 @@ module.exports = {
80
98
  return transformNodeToText(filteredNodes[0])?.trim();
81
99
  }
82
100
 
83
- const content = node.children
101
+ const content = contentNodes
84
102
  // eslint-disable-next-line @typescript-eslint/no-shadow
85
103
  .map((/** @type {VText | VExpressionContainer} */ node) => transformNodeToText(node, true))
86
104
  .join('')
@@ -1,63 +0,0 @@
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>
@@ -1,26 +0,0 @@
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
- ]);
@@ -1,24 +0,0 @@
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
- });
@@ -1,116 +0,0 @@
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
- });
@@ -1,10 +0,0 @@
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>
@@ -1,29 +0,0 @@
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-date-range-picker-has-actions-prop': [
23
- 'warn',
24
- { action: 'add', autofix: true },
25
- ],
26
- },
27
- files: ['**/*.vue'],
28
- },
29
- ]);
@@ -1,11 +0,0 @@
1
- <template>
2
- <div>
3
- <!-- These should trigger the "remove" action (has-actions present) -->
4
- <bento-date-range-picker has-actions />
5
- <bento-date-range-picker has-actions label="Pick a date" />
6
- <bento-date-range-picker :has-actions="true" />
7
- <bento-date-range-picker :has-actions="false" />
8
- </div>
9
- </template>
10
-
11
- <script setup></script>
@@ -1,29 +0,0 @@
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-date-range-picker-has-actions-prop': [
23
- 'warn',
24
- { action: 'remove', autofix: true },
25
- ],
26
- },
27
- files: ['**/*.vue'],
28
- },
29
- ]);
@@ -1,47 +0,0 @@
1
- import path from 'node:path';
2
- import { execFileSyncEslintVueFiles } from '../../utils/exec-file-sync-eslint-vue-files';
3
-
4
- describe('@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop', () => {
5
- it('should lint with warning when has-actions is missing (add action)', () => {
6
- const eslintrc = path.resolve(__dirname, '__tests__', 'eslint.config.js');
7
- const vueFile = path.resolve(
8
- __dirname,
9
- '__tests__',
10
- 'deprecation-bento-date-range-picker-has-actions-prop.vue'
11
- );
12
-
13
- const result = JSON.parse(execFileSyncEslintVueFiles(eslintrc, vueFile));
14
-
15
- // The test .vue file has 3 bento-date-range-picker instances without has-actions
16
- expect(result[0].warningCount).toBe(3);
17
-
18
- expect(result[0].messages[0]).toMatchObject({
19
- ruleId: '@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop',
20
- severity: 1,
21
- messageId: 'missingProp',
22
- message: `The temporary "has-actions" prop is missing on bento-date-range-picker. Add it to opt in to the new actions behavior.`,
23
- });
24
- });
25
-
26
- it('should lint with warning when has-actions is present (remove action)', () => {
27
- const eslintrc = path.resolve(__dirname, '__tests__', 'remove', 'eslint.config.js');
28
- const vueFile = path.resolve(
29
- __dirname,
30
- '__tests__',
31
- 'remove',
32
- 'deprecation-bento-date-range-picker-has-actions-prop.vue'
33
- );
34
-
35
- const result = JSON.parse(execFileSyncEslintVueFiles(eslintrc, vueFile));
36
-
37
- // The test .vue file has 4 bento-date-range-picker instances with has-actions
38
- expect(result[0].warningCount).toBe(4);
39
-
40
- expect(result[0].messages[0]).toMatchObject({
41
- ruleId: '@adyen/bento/deprecation-bento-date-range-picker-has-actions-prop',
42
- severity: 1,
43
- messageId: 'removeProp',
44
- message: `The temporary "has-actions" prop should be removed from bento-date-range-picker.`,
45
- });
46
- });
47
- });