@taiga-ui/eslint-plugin-experience-next 0.507.0 → 0.509.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 +1 -36
- package/index.d.ts +4 -1
- package/index.esm.js +503 -187
- package/package.json +1 -1
- package/rules/recommended/decorator-key-sort.d.ts +2 -2
- package/rules/recommended/no-empty-style-metadata.d.ts +5 -0
- package/rules/recommended/prefer-conditional-return.d.ts +2 -2
- package/rules/utils/angular/get-decorator-metadata.d.ts +8 -2
- package/rules/utils/angular/is-imports-array-property.d.ts +1 -1
- package/rules/utils/sorting/get-sorted-names.d.ts +2 -2
package/README.md
CHANGED
|
@@ -88,6 +88,7 @@ from third-party plugins. The exact severities and file globs live in
|
|
|
88
88
|
| [no-duplicate-attrs](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-duplicate-attrs.md) | Disallow duplicate attributes on the same HTML element | ✅ | | |
|
|
89
89
|
| [no-duplicate-id](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-duplicate-id.md) | Disallow duplicate static `id` values in HTML templates | ✅ | | |
|
|
90
90
|
| [no-duplicate-in-head](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-duplicate-in-head.md) | Disallow duplicate `title`, `base`, and key metadata tags inside `<head>` | ✅ | | |
|
|
91
|
+
| [no-empty-style-metadata](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-empty-style-metadata.md) | Remove empty Angular component style metadata | ✅ | 🔧 | |
|
|
91
92
|
| [no-fully-untracked-effect](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-fully-untracked-effect.md) | Disallow reactive callbacks where all signal reads are hidden inside `untracked()` | ✅ | | |
|
|
92
93
|
| [no-href-with-router-link](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-href-with-router-link.md) | Do not use href and routerLink attributes together on the same element | ✅ | 🔧 | |
|
|
93
94
|
| [no-import-assertions](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-import-assertions.md) | Replace legacy `assert { ... }` import assertions with `with { ... }` | ✅ | 🔧 | |
|
|
@@ -126,39 +127,3 @@ from third-party plugins. The exact severities and file globs live in
|
|
|
126
127
|
| [single-line-variable-spacing](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/single-line-variable-spacing.md) | Group consecutive single-line variables and separate multiline ones with a blank line | ✅ | 🔧 | |
|
|
127
128
|
| [standalone-imports-sort](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/standalone-imports-sort.md) | Auto sort names inside Angular decorators | ✅ | 🔧 | |
|
|
128
129
|
| [strict-tui-doc-example](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/strict-tui-doc-example.md) | If you use the addon-doc, there will be a hint that you are importing something incorrectly | | 🔧 | |
|
|
129
|
-
|
|
130
|
-
## prefer-conditional-return
|
|
131
|
-
|
|
132
|
-
Prefer a single conditional return when an `if` statement returns one expression and the immediately following statement
|
|
133
|
-
returns the fallback expression. The rule skips branches with comments, `else`, empty returns, intervening statements,
|
|
134
|
-
or a return expression that is already a conditional expression.
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
// ❌ error
|
|
138
|
-
if (index < count) {
|
|
139
|
-
return {value: index++, done: false};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return {value: undefined, done: true};
|
|
143
|
-
|
|
144
|
-
// ✅ after autofix
|
|
145
|
-
return index < count ? {value: index++, done: false} : {value: undefined, done: true};
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
```ts
|
|
149
|
-
// not changed: if branch return is already conditional
|
|
150
|
-
if (condition) {
|
|
151
|
-
return first ? second : third;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return fallback;
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
// not changed: fallback return is already conditional
|
|
159
|
-
if (condition) {
|
|
160
|
-
return value;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return first ? second : third;
|
|
164
|
-
```
|
package/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ declare const plugin: {
|
|
|
18
18
|
'class-property-naming': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidName", [import("./rules/taiga-specific/class-property-naming").RuleConfig[]], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
19
19
|
name: string;
|
|
20
20
|
};
|
|
21
|
-
'decorator-key-sort': import("eslint").
|
|
21
|
+
'decorator-key-sort': import("@typescript-eslint/utils/ts-eslint").RuleModule<"incorrectOrder", [Record<string, readonly string[]>], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
22
22
|
name: string;
|
|
23
23
|
};
|
|
24
24
|
'element-newline': import("eslint").Rule.RuleModule & {
|
|
@@ -78,6 +78,9 @@ declare const plugin: {
|
|
|
78
78
|
'no-duplicate-in-head': import("eslint").Rule.RuleModule & {
|
|
79
79
|
name: string;
|
|
80
80
|
};
|
|
81
|
+
'no-empty-style-metadata': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noEmptyStyleMetadata", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
82
|
+
name: string;
|
|
83
|
+
};
|
|
81
84
|
'no-fully-untracked-effect': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noTrackedReads", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
82
85
|
name: string;
|
|
83
86
|
};
|
package/index.esm.js
CHANGED
|
@@ -532,6 +532,7 @@ var recommended = defineConfig([
|
|
|
532
532
|
progress.configs['recommended-ci'],
|
|
533
533
|
{
|
|
534
534
|
ignores: [
|
|
535
|
+
'**/tests-results/**',
|
|
535
536
|
'**/tests-report/**',
|
|
536
537
|
'**/snapshots/**',
|
|
537
538
|
'**/test-results/**',
|
|
@@ -1201,6 +1202,7 @@ var recommended = defineConfig([
|
|
|
1201
1202
|
},
|
|
1202
1203
|
],
|
|
1203
1204
|
'@taiga-ui/experience-next/no-deep-imports-to-indexed-packages': 'error',
|
|
1205
|
+
'@taiga-ui/experience-next/no-empty-style-metadata': 'error',
|
|
1204
1206
|
'@taiga-ui/experience-next/no-fully-untracked-effect': 'error',
|
|
1205
1207
|
'@taiga-ui/experience-next/no-implicit-public': 'error',
|
|
1206
1208
|
'@taiga-ui/experience-next/no-import-assertions': 'error',
|
|
@@ -46222,7 +46224,7 @@ function buildMultilineStartTag(node, sourceText) {
|
|
|
46222
46224
|
closing,
|
|
46223
46225
|
].join('\n');
|
|
46224
46226
|
}
|
|
46225
|
-
const rule$
|
|
46227
|
+
const rule$S = createRule({
|
|
46226
46228
|
name: 'attrs-newline',
|
|
46227
46229
|
rule: {
|
|
46228
46230
|
create(context) {
|
|
@@ -46308,54 +46310,151 @@ const rule$R = createRule({
|
|
|
46308
46310
|
},
|
|
46309
46311
|
});
|
|
46310
46312
|
|
|
46313
|
+
function isObject(node) {
|
|
46314
|
+
return node?.type === dist$2.AST_NODE_TYPES.ObjectExpression;
|
|
46315
|
+
}
|
|
46316
|
+
|
|
46317
|
+
/**
|
|
46318
|
+
* Extracts the metadata object from a class decorator such as
|
|
46319
|
+
* `@Component()`, `@Directive()`, `@NgModule()`, or `@Pipe()`.
|
|
46320
|
+
*
|
|
46321
|
+
* Returns the first argument of the decorator call *if and only if*
|
|
46322
|
+
* it is an `ObjectExpression`.
|
|
46323
|
+
*
|
|
46324
|
+
* @example
|
|
46325
|
+
* // Given:
|
|
46326
|
+
* @Component({
|
|
46327
|
+
* selector: 'x',
|
|
46328
|
+
* imports: [A, B],
|
|
46329
|
+
* })
|
|
46330
|
+
* class MyCmp {}
|
|
46331
|
+
*
|
|
46332
|
+
* // In the AST for @Component(...)
|
|
46333
|
+
* getDecoratorMetadata(decorator, allowed) returns
|
|
46334
|
+
* ObjectExpression({ selector: ..., imports: ... })
|
|
46335
|
+
*
|
|
46336
|
+
* @param decorator - The decorator node attached to a class declaration.
|
|
46337
|
+
* @param allowedNames - A set of decorator names to consider
|
|
46338
|
+
* (e.g., Component, Directive, NgModule, Pipe).
|
|
46339
|
+
*
|
|
46340
|
+
* @returns The metadata `ObjectExpression` if present and valid,
|
|
46341
|
+
* otherwise `null`.
|
|
46342
|
+
*/
|
|
46343
|
+
function getDecoratorMetadata(decorator, allowedNames) {
|
|
46344
|
+
return getDecoratorMetadataWithName(decorator, allowedNames)?.metadata ?? null;
|
|
46345
|
+
}
|
|
46346
|
+
function getDecoratorMetadataWithName(decorator, allowedNames) {
|
|
46347
|
+
const expr = decorator.expression;
|
|
46348
|
+
if (expr.type !== dist$2.AST_NODE_TYPES.CallExpression) {
|
|
46349
|
+
return null;
|
|
46350
|
+
}
|
|
46351
|
+
const callee = expr.callee;
|
|
46352
|
+
if (callee.type !== dist$2.AST_NODE_TYPES.Identifier || !allowedNames.has(callee.name)) {
|
|
46353
|
+
return null;
|
|
46354
|
+
}
|
|
46355
|
+
const arg = expr.arguments[0];
|
|
46356
|
+
return isObject(arg) ? { expression: expr, metadata: arg, name: callee.name } : null;
|
|
46357
|
+
}
|
|
46358
|
+
|
|
46359
|
+
function isStringLiteral(node) {
|
|
46360
|
+
return node?.type === dist$3.AST_NODE_TYPES.Literal && typeof node.value === 'string';
|
|
46361
|
+
}
|
|
46362
|
+
function isStaticTemplateLiteral(node) {
|
|
46363
|
+
return (node?.type === dist$3.AST_NODE_TYPES.TemplateLiteral &&
|
|
46364
|
+
node.expressions.length === 0 &&
|
|
46365
|
+
node.quasis.length === 1);
|
|
46366
|
+
}
|
|
46367
|
+
function getStaticStringValue(node) {
|
|
46368
|
+
if (isStringLiteral(node)) {
|
|
46369
|
+
return node.value;
|
|
46370
|
+
}
|
|
46371
|
+
return isStaticTemplateLiteral(node)
|
|
46372
|
+
? (node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? '')
|
|
46373
|
+
: null;
|
|
46374
|
+
}
|
|
46375
|
+
function isEmptyStaticString(node) {
|
|
46376
|
+
return getStaticStringValue(node) === '';
|
|
46377
|
+
}
|
|
46378
|
+
|
|
46379
|
+
function getStaticPropertyName(key) {
|
|
46380
|
+
if (key.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46381
|
+
return key.name;
|
|
46382
|
+
}
|
|
46383
|
+
return key.type === dist$3.AST_NODE_TYPES.Literal &&
|
|
46384
|
+
(typeof key.value === 'string' || typeof key.value === 'number')
|
|
46385
|
+
? String(key.value)
|
|
46386
|
+
: getStaticStringValue(key);
|
|
46387
|
+
}
|
|
46388
|
+
function getObjectPropertyName(node) {
|
|
46389
|
+
return node.computed ? null : getStaticPropertyName(node.key);
|
|
46390
|
+
}
|
|
46391
|
+
function getMemberExpressionPropertyName(node) {
|
|
46392
|
+
if (!node.computed && node.property.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46393
|
+
return node.property.name;
|
|
46394
|
+
}
|
|
46395
|
+
return node.computed ? getStaticStringValue(node.property) : null;
|
|
46396
|
+
}
|
|
46397
|
+
function getClassMemberName(member) {
|
|
46398
|
+
return member.key.type === dist$3.AST_NODE_TYPES.PrivateIdentifier
|
|
46399
|
+
? null
|
|
46400
|
+
: getStaticPropertyName(member.key);
|
|
46401
|
+
}
|
|
46402
|
+
|
|
46311
46403
|
function sameOrder(a, b) {
|
|
46312
46404
|
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
46313
46405
|
}
|
|
46314
46406
|
|
|
46315
|
-
const
|
|
46316
|
-
create(context) {
|
|
46317
|
-
const
|
|
46407
|
+
const rule$R = createRule({
|
|
46408
|
+
create(context, [order]) {
|
|
46409
|
+
const decorators = new Set(Object.keys(order));
|
|
46318
46410
|
return {
|
|
46319
46411
|
ClassDeclaration(node) {
|
|
46320
|
-
const
|
|
46321
|
-
|
|
46322
|
-
|
|
46323
|
-
|
|
46324
|
-
|
|
46325
|
-
|
|
46326
|
-
|
|
46327
|
-
|
|
46328
|
-
|
|
46329
|
-
|
|
46330
|
-
|
|
46331
|
-
|
|
46332
|
-
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
fix: (fixer) => {
|
|
46336
|
-
const fileContent = context.sourceCode.text;
|
|
46337
|
-
const forgottenProps = current.filter((key) => !orderList.includes(key));
|
|
46338
|
-
const sortedDecoratorProperties = [
|
|
46339
|
-
...correct,
|
|
46340
|
-
...forgottenProps,
|
|
46341
|
-
].map((key) => properties.find((prop) => prop.key.name === key));
|
|
46342
|
-
const newDecoratorArgument = `{${sortedDecoratorProperties
|
|
46343
|
-
.map(({ range }) => fileContent.slice(...range))
|
|
46344
|
-
.toString()}}`;
|
|
46345
|
-
return fixer.replaceTextRange(argument.range, newDecoratorArgument);
|
|
46346
|
-
},
|
|
46347
|
-
message: `Incorrect order keys in @${decoratorName} decorator, please sort by [${correct.join(' -> ')}]`,
|
|
46348
|
-
node: expression,
|
|
46349
|
-
});
|
|
46350
|
-
}
|
|
46351
|
-
}
|
|
46412
|
+
for (const decorator of node?.decorators ?? []) {
|
|
46413
|
+
const metadata = getDecoratorMetadataWithName(decorator, decorators);
|
|
46414
|
+
if (!metadata) {
|
|
46415
|
+
continue;
|
|
46416
|
+
}
|
|
46417
|
+
const orderList = order[metadata.name] ?? [];
|
|
46418
|
+
const properties = getDecoratorProperties(metadata.metadata);
|
|
46419
|
+
if (!properties) {
|
|
46420
|
+
continue;
|
|
46421
|
+
}
|
|
46422
|
+
const current = properties.map(({ name }) => name);
|
|
46423
|
+
const correct = getCorrectOrderRelative(orderList, current);
|
|
46424
|
+
const sortableCurrent = current.filter((item) => correct.includes(item));
|
|
46425
|
+
if (sameOrder(correct, sortableCurrent)) {
|
|
46426
|
+
continue;
|
|
46352
46427
|
}
|
|
46428
|
+
context.report({
|
|
46429
|
+
data: {
|
|
46430
|
+
decorator: metadata.name,
|
|
46431
|
+
order: correct.join(' -> '),
|
|
46432
|
+
},
|
|
46433
|
+
fix: (fixer) => {
|
|
46434
|
+
const forgottenProps = properties.filter(({ name }) => !orderList.includes(name));
|
|
46435
|
+
const sortedDecoratorProperties = [
|
|
46436
|
+
...correct.flatMap((key) => properties.filter(({ name }) => name === key)),
|
|
46437
|
+
...forgottenProps,
|
|
46438
|
+
];
|
|
46439
|
+
const newDecoratorArgument = `{${sortedDecoratorProperties
|
|
46440
|
+
.map(({ node }) => context.sourceCode.text.slice(...node.range))
|
|
46441
|
+
.join(',')}}`;
|
|
46442
|
+
return fixer.replaceTextRange(metadata.metadata.range, newDecoratorArgument);
|
|
46443
|
+
},
|
|
46444
|
+
messageId: 'incorrectOrder',
|
|
46445
|
+
node: metadata.expression,
|
|
46446
|
+
});
|
|
46353
46447
|
}
|
|
46354
46448
|
},
|
|
46355
46449
|
};
|
|
46356
46450
|
},
|
|
46357
46451
|
meta: {
|
|
46452
|
+
defaultOptions: [{}],
|
|
46453
|
+
docs: { description: 'Sorts keys of Angular decorator metadata.' },
|
|
46358
46454
|
fixable: 'code',
|
|
46455
|
+
messages: {
|
|
46456
|
+
incorrectOrder: 'Incorrect order keys in @{{decorator}} decorator, please sort by [{{order}}]',
|
|
46457
|
+
},
|
|
46359
46458
|
schema: [
|
|
46360
46459
|
{
|
|
46361
46460
|
additionalProperties: true,
|
|
@@ -46365,14 +46464,25 @@ const config$5 = {
|
|
|
46365
46464
|
],
|
|
46366
46465
|
type: 'problem',
|
|
46367
46466
|
},
|
|
46368
|
-
|
|
46467
|
+
name: 'decorator-key-sort',
|
|
46468
|
+
});
|
|
46369
46469
|
function getCorrectOrderRelative(correct, current) {
|
|
46370
46470
|
return correct.filter((item) => current.includes(item));
|
|
46371
46471
|
}
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
|
|
46375
|
-
|
|
46472
|
+
function getDecoratorProperties(metadata) {
|
|
46473
|
+
const properties = [];
|
|
46474
|
+
for (const property of metadata.properties) {
|
|
46475
|
+
if (property.type !== dist$3.AST_NODE_TYPES.Property) {
|
|
46476
|
+
return null;
|
|
46477
|
+
}
|
|
46478
|
+
const name = getObjectPropertyName(property);
|
|
46479
|
+
if (!name) {
|
|
46480
|
+
return null;
|
|
46481
|
+
}
|
|
46482
|
+
properties.push({ name, node: property });
|
|
46483
|
+
}
|
|
46484
|
+
return properties;
|
|
46485
|
+
}
|
|
46376
46486
|
|
|
46377
46487
|
const INLINE_HTML_ELEMENTS = new Set([
|
|
46378
46488
|
'a',
|
|
@@ -46430,7 +46540,7 @@ function getNodeLabel(node) {
|
|
|
46430
46540
|
}
|
|
46431
46541
|
return node instanceof dist$4.TmplAstBoundText ? 'binding' : 'text';
|
|
46432
46542
|
}
|
|
46433
|
-
const rule$
|
|
46543
|
+
const rule$Q = createRule({
|
|
46434
46544
|
name: 'element-newline',
|
|
46435
46545
|
rule: {
|
|
46436
46546
|
create(context) {
|
|
@@ -46504,93 +46614,6 @@ const rule$P = createRule({
|
|
|
46504
46614
|
},
|
|
46505
46615
|
});
|
|
46506
46616
|
|
|
46507
|
-
function isObject(node) {
|
|
46508
|
-
return node?.type === dist$2.AST_NODE_TYPES.ObjectExpression;
|
|
46509
|
-
}
|
|
46510
|
-
|
|
46511
|
-
/**
|
|
46512
|
-
* Extracts the metadata object from a class decorator such as
|
|
46513
|
-
* `@Component()`, `@Directive()`, `@NgModule()`, or `@Pipe()`.
|
|
46514
|
-
*
|
|
46515
|
-
* Returns the first argument of the decorator call *if and only if*
|
|
46516
|
-
* it is an `ObjectExpression`.
|
|
46517
|
-
*
|
|
46518
|
-
* @example
|
|
46519
|
-
* // Given:
|
|
46520
|
-
* @Component({
|
|
46521
|
-
* selector: 'x',
|
|
46522
|
-
* imports: [A, B],
|
|
46523
|
-
* })
|
|
46524
|
-
* class MyCmp {}
|
|
46525
|
-
*
|
|
46526
|
-
* // In the AST for @Component(...)
|
|
46527
|
-
* getDecoratorMetadata(decorator, allowed) →
|
|
46528
|
-
* ObjectExpression({ selector: ..., imports: ... })
|
|
46529
|
-
*
|
|
46530
|
-
* @param decorator - The decorator node attached to a class declaration.
|
|
46531
|
-
* @param allowedNames - A set of decorator names to consider
|
|
46532
|
-
* (e.g., Component, Directive, NgModule, Pipe).
|
|
46533
|
-
*
|
|
46534
|
-
* @returns The metadata `ObjectExpression` if present and valid,
|
|
46535
|
-
* otherwise `null`.
|
|
46536
|
-
*/
|
|
46537
|
-
function getDecoratorMetadata(decorator, allowedNames) {
|
|
46538
|
-
const expr = decorator.expression;
|
|
46539
|
-
if (expr.type !== dist$2.AST_NODE_TYPES.CallExpression) {
|
|
46540
|
-
return null;
|
|
46541
|
-
}
|
|
46542
|
-
const callee = expr.callee;
|
|
46543
|
-
if (callee.type !== dist$2.AST_NODE_TYPES.Identifier || !allowedNames.has(callee.name)) {
|
|
46544
|
-
return null;
|
|
46545
|
-
}
|
|
46546
|
-
const arg = expr.arguments[0];
|
|
46547
|
-
return isObject(arg) ? arg : null;
|
|
46548
|
-
}
|
|
46549
|
-
|
|
46550
|
-
function isStringLiteral(node) {
|
|
46551
|
-
return node?.type === dist$3.AST_NODE_TYPES.Literal && typeof node.value === 'string';
|
|
46552
|
-
}
|
|
46553
|
-
function isStaticTemplateLiteral(node) {
|
|
46554
|
-
return (node?.type === dist$3.AST_NODE_TYPES.TemplateLiteral &&
|
|
46555
|
-
node.expressions.length === 0 &&
|
|
46556
|
-
node.quasis.length === 1);
|
|
46557
|
-
}
|
|
46558
|
-
function getStaticStringValue(node) {
|
|
46559
|
-
if (isStringLiteral(node)) {
|
|
46560
|
-
return node.value;
|
|
46561
|
-
}
|
|
46562
|
-
return isStaticTemplateLiteral(node)
|
|
46563
|
-
? (node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? '')
|
|
46564
|
-
: null;
|
|
46565
|
-
}
|
|
46566
|
-
function isEmptyStaticString(node) {
|
|
46567
|
-
return getStaticStringValue(node) === '';
|
|
46568
|
-
}
|
|
46569
|
-
|
|
46570
|
-
function getStaticPropertyName(key) {
|
|
46571
|
-
if (key.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46572
|
-
return key.name;
|
|
46573
|
-
}
|
|
46574
|
-
return key.type === dist$3.AST_NODE_TYPES.Literal &&
|
|
46575
|
-
(typeof key.value === 'string' || typeof key.value === 'number')
|
|
46576
|
-
? String(key.value)
|
|
46577
|
-
: getStaticStringValue(key);
|
|
46578
|
-
}
|
|
46579
|
-
function getObjectPropertyName(node) {
|
|
46580
|
-
return node.computed ? null : getStaticPropertyName(node.key);
|
|
46581
|
-
}
|
|
46582
|
-
function getMemberExpressionPropertyName(node) {
|
|
46583
|
-
if (!node.computed && node.property.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46584
|
-
return node.property.name;
|
|
46585
|
-
}
|
|
46586
|
-
return node.computed ? getStaticStringValue(node.property) : null;
|
|
46587
|
-
}
|
|
46588
|
-
function getClassMemberName(member) {
|
|
46589
|
-
return member.key.type === dist$3.AST_NODE_TYPES.PrivateIdentifier
|
|
46590
|
-
? null
|
|
46591
|
-
: getStaticPropertyName(member.key);
|
|
46592
|
-
}
|
|
46593
|
-
|
|
46594
46617
|
const DEFAULT_GROUP = '$DEFAULT';
|
|
46595
46618
|
const DEFAULT_ATTRIBUTE_GROUPS = [
|
|
46596
46619
|
'$ANGULAR_STRUCTURAL_DIRECTIVE',
|
|
@@ -46656,7 +46679,7 @@ const PRESETS = {
|
|
|
46656
46679
|
$VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
|
|
46657
46680
|
$VUE_ATTRIBUTE: /^v-/,
|
|
46658
46681
|
};
|
|
46659
|
-
const rule$
|
|
46682
|
+
const rule$P = createRule({
|
|
46660
46683
|
create(context, [options]) {
|
|
46661
46684
|
const sourceCode = context.sourceCode;
|
|
46662
46685
|
const settings = {
|
|
@@ -46987,7 +47010,7 @@ const config$4 = {
|
|
|
46987
47010
|
type: 'suggestion',
|
|
46988
47011
|
},
|
|
46989
47012
|
};
|
|
46990
|
-
const rule$
|
|
47013
|
+
const rule$O = createRule({
|
|
46991
47014
|
name: 'html-logical-properties',
|
|
46992
47015
|
rule: config$4,
|
|
46993
47016
|
});
|
|
@@ -247920,6 +247943,9 @@ function sourceFileHasDefaultExport(sourceFile) {
|
|
|
247920
247943
|
hasRuntimeDefaultModifier(statement) ||
|
|
247921
247944
|
(ts.isExportDeclaration(statement) && exportsDefaultSpecifier(statement)));
|
|
247922
247945
|
}
|
|
247946
|
+
function isJsonModuleFileName(fileName) {
|
|
247947
|
+
return path.extname(fileName).toLowerCase() === '.json';
|
|
247948
|
+
}
|
|
247923
247949
|
function hasDefaultExport(program, fileName) {
|
|
247924
247950
|
const canonicalFileName = createCanonicalFileName();
|
|
247925
247951
|
const normalizedFileName = canonicalFileName(fileName);
|
|
@@ -248226,7 +248252,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
|
|
|
248226
248252
|
}
|
|
248227
248253
|
return hasSafeRuntimeUsage;
|
|
248228
248254
|
}
|
|
248229
|
-
const rule$
|
|
248255
|
+
const rule$N = createRule({
|
|
248230
248256
|
create(context) {
|
|
248231
248257
|
const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
|
|
248232
248258
|
const checkCycles = context.options[0]?.checkCycles ?? true;
|
|
@@ -248379,7 +248405,8 @@ const rule$M = createRule({
|
|
|
248379
248405
|
: null;
|
|
248380
248406
|
}
|
|
248381
248407
|
function getIndexPathReplacement(moduleSpecifierPath, canonicalResolvedFileName) {
|
|
248382
|
-
if (
|
|
248408
|
+
if (codeFileExtensionRegExp.test(moduleSpecifierPath) ||
|
|
248409
|
+
!isIndexModulePath(moduleSpecifierPath)) {
|
|
248383
248410
|
return null;
|
|
248384
248411
|
}
|
|
248385
248412
|
const parentDirectory = path.posix.dirname(moduleSpecifierPath);
|
|
@@ -248596,7 +248623,8 @@ const rule$M = createRule({
|
|
|
248596
248623
|
const moduleSpecifier = node.source.value;
|
|
248597
248624
|
const resolved = resolveModule(tsProgram, context.filename, moduleSpecifier);
|
|
248598
248625
|
if (!resolved ||
|
|
248599
|
-
(resolved.isExternalLibraryImport && ignoreExternalDefaultImports)
|
|
248626
|
+
(resolved.isExternalLibraryImport && ignoreExternalDefaultImports) ||
|
|
248627
|
+
isJsonModuleFileName(resolved.resolvedFileName)) {
|
|
248600
248628
|
return;
|
|
248601
248629
|
}
|
|
248602
248630
|
const hasResolvedDefaultExport = hasDefaultExport(tsProgram, resolved.resolvedFileName);
|
|
@@ -248687,6 +248715,7 @@ const rule$M = createRule({
|
|
|
248687
248715
|
const resolved = resolveModule(tsProgram, context.filename, moduleSpecifier);
|
|
248688
248716
|
if (!resolved ||
|
|
248689
248717
|
(resolved.isExternalLibraryImport && ignoreExternalDefaultImports) ||
|
|
248718
|
+
isJsonModuleFileName(resolved.resolvedFileName) ||
|
|
248690
248719
|
!hasDefaultExport(tsProgram, resolved.resolvedFileName)) {
|
|
248691
248720
|
return;
|
|
248692
248721
|
}
|
|
@@ -248712,7 +248741,11 @@ const rule$M = createRule({
|
|
|
248712
248741
|
return;
|
|
248713
248742
|
}
|
|
248714
248743
|
const namespaceImport = node.specifiers.find((specifier) => specifier.type === dist$3.AST_NODE_TYPES.ImportNamespaceSpecifier);
|
|
248715
|
-
if (!namespaceImport) {
|
|
248744
|
+
if (!namespaceImport || typeof node.source.value !== 'string') {
|
|
248745
|
+
return;
|
|
248746
|
+
}
|
|
248747
|
+
const resolved = resolveModule(tsProgram, context.filename, node.source.value);
|
|
248748
|
+
if (resolved && isJsonModuleFileName(resolved.resolvedFileName)) {
|
|
248716
248749
|
return;
|
|
248717
248750
|
}
|
|
248718
248751
|
const exportNames = getNamespaceImportExportNames(checker, esTreeNodeToTSNodeMap, node);
|
|
@@ -248944,7 +248977,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
|
|
|
248944
248977
|
? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
|
|
248945
248978
|
: fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
|
|
248946
248979
|
}
|
|
248947
|
-
const rule$
|
|
248980
|
+
const rule$M = createRule({
|
|
248948
248981
|
create(context) {
|
|
248949
248982
|
const { sourceCode } = context;
|
|
248950
248983
|
const program = sourceCode.ast;
|
|
@@ -248993,7 +249026,7 @@ const rule$L = createRule({
|
|
|
248993
249026
|
name: 'injection-token-description',
|
|
248994
249027
|
});
|
|
248995
249028
|
|
|
248996
|
-
const rule$
|
|
249029
|
+
const rule$L = createRule({
|
|
248997
249030
|
create(context) {
|
|
248998
249031
|
const { sourceCode } = context;
|
|
248999
249032
|
const namespaceImports = new Map();
|
|
@@ -249088,7 +249121,7 @@ const DEFAULT_OPTIONS = {
|
|
|
249088
249121
|
importDeclaration: '^@taiga-ui*',
|
|
249089
249122
|
projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
|
|
249090
249123
|
};
|
|
249091
|
-
const rule$
|
|
249124
|
+
const rule$K = createRule({
|
|
249092
249125
|
create(context) {
|
|
249093
249126
|
const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
|
|
249094
249127
|
const hasNonCodeExtension = (source) => {
|
|
@@ -249180,7 +249213,7 @@ const nearestFileUpCache = new Map();
|
|
|
249180
249213
|
const markerCache = new Map();
|
|
249181
249214
|
const indexFileCache = new Map();
|
|
249182
249215
|
const indexExportsCache = new Map();
|
|
249183
|
-
const rule$
|
|
249216
|
+
const rule$J = createRule({
|
|
249184
249217
|
create(context) {
|
|
249185
249218
|
const parserServices = dist$3.ESLintUtils.getParserServices(context);
|
|
249186
249219
|
const program = parserServices.program;
|
|
@@ -249374,13 +249407,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
|
|
|
249374
249407
|
if (!noDuplicateAttributesRule) {
|
|
249375
249408
|
throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
|
|
249376
249409
|
}
|
|
249377
|
-
const rule$
|
|
249410
|
+
const rule$I = createRule({
|
|
249378
249411
|
name: 'no-duplicate-attrs',
|
|
249379
249412
|
rule: noDuplicateAttributesRule,
|
|
249380
249413
|
});
|
|
249381
249414
|
|
|
249382
249415
|
const MESSAGE_ID$c = 'duplicateId';
|
|
249383
|
-
const rule$
|
|
249416
|
+
const rule$H = createRule({
|
|
249384
249417
|
name: 'no-duplicate-id',
|
|
249385
249418
|
rule: {
|
|
249386
249419
|
create(context) {
|
|
@@ -249441,7 +249474,7 @@ function getTrackingKey(node) {
|
|
|
249441
249474
|
? 'link[rel=canonical]'
|
|
249442
249475
|
: null;
|
|
249443
249476
|
}
|
|
249444
|
-
const rule$
|
|
249477
|
+
const rule$G = createRule({
|
|
249445
249478
|
name: 'no-duplicate-in-head',
|
|
249446
249479
|
rule: {
|
|
249447
249480
|
create(context) {
|
|
@@ -249496,6 +249529,133 @@ const rule$F = createRule({
|
|
|
249496
249529
|
},
|
|
249497
249530
|
});
|
|
249498
249531
|
|
|
249532
|
+
const COMPONENT_DECORATORS = new Set(['Component']);
|
|
249533
|
+
const rule$F = createRule({
|
|
249534
|
+
create(context) {
|
|
249535
|
+
const { sourceCode } = context;
|
|
249536
|
+
return {
|
|
249537
|
+
ClassDeclaration(node) {
|
|
249538
|
+
for (const decorator of node?.decorators ?? []) {
|
|
249539
|
+
const metadata = getDecoratorMetadata(decorator, COMPONENT_DECORATORS);
|
|
249540
|
+
if (!metadata) {
|
|
249541
|
+
continue;
|
|
249542
|
+
}
|
|
249543
|
+
const emptyProperties = metadata.properties.filter((property) => property.type === dist$3.AST_NODE_TYPES.Property &&
|
|
249544
|
+
isEmptyStyleMetadata(getObjectPropertyName(property), property, sourceCode));
|
|
249545
|
+
if (emptyProperties.length === 0) {
|
|
249546
|
+
continue;
|
|
249547
|
+
}
|
|
249548
|
+
const [firstEmptyProperty] = emptyProperties;
|
|
249549
|
+
if (!firstEmptyProperty) {
|
|
249550
|
+
continue;
|
|
249551
|
+
}
|
|
249552
|
+
context.report({
|
|
249553
|
+
fix: (fixer) => {
|
|
249554
|
+
const ranges = emptyProperties.map((property) => getPropertyRemovalRange(sourceCode, property));
|
|
249555
|
+
return ranges.some((range) => hasCommentsInRange(sourceCode, range))
|
|
249556
|
+
? null
|
|
249557
|
+
: fixer.replaceTextRange(metadata.range, removeRanges(sourceCode.text.slice(...metadata.range), ranges.map(([start, end]) => [
|
|
249558
|
+
start - metadata.range[0],
|
|
249559
|
+
end - metadata.range[0],
|
|
249560
|
+
])));
|
|
249561
|
+
},
|
|
249562
|
+
messageId: 'noEmptyStyleMetadata',
|
|
249563
|
+
node: firstEmptyProperty,
|
|
249564
|
+
});
|
|
249565
|
+
}
|
|
249566
|
+
},
|
|
249567
|
+
};
|
|
249568
|
+
},
|
|
249569
|
+
meta: {
|
|
249570
|
+
docs: {
|
|
249571
|
+
description: 'Disallow empty `styles`, `styleUrl`, and `styleUrls` metadata in Angular components.',
|
|
249572
|
+
},
|
|
249573
|
+
fixable: 'code',
|
|
249574
|
+
messages: {
|
|
249575
|
+
noEmptyStyleMetadata: 'Empty style metadata should be removed from @Component decorator.',
|
|
249576
|
+
},
|
|
249577
|
+
schema: [],
|
|
249578
|
+
type: 'problem',
|
|
249579
|
+
},
|
|
249580
|
+
name: 'no-empty-style-metadata',
|
|
249581
|
+
});
|
|
249582
|
+
function isEmptyStyleMetadata(name, property, sourceCode) {
|
|
249583
|
+
return (((name === 'styles' || name === 'styleUrl') &&
|
|
249584
|
+
isEmptyStringExpression(property.value)) ||
|
|
249585
|
+
(name === 'styleUrls' &&
|
|
249586
|
+
property.value.type === dist$3.AST_NODE_TYPES.ArrayExpression &&
|
|
249587
|
+
property.value.elements.length === 0 &&
|
|
249588
|
+
sourceCode.getText(property.value).replaceAll(/\s/g, '') === '[]'));
|
|
249589
|
+
}
|
|
249590
|
+
function isEmptyStringExpression(node) {
|
|
249591
|
+
if (node.type === dist$3.AST_NODE_TYPES.Literal) {
|
|
249592
|
+
return node.value === '';
|
|
249593
|
+
}
|
|
249594
|
+
if (node.type !== dist$3.AST_NODE_TYPES.TemplateLiteral || node.expressions.length > 0) {
|
|
249595
|
+
return false;
|
|
249596
|
+
}
|
|
249597
|
+
const [quasi] = node.quasis;
|
|
249598
|
+
return quasi?.value.raw === '';
|
|
249599
|
+
}
|
|
249600
|
+
function getPropertyRemovalRange(sourceCode, property) {
|
|
249601
|
+
const nextToken = sourceCode.getTokenAfter(property);
|
|
249602
|
+
if (nextToken?.value === ',') {
|
|
249603
|
+
return getRangeWithFollowingComma(sourceCode.text, property, nextToken.range);
|
|
249604
|
+
}
|
|
249605
|
+
const previousToken = sourceCode.getTokenBefore(property);
|
|
249606
|
+
return previousToken?.value === ','
|
|
249607
|
+
? [previousToken.range[0], property.range[1]]
|
|
249608
|
+
: getSinglePropertyRange(sourceCode.text, property);
|
|
249609
|
+
}
|
|
249610
|
+
function getRangeWithFollowingComma(text, property, commaRange) {
|
|
249611
|
+
const lineStart = getLineStart(text, property.range[0]);
|
|
249612
|
+
const nextLineStart = getNextLineStart(text, commaRange[1]);
|
|
249613
|
+
return text.slice(lineStart, property.range[0]).trim() === '' &&
|
|
249614
|
+
text.slice(commaRange[1], nextLineStart).trim() === '' &&
|
|
249615
|
+
nextLineStart > commaRange[1]
|
|
249616
|
+
? [lineStart, nextLineStart]
|
|
249617
|
+
: [property.range[0], commaRange[1]];
|
|
249618
|
+
}
|
|
249619
|
+
function getSinglePropertyRange(text, property) {
|
|
249620
|
+
const lineStart = getLineStart(text, property.range[0]);
|
|
249621
|
+
const nextLineStart = getNextLineStart(text, property.range[1]);
|
|
249622
|
+
return text.slice(lineStart, property.range[0]).trim() === '' &&
|
|
249623
|
+
text.slice(property.range[1], nextLineStart).trim() === '' &&
|
|
249624
|
+
nextLineStart > property.range[1]
|
|
249625
|
+
? [lineStart, nextLineStart]
|
|
249626
|
+
: [property.range[0], property.range[1]];
|
|
249627
|
+
}
|
|
249628
|
+
function getLineStart(text, index) {
|
|
249629
|
+
return text.lastIndexOf('\n', index - 1) + 1;
|
|
249630
|
+
}
|
|
249631
|
+
function getNextLineStart(text, index) {
|
|
249632
|
+
const lineEnd = text.indexOf('\n', index);
|
|
249633
|
+
return lineEnd === -1 ? index : lineEnd + 1;
|
|
249634
|
+
}
|
|
249635
|
+
function hasCommentsInRange(sourceCode, [start, end]) {
|
|
249636
|
+
return sourceCode
|
|
249637
|
+
.getAllComments()
|
|
249638
|
+
.some((comment) => comment.range[0] >= start && comment.range[1] <= end);
|
|
249639
|
+
}
|
|
249640
|
+
function removeRanges(text, ranges) {
|
|
249641
|
+
return mergeRanges(ranges)
|
|
249642
|
+
.sort((left, right) => right[0] - left[0])
|
|
249643
|
+
.reduce((result, [start, end]) => `${result.slice(0, start)}${result.slice(end)}`, text);
|
|
249644
|
+
}
|
|
249645
|
+
function mergeRanges(ranges) {
|
|
249646
|
+
const sorted = [...ranges].sort((left, right) => left[0] - right[0]);
|
|
249647
|
+
const merged = [];
|
|
249648
|
+
for (const range of sorted) {
|
|
249649
|
+
const last = merged[merged.length - 1];
|
|
249650
|
+
if (!last || range[0] > last[1]) {
|
|
249651
|
+
merged.push([...range]);
|
|
249652
|
+
continue;
|
|
249653
|
+
}
|
|
249654
|
+
last[1] = Math.max(last[1], range[1]);
|
|
249655
|
+
}
|
|
249656
|
+
return merged;
|
|
249657
|
+
}
|
|
249658
|
+
|
|
249499
249659
|
function isFunctionLike(node) {
|
|
249500
249660
|
return (node.type === dist$3.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
249501
249661
|
node.type === dist$3.AST_NODE_TYPES.FunctionDeclaration ||
|
|
@@ -251231,6 +251391,34 @@ function getStatementIndent$1(statement, sourceText) {
|
|
|
251231
251391
|
const before = sourceText.slice(lineStart, start);
|
|
251232
251392
|
return /^\s*$/.test(before) ? before : '';
|
|
251233
251393
|
}
|
|
251394
|
+
function isAstNode(value) {
|
|
251395
|
+
if (!value || typeof value !== 'object' || !('type' in value)) {
|
|
251396
|
+
return false;
|
|
251397
|
+
}
|
|
251398
|
+
const { type } = value;
|
|
251399
|
+
return typeof type === 'string';
|
|
251400
|
+
}
|
|
251401
|
+
function getParent(node) {
|
|
251402
|
+
const maybeNode = node;
|
|
251403
|
+
if (!maybeNode || typeof maybeNode !== 'object' || !('parent' in maybeNode)) {
|
|
251404
|
+
return null;
|
|
251405
|
+
}
|
|
251406
|
+
const { parent } = maybeNode;
|
|
251407
|
+
return isAstNode(parent) ? parent : null;
|
|
251408
|
+
}
|
|
251409
|
+
function isOptionalMemberReceiver(call) {
|
|
251410
|
+
let current = call;
|
|
251411
|
+
let parent = getParent(current);
|
|
251412
|
+
while (parent?.type === dist$3.AST_NODE_TYPES.TSAsExpression ||
|
|
251413
|
+
parent?.type === dist$3.AST_NODE_TYPES.TSNonNullExpression ||
|
|
251414
|
+
parent?.type === dist$3.AST_NODE_TYPES.TSTypeAssertion) {
|
|
251415
|
+
current = parent;
|
|
251416
|
+
parent = getParent(current);
|
|
251417
|
+
}
|
|
251418
|
+
return (parent?.type === dist$3.AST_NODE_TYPES.MemberExpression &&
|
|
251419
|
+
parent.object === current &&
|
|
251420
|
+
parent.optional);
|
|
251421
|
+
}
|
|
251234
251422
|
const rule$t = createRule({
|
|
251235
251423
|
create(context) {
|
|
251236
251424
|
const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
|
|
@@ -251247,6 +251435,7 @@ const rule$t = createRule({
|
|
|
251247
251435
|
return false;
|
|
251248
251436
|
}
|
|
251249
251437
|
if (child.type === dist$3.AST_NODE_TYPES.CallExpression &&
|
|
251438
|
+
!isOptionalMemberReceiver(child) &&
|
|
251250
251439
|
isSignalReadCall(child, checker, signalNodeMap) &&
|
|
251251
251440
|
isNullableCallType(child, checker, signalNodeMap)) {
|
|
251252
251441
|
const text = sourceCode.getText(child);
|
|
@@ -252723,6 +252912,18 @@ const rule$m = createRule({
|
|
|
252723
252912
|
});
|
|
252724
252913
|
|
|
252725
252914
|
const MAX_INLINE_CONDITIONAL_RETURN_LENGTH = 90;
|
|
252915
|
+
const BOOLEAN_BINARY_OPERATORS = new Set([
|
|
252916
|
+
'!=',
|
|
252917
|
+
'!==',
|
|
252918
|
+
'<',
|
|
252919
|
+
'<=',
|
|
252920
|
+
'==',
|
|
252921
|
+
'===',
|
|
252922
|
+
'>',
|
|
252923
|
+
'>=',
|
|
252924
|
+
'in',
|
|
252925
|
+
'instanceof',
|
|
252926
|
+
]);
|
|
252726
252927
|
function getReturnStatement(statement) {
|
|
252727
252928
|
if (statement.type === dist$3.AST_NODE_TYPES.ReturnStatement) {
|
|
252728
252929
|
return statement;
|
|
@@ -252763,6 +252964,52 @@ function isConditionalExpression(node) {
|
|
|
252763
252964
|
return (node !== null &&
|
|
252764
252965
|
unwrapTypeAndParentheses(node).type === dist$3.AST_NODE_TYPES.ConditionalExpression);
|
|
252765
252966
|
}
|
|
252967
|
+
function isBooleanLiteral(node) {
|
|
252968
|
+
return node.type === dist$3.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
|
|
252969
|
+
}
|
|
252970
|
+
function getBooleanLiteralValue(node) {
|
|
252971
|
+
return isBooleanLiteral(node) ? node.value : null;
|
|
252972
|
+
}
|
|
252973
|
+
function isKnownBooleanExpression(node) {
|
|
252974
|
+
const unwrapped = unwrapTypeAndParentheses(node);
|
|
252975
|
+
switch (unwrapped.type) {
|
|
252976
|
+
case dist$3.AST_NODE_TYPES.BinaryExpression:
|
|
252977
|
+
return BOOLEAN_BINARY_OPERATORS.has(unwrapped.operator);
|
|
252978
|
+
case dist$3.AST_NODE_TYPES.Literal:
|
|
252979
|
+
return typeof unwrapped.value === 'boolean';
|
|
252980
|
+
case dist$3.AST_NODE_TYPES.LogicalExpression:
|
|
252981
|
+
return (isKnownBooleanExpression(unwrapped.left) &&
|
|
252982
|
+
isKnownBooleanExpression(unwrapped.right));
|
|
252983
|
+
case dist$3.AST_NODE_TYPES.UnaryExpression:
|
|
252984
|
+
return unwrapped.operator === '!';
|
|
252985
|
+
default:
|
|
252986
|
+
return false;
|
|
252987
|
+
}
|
|
252988
|
+
}
|
|
252989
|
+
function isBooleanType(type) {
|
|
252990
|
+
const types = type.isUnion() ? type.types : [type];
|
|
252991
|
+
return types.every((part) => !!(part.flags & ts.TypeFlags.BooleanLike));
|
|
252992
|
+
}
|
|
252993
|
+
function getBooleanTestReturnStrategy(test, consequentExpression, alternateExpression, isTypeCheckedBooleanExpression) {
|
|
252994
|
+
const consequentValue = getBooleanLiteralValue(consequentExpression);
|
|
252995
|
+
const alternateValue = getBooleanLiteralValue(alternateExpression);
|
|
252996
|
+
if (consequentValue === false && alternateValue === true) {
|
|
252997
|
+
return unwrapTypeAndParentheses(test).type === dist$3.AST_NODE_TYPES.LogicalExpression
|
|
252998
|
+
? 'skip'
|
|
252999
|
+
: 'negate';
|
|
253000
|
+
}
|
|
253001
|
+
if (consequentValue !== true || alternateValue !== false) {
|
|
253002
|
+
return 'skip';
|
|
253003
|
+
}
|
|
253004
|
+
return isKnownBooleanExpression(test) || isTypeCheckedBooleanExpression(test)
|
|
253005
|
+
? 'direct'
|
|
253006
|
+
: 'coerce';
|
|
253007
|
+
}
|
|
253008
|
+
function shouldSkipBooleanReturn(test, consequentExpression, alternateExpression) {
|
|
253009
|
+
return (getBooleanLiteralValue(consequentExpression) === false &&
|
|
253010
|
+
getBooleanLiteralValue(alternateExpression) === true &&
|
|
253011
|
+
unwrapTypeAndParentheses(test).type === dist$3.AST_NODE_TYPES.LogicalExpression);
|
|
253012
|
+
}
|
|
252766
253013
|
function needsParenthesesInConditionalTest(node) {
|
|
252767
253014
|
if (getParenthesizedInner(node)) {
|
|
252768
253015
|
return false;
|
|
@@ -252800,6 +253047,27 @@ function needsParenthesesInConditionalBranch(node) {
|
|
|
252800
253047
|
return false;
|
|
252801
253048
|
}
|
|
252802
253049
|
}
|
|
253050
|
+
function needsParenthesesInBooleanCoercion(node) {
|
|
253051
|
+
if (getParenthesizedInner(node)) {
|
|
253052
|
+
return false;
|
|
253053
|
+
}
|
|
253054
|
+
switch (node.type) {
|
|
253055
|
+
case dist$3.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
253056
|
+
case dist$3.AST_NODE_TYPES.AssignmentExpression:
|
|
253057
|
+
case dist$3.AST_NODE_TYPES.BinaryExpression:
|
|
253058
|
+
case dist$3.AST_NODE_TYPES.ConditionalExpression:
|
|
253059
|
+
case dist$3.AST_NODE_TYPES.LogicalExpression:
|
|
253060
|
+
case dist$3.AST_NODE_TYPES.ObjectExpression:
|
|
253061
|
+
case dist$3.AST_NODE_TYPES.SequenceExpression:
|
|
253062
|
+
case dist$3.AST_NODE_TYPES.TSAsExpression:
|
|
253063
|
+
case dist$3.AST_NODE_TYPES.TSSatisfiesExpression:
|
|
253064
|
+
case dist$3.AST_NODE_TYPES.TSTypeAssertion:
|
|
253065
|
+
case dist$3.AST_NODE_TYPES.YieldExpression:
|
|
253066
|
+
return true;
|
|
253067
|
+
default:
|
|
253068
|
+
return false;
|
|
253069
|
+
}
|
|
253070
|
+
}
|
|
252803
253071
|
function renderExpression(node, sourceCode, needsParentheses) {
|
|
252804
253072
|
const text = sourceCode.getText(node);
|
|
252805
253073
|
return needsParentheses(node) ? `(${text})` : text;
|
|
@@ -252823,9 +253091,58 @@ function renderConditionalReturn(ifStatement, consequentExpression, alternateExp
|
|
|
252823
253091
|
const branchIndent = `${indent} `;
|
|
252824
253092
|
return `return ${test}\n${branchIndent}? ${consequent}\n${branchIndent}: ${alternate};`;
|
|
252825
253093
|
}
|
|
253094
|
+
function renderBooleanTestReturn(ifStatement, sourceCode, strategy) {
|
|
253095
|
+
const test = sourceCode.getText(ifStatement.test);
|
|
253096
|
+
if (strategy === 'negate') {
|
|
253097
|
+
if (!test.includes('\n')) {
|
|
253098
|
+
const renderedTest = needsParenthesesInBooleanCoercion(ifStatement.test)
|
|
253099
|
+
? `(${test})`
|
|
253100
|
+
: test;
|
|
253101
|
+
return `return !${renderedTest};`;
|
|
253102
|
+
}
|
|
253103
|
+
const indent = getStatementIndent(ifStatement, sourceCode);
|
|
253104
|
+
return `return !(\n${indent} ${test}\n${indent});`;
|
|
253105
|
+
}
|
|
253106
|
+
if (strategy === 'coerce') {
|
|
253107
|
+
if (!test.includes('\n')) {
|
|
253108
|
+
const renderedTest = needsParenthesesInBooleanCoercion(ifStatement.test)
|
|
253109
|
+
? `(${test})`
|
|
253110
|
+
: test;
|
|
253111
|
+
return `return !!${renderedTest};`;
|
|
253112
|
+
}
|
|
253113
|
+
const indent = getStatementIndent(ifStatement, sourceCode);
|
|
253114
|
+
return `return !!(\n${indent} ${test}\n${indent});`;
|
|
253115
|
+
}
|
|
253116
|
+
if (!test.includes('\n')) {
|
|
253117
|
+
return `return ${test};`;
|
|
253118
|
+
}
|
|
253119
|
+
const indent = getStatementIndent(ifStatement, sourceCode);
|
|
253120
|
+
return `return (\n${indent} ${test}\n${indent});`;
|
|
253121
|
+
}
|
|
252826
253122
|
const rule$l = createRule({
|
|
252827
253123
|
create(context) {
|
|
252828
253124
|
const { sourceCode } = context;
|
|
253125
|
+
let parserServices = null;
|
|
253126
|
+
let checker = null;
|
|
253127
|
+
try {
|
|
253128
|
+
parserServices = dist$3.ESLintUtils.getParserServices(context);
|
|
253129
|
+
checker = parserServices.program.getTypeChecker();
|
|
253130
|
+
}
|
|
253131
|
+
catch {
|
|
253132
|
+
// Type checking is optional; syntactic boolean detection still works.
|
|
253133
|
+
}
|
|
253134
|
+
function isTypeCheckedBooleanExpression(node) {
|
|
253135
|
+
if (!parserServices || !checker) {
|
|
253136
|
+
return false;
|
|
253137
|
+
}
|
|
253138
|
+
try {
|
|
253139
|
+
const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
|
|
253140
|
+
return isBooleanType(checker.getTypeAtLocation(tsNode));
|
|
253141
|
+
}
|
|
253142
|
+
catch {
|
|
253143
|
+
return false;
|
|
253144
|
+
}
|
|
253145
|
+
}
|
|
252829
253146
|
function checkBody(statements) {
|
|
252830
253147
|
for (const [index, statement] of statements.entries()) {
|
|
252831
253148
|
if (statement.type !== dist$3.AST_NODE_TYPES.IfStatement) {
|
|
@@ -252844,6 +253161,7 @@ const rule$l = createRule({
|
|
|
252844
253161
|
!finalArgument ||
|
|
252845
253162
|
isConditionalExpression(consequentArgument) ||
|
|
252846
253163
|
isConditionalExpression(finalArgument) ||
|
|
253164
|
+
shouldSkipBooleanReturn(statement.test, consequentArgument, finalArgument) ||
|
|
252847
253165
|
!hasOnlyWhitespaceBetween(sourceCode, statement, finalReturn) ||
|
|
252848
253166
|
sourceCode.getCommentsInside(statement).length > 0 ||
|
|
252849
253167
|
sourceCode.getCommentsInside(finalReturn).length > 0) {
|
|
@@ -252851,7 +253169,10 @@ const rule$l = createRule({
|
|
|
252851
253169
|
}
|
|
252852
253170
|
context.report({
|
|
252853
253171
|
fix(fixer) {
|
|
252854
|
-
const
|
|
253172
|
+
const booleanTestReturnStrategy = getBooleanTestReturnStrategy(statement.test, consequentArgument, finalArgument, isTypeCheckedBooleanExpression);
|
|
253173
|
+
const replacement = booleanTestReturnStrategy === 'skip'
|
|
253174
|
+
? renderConditionalReturn(statement, consequentArgument, finalArgument, sourceCode)
|
|
253175
|
+
: renderBooleanTestReturn(statement, sourceCode, booleanTestReturnStrategy);
|
|
252855
253176
|
return fixer.replaceTextRange([statement.range[0], finalReturn.range[1]], replacement);
|
|
252856
253177
|
},
|
|
252857
253178
|
messageId: 'preferConditionalReturn',
|
|
@@ -253819,10 +254140,17 @@ function isArray(node) {
|
|
|
253819
254140
|
}
|
|
253820
254141
|
|
|
253821
254142
|
function isImportsArrayProperty(property) {
|
|
253822
|
-
|
|
253823
|
-
|
|
254143
|
+
if (property?.type !== dist$3.AST_NODE_TYPES.Property) {
|
|
254144
|
+
return false;
|
|
254145
|
+
}
|
|
254146
|
+
const hasIdentifierKey = property.key.type === dist$3.AST_NODE_TYPES.Identifier &&
|
|
253824
254147
|
property.key.name === 'imports';
|
|
253825
|
-
return
|
|
254148
|
+
return hasIdentifierKey && isArray(property.value);
|
|
254149
|
+
}
|
|
254150
|
+
|
|
254151
|
+
function getImportsArray(meta) {
|
|
254152
|
+
const property = meta.properties.find(isImportsArrayProperty);
|
|
254153
|
+
return property?.value ?? null;
|
|
253826
254154
|
}
|
|
253827
254155
|
|
|
253828
254156
|
function getImportedName$1(spec) {
|
|
@@ -253843,28 +254171,19 @@ const DEFAULT_EXCEPTIONS = [
|
|
|
253843
254171
|
const rule$9 = createRule({
|
|
253844
254172
|
create(context, [{ decorators = DEFAULT_DECORATORS, exceptions = DEFAULT_EXCEPTIONS }]) {
|
|
253845
254173
|
const sourceCode = context.getSourceCode();
|
|
254174
|
+
const allowedDecorators = new Set(decorators);
|
|
253846
254175
|
const importedFromTaiga = {};
|
|
253847
|
-
const decoratorSelector = `Decorator[expression.callee.name=/^(${decorators.join('|')})$/]`;
|
|
253848
254176
|
return {
|
|
253849
|
-
|
|
253850
|
-
const
|
|
253851
|
-
|
|
253852
|
-
expression.arguments.length === 0;
|
|
253853
|
-
if (isInvalidExpression) {
|
|
254177
|
+
Decorator(decorator) {
|
|
254178
|
+
const metadata = getDecoratorMetadata(decorator, allowedDecorators);
|
|
254179
|
+
if (!metadata) {
|
|
253854
254180
|
return;
|
|
253855
254181
|
}
|
|
253856
|
-
const
|
|
253857
|
-
|
|
253858
|
-
if (isNotObject) {
|
|
254182
|
+
const importsArray = getImportsArray(metadata);
|
|
254183
|
+
if (!importsArray) {
|
|
253859
254184
|
return;
|
|
253860
254185
|
}
|
|
253861
|
-
const
|
|
253862
|
-
.filter((literal) => literal.type === dist$3.AST_NODE_TYPES.Property)
|
|
253863
|
-
.find((literal) => isImportsArrayProperty(literal));
|
|
253864
|
-
if (!importsProperty) {
|
|
253865
|
-
return;
|
|
253866
|
-
}
|
|
253867
|
-
const imports = importsProperty.value.elements.filter((el) => {
|
|
254186
|
+
const imports = importsArray.elements.filter((el) => {
|
|
253868
254187
|
const isIdentifier = el?.type === dist$3.AST_NODE_TYPES.Identifier;
|
|
253869
254188
|
return Boolean(el && isIdentifier);
|
|
253870
254189
|
});
|
|
@@ -254275,14 +254594,6 @@ const rule$7 = createRule({
|
|
|
254275
254594
|
name: 'single-line-variable-spacing',
|
|
254276
254595
|
});
|
|
254277
254596
|
|
|
254278
|
-
function getImportsArray(meta) {
|
|
254279
|
-
const property = meta.properties.find((literal) => literal.type === dist$2.AST_NODE_TYPES.Property &&
|
|
254280
|
-
literal.key.type === dist$2.AST_NODE_TYPES.Identifier &&
|
|
254281
|
-
literal.key.name === 'imports' &&
|
|
254282
|
-
isArray(literal.value));
|
|
254283
|
-
return property ? property.value : null;
|
|
254284
|
-
}
|
|
254285
|
-
|
|
254286
254597
|
function isSpread(node) {
|
|
254287
254598
|
return node.type === dist$2.AST_NODE_TYPES.SpreadElement;
|
|
254288
254599
|
}
|
|
@@ -254322,11 +254633,12 @@ function nameOf(node, source) {
|
|
|
254322
254633
|
return source.getText(node);
|
|
254323
254634
|
}
|
|
254324
254635
|
|
|
254636
|
+
const IMPORT_NAME_COLLATOR = new Intl.Collator('en', { numeric: true });
|
|
254325
254637
|
/**
|
|
254326
|
-
* Sorts Angular standalone import elements into a deterministic,
|
|
254638
|
+
* Sorts Angular standalone import elements into a deterministic, natural order.
|
|
254327
254639
|
*
|
|
254328
254640
|
* The sorting rules:
|
|
254329
|
-
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted
|
|
254641
|
+
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted naturally.
|
|
254330
254642
|
* 2. Spread elements (e.g. `...A`) are sorted separately and placed after regular ones.
|
|
254331
254643
|
* 3. Sorting is based on the string value returned by `nameOf()`.
|
|
254332
254644
|
*
|
|
@@ -254345,10 +254657,13 @@ function nameOf(node, source) {
|
|
|
254345
254657
|
function getSortedNames(elements, source) {
|
|
254346
254658
|
const regular = elements.filter((e) => !isSpread(e));
|
|
254347
254659
|
const spreads = elements.filter((e) => isSpread(e));
|
|
254348
|
-
const sortedRegular = [...regular].sort((a, b) => nameOf(a, source)
|
|
254349
|
-
const sortedSpreads = [...spreads].sort((a, b) => nameOf(a.argument, source)
|
|
254660
|
+
const sortedRegular = [...regular].sort((a, b) => compareImportNames(nameOf(a, source), nameOf(b, source)));
|
|
254661
|
+
const sortedSpreads = [...spreads].sort((a, b) => compareImportNames(nameOf(a.argument, source), nameOf(b.argument, source)));
|
|
254350
254662
|
return [...sortedRegular, ...sortedSpreads].map((n) => nameOf(n, source));
|
|
254351
254663
|
}
|
|
254664
|
+
function compareImportNames(x, y) {
|
|
254665
|
+
return IMPORT_NAME_COLLATOR.compare(x, y);
|
|
254666
|
+
}
|
|
254352
254667
|
|
|
254353
254668
|
const rule$6 = createRule({
|
|
254354
254669
|
create(context, [options]) {
|
|
@@ -255277,21 +255592,22 @@ const plugin = {
|
|
|
255277
255592
|
},
|
|
255278
255593
|
rules: {
|
|
255279
255594
|
'array-as-const': rule$5,
|
|
255280
|
-
'attrs-newline': rule$
|
|
255595
|
+
'attrs-newline': rule$S,
|
|
255281
255596
|
'class-property-naming': rule$4,
|
|
255282
|
-
'decorator-key-sort': rule$
|
|
255283
|
-
'element-newline': rule$
|
|
255597
|
+
'decorator-key-sort': rule$R,
|
|
255598
|
+
'element-newline': rule$Q,
|
|
255284
255599
|
'flat-exports': rule$3,
|
|
255285
|
-
'host-attributes-sort': rule$
|
|
255286
|
-
'html-logical-properties': rule$
|
|
255287
|
-
'import-integrity': rule$
|
|
255288
|
-
'injection-token-description': rule$
|
|
255289
|
-
'no-commonjs-import-patterns': rule$
|
|
255290
|
-
'no-deep-imports': rule$
|
|
255291
|
-
'no-deep-imports-to-indexed-packages': rule$
|
|
255292
|
-
'no-duplicate-attrs': rule$
|
|
255293
|
-
'no-duplicate-id': rule$
|
|
255294
|
-
'no-duplicate-in-head': rule$
|
|
255600
|
+
'host-attributes-sort': rule$P,
|
|
255601
|
+
'html-logical-properties': rule$O,
|
|
255602
|
+
'import-integrity': rule$N,
|
|
255603
|
+
'injection-token-description': rule$M,
|
|
255604
|
+
'no-commonjs-import-patterns': rule$L,
|
|
255605
|
+
'no-deep-imports': rule$K,
|
|
255606
|
+
'no-deep-imports-to-indexed-packages': rule$J,
|
|
255607
|
+
'no-duplicate-attrs': rule$I,
|
|
255608
|
+
'no-duplicate-id': rule$H,
|
|
255609
|
+
'no-duplicate-in-head': rule$G,
|
|
255610
|
+
'no-empty-style-metadata': rule$F,
|
|
255295
255611
|
'no-fully-untracked-effect': rule$E,
|
|
255296
255612
|
'no-href-with-router-link': rule$D,
|
|
255297
255613
|
'no-implicit-public': rule$C,
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const rule:
|
|
1
|
+
type Options = [Record<string, readonly string[]>];
|
|
2
|
+
export declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"incorrectOrder", Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
3
3
|
name: string;
|
|
4
4
|
};
|
|
5
5
|
export default rule;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const rule:
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const rule: ESLintUtils.RuleModule<"preferConditionalReturn", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
3
|
name: string;
|
|
4
4
|
};
|
|
5
5
|
export default rule;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export interface DecoratorMetadataWithName {
|
|
3
|
+
readonly expression: TSESTree.CallExpression;
|
|
4
|
+
readonly metadata: TSESTree.ObjectExpression;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Extracts the metadata object from a class decorator such as
|
|
4
9
|
* `@Component()`, `@Directive()`, `@NgModule()`, or `@Pipe()`.
|
|
@@ -15,7 +20,7 @@ import { type TSESTree } from '@typescript-eslint/utils';
|
|
|
15
20
|
* class MyCmp {}
|
|
16
21
|
*
|
|
17
22
|
* // In the AST for @Component(...)
|
|
18
|
-
* getDecoratorMetadata(decorator, allowed)
|
|
23
|
+
* getDecoratorMetadata(decorator, allowed) returns
|
|
19
24
|
* ObjectExpression({ selector: ..., imports: ... })
|
|
20
25
|
*
|
|
21
26
|
* @param decorator - The decorator node attached to a class declaration.
|
|
@@ -25,4 +30,5 @@ import { type TSESTree } from '@typescript-eslint/utils';
|
|
|
25
30
|
* @returns The metadata `ObjectExpression` if present and valid,
|
|
26
31
|
* otherwise `null`.
|
|
27
32
|
*/
|
|
28
|
-
export declare function getDecoratorMetadata(decorator: TSESTree.Decorator, allowedNames:
|
|
33
|
+
export declare function getDecoratorMetadata(decorator: TSESTree.Decorator, allowedNames: ReadonlySet<string>): TSESTree.ObjectExpression | null;
|
|
34
|
+
export declare function getDecoratorMetadataWithName(decorator: TSESTree.Decorator, allowedNames: ReadonlySet<string>): DecoratorMetadataWithName | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
export declare function isImportsArrayProperty(property?: TSESTree.
|
|
2
|
+
export declare function isImportsArrayProperty(property?: TSESTree.ObjectExpression['properties'][number]): property is TSESTree.Property & {
|
|
3
3
|
value: TSESTree.ArrayExpression;
|
|
4
4
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
2
|
/**
|
|
3
|
-
* Sorts Angular standalone import elements into a deterministic,
|
|
3
|
+
* Sorts Angular standalone import elements into a deterministic, natural order.
|
|
4
4
|
*
|
|
5
5
|
* The sorting rules:
|
|
6
|
-
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted
|
|
6
|
+
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted naturally.
|
|
7
7
|
* 2. Spread elements (e.g. `...A`) are sorted separately and placed after regular ones.
|
|
8
8
|
* 3. Sorting is based on the string value returned by `nameOf()`.
|
|
9
9
|
*
|