lint-suite 1.6.0 → 1.6.1
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 +149 -16
- package/eslint.cjs +1137 -132
- package/eslint.cjs.map +4 -4
- package/eslint.js +1205 -132
- package/eslint.js.map +4 -4
- package/lib/angular.d.ts.map +1 -1
- package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts +12 -0
- package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts.map +1 -0
- package/lib/rules/explicit-accessibility/explicit-accessibility.spec.d.ts +2 -0
- package/lib/rules/explicit-accessibility/explicit-accessibility.spec.d.ts.map +1 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts +6 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts.map +1 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.spec.d.ts +2 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.spec.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.fixtures.spec.d.ts +2 -0
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.fixtures.spec.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/angular-index.type.d.ts +33 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/angular-index.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts +7 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.d.ts +2 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/{angular-class-fields.d.ts → rule/angular/angular-class-fields.d.ts} +3 -3
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/{utils/angular-expression-reads.util.d.ts → rule/angular/angular-expression-reads.d.ts} +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/{common → rule/common}/no-unused-angular-instance-fields.type.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts +9 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-instance-fields.spec.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/{utils/typescript-field-reads.util.d.ts → rule/typescript/typescript-field-reads.d.ts} +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.d.ts.map +1 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts +6 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts.map +1 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.spec.d.ts +2 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.spec.d.ts.map +1 -0
- package/lib/typescript.d.ts.map +1 -1
- package/package.json +8 -3
- package/lib/rules/explicit-accessibility.d.ts +0 -12
- package/lib/rules/explicit-accessibility.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts +0 -7
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts.map +0 -1
- /package/lib/rules/no-unused-angular-instance-fields/{angular-metadata-reads.d.ts → rule/angular/angular-metadata-reads.d.ts} +0 -0
- /package/lib/rules/no-unused-angular-instance-fields/{no-unused-instance-fields.spec.d.ts → rule/no-unused-instance-fields.spec.d.ts} +0 -0
package/eslint.cjs
CHANGED
|
@@ -128,19 +128,19 @@ var import_globals = __toESM(require("globals"), 1);
|
|
|
128
128
|
var import_angular_eslint2 = require("angular-eslint");
|
|
129
129
|
var import_config2 = require("eslint/config");
|
|
130
130
|
|
|
131
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
|
|
131
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.ts
|
|
132
132
|
var import_utils4 = require("@typescript-eslint/utils");
|
|
133
133
|
|
|
134
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
|
|
134
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.ts
|
|
135
135
|
var import_utils2 = require("@typescript-eslint/utils");
|
|
136
136
|
|
|
137
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
|
|
137
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
|
|
138
138
|
var import_node_fs = require("node:fs");
|
|
139
139
|
var import_node_path = require("node:path");
|
|
140
140
|
var import_compiler2 = require("@angular/compiler");
|
|
141
141
|
var import_utils = require("@typescript-eslint/utils");
|
|
142
142
|
|
|
143
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/
|
|
143
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
|
|
144
144
|
var import_compiler = require("@angular/compiler");
|
|
145
145
|
var ReadCollector = class extends import_compiler.CombinedRecursiveAstVisitor {
|
|
146
146
|
constructor(boundTarget, action) {
|
|
@@ -190,7 +190,7 @@ var collectAngularExpressionReads = (nodes, boundTarget, action) => {
|
|
|
190
190
|
return collector.reads;
|
|
191
191
|
};
|
|
192
192
|
|
|
193
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
|
|
193
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
|
|
194
194
|
var externalTemplates = /* @__PURE__ */ new Map();
|
|
195
195
|
var parser = new import_compiler2.Parser(new import_compiler2.Lexer());
|
|
196
196
|
var templateBinder = new import_compiler2.R3TargetBinder(null);
|
|
@@ -328,11 +328,15 @@ var metadataReads = (metadata, component, filename, remainingNames) => {
|
|
|
328
328
|
return null;
|
|
329
329
|
};
|
|
330
330
|
|
|
331
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
|
|
331
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.ts
|
|
332
332
|
var managedApis = {
|
|
333
333
|
input: true,
|
|
334
334
|
model: true,
|
|
335
|
-
output: true
|
|
335
|
+
output: true,
|
|
336
|
+
viewChild: true,
|
|
337
|
+
viewChildren: true,
|
|
338
|
+
contentChild: true,
|
|
339
|
+
contentChildren: true
|
|
336
340
|
};
|
|
337
341
|
var angularName = (node, imports) => {
|
|
338
342
|
if (node.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
@@ -346,6 +350,28 @@ var angularName = (node, imports) => {
|
|
|
346
350
|
}
|
|
347
351
|
return angularName(node.object, imports);
|
|
348
352
|
};
|
|
353
|
+
var calleeRoot = (node) => {
|
|
354
|
+
if (node.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
355
|
+
return node;
|
|
356
|
+
}
|
|
357
|
+
if (node.type !== import_utils2.TSESTree.AST_NODE_TYPES.MemberExpression || node.object.type === import_utils2.TSESTree.AST_NODE_TYPES.Super) {
|
|
358
|
+
return void 0;
|
|
359
|
+
}
|
|
360
|
+
return calleeRoot(node.object);
|
|
361
|
+
};
|
|
362
|
+
var isImportBinding = (node, sourceCode) => {
|
|
363
|
+
const root = calleeRoot(node);
|
|
364
|
+
if (!root) {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
for (let scope = sourceCode.getScope(root); scope; scope = scope.upper) {
|
|
368
|
+
const variable = scope.set.get(root.name);
|
|
369
|
+
if (variable) {
|
|
370
|
+
return variable.defs[0]?.type === "ImportBinding";
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return false;
|
|
374
|
+
};
|
|
349
375
|
var angularClass = (node, imports) => {
|
|
350
376
|
for (const decorator of node.decorators) {
|
|
351
377
|
if (decorator.expression.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
@@ -373,24 +399,72 @@ var lifecycleHooks = {
|
|
|
373
399
|
ngAfterViewChecked: true,
|
|
374
400
|
ngOnDestroy: true
|
|
375
401
|
};
|
|
402
|
+
var formsInterfaceMethods = {
|
|
403
|
+
AsyncValidator: ["validate", "registerOnValidatorChange"],
|
|
404
|
+
ControlValueAccessor: [
|
|
405
|
+
"writeValue",
|
|
406
|
+
"registerOnChange",
|
|
407
|
+
"registerOnTouched",
|
|
408
|
+
"setDisabledState"
|
|
409
|
+
],
|
|
410
|
+
Validator: ["validate", "registerOnValidatorChange"]
|
|
411
|
+
};
|
|
412
|
+
var implementedFormsMethods = (node) => {
|
|
413
|
+
const methods = /* @__PURE__ */ new Set();
|
|
414
|
+
for (const heritage of node.implements) {
|
|
415
|
+
if (heritage.expression.type !== import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
for (const name of formsInterfaceMethods[heritage.expression.name] ?? []) {
|
|
419
|
+
methods.add(name);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return methods;
|
|
423
|
+
};
|
|
376
424
|
var isInstanceMethod = (node) => node.type === import_utils2.TSESTree.AST_NODE_TYPES.MethodDefinition && node.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier;
|
|
377
|
-
var
|
|
378
|
-
|
|
425
|
+
var isAngularComponentRefField = (node, sourceCode) => {
|
|
426
|
+
const type = node.typeAnnotation?.typeAnnotation;
|
|
427
|
+
if (type?.type !== import_utils2.TSESTree.AST_NODE_TYPES.TSTypeReference || type.typeName.type !== import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
const reference = sourceCode.getScope(type.typeName).references.find(({ identifier }) => identifier === type.typeName);
|
|
431
|
+
const variable = reference?.resolved;
|
|
432
|
+
const definition = variable?.defs[0];
|
|
433
|
+
return definition?.type === "ImportBinding" && definition.node.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportSpecifier && definition.parent?.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportDeclaration && definition.parent.source.value === "@angular/core" && (definition.node.imported.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier && definition.node.imported.name === "ComponentRef" || definition.node.imported.type === import_utils2.TSESTree.AST_NODE_TYPES.Literal && definition.node.imported.value === "ComponentRef");
|
|
434
|
+
};
|
|
435
|
+
var isExcludedField = (node, localPrivateOnly, sourceCode) => node.static || node.declare || node.override || node.decorators.length > 0 || isAngularComponentRefField(node, sourceCode) || localPrivateOnly && node.accessibility !== "private";
|
|
436
|
+
var hasAutomaticEffectCleanup = (node) => {
|
|
437
|
+
const options = node.arguments[1];
|
|
438
|
+
if (options === void 0) {
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
if (options.type !== import_utils2.TSESTree.AST_NODE_TYPES.ObjectExpression) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
return options.properties.every((property) => {
|
|
445
|
+
if (property.type !== import_utils2.TSESTree.AST_NODE_TYPES.Property || property.computed) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
const manualCleanup = property.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier && property.key.name === "manualCleanup" || property.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Literal && property.key.value === "manualCleanup";
|
|
449
|
+
return !manualCleanup || property.value.type === import_utils2.TSESTree.AST_NODE_TYPES.Literal && property.value.value === false;
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
var isManagedField = (node, imports, allowEffectFields, sourceCode) => {
|
|
379
453
|
if (node.value?.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
|
|
380
454
|
return false;
|
|
381
455
|
}
|
|
382
456
|
const name = angularName(node.value.callee, imports);
|
|
383
|
-
return typeof name === "string" && managedApis[name] === true;
|
|
457
|
+
return typeof name === "string" && managedApis[name] === true || allowEffectFields && name === "effect" && isImportBinding(node.value.callee, sourceCode) && hasAutomaticEffectCleanup(node.value);
|
|
384
458
|
};
|
|
385
|
-
var field = (node, imports,
|
|
386
|
-
if (isInstanceField(node) && !isExcludedField(node,
|
|
459
|
+
var field = (node, imports, localPrivateOnly, allowEffectFields, sourceCode) => {
|
|
460
|
+
if (isInstanceField(node) && !isExcludedField(node, localPrivateOnly, sourceCode) && !isManagedField(node, imports, allowEffectFields, sourceCode)) {
|
|
387
461
|
return { messageId: "unusedField", name: node.key.name, node };
|
|
388
462
|
}
|
|
389
463
|
return null;
|
|
390
464
|
};
|
|
391
|
-
var isExcludedMethod = (node,
|
|
392
|
-
var method = (node,
|
|
393
|
-
if (isInstanceMethod(node) && !isExcludedMethod(node,
|
|
465
|
+
var isExcludedMethod = (node, localPrivateOnly, implementedMethods) => node.static || node.override || node.decorators.length > 0 || node.computed || node.kind !== "method" || node.value.body === null || lifecycleHooks[node.key.name] === true || implementedMethods.has(node.key.name) || localPrivateOnly && node.accessibility !== "private";
|
|
466
|
+
var method = (node, localPrivateOnly, implementedMethods) => {
|
|
467
|
+
if (isInstanceMethod(node) && !isExcludedMethod(node, localPrivateOnly, implementedMethods)) {
|
|
394
468
|
return { messageId: "unusedMethod", name: node.key.name, node };
|
|
395
469
|
}
|
|
396
470
|
return null;
|
|
@@ -408,15 +482,24 @@ var addAngularImport = (node, imports) => {
|
|
|
408
482
|
}
|
|
409
483
|
}
|
|
410
484
|
};
|
|
411
|
-
var reportUnusedMembers = (context, imports, classes, dynamicClasses) => {
|
|
485
|
+
var reportUnusedMembers = (context, imports, classes, dynamicClasses, allowEffectFields, projectMemberUsed) => {
|
|
486
|
+
const projectAnalysis = projectMemberUsed !== void 0;
|
|
412
487
|
for (const entry of classes) {
|
|
413
488
|
const ngClass = angularClass(entry.node, imports);
|
|
414
489
|
if (!ngClass || dynamicClasses.has(entry)) {
|
|
415
490
|
continue;
|
|
416
491
|
}
|
|
492
|
+
const localPrivateOnly = !projectAnalysis && (!ngClass.component || entry.node.abstract === true);
|
|
493
|
+
const implementedMethods = implementedFormsMethods(entry.node);
|
|
417
494
|
const members = [];
|
|
418
495
|
for (const node of entry.node.body.body) {
|
|
419
|
-
const candidate = field(
|
|
496
|
+
const candidate = field(
|
|
497
|
+
node,
|
|
498
|
+
imports,
|
|
499
|
+
localPrivateOnly,
|
|
500
|
+
allowEffectFields,
|
|
501
|
+
context.sourceCode
|
|
502
|
+
) ?? method(node, localPrivateOnly, implementedMethods);
|
|
420
503
|
if (candidate) {
|
|
421
504
|
members.push(candidate);
|
|
422
505
|
}
|
|
@@ -440,18 +523,800 @@ var reportUnusedMembers = (context, imports, classes, dynamicClasses) => {
|
|
|
440
523
|
continue;
|
|
441
524
|
}
|
|
442
525
|
for (const candidate of unreadMembers) {
|
|
443
|
-
if (
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
526
|
+
if (reads.has(candidate.name) || projectMemberUsed?.(candidate.node) === true) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
context.report({
|
|
530
|
+
data: { name: candidate.name },
|
|
531
|
+
messageId: candidate.messageId,
|
|
532
|
+
node: candidate.node.key
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
|
|
539
|
+
var import_node_fs3 = require("node:fs");
|
|
540
|
+
var import_node_path2 = require("node:path");
|
|
541
|
+
|
|
542
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
|
|
543
|
+
var compilerCli = __toESM(require("@angular/compiler-cli"), 1);
|
|
544
|
+
var import_typescript4 = require("typescript");
|
|
545
|
+
|
|
546
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.ts
|
|
547
|
+
var isSpecFile = (fileName) => /\.spec\.[cm]?[tj]sx?$/u.test(fileName);
|
|
548
|
+
|
|
549
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
|
|
550
|
+
var import_node_fs2 = require("node:fs");
|
|
551
|
+
var import_compiler3 = require("@angular/compiler");
|
|
552
|
+
var import_typescript3 = require("typescript");
|
|
553
|
+
|
|
554
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.ts
|
|
555
|
+
var import_typescript = require("typescript");
|
|
556
|
+
var symbolsForName = (checker, type, name) => {
|
|
557
|
+
const symbol = checker.getPropertyOfType(checker.getApparentType(type), name);
|
|
558
|
+
if (symbol) {
|
|
559
|
+
return [symbol];
|
|
560
|
+
}
|
|
561
|
+
if (!type.isUnionOrIntersection()) {
|
|
562
|
+
return [];
|
|
563
|
+
}
|
|
564
|
+
const symbols = /* @__PURE__ */ new Set();
|
|
565
|
+
for (const member of type.types) {
|
|
566
|
+
for (const memberSymbol of symbolsForName(checker, member, name)) {
|
|
567
|
+
symbols.add(memberSymbol);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return [...symbols];
|
|
571
|
+
};
|
|
572
|
+
var stringIndexTypes = (checker, type) => {
|
|
573
|
+
const indexedType = checker.getIndexTypeOfType(
|
|
574
|
+
checker.getApparentType(type),
|
|
575
|
+
import_typescript.IndexKind.String
|
|
576
|
+
);
|
|
577
|
+
if (indexedType) {
|
|
578
|
+
return [indexedType];
|
|
579
|
+
}
|
|
580
|
+
if (!type.isUnionOrIntersection()) {
|
|
581
|
+
return [];
|
|
582
|
+
}
|
|
583
|
+
const indexedTypes = /* @__PURE__ */ new Set();
|
|
584
|
+
for (const member of type.types) {
|
|
585
|
+
for (const memberIndexedType of stringIndexTypes(checker, member)) {
|
|
586
|
+
indexedTypes.add(memberIndexedType);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return [...indexedTypes];
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.ts
|
|
593
|
+
var import_typescript2 = require("typescript");
|
|
594
|
+
var importedFromAngularCore = (declaration) => {
|
|
595
|
+
let current = declaration;
|
|
596
|
+
while (current.parent) {
|
|
597
|
+
current = current.parent;
|
|
598
|
+
if ((0, import_typescript2.isImportDeclaration)(current)) {
|
|
599
|
+
return (0, import_typescript2.isStringLiteralLike)(current.moduleSpecifier) && current.moduleSpecifier.text === "@angular/core";
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return false;
|
|
603
|
+
};
|
|
604
|
+
var isAngularComponentDecorator = (expression, checker) => {
|
|
605
|
+
const unresolved = checker.getSymbolAtLocation(expression);
|
|
606
|
+
if (!unresolved) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
const symbol = (unresolved.flags & import_typescript2.SymbolFlags.Alias) === 0 ? unresolved : checker.getAliasedSymbol(unresolved);
|
|
610
|
+
return symbol.getName() === "Component" && ((unresolved.declarations ?? []).some(importedFromAngularCore) || (symbol.declarations ?? []).some(
|
|
611
|
+
(declaration) => declaration.getSourceFile().fileName.replaceAll("\\", "/").includes("/node_modules/@angular/core/")
|
|
612
|
+
));
|
|
613
|
+
};
|
|
614
|
+
var componentMetadata = (declaration, checker) => {
|
|
615
|
+
if (!(0, import_typescript2.canHaveDecorators)(declaration)) {
|
|
616
|
+
return void 0;
|
|
617
|
+
}
|
|
618
|
+
for (const decorator of (0, import_typescript2.getDecorators)(declaration) ?? []) {
|
|
619
|
+
if (!(0, import_typescript2.isCallExpression)(decorator.expression) || !isAngularComponentDecorator(decorator.expression.expression, checker)) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const metadata = decorator.expression.arguments[0];
|
|
623
|
+
return metadata && (0, import_typescript2.isObjectLiteralExpression)(metadata) ? metadata : null;
|
|
624
|
+
}
|
|
625
|
+
return void 0;
|
|
626
|
+
};
|
|
627
|
+
var inlineTemplate = (declaration, checker) => {
|
|
628
|
+
const metadata = componentMetadata(declaration, checker);
|
|
629
|
+
if (!metadata) {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
for (const property of metadata.properties) {
|
|
633
|
+
if ((0, import_typescript2.isPropertyAssignment)(property) && ((0, import_typescript2.isIdentifier)(property.name) || (0, import_typescript2.isStringLiteralLike)(property.name) || (0, import_typescript2.isNumericLiteral)(property.name)) && property.name.text === "template") {
|
|
634
|
+
return (0, import_typescript2.isStringLiteralLike)(property.initializer) ? property.initializer.text : null;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return null;
|
|
638
|
+
};
|
|
639
|
+
var projectComponents = (program, checker) => {
|
|
640
|
+
const declarations = [];
|
|
641
|
+
let valid = true;
|
|
642
|
+
const visit = (node) => {
|
|
643
|
+
if ((0, import_typescript2.isClassLike)(node)) {
|
|
644
|
+
const metadata = componentMetadata(node, checker);
|
|
645
|
+
if (metadata === null) {
|
|
646
|
+
valid = false;
|
|
647
|
+
} else if (metadata) {
|
|
648
|
+
declarations.push(node);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
(0, import_typescript2.forEachChild)(node, visit);
|
|
652
|
+
};
|
|
653
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
654
|
+
if (!sourceFile.isDeclarationFile && !program.isSourceFileFromExternalLibrary(sourceFile) && !isSpecFile(sourceFile.fileName)) {
|
|
655
|
+
visit(sourceFile);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return valid ? declarations : null;
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
|
|
662
|
+
var propertyIdentifierKind = 0;
|
|
663
|
+
var referenceIdentifierKind = 5;
|
|
664
|
+
var RootCollector = class extends import_compiler3.CombinedRecursiveAstVisitor {
|
|
665
|
+
roots = [];
|
|
666
|
+
visitPropertyRead(node, context) {
|
|
667
|
+
if (node.receiver instanceof import_compiler3.ImplicitReceiver || node.receiver instanceof import_compiler3.ThisReceiver) {
|
|
668
|
+
this.roots.push(node);
|
|
669
|
+
}
|
|
670
|
+
return super.visitPropertyRead(node, context);
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
var readChain = (node) => {
|
|
674
|
+
const names = [];
|
|
675
|
+
let current = node;
|
|
676
|
+
let called = false;
|
|
677
|
+
while (true) {
|
|
678
|
+
names.unshift({ called, name: current.name });
|
|
679
|
+
if (current.receiver instanceof import_compiler3.PropertyRead || current.receiver instanceof import_compiler3.SafePropertyRead) {
|
|
680
|
+
current = current.receiver;
|
|
681
|
+
called = false;
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
if (current.receiver instanceof import_compiler3.Call) {
|
|
685
|
+
if (!(current.receiver.receiver instanceof import_compiler3.PropertyRead) && !(current.receiver.receiver instanceof import_compiler3.SafePropertyRead)) {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
current = current.receiver.receiver;
|
|
689
|
+
called = true;
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
return (current.receiver instanceof import_compiler3.ImplicitReceiver || current.receiver instanceof import_compiler3.ThisReceiver) && current instanceof import_compiler3.PropertyRead ? { names, root: current } : null;
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
var ReadCollector2 = class extends import_compiler3.CombinedRecursiveAstVisitor {
|
|
696
|
+
reads = [];
|
|
697
|
+
record(node) {
|
|
698
|
+
const chain = readChain(node);
|
|
699
|
+
if (chain) {
|
|
700
|
+
this.reads.push(chain);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
visitBinary(node, context) {
|
|
704
|
+
if (node.operation !== "=") {
|
|
705
|
+
return super.visitBinary(node, context);
|
|
706
|
+
}
|
|
707
|
+
if (node.left instanceof import_compiler3.PropertyRead || node.left instanceof import_compiler3.SafePropertyRead || node.left instanceof import_compiler3.KeyedRead || node.left instanceof import_compiler3.SafeKeyedRead) {
|
|
708
|
+
this.visit(node.left.receiver);
|
|
709
|
+
}
|
|
710
|
+
if (node.left instanceof import_compiler3.KeyedRead || node.left instanceof import_compiler3.SafeKeyedRead) {
|
|
711
|
+
this.visit(node.left.key);
|
|
712
|
+
}
|
|
713
|
+
this.visit(node.right);
|
|
714
|
+
return void 0;
|
|
715
|
+
}
|
|
716
|
+
visitPropertyRead(node, context) {
|
|
717
|
+
this.record(node);
|
|
718
|
+
return super.visitPropertyRead(node, context);
|
|
719
|
+
}
|
|
720
|
+
visitSafePropertyRead(node, context) {
|
|
721
|
+
this.record(node);
|
|
722
|
+
return super.visitSafePropertyRead(node, context);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
var templateText = (declaration, component, checker) => {
|
|
726
|
+
if (component.template.fileUrl === component.fileUrl) {
|
|
727
|
+
return inlineTemplate(declaration, checker);
|
|
728
|
+
}
|
|
729
|
+
return (0, import_node_fs2.readFileSync)(component.template.fileUrl, "utf8");
|
|
730
|
+
};
|
|
731
|
+
var isPropertyIdentifier = (identifier) => identifier.kind === propertyIdentifierKind;
|
|
732
|
+
var addResolvedPath = (declaration, names, checker, addDeclaration, allowMissingRoot) => {
|
|
733
|
+
let types = [checker.getTypeAtLocation(declaration)];
|
|
734
|
+
for (const [index, segment] of names.entries()) {
|
|
735
|
+
const symbols = new Set(
|
|
736
|
+
types.flatMap((type) => symbolsForName(checker, type, segment.name))
|
|
737
|
+
);
|
|
738
|
+
if (symbols.size === 0) {
|
|
739
|
+
const indexedTypes = types.flatMap(
|
|
740
|
+
(type) => stringIndexTypes(checker, type)
|
|
741
|
+
);
|
|
742
|
+
if (indexedTypes.length > 0) {
|
|
743
|
+
types = indexedTypes;
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (types.some(
|
|
747
|
+
(type) => (type.flags & (import_typescript3.TypeFlags.Any | import_typescript3.TypeFlags.Unknown)) !== 0
|
|
748
|
+
)) {
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
return index === 0 && allowMissingRoot;
|
|
752
|
+
}
|
|
753
|
+
for (const symbol of symbols) {
|
|
754
|
+
for (const memberDeclaration of symbol.declarations ?? []) {
|
|
755
|
+
addDeclaration(memberDeclaration);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
types = [...symbols].map(
|
|
759
|
+
(symbol) => checker.getTypeOfSymbolAtLocation(symbol, declaration)
|
|
760
|
+
);
|
|
761
|
+
if (segment.called) {
|
|
762
|
+
const returnTypes = types.flatMap(
|
|
763
|
+
(type) => checker.getSignaturesOfType(type, import_typescript3.SignatureKind.Call).map((signature) => signature.getReturnType())
|
|
764
|
+
);
|
|
765
|
+
if (returnTypes.length === 0) {
|
|
766
|
+
if (types.some(
|
|
767
|
+
(type) => (type.flags & (import_typescript3.TypeFlags.Any | import_typescript3.TypeFlags.Unknown)) !== 0
|
|
768
|
+
)) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
types = returnTypes;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return true;
|
|
777
|
+
};
|
|
778
|
+
var addTemplateReads = (declaration, component, checker, addDeclaration, missingRootNames) => {
|
|
779
|
+
const source = templateText(declaration, component, checker);
|
|
780
|
+
if (source === null) {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
const parsed = (0, import_compiler3.parseTemplate)(source, component.template.fileUrl);
|
|
784
|
+
if (parsed.errors?.length) {
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
const roots = new RootCollector();
|
|
788
|
+
const reads = new ReadCollector2();
|
|
789
|
+
for (const node of parsed.nodes) {
|
|
790
|
+
roots.visit(node);
|
|
791
|
+
reads.visit(node);
|
|
792
|
+
}
|
|
793
|
+
roots.roots.sort((left, right) => left.nameSpan.start - right.nameSpan.start);
|
|
794
|
+
const indexedRoots = [...component.template.identifiers].filter(isPropertyIdentifier).sort((left, right) => left.span.start - right.span.start);
|
|
795
|
+
const indexedByRoot = /* @__PURE__ */ new Map();
|
|
796
|
+
let indexedRootIndex = 0;
|
|
797
|
+
for (const root of roots.roots) {
|
|
798
|
+
const identifier = indexedRoots[indexedRootIndex];
|
|
799
|
+
if (identifier?.name === root.name) {
|
|
800
|
+
indexedByRoot.set(root, identifier);
|
|
801
|
+
indexedRootIndex += 1;
|
|
802
|
+
} else if (!missingRootNames.has(root.name)) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
if (indexedRootIndex !== indexedRoots.length) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
for (const chain of reads.reads) {
|
|
810
|
+
const identifier = indexedByRoot.get(chain.root);
|
|
811
|
+
if (!identifier) {
|
|
812
|
+
if (missingRootNames.has(chain.root.name)) {
|
|
813
|
+
continue;
|
|
449
814
|
}
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
if (identifier.target === null) {
|
|
818
|
+
if (!addResolvedPath(
|
|
819
|
+
declaration,
|
|
820
|
+
chain.names,
|
|
821
|
+
checker,
|
|
822
|
+
addDeclaration,
|
|
823
|
+
true
|
|
824
|
+
)) {
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
if (identifier.target.kind !== referenceIdentifierKind) {
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
const referenceTarget = identifier.target.target;
|
|
833
|
+
if (!referenceTarget) {
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
const targetDeclaration = referenceTarget.directive;
|
|
837
|
+
const targetNames = chain.names.slice(1);
|
|
838
|
+
const targetResolved = !targetDeclaration || addResolvedPath(
|
|
839
|
+
targetDeclaration,
|
|
840
|
+
targetNames,
|
|
841
|
+
checker,
|
|
842
|
+
addDeclaration,
|
|
843
|
+
false
|
|
844
|
+
);
|
|
845
|
+
if (!targetResolved) {
|
|
846
|
+
return false;
|
|
450
847
|
}
|
|
451
848
|
}
|
|
849
|
+
return true;
|
|
452
850
|
};
|
|
453
851
|
|
|
454
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/
|
|
852
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
|
|
853
|
+
var hasReadConfiguration = (value) => "readConfiguration" in value && typeof value.readConfiguration === "function";
|
|
854
|
+
var contextIndexErrorPattern = /^Impossible state: "(.+)" not found in "/u;
|
|
855
|
+
var missingContextRootNames = (errors) => {
|
|
856
|
+
const names = /* @__PURE__ */ new Set();
|
|
857
|
+
for (const error of errors) {
|
|
858
|
+
const match = contextIndexErrorPattern.exec(error.message);
|
|
859
|
+
if (!match?.[1]) {
|
|
860
|
+
return null;
|
|
861
|
+
}
|
|
862
|
+
names.add(match[1]);
|
|
863
|
+
}
|
|
864
|
+
return names;
|
|
865
|
+
};
|
|
866
|
+
var reusingCompilerHost = (program, options) => {
|
|
867
|
+
const base2 = (0, import_typescript4.createCompilerHost)(options, true);
|
|
868
|
+
return {
|
|
869
|
+
...base2,
|
|
870
|
+
getSourceFile: (fileName, ...rest) => program.getSourceFile(fileName) ?? base2.getSourceFile(fileName, ...rest)
|
|
871
|
+
};
|
|
872
|
+
};
|
|
873
|
+
var collectAngularTemplateReads = (program, configFilePath, addDeclaration) => {
|
|
874
|
+
if (!hasReadConfiguration(compilerCli)) {
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
const configuration = compilerCli.readConfiguration(configFilePath);
|
|
878
|
+
if (configuration.errors.some(
|
|
879
|
+
(diagnostic) => diagnostic.category === import_typescript4.DiagnosticCategory.Error
|
|
880
|
+
)) {
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
const angularProgram = new compilerCli.NgtscProgram(
|
|
884
|
+
configuration.rootNames,
|
|
885
|
+
configuration.options,
|
|
886
|
+
reusingCompilerHost(program, configuration.options)
|
|
887
|
+
);
|
|
888
|
+
if (angularProgram.getNgOptionDiagnostics().some(
|
|
889
|
+
(diagnostic) => diagnostic.category === import_typescript4.DiagnosticCategory.Error
|
|
890
|
+
)) {
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
const indexedComponents = angularProgram.getIndexedComponents();
|
|
894
|
+
const typescriptProgram = angularProgram.getTsProgram();
|
|
895
|
+
const checker = typescriptProgram.getTypeChecker();
|
|
896
|
+
const components = projectComponents(typescriptProgram, checker);
|
|
897
|
+
if (!components || components.some((declaration) => !indexedComponents.has(declaration))) {
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
const templateFiles = /* @__PURE__ */ new Set();
|
|
901
|
+
for (const [declaration, component] of indexedComponents) {
|
|
902
|
+
if (isSpecFile(declaration.getSourceFile().fileName)) {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
const missingRootNames = missingContextRootNames(component.errors);
|
|
906
|
+
if (!missingRootNames) {
|
|
907
|
+
return null;
|
|
908
|
+
}
|
|
909
|
+
if (!addTemplateReads(
|
|
910
|
+
declaration,
|
|
911
|
+
component,
|
|
912
|
+
checker,
|
|
913
|
+
addDeclaration,
|
|
914
|
+
missingRootNames
|
|
915
|
+
)) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
if (component.template.fileUrl !== component.fileUrl) {
|
|
919
|
+
templateFiles.add(component.template.fileUrl);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return [...templateFiles];
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
|
|
926
|
+
var import_typescript7 = require("typescript");
|
|
927
|
+
|
|
928
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.ts
|
|
929
|
+
var import_typescript6 = require("typescript");
|
|
930
|
+
|
|
931
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.ts
|
|
932
|
+
var import_typescript5 = require("typescript");
|
|
933
|
+
var addSymbolDeclarations = (checker, symbol, addDeclaration) => {
|
|
934
|
+
const resolved = (symbol.flags & import_typescript5.SymbolFlags.Alias) === 0 ? symbol : checker.getAliasedSymbol(symbol);
|
|
935
|
+
for (const declaration of resolved.declarations ?? []) {
|
|
936
|
+
addDeclaration(declaration);
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
var allPropertySymbols = (checker, type) => {
|
|
940
|
+
const symbols = new Set(
|
|
941
|
+
checker.getPropertiesOfType(checker.getApparentType(type))
|
|
942
|
+
);
|
|
943
|
+
if (type.isUnionOrIntersection()) {
|
|
944
|
+
for (const member of type.types) {
|
|
945
|
+
for (const symbol of allPropertySymbols(checker, member)) {
|
|
946
|
+
symbols.add(symbol);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return [...symbols];
|
|
951
|
+
};
|
|
952
|
+
var addNamedProperties = (checker, type, names, addDeclaration) => {
|
|
953
|
+
const symbols = names ? names.flatMap((name) => symbolsForName(checker, type, name)) : allPropertySymbols(checker, type);
|
|
954
|
+
for (const symbol of symbols) {
|
|
955
|
+
addSymbolDeclarations(checker, symbol, addDeclaration);
|
|
956
|
+
}
|
|
957
|
+
return symbols;
|
|
958
|
+
};
|
|
959
|
+
var literalPropertyNames = (type) => {
|
|
960
|
+
if (type.isStringLiteral() || type.isNumberLiteral()) {
|
|
961
|
+
return [String(type.value)];
|
|
962
|
+
}
|
|
963
|
+
if (!type.isUnion()) {
|
|
964
|
+
return null;
|
|
965
|
+
}
|
|
966
|
+
const names = [];
|
|
967
|
+
for (const member of type.types) {
|
|
968
|
+
const memberNames = literalPropertyNames(member);
|
|
969
|
+
if (!memberNames) {
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
names.push(...memberNames);
|
|
973
|
+
}
|
|
974
|
+
return names;
|
|
975
|
+
};
|
|
976
|
+
var propertyName = (checker, node) => {
|
|
977
|
+
if ((0, import_typescript5.isIdentifier)(node) || (0, import_typescript5.isPrivateIdentifier)(node) || (0, import_typescript5.isStringLiteralLike)(node) || (0, import_typescript5.isNumericLiteral)(node) || (0, import_typescript5.isBigIntLiteral)(node)) {
|
|
978
|
+
return [node.text];
|
|
979
|
+
}
|
|
980
|
+
return literalPropertyNames(checker.getTypeAtLocation(node.expression));
|
|
981
|
+
};
|
|
982
|
+
|
|
983
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.ts
|
|
984
|
+
var isBindingPattern = (node) => (0, import_typescript6.isArrayBindingPattern)(node) || (0, import_typescript6.isObjectBindingPattern)(node);
|
|
985
|
+
var lazyType = (compute) => {
|
|
986
|
+
let type;
|
|
987
|
+
return () => type ??= compute();
|
|
988
|
+
};
|
|
989
|
+
var skippable = (names, nested, candidateNames) => !nested && names !== null && !names.some((name) => candidateNames.has(name));
|
|
990
|
+
var collectBindingPattern = (pattern, type, checker, addDeclaration, candidateNames) => {
|
|
991
|
+
if ((0, import_typescript6.isArrayBindingPattern)(pattern)) {
|
|
992
|
+
for (const [index, element] of pattern.elements.entries()) {
|
|
993
|
+
if ((0, import_typescript6.isOmittedExpression)(element)) {
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
const names = element.dotDotDotToken ? null : [String(index)];
|
|
997
|
+
const nested = isBindingPattern(element.name);
|
|
998
|
+
if (skippable(names, nested, candidateNames)) {
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
const symbols = addNamedProperties(
|
|
1002
|
+
checker,
|
|
1003
|
+
type(),
|
|
1004
|
+
names,
|
|
1005
|
+
addDeclaration
|
|
1006
|
+
);
|
|
1007
|
+
if (nested) {
|
|
1008
|
+
for (const symbol of symbols) {
|
|
1009
|
+
collectBindingPattern(
|
|
1010
|
+
element.name,
|
|
1011
|
+
lazyType(() => checker.getTypeOfSymbolAtLocation(symbol, element)),
|
|
1012
|
+
checker,
|
|
1013
|
+
addDeclaration,
|
|
1014
|
+
candidateNames
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1022
|
+
for (const element of pattern.elements) {
|
|
1023
|
+
if (element.dotDotDotToken) {
|
|
1024
|
+
for (const symbol of allPropertySymbols(checker, type())) {
|
|
1025
|
+
if (!consumed.has(symbol.name)) {
|
|
1026
|
+
addSymbolDeclarations(checker, symbol, addDeclaration);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
1031
|
+
const names = element.propertyName ? propertyName(checker, element.propertyName) : (0, import_typescript6.isIdentifier)(element.name) ? [element.name.text] : null;
|
|
1032
|
+
for (const name of names ?? []) {
|
|
1033
|
+
consumed.add(name);
|
|
1034
|
+
}
|
|
1035
|
+
const nested = isBindingPattern(element.name);
|
|
1036
|
+
if (skippable(names, nested, candidateNames)) {
|
|
1037
|
+
continue;
|
|
1038
|
+
}
|
|
1039
|
+
const symbols = addNamedProperties(checker, type(), names, addDeclaration);
|
|
1040
|
+
if (nested) {
|
|
1041
|
+
for (const symbol of symbols) {
|
|
1042
|
+
collectBindingPattern(
|
|
1043
|
+
element.name,
|
|
1044
|
+
lazyType(() => checker.getTypeOfSymbolAtLocation(symbol, element)),
|
|
1045
|
+
checker,
|
|
1046
|
+
addDeclaration,
|
|
1047
|
+
candidateNames
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
var collectAssignmentPattern = (pattern, type, checker, addDeclaration, candidateNames) => {
|
|
1054
|
+
if ((0, import_typescript6.isArrayLiteralExpression)(pattern)) {
|
|
1055
|
+
for (const [index, element] of pattern.elements.entries()) {
|
|
1056
|
+
if ((0, import_typescript6.isOmittedExpression)(element)) {
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
const names = (0, import_typescript6.isSpreadElement)(element) ? null : [String(index)];
|
|
1060
|
+
const nested = (0, import_typescript6.isArrayLiteralExpression)(element) || (0, import_typescript6.isObjectLiteralExpression)(element);
|
|
1061
|
+
if (skippable(names, nested, candidateNames)) {
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
const symbols = addNamedProperties(
|
|
1065
|
+
checker,
|
|
1066
|
+
type(),
|
|
1067
|
+
names,
|
|
1068
|
+
addDeclaration
|
|
1069
|
+
);
|
|
1070
|
+
if (nested) {
|
|
1071
|
+
for (const symbol of symbols) {
|
|
1072
|
+
collectAssignmentPattern(
|
|
1073
|
+
element,
|
|
1074
|
+
lazyType(() => checker.getTypeOfSymbolAtLocation(symbol, element)),
|
|
1075
|
+
checker,
|
|
1076
|
+
addDeclaration,
|
|
1077
|
+
candidateNames
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
1085
|
+
for (const property of pattern.properties) {
|
|
1086
|
+
if ((0, import_typescript6.isSpreadAssignment)(property)) {
|
|
1087
|
+
for (const symbol of allPropertySymbols(checker, type())) {
|
|
1088
|
+
if (!consumed.has(symbol.name)) {
|
|
1089
|
+
addSymbolDeclarations(checker, symbol, addDeclaration);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
const names = propertyName(checker, property.name);
|
|
1095
|
+
for (const name of names ?? []) {
|
|
1096
|
+
consumed.add(name);
|
|
1097
|
+
}
|
|
1098
|
+
const nested = (0, import_typescript6.isPropertyAssignment)(property) && ((0, import_typescript6.isArrayLiteralExpression)(property.initializer) || (0, import_typescript6.isObjectLiteralExpression)(property.initializer));
|
|
1099
|
+
if (skippable(names, nested, candidateNames)) {
|
|
1100
|
+
continue;
|
|
1101
|
+
}
|
|
1102
|
+
const symbols = addNamedProperties(checker, type(), names, addDeclaration);
|
|
1103
|
+
if (nested) {
|
|
1104
|
+
for (const symbol of symbols) {
|
|
1105
|
+
collectAssignmentPattern(
|
|
1106
|
+
property.initializer,
|
|
1107
|
+
lazyType(() => checker.getTypeOfSymbolAtLocation(symbol, property)),
|
|
1108
|
+
checker,
|
|
1109
|
+
addDeclaration,
|
|
1110
|
+
candidateNames
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
var collectDestructuringReads = (node, checker, addDeclaration, candidateNames) => {
|
|
1117
|
+
const isDestructuringBindingPattern = isBindingPattern(node) && !((0, import_typescript6.isBindingElement)(node.parent) && node.parent.name === node);
|
|
1118
|
+
if (isDestructuringBindingPattern) {
|
|
1119
|
+
const declaration = node.parent;
|
|
1120
|
+
const source = (0, import_typescript6.isVariableDeclaration)(declaration) && declaration.initializer ? declaration.initializer : declaration;
|
|
1121
|
+
collectBindingPattern(
|
|
1122
|
+
node,
|
|
1123
|
+
lazyType(() => checker.getTypeAtLocation(source)),
|
|
1124
|
+
checker,
|
|
1125
|
+
addDeclaration,
|
|
1126
|
+
candidateNames
|
|
1127
|
+
);
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
const isDestructuringAssignment = (0, import_typescript6.isBinaryExpression)(node) && node.operatorToken.kind === import_typescript6.SyntaxKind.EqualsToken && ((0, import_typescript6.isArrayLiteralExpression)(node.left) || (0, import_typescript6.isObjectLiteralExpression)(node.left));
|
|
1131
|
+
if (isDestructuringAssignment) {
|
|
1132
|
+
collectAssignmentPattern(
|
|
1133
|
+
node.left,
|
|
1134
|
+
lazyType(() => checker.getTypeAtLocation(node.right)),
|
|
1135
|
+
checker,
|
|
1136
|
+
addDeclaration,
|
|
1137
|
+
candidateNames
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
|
|
1143
|
+
var isExpressionWrapper = (parent, child) => ((0, import_typescript7.isParenthesizedExpression)(parent) || (0, import_typescript7.isAsExpression)(parent) || (0, import_typescript7.isTypeAssertionExpression)(parent) || (0, import_typescript7.isNonNullExpression)(parent) || (0, import_typescript7.isSatisfiesExpression)(parent)) && parent.expression === child;
|
|
1144
|
+
var isPatternContainer = (parent, child) => (0, import_typescript7.isArrayLiteralExpression)(parent) && parent.elements.some((element) => element === child) || (0, import_typescript7.isObjectLiteralExpression)(parent) && parent.properties.some((property) => property === child) || (0, import_typescript7.isPropertyAssignment)(parent) && parent.initializer === child || (0, import_typescript7.isSpreadAssignment)(parent) && parent.expression === child;
|
|
1145
|
+
var isWriteOnly = (node) => {
|
|
1146
|
+
let current = node;
|
|
1147
|
+
let parent = node.parent;
|
|
1148
|
+
while (parent && (isExpressionWrapper(parent, current) || isPatternContainer(parent, current))) {
|
|
1149
|
+
current = parent;
|
|
1150
|
+
parent = parent.parent;
|
|
1151
|
+
}
|
|
1152
|
+
const isWriteOnlyBinaryAssignment = (0, import_typescript7.isBinaryExpression)(parent) && parent.left === current && parent.operatorToken.kind === import_typescript7.SyntaxKind.EqualsToken;
|
|
1153
|
+
const isWriteOnlyDelete = (0, import_typescript7.isDeleteExpression)(parent) && parent.expression === current;
|
|
1154
|
+
const isWriteOnlyIteration = ((0, import_typescript7.isForInStatement)(parent) || (0, import_typescript7.isForOfStatement)(parent)) && parent.initializer === current;
|
|
1155
|
+
return isWriteOnlyBinaryAssignment || isWriteOnlyDelete || isWriteOnlyIteration;
|
|
1156
|
+
};
|
|
1157
|
+
var addPropertyAccessRead = (node, checker, addDeclaration, candidateNames) => {
|
|
1158
|
+
if (!candidateNames.has(node.name.text) || isWriteOnly(node)) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
1162
|
+
if (symbol) {
|
|
1163
|
+
addSymbolDeclarations(checker, symbol, addDeclaration);
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
var addElementAccessRead = (node, checker, addDeclaration, candidateNames) => {
|
|
1167
|
+
if (isWriteOnly(node) || !node.argumentExpression) {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const names = literalPropertyNames(
|
|
1171
|
+
checker.getTypeAtLocation(node.argumentExpression)
|
|
1172
|
+
);
|
|
1173
|
+
if (names && !names.some((name) => candidateNames.has(name))) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
addNamedProperties(
|
|
1177
|
+
checker,
|
|
1178
|
+
checker.getTypeAtLocation(node.expression),
|
|
1179
|
+
names,
|
|
1180
|
+
addDeclaration
|
|
1181
|
+
);
|
|
1182
|
+
};
|
|
1183
|
+
var isAngularInterfaceMethod = (symbol) => (symbol.declarations ?? []).some(
|
|
1184
|
+
(declaration) => (0, import_typescript7.isMethodSignature)(declaration) && declaration.getSourceFile().fileName.replaceAll("\\", "/").includes("/node_modules/@angular/")
|
|
1185
|
+
);
|
|
1186
|
+
var collectAngularInterfaceMethods = (node, checker, addDeclaration) => {
|
|
1187
|
+
const implementsClauses = (node.heritageClauses ?? []).filter(
|
|
1188
|
+
(clause) => clause.token === import_typescript7.SyntaxKind.ImplementsKeyword
|
|
1189
|
+
);
|
|
1190
|
+
if (implementsClauses.length === 0) {
|
|
1191
|
+
return;
|
|
1192
|
+
}
|
|
1193
|
+
const classType = checker.getTypeAtLocation(node);
|
|
1194
|
+
for (const clause of implementsClauses) {
|
|
1195
|
+
for (const heritageType of clause.types) {
|
|
1196
|
+
const type = checker.getTypeAtLocation(heritageType);
|
|
1197
|
+
for (const interfaceMethod of type.getProperties()) {
|
|
1198
|
+
if (!isAngularInterfaceMethod(interfaceMethod)) {
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
const implementation = classType.getProperty(interfaceMethod.name);
|
|
1202
|
+
if (implementation) {
|
|
1203
|
+
addSymbolDeclarations(checker, implementation, addDeclaration);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
var collectCandidateNames = (sourceFiles) => {
|
|
1210
|
+
const names = /* @__PURE__ */ new Set();
|
|
1211
|
+
const visit = (node) => {
|
|
1212
|
+
if ((0, import_typescript7.isClassLike)(node) && (0, import_typescript7.canHaveDecorators)(node) && ((0, import_typescript7.getDecorators)(node)?.length ?? 0) > 0) {
|
|
1213
|
+
for (const member of node.members) {
|
|
1214
|
+
if (member.name && ((0, import_typescript7.isIdentifier)(member.name) || (0, import_typescript7.isStringLiteralLike)(member.name))) {
|
|
1215
|
+
names.add(member.name.text);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
(0, import_typescript7.forEachChild)(node, visit);
|
|
1220
|
+
};
|
|
1221
|
+
for (const sourceFile of sourceFiles) {
|
|
1222
|
+
visit(sourceFile);
|
|
1223
|
+
}
|
|
1224
|
+
return names;
|
|
1225
|
+
};
|
|
1226
|
+
var collectTypeScriptReads = (program, addDeclaration) => {
|
|
1227
|
+
const checker = program.getTypeChecker();
|
|
1228
|
+
const sourceFiles = program.getSourceFiles().filter(
|
|
1229
|
+
(sourceFile) => !sourceFile.isDeclarationFile && !program.isSourceFileFromExternalLibrary(sourceFile) && !isSpecFile(sourceFile.fileName) && /\.(?:[cm]?ts|tsx)$/u.test(sourceFile.fileName)
|
|
1230
|
+
);
|
|
1231
|
+
const candidateNames = collectCandidateNames(sourceFiles);
|
|
1232
|
+
const visit = (node) => {
|
|
1233
|
+
if ((0, import_typescript7.isPropertyAccessExpression)(node)) {
|
|
1234
|
+
addPropertyAccessRead(node, checker, addDeclaration, candidateNames);
|
|
1235
|
+
} else if ((0, import_typescript7.isElementAccessExpression)(node)) {
|
|
1236
|
+
addElementAccessRead(node, checker, addDeclaration, candidateNames);
|
|
1237
|
+
} else if ((0, import_typescript7.isClassLike)(node)) {
|
|
1238
|
+
collectAngularInterfaceMethods(node, checker, addDeclaration);
|
|
1239
|
+
}
|
|
1240
|
+
collectDestructuringReads(node, checker, addDeclaration, candidateNames);
|
|
1241
|
+
(0, import_typescript7.forEachChild)(node, visit);
|
|
1242
|
+
};
|
|
1243
|
+
for (const sourceFile of sourceFiles) {
|
|
1244
|
+
visit(sourceFile);
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
|
|
1248
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
|
|
1249
|
+
var projectUsageCache = /* @__PURE__ */ new WeakMap();
|
|
1250
|
+
var templateFileVersion = (fileName) => {
|
|
1251
|
+
const { mtimeNs, size } = (0, import_node_fs3.statSync)(fileName, { bigint: true });
|
|
1252
|
+
return { fileName: (0, import_node_path2.resolve)(fileName), mtimeNs, size };
|
|
1253
|
+
};
|
|
1254
|
+
var templateFileVersionsAreCurrent = (versions) => {
|
|
1255
|
+
try {
|
|
1256
|
+
return versions.every(({ fileName, mtimeNs, size }) => {
|
|
1257
|
+
const current = (0, import_node_fs3.statSync)(fileName, { bigint: true });
|
|
1258
|
+
return current.mtimeNs === mtimeNs && current.size === size;
|
|
1259
|
+
});
|
|
1260
|
+
} catch {
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
var cacheEntryIsCurrent = (entry) => {
|
|
1265
|
+
const now = performance.now();
|
|
1266
|
+
if (now - entry.checkedAt < entry.checkDuration * 20) {
|
|
1267
|
+
return true;
|
|
1268
|
+
}
|
|
1269
|
+
const current = templateFileVersionsAreCurrent(entry.templateFileVersions);
|
|
1270
|
+
entry.checkedAt = now;
|
|
1271
|
+
entry.checkDuration = performance.now() - now;
|
|
1272
|
+
return current;
|
|
1273
|
+
};
|
|
1274
|
+
var buildProjectUsage = (program) => {
|
|
1275
|
+
try {
|
|
1276
|
+
const configFilePath = program.getCompilerOptions()["configFilePath"];
|
|
1277
|
+
if (typeof configFilePath !== "string") {
|
|
1278
|
+
return null;
|
|
1279
|
+
}
|
|
1280
|
+
const declarations = /* @__PURE__ */ new Set();
|
|
1281
|
+
const addDeclaration = (declaration) => {
|
|
1282
|
+
declarations.add(declaration);
|
|
1283
|
+
};
|
|
1284
|
+
collectTypeScriptReads(program, addDeclaration);
|
|
1285
|
+
const templateFiles = collectAngularTemplateReads(
|
|
1286
|
+
program,
|
|
1287
|
+
configFilePath,
|
|
1288
|
+
addDeclaration
|
|
1289
|
+
);
|
|
1290
|
+
if (!templateFiles) {
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1294
|
+
checkDuration: 0,
|
|
1295
|
+
checkedAt: performance.now(),
|
|
1296
|
+
templateFileVersions: templateFiles.map(templateFileVersion),
|
|
1297
|
+
usage: {
|
|
1298
|
+
has: (node) => declarations.has(node)
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
} catch {
|
|
1302
|
+
return null;
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
var projectUsage = (program) => {
|
|
1306
|
+
const cached = projectUsageCache.get(program);
|
|
1307
|
+
if (cached && cacheEntryIsCurrent(cached)) {
|
|
1308
|
+
return cached.usage;
|
|
1309
|
+
}
|
|
1310
|
+
const built = buildProjectUsage(program);
|
|
1311
|
+
if (!built) {
|
|
1312
|
+
projectUsageCache.delete(program);
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
projectUsageCache.set(program, built);
|
|
1316
|
+
return built.usage;
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.ts
|
|
455
1320
|
var import_utils3 = require("@typescript-eslint/utils");
|
|
456
1321
|
var isTypeScriptExpressionWrapper = (node) => {
|
|
457
1322
|
switch (node.type) {
|
|
@@ -518,7 +1383,7 @@ var isDestructuringOrLoopTarget = (node) => {
|
|
|
518
1383
|
}
|
|
519
1384
|
return patternTarget && isSimpleAssignmentTarget(parent, current) || isLoopTarget(parent, current);
|
|
520
1385
|
};
|
|
521
|
-
var
|
|
1386
|
+
var isWriteOnly2 = (node) => isDirectWrite(node) || isDestructuringOrLoopTarget(node);
|
|
522
1387
|
var destructuringParts = (node) => {
|
|
523
1388
|
if (node.type === import_utils3.TSESTree.AST_NODE_TYPES.VariableDeclarator) {
|
|
524
1389
|
return { pattern: node.id, source: node.init };
|
|
@@ -528,7 +1393,7 @@ var destructuringParts = (node) => {
|
|
|
528
1393
|
}
|
|
529
1394
|
return null;
|
|
530
1395
|
};
|
|
531
|
-
var
|
|
1396
|
+
var propertyName2 = (property) => {
|
|
532
1397
|
if (property.type !== import_utils3.TSESTree.AST_NODE_TYPES.Property || property.computed) {
|
|
533
1398
|
return null;
|
|
534
1399
|
}
|
|
@@ -544,7 +1409,7 @@ var destructuredThisReads = (node) => {
|
|
|
544
1409
|
}
|
|
545
1410
|
const reads = [];
|
|
546
1411
|
for (const property of parts.pattern.properties) {
|
|
547
|
-
const name =
|
|
1412
|
+
const name = propertyName2(property);
|
|
548
1413
|
if (name === null) {
|
|
549
1414
|
return null;
|
|
550
1415
|
}
|
|
@@ -553,7 +1418,11 @@ var destructuredThisReads = (node) => {
|
|
|
553
1418
|
return reads;
|
|
554
1419
|
};
|
|
555
1420
|
|
|
556
|
-
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
|
|
1421
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.ts
|
|
1422
|
+
var defaultOptions = {
|
|
1423
|
+
allowEffectFields: false,
|
|
1424
|
+
analysis: "local"
|
|
1425
|
+
};
|
|
557
1426
|
var createRule = import_utils4.ESLintUtils.RuleCreator(
|
|
558
1427
|
() => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
|
|
559
1428
|
);
|
|
@@ -576,7 +1445,7 @@ var trackMemberRead = (node, stack, thisStack, dynamicClasses) => {
|
|
|
576
1445
|
if (node.computed && receiverIsThis) {
|
|
577
1446
|
dynamicClasses.add(current);
|
|
578
1447
|
}
|
|
579
|
-
if (receiverIsThis && !node.computed && node.property.type === import_utils4.TSESTree.AST_NODE_TYPES.Identifier && !
|
|
1448
|
+
if (receiverIsThis && !node.computed && node.property.type === import_utils4.TSESTree.AST_NODE_TYPES.Identifier && !isWriteOnly2(node)) {
|
|
580
1449
|
current.reads.add(node.property.name);
|
|
581
1450
|
}
|
|
582
1451
|
};
|
|
@@ -633,7 +1502,7 @@ var lexicalThisVisitor = (thisStack) => ({
|
|
|
633
1502
|
}
|
|
634
1503
|
}
|
|
635
1504
|
});
|
|
636
|
-
var visitor = (context, imports, classes, stack, dynamicClasses) => {
|
|
1505
|
+
var visitor = (context, imports, classes, stack, dynamicClasses, allowEffectFields, projectMemberUsed) => {
|
|
637
1506
|
const thisStack = [];
|
|
638
1507
|
return {
|
|
639
1508
|
ClassDeclaration(node) {
|
|
@@ -661,10 +1530,26 @@ var visitor = (context, imports, classes, stack, dynamicClasses) => {
|
|
|
661
1530
|
trackDestructuringRead(node, stack, thisStack, dynamicClasses);
|
|
662
1531
|
},
|
|
663
1532
|
"Program:exit"() {
|
|
664
|
-
reportUnusedMembers(
|
|
1533
|
+
reportUnusedMembers(
|
|
1534
|
+
context,
|
|
1535
|
+
imports,
|
|
1536
|
+
classes,
|
|
1537
|
+
dynamicClasses,
|
|
1538
|
+
allowEffectFields,
|
|
1539
|
+
projectMemberUsed
|
|
1540
|
+
);
|
|
665
1541
|
}
|
|
666
1542
|
};
|
|
667
1543
|
};
|
|
1544
|
+
var projectParserServices = (context) => {
|
|
1545
|
+
try {
|
|
1546
|
+
return import_utils4.ESLintUtils.getParserServices(context);
|
|
1547
|
+
} catch {
|
|
1548
|
+
throw new Error(
|
|
1549
|
+
"Project analysis requires parser services with type information."
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
668
1553
|
var no_unused_angular_instance_fields_default = createRule({
|
|
669
1554
|
name: "no-unused-instance-fields",
|
|
670
1555
|
meta: {
|
|
@@ -676,23 +1561,70 @@ var no_unused_angular_instance_fields_default = createRule({
|
|
|
676
1561
|
unusedField: "Angular instance field '{{name}}' is never read.",
|
|
677
1562
|
unusedMethod: "Angular instance method '{{name}}' is never read."
|
|
678
1563
|
},
|
|
679
|
-
schema: [
|
|
1564
|
+
schema: [
|
|
1565
|
+
{
|
|
1566
|
+
type: "object",
|
|
1567
|
+
properties: {
|
|
1568
|
+
allowEffectFields: {
|
|
1569
|
+
type: "boolean",
|
|
1570
|
+
description: "Allow Angular effect() fields with automatic cleanup."
|
|
1571
|
+
},
|
|
1572
|
+
analysis: {
|
|
1573
|
+
type: "string",
|
|
1574
|
+
enum: ["local", "project"],
|
|
1575
|
+
description: "Choose local-file or typed whole-project analysis."
|
|
1576
|
+
}
|
|
1577
|
+
},
|
|
1578
|
+
additionalProperties: false
|
|
1579
|
+
}
|
|
1580
|
+
]
|
|
680
1581
|
},
|
|
681
|
-
defaultOptions: [],
|
|
682
|
-
create(context) {
|
|
1582
|
+
defaultOptions: [defaultOptions],
|
|
1583
|
+
create(context, [options]) {
|
|
1584
|
+
const analysis = options.analysis ?? "local";
|
|
1585
|
+
if (analysis === "project" && isSpecFile(context.filename)) {
|
|
1586
|
+
return {};
|
|
1587
|
+
}
|
|
1588
|
+
const parserServices = analysis === "project" ? projectParserServices(context) : void 0;
|
|
683
1589
|
const imports = /* @__PURE__ */ new Map();
|
|
684
1590
|
for (const node of context.sourceCode.ast.body) {
|
|
685
1591
|
if (node.type === import_utils4.TSESTree.AST_NODE_TYPES.ImportDeclaration) {
|
|
686
1592
|
addAngularImport(node, imports);
|
|
687
1593
|
}
|
|
688
1594
|
}
|
|
689
|
-
|
|
1595
|
+
let hasAngularClassImport = false;
|
|
1596
|
+
for (const imported of imports.values()) {
|
|
1597
|
+
if (imported === null || imported === "Component" || imported === "Directive") {
|
|
1598
|
+
hasAngularClassImport = true;
|
|
1599
|
+
break;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
if (!hasAngularClassImport) {
|
|
690
1603
|
return {};
|
|
691
1604
|
}
|
|
1605
|
+
let projectMemberUsed;
|
|
1606
|
+
if (parserServices) {
|
|
1607
|
+
let usage;
|
|
1608
|
+
projectMemberUsed = (node) => {
|
|
1609
|
+
if (usage === void 0) {
|
|
1610
|
+
usage = projectUsage(parserServices.program);
|
|
1611
|
+
}
|
|
1612
|
+
return usage?.has(parserServices.esTreeNodeToTSNodeMap.get(node)) ?? true;
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
692
1615
|
const classes = [];
|
|
693
1616
|
const stack = [];
|
|
694
1617
|
const dynamicClasses = /* @__PURE__ */ new Set();
|
|
695
|
-
|
|
1618
|
+
const allowEffectFields = options.allowEffectFields ?? false;
|
|
1619
|
+
return visitor(
|
|
1620
|
+
context,
|
|
1621
|
+
imports,
|
|
1622
|
+
classes,
|
|
1623
|
+
stack,
|
|
1624
|
+
dynamicClasses,
|
|
1625
|
+
allowEffectFields,
|
|
1626
|
+
projectMemberUsed
|
|
1627
|
+
);
|
|
696
1628
|
}
|
|
697
1629
|
});
|
|
698
1630
|
|
|
@@ -714,11 +1646,17 @@ var angular = (0, import_config2.defineConfig)([
|
|
|
714
1646
|
...import_globals.default.browser,
|
|
715
1647
|
...import_globals.default.es2025,
|
|
716
1648
|
...import_globals.default.node
|
|
1649
|
+
},
|
|
1650
|
+
parserOptions: {
|
|
1651
|
+
projectService: true
|
|
717
1652
|
}
|
|
718
1653
|
},
|
|
719
1654
|
processor: import_angular_eslint2.processInlineTemplates,
|
|
720
1655
|
rules: {
|
|
721
|
-
"lint-suite-angular/no-unused-instance-fields":
|
|
1656
|
+
"lint-suite-angular/no-unused-instance-fields": [
|
|
1657
|
+
"error",
|
|
1658
|
+
{ analysis: "project" }
|
|
1659
|
+
],
|
|
722
1660
|
"@angular-eslint/prefer-on-push-component-change-detection": "error",
|
|
723
1661
|
// v22: flags only explicit opt-out of OnPush (omission now means OnPush)
|
|
724
1662
|
"@angular-eslint/prefer-signals": "error",
|
|
@@ -1102,44 +2040,38 @@ var import_eslint_import_resolver_typescript = require("eslint-import-resolver-t
|
|
|
1102
2040
|
var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"), 1);
|
|
1103
2041
|
var import_config9 = require("eslint/config");
|
|
1104
2042
|
|
|
1105
|
-
// packages/lint-suite/src/lib/rules/explicit-accessibility.ts
|
|
2043
|
+
// packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
|
|
1106
2044
|
var import_utils5 = require("@typescript-eslint/utils");
|
|
2045
|
+
var accessibilities = [
|
|
2046
|
+
"public",
|
|
2047
|
+
"private",
|
|
2048
|
+
"protected"
|
|
2049
|
+
];
|
|
1107
2050
|
var createRule2 = import_utils5.ESLintUtils.RuleCreator(
|
|
1108
|
-
() => "https://
|
|
2051
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#explicit-accessibility"
|
|
1109
2052
|
);
|
|
1110
|
-
var
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
return "<unknown>";
|
|
1116
|
-
}
|
|
1117
|
-
if ("key" in node && node.key) {
|
|
1118
|
-
if (node.key.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
1119
|
-
return node.key.name;
|
|
1120
|
-
}
|
|
1121
|
-
if (node.key.type === import_utils5.TSESTree.AST_NODE_TYPES.PrivateIdentifier) {
|
|
1122
|
-
return `#${node.key.name}`;
|
|
1123
|
-
}
|
|
1124
|
-
return "<computed/complex key>";
|
|
2053
|
+
var isPrivateMember = (node) => node.type !== import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty && node.key.type === import_utils5.TSESTree.AST_NODE_TYPES.PrivateIdentifier;
|
|
2054
|
+
var isConstructor = (node) => node.type === import_utils5.TSESTree.AST_NODE_TYPES.MethodDefinition && node.kind === "constructor";
|
|
2055
|
+
var reportTarget = (node) => {
|
|
2056
|
+
if (node.type !== import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty) {
|
|
2057
|
+
return node.key;
|
|
1125
2058
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
2059
|
+
const { parameter } = node;
|
|
2060
|
+
if (parameter.type === import_utils5.TSESTree.AST_NODE_TYPES.AssignmentPattern && parameter.left.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
2061
|
+
return parameter.left;
|
|
1128
2062
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
}
|
|
1142
|
-
return "<unknown>";
|
|
2063
|
+
return parameter;
|
|
2064
|
+
};
|
|
2065
|
+
var memberName = (target, sourceCode) => target.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier ? target.name : sourceCode.getText(target);
|
|
2066
|
+
var insertModifier = (node, accessibility, sourceCode) => {
|
|
2067
|
+
const lastDecorator = node.decorators.at(-1);
|
|
2068
|
+
const token = lastDecorator ? sourceCode.getTokenAfter(lastDecorator) : sourceCode.getFirstToken(node);
|
|
2069
|
+
if (!token) {
|
|
2070
|
+
return () => null;
|
|
2071
|
+
}
|
|
2072
|
+
const adjacentToDecorator = lastDecorator?.range[1] === token.range[0];
|
|
2073
|
+
const text2 = `${adjacentToDecorator ? " " : ""}${accessibility} `;
|
|
2074
|
+
return (fixer) => fixer.insertTextBefore(token, text2);
|
|
1143
2075
|
};
|
|
1144
2076
|
var explicit_accessibility_default = createRule2({
|
|
1145
2077
|
name: "explicit-accessibility",
|
|
@@ -1149,87 +2081,157 @@ var explicit_accessibility_default = createRule2({
|
|
|
1149
2081
|
description: "Require explicit accessibility modifiers on class members"
|
|
1150
2082
|
},
|
|
1151
2083
|
fixable: "code",
|
|
2084
|
+
hasSuggestions: true,
|
|
1152
2085
|
schema: [
|
|
1153
2086
|
{
|
|
1154
2087
|
type: "object",
|
|
1155
2088
|
properties: {
|
|
1156
2089
|
defaultAccessibility: {
|
|
1157
2090
|
type: "string",
|
|
1158
|
-
enum: ["public", "private", "protected"],
|
|
1159
|
-
description: "The accessibility modifier
|
|
2091
|
+
enum: ["public", "private", "protected", "none"],
|
|
2092
|
+
description: "The accessibility modifier inserted by the auto-fix; constructors always get public. 'none' reports without an auto-fix and offers all three levels as suggestions."
|
|
1160
2093
|
}
|
|
1161
2094
|
},
|
|
1162
2095
|
additionalProperties: false
|
|
1163
2096
|
}
|
|
1164
2097
|
],
|
|
1165
2098
|
messages: {
|
|
1166
|
-
missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected)."
|
|
2099
|
+
missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected).",
|
|
2100
|
+
setAccessibility: "Add the '{{ accessibility }}' modifier."
|
|
1167
2101
|
}
|
|
1168
2102
|
},
|
|
1169
|
-
defaultOptions: [
|
|
1170
|
-
create(context, [
|
|
1171
|
-
const {
|
|
1172
|
-
const
|
|
1173
|
-
|
|
1174
|
-
if (node.accessibility) {
|
|
2103
|
+
defaultOptions: [{ defaultAccessibility: "public" }],
|
|
2104
|
+
create(context, [{ defaultAccessibility = "public" }]) {
|
|
2105
|
+
const { sourceCode } = context;
|
|
2106
|
+
const check = (node) => {
|
|
2107
|
+
if (node.accessibility || isPrivateMember(node)) {
|
|
1175
2108
|
return;
|
|
1176
2109
|
}
|
|
1177
|
-
|
|
1178
|
-
const
|
|
1179
|
-
if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.MethodDefinition || node.type === import_utils5.TSESTree.AST_NODE_TYPES.PropertyDefinition) {
|
|
1180
|
-
reportNode = node.key;
|
|
1181
|
-
} else {
|
|
1182
|
-
const param = node.parameter;
|
|
1183
|
-
if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
1184
|
-
reportNode = param;
|
|
1185
|
-
} else if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.AssignmentPattern && param.left.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
1186
|
-
reportNode = param.left;
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
2110
|
+
const target = reportTarget(node);
|
|
2111
|
+
const fixAccessibility = isConstructor(node) && defaultAccessibility !== "none" ? "public" : defaultAccessibility;
|
|
1189
2112
|
context.report({
|
|
1190
|
-
node:
|
|
2113
|
+
node: target,
|
|
1191
2114
|
messageId: "missingAccessibility",
|
|
1192
|
-
data: { name },
|
|
1193
|
-
fix(
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
} else {
|
|
1200
|
-
tokenToInsertBefore = sourceCode.getFirstToken(node);
|
|
1201
|
-
}
|
|
1202
|
-
if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty && node.readonly) {
|
|
1203
|
-
const firstToken = sourceCode.getFirstToken(node);
|
|
1204
|
-
if (firstToken?.value === "readonly") {
|
|
1205
|
-
tokenToInsertBefore = firstToken;
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
if (!tokenToInsertBefore) return null;
|
|
1209
|
-
const tokenAfterInsertion = sourceCode.getTokenAfter(
|
|
1210
|
-
tokenToInsertBefore,
|
|
1211
|
-
{ includeComments: false }
|
|
1212
|
-
);
|
|
1213
|
-
const textBetween = sourceCode.text.slice(
|
|
1214
|
-
tokenToInsertBefore.range[1],
|
|
1215
|
-
tokenAfterInsertion?.range[0]
|
|
1216
|
-
);
|
|
1217
|
-
if (!/^\s/.test(textBetween)) {
|
|
1218
|
-
insertText = ` ${insertText}`;
|
|
1219
|
-
}
|
|
1220
|
-
return fixer.insertTextBefore(tokenToInsertBefore, insertText);
|
|
1221
|
-
}
|
|
2115
|
+
data: { name: memberName(target, sourceCode) },
|
|
2116
|
+
...fixAccessibility === "none" ? {} : { fix: insertModifier(node, fixAccessibility, sourceCode) },
|
|
2117
|
+
suggest: accessibilities.filter((accessibility) => accessibility !== fixAccessibility).map((accessibility) => ({
|
|
2118
|
+
messageId: "setAccessibility",
|
|
2119
|
+
data: { accessibility },
|
|
2120
|
+
fix: insertModifier(node, accessibility, sourceCode)
|
|
2121
|
+
}))
|
|
1222
2122
|
});
|
|
2123
|
+
};
|
|
2124
|
+
return {
|
|
2125
|
+
AccessorProperty: check,
|
|
2126
|
+
MethodDefinition: check,
|
|
2127
|
+
PropertyDefinition: check,
|
|
2128
|
+
TSAbstractAccessorProperty: check,
|
|
2129
|
+
TSAbstractMethodDefinition: check,
|
|
2130
|
+
TSAbstractPropertyDefinition: check,
|
|
2131
|
+
TSParameterProperty: check
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
});
|
|
2135
|
+
|
|
2136
|
+
// packages/lint-suite/src/lib/rules/no-inline-object-types/no-inline-object-types.ts
|
|
2137
|
+
var import_utils6 = require("@typescript-eslint/utils");
|
|
2138
|
+
var createRule3 = import_utils6.ESLintUtils.RuleCreator(
|
|
2139
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-inline-object-types"
|
|
2140
|
+
);
|
|
2141
|
+
var enclosingTypeAlias = (node) => {
|
|
2142
|
+
let current = node.parent;
|
|
2143
|
+
while (current && current.type !== import_utils6.TSESTree.AST_NODE_TYPES.Program) {
|
|
2144
|
+
if (current.type === import_utils6.TSESTree.AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
|
2145
|
+
return current;
|
|
2146
|
+
}
|
|
2147
|
+
current = current.parent;
|
|
2148
|
+
}
|
|
2149
|
+
return void 0;
|
|
2150
|
+
};
|
|
2151
|
+
var no_inline_object_types_default = createRule3({
|
|
2152
|
+
name: "no-inline-object-types",
|
|
2153
|
+
meta: {
|
|
2154
|
+
type: "suggestion",
|
|
2155
|
+
docs: {
|
|
2156
|
+
description: "Require nested object types inside a type alias to be extracted to a named type alias"
|
|
2157
|
+
},
|
|
2158
|
+
schema: [],
|
|
2159
|
+
messages: {
|
|
2160
|
+
inlineObjectType: "Inline object type must be extracted to a named type alias."
|
|
1223
2161
|
}
|
|
2162
|
+
},
|
|
2163
|
+
defaultOptions: [],
|
|
2164
|
+
create(context) {
|
|
1224
2165
|
return {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
2166
|
+
TSTypeLiteral(node) {
|
|
2167
|
+
if (node.parent.type !== import_utils6.TSESTree.AST_NODE_TYPES.TSTypeAliasDeclaration && enclosingTypeAlias(node)) {
|
|
2168
|
+
context.report({ node, messageId: "inlineObjectType" });
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
});
|
|
2174
|
+
|
|
2175
|
+
// packages/lint-suite/src/lib/rules/readonly-type-properties/readonly-type-properties.ts
|
|
2176
|
+
var import_utils7 = require("@typescript-eslint/utils");
|
|
2177
|
+
var createRule4 = import_utils7.ESLintUtils.RuleCreator(
|
|
2178
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#readonly-type-properties"
|
|
2179
|
+
);
|
|
2180
|
+
var propertyName3 = (node, sourceCode) => node.key.type === import_utils7.TSESTree.AST_NODE_TYPES.Identifier ? node.key.name : sourceCode.getText(node.key);
|
|
2181
|
+
var PRIMITIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
2182
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSStringKeyword,
|
|
2183
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSNumberKeyword,
|
|
2184
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSBooleanKeyword,
|
|
2185
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSBigIntKeyword,
|
|
2186
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSSymbolKeyword,
|
|
2187
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSNullKeyword,
|
|
2188
|
+
import_utils7.TSESTree.AST_NODE_TYPES.TSUndefinedKeyword
|
|
2189
|
+
]);
|
|
2190
|
+
var isPrimitive = (type) => {
|
|
2191
|
+
if (PRIMITIVE_KEYWORDS.has(type.type)) {
|
|
2192
|
+
return true;
|
|
2193
|
+
}
|
|
2194
|
+
if (type.type === import_utils7.TSESTree.AST_NODE_TYPES.TSLiteralType || type.type === import_utils7.TSESTree.AST_NODE_TYPES.TSTemplateLiteralType) {
|
|
2195
|
+
return true;
|
|
2196
|
+
}
|
|
2197
|
+
if (type.type === import_utils7.TSESTree.AST_NODE_TYPES.TSUnionType || type.type === import_utils7.TSESTree.AST_NODE_TYPES.TSIntersectionType) {
|
|
2198
|
+
return type.types.every(isPrimitive);
|
|
2199
|
+
}
|
|
2200
|
+
return false;
|
|
2201
|
+
};
|
|
2202
|
+
var readonly_type_properties_default = createRule4({
|
|
2203
|
+
name: "readonly-type-properties",
|
|
2204
|
+
meta: {
|
|
2205
|
+
type: "suggestion",
|
|
2206
|
+
docs: {
|
|
2207
|
+
description: "Require readonly on primitive-typed type and interface properties"
|
|
2208
|
+
},
|
|
2209
|
+
fixable: "code",
|
|
2210
|
+
schema: [],
|
|
2211
|
+
messages: {
|
|
2212
|
+
missingReadonly: "Type property '{{ name }}' should be readonly. Disable this rule on the line if mutation is required."
|
|
2213
|
+
}
|
|
2214
|
+
},
|
|
2215
|
+
defaultOptions: [],
|
|
2216
|
+
create(context) {
|
|
2217
|
+
const { sourceCode } = context;
|
|
2218
|
+
return {
|
|
2219
|
+
TSPropertySignature(node) {
|
|
2220
|
+
if (node.readonly || !node.typeAnnotation) {
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
if (!isPrimitive(node.typeAnnotation.typeAnnotation)) {
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
context.report({
|
|
2227
|
+
node: node.key,
|
|
2228
|
+
messageId: "missingReadonly",
|
|
2229
|
+
data: { name: propertyName3(node, sourceCode) },
|
|
2230
|
+
fix(fixer) {
|
|
2231
|
+
const firstToken = sourceCode.getFirstToken(node);
|
|
2232
|
+
return firstToken ? fixer.insertTextBefore(firstToken, "readonly ") : null;
|
|
2233
|
+
}
|
|
2234
|
+
});
|
|
1233
2235
|
}
|
|
1234
2236
|
};
|
|
1235
2237
|
}
|
|
@@ -1238,7 +2240,9 @@ var explicit_accessibility_default = createRule2({
|
|
|
1238
2240
|
// packages/lint-suite/src/lib/typescript.ts
|
|
1239
2241
|
var localTypescriptRules = {
|
|
1240
2242
|
rules: {
|
|
1241
|
-
"explicit-accessibility": explicit_accessibility_default
|
|
2243
|
+
"explicit-accessibility": explicit_accessibility_default,
|
|
2244
|
+
"readonly-type-properties": readonly_type_properties_default,
|
|
2245
|
+
"no-inline-object-types": no_inline_object_types_default
|
|
1242
2246
|
}
|
|
1243
2247
|
};
|
|
1244
2248
|
var typescript = (0, import_config9.defineConfig)([
|
|
@@ -1255,7 +2259,8 @@ var typescript = (0, import_config9.defineConfig)([
|
|
|
1255
2259
|
plugins: { local: localTypescriptRules },
|
|
1256
2260
|
rules: {
|
|
1257
2261
|
"local/explicit-accessibility": "error",
|
|
1258
|
-
"
|
|
2262
|
+
"local/readonly-type-properties": "error",
|
|
2263
|
+
"local/no-inline-object-types": "error",
|
|
1259
2264
|
"@typescript-eslint/explicit-function-return-type": "error",
|
|
1260
2265
|
"@typescript-eslint/no-empty-function": "error",
|
|
1261
2266
|
"@typescript-eslint/no-unused-vars": "error",
|