@taiga-ui/eslint-plugin-experience-next 0.507.0 → 0.508.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 +23 -0
- package/index.d.ts +4 -1
- package/index.esm.js +327 -183
- 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/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 { ... }` | ✅ | 🔧 | |
|
|
@@ -127,6 +128,28 @@ from third-party plugins. The exact severities and file globs live in
|
|
|
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
|
|
|
131
|
+
## no-empty-style-metadata
|
|
132
|
+
|
|
133
|
+
Disallows empty Angular component style metadata. The rule reports empty string and empty template literal values for
|
|
134
|
+
`styles` and `styleUrl`, plus `styleUrls: []`, because they do not add component styles and can be safely removed.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
// ❌ error
|
|
138
|
+
@Component({
|
|
139
|
+
selector: 'app-root',
|
|
140
|
+
templateUrl: './app.component.html',
|
|
141
|
+
styles: ``,
|
|
142
|
+
styleUrl: '',
|
|
143
|
+
styleUrls: [],
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// ✅ after autofix
|
|
147
|
+
@Component({
|
|
148
|
+
selector: 'app-root',
|
|
149
|
+
templateUrl: './app.component.html',
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
130
153
|
## prefer-conditional-return
|
|
131
154
|
|
|
132
155
|
Prefer a single conditional return when an `if` statement returns one expression and the immediately following statement
|
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
|
@@ -1201,6 +1201,7 @@ var recommended = defineConfig([
|
|
|
1201
1201
|
},
|
|
1202
1202
|
],
|
|
1203
1203
|
'@taiga-ui/experience-next/no-deep-imports-to-indexed-packages': 'error',
|
|
1204
|
+
'@taiga-ui/experience-next/no-empty-style-metadata': 'error',
|
|
1204
1205
|
'@taiga-ui/experience-next/no-fully-untracked-effect': 'error',
|
|
1205
1206
|
'@taiga-ui/experience-next/no-implicit-public': 'error',
|
|
1206
1207
|
'@taiga-ui/experience-next/no-import-assertions': 'error',
|
|
@@ -46222,7 +46223,7 @@ function buildMultilineStartTag(node, sourceText) {
|
|
|
46222
46223
|
closing,
|
|
46223
46224
|
].join('\n');
|
|
46224
46225
|
}
|
|
46225
|
-
const rule$
|
|
46226
|
+
const rule$S = createRule({
|
|
46226
46227
|
name: 'attrs-newline',
|
|
46227
46228
|
rule: {
|
|
46228
46229
|
create(context) {
|
|
@@ -46308,54 +46309,151 @@ const rule$R = createRule({
|
|
|
46308
46309
|
},
|
|
46309
46310
|
});
|
|
46310
46311
|
|
|
46312
|
+
function isObject(node) {
|
|
46313
|
+
return node?.type === dist$2.AST_NODE_TYPES.ObjectExpression;
|
|
46314
|
+
}
|
|
46315
|
+
|
|
46316
|
+
/**
|
|
46317
|
+
* Extracts the metadata object from a class decorator such as
|
|
46318
|
+
* `@Component()`, `@Directive()`, `@NgModule()`, or `@Pipe()`.
|
|
46319
|
+
*
|
|
46320
|
+
* Returns the first argument of the decorator call *if and only if*
|
|
46321
|
+
* it is an `ObjectExpression`.
|
|
46322
|
+
*
|
|
46323
|
+
* @example
|
|
46324
|
+
* // Given:
|
|
46325
|
+
* @Component({
|
|
46326
|
+
* selector: 'x',
|
|
46327
|
+
* imports: [A, B],
|
|
46328
|
+
* })
|
|
46329
|
+
* class MyCmp {}
|
|
46330
|
+
*
|
|
46331
|
+
* // In the AST for @Component(...)
|
|
46332
|
+
* getDecoratorMetadata(decorator, allowed) returns
|
|
46333
|
+
* ObjectExpression({ selector: ..., imports: ... })
|
|
46334
|
+
*
|
|
46335
|
+
* @param decorator - The decorator node attached to a class declaration.
|
|
46336
|
+
* @param allowedNames - A set of decorator names to consider
|
|
46337
|
+
* (e.g., Component, Directive, NgModule, Pipe).
|
|
46338
|
+
*
|
|
46339
|
+
* @returns The metadata `ObjectExpression` if present and valid,
|
|
46340
|
+
* otherwise `null`.
|
|
46341
|
+
*/
|
|
46342
|
+
function getDecoratorMetadata(decorator, allowedNames) {
|
|
46343
|
+
return getDecoratorMetadataWithName(decorator, allowedNames)?.metadata ?? null;
|
|
46344
|
+
}
|
|
46345
|
+
function getDecoratorMetadataWithName(decorator, allowedNames) {
|
|
46346
|
+
const expr = decorator.expression;
|
|
46347
|
+
if (expr.type !== dist$2.AST_NODE_TYPES.CallExpression) {
|
|
46348
|
+
return null;
|
|
46349
|
+
}
|
|
46350
|
+
const callee = expr.callee;
|
|
46351
|
+
if (callee.type !== dist$2.AST_NODE_TYPES.Identifier || !allowedNames.has(callee.name)) {
|
|
46352
|
+
return null;
|
|
46353
|
+
}
|
|
46354
|
+
const arg = expr.arguments[0];
|
|
46355
|
+
return isObject(arg) ? { expression: expr, metadata: arg, name: callee.name } : null;
|
|
46356
|
+
}
|
|
46357
|
+
|
|
46358
|
+
function isStringLiteral(node) {
|
|
46359
|
+
return node?.type === dist$3.AST_NODE_TYPES.Literal && typeof node.value === 'string';
|
|
46360
|
+
}
|
|
46361
|
+
function isStaticTemplateLiteral(node) {
|
|
46362
|
+
return (node?.type === dist$3.AST_NODE_TYPES.TemplateLiteral &&
|
|
46363
|
+
node.expressions.length === 0 &&
|
|
46364
|
+
node.quasis.length === 1);
|
|
46365
|
+
}
|
|
46366
|
+
function getStaticStringValue(node) {
|
|
46367
|
+
if (isStringLiteral(node)) {
|
|
46368
|
+
return node.value;
|
|
46369
|
+
}
|
|
46370
|
+
return isStaticTemplateLiteral(node)
|
|
46371
|
+
? (node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? '')
|
|
46372
|
+
: null;
|
|
46373
|
+
}
|
|
46374
|
+
function isEmptyStaticString(node) {
|
|
46375
|
+
return getStaticStringValue(node) === '';
|
|
46376
|
+
}
|
|
46377
|
+
|
|
46378
|
+
function getStaticPropertyName(key) {
|
|
46379
|
+
if (key.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46380
|
+
return key.name;
|
|
46381
|
+
}
|
|
46382
|
+
return key.type === dist$3.AST_NODE_TYPES.Literal &&
|
|
46383
|
+
(typeof key.value === 'string' || typeof key.value === 'number')
|
|
46384
|
+
? String(key.value)
|
|
46385
|
+
: getStaticStringValue(key);
|
|
46386
|
+
}
|
|
46387
|
+
function getObjectPropertyName(node) {
|
|
46388
|
+
return node.computed ? null : getStaticPropertyName(node.key);
|
|
46389
|
+
}
|
|
46390
|
+
function getMemberExpressionPropertyName(node) {
|
|
46391
|
+
if (!node.computed && node.property.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
46392
|
+
return node.property.name;
|
|
46393
|
+
}
|
|
46394
|
+
return node.computed ? getStaticStringValue(node.property) : null;
|
|
46395
|
+
}
|
|
46396
|
+
function getClassMemberName(member) {
|
|
46397
|
+
return member.key.type === dist$3.AST_NODE_TYPES.PrivateIdentifier
|
|
46398
|
+
? null
|
|
46399
|
+
: getStaticPropertyName(member.key);
|
|
46400
|
+
}
|
|
46401
|
+
|
|
46311
46402
|
function sameOrder(a, b) {
|
|
46312
46403
|
return a.length === b.length && a.every((value, index) => value === b[index]);
|
|
46313
46404
|
}
|
|
46314
46405
|
|
|
46315
|
-
const
|
|
46316
|
-
create(context) {
|
|
46317
|
-
const
|
|
46406
|
+
const rule$R = createRule({
|
|
46407
|
+
create(context, [order]) {
|
|
46408
|
+
const decorators = new Set(Object.keys(order));
|
|
46318
46409
|
return {
|
|
46319
46410
|
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
|
-
}
|
|
46411
|
+
for (const decorator of node?.decorators ?? []) {
|
|
46412
|
+
const metadata = getDecoratorMetadataWithName(decorator, decorators);
|
|
46413
|
+
if (!metadata) {
|
|
46414
|
+
continue;
|
|
46415
|
+
}
|
|
46416
|
+
const orderList = order[metadata.name] ?? [];
|
|
46417
|
+
const properties = getDecoratorProperties(metadata.metadata);
|
|
46418
|
+
if (!properties) {
|
|
46419
|
+
continue;
|
|
46420
|
+
}
|
|
46421
|
+
const current = properties.map(({ name }) => name);
|
|
46422
|
+
const correct = getCorrectOrderRelative(orderList, current);
|
|
46423
|
+
const sortableCurrent = current.filter((item) => correct.includes(item));
|
|
46424
|
+
if (sameOrder(correct, sortableCurrent)) {
|
|
46425
|
+
continue;
|
|
46352
46426
|
}
|
|
46427
|
+
context.report({
|
|
46428
|
+
data: {
|
|
46429
|
+
decorator: metadata.name,
|
|
46430
|
+
order: correct.join(' -> '),
|
|
46431
|
+
},
|
|
46432
|
+
fix: (fixer) => {
|
|
46433
|
+
const forgottenProps = properties.filter(({ name }) => !orderList.includes(name));
|
|
46434
|
+
const sortedDecoratorProperties = [
|
|
46435
|
+
...correct.flatMap((key) => properties.filter(({ name }) => name === key)),
|
|
46436
|
+
...forgottenProps,
|
|
46437
|
+
];
|
|
46438
|
+
const newDecoratorArgument = `{${sortedDecoratorProperties
|
|
46439
|
+
.map(({ node }) => context.sourceCode.text.slice(...node.range))
|
|
46440
|
+
.join(',')}}`;
|
|
46441
|
+
return fixer.replaceTextRange(metadata.metadata.range, newDecoratorArgument);
|
|
46442
|
+
},
|
|
46443
|
+
messageId: 'incorrectOrder',
|
|
46444
|
+
node: metadata.expression,
|
|
46445
|
+
});
|
|
46353
46446
|
}
|
|
46354
46447
|
},
|
|
46355
46448
|
};
|
|
46356
46449
|
},
|
|
46357
46450
|
meta: {
|
|
46451
|
+
defaultOptions: [{}],
|
|
46452
|
+
docs: { description: 'Sorts keys of Angular decorator metadata.' },
|
|
46358
46453
|
fixable: 'code',
|
|
46454
|
+
messages: {
|
|
46455
|
+
incorrectOrder: 'Incorrect order keys in @{{decorator}} decorator, please sort by [{{order}}]',
|
|
46456
|
+
},
|
|
46359
46457
|
schema: [
|
|
46360
46458
|
{
|
|
46361
46459
|
additionalProperties: true,
|
|
@@ -46365,14 +46463,25 @@ const config$5 = {
|
|
|
46365
46463
|
],
|
|
46366
46464
|
type: 'problem',
|
|
46367
46465
|
},
|
|
46368
|
-
|
|
46466
|
+
name: 'decorator-key-sort',
|
|
46467
|
+
});
|
|
46369
46468
|
function getCorrectOrderRelative(correct, current) {
|
|
46370
46469
|
return correct.filter((item) => current.includes(item));
|
|
46371
46470
|
}
|
|
46372
|
-
|
|
46373
|
-
|
|
46374
|
-
|
|
46375
|
-
|
|
46471
|
+
function getDecoratorProperties(metadata) {
|
|
46472
|
+
const properties = [];
|
|
46473
|
+
for (const property of metadata.properties) {
|
|
46474
|
+
if (property.type !== dist$3.AST_NODE_TYPES.Property) {
|
|
46475
|
+
return null;
|
|
46476
|
+
}
|
|
46477
|
+
const name = getObjectPropertyName(property);
|
|
46478
|
+
if (!name) {
|
|
46479
|
+
return null;
|
|
46480
|
+
}
|
|
46481
|
+
properties.push({ name, node: property });
|
|
46482
|
+
}
|
|
46483
|
+
return properties;
|
|
46484
|
+
}
|
|
46376
46485
|
|
|
46377
46486
|
const INLINE_HTML_ELEMENTS = new Set([
|
|
46378
46487
|
'a',
|
|
@@ -46430,7 +46539,7 @@ function getNodeLabel(node) {
|
|
|
46430
46539
|
}
|
|
46431
46540
|
return node instanceof dist$4.TmplAstBoundText ? 'binding' : 'text';
|
|
46432
46541
|
}
|
|
46433
|
-
const rule$
|
|
46542
|
+
const rule$Q = createRule({
|
|
46434
46543
|
name: 'element-newline',
|
|
46435
46544
|
rule: {
|
|
46436
46545
|
create(context) {
|
|
@@ -46504,93 +46613,6 @@ const rule$P = createRule({
|
|
|
46504
46613
|
},
|
|
46505
46614
|
});
|
|
46506
46615
|
|
|
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
46616
|
const DEFAULT_GROUP = '$DEFAULT';
|
|
46595
46617
|
const DEFAULT_ATTRIBUTE_GROUPS = [
|
|
46596
46618
|
'$ANGULAR_STRUCTURAL_DIRECTIVE',
|
|
@@ -46656,7 +46678,7 @@ const PRESETS = {
|
|
|
46656
46678
|
$VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
|
|
46657
46679
|
$VUE_ATTRIBUTE: /^v-/,
|
|
46658
46680
|
};
|
|
46659
|
-
const rule$
|
|
46681
|
+
const rule$P = createRule({
|
|
46660
46682
|
create(context, [options]) {
|
|
46661
46683
|
const sourceCode = context.sourceCode;
|
|
46662
46684
|
const settings = {
|
|
@@ -46987,7 +47009,7 @@ const config$4 = {
|
|
|
46987
47009
|
type: 'suggestion',
|
|
46988
47010
|
},
|
|
46989
47011
|
};
|
|
46990
|
-
const rule$
|
|
47012
|
+
const rule$O = createRule({
|
|
46991
47013
|
name: 'html-logical-properties',
|
|
46992
47014
|
rule: config$4,
|
|
46993
47015
|
});
|
|
@@ -248226,7 +248248,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
|
|
|
248226
248248
|
}
|
|
248227
248249
|
return hasSafeRuntimeUsage;
|
|
248228
248250
|
}
|
|
248229
|
-
const rule$
|
|
248251
|
+
const rule$N = createRule({
|
|
248230
248252
|
create(context) {
|
|
248231
248253
|
const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
|
|
248232
248254
|
const checkCycles = context.options[0]?.checkCycles ?? true;
|
|
@@ -248944,7 +248966,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
|
|
|
248944
248966
|
? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
|
|
248945
248967
|
: fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
|
|
248946
248968
|
}
|
|
248947
|
-
const rule$
|
|
248969
|
+
const rule$M = createRule({
|
|
248948
248970
|
create(context) {
|
|
248949
248971
|
const { sourceCode } = context;
|
|
248950
248972
|
const program = sourceCode.ast;
|
|
@@ -248993,7 +249015,7 @@ const rule$L = createRule({
|
|
|
248993
249015
|
name: 'injection-token-description',
|
|
248994
249016
|
});
|
|
248995
249017
|
|
|
248996
|
-
const rule$
|
|
249018
|
+
const rule$L = createRule({
|
|
248997
249019
|
create(context) {
|
|
248998
249020
|
const { sourceCode } = context;
|
|
248999
249021
|
const namespaceImports = new Map();
|
|
@@ -249088,7 +249110,7 @@ const DEFAULT_OPTIONS = {
|
|
|
249088
249110
|
importDeclaration: '^@taiga-ui*',
|
|
249089
249111
|
projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
|
|
249090
249112
|
};
|
|
249091
|
-
const rule$
|
|
249113
|
+
const rule$K = createRule({
|
|
249092
249114
|
create(context) {
|
|
249093
249115
|
const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
|
|
249094
249116
|
const hasNonCodeExtension = (source) => {
|
|
@@ -249180,7 +249202,7 @@ const nearestFileUpCache = new Map();
|
|
|
249180
249202
|
const markerCache = new Map();
|
|
249181
249203
|
const indexFileCache = new Map();
|
|
249182
249204
|
const indexExportsCache = new Map();
|
|
249183
|
-
const rule$
|
|
249205
|
+
const rule$J = createRule({
|
|
249184
249206
|
create(context) {
|
|
249185
249207
|
const parserServices = dist$3.ESLintUtils.getParserServices(context);
|
|
249186
249208
|
const program = parserServices.program;
|
|
@@ -249374,13 +249396,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
|
|
|
249374
249396
|
if (!noDuplicateAttributesRule) {
|
|
249375
249397
|
throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
|
|
249376
249398
|
}
|
|
249377
|
-
const rule$
|
|
249399
|
+
const rule$I = createRule({
|
|
249378
249400
|
name: 'no-duplicate-attrs',
|
|
249379
249401
|
rule: noDuplicateAttributesRule,
|
|
249380
249402
|
});
|
|
249381
249403
|
|
|
249382
249404
|
const MESSAGE_ID$c = 'duplicateId';
|
|
249383
|
-
const rule$
|
|
249405
|
+
const rule$H = createRule({
|
|
249384
249406
|
name: 'no-duplicate-id',
|
|
249385
249407
|
rule: {
|
|
249386
249408
|
create(context) {
|
|
@@ -249441,7 +249463,7 @@ function getTrackingKey(node) {
|
|
|
249441
249463
|
? 'link[rel=canonical]'
|
|
249442
249464
|
: null;
|
|
249443
249465
|
}
|
|
249444
|
-
const rule$
|
|
249466
|
+
const rule$G = createRule({
|
|
249445
249467
|
name: 'no-duplicate-in-head',
|
|
249446
249468
|
rule: {
|
|
249447
249469
|
create(context) {
|
|
@@ -249496,6 +249518,133 @@ const rule$F = createRule({
|
|
|
249496
249518
|
},
|
|
249497
249519
|
});
|
|
249498
249520
|
|
|
249521
|
+
const COMPONENT_DECORATORS = new Set(['Component']);
|
|
249522
|
+
const rule$F = createRule({
|
|
249523
|
+
create(context) {
|
|
249524
|
+
const { sourceCode } = context;
|
|
249525
|
+
return {
|
|
249526
|
+
ClassDeclaration(node) {
|
|
249527
|
+
for (const decorator of node?.decorators ?? []) {
|
|
249528
|
+
const metadata = getDecoratorMetadata(decorator, COMPONENT_DECORATORS);
|
|
249529
|
+
if (!metadata) {
|
|
249530
|
+
continue;
|
|
249531
|
+
}
|
|
249532
|
+
const emptyProperties = metadata.properties.filter((property) => property.type === dist$3.AST_NODE_TYPES.Property &&
|
|
249533
|
+
isEmptyStyleMetadata(getObjectPropertyName(property), property, sourceCode));
|
|
249534
|
+
if (emptyProperties.length === 0) {
|
|
249535
|
+
continue;
|
|
249536
|
+
}
|
|
249537
|
+
const [firstEmptyProperty] = emptyProperties;
|
|
249538
|
+
if (!firstEmptyProperty) {
|
|
249539
|
+
continue;
|
|
249540
|
+
}
|
|
249541
|
+
context.report({
|
|
249542
|
+
fix: (fixer) => {
|
|
249543
|
+
const ranges = emptyProperties.map((property) => getPropertyRemovalRange(sourceCode, property));
|
|
249544
|
+
return ranges.some((range) => hasCommentsInRange(sourceCode, range))
|
|
249545
|
+
? null
|
|
249546
|
+
: fixer.replaceTextRange(metadata.range, removeRanges(sourceCode.text.slice(...metadata.range), ranges.map(([start, end]) => [
|
|
249547
|
+
start - metadata.range[0],
|
|
249548
|
+
end - metadata.range[0],
|
|
249549
|
+
])));
|
|
249550
|
+
},
|
|
249551
|
+
messageId: 'noEmptyStyleMetadata',
|
|
249552
|
+
node: firstEmptyProperty,
|
|
249553
|
+
});
|
|
249554
|
+
}
|
|
249555
|
+
},
|
|
249556
|
+
};
|
|
249557
|
+
},
|
|
249558
|
+
meta: {
|
|
249559
|
+
docs: {
|
|
249560
|
+
description: 'Disallow empty `styles`, `styleUrl`, and `styleUrls` metadata in Angular components.',
|
|
249561
|
+
},
|
|
249562
|
+
fixable: 'code',
|
|
249563
|
+
messages: {
|
|
249564
|
+
noEmptyStyleMetadata: 'Empty style metadata should be removed from @Component decorator.',
|
|
249565
|
+
},
|
|
249566
|
+
schema: [],
|
|
249567
|
+
type: 'problem',
|
|
249568
|
+
},
|
|
249569
|
+
name: 'no-empty-style-metadata',
|
|
249570
|
+
});
|
|
249571
|
+
function isEmptyStyleMetadata(name, property, sourceCode) {
|
|
249572
|
+
return (((name === 'styles' || name === 'styleUrl') &&
|
|
249573
|
+
isEmptyStringExpression(property.value)) ||
|
|
249574
|
+
(name === 'styleUrls' &&
|
|
249575
|
+
property.value.type === dist$3.AST_NODE_TYPES.ArrayExpression &&
|
|
249576
|
+
property.value.elements.length === 0 &&
|
|
249577
|
+
sourceCode.getText(property.value).replaceAll(/\s/g, '') === '[]'));
|
|
249578
|
+
}
|
|
249579
|
+
function isEmptyStringExpression(node) {
|
|
249580
|
+
if (node.type === dist$3.AST_NODE_TYPES.Literal) {
|
|
249581
|
+
return node.value === '';
|
|
249582
|
+
}
|
|
249583
|
+
if (node.type !== dist$3.AST_NODE_TYPES.TemplateLiteral || node.expressions.length > 0) {
|
|
249584
|
+
return false;
|
|
249585
|
+
}
|
|
249586
|
+
const [quasi] = node.quasis;
|
|
249587
|
+
return quasi?.value.raw === '';
|
|
249588
|
+
}
|
|
249589
|
+
function getPropertyRemovalRange(sourceCode, property) {
|
|
249590
|
+
const nextToken = sourceCode.getTokenAfter(property);
|
|
249591
|
+
if (nextToken?.value === ',') {
|
|
249592
|
+
return getRangeWithFollowingComma(sourceCode.text, property, nextToken.range);
|
|
249593
|
+
}
|
|
249594
|
+
const previousToken = sourceCode.getTokenBefore(property);
|
|
249595
|
+
return previousToken?.value === ','
|
|
249596
|
+
? [previousToken.range[0], property.range[1]]
|
|
249597
|
+
: getSinglePropertyRange(sourceCode.text, property);
|
|
249598
|
+
}
|
|
249599
|
+
function getRangeWithFollowingComma(text, property, commaRange) {
|
|
249600
|
+
const lineStart = getLineStart(text, property.range[0]);
|
|
249601
|
+
const nextLineStart = getNextLineStart(text, commaRange[1]);
|
|
249602
|
+
return text.slice(lineStart, property.range[0]).trim() === '' &&
|
|
249603
|
+
text.slice(commaRange[1], nextLineStart).trim() === '' &&
|
|
249604
|
+
nextLineStart > commaRange[1]
|
|
249605
|
+
? [lineStart, nextLineStart]
|
|
249606
|
+
: [property.range[0], commaRange[1]];
|
|
249607
|
+
}
|
|
249608
|
+
function getSinglePropertyRange(text, property) {
|
|
249609
|
+
const lineStart = getLineStart(text, property.range[0]);
|
|
249610
|
+
const nextLineStart = getNextLineStart(text, property.range[1]);
|
|
249611
|
+
return text.slice(lineStart, property.range[0]).trim() === '' &&
|
|
249612
|
+
text.slice(property.range[1], nextLineStart).trim() === '' &&
|
|
249613
|
+
nextLineStart > property.range[1]
|
|
249614
|
+
? [lineStart, nextLineStart]
|
|
249615
|
+
: [property.range[0], property.range[1]];
|
|
249616
|
+
}
|
|
249617
|
+
function getLineStart(text, index) {
|
|
249618
|
+
return text.lastIndexOf('\n', index - 1) + 1;
|
|
249619
|
+
}
|
|
249620
|
+
function getNextLineStart(text, index) {
|
|
249621
|
+
const lineEnd = text.indexOf('\n', index);
|
|
249622
|
+
return lineEnd === -1 ? index : lineEnd + 1;
|
|
249623
|
+
}
|
|
249624
|
+
function hasCommentsInRange(sourceCode, [start, end]) {
|
|
249625
|
+
return sourceCode
|
|
249626
|
+
.getAllComments()
|
|
249627
|
+
.some((comment) => comment.range[0] >= start && comment.range[1] <= end);
|
|
249628
|
+
}
|
|
249629
|
+
function removeRanges(text, ranges) {
|
|
249630
|
+
return mergeRanges(ranges)
|
|
249631
|
+
.sort((left, right) => right[0] - left[0])
|
|
249632
|
+
.reduce((result, [start, end]) => `${result.slice(0, start)}${result.slice(end)}`, text);
|
|
249633
|
+
}
|
|
249634
|
+
function mergeRanges(ranges) {
|
|
249635
|
+
const sorted = [...ranges].sort((left, right) => left[0] - right[0]);
|
|
249636
|
+
const merged = [];
|
|
249637
|
+
for (const range of sorted) {
|
|
249638
|
+
const last = merged[merged.length - 1];
|
|
249639
|
+
if (!last || range[0] > last[1]) {
|
|
249640
|
+
merged.push([...range]);
|
|
249641
|
+
continue;
|
|
249642
|
+
}
|
|
249643
|
+
last[1] = Math.max(last[1], range[1]);
|
|
249644
|
+
}
|
|
249645
|
+
return merged;
|
|
249646
|
+
}
|
|
249647
|
+
|
|
249499
249648
|
function isFunctionLike(node) {
|
|
249500
249649
|
return (node.type === dist$3.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
249501
249650
|
node.type === dist$3.AST_NODE_TYPES.FunctionDeclaration ||
|
|
@@ -253819,10 +253968,17 @@ function isArray(node) {
|
|
|
253819
253968
|
}
|
|
253820
253969
|
|
|
253821
253970
|
function isImportsArrayProperty(property) {
|
|
253822
|
-
|
|
253823
|
-
|
|
253971
|
+
if (property?.type !== dist$3.AST_NODE_TYPES.Property) {
|
|
253972
|
+
return false;
|
|
253973
|
+
}
|
|
253974
|
+
const hasIdentifierKey = property.key.type === dist$3.AST_NODE_TYPES.Identifier &&
|
|
253824
253975
|
property.key.name === 'imports';
|
|
253825
|
-
return
|
|
253976
|
+
return hasIdentifierKey && isArray(property.value);
|
|
253977
|
+
}
|
|
253978
|
+
|
|
253979
|
+
function getImportsArray(meta) {
|
|
253980
|
+
const property = meta.properties.find(isImportsArrayProperty);
|
|
253981
|
+
return property?.value ?? null;
|
|
253826
253982
|
}
|
|
253827
253983
|
|
|
253828
253984
|
function getImportedName$1(spec) {
|
|
@@ -253843,28 +253999,19 @@ const DEFAULT_EXCEPTIONS = [
|
|
|
253843
253999
|
const rule$9 = createRule({
|
|
253844
254000
|
create(context, [{ decorators = DEFAULT_DECORATORS, exceptions = DEFAULT_EXCEPTIONS }]) {
|
|
253845
254001
|
const sourceCode = context.getSourceCode();
|
|
254002
|
+
const allowedDecorators = new Set(decorators);
|
|
253846
254003
|
const importedFromTaiga = {};
|
|
253847
|
-
const decoratorSelector = `Decorator[expression.callee.name=/^(${decorators.join('|')})$/]`;
|
|
253848
254004
|
return {
|
|
253849
|
-
|
|
253850
|
-
const
|
|
253851
|
-
|
|
253852
|
-
expression.arguments.length === 0;
|
|
253853
|
-
if (isInvalidExpression) {
|
|
253854
|
-
return;
|
|
253855
|
-
}
|
|
253856
|
-
const [arg] = expression.arguments;
|
|
253857
|
-
const isNotObject = arg?.type !== dist$3.AST_NODE_TYPES.ObjectExpression;
|
|
253858
|
-
if (isNotObject) {
|
|
254005
|
+
Decorator(decorator) {
|
|
254006
|
+
const metadata = getDecoratorMetadata(decorator, allowedDecorators);
|
|
254007
|
+
if (!metadata) {
|
|
253859
254008
|
return;
|
|
253860
254009
|
}
|
|
253861
|
-
const
|
|
253862
|
-
|
|
253863
|
-
.find((literal) => isImportsArrayProperty(literal));
|
|
253864
|
-
if (!importsProperty) {
|
|
254010
|
+
const importsArray = getImportsArray(metadata);
|
|
254011
|
+
if (!importsArray) {
|
|
253865
254012
|
return;
|
|
253866
254013
|
}
|
|
253867
|
-
const imports =
|
|
254014
|
+
const imports = importsArray.elements.filter((el) => {
|
|
253868
254015
|
const isIdentifier = el?.type === dist$3.AST_NODE_TYPES.Identifier;
|
|
253869
254016
|
return Boolean(el && isIdentifier);
|
|
253870
254017
|
});
|
|
@@ -254275,14 +254422,6 @@ const rule$7 = createRule({
|
|
|
254275
254422
|
name: 'single-line-variable-spacing',
|
|
254276
254423
|
});
|
|
254277
254424
|
|
|
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
254425
|
function isSpread(node) {
|
|
254287
254426
|
return node.type === dist$2.AST_NODE_TYPES.SpreadElement;
|
|
254288
254427
|
}
|
|
@@ -254322,11 +254461,12 @@ function nameOf(node, source) {
|
|
|
254322
254461
|
return source.getText(node);
|
|
254323
254462
|
}
|
|
254324
254463
|
|
|
254464
|
+
const IMPORT_NAME_COLLATOR = new Intl.Collator('en', { numeric: true });
|
|
254325
254465
|
/**
|
|
254326
|
-
* Sorts Angular standalone import elements into a deterministic,
|
|
254466
|
+
* Sorts Angular standalone import elements into a deterministic, natural order.
|
|
254327
254467
|
*
|
|
254328
254468
|
* The sorting rules:
|
|
254329
|
-
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted
|
|
254469
|
+
* 1. Regular elements (Identifiers, MemberExpressions, etc.) are sorted naturally.
|
|
254330
254470
|
* 2. Spread elements (e.g. `...A`) are sorted separately and placed after regular ones.
|
|
254331
254471
|
* 3. Sorting is based on the string value returned by `nameOf()`.
|
|
254332
254472
|
*
|
|
@@ -254345,10 +254485,13 @@ function nameOf(node, source) {
|
|
|
254345
254485
|
function getSortedNames(elements, source) {
|
|
254346
254486
|
const regular = elements.filter((e) => !isSpread(e));
|
|
254347
254487
|
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)
|
|
254488
|
+
const sortedRegular = [...regular].sort((a, b) => compareImportNames(nameOf(a, source), nameOf(b, source)));
|
|
254489
|
+
const sortedSpreads = [...spreads].sort((a, b) => compareImportNames(nameOf(a.argument, source), nameOf(b.argument, source)));
|
|
254350
254490
|
return [...sortedRegular, ...sortedSpreads].map((n) => nameOf(n, source));
|
|
254351
254491
|
}
|
|
254492
|
+
function compareImportNames(x, y) {
|
|
254493
|
+
return IMPORT_NAME_COLLATOR.compare(x, y);
|
|
254494
|
+
}
|
|
254352
254495
|
|
|
254353
254496
|
const rule$6 = createRule({
|
|
254354
254497
|
create(context, [options]) {
|
|
@@ -255277,21 +255420,22 @@ const plugin = {
|
|
|
255277
255420
|
},
|
|
255278
255421
|
rules: {
|
|
255279
255422
|
'array-as-const': rule$5,
|
|
255280
|
-
'attrs-newline': rule$
|
|
255423
|
+
'attrs-newline': rule$S,
|
|
255281
255424
|
'class-property-naming': rule$4,
|
|
255282
|
-
'decorator-key-sort': rule$
|
|
255283
|
-
'element-newline': rule$
|
|
255425
|
+
'decorator-key-sort': rule$R,
|
|
255426
|
+
'element-newline': rule$Q,
|
|
255284
255427
|
'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$
|
|
255428
|
+
'host-attributes-sort': rule$P,
|
|
255429
|
+
'html-logical-properties': rule$O,
|
|
255430
|
+
'import-integrity': rule$N,
|
|
255431
|
+
'injection-token-description': rule$M,
|
|
255432
|
+
'no-commonjs-import-patterns': rule$L,
|
|
255433
|
+
'no-deep-imports': rule$K,
|
|
255434
|
+
'no-deep-imports-to-indexed-packages': rule$J,
|
|
255435
|
+
'no-duplicate-attrs': rule$I,
|
|
255436
|
+
'no-duplicate-id': rule$H,
|
|
255437
|
+
'no-duplicate-in-head': rule$G,
|
|
255438
|
+
'no-empty-style-metadata': rule$F,
|
|
255295
255439
|
'no-fully-untracked-effect': rule$E,
|
|
255296
255440
|
'no-href-with-router-link': rule$D,
|
|
255297
255441
|
'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,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
|
*
|