@taiga-ui/eslint-plugin-experience-next 0.472.0 → 0.473.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 +93 -0
- package/index.d.ts +3 -0
- package/index.esm.js +251 -130
- package/package.json +1 -1
- package/rules/prefer-combined-if-control-flow.d.ts +5 -0
package/README.md
CHANGED
|
@@ -60,6 +60,7 @@ export default [
|
|
|
60
60
|
| no-untracked-outside-reactive-context | Disallow `untracked()` outside reactive callbacks, except explicit post-`await` snapshots | ✅ | 🔧 | |
|
|
61
61
|
| no-useless-untracked | Disallow provably useless `untracked()` wrappers in reactive callbacks | ✅ | 🔧 | |
|
|
62
62
|
| object-single-line | Enforce single-line formatting for single-property objects when it fits `printWidth` | ✅ | 🔧 | |
|
|
63
|
+
| prefer-combined-if-control-flow | Combine consecutive `if` statements that use the same `return`, `break`, `continue`, or `throw` | ✅ | 🔧 | |
|
|
63
64
|
| prefer-deep-imports | Allow deep imports of Taiga UI packages | | 🔧 | |
|
|
64
65
|
| prefer-multi-arg-push | Combine consecutive `.push()` calls on the same array into a single multi-argument call | ✅ | 🔧 | |
|
|
65
66
|
| prefer-untracked-incidental-signal-reads | Wrap likely-incidental signal reads with `untracked()` in reactive callbacks | ✅ | 🔧 | |
|
|
@@ -863,6 +864,98 @@ const x = {foo: bar};
|
|
|
863
864
|
|
|
864
865
|
---
|
|
865
866
|
|
|
867
|
+
## prefer-combined-if-control-flow
|
|
868
|
+
|
|
869
|
+
<sup>`✅ Recommended`</sup> <sup>`Fixable`</sup>
|
|
870
|
+
|
|
871
|
+
Combine consecutive `if` statements when they have no `else` branch and use the same `return`, `break`, `continue`, or
|
|
872
|
+
`throw` statement. The autofix merges their conditions with `||`, while intentionally skipping cases with intervening
|
|
873
|
+
code or comments that should remain a separate control-flow boundary.
|
|
874
|
+
|
|
875
|
+
```ts
|
|
876
|
+
// ❌ error
|
|
877
|
+
while (true) {
|
|
878
|
+
if (a) continue;
|
|
879
|
+
if (b && c) continue;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// ✅ after autofix
|
|
883
|
+
while (true) {
|
|
884
|
+
if (a || (b && c)) continue;
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
```ts
|
|
889
|
+
// ❌ error
|
|
890
|
+
if (a || b) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (c) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// ✅ after autofix
|
|
899
|
+
if (a || b || c) {
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
```ts
|
|
905
|
+
// ❌ error
|
|
906
|
+
if (isInvalid) return result;
|
|
907
|
+
|
|
908
|
+
if (isLegacy && shouldStop) return result;
|
|
909
|
+
|
|
910
|
+
// ✅ after autofix
|
|
911
|
+
if (isInvalid || (isLegacy && shouldStop)) return result;
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
```ts
|
|
915
|
+
// ❌ error
|
|
916
|
+
while (true) {
|
|
917
|
+
if (isDone) break;
|
|
918
|
+
if (hasError) break;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// ✅ after autofix
|
|
922
|
+
while (true) {
|
|
923
|
+
if (isDone || hasError) break;
|
|
924
|
+
}
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
```ts
|
|
928
|
+
// ❌ error
|
|
929
|
+
if (isFatal) throw error;
|
|
930
|
+
|
|
931
|
+
if (isExpired && shouldAbort) throw error;
|
|
932
|
+
|
|
933
|
+
// ✅ after autofix
|
|
934
|
+
if (isFatal || (isExpired && shouldAbort)) throw error;
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
```ts
|
|
938
|
+
// not changed — different control flow
|
|
939
|
+
while (true) {
|
|
940
|
+
if (isDone) continue;
|
|
941
|
+
if (hasError) break;
|
|
942
|
+
}
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
```ts
|
|
946
|
+
// not changed — comment keeps branches separate
|
|
947
|
+
if (a) {
|
|
948
|
+
return value;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// explain why this branch exists
|
|
952
|
+
if (b) {
|
|
953
|
+
return value;
|
|
954
|
+
}
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
866
959
|
## prefer-deep-imports
|
|
867
960
|
|
|
868
961
|
<sup>`Taiga-specific`</sup> <sup>`Fixable`</sup>
|
package/index.d.ts
CHANGED
|
@@ -81,6 +81,9 @@ declare const plugin: {
|
|
|
81
81
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
82
82
|
name: string;
|
|
83
83
|
};
|
|
84
|
+
'prefer-combined-if-control-flow': import("@typescript-eslint/utils/ts-eslint").RuleModule<"preferCombinedIfControlFlow", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
|
85
|
+
name: string;
|
|
86
|
+
};
|
|
84
87
|
'prefer-deep-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"prefer-deep-imports", [{
|
|
85
88
|
importFilter: string[] | string;
|
|
86
89
|
strict?: boolean;
|
package/index.esm.js
CHANGED
|
@@ -914,6 +914,7 @@ var recommended = defineConfig([
|
|
|
914
914
|
'@taiga-ui/experience-next/no-untracked-outside-reactive-context': 'error',
|
|
915
915
|
'@taiga-ui/experience-next/no-useless-untracked': 'error',
|
|
916
916
|
'@taiga-ui/experience-next/object-single-line': ['error', { printWidth: 90 }],
|
|
917
|
+
'@taiga-ui/experience-next/prefer-combined-if-control-flow': 'error',
|
|
917
918
|
'@taiga-ui/experience-next/prefer-multi-arg-push': 'error',
|
|
918
919
|
'@taiga-ui/experience-next/prefer-untracked-incidental-signal-reads': 'error',
|
|
919
920
|
'@taiga-ui/experience-next/prefer-untracked-signal-getter': 'error',
|
|
@@ -1335,8 +1336,8 @@ function intersect(a, b) {
|
|
|
1335
1336
|
return a.some((type) => origin.has(type));
|
|
1336
1337
|
}
|
|
1337
1338
|
|
|
1338
|
-
const createRule$
|
|
1339
|
-
var classPropertyNaming = createRule$
|
|
1339
|
+
const createRule$i = ESLintUtils.RuleCreator((name) => name);
|
|
1340
|
+
var classPropertyNaming = createRule$i({
|
|
1340
1341
|
create(context, [configs]) {
|
|
1341
1342
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1342
1343
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
@@ -1505,9 +1506,9 @@ function isExternalPureTuple(typeChecker, type) {
|
|
|
1505
1506
|
return typeArgs.every((item) => isClassType(item));
|
|
1506
1507
|
}
|
|
1507
1508
|
|
|
1508
|
-
const createRule$
|
|
1509
|
+
const createRule$h = ESLintUtils.RuleCreator((name) => name);
|
|
1509
1510
|
const MESSAGE_ID$7 = 'spreadArrays';
|
|
1510
|
-
var flatExports = createRule$
|
|
1511
|
+
var flatExports = createRule$h({
|
|
1511
1512
|
create(context) {
|
|
1512
1513
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1513
1514
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
@@ -1667,10 +1668,7 @@ function getDecoratorMetadata(decorator, allowedNames) {
|
|
|
1667
1668
|
return null;
|
|
1668
1669
|
}
|
|
1669
1670
|
const callee = expr.callee;
|
|
1670
|
-
if (callee.type !== AST_NODE_TYPES$1.Identifier) {
|
|
1671
|
-
return null;
|
|
1672
|
-
}
|
|
1673
|
-
if (!allowedNames.has(callee.name)) {
|
|
1671
|
+
if (callee.type !== AST_NODE_TYPES$1.Identifier || !allowedNames.has(callee.name)) {
|
|
1674
1672
|
return null;
|
|
1675
1673
|
}
|
|
1676
1674
|
const arg = expr.arguments[0];
|
|
@@ -1746,8 +1744,8 @@ const PRESETS = {
|
|
|
1746
1744
|
$VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
|
|
1747
1745
|
$VUE_ATTRIBUTE: /^v-/,
|
|
1748
1746
|
};
|
|
1749
|
-
const createRule$
|
|
1750
|
-
const rule$
|
|
1747
|
+
const createRule$g = ESLintUtils.RuleCreator((name) => name);
|
|
1748
|
+
const rule$j = createRule$g({
|
|
1751
1749
|
create(context, [options]) {
|
|
1752
1750
|
const sourceCode = context.sourceCode;
|
|
1753
1751
|
const settings = {
|
|
@@ -1842,10 +1840,8 @@ function getHostObject(metadata) {
|
|
|
1842
1840
|
if (property.type !== AST_NODE_TYPES$1.Property ||
|
|
1843
1841
|
property.kind !== 'init' ||
|
|
1844
1842
|
property.computed ||
|
|
1845
|
-
property.method
|
|
1846
|
-
|
|
1847
|
-
}
|
|
1848
|
-
if (getStaticPropertyName(property.key) !== 'host') {
|
|
1843
|
+
property.method ||
|
|
1844
|
+
getStaticPropertyName(property.key) !== 'host') {
|
|
1849
1845
|
continue;
|
|
1850
1846
|
}
|
|
1851
1847
|
return property.value.type === AST_NODE_TYPES$1.ObjectExpression
|
|
@@ -2025,7 +2021,7 @@ const config$2 = {
|
|
|
2025
2021
|
const MESSAGE_ID$5 = 'invalid-injection-token-description';
|
|
2026
2022
|
const ERROR_MESSAGE$3 = "InjectionToken's description should contain token's name";
|
|
2027
2023
|
const NG_DEV_MODE = 'ngDevMode';
|
|
2028
|
-
const createRule$
|
|
2024
|
+
const createRule$f = ESLintUtils.RuleCreator((name) => name);
|
|
2029
2025
|
function getVariableName(node) {
|
|
2030
2026
|
if (node.parent.type !== AST_NODE_TYPES$1.VariableDeclarator) {
|
|
2031
2027
|
return undefined;
|
|
@@ -2096,7 +2092,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
|
|
|
2096
2092
|
}
|
|
2097
2093
|
return fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
|
|
2098
2094
|
}
|
|
2099
|
-
const rule$
|
|
2095
|
+
const rule$i = createRule$f({
|
|
2100
2096
|
create(context) {
|
|
2101
2097
|
const { sourceCode } = context;
|
|
2102
2098
|
const program = sourceCode.ast;
|
|
@@ -2164,8 +2160,8 @@ const DEFAULT_OPTIONS = {
|
|
|
2164
2160
|
importDeclaration: '^@taiga-ui*',
|
|
2165
2161
|
projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
|
|
2166
2162
|
};
|
|
2167
|
-
const createRule$
|
|
2168
|
-
const rule$
|
|
2163
|
+
const createRule$e = ESLintUtils.RuleCreator((name) => name);
|
|
2164
|
+
const rule$h = createRule$e({
|
|
2169
2165
|
create(context) {
|
|
2170
2166
|
const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
|
|
2171
2167
|
const hasNonCodeExtension = (source) => {
|
|
@@ -2252,13 +2248,13 @@ const rule$g = createRule$d({
|
|
|
2252
2248
|
name: 'no-deep-imports',
|
|
2253
2249
|
});
|
|
2254
2250
|
|
|
2255
|
-
const createRule$
|
|
2251
|
+
const createRule$d = ESLintUtils.RuleCreator((name) => name);
|
|
2256
2252
|
const resolveCacheByOptions = new WeakMap();
|
|
2257
2253
|
const nearestFileUpCache = new Map();
|
|
2258
2254
|
const markerCache = new Map();
|
|
2259
2255
|
const indexFileCache = new Map();
|
|
2260
2256
|
const indexExportsCache = new Map();
|
|
2261
|
-
var noDeepImportsToIndexedPackages = createRule$
|
|
2257
|
+
var noDeepImportsToIndexedPackages = createRule$d({
|
|
2262
2258
|
create(context) {
|
|
2263
2259
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
2264
2260
|
const program = parserServices.program;
|
|
@@ -2364,13 +2360,9 @@ var noDeepImportsToIndexedPackages = createRule$c({
|
|
|
2364
2360
|
return {
|
|
2365
2361
|
ImportDeclaration(node) {
|
|
2366
2362
|
const importSpecifier = node.source.value;
|
|
2367
|
-
if (typeof importSpecifier !== 'string'
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
if (!importSpecifier.includes('/')) {
|
|
2371
|
-
return;
|
|
2372
|
-
}
|
|
2373
|
-
if (!isExternalModuleSpecifier(importSpecifier)) {
|
|
2363
|
+
if (typeof importSpecifier !== 'string' ||
|
|
2364
|
+
!importSpecifier.includes('/') ||
|
|
2365
|
+
!isExternalModuleSpecifier(importSpecifier)) {
|
|
2374
2366
|
return;
|
|
2375
2367
|
}
|
|
2376
2368
|
const packageRootSpecifier = getPackageRootSpecifier(importSpecifier);
|
|
@@ -2438,10 +2430,8 @@ function getPackageRootSpecifier(importSpecifier) {
|
|
|
2438
2430
|
return pathParts[0] ?? importSpecifier;
|
|
2439
2431
|
}
|
|
2440
2432
|
function getSubpath(importSpecifier, packageRootSpecifier) {
|
|
2441
|
-
if (importSpecifier === packageRootSpecifier
|
|
2442
|
-
|
|
2443
|
-
}
|
|
2444
|
-
if (!importSpecifier.startsWith(`${packageRootSpecifier}/`)) {
|
|
2433
|
+
if (importSpecifier === packageRootSpecifier ||
|
|
2434
|
+
!importSpecifier.startsWith(`${packageRootSpecifier}/`)) {
|
|
2445
2435
|
return null;
|
|
2446
2436
|
}
|
|
2447
2437
|
return importSpecifier.slice(packageRootSpecifier.length + 1);
|
|
@@ -2516,10 +2506,8 @@ function getOrderedChildren(node) {
|
|
|
2516
2506
|
];
|
|
2517
2507
|
return children.filter((child) => child !== undefined && child !== null);
|
|
2518
2508
|
}
|
|
2519
|
-
if (node.type === AST_NODE_TYPES.BlockStatement
|
|
2520
|
-
|
|
2521
|
-
}
|
|
2522
|
-
if (node.type === AST_NODE_TYPES.Program) {
|
|
2509
|
+
if (node.type === AST_NODE_TYPES.BlockStatement ||
|
|
2510
|
+
node.type === AST_NODE_TYPES.Program) {
|
|
2523
2511
|
return node.body;
|
|
2524
2512
|
}
|
|
2525
2513
|
if (node.type === AST_NODE_TYPES.IfStatement) {
|
|
@@ -2580,10 +2568,7 @@ function getOrderedChildren(node) {
|
|
|
2580
2568
|
function walkSynchronousAst(root, visitor) {
|
|
2581
2569
|
traverse(root, true);
|
|
2582
2570
|
function traverse(node, isRoot = false) {
|
|
2583
|
-
if (visitor(node) === false) {
|
|
2584
|
-
return false;
|
|
2585
|
-
}
|
|
2586
|
-
if (!isRoot && isFunctionLike$1(node)) {
|
|
2571
|
+
if (visitor(node) === false || (!isRoot && isFunctionLike$1(node))) {
|
|
2587
2572
|
return false;
|
|
2588
2573
|
}
|
|
2589
2574
|
if (node.type === AST_NODE_TYPES.AwaitExpression) {
|
|
@@ -2864,10 +2849,8 @@ function isWritableSignalWrite(node, checker, esTreeNodeToTSNodeMap) {
|
|
|
2864
2849
|
return false;
|
|
2865
2850
|
}
|
|
2866
2851
|
const { object, property } = node.callee;
|
|
2867
|
-
if (property.type !== AST_NODE_TYPES.Identifier
|
|
2868
|
-
|
|
2869
|
-
}
|
|
2870
|
-
if (!SIGNAL_WRITE_METHODS.has(property.name)) {
|
|
2852
|
+
if (property.type !== AST_NODE_TYPES.Identifier ||
|
|
2853
|
+
!SIGNAL_WRITE_METHODS.has(property.name)) {
|
|
2871
2854
|
return false;
|
|
2872
2855
|
}
|
|
2873
2856
|
return isSignalType(object, checker, esTreeNodeToTSNodeMap);
|
|
@@ -2941,10 +2924,8 @@ const createUntrackedRule = ESLintUtils.RuleCreator((name) => `${UNTRACKED_RULES
|
|
|
2941
2924
|
function collectReadsInsideUntracked(root, checker, esTreeNodeToTSNodeMap, program) {
|
|
2942
2925
|
const reads = [];
|
|
2943
2926
|
walkSynchronousAst(root, (node) => {
|
|
2944
|
-
if (node.type !== AST_NODE_TYPES.CallExpression
|
|
2945
|
-
|
|
2946
|
-
}
|
|
2947
|
-
if (!isAngularUntrackedCall(node, program)) {
|
|
2927
|
+
if (node.type !== AST_NODE_TYPES.CallExpression ||
|
|
2928
|
+
!isAngularUntrackedCall(node, program)) {
|
|
2948
2929
|
return;
|
|
2949
2930
|
}
|
|
2950
2931
|
const [arg] = node.arguments;
|
|
@@ -2963,7 +2944,7 @@ function collectReadsInsideUntracked(root, checker, esTreeNodeToTSNodeMap, progr
|
|
|
2963
2944
|
});
|
|
2964
2945
|
return reads;
|
|
2965
2946
|
}
|
|
2966
|
-
const rule$
|
|
2947
|
+
const rule$g = createUntrackedRule({
|
|
2967
2948
|
create(context) {
|
|
2968
2949
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
2969
2950
|
const checker = parserServices.program.getTypeChecker();
|
|
@@ -3049,15 +3030,15 @@ const config$1 = {
|
|
|
3049
3030
|
},
|
|
3050
3031
|
};
|
|
3051
3032
|
|
|
3052
|
-
const createRule$
|
|
3053
|
-
const rule$
|
|
3033
|
+
const createRule$c = ESLintUtils.RuleCreator((name) => name);
|
|
3034
|
+
const rule$f = createRule$c({
|
|
3054
3035
|
create(context) {
|
|
3055
3036
|
const checkImplicitPublic = (node) => {
|
|
3056
3037
|
const classRef = getClass(node);
|
|
3057
|
-
if (!classRef ||
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3038
|
+
if (!classRef ||
|
|
3039
|
+
node.kind === 'constructor' ||
|
|
3040
|
+
!!node?.accessibility ||
|
|
3041
|
+
node.key?.type === AST_NODE_TYPES.PrivateIdentifier) {
|
|
3061
3042
|
return;
|
|
3062
3043
|
}
|
|
3063
3044
|
const name = node?.key?.name ||
|
|
@@ -3121,9 +3102,9 @@ function getClass(node) {
|
|
|
3121
3102
|
return getClass(node.parent);
|
|
3122
3103
|
}
|
|
3123
3104
|
|
|
3124
|
-
const createRule$
|
|
3105
|
+
const createRule$b = ESLintUtils.RuleCreator((name) => name);
|
|
3125
3106
|
const LEGACY_PEER_DEPS_PATTERN = /^legacy-peer-deps\s*=\s*true$/i;
|
|
3126
|
-
const rule$
|
|
3107
|
+
const rule$e = createRule$b({
|
|
3127
3108
|
create(context) {
|
|
3128
3109
|
return {
|
|
3129
3110
|
Program(node) {
|
|
@@ -3161,8 +3142,8 @@ const rule$d = createRule$a({
|
|
|
3161
3142
|
name: 'no-legacy-peer-deps',
|
|
3162
3143
|
});
|
|
3163
3144
|
|
|
3164
|
-
const createRule$
|
|
3165
|
-
const rule$
|
|
3145
|
+
const createRule$a = ESLintUtils.RuleCreator((name) => name);
|
|
3146
|
+
const rule$d = createRule$a({
|
|
3166
3147
|
create(context) {
|
|
3167
3148
|
const services = ESLintUtils.getParserServices(context);
|
|
3168
3149
|
const checker = services.program.getTypeChecker();
|
|
@@ -3327,7 +3308,7 @@ const config = {
|
|
|
3327
3308
|
},
|
|
3328
3309
|
};
|
|
3329
3310
|
|
|
3330
|
-
const createRule$
|
|
3311
|
+
const createRule$9 = ESLintUtils.RuleCreator((name) => name);
|
|
3331
3312
|
function collectArrayExpressions(node) {
|
|
3332
3313
|
const result = [];
|
|
3333
3314
|
if (node.type === AST_NODE_TYPES.ArrayExpression) {
|
|
@@ -3353,7 +3334,7 @@ function collectArrayExpressions(node) {
|
|
|
3353
3334
|
}
|
|
3354
3335
|
return result;
|
|
3355
3336
|
}
|
|
3356
|
-
const rule$
|
|
3337
|
+
const rule$c = createRule$9({
|
|
3357
3338
|
create(context) {
|
|
3358
3339
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
3359
3340
|
const typeChecker = parserServices.program.getTypeChecker();
|
|
@@ -3481,7 +3462,7 @@ function unwrapExpression(expression) {
|
|
|
3481
3462
|
return current;
|
|
3482
3463
|
}
|
|
3483
3464
|
|
|
3484
|
-
const createRule$
|
|
3465
|
+
const createRule$8 = ESLintUtils.RuleCreator((name) => name);
|
|
3485
3466
|
function isReactiveCallback(node) {
|
|
3486
3467
|
return (node?.type === AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
3487
3468
|
node?.type === AST_NODE_TYPES.FunctionExpression);
|
|
@@ -3603,7 +3584,7 @@ function inspectComputedBody(root, inspectionContext, report) {
|
|
|
3603
3584
|
return;
|
|
3604
3585
|
});
|
|
3605
3586
|
}
|
|
3606
|
-
const rule$
|
|
3587
|
+
const rule$b = createRule$8({
|
|
3607
3588
|
create(context) {
|
|
3608
3589
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
3609
3590
|
const checker = parserServices.program.getTypeChecker();
|
|
@@ -3650,7 +3631,7 @@ const rule$a = createRule$7({
|
|
|
3650
3631
|
name: 'no-side-effects-in-computed',
|
|
3651
3632
|
});
|
|
3652
3633
|
|
|
3653
|
-
const rule$
|
|
3634
|
+
const rule$a = createUntrackedRule({
|
|
3654
3635
|
create(context) {
|
|
3655
3636
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
3656
3637
|
const checker = parserServices.program.getTypeChecker();
|
|
@@ -3699,7 +3680,7 @@ const rule$9 = createUntrackedRule({
|
|
|
3699
3680
|
name: 'no-signal-reads-after-await-in-reactive-context',
|
|
3700
3681
|
});
|
|
3701
3682
|
|
|
3702
|
-
const createRule$
|
|
3683
|
+
const createRule$7 = ESLintUtils.RuleCreator((name) => name);
|
|
3703
3684
|
function isStringLiteral(node) {
|
|
3704
3685
|
return (node.type === AST_NODE_TYPES.Literal &&
|
|
3705
3686
|
typeof node.value === 'string');
|
|
@@ -3763,7 +3744,7 @@ function hasTemplateLiteralAncestor(node) {
|
|
|
3763
3744
|
}
|
|
3764
3745
|
return false;
|
|
3765
3746
|
}
|
|
3766
|
-
const rule$
|
|
3747
|
+
const rule$9 = createRule$7({
|
|
3767
3748
|
create(context) {
|
|
3768
3749
|
const { sourceCode } = context;
|
|
3769
3750
|
let parserServices = null;
|
|
@@ -4183,7 +4164,7 @@ function buildReactiveCallReplacement(outerUntrackedCall, reactiveCall, sourceCo
|
|
|
4183
4164
|
}
|
|
4184
4165
|
return dedent$1(text, reactiveCall.loc.start.column - outerUntrackedCall.parent.loc.start.column);
|
|
4185
4166
|
}
|
|
4186
|
-
const rule$
|
|
4167
|
+
const rule$8 = createUntrackedRule({
|
|
4187
4168
|
create(context) {
|
|
4188
4169
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
4189
4170
|
const checker = parserServices.program.getTypeChecker();
|
|
@@ -4207,20 +4188,12 @@ const rule$7 = createUntrackedRule({
|
|
|
4207
4188
|
}
|
|
4208
4189
|
return {
|
|
4209
4190
|
CallExpression(node) {
|
|
4210
|
-
if (!isAngularUntrackedCall(node, program)
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
}
|
|
4217
|
-
if (isAllowedImperativeAngularContext(node)) {
|
|
4218
|
-
return;
|
|
4219
|
-
}
|
|
4220
|
-
if (isAllowedDeferredCallbackContext(node, checker, esTreeNodeToTSNodeMap)) {
|
|
4221
|
-
return;
|
|
4222
|
-
}
|
|
4223
|
-
if (isAllowedLazyAngularFactoryContext(node, program)) {
|
|
4191
|
+
if (!isAngularUntrackedCall(node, program) ||
|
|
4192
|
+
findEnclosingReactiveScope(node, program) ||
|
|
4193
|
+
findEnclosingReactiveScopeAfterAsyncBoundary(node, program) ||
|
|
4194
|
+
isAllowedImperativeAngularContext(node) ||
|
|
4195
|
+
isAllowedDeferredCallbackContext(node, checker, esTreeNodeToTSNodeMap) ||
|
|
4196
|
+
isAllowedLazyAngularFactoryContext(node, program)) {
|
|
4224
4197
|
return;
|
|
4225
4198
|
}
|
|
4226
4199
|
const reactiveCall = getFixableReactiveCall(node, program);
|
|
@@ -4327,10 +4300,8 @@ function hasOpaqueSynchronousCalls(root, checker, esTreeNodeToTSNodeMap, program
|
|
|
4327
4300
|
}
|
|
4328
4301
|
return;
|
|
4329
4302
|
}
|
|
4330
|
-
if (node.type !== AST_NODE_TYPES.CallExpression
|
|
4331
|
-
|
|
4332
|
-
}
|
|
4333
|
-
if (isAngularUntrackedCall(node, program) ||
|
|
4303
|
+
if (node.type !== AST_NODE_TYPES.CallExpression ||
|
|
4304
|
+
isAngularUntrackedCall(node, program) ||
|
|
4334
4305
|
isSignalReadCall(node, checker, esTreeNodeToTSNodeMap) ||
|
|
4335
4306
|
isWritableSignalWrite(node, checker, esTreeNodeToTSNodeMap)) {
|
|
4336
4307
|
return;
|
|
@@ -4340,7 +4311,7 @@ function hasOpaqueSynchronousCalls(root, checker, esTreeNodeToTSNodeMap, program
|
|
|
4340
4311
|
});
|
|
4341
4312
|
return found;
|
|
4342
4313
|
}
|
|
4343
|
-
const rule$
|
|
4314
|
+
const rule$7 = createUntrackedRule({
|
|
4344
4315
|
create(context) {
|
|
4345
4316
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
4346
4317
|
const checker = parserServices.program.getTypeChecker();
|
|
@@ -4361,14 +4332,12 @@ const rule$6 = createUntrackedRule({
|
|
|
4361
4332
|
return;
|
|
4362
4333
|
}
|
|
4363
4334
|
const { reads } = collectSignalUsages(arg, checker, esTreeNodeToTSNodeMap, program);
|
|
4364
|
-
if (reads.length > 0
|
|
4335
|
+
if (reads.length > 0 ||
|
|
4336
|
+
hasOpaqueSynchronousCalls(arg, checker, esTreeNodeToTSNodeMap, program)) {
|
|
4365
4337
|
// Snapshot reads inside reactive callbacks are a valid Angular
|
|
4366
4338
|
// pattern even when the snapshot later influences branching.
|
|
4367
4339
|
return;
|
|
4368
4340
|
}
|
|
4369
|
-
if (hasOpaqueSynchronousCalls(arg, checker, esTreeNodeToTSNodeMap, program)) {
|
|
4370
|
-
return;
|
|
4371
|
-
}
|
|
4372
4341
|
// Only fix when the parent is a plain ExpressionStatement so we can
|
|
4373
4342
|
// replace statement-for-statement without breaking surrounding structure.
|
|
4374
4343
|
const parent = untrackedCall.parent;
|
|
@@ -4430,8 +4399,8 @@ const rule$6 = createUntrackedRule({
|
|
|
4430
4399
|
name: 'no-useless-untracked',
|
|
4431
4400
|
});
|
|
4432
4401
|
|
|
4433
|
-
const createRule$
|
|
4434
|
-
const rule$
|
|
4402
|
+
const createRule$6 = ESLintUtils.RuleCreator((name) => name);
|
|
4403
|
+
const rule$6 = createRule$6({
|
|
4435
4404
|
create(context, [{ printWidth }]) {
|
|
4436
4405
|
const sourceCode = context.sourceCode;
|
|
4437
4406
|
const getLineEndIndex = (lineStartIndex) => {
|
|
@@ -4683,6 +4652,169 @@ const rule$5 = createRule$5({
|
|
|
4683
4652
|
name: 'object-single-line',
|
|
4684
4653
|
});
|
|
4685
4654
|
|
|
4655
|
+
const createRule$5 = ESLintUtils.RuleCreator((name) => name);
|
|
4656
|
+
const EMPTY_ARGUMENT = '__EMPTY_ARGUMENT__';
|
|
4657
|
+
function getParenthesizedInner(node) {
|
|
4658
|
+
const maybeNode = node;
|
|
4659
|
+
if (maybeNode.type === 'ParenthesizedExpression') {
|
|
4660
|
+
return maybeNode.expression ?? null;
|
|
4661
|
+
}
|
|
4662
|
+
return null;
|
|
4663
|
+
}
|
|
4664
|
+
function unwrapParenthesized(node) {
|
|
4665
|
+
let current = node;
|
|
4666
|
+
let inner = getParenthesizedInner(current);
|
|
4667
|
+
while (inner) {
|
|
4668
|
+
current = inner;
|
|
4669
|
+
inner = getParenthesizedInner(current);
|
|
4670
|
+
}
|
|
4671
|
+
return current;
|
|
4672
|
+
}
|
|
4673
|
+
function isSupportedControlFlowStatement(node) {
|
|
4674
|
+
return (node.type === AST_NODE_TYPES.BreakStatement ||
|
|
4675
|
+
node.type === AST_NODE_TYPES.ContinueStatement ||
|
|
4676
|
+
node.type === AST_NODE_TYPES.ReturnStatement ||
|
|
4677
|
+
node.type === AST_NODE_TYPES.ThrowStatement);
|
|
4678
|
+
}
|
|
4679
|
+
function getControlFlowStatement(node) {
|
|
4680
|
+
if (isSupportedControlFlowStatement(node)) {
|
|
4681
|
+
return node;
|
|
4682
|
+
}
|
|
4683
|
+
if (node.type === AST_NODE_TYPES.BlockStatement &&
|
|
4684
|
+
node.body.length === 1 &&
|
|
4685
|
+
isSupportedControlFlowStatement(node.body[0])) {
|
|
4686
|
+
return node.body[0];
|
|
4687
|
+
}
|
|
4688
|
+
return null;
|
|
4689
|
+
}
|
|
4690
|
+
function getControlFlowSignature(node, sourceCode) {
|
|
4691
|
+
if (node.alternate) {
|
|
4692
|
+
return null;
|
|
4693
|
+
}
|
|
4694
|
+
const controlFlowStatement = getControlFlowStatement(node.consequent);
|
|
4695
|
+
if (!controlFlowStatement) {
|
|
4696
|
+
return null;
|
|
4697
|
+
}
|
|
4698
|
+
switch (controlFlowStatement.type) {
|
|
4699
|
+
case AST_NODE_TYPES.BreakStatement:
|
|
4700
|
+
return controlFlowStatement.label
|
|
4701
|
+
? `break:${sourceCode.getText(controlFlowStatement.label)}`
|
|
4702
|
+
: `break:${EMPTY_ARGUMENT}`;
|
|
4703
|
+
case AST_NODE_TYPES.ContinueStatement:
|
|
4704
|
+
return controlFlowStatement.label
|
|
4705
|
+
? `continue:${sourceCode.getText(controlFlowStatement.label)}`
|
|
4706
|
+
: `continue:${EMPTY_ARGUMENT}`;
|
|
4707
|
+
case AST_NODE_TYPES.ReturnStatement:
|
|
4708
|
+
return controlFlowStatement.argument
|
|
4709
|
+
? `return:${sourceCode.getText(unwrapParenthesized(controlFlowStatement.argument))}`
|
|
4710
|
+
: `return:${EMPTY_ARGUMENT}`;
|
|
4711
|
+
case AST_NODE_TYPES.ThrowStatement:
|
|
4712
|
+
return `throw:${sourceCode.getText(unwrapParenthesized(controlFlowStatement.argument))}`;
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4715
|
+
function hasNonWhitespaceBetween(sourceCode, left, right) {
|
|
4716
|
+
return sourceCode.text.slice(left.range[1], right.range[0]).trim() !== '';
|
|
4717
|
+
}
|
|
4718
|
+
function needsParenthesesInOrChain(node) {
|
|
4719
|
+
if (getParenthesizedInner(node)) {
|
|
4720
|
+
return false;
|
|
4721
|
+
}
|
|
4722
|
+
switch (node.type) {
|
|
4723
|
+
case AST_NODE_TYPES.AssignmentExpression:
|
|
4724
|
+
case AST_NODE_TYPES.ConditionalExpression:
|
|
4725
|
+
case AST_NODE_TYPES.SequenceExpression:
|
|
4726
|
+
case AST_NODE_TYPES.TSAsExpression:
|
|
4727
|
+
case AST_NODE_TYPES.TSSatisfiesExpression:
|
|
4728
|
+
case AST_NODE_TYPES.YieldExpression:
|
|
4729
|
+
return true;
|
|
4730
|
+
case AST_NODE_TYPES.LogicalExpression:
|
|
4731
|
+
return node.operator !== '||';
|
|
4732
|
+
default:
|
|
4733
|
+
return false;
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
function renderTest(node, sourceCode) {
|
|
4737
|
+
const text = sourceCode.getText(node);
|
|
4738
|
+
return needsParenthesesInOrChain(node) ? `(${text})` : text;
|
|
4739
|
+
}
|
|
4740
|
+
const rule$5 = createRule$5({
|
|
4741
|
+
create(context) {
|
|
4742
|
+
const { sourceCode } = context;
|
|
4743
|
+
function checkBody(statements) {
|
|
4744
|
+
let i = 0;
|
|
4745
|
+
while (i < statements.length) {
|
|
4746
|
+
const statement = statements[i];
|
|
4747
|
+
if (statement.type !== AST_NODE_TYPES.IfStatement) {
|
|
4748
|
+
i++;
|
|
4749
|
+
continue;
|
|
4750
|
+
}
|
|
4751
|
+
const signature = getControlFlowSignature(statement, sourceCode);
|
|
4752
|
+
if (!signature) {
|
|
4753
|
+
i++;
|
|
4754
|
+
continue;
|
|
4755
|
+
}
|
|
4756
|
+
const group = [statement];
|
|
4757
|
+
let j = i + 1;
|
|
4758
|
+
while (j < statements.length) {
|
|
4759
|
+
const nextStatement = statements[j];
|
|
4760
|
+
if (nextStatement.type !== AST_NODE_TYPES.IfStatement) {
|
|
4761
|
+
break;
|
|
4762
|
+
}
|
|
4763
|
+
if (!hasNonWhitespaceBetween(sourceCode, group[group.length - 1], nextStatement) &&
|
|
4764
|
+
sourceCode.getCommentsInside(nextStatement).length === 0 &&
|
|
4765
|
+
getControlFlowSignature(nextStatement, sourceCode) === signature) {
|
|
4766
|
+
group.push(nextStatement);
|
|
4767
|
+
j++;
|
|
4768
|
+
continue;
|
|
4769
|
+
}
|
|
4770
|
+
break;
|
|
4771
|
+
}
|
|
4772
|
+
if (group.length > 1) {
|
|
4773
|
+
for (const [index, ifStatement] of group.entries()) {
|
|
4774
|
+
context.report({
|
|
4775
|
+
...(index === 0
|
|
4776
|
+
? {
|
|
4777
|
+
fix(fixer) {
|
|
4778
|
+
const firstIf = group[0];
|
|
4779
|
+
const lastIf = group[group.length - 1];
|
|
4780
|
+
const condition = group
|
|
4781
|
+
.map((item) => renderTest(item.test, sourceCode))
|
|
4782
|
+
.join(' || ');
|
|
4783
|
+
return fixer.replaceTextRange([firstIf.range[0], lastIf.range[1]], `if (${condition}) ${sourceCode.getText(firstIf.consequent)}`);
|
|
4784
|
+
},
|
|
4785
|
+
}
|
|
4786
|
+
: {}),
|
|
4787
|
+
messageId: 'preferCombinedIfControlFlow',
|
|
4788
|
+
node: ifStatement,
|
|
4789
|
+
});
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
i = j;
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
return {
|
|
4796
|
+
BlockStatement(node) {
|
|
4797
|
+
checkBody(node.body);
|
|
4798
|
+
},
|
|
4799
|
+
Program(node) {
|
|
4800
|
+
checkBody(node.body);
|
|
4801
|
+
},
|
|
4802
|
+
};
|
|
4803
|
+
},
|
|
4804
|
+
meta: {
|
|
4805
|
+
docs: {
|
|
4806
|
+
description: 'Combine consecutive if statements that use the same return, break, continue, or throw statement into a single if statement.',
|
|
4807
|
+
},
|
|
4808
|
+
fixable: 'code',
|
|
4809
|
+
messages: {
|
|
4810
|
+
preferCombinedIfControlFlow: 'Combine consecutive if statements with identical return, break, continue, or throw statements.',
|
|
4811
|
+
},
|
|
4812
|
+
schema: [],
|
|
4813
|
+
type: 'suggestion',
|
|
4814
|
+
},
|
|
4815
|
+
name: 'prefer-combined-if-control-flow',
|
|
4816
|
+
});
|
|
4817
|
+
|
|
4686
4818
|
const MESSAGE_ID$1 = 'prefer-deep-imports';
|
|
4687
4819
|
const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
|
|
4688
4820
|
const createRule$4 = ESLintUtils.RuleCreator(() => ERROR_MESSAGE);
|
|
@@ -4700,14 +4832,10 @@ var preferDeepImports = createRule$4({
|
|
|
4700
4832
|
return;
|
|
4701
4833
|
}
|
|
4702
4834
|
const rootPackageName = getRootPackageName(rawImportPath);
|
|
4703
|
-
if (!rootPackageName
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
return;
|
|
4708
|
-
}
|
|
4709
|
-
if (!isStrictMode &&
|
|
4710
|
-
isAlreadyNestedImport(rawImportPath, rootPackageName)) {
|
|
4835
|
+
if (!rootPackageName ||
|
|
4836
|
+
!allowedPackages.includes(rootPackageName) ||
|
|
4837
|
+
(!isStrictMode &&
|
|
4838
|
+
isAlreadyNestedImport(rawImportPath, rootPackageName))) {
|
|
4711
4839
|
return;
|
|
4712
4840
|
}
|
|
4713
4841
|
const importedSymbols = extractNamedImportedSymbols(node);
|
|
@@ -4938,10 +5066,7 @@ function mapSymbolsToEntryPointsUsingTypeChecker(importedSymbols, candidateEntry
|
|
|
4938
5066
|
for (const importedSymbol of importedSymbols) {
|
|
4939
5067
|
for (const relativeEntryDir of candidateEntryPoints) {
|
|
4940
5068
|
const exportedNames = exportTableByEntryPoint.get(relativeEntryDir);
|
|
4941
|
-
if (!exportedNames) {
|
|
4942
|
-
continue;
|
|
4943
|
-
}
|
|
4944
|
-
if (!exportedNames.has(importedSymbol)) {
|
|
5069
|
+
if (!exportedNames?.has(importedSymbol)) {
|
|
4945
5070
|
continue;
|
|
4946
5071
|
}
|
|
4947
5072
|
symbolToEntryPoint.set(importedSymbol, relativeEntryDir);
|
|
@@ -5224,10 +5349,8 @@ function isDomImperativeCall(node, checker, esTreeNodeToTSNodeMap) {
|
|
|
5224
5349
|
}
|
|
5225
5350
|
const signature = checker.getResolvedSignature(tsNode);
|
|
5226
5351
|
const declaration = signature?.declaration;
|
|
5227
|
-
if (!declaration
|
|
5228
|
-
|
|
5229
|
-
}
|
|
5230
|
-
if (!LIB_DOM_FILE_PATTERN.test(declaration.getSourceFile().fileName)) {
|
|
5352
|
+
if (!declaration ||
|
|
5353
|
+
!LIB_DOM_FILE_PATTERN.test(declaration.getSourceFile().fileName)) {
|
|
5231
5354
|
return false;
|
|
5232
5355
|
}
|
|
5233
5356
|
const returnType = checker.typeToString(checker.getReturnTypeOfSignature(signature));
|
|
@@ -5459,18 +5582,15 @@ function getReturnedExpression(node) {
|
|
|
5459
5582
|
}
|
|
5460
5583
|
function getWrappedSignalGetter(node, checker, esTreeNodeToTSNodeMap) {
|
|
5461
5584
|
const [arg] = node.arguments;
|
|
5462
|
-
if (!arg ||
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
arg.type !== AST_NODE_TYPES.FunctionExpression) {
|
|
5585
|
+
if (!arg ||
|
|
5586
|
+
arg.type === AST_NODE_TYPES.SpreadElement ||
|
|
5587
|
+
(arg.type !== AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
5588
|
+
arg.type !== AST_NODE_TYPES.FunctionExpression)) {
|
|
5467
5589
|
return null;
|
|
5468
5590
|
}
|
|
5469
5591
|
const body = getReturnedExpression(arg);
|
|
5470
|
-
if (body?.type !== AST_NODE_TYPES.CallExpression
|
|
5471
|
-
|
|
5472
|
-
}
|
|
5473
|
-
if (!isSignalReadCall(body, checker, esTreeNodeToTSNodeMap)) {
|
|
5592
|
+
if (body?.type !== AST_NODE_TYPES.CallExpression ||
|
|
5593
|
+
!isSignalReadCall(body, checker, esTreeNodeToTSNodeMap)) {
|
|
5474
5594
|
return null;
|
|
5475
5595
|
}
|
|
5476
5596
|
const getter = unwrapExpression(body.callee);
|
|
@@ -5943,24 +6063,25 @@ const plugin = {
|
|
|
5943
6063
|
'class-property-naming': classPropertyNaming,
|
|
5944
6064
|
'decorator-key-sort': config$3,
|
|
5945
6065
|
'flat-exports': flatExports,
|
|
5946
|
-
'host-attributes-sort': rule$
|
|
6066
|
+
'host-attributes-sort': rule$j,
|
|
5947
6067
|
'html-logical-properties': config$2,
|
|
5948
|
-
'injection-token-description': rule$
|
|
5949
|
-
'no-deep-imports': rule$
|
|
6068
|
+
'injection-token-description': rule$i,
|
|
6069
|
+
'no-deep-imports': rule$h,
|
|
5950
6070
|
'no-deep-imports-to-indexed-packages': noDeepImportsToIndexedPackages,
|
|
5951
|
-
'no-fully-untracked-effect': rule$
|
|
6071
|
+
'no-fully-untracked-effect': rule$g,
|
|
5952
6072
|
'no-href-with-router-link': config$1,
|
|
5953
|
-
'no-implicit-public': rule$
|
|
5954
|
-
'no-legacy-peer-deps': rule$
|
|
5955
|
-
'no-playwright-empty-fill': rule$
|
|
6073
|
+
'no-implicit-public': rule$f,
|
|
6074
|
+
'no-legacy-peer-deps': rule$e,
|
|
6075
|
+
'no-playwright-empty-fill': rule$d,
|
|
5956
6076
|
'no-project-as-in-ng-template': config,
|
|
5957
|
-
'no-redundant-type-annotation': rule$
|
|
5958
|
-
'no-side-effects-in-computed': rule$
|
|
5959
|
-
'no-signal-reads-after-await-in-reactive-context': rule$
|
|
5960
|
-
'no-string-literal-concat': rule$
|
|
5961
|
-
'no-untracked-outside-reactive-context': rule$
|
|
5962
|
-
'no-useless-untracked': rule$
|
|
5963
|
-
'object-single-line': rule$
|
|
6077
|
+
'no-redundant-type-annotation': rule$c,
|
|
6078
|
+
'no-side-effects-in-computed': rule$b,
|
|
6079
|
+
'no-signal-reads-after-await-in-reactive-context': rule$a,
|
|
6080
|
+
'no-string-literal-concat': rule$9,
|
|
6081
|
+
'no-untracked-outside-reactive-context': rule$8,
|
|
6082
|
+
'no-useless-untracked': rule$7,
|
|
6083
|
+
'object-single-line': rule$6,
|
|
6084
|
+
'prefer-combined-if-control-flow': rule$5,
|
|
5964
6085
|
'prefer-deep-imports': preferDeepImports,
|
|
5965
6086
|
'prefer-multi-arg-push': rule$4,
|
|
5966
6087
|
'prefer-untracked-incidental-signal-reads': rule$3,
|
package/package.json
CHANGED