@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 +359 -1
- package/index.d.ts +3 -0
- package/index.esm.js +120 -23
- package/package.json +1 -1
- package/rules/prefer-multi-arg-push.d.ts +5 -0
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
|
-
|
|
|
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$
|
|
1316
|
-
var classPropertyNaming = createRule$
|
|
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$
|
|
1487
|
+
const createRule$b = ESLintUtils.RuleCreator((name) => name);
|
|
1486
1488
|
const MESSAGE_ID$5 = 'spreadArrays';
|
|
1487
|
-
var flatExports = createRule$
|
|
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$
|
|
1615
|
-
const rule$
|
|
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$
|
|
1684
|
-
const rule$
|
|
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$
|
|
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$
|
|
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$
|
|
2021
|
-
const rule$
|
|
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$
|
|
2094
|
-
const rule$
|
|
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$
|
|
2183
|
-
const rule$
|
|
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$
|
|
2464
|
-
var preferDeepImports = createRule$
|
|
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$
|
|
3288
|
-
'no-deep-imports': rule$
|
|
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$
|
|
3292
|
-
'no-playwright-empty-fill': rule$
|
|
3293
|
-
'object-single-line': rule$
|
|
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