@taiga-ui/eslint-plugin-experience-next 0.438.0 → 0.440.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 +121 -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
|
@@ -579,6 +579,7 @@ var recommended = defineConfig([
|
|
|
579
579
|
],
|
|
580
580
|
'@typescript-eslint/unbound-method': 'off',
|
|
581
581
|
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'error',
|
|
582
|
+
'arrow-body-style': ['error', 'as-needed'],
|
|
582
583
|
curly: ['error', 'all'],
|
|
583
584
|
'decorator-position/decorator-position': [
|
|
584
585
|
'error',
|
|
@@ -600,6 +601,7 @@ var recommended = defineConfig([
|
|
|
600
601
|
'import/no-cycle': 'error',
|
|
601
602
|
'import/no-duplicates': ['error', { 'prefer-inline': true }],
|
|
602
603
|
'import/no-mutable-exports': 'error',
|
|
604
|
+
'import/no-named-as-default': 'error',
|
|
603
605
|
'import/no-self-import': 'error',
|
|
604
606
|
'import/no-unresolved': 'off',
|
|
605
607
|
'import/no-useless-path-segments': ['error', { noUselessIndex: true }],
|
|
@@ -901,6 +903,7 @@ var recommended = defineConfig([
|
|
|
901
903
|
'@taiga-ui/experience-next/no-deep-imports-to-indexed-packages': 'error',
|
|
902
904
|
'@taiga-ui/experience-next/no-implicit-public': 'error',
|
|
903
905
|
'@taiga-ui/experience-next/object-single-line': ['error', { printWidth: 90 }],
|
|
906
|
+
'@taiga-ui/experience-next/prefer-multi-arg-push': 'error',
|
|
904
907
|
'@taiga-ui/experience-next/short-tui-imports': 'error',
|
|
905
908
|
'@taiga-ui/experience-next/standalone-imports-sort': [
|
|
906
909
|
'error',
|
|
@@ -1312,8 +1315,8 @@ function intersect(a, b) {
|
|
|
1312
1315
|
return a.some((type) => origin.has(type));
|
|
1313
1316
|
}
|
|
1314
1317
|
|
|
1315
|
-
const createRule$
|
|
1316
|
-
var classPropertyNaming = createRule$
|
|
1318
|
+
const createRule$c = ESLintUtils.RuleCreator((name) => name);
|
|
1319
|
+
var classPropertyNaming = createRule$c({
|
|
1317
1320
|
create(context, [configs]) {
|
|
1318
1321
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1319
1322
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
@@ -1482,9 +1485,9 @@ function isExternalPureTuple(typeChecker, type) {
|
|
|
1482
1485
|
return typeArgs.every((item) => isClassType(item));
|
|
1483
1486
|
}
|
|
1484
1487
|
|
|
1485
|
-
const createRule$
|
|
1488
|
+
const createRule$b = ESLintUtils.RuleCreator((name) => name);
|
|
1486
1489
|
const MESSAGE_ID$5 = 'spreadArrays';
|
|
1487
|
-
var flatExports = createRule$
|
|
1490
|
+
var flatExports = createRule$b({
|
|
1488
1491
|
create(context) {
|
|
1489
1492
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1490
1493
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
@@ -1611,8 +1614,8 @@ var flatExports = createRule$a({
|
|
|
1611
1614
|
|
|
1612
1615
|
const MESSAGE_ID$4 = 'invalid-injection-token-description';
|
|
1613
1616
|
const ERROR_MESSAGE$3 = "InjectionToken's description should contain token's name";
|
|
1614
|
-
const createRule$
|
|
1615
|
-
const rule$
|
|
1617
|
+
const createRule$a = ESLintUtils.RuleCreator((name) => name);
|
|
1618
|
+
const rule$7 = createRule$a({
|
|
1616
1619
|
create(context) {
|
|
1617
1620
|
return {
|
|
1618
1621
|
'NewExpression[callee.name="InjectionToken"]'(node) {
|
|
@@ -1680,8 +1683,8 @@ const DEFAULT_OPTIONS = {
|
|
|
1680
1683
|
importDeclaration: '^@taiga-ui*',
|
|
1681
1684
|
projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
|
|
1682
1685
|
};
|
|
1683
|
-
const createRule$
|
|
1684
|
-
const rule$
|
|
1686
|
+
const createRule$9 = ESLintUtils.RuleCreator((name) => name);
|
|
1687
|
+
const rule$6 = createRule$9({
|
|
1685
1688
|
create(context) {
|
|
1686
1689
|
const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
|
|
1687
1690
|
const hasNonCodeExtension = (source) => {
|
|
@@ -1768,13 +1771,13 @@ const rule$5 = createRule$8({
|
|
|
1768
1771
|
name: 'no-deep-imports',
|
|
1769
1772
|
});
|
|
1770
1773
|
|
|
1771
|
-
const createRule$
|
|
1774
|
+
const createRule$8 = ESLintUtils.RuleCreator((name) => name);
|
|
1772
1775
|
const resolveCacheByOptions = new WeakMap();
|
|
1773
1776
|
const nearestFileUpCache = new Map();
|
|
1774
1777
|
const markerCache = new Map();
|
|
1775
1778
|
const indexFileCache = new Map();
|
|
1776
1779
|
const indexExportsCache = new Map();
|
|
1777
|
-
var noDeepImportsToIndexedPackages = createRule$
|
|
1780
|
+
var noDeepImportsToIndexedPackages = createRule$8({
|
|
1778
1781
|
create(context) {
|
|
1779
1782
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1780
1783
|
const program = parserServices.program;
|
|
@@ -2017,8 +2020,8 @@ const config = {
|
|
|
2017
2020
|
},
|
|
2018
2021
|
};
|
|
2019
2022
|
|
|
2020
|
-
const createRule$
|
|
2021
|
-
const rule$
|
|
2023
|
+
const createRule$7 = ESLintUtils.RuleCreator((name) => name);
|
|
2024
|
+
const rule$5 = createRule$7({
|
|
2022
2025
|
create(context) {
|
|
2023
2026
|
const checkImplicitPublic = (node) => {
|
|
2024
2027
|
const classRef = getClass(node);
|
|
@@ -2090,8 +2093,8 @@ function getClass(node) {
|
|
|
2090
2093
|
return getClass(node.parent);
|
|
2091
2094
|
}
|
|
2092
2095
|
|
|
2093
|
-
const createRule$
|
|
2094
|
-
const rule$
|
|
2096
|
+
const createRule$6 = ESLintUtils.RuleCreator((name) => name);
|
|
2097
|
+
const rule$4 = createRule$6({
|
|
2095
2098
|
create(context) {
|
|
2096
2099
|
const services = ESLintUtils.getParserServices(context);
|
|
2097
2100
|
const checker = services.program.getTypeChecker();
|
|
@@ -2179,8 +2182,8 @@ function isPlaywrightLocatorType(type) {
|
|
|
2179
2182
|
});
|
|
2180
2183
|
}
|
|
2181
2184
|
|
|
2182
|
-
const createRule$
|
|
2183
|
-
const rule$
|
|
2185
|
+
const createRule$5 = ESLintUtils.RuleCreator((name) => name);
|
|
2186
|
+
const rule$3 = createRule$5({
|
|
2184
2187
|
create(context, [{ printWidth }]) {
|
|
2185
2188
|
const sourceCode = context.sourceCode;
|
|
2186
2189
|
const getLineEndIndex = (lineStartIndex) => {
|
|
@@ -2460,8 +2463,8 @@ const rule$2 = createRule$4({
|
|
|
2460
2463
|
|
|
2461
2464
|
const MESSAGE_ID$1 = 'prefer-deep-imports';
|
|
2462
2465
|
const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
|
|
2463
|
-
const createRule$
|
|
2464
|
-
var preferDeepImports = createRule$
|
|
2466
|
+
const createRule$4 = ESLintUtils.RuleCreator(() => ERROR_MESSAGE);
|
|
2467
|
+
var preferDeepImports = createRule$4({
|
|
2465
2468
|
create(context, [options]) {
|
|
2466
2469
|
const allowedPackages = normalizeImportFilter(options.importFilter);
|
|
2467
2470
|
const isStrictMode = options.strict ?? false;
|
|
@@ -2809,6 +2812,100 @@ function buildRewrittenImports(node, baseImportPath, symbolToEntryPoint) {
|
|
|
2809
2812
|
return importStatements.join('\n');
|
|
2810
2813
|
}
|
|
2811
2814
|
|
|
2815
|
+
const createRule$3 = ESLintUtils.RuleCreator((name) => name);
|
|
2816
|
+
function getPushCall(node) {
|
|
2817
|
+
if (node.expression.type !== AST_NODE_TYPES.CallExpression) {
|
|
2818
|
+
return null;
|
|
2819
|
+
}
|
|
2820
|
+
const call = node.expression;
|
|
2821
|
+
if (call.callee.type !== AST_NODE_TYPES.MemberExpression) {
|
|
2822
|
+
return null;
|
|
2823
|
+
}
|
|
2824
|
+
const { property } = call.callee;
|
|
2825
|
+
if (property.type !== AST_NODE_TYPES.Identifier || property.name !== 'push') {
|
|
2826
|
+
return null;
|
|
2827
|
+
}
|
|
2828
|
+
return call;
|
|
2829
|
+
}
|
|
2830
|
+
const rule$2 = createRule$3({
|
|
2831
|
+
create(context) {
|
|
2832
|
+
const { sourceCode } = context;
|
|
2833
|
+
function checkBody(statements) {
|
|
2834
|
+
let i = 0;
|
|
2835
|
+
while (i < statements.length) {
|
|
2836
|
+
const stmt = statements[i];
|
|
2837
|
+
if (stmt.type !== AST_NODE_TYPES.ExpressionStatement) {
|
|
2838
|
+
i++;
|
|
2839
|
+
continue;
|
|
2840
|
+
}
|
|
2841
|
+
const call = getPushCall(stmt);
|
|
2842
|
+
if (!call) {
|
|
2843
|
+
i++;
|
|
2844
|
+
continue;
|
|
2845
|
+
}
|
|
2846
|
+
const arrayText = sourceCode.getText(call.callee.object);
|
|
2847
|
+
const group = [stmt];
|
|
2848
|
+
let j = i + 1;
|
|
2849
|
+
while (j < statements.length) {
|
|
2850
|
+
const nextStmt = statements[j];
|
|
2851
|
+
if (nextStmt.type !== AST_NODE_TYPES.ExpressionStatement) {
|
|
2852
|
+
break;
|
|
2853
|
+
}
|
|
2854
|
+
const nextCall = getPushCall(nextStmt);
|
|
2855
|
+
if (!nextCall ||
|
|
2856
|
+
sourceCode.getText(nextCall.callee.object) !== arrayText) {
|
|
2857
|
+
break;
|
|
2858
|
+
}
|
|
2859
|
+
group.push(nextStmt);
|
|
2860
|
+
j++;
|
|
2861
|
+
}
|
|
2862
|
+
if (group.length > 1) {
|
|
2863
|
+
group.forEach((groupStmt, idx) => {
|
|
2864
|
+
context.report({
|
|
2865
|
+
...(idx === 0
|
|
2866
|
+
? {
|
|
2867
|
+
fix(fixer) {
|
|
2868
|
+
const allArgs = group
|
|
2869
|
+
.flatMap((s) => s.expression.arguments)
|
|
2870
|
+
.map((arg) => sourceCode.getText(arg))
|
|
2871
|
+
.join(', ');
|
|
2872
|
+
const lastStmt = group[group.length - 1];
|
|
2873
|
+
return fixer.replaceTextRange([groupStmt.range[0], lastStmt.range[1]], `${arrayText}.push(${allArgs});`);
|
|
2874
|
+
},
|
|
2875
|
+
}
|
|
2876
|
+
: {}),
|
|
2877
|
+
messageId: 'preferMultiArgPush',
|
|
2878
|
+
node: groupStmt,
|
|
2879
|
+
});
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2882
|
+
i = j;
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
return {
|
|
2886
|
+
BlockStatement(node) {
|
|
2887
|
+
checkBody(node.body);
|
|
2888
|
+
},
|
|
2889
|
+
Program(node) {
|
|
2890
|
+
checkBody(node.body);
|
|
2891
|
+
},
|
|
2892
|
+
};
|
|
2893
|
+
},
|
|
2894
|
+
defaultOptions: [],
|
|
2895
|
+
meta: {
|
|
2896
|
+
docs: {
|
|
2897
|
+
description: 'Enforce combining consecutive .push() calls on the same array into a single call.',
|
|
2898
|
+
},
|
|
2899
|
+
fixable: 'code',
|
|
2900
|
+
messages: {
|
|
2901
|
+
preferMultiArgPush: 'Combine consecutive .push() calls on the same array into a single multi-argument call.',
|
|
2902
|
+
},
|
|
2903
|
+
schema: [],
|
|
2904
|
+
type: 'suggestion',
|
|
2905
|
+
},
|
|
2906
|
+
name: 'prefer-multi-arg-push',
|
|
2907
|
+
});
|
|
2908
|
+
|
|
2812
2909
|
function getImportedName(spec) {
|
|
2813
2910
|
if (spec.imported.type === AST_NODE_TYPES.Identifier) {
|
|
2814
2911
|
return spec.imported.name;
|
|
@@ -3284,14 +3381,15 @@ const plugin = {
|
|
|
3284
3381
|
'class-property-naming': classPropertyNaming,
|
|
3285
3382
|
'decorator-key-sort': config$1,
|
|
3286
3383
|
'flat-exports': flatExports,
|
|
3287
|
-
'injection-token-description': rule$
|
|
3288
|
-
'no-deep-imports': rule$
|
|
3384
|
+
'injection-token-description': rule$7,
|
|
3385
|
+
'no-deep-imports': rule$6,
|
|
3289
3386
|
'no-deep-imports-to-indexed-packages': noDeepImportsToIndexedPackages,
|
|
3290
3387
|
'no-href-with-router-link': config,
|
|
3291
|
-
'no-implicit-public': rule$
|
|
3292
|
-
'no-playwright-empty-fill': rule$
|
|
3293
|
-
'object-single-line': rule$
|
|
3388
|
+
'no-implicit-public': rule$5,
|
|
3389
|
+
'no-playwright-empty-fill': rule$4,
|
|
3390
|
+
'object-single-line': rule$3,
|
|
3294
3391
|
'prefer-deep-imports': preferDeepImports,
|
|
3392
|
+
'prefer-multi-arg-push': rule$2,
|
|
3295
3393
|
'short-tui-imports': rule$1,
|
|
3296
3394
|
'standalone-imports-sort': standaloneImportsSort,
|
|
3297
3395
|
'strict-tui-doc-example': rule,
|
package/package.json
CHANGED