@wordpress/eslint-plugin 24.4.1-next.v.202603161435.0 → 24.5.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/README.md CHANGED
@@ -82,9 +82,14 @@ The granular rulesets will not define any environment globals. As such, if they
82
82
  | [i18n-text-domain](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/i18n-text-domain.md) | Enforce passing valid text domains. | ✓ |
83
83
  | [i18n-translator-comments](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/i18n-translator-comments.md) | Enforce adding translator comments. | ✓ |
84
84
  | [no-base-control-with-label-without-id](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-base-control-with-label-without-id.md) | Disallow the usage of BaseControl component with a label prop set but omitting the id property. | ✓ |
85
+ | [no-dom-globals-in-constructor](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-dom-globals-in-constructor.md) | Disallow use of DOM globals in class constructors. | |
86
+ | [no-dom-globals-in-module-scope](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-dom-globals-in-module-scope.md) | Disallow use of DOM globals in module scope. | |
87
+ | [no-dom-globals-in-react-cc-render](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-dom-globals-in-react-cc-render.md) | Disallow use of DOM globals in React class component render methods. | |
88
+ | [no-dom-globals-in-react-fc](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-dom-globals-in-react-fc.md) | Disallow use of DOM globals in the render cycle of a React function component. | |
85
89
  | [components-no-missing-40px-size-prop](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/components-no-missing-40px-size-prop.md) | Disallow missing `__next40pxDefaultSize` prop on `@wordpress/components` components. | ✓ |
86
90
  | [components-no-unsafe-button-disabled](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/components-no-unsafe-button-disabled.md) | Disallow using `disabled` on Button without `accessibleWhenDisabled`. | ✓ |
87
91
  | [no-i18n-in-save](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-i18n-in-save.md) | Disallow translation functions in block save methods. | |
92
+ | [no-unmerged-classname](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-unmerged-classname.md) | Disallow unmerged `className` in components that spread rest props. | |
88
93
  | [no-unguarded-get-range-at](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-unguarded-get-range-at.md) | Disallow the usage of unguarded `getRangeAt` calls. | ✓ |
89
94
  | [no-unsafe-wp-apis](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/no-unsafe-wp-apis.md) | Disallow the usage of unsafe APIs from `@wordpress/*` packages | ✓ |
90
95
  | [use-recommended-components](https://github.com/WordPress/gutenberg/tree/HEAD/packages/eslint-plugin/docs/rules/use-recommended-components.md) | Encourage the use of recommended UI components in a WordPress environment. | |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/eslint-plugin",
3
- "version": "24.4.1-next.v.202603161435.0+ab4981c4f",
3
+ "version": "24.5.0",
4
4
  "description": "ESLint plugin for WordPress development.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -40,9 +40,9 @@
40
40
  "@babel/eslint-parser": "7.25.7",
41
41
  "@typescript-eslint/eslint-plugin": "^6.4.1",
42
42
  "@typescript-eslint/parser": "^6.4.1",
43
- "@wordpress/babel-preset-default": "^8.41.1-next.v.202603161435.0+ab4981c4f",
44
- "@wordpress/prettier-config": "^4.41.1-next.v.202603161435.0+ab4981c4f",
45
- "@wordpress/theme": "^0.8.1-next.v.202603161435.0+ab4981c4f",
43
+ "@wordpress/babel-preset-default": "^8.43.0",
44
+ "@wordpress/prettier-config": "^4.43.0",
45
+ "@wordpress/theme": "^0.10.0",
46
46
  "cosmiconfig": "^7.0.0",
47
47
  "eslint-config-prettier": "^8.3.0",
48
48
  "eslint-import-resolver-typescript": "^4.4.4",
@@ -78,5 +78,5 @@
78
78
  "publishConfig": {
79
79
  "access": "public"
80
80
  },
81
- "gitHead": "748f4e4564fcc0e6ae90200d90bb993a3cef5828"
81
+ "gitHead": "2cea90674d11aa521ec3f71652fb3a6a4c383969"
82
82
  }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { RuleTester } from 'eslint';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import rule from '../no-dom-globals-in-constructor';
10
+
11
+ const ruleTester = new RuleTester( {
12
+ parserOptions: {
13
+ ecmaVersion: 2020,
14
+ sourceType: 'module',
15
+ ecmaFeatures: { jsx: true },
16
+ },
17
+ } );
18
+
19
+ ruleTester.run( 'no-dom-globals-in-constructor', rule, {
20
+ valid: [
21
+ {
22
+ code: `class Foo {
23
+ method() { document.title = "test"; }
24
+ }`,
25
+ },
26
+ {
27
+ code: `class Foo {
28
+ constructor() { this.name = "test"; }
29
+ }`,
30
+ },
31
+ ],
32
+ invalid: [
33
+ {
34
+ code: `class Foo {
35
+ constructor() { document.title = "test"; }
36
+ }`,
37
+ errors: [
38
+ {
39
+ messageId: 'defaultMessage',
40
+ data: { name: 'document' },
41
+ },
42
+ ],
43
+ },
44
+ {
45
+ code: `class Foo {
46
+ constructor() { window.addEventListener("resize", () => {}); }
47
+ }`,
48
+ errors: [
49
+ {
50
+ messageId: 'defaultMessage',
51
+ data: { name: 'window' },
52
+ },
53
+ ],
54
+ },
55
+ ],
56
+ } );
57
+
58
+ // TypeScript-specific tests for shouldSkipReference.
59
+ const tsRuleTester = new RuleTester( {
60
+ parser: require.resolve( '@typescript-eslint/parser' ),
61
+ parserOptions: {
62
+ ecmaVersion: 2020,
63
+ sourceType: 'module',
64
+ ecmaFeatures: { jsx: true },
65
+ },
66
+ } );
67
+
68
+ tsRuleTester.run( 'no-dom-globals-in-constructor (TypeScript)', rule, {
69
+ valid: [
70
+ {
71
+ // TSTypeReference — type annotation using a DOM global.
72
+ code: `class Foo {
73
+ constructor( el: HTMLElement ) { this.el = el; }
74
+ }`,
75
+ },
76
+ {
77
+ // TSInterfaceHeritage — extending a DOM interface.
78
+ code: 'interface MyEl extends HTMLElement {}',
79
+ },
80
+ {
81
+ // TSTypeQuery — typeof in type position.
82
+ code: 'type Win = typeof window;',
83
+ },
84
+ {
85
+ // TSQualifiedName — DOM global as left side of a qualified type name.
86
+ code: 'type DocType = typeof window.document;',
87
+ },
88
+ ],
89
+ invalid: [
90
+ {
91
+ // Value-level usage should still be flagged even in TS files.
92
+ code: `class Foo {
93
+ constructor() { document.title = "test"; }
94
+ }`,
95
+ errors: [
96
+ {
97
+ messageId: 'defaultMessage',
98
+ data: { name: 'document' },
99
+ },
100
+ ],
101
+ },
102
+ ],
103
+ } );
@@ -0,0 +1,160 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { RuleTester } from 'eslint';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import rule from '../no-dom-globals-in-module-scope';
10
+
11
+ const ruleTester = new RuleTester( {
12
+ parserOptions: {
13
+ ecmaVersion: 2020,
14
+ sourceType: 'module',
15
+ ecmaFeatures: { jsx: true },
16
+ },
17
+ } );
18
+
19
+ ruleTester.run( 'no-dom-globals-in-module-scope', rule, {
20
+ valid: [
21
+ {
22
+ code: 'function foo() { window.scrollTo(0, 0); }',
23
+ },
24
+ {
25
+ code: 'if (typeof window !== "undefined") {}',
26
+ },
27
+ {
28
+ code: 'const isClient = typeof document !== "undefined";',
29
+ },
30
+ {
31
+ code: 'function effect() { const el = document.createElement("div"); }',
32
+ },
33
+ {
34
+ // Function scope in a script file should not be flagged.
35
+ code: 'function foo() { window.scrollTo(0, 0); }',
36
+ parserOptions: { ecmaVersion: 2020, sourceType: 'script' },
37
+ },
38
+ // Shared globals (browser + node) should NOT be flagged.
39
+ {
40
+ code: 'console.log("hello");',
41
+ },
42
+ {
43
+ code: 'setTimeout(() => {}, 100);',
44
+ },
45
+ {
46
+ code: 'const u = new URL("https://example.com");',
47
+ },
48
+ {
49
+ code: 'fetch("/api/data");',
50
+ },
51
+ ],
52
+ invalid: [
53
+ {
54
+ code: 'const width = window.innerWidth;',
55
+ errors: [
56
+ {
57
+ messageId: 'defaultMessage',
58
+ data: { name: 'window' },
59
+ },
60
+ ],
61
+ },
62
+ {
63
+ code: 'const el = document.createElement("div");',
64
+ errors: [
65
+ {
66
+ messageId: 'defaultMessage',
67
+ data: { name: 'document' },
68
+ },
69
+ ],
70
+ },
71
+ {
72
+ code: 'navigator.userAgent;',
73
+ errors: [
74
+ {
75
+ messageId: 'defaultMessage',
76
+ data: { name: 'navigator' },
77
+ },
78
+ ],
79
+ },
80
+ {
81
+ code: 'localStorage.getItem("key");',
82
+ errors: [
83
+ {
84
+ messageId: 'defaultMessage',
85
+ data: { name: 'localStorage' },
86
+ },
87
+ ],
88
+ },
89
+ {
90
+ code: 'sessionStorage.setItem("key", "value");',
91
+ errors: [
92
+ {
93
+ messageId: 'defaultMessage',
94
+ data: { name: 'sessionStorage' },
95
+ },
96
+ ],
97
+ },
98
+ {
99
+ code: 'history.pushState({}, "", "/new");',
100
+ errors: [
101
+ {
102
+ messageId: 'defaultMessage',
103
+ data: { name: 'history' },
104
+ },
105
+ ],
106
+ },
107
+ {
108
+ code: 'location.href = "/";',
109
+ errors: [
110
+ {
111
+ messageId: 'defaultMessage',
112
+ data: { name: 'location' },
113
+ },
114
+ ],
115
+ },
116
+ ],
117
+ } );
118
+
119
+ // TypeScript-specific tests for shouldSkipReference.
120
+ const tsRuleTester = new RuleTester( {
121
+ parser: require.resolve( '@typescript-eslint/parser' ),
122
+ parserOptions: {
123
+ ecmaVersion: 2020,
124
+ sourceType: 'module',
125
+ ecmaFeatures: { jsx: true },
126
+ },
127
+ } );
128
+
129
+ tsRuleTester.run( 'no-dom-globals-in-module-scope (TypeScript)', rule, {
130
+ valid: [
131
+ {
132
+ // TSTypeReference — type annotation using a DOM global.
133
+ code: 'const el: HTMLElement = null as any;',
134
+ },
135
+ {
136
+ // TSInterfaceHeritage — extending a DOM interface.
137
+ code: 'interface MyEl extends HTMLElement {}',
138
+ },
139
+ {
140
+ // TSTypeQuery — typeof in type position.
141
+ code: 'type Win = typeof window;',
142
+ },
143
+ {
144
+ // TSQualifiedName — DOM global as left side of a qualified type name.
145
+ code: 'type DocType = typeof window.document;',
146
+ },
147
+ ],
148
+ invalid: [
149
+ {
150
+ // Value-level usage should still be flagged even in TS files.
151
+ code: 'const width = window.innerWidth;',
152
+ errors: [
153
+ {
154
+ messageId: 'defaultMessage',
155
+ data: { name: 'window' },
156
+ },
157
+ ],
158
+ },
159
+ ],
160
+ } );
@@ -0,0 +1,98 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { RuleTester } from 'eslint';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import rule from '../no-dom-globals-in-react-cc-render';
10
+
11
+ const ruleTester = new RuleTester( {
12
+ parserOptions: {
13
+ ecmaVersion: 2020,
14
+ sourceType: 'module',
15
+ ecmaFeatures: { jsx: true },
16
+ },
17
+ } );
18
+
19
+ ruleTester.run( 'no-dom-globals-in-react-cc-render', rule, {
20
+ valid: [
21
+ {
22
+ code: `class Foo {
23
+ render() { const x = 1; return <div>{x}</div>; }
24
+ }`,
25
+ },
26
+ {
27
+ code: `class Foo {
28
+ componentDidMount() { window.scrollTo(0, 0); }
29
+ render() { return <div />; }
30
+ }`,
31
+ },
32
+ {
33
+ code: `class Foo {
34
+ render() { return "not jsx"; }
35
+ }`,
36
+ },
37
+ ],
38
+ invalid: [
39
+ {
40
+ code: `class Foo {
41
+ render() { const w = window.innerWidth; return <div>{w}</div>; }
42
+ }`,
43
+ errors: [
44
+ {
45
+ messageId: 'defaultMessage',
46
+ data: { name: 'window' },
47
+ },
48
+ ],
49
+ },
50
+ ],
51
+ } );
52
+
53
+ // TypeScript-specific tests for shouldSkipReference.
54
+ const tsRuleTester = new RuleTester( {
55
+ parser: require.resolve( '@typescript-eslint/parser' ),
56
+ parserOptions: {
57
+ ecmaVersion: 2020,
58
+ sourceType: 'module',
59
+ ecmaFeatures: { jsx: true },
60
+ },
61
+ } );
62
+
63
+ tsRuleTester.run( 'no-dom-globals-in-react-cc-render (TypeScript)', rule, {
64
+ valid: [
65
+ {
66
+ // TSTypeReference — type annotation using a DOM global.
67
+ code: `class Foo {
68
+ render() { const el: HTMLElement = this.ref; return <div />; }
69
+ }`,
70
+ },
71
+ {
72
+ // TSInterfaceHeritage — extending a DOM interface.
73
+ code: 'interface MyEl extends HTMLElement {}',
74
+ },
75
+ {
76
+ // TSTypeQuery — typeof in type position.
77
+ code: 'type Win = typeof window;',
78
+ },
79
+ {
80
+ // TSQualifiedName — DOM global as left side of a qualified type name.
81
+ code: 'type DocType = typeof window.document;',
82
+ },
83
+ ],
84
+ invalid: [
85
+ {
86
+ // Value-level usage should still be flagged even in TS files.
87
+ code: `class Foo {
88
+ render() { const w = window.innerWidth; return <div>{w}</div>; }
89
+ }`,
90
+ errors: [
91
+ {
92
+ messageId: 'defaultMessage',
93
+ data: { name: 'window' },
94
+ },
95
+ ],
96
+ },
97
+ ],
98
+ } );
@@ -0,0 +1,125 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { RuleTester } from 'eslint';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import rule from '../no-dom-globals-in-react-fc';
10
+
11
+ const ruleTester = new RuleTester( {
12
+ parserOptions: {
13
+ ecmaVersion: 2020,
14
+ sourceType: 'module',
15
+ ecmaFeatures: { jsx: true },
16
+ },
17
+ } );
18
+
19
+ ruleTester.run( 'no-dom-globals-in-react-fc', rule, {
20
+ valid: [
21
+ {
22
+ code: 'function notAComponent() { window.scrollTo(0, 0); }',
23
+ },
24
+ {
25
+ code: 'function Component() { return <div />; }',
26
+ },
27
+ {
28
+ code: `function Component() {
29
+ useEffect(() => { window.scrollTo(0, 0); });
30
+ return <div />;
31
+ }`,
32
+ },
33
+ {
34
+ // DOM global inside a nested callback (event handler) inside FC
35
+ // is allowed — the handler runs at event time, not render time.
36
+ code: `function Component() {
37
+ const onClick = () => { document.title = "clicked"; };
38
+ return <button onClick={onClick} />;
39
+ }`,
40
+ },
41
+ ],
42
+ invalid: [
43
+ {
44
+ code: `function Component() {
45
+ window.addEventListener("resize", () => {});
46
+ return <div />;
47
+ }`,
48
+ errors: [
49
+ {
50
+ messageId: 'defaultMessage',
51
+ data: { name: 'window' },
52
+ },
53
+ ],
54
+ },
55
+ {
56
+ code: `const Header = () => {
57
+ const w = document.body.clientWidth;
58
+ return <header>{w}</header>;
59
+ }`,
60
+ errors: [
61
+ {
62
+ messageId: 'defaultMessage',
63
+ data: { name: 'document' },
64
+ },
65
+ ],
66
+ },
67
+ {
68
+ code: `const Icon = ( { name } ) => <span className={ window.iconPrefix + name } />;`,
69
+ errors: [
70
+ {
71
+ messageId: 'defaultMessage',
72
+ data: { name: 'window' },
73
+ },
74
+ ],
75
+ },
76
+ ],
77
+ } );
78
+
79
+ // TypeScript-specific tests for shouldSkipReference.
80
+ const tsRuleTester = new RuleTester( {
81
+ parser: require.resolve( '@typescript-eslint/parser' ),
82
+ parserOptions: {
83
+ ecmaVersion: 2020,
84
+ sourceType: 'module',
85
+ ecmaFeatures: { jsx: true },
86
+ },
87
+ } );
88
+
89
+ tsRuleTester.run( 'no-dom-globals-in-react-fc (TypeScript)', rule, {
90
+ valid: [
91
+ {
92
+ // TSTypeReference — type annotation using a DOM global.
93
+ code: `function Component( { el }: { el: HTMLElement } ) {
94
+ return <div />;
95
+ }`,
96
+ },
97
+ {
98
+ // TSInterfaceHeritage — extending a DOM interface.
99
+ code: 'interface MyEl extends HTMLElement {}',
100
+ },
101
+ {
102
+ // TSTypeQuery — typeof in type position.
103
+ code: 'type Win = typeof window;',
104
+ },
105
+ {
106
+ // TSQualifiedName — DOM global as left side of a qualified type name.
107
+ code: 'type DocType = typeof window.document;',
108
+ },
109
+ ],
110
+ invalid: [
111
+ {
112
+ // Value-level usage should still be flagged even in TS files.
113
+ code: `function Component() {
114
+ const w = window.innerWidth;
115
+ return <div>{w}</div>;
116
+ }`,
117
+ errors: [
118
+ {
119
+ messageId: 'defaultMessage',
120
+ data: { name: 'window' },
121
+ },
122
+ ],
123
+ },
124
+ ],
125
+ } );
@@ -90,7 +90,6 @@ function render() {
90
90
  errors: [
91
91
  {
92
92
  messageId: 'noI18nInSave',
93
- type: 'CallExpression',
94
93
  },
95
94
  ],
96
95
  },
@@ -103,7 +102,6 @@ function save() {
103
102
  errors: [
104
103
  {
105
104
  messageId: 'noI18nInSave',
106
- type: 'CallExpression',
107
105
  },
108
106
  ],
109
107
  },
@@ -116,7 +114,6 @@ const save = () => {
116
114
  errors: [
117
115
  {
118
116
  messageId: 'noI18nInSave',
119
- type: 'CallExpression',
120
117
  },
121
118
  ],
122
119
  },
@@ -129,7 +126,6 @@ const save = function() {
129
126
  errors: [
130
127
  {
131
128
  messageId: 'noI18nInSave',
132
- type: 'CallExpression',
133
129
  },
134
130
  ],
135
131
  },
@@ -142,7 +138,6 @@ export default function save() {
142
138
  errors: [
143
139
  {
144
140
  messageId: 'noI18nInSave',
145
- type: 'CallExpression',
146
141
  },
147
142
  ],
148
143
  },
@@ -157,7 +152,6 @@ const settings = {
157
152
  errors: [
158
153
  {
159
154
  messageId: 'noI18nInSave',
160
- type: 'CallExpression',
161
155
  },
162
156
  ],
163
157
  },
@@ -170,7 +164,6 @@ const settings = {
170
164
  errors: [
171
165
  {
172
166
  messageId: 'noI18nInSave',
173
- type: 'CallExpression',
174
167
  },
175
168
  ],
176
169
  },
@@ -183,7 +176,6 @@ function save() {
183
176
  errors: [
184
177
  {
185
178
  messageId: 'noI18nInSave',
186
- type: 'CallExpression',
187
179
  },
188
180
  ],
189
181
  },
@@ -197,7 +189,6 @@ function save() {
197
189
  errors: [
198
190
  {
199
191
  messageId: 'noI18nInSave',
200
- type: 'CallExpression',
201
192
  },
202
193
  ],
203
194
  },
@@ -211,7 +202,6 @@ function save() {
211
202
  errors: [
212
203
  {
213
204
  messageId: 'noI18nInSave',
214
- type: 'CallExpression',
215
205
  },
216
206
  ],
217
207
  },
@@ -228,7 +218,6 @@ function save() {
228
218
  errors: [
229
219
  {
230
220
  messageId: 'noI18nInSave',
231
- type: 'CallExpression',
232
221
  },
233
222
  ],
234
223
  },
@@ -243,11 +232,9 @@ function save() {
243
232
  errors: [
244
233
  {
245
234
  messageId: 'noI18nInSave',
246
- type: 'CallExpression',
247
235
  },
248
236
  {
249
237
  messageId: 'noI18nInSave',
250
- type: 'CallExpression',
251
238
  },
252
239
  ],
253
240
  },
@@ -262,7 +249,6 @@ function save() {
262
249
  errors: [
263
250
  {
264
251
  messageId: 'noI18nInSave',
265
- type: 'CallExpression',
266
252
  },
267
253
  ],
268
254
  },
@@ -24,6 +24,15 @@ ruleTester.run( 'no-setting-ds-tokens', rule, {
24
24
  {
25
25
  code: `<div style={ { margin: '10px' } } />`,
26
26
  },
27
+ {
28
+ code: `const styles = { '--my-custom-prop': 'value' };`,
29
+ },
30
+ {
31
+ code: `const styles = { color: 'var(--wpds-color-fg-content-neutral)' };`,
32
+ },
33
+ {
34
+ code: `const { '--wpds-color-fg-content-neutral': neutralColor } = styles;`,
35
+ },
27
36
  ],
28
37
  invalid: [
29
38
  {
@@ -42,5 +51,29 @@ ruleTester.run( 'no-setting-ds-tokens', rule, {
42
51
  },
43
52
  ],
44
53
  },
54
+ {
55
+ code: `const styles = { '--wpds-color-fg-content-neutral': 'red' };`,
56
+ errors: [
57
+ {
58
+ messageId: 'disallowedSet',
59
+ },
60
+ ],
61
+ },
62
+ {
63
+ code: `function getStyles() { return { '--wpds-font-size-md': '10px' }; }`,
64
+ errors: [
65
+ {
66
+ messageId: 'disallowedSet',
67
+ },
68
+ ],
69
+ },
70
+ {
71
+ code: `const config = { inner: { '--wpds-color-fg-content-neutral': 'red' } };`,
72
+ errors: [
73
+ {
74
+ messageId: 'disallowedSet',
75
+ },
76
+ ],
77
+ },
45
78
  ],
46
79
  } );