@taiga-ui/eslint-plugin-experience-next 0.438.0 → 0.439.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
@@ -49,12 +49,267 @@ export default [
49
49
  | no-href-with-router-link | Do not use href and routerLink attributes together on the same element | | 🔧 | |
50
50
  | no-implicit-public | Require explicit `public` modifier for class members and parameter properties | ✅ | 🔧 | |
51
51
  | no-playwright-empty-fill | Enforce `clear()` over `fill('')` in Playwright tests | ✅ | 🔧 | |
52
- | standalone-imports-sort | Sort imports alphabetically | ✅ | 🔧 | |
52
+ | object-single-line | Enforce single-line formatting for single-property objects when it fits `printWidth` | ✅ | 🔧 | |
53
53
  | prefer-deep-imports | Allow deep imports of Taiga UI packages | | 🔧 | |
54
+ | prefer-multi-arg-push | Combine consecutive `.push()` calls on the same array into a single multi-argument call | ✅ | 🔧 | |
54
55
  | short-tui-imports | Shorten TuiXxxComponent / TuiYyyDirective in Angular metadata | ✅ | 🔧 | |
55
56
  | standalone-imports-sort | Auto sort names inside Angular decorators | ✅ | 🔧 | |
56
57
  | strict-tui-doc-example | If you use the addon-doc, there will be a hint that you are importing something incorrectly | | 🔧 | |
57
58
 
59
+ ---
60
+
61
+ ## array-as-const
62
+
63
+ Exported arrays containing only class references must be marked with `as const` to preserve the tuple type and enable
64
+ proper type inference.
65
+
66
+ ```ts
67
+ // ❌ error
68
+ export const PROVIDERS = [FooService, BarService];
69
+
70
+ // ✅ after autofix
71
+ export const PROVIDERS = [FooService, BarService] as const;
72
+ ```
73
+
74
+ ---
75
+
76
+ ## class-property-naming
77
+
78
+ Enforce custom naming conventions for class properties based on their TypeScript type. Useful for enforcing project-wide
79
+ patterns (e.g. all `Subject` fields must be called `destroy$`).
80
+
81
+ Requires explicit configuration — not enabled in `recommended` by default.
82
+
83
+ ```json
84
+ {
85
+ "@taiga-ui/experience-next/class-property-naming": [
86
+ "error",
87
+ [
88
+ {
89
+ "fieldNames": ["sub", "subscription"],
90
+ "newFieldName": "destroy$",
91
+ "withTypesSpecifier": ["Subject", "Subscription"]
92
+ }
93
+ ]
94
+ ]
95
+ }
96
+ ```
97
+
98
+ ```ts
99
+ // ❌ error
100
+ class MyComponent {
101
+ sub = new Subject<void>();
102
+ }
103
+
104
+ // ✅ after autofix
105
+ class MyComponent {
106
+ destroy$ = new Subject<void>();
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## decorator-key-sort
113
+
114
+ Enforces a consistent key order inside Angular decorator objects (`@Component`, `@Directive`, `@NgModule`, `@Pipe`,
115
+ `@Injectable`). The expected order is passed as configuration.
116
+
117
+ ```json
118
+ {
119
+ "@taiga-ui/experience-next/decorator-key-sort": [
120
+ "error",
121
+ {
122
+ "Component": ["standalone", "selector", "imports", "templateUrl", "styleUrl", "changeDetection"],
123
+ "Pipe": ["standalone", "name", "pure"]
124
+ }
125
+ ]
126
+ }
127
+ ```
128
+
129
+ ```ts
130
+ // ❌ error
131
+ @Component({
132
+ templateUrl: './app.component.html',
133
+ selector: 'app-root',
134
+ standalone: true,
135
+ })
136
+
137
+ // ✅ after autofix
138
+ @Component({
139
+ standalone: true,
140
+ selector: 'app-root',
141
+ templateUrl: './app.component.html',
142
+ })
143
+ ```
144
+
145
+ ---
146
+
147
+ ## flat-exports
148
+
149
+ When an exported `as const` tuple contains another exported `as const` tuple of Angular classes, it should be spread
150
+ rather than nested. This keeps entity collections flat and avoids double-wrapping.
151
+
152
+ ```ts
153
+ // ❌ error
154
+ export const TuiTextfield = [TuiTextfieldDirective] as const;
155
+ export const TuiInput = [TuiTextfield, TuiInputDirective] as const;
156
+
157
+ // ✅ after autofix
158
+ export const TuiTextfield = [TuiTextfieldDirective] as const;
159
+ export const TuiInput = [...TuiTextfield, TuiInputDirective] as const;
160
+ ```
161
+
162
+ ---
163
+
164
+ ## injection-token-description
165
+
166
+ The description string passed to `new InjectionToken(...)` must contain the name of the variable it is assigned to. This
167
+ makes token names visible in Angular DevTools and error messages.
168
+
169
+ ```ts
170
+ // ❌ error — description does not mention TUI_MY_TOKEN
171
+ const TUI_MY_TOKEN = new InjectionToken<string>('some description');
172
+
173
+ // ✅ after autofix
174
+ const TUI_MY_TOKEN = new InjectionToken<string>('[TUI_MY_TOKEN]: some description');
175
+ ```
176
+
177
+ ---
178
+
179
+ ## no-deep-imports
180
+
181
+ Disallows deep path imports from Taiga UI packages — imports must go through the package root. Works for any
182
+ `@taiga-ui/*` package by default. Autofix strips the deep path.
183
+
184
+ ```ts
185
+ // ❌ error
186
+ import {TuiButton} from '@taiga-ui/core/components/button';
187
+
188
+ // ✅ after autofix
189
+ import {TuiButton} from '@taiga-ui/core';
190
+ ```
191
+
192
+ ```json
193
+ {
194
+ "@taiga-ui/experience-next/no-deep-imports": [
195
+ "error",
196
+ {
197
+ "currentProject": "(?<=projects/)([\\w-]+)",
198
+ "ignoreImports": ["\\?raw", "@taiga-ui/testing/cypress"]
199
+ }
200
+ ]
201
+ }
202
+ ```
203
+
204
+ | Option | Type | Description |
205
+ | ------------------- | ---------- | -------------------------------------------------------------------------- |
206
+ | `currentProject` | `string` | RegExp to extract the current project name from the file path |
207
+ | `deepImport` | `string` | RegExp to detect the deep import segment (default: `@taiga-ui/` sub-paths) |
208
+ | `importDeclaration` | `string` | RegExp to match import declarations the rule applies to |
209
+ | `ignoreImports` | `string[]` | RegExp patterns for imports to ignore |
210
+ | `projectName` | `string` | RegExp to extract the package name from the import source |
211
+
212
+ ---
213
+
214
+ ## no-deep-imports-to-indexed-packages
215
+
216
+ Disallows deep imports from any external package whose root `index.ts` (or `index.d.ts`) re-exports the same subpath and
217
+ is co-located with a `package.json` or `ng-package.json`. Does not require explicit package lists — resolves via
218
+ TypeScript.
219
+
220
+ ```ts
221
+ // ❌ error — @my-lib/index.ts already re-exports this subpath
222
+ import {Foo} from '@my-lib/internal/foo';
223
+
224
+ // ✅
225
+ import {Foo} from '@my-lib/internal';
226
+ ```
227
+
228
+ ---
229
+
230
+ ## no-href-with-router-link
231
+
232
+ Disallows using both `href` and `routerLink` on the same `<a>` element in Angular templates. Autofix removes the `href`
233
+ attribute.
234
+
235
+ ```html
236
+ <!-- ❌ error -->
237
+ <a
238
+ href="/home"
239
+ routerLink="/home"
240
+ >
241
+ Home
242
+ </a>
243
+
244
+ <!-- ✅ after autofix -->
245
+ <a routerLink="/home">Home</a>
246
+ ```
247
+
248
+ ---
249
+
250
+ ## no-implicit-public
251
+
252
+ Requires an explicit `public` modifier on all class members and constructor parameter properties that are public.
253
+ Constructors are excluded.
254
+
255
+ ```ts
256
+ // ❌ error
257
+ class MyService {
258
+ value = 42;
259
+ doSomething(): void {}
260
+ }
261
+
262
+ // ✅ after autofix
263
+ class MyService {
264
+ public value = 42;
265
+ public doSomething(): void {}
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## no-playwright-empty-fill
272
+
273
+ In Playwright tests, calling `.fill('')` on a locator should be replaced with `.clear()` — it is the idiomatic way to
274
+ empty a field and communicates intent more clearly.
275
+
276
+ ```ts
277
+ // ❌ error
278
+ await page.getByLabel('Name').fill('');
279
+
280
+ // ✅ after autofix
281
+ await page.getByLabel('Name').clear();
282
+ ```
283
+
284
+ ---
285
+
286
+ ## object-single-line
287
+
288
+ Single-property object literals that fit within `printWidth` characters on one line are collapsed to a single line.
289
+ Compatible with Prettier formatting.
290
+
291
+ ```ts
292
+ // ❌ error
293
+ const x = {
294
+ foo: bar,
295
+ };
296
+
297
+ // ✅ after autofix
298
+ const x = {foo: bar};
299
+ ```
300
+
301
+ ```json
302
+ {
303
+ "@taiga-ui/experience-next/object-single-line": ["error", {"printWidth": 90}]
304
+ }
305
+ ```
306
+
307
+ | Option | Type | Default | Description |
308
+ | ------------ | -------- | ------- | ------------------------------------- |
309
+ | `printWidth` | `number` | `90` | Maximum line length to allow inlining |
310
+
311
+ ---
312
+
58
313
  ## prefer-deep-imports
59
314
 
60
315
  Enforce imports from the deepest available entry point of Taiga UI packages.
@@ -72,3 +327,106 @@ Enforce imports from the deepest available entry point of Taiga UI packages.
72
327
  ```
73
328
 
74
329
  Use `strict` to forbid imports from intermediate entry points when deeper ones exist (recommended for CI).
330
+
331
+ ---
332
+
333
+ ## prefer-multi-arg-push
334
+
335
+ Combine consecutive `.push()` calls on the same array into a single multi-argument call.
336
+
337
+ ```ts
338
+ // ❌ error
339
+ output.push('# Getting Started');
340
+ output.push('');
341
+
342
+ // ✅ after autofix
343
+ output.push('# Getting Started', '');
344
+ ```
345
+
346
+ ---
347
+
348
+ ## short-tui-imports
349
+
350
+ In Angular decorator `imports` arrays, replaces full `TuiXxxComponent` / `TuiYyyDirective` names with their shorthand
351
+ aliases (e.g. `TuiButton`). Also updates the corresponding `import` statement.
352
+
353
+ ```ts
354
+ // ❌ error
355
+ import {TuiButtonDirective} from '@taiga-ui/core';
356
+
357
+ @Component({
358
+ imports: [TuiButtonDirective],
359
+ })
360
+
361
+ // ✅ after autofix
362
+ import {TuiButton} from '@taiga-ui/core';
363
+
364
+ @Component({
365
+ imports: [TuiButton],
366
+ })
367
+ ```
368
+
369
+ ```json
370
+ {
371
+ "@taiga-ui/experience-next/short-tui-imports": [
372
+ "error",
373
+ {
374
+ "decorators": ["Component", "Directive", "NgModule", "Pipe"],
375
+ "exceptions": [{"from": "TuiTextfieldOptionsDirective", "to": "TuiTextfield"}]
376
+ }
377
+ ]
378
+ }
379
+ ```
380
+
381
+ | Option | Type | Description |
382
+ | ------------ | ------------------------------ | ---------------------------------------------------------- |
383
+ | `decorators` | `string[]` | Decorator names to inspect (default: all Angular ones) |
384
+ | `exceptions` | `{from: string, to: string}[]` | Explicit rename mappings that override the default pattern |
385
+
386
+ ---
387
+
388
+ ## standalone-imports-sort
389
+
390
+ Sorts the `imports` array inside Angular decorators (`@Component`, `@Directive`, `@NgModule`, `@Pipe`) alphabetically.
391
+ Spread elements are placed after named identifiers.
392
+
393
+ ```ts
394
+ // ❌ error
395
+ @Component({
396
+ imports: [TuiButton, CommonModule, AsyncPipe],
397
+ })
398
+
399
+ // ✅ after autofix
400
+ @Component({
401
+ imports: [AsyncPipe, CommonModule, TuiButton],
402
+ })
403
+ ```
404
+
405
+ ```json
406
+ {
407
+ "@taiga-ui/experience-next/standalone-imports-sort": [
408
+ "error",
409
+ {"decorators": ["Component", "Directive", "NgModule", "Pipe"]}
410
+ ]
411
+ }
412
+ ```
413
+
414
+ ---
415
+
416
+ ## strict-tui-doc-example
417
+
418
+ Validates that properties of a `TuiDocExample`-typed object have keys matching known file-type names (`TypeScript`,
419
+ `HTML`, `CSS`, `LESS`, `JavaScript`) and that the import path extension matches the key. Autofix corrects the import
420
+ extension.
421
+
422
+ ```ts
423
+ // ❌ error — key says "TypeScript" but path has .html extension
424
+ readonly example: TuiDocExample = {
425
+ TypeScript: import('./example/index.html?raw'),
426
+ };
427
+
428
+ // ✅ after autofix
429
+ readonly example: TuiDocExample = {
430
+ TypeScript: import('./example/index.ts?raw'),
431
+ };
432
+ ```
package/index.d.ts CHANGED
@@ -51,6 +51,9 @@ declare const plugin: {
51
51
  }], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
52
52
  name: string;
53
53
  };
54
+ 'prefer-multi-arg-push': import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferMultiArgPush", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
55
+ name: string;
56
+ };
54
57
  'short-tui-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceTuiImport", import("./rules/short-tui-imports").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
55
58
  name: string;
56
59
  };
package/index.esm.js CHANGED
@@ -600,6 +600,7 @@ var recommended = defineConfig([
600
600
  'import/no-cycle': 'error',
601
601
  'import/no-duplicates': ['error', { 'prefer-inline': true }],
602
602
  'import/no-mutable-exports': 'error',
603
+ 'import/no-named-as-default': 'error',
603
604
  'import/no-self-import': 'error',
604
605
  'import/no-unresolved': 'off',
605
606
  'import/no-useless-path-segments': ['error', { noUselessIndex: true }],
@@ -901,6 +902,7 @@ var recommended = defineConfig([
901
902
  '@taiga-ui/experience-next/no-deep-imports-to-indexed-packages': 'error',
902
903
  '@taiga-ui/experience-next/no-implicit-public': 'error',
903
904
  '@taiga-ui/experience-next/object-single-line': ['error', { printWidth: 90 }],
905
+ '@taiga-ui/experience-next/prefer-multi-arg-push': 'error',
904
906
  '@taiga-ui/experience-next/short-tui-imports': 'error',
905
907
  '@taiga-ui/experience-next/standalone-imports-sort': [
906
908
  'error',
@@ -1312,8 +1314,8 @@ function intersect(a, b) {
1312
1314
  return a.some((type) => origin.has(type));
1313
1315
  }
1314
1316
 
1315
- const createRule$b = ESLintUtils.RuleCreator((name) => name);
1316
- var classPropertyNaming = createRule$b({
1317
+ const createRule$c = ESLintUtils.RuleCreator((name) => name);
1318
+ var classPropertyNaming = createRule$c({
1317
1319
  create(context, [configs]) {
1318
1320
  const parserServices = ESLintUtils.getParserServices(context);
1319
1321
  const typeChecker = parserServices.program.getTypeChecker();
@@ -1482,9 +1484,9 @@ function isExternalPureTuple(typeChecker, type) {
1482
1484
  return typeArgs.every((item) => isClassType(item));
1483
1485
  }
1484
1486
 
1485
- const createRule$a = ESLintUtils.RuleCreator((name) => name);
1487
+ const createRule$b = ESLintUtils.RuleCreator((name) => name);
1486
1488
  const MESSAGE_ID$5 = 'spreadArrays';
1487
- var flatExports = createRule$a({
1489
+ var flatExports = createRule$b({
1488
1490
  create(context) {
1489
1491
  const parserServices = ESLintUtils.getParserServices(context);
1490
1492
  const typeChecker = parserServices.program.getTypeChecker();
@@ -1611,8 +1613,8 @@ var flatExports = createRule$a({
1611
1613
 
1612
1614
  const MESSAGE_ID$4 = 'invalid-injection-token-description';
1613
1615
  const ERROR_MESSAGE$3 = "InjectionToken's description should contain token's name";
1614
- const createRule$9 = ESLintUtils.RuleCreator((name) => name);
1615
- const rule$6 = createRule$9({
1616
+ const createRule$a = ESLintUtils.RuleCreator((name) => name);
1617
+ const rule$7 = createRule$a({
1616
1618
  create(context) {
1617
1619
  return {
1618
1620
  'NewExpression[callee.name="InjectionToken"]'(node) {
@@ -1680,8 +1682,8 @@ const DEFAULT_OPTIONS = {
1680
1682
  importDeclaration: '^@taiga-ui*',
1681
1683
  projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
1682
1684
  };
1683
- const createRule$8 = ESLintUtils.RuleCreator((name) => name);
1684
- const rule$5 = createRule$8({
1685
+ const createRule$9 = ESLintUtils.RuleCreator((name) => name);
1686
+ const rule$6 = createRule$9({
1685
1687
  create(context) {
1686
1688
  const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
1687
1689
  const hasNonCodeExtension = (source) => {
@@ -1768,13 +1770,13 @@ const rule$5 = createRule$8({
1768
1770
  name: 'no-deep-imports',
1769
1771
  });
1770
1772
 
1771
- const createRule$7 = ESLintUtils.RuleCreator((name) => name);
1773
+ const createRule$8 = ESLintUtils.RuleCreator((name) => name);
1772
1774
  const resolveCacheByOptions = new WeakMap();
1773
1775
  const nearestFileUpCache = new Map();
1774
1776
  const markerCache = new Map();
1775
1777
  const indexFileCache = new Map();
1776
1778
  const indexExportsCache = new Map();
1777
- var noDeepImportsToIndexedPackages = createRule$7({
1779
+ var noDeepImportsToIndexedPackages = createRule$8({
1778
1780
  create(context) {
1779
1781
  const parserServices = ESLintUtils.getParserServices(context);
1780
1782
  const program = parserServices.program;
@@ -2017,8 +2019,8 @@ const config = {
2017
2019
  },
2018
2020
  };
2019
2021
 
2020
- const createRule$6 = ESLintUtils.RuleCreator((name) => name);
2021
- const rule$4 = createRule$6({
2022
+ const createRule$7 = ESLintUtils.RuleCreator((name) => name);
2023
+ const rule$5 = createRule$7({
2022
2024
  create(context) {
2023
2025
  const checkImplicitPublic = (node) => {
2024
2026
  const classRef = getClass(node);
@@ -2090,8 +2092,8 @@ function getClass(node) {
2090
2092
  return getClass(node.parent);
2091
2093
  }
2092
2094
 
2093
- const createRule$5 = ESLintUtils.RuleCreator((name) => name);
2094
- const rule$3 = createRule$5({
2095
+ const createRule$6 = ESLintUtils.RuleCreator((name) => name);
2096
+ const rule$4 = createRule$6({
2095
2097
  create(context) {
2096
2098
  const services = ESLintUtils.getParserServices(context);
2097
2099
  const checker = services.program.getTypeChecker();
@@ -2179,8 +2181,8 @@ function isPlaywrightLocatorType(type) {
2179
2181
  });
2180
2182
  }
2181
2183
 
2182
- const createRule$4 = ESLintUtils.RuleCreator((name) => name);
2183
- const rule$2 = createRule$4({
2184
+ const createRule$5 = ESLintUtils.RuleCreator((name) => name);
2185
+ const rule$3 = createRule$5({
2184
2186
  create(context, [{ printWidth }]) {
2185
2187
  const sourceCode = context.sourceCode;
2186
2188
  const getLineEndIndex = (lineStartIndex) => {
@@ -2460,8 +2462,8 @@ const rule$2 = createRule$4({
2460
2462
 
2461
2463
  const MESSAGE_ID$1 = 'prefer-deep-imports';
2462
2464
  const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
2463
- const createRule$3 = ESLintUtils.RuleCreator(() => ERROR_MESSAGE);
2464
- var preferDeepImports = createRule$3({
2465
+ const createRule$4 = ESLintUtils.RuleCreator(() => ERROR_MESSAGE);
2466
+ var preferDeepImports = createRule$4({
2465
2467
  create(context, [options]) {
2466
2468
  const allowedPackages = normalizeImportFilter(options.importFilter);
2467
2469
  const isStrictMode = options.strict ?? false;
@@ -2809,6 +2811,100 @@ function buildRewrittenImports(node, baseImportPath, symbolToEntryPoint) {
2809
2811
  return importStatements.join('\n');
2810
2812
  }
2811
2813
 
2814
+ const createRule$3 = ESLintUtils.RuleCreator((name) => name);
2815
+ function getPushCall(node) {
2816
+ if (node.expression.type !== AST_NODE_TYPES.CallExpression) {
2817
+ return null;
2818
+ }
2819
+ const call = node.expression;
2820
+ if (call.callee.type !== AST_NODE_TYPES.MemberExpression) {
2821
+ return null;
2822
+ }
2823
+ const { property } = call.callee;
2824
+ if (property.type !== AST_NODE_TYPES.Identifier || property.name !== 'push') {
2825
+ return null;
2826
+ }
2827
+ return call;
2828
+ }
2829
+ const rule$2 = createRule$3({
2830
+ create(context) {
2831
+ const { sourceCode } = context;
2832
+ function checkBody(statements) {
2833
+ let i = 0;
2834
+ while (i < statements.length) {
2835
+ const stmt = statements[i];
2836
+ if (stmt.type !== AST_NODE_TYPES.ExpressionStatement) {
2837
+ i++;
2838
+ continue;
2839
+ }
2840
+ const call = getPushCall(stmt);
2841
+ if (!call) {
2842
+ i++;
2843
+ continue;
2844
+ }
2845
+ const arrayText = sourceCode.getText(call.callee.object);
2846
+ const group = [stmt];
2847
+ let j = i + 1;
2848
+ while (j < statements.length) {
2849
+ const nextStmt = statements[j];
2850
+ if (nextStmt.type !== AST_NODE_TYPES.ExpressionStatement) {
2851
+ break;
2852
+ }
2853
+ const nextCall = getPushCall(nextStmt);
2854
+ if (!nextCall ||
2855
+ sourceCode.getText(nextCall.callee.object) !== arrayText) {
2856
+ break;
2857
+ }
2858
+ group.push(nextStmt);
2859
+ j++;
2860
+ }
2861
+ if (group.length > 1) {
2862
+ group.forEach((groupStmt, idx) => {
2863
+ context.report({
2864
+ ...(idx === 0
2865
+ ? {
2866
+ fix(fixer) {
2867
+ const allArgs = group
2868
+ .flatMap((s) => s.expression.arguments)
2869
+ .map((arg) => sourceCode.getText(arg))
2870
+ .join(', ');
2871
+ const lastStmt = group[group.length - 1];
2872
+ return fixer.replaceTextRange([groupStmt.range[0], lastStmt.range[1]], `${arrayText}.push(${allArgs});`);
2873
+ },
2874
+ }
2875
+ : {}),
2876
+ messageId: 'preferMultiArgPush',
2877
+ node: groupStmt,
2878
+ });
2879
+ });
2880
+ }
2881
+ i = j;
2882
+ }
2883
+ }
2884
+ return {
2885
+ BlockStatement(node) {
2886
+ checkBody(node.body);
2887
+ },
2888
+ Program(node) {
2889
+ checkBody(node.body);
2890
+ },
2891
+ };
2892
+ },
2893
+ defaultOptions: [],
2894
+ meta: {
2895
+ docs: {
2896
+ description: 'Enforce combining consecutive .push() calls on the same array into a single call.',
2897
+ },
2898
+ fixable: 'code',
2899
+ messages: {
2900
+ preferMultiArgPush: 'Combine consecutive .push() calls on the same array into a single multi-argument call.',
2901
+ },
2902
+ schema: [],
2903
+ type: 'suggestion',
2904
+ },
2905
+ name: 'prefer-multi-arg-push',
2906
+ });
2907
+
2812
2908
  function getImportedName(spec) {
2813
2909
  if (spec.imported.type === AST_NODE_TYPES.Identifier) {
2814
2910
  return spec.imported.name;
@@ -3284,14 +3380,15 @@ const plugin = {
3284
3380
  'class-property-naming': classPropertyNaming,
3285
3381
  'decorator-key-sort': config$1,
3286
3382
  'flat-exports': flatExports,
3287
- 'injection-token-description': rule$6,
3288
- 'no-deep-imports': rule$5,
3383
+ 'injection-token-description': rule$7,
3384
+ 'no-deep-imports': rule$6,
3289
3385
  'no-deep-imports-to-indexed-packages': noDeepImportsToIndexedPackages,
3290
3386
  'no-href-with-router-link': config,
3291
- 'no-implicit-public': rule$4,
3292
- 'no-playwright-empty-fill': rule$3,
3293
- 'object-single-line': rule$2,
3387
+ 'no-implicit-public': rule$5,
3388
+ 'no-playwright-empty-fill': rule$4,
3389
+ 'object-single-line': rule$3,
3294
3390
  'prefer-deep-imports': preferDeepImports,
3391
+ 'prefer-multi-arg-push': rule$2,
3295
3392
  'short-tui-imports': rule$1,
3296
3393
  'standalone-imports-sort': standaloneImportsSort,
3297
3394
  'strict-tui-doc-example': rule,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/eslint-plugin-experience-next",
3
- "version": "0.438.0",
3
+ "version": "0.439.0",
4
4
  "description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,5 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const rule: ESLintUtils.RuleModule<"preferMultiArgPush", [], unknown, ESLintUtils.RuleListener> & {
3
+ name: string;
4
+ };
5
+ export default rule;