@frontify/eslint-config-basic 1.0.13 → 1.0.15

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/eslint.config.mjs CHANGED
@@ -3,16 +3,16 @@
3
3
  // @ts-check
4
4
 
5
5
  import eslint from '@eslint/js';
6
+ import eslintPluginMarkdown from '@eslint/markdown';
6
7
  import eslintPluginComments from '@eslint-community/eslint-plugin-eslint-comments/configs';
7
8
  import eslintPluginStylistic from '@stylistic/eslint-plugin';
8
9
  import { defineConfig } from 'eslint/config';
9
- import eslintPluginImport from 'eslint-plugin-import';
10
+ import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
11
+ import { createNodeResolver, default as eslintPluginImportX } from 'eslint-plugin-import-x';
10
12
  import eslintPluginJsonc from 'eslint-plugin-jsonc';
11
13
  // @ts-expect-error No types available
12
14
  import eslintPluginLodash from 'eslint-plugin-lodash';
13
15
  // @ts-expect-error No types available
14
- import eslintPluginMarkdown from 'eslint-plugin-markdown';
15
- // @ts-expect-error No types available
16
16
  import eslintPluginNoOnlyTests from 'eslint-plugin-no-only-tests';
17
17
  import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
18
18
  // @ts-expect-error No types available
@@ -22,23 +22,131 @@ import eslintPluginYml from 'eslint-plugin-yml';
22
22
  import globals from 'globals';
23
23
  import tseslint from 'typescript-eslint';
24
24
 
25
+ /**
26
+ * eslint-plugin-jsonc / eslint-plugin-yml flat presets end with `{ rules }` without `files`, which would apply to every file.
27
+ * Spreading the scoped preset into `defineConfig` matches `{ files, ...preset }` for a single merged object.
28
+ *
29
+ * @param {import('eslint').Linter.Config[]} preset
30
+ * @param {{ files: string[], ignores?: string[], language?: string }} scope
31
+ */
32
+ function scopeFlatPreset(preset, scope) {
33
+ const { files, ignores, language } = scope;
34
+ return preset.map((config) => {
35
+ if (config.rules !== undefined && config.files === undefined) {
36
+ return {
37
+ ...config,
38
+ files,
39
+ ...(ignores?.length ? { ignores } : {}),
40
+ };
41
+ }
42
+ if (language !== undefined && 'language' in config && Array.isArray(config.files)) {
43
+ return {
44
+ ...config,
45
+ files,
46
+ ...(ignores?.length ? { ignores } : {}),
47
+ language,
48
+ };
49
+ }
50
+ return config;
51
+ });
52
+ }
53
+
54
+ const jsonWithCommentsPatterns = ['**/*.jsonc', '**/.vscode/**/*.json', '**/tsconfig.json', '**/tsconfig.*.json'];
55
+
56
+ const strictJsonScope = {
57
+ files: ['**/*.json'],
58
+ ignores: ['**/package-lock.json', ...jsonWithCommentsPatterns],
59
+ language: 'jsonc/json',
60
+ };
61
+
62
+ const yamlScope = {
63
+ files: ['**/*.yaml', '**/*.yml'],
64
+ ignores: ['**/pnpm-lock.yaml', '**/yarn.lock'],
65
+ language: 'yml/yaml',
66
+ };
67
+
25
68
  export default defineConfig(
26
- eslint.configs.recommended,
69
+ {
70
+ ...eslint.configs.recommended,
71
+ files: ['**/*.{js,mjs,cjs,jsx}'],
72
+ },
27
73
  tseslint.configs.recommendedTypeChecked,
28
74
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
29
75
  eslintPluginPromise.configs['flat/recommended'],
30
76
  eslintPluginComments.recommended,
31
- eslintPluginJsonc.configs['flat/recommended-with-json'],
32
- eslintPluginJsonc.configs['flat/prettier'],
33
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
34
- eslintPluginMarkdown.configs.recommended,
35
- eslintPluginYml.configs['flat/recommended'],
77
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/recommended-with-json'], strictJsonScope),
78
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/prettier'], strictJsonScope),
79
+ {
80
+ ...strictJsonScope,
81
+ extends: [tseslint.configs.disableTypeChecked],
82
+ rules: {
83
+ quotes: ['error', 'double'],
84
+ 'quote-props': ['error', 'always'],
85
+ 'comma-dangle': ['error', 'never'],
86
+ semi: 'off',
87
+ 'jsonc/array-bracket-spacing': ['error', 'never'],
88
+ 'jsonc/comma-dangle': ['error', 'never'],
89
+ 'jsonc/comma-style': ['error', 'last'],
90
+ 'jsonc/key-spacing': ['error', { beforeColon: false, afterColon: true }],
91
+ 'jsonc/no-octal-escape': 'error',
92
+ 'jsonc/object-curly-newline': ['error', { multiline: true, consistent: true }],
93
+ 'jsonc/object-curly-spacing': ['error', 'always'],
94
+ 'jsonc/object-property-newline': ['error', { allowMultiplePropertiesPerLine: true }],
95
+ 'jsonc/no-dupe-keys': 'error',
96
+ 'jsonc/sort-keys': ['warn', 'asc'],
97
+ },
98
+ },
99
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/recommended-with-jsonc'], {
100
+ files: jsonWithCommentsPatterns,
101
+ language: 'jsonc/jsonc',
102
+ }),
103
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/prettier'], {
104
+ files: jsonWithCommentsPatterns,
105
+ language: 'jsonc/jsonc',
106
+ }),
36
107
  {
37
- // General configuration for all files
108
+ files: jsonWithCommentsPatterns,
109
+ language: 'jsonc/jsonc',
110
+ extends: [tseslint.configs.disableTypeChecked],
111
+ },
112
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/recommended-with-json5'], {
113
+ files: ['**/*.json5'],
114
+ language: 'jsonc/json5',
115
+ }),
116
+ ...scopeFlatPreset(eslintPluginJsonc.configs['flat/prettier'], {
117
+ files: ['**/*.json5'],
118
+ language: 'jsonc/json5',
119
+ }),
120
+ {
121
+ files: ['**/*.json5'],
122
+ language: 'jsonc/json5',
123
+ extends: [tseslint.configs.disableTypeChecked],
124
+ },
125
+ ...scopeFlatPreset(eslintPluginYml.configs['flat/recommended'], yamlScope),
126
+ ...scopeFlatPreset(eslintPluginYml.configs['flat/prettier'], yamlScope),
127
+ {
128
+ ...yamlScope,
129
+ extends: [tseslint.configs.disableTypeChecked],
130
+ rules: {
131
+ 'yml/quotes': ['error', { prefer: 'single', avoidEscape: false }],
132
+ 'yml/no-empty-document': 'off',
133
+ 'yml/indent': ['error', 4, { indicatorValueIndent: 2 }],
134
+ '@stylistic/spaced-comment': 'off',
135
+ 'yml/no-empty-mapping-value': 'off',
136
+ },
137
+ },
138
+ {
139
+ files: ['**/*.md'],
140
+ plugins: { markdown: eslintPluginMarkdown },
141
+ extends: ['markdown/recommended'],
142
+ },
143
+ {
144
+ // General configuration for JS/TS source (not JSON, YAML, Markdown, etc.)
145
+ files: ['**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}'],
38
146
  linterOptions: {
39
147
  reportUnusedDisableDirectives: true,
40
148
  },
41
- extends: [eslintPluginImport.flatConfigs.typescript],
149
+ extends: [eslintPluginImportX.flatConfigs.typescript],
42
150
  plugins: {
43
151
  // Where we want to customize few part and not use recommended
44
152
  unicorn: eslintPluginUnicorn,
@@ -58,10 +166,7 @@ export default defineConfig(
58
166
  },
59
167
  },
60
168
  settings: {
61
- 'import/resolver': {
62
- typescript: true,
63
- node: true,
64
- },
169
+ 'import-x/resolver-next': [createTypeScriptImportResolver(), createNodeResolver()],
65
170
  },
66
171
  rules: {
67
172
  // Eslint (base)
@@ -145,16 +250,16 @@ export default defineConfig(
145
250
  ],
146
251
 
147
252
  // Eslint Import
148
- 'import/no-unresolved': 'off',
149
- 'import/no-internal-modules': 'off',
150
- 'import/no-relative-parent-imports': 'off',
151
- 'import/no-named-as-default': 'off',
152
- 'import/exports-last': 'off',
153
- 'import/no-namespace': 'off',
154
- 'import/extensions': 'off',
155
- 'import/namespace': 'off',
156
- 'import/default': 'off',
157
- 'import/order': [
253
+ 'import-x/no-unresolved': 'off',
254
+ 'import-x/no-internal-modules': 'off',
255
+ 'import-x/no-relative-parent-imports': 'off',
256
+ 'import-x/no-named-as-default': 'off',
257
+ 'import-x/exports-last': 'off',
258
+ 'import-x/no-namespace': 'off',
259
+ 'import-x/extensions': 'off',
260
+ 'import-x/namespace': 'off',
261
+ 'import-x/default': 'off',
262
+ 'import-x/order': [
158
263
  'error',
159
264
  {
160
265
  groups: [
@@ -179,14 +284,14 @@ export default defineConfig(
179
284
  },
180
285
  },
181
286
  ],
182
- 'import/prefer-default-export': 'off',
183
- 'import/max-dependencies': 'off',
184
- 'import/no-unassigned-import': 'off',
185
- 'import/no-default-export': 'off',
186
- 'import/no-named-export': 'off',
187
- 'import/group-exports': 'off',
188
- 'import/no-duplicates': ['error', { 'prefer-inline': true }],
189
- 'import/consistent-type-specifier-style': ['error', 'prefer-inline'],
287
+ 'import-x/prefer-default-export': 'off',
288
+ 'import-x/max-dependencies': 'off',
289
+ 'import-x/no-unassigned-import': 'off',
290
+ 'import-x/no-default-export': 'off',
291
+ 'import-x/no-named-export': 'off',
292
+ 'import-x/group-exports': 'off',
293
+ 'import-x/no-duplicates': ['error', { 'prefer-inline': true }],
294
+ 'import-x/consistent-type-specifier-style': ['error', 'prefer-inline'],
190
295
 
191
296
  // Unicorn
192
297
  // Pass error message when throwing errors
@@ -268,40 +373,6 @@ export default defineConfig(
268
373
  '@typescript-eslint/no-misused-promises': [2, { checksVoidReturn: { attributes: false } }],
269
374
  },
270
375
  },
271
- {
272
- // JSON files
273
- files: ['**/*.json'],
274
- extends: [tseslint.configs.disableTypeChecked],
275
- rules: {
276
- quotes: ['error', 'double'],
277
- 'quote-props': ['error', 'always'],
278
- 'comma-dangle': ['error', 'never'],
279
- semi: 'off',
280
- 'jsonc/array-bracket-spacing': ['error', 'never'],
281
- 'jsonc/comma-dangle': ['error', 'never'],
282
- 'jsonc/comma-style': ['error', 'last'],
283
- 'jsonc/key-spacing': ['error', { beforeColon: false, afterColon: true }],
284
- 'jsonc/no-octal-escape': 'error',
285
- 'jsonc/object-curly-newline': ['error', { multiline: true, consistent: true }],
286
- 'jsonc/object-curly-spacing': ['error', 'always'],
287
- 'jsonc/object-property-newline': ['error', { allowMultiplePropertiesPerLine: true }],
288
- 'jsonc/no-dupe-keys': 'error',
289
- 'jsonc/sort-keys': ['warn', 'asc'],
290
- },
291
- },
292
- {
293
- // YAML files rules
294
- files: ['**/*.yaml', '**/*.yml'],
295
- extends: [tseslint.configs.disableTypeChecked],
296
- rules: {
297
- 'spaced-comment': 'off',
298
- 'yml/quotes': ['error', { prefer: 'single', avoidEscape: false }],
299
- 'yml/no-empty-document': 'off',
300
- 'yml/indent': ['error', 4, { indicatorValueIndent: 2 }],
301
- '@stylistic/spaced-comment': 'off', // False positive in yaml/yml files
302
- 'yml/no-empty-mapping-value': 'off', // Breaks comments on GitHub Actions
303
- },
304
- },
305
376
  {
306
377
  // package.json rules
307
378
  files: ['**/package.json'],
@@ -369,7 +440,7 @@ export default defineConfig(
369
440
  // d.ts files
370
441
  files: ['**/*.d.ts'],
371
442
  rules: {
372
- 'import/no-duplicates': 'off',
443
+ 'import-x/no-duplicates': 'off',
373
444
  },
374
445
  },
375
446
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@frontify/eslint-config-basic",
3
3
  "type": "module",
4
- "version": "1.0.13",
4
+ "version": "1.0.15",
5
5
  "author": "Frontify Developers <developers@frontify.com>",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -11,44 +11,46 @@
11
11
  },
12
12
  "main": "eslint.config.mjs",
13
13
  "files": [
14
+ "rules",
14
15
  "eslint.config.mjs"
15
16
  ],
16
17
  "peerDependencies": {
17
18
  "eslint": "^9.0.0 || ^10.0.0",
18
19
  "prettier": "^3.0.0",
19
- "typescript": "^5.0.0"
20
+ "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0"
20
21
  },
21
22
  "dependencies": {
22
23
  "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1",
23
24
  "@eslint/js": "^10.0.1",
24
- "@stylistic/eslint-plugin": "^5.9.0",
25
- "@typescript-eslint/eslint-plugin": "^8.56.1",
26
- "@typescript-eslint/parser": "^8.56.1",
25
+ "@eslint/markdown": "^8.0.0",
26
+ "@stylistic/eslint-plugin": "^5.10.0",
27
+ "@typescript-eslint/eslint-plugin": "^8.57.2",
28
+ "@typescript-eslint/parser": "^8.57.2",
27
29
  "eslint-config-prettier": "^10.1.8",
28
30
  "eslint-import-resolver-typescript": "^4.4.4",
29
- "eslint-plugin-import": "^2.32.0",
30
- "eslint-plugin-jsonc": "^3.1.1",
31
+ "eslint-plugin-import-x": "^4.16.2",
32
+ "eslint-plugin-jsonc": "^3.1.2",
31
33
  "eslint-plugin-lodash": "^8.0.0",
32
- "eslint-plugin-markdown": "^5.1.0",
33
34
  "eslint-plugin-no-only-tests": "^3.3.0",
34
35
  "eslint-plugin-prettier": "^5.5.5",
35
36
  "eslint-plugin-promise": "^7.2.1",
36
- "eslint-plugin-unicorn": "^63.0.0",
37
- "eslint-plugin-yml": "^3.3.0",
37
+ "eslint-plugin-unicorn": "^64.0.0",
38
+ "eslint-plugin-yml": "^3.3.1",
38
39
  "globals": "^17.4.0",
39
- "typescript-eslint": "^8.56.1",
40
+ "typescript-eslint": "^8.57.2",
40
41
  "yaml-eslint-parser": "^2.0.0"
41
42
  },
42
43
  "devDependencies": {
43
- "eslint": "^10.0.2",
44
+ "eslint": "^10.1.0",
44
45
  "prettier": "^3.8.1",
45
- "typescript": "^5.9.3"
46
+ "typescript": "^6.0.2"
46
47
  },
47
48
  "publishConfig": {
48
49
  "access": "public"
49
50
  },
50
51
  "scripts": {
51
52
  "lint": "eslint .",
53
+ "test": "node --test 'rules/**/*.test.mjs'",
52
54
  "typecheck": "tsc --noEmit"
53
55
  }
54
56
  }
@@ -0,0 +1,192 @@
1
+ /* (c) Copyright Frontify Ltd., all rights reserved. */
2
+
3
+ import { RuleTester } from 'eslint';
4
+ import eslintPluginImportX from 'eslint-plugin-import-x';
5
+
6
+ import config from '../eslint.config.mjs';
7
+
8
+ const rule = eslintPluginImportX.rules['order'];
9
+
10
+ const importOrderEntry = config.find((c) => c?.rules?.['import-x/order'] !== undefined);
11
+ if (!importOrderEntry) {
12
+ throw new Error("Could not find 'import-x/order' rule in eslint.config.mjs");
13
+ }
14
+ const [, orderOptions] = /** @type {[string, import('eslint-plugin-import-x').RuleOptions['order'][1]]} */ (
15
+ importOrderEntry.rules['import-x/order']
16
+ );
17
+
18
+ const ruleTester = new RuleTester({
19
+ languageOptions: {
20
+ ecmaVersion: 'latest',
21
+ sourceType: 'module',
22
+ },
23
+ });
24
+
25
+ ruleTester.run('import-x/order', rule, {
26
+ valid: [
27
+ {
28
+ name: 'single external import',
29
+ code: "import foo from 'foo';",
30
+ options: [orderOptions],
31
+ },
32
+ {
33
+ name: 'builtin before external with blank line',
34
+ code: ["import path from 'node:path';", '', "import foo from 'foo';"].join('\n'),
35
+ options: [orderOptions],
36
+ },
37
+ {
38
+ name: 'external imports alphabetized',
39
+ code: ["import alpha from 'alpha';", "import beta from 'beta';", "import zeta from 'zeta';"].join('\n'),
40
+ options: [orderOptions],
41
+ },
42
+ {
43
+ name: 'external before parent with blank line',
44
+ code: ["import foo from 'foo';", '', "import bar from '../bar';"].join('\n'),
45
+ options: [orderOptions],
46
+ },
47
+ {
48
+ name: 'external before sibling with blank line',
49
+ code: ["import foo from 'foo';", '', "import bar from './bar';"].join('\n'),
50
+ options: [orderOptions],
51
+ },
52
+ {
53
+ name: 'all groups in order with blank lines between each',
54
+ code: [
55
+ "import path from 'node:path';",
56
+ '',
57
+ "import foo from 'foo';",
58
+ '',
59
+ "import bar from '../bar';",
60
+ '',
61
+ "import baz from './baz';",
62
+ ].join('\n'),
63
+ options: [orderOptions],
64
+ },
65
+ {
66
+ name: 'scoped externals alphabetized (@frontify before @tanstack)',
67
+ code: [
68
+ "import { Button } from '@frontify/fondue';",
69
+ "import { useQuery } from '@tanstack/react-query';",
70
+ ].join('\n'),
71
+ options: [orderOptions],
72
+ },
73
+ {
74
+ name: 'realistic file: node builtin, scoped externals, deep parent, sibling',
75
+ code: [
76
+ "import path from 'node:path';",
77
+ '',
78
+ "import { Button } from '@frontify/fondue';",
79
+ "import { useQuery } from '@tanstack/react-query';",
80
+ '',
81
+ "import { formatDate } from '../../../utils/date';",
82
+ "import { getUser } from '../../services/user';",
83
+ '',
84
+ "import { MyComponent } from './MyComponent';",
85
+ "import styles from './styles.module.css';",
86
+ ].join('\n'),
87
+ options: [orderOptions],
88
+ },
89
+ {
90
+ name: 'multiple sibling imports alphabetized',
91
+ code: [
92
+ "import { Avatar } from './Avatar';",
93
+ "import { Button } from './Button';",
94
+ "import { Input } from './Input';",
95
+ ].join('\n'),
96
+ options: [orderOptions],
97
+ },
98
+ {
99
+ name: 'deep parent imports (../../../) are treated as parent group',
100
+ code: [
101
+ "import { useQuery } from '@tanstack/react-query';",
102
+ '',
103
+ "import { formatDate } from '../../../utils/date';",
104
+ ].join('\n'),
105
+ options: [orderOptions],
106
+ },
107
+ ],
108
+ invalid: [
109
+ {
110
+ name: 'missing blank line between builtin and external',
111
+ code: ["import path from 'node:path';", "import foo from 'foo';"].join('\n'),
112
+ output: ["import path from 'node:path';", '', "import foo from 'foo';"].join('\n'),
113
+ options: [orderOptions],
114
+ errors: [{ messageId: 'oneLineBetweenGroups' }],
115
+ },
116
+ {
117
+ name: 'missing blank line between external and parent',
118
+ code: ["import foo from 'foo';", "import bar from '../bar';"].join('\n'),
119
+ output: ["import foo from 'foo';", '', "import bar from '../bar';"].join('\n'),
120
+ options: [orderOptions],
121
+ errors: [{ messageId: 'oneLineBetweenGroups' }],
122
+ },
123
+ {
124
+ name: 'missing blank line between external and sibling',
125
+ code: ["import foo from 'foo';", "import bar from './bar';"].join('\n'),
126
+ output: ["import foo from 'foo';", '', "import bar from './bar';"].join('\n'),
127
+ options: [orderOptions],
128
+ errors: [{ messageId: 'oneLineBetweenGroups' }],
129
+ },
130
+ {
131
+ name: 'external imports not alphabetized',
132
+ code: ["import zeta from 'zeta';", "import alpha from 'alpha';"].join('\n'),
133
+ output: ["import alpha from 'alpha';", "import zeta from 'zeta';", ''].join('\n'),
134
+ options: [orderOptions],
135
+ errors: [{ messageId: 'order' }],
136
+ },
137
+ {
138
+ name: 'external before builtin (wrong group order)',
139
+ code: ["import foo from 'foo';", '', "import path from 'node:path';"].join('\n'),
140
+ // One-pass fix swaps the imports; the blank line between groups is added by a second pass.
141
+ output: "import path from 'node:path';\nimport foo from 'foo';\n\n",
142
+ options: [orderOptions],
143
+ errors: [{ messageId: 'order' }],
144
+ },
145
+ {
146
+ name: 'sibling before parent (wrong group order)',
147
+ code: ["import baz from './baz';", '', "import bar from '../bar';"].join('\n'),
148
+ // One-pass fix swaps the imports; the blank line between groups is added by a second pass.
149
+ output: "import bar from '../bar';\nimport baz from './baz';\n\n",
150
+ options: [orderOptions],
151
+ errors: [{ messageId: 'order' }],
152
+ },
153
+ {
154
+ name: 'extra blank line within the same group',
155
+ code: ["import alpha from 'alpha';", '', "import beta from 'beta';"].join('\n'),
156
+ output: ["import alpha from 'alpha';", "import beta from 'beta';"].join('\n'),
157
+ options: [orderOptions],
158
+ errors: [{ messageId: 'noLineWithinGroup' }],
159
+ },
160
+ {
161
+ name: '@tanstack before @frontify (wrong alphabetical order)',
162
+ code: [
163
+ "import { useQuery } from '@tanstack/react-query';",
164
+ "import { Button } from '@frontify/fondue';",
165
+ ].join('\n'),
166
+ output: [
167
+ "import { Button } from '@frontify/fondue';",
168
+ "import { useQuery } from '@tanstack/react-query';",
169
+ '',
170
+ ].join('\n'),
171
+ options: [orderOptions],
172
+ errors: [{ messageId: 'order' }],
173
+ },
174
+ {
175
+ name: 'missing blank line between scoped external and deep parent',
176
+ code: ["import { Button } from '@frontify/fondue';", "import utils from '../../../utils';"].join('\n'),
177
+ output: ["import { Button } from '@frontify/fondue';", '', "import utils from '../../../utils';"].join(
178
+ '\n',
179
+ ),
180
+ options: [orderOptions],
181
+ errors: [{ messageId: 'oneLineBetweenGroups' }],
182
+ },
183
+ {
184
+ name: 'sibling (./Button) before deep parent (../../../utils) — wrong group order',
185
+ code: ["import Button from './Button';", '', "import utils from '../../../utils';"].join('\n'),
186
+ // One-pass fix swaps the imports; the blank line between groups is added by a second pass.
187
+ output: "import utils from '../../../utils';\nimport Button from './Button';\n\n",
188
+ options: [orderOptions],
189
+ errors: [{ messageId: 'order' }],
190
+ },
191
+ ],
192
+ });