lint-suite 1.6.0 → 1.6.2

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.
Files changed (148) hide show
  1. package/README.md +161 -16
  2. package/eslint.cjs +3085 -998
  3. package/eslint.cjs.map +4 -4
  4. package/eslint.d.ts +13 -13
  5. package/eslint.d.ts.map +1 -1
  6. package/eslint.js +3173 -990
  7. package/eslint.js.map +4 -4
  8. package/lib/angular-template.d.ts.map +1 -1
  9. package/lib/angular.d.ts +1 -0
  10. package/lib/angular.d.ts.map +1 -1
  11. package/lib/base-limits.d.ts +2 -0
  12. package/lib/base-limits.d.ts.map +1 -0
  13. package/lib/base-practices.d.ts +2 -0
  14. package/lib/base-practices.d.ts.map +1 -0
  15. package/lib/base-recommended.d.ts +2 -0
  16. package/lib/base-recommended.d.ts.map +1 -0
  17. package/lib/base.d.ts.map +1 -1
  18. package/lib/javascript.d.ts.map +1 -1
  19. package/lib/rules/define-plugin.util.d.ts +6 -0
  20. package/lib/rules/define-plugin.util.d.ts.map +1 -0
  21. package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts +6 -0
  22. package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts.map +1 -0
  23. package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts +14 -0
  24. package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts.map +1 -0
  25. package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts +7 -0
  26. package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts.map +1 -0
  27. package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts +6 -0
  28. package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts.map +1 -0
  29. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts +5 -0
  30. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts.map +1 -0
  31. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.d.ts +9 -0
  32. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.d.ts.map +1 -0
  33. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-decorator-kind.d.ts +10 -0
  34. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-decorator-kind.d.ts.map +1 -0
  35. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts +4 -0
  36. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts.map +1 -0
  37. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.d.ts +12 -0
  38. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.d.ts.map +1 -0
  39. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts +3 -0
  40. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts.map +1 -0
  41. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-chains.d.ts +17 -0
  42. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-chains.d.ts.map +1 -0
  43. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts +8 -0
  44. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts.map +1 -0
  45. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts +6 -0
  46. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -0
  47. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts +5 -0
  48. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts.map +1 -0
  49. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts +54 -0
  50. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts.map +1 -0
  51. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts +116 -0
  52. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts.map +1 -0
  53. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts +4 -0
  54. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts.map +1 -0
  55. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts +4 -0
  56. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts.map +1 -0
  57. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts +4 -0
  58. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts.map +1 -0
  59. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts +10 -0
  60. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts.map +1 -0
  61. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts +17 -0
  62. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts.map +1 -0
  63. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.d.ts +8 -0
  64. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.d.ts.map +1 -0
  65. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.d.ts +5 -0
  66. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.d.ts.map +1 -0
  67. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.d.ts +6 -0
  68. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.d.ts.map +1 -0
  69. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-candidate-names.d.ts +4 -0
  70. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-candidate-names.d.ts.map +1 -0
  71. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts +4 -0
  72. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts.map +1 -0
  73. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts +4 -0
  74. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts.map +1 -0
  75. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts +8 -0
  76. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts.map +1 -0
  77. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-type-dependencies.d.ts +3 -0
  78. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-type-dependencies.d.ts.map +1 -0
  79. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.d.ts +7 -0
  80. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.d.ts.map +1 -0
  81. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/read-chain-text.util.d.ts +4 -0
  82. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/read-chain-text.util.d.ts.map +1 -0
  83. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.util.d.ts +2 -0
  84. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.util.d.ts.map +1 -0
  85. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.d.ts +4 -0
  86. package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.d.ts.map +1 -0
  87. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts +3 -0
  88. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts.map +1 -0
  89. package/lib/rules/no-unused-angular-instance-fields/{utils/angular-expression-reads.util.d.ts → rule/angular/angular-expression-reads.d.ts} +1 -1
  90. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.d.ts.map +1 -0
  91. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts +9 -0
  92. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts.map +1 -0
  93. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts +5 -0
  94. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts.map +1 -0
  95. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.d.ts +6 -0
  96. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.d.ts.map +1 -0
  97. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.d.ts +5 -0
  98. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.d.ts.map +1 -0
  99. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.d.ts +9 -0
  100. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.d.ts.map +1 -0
  101. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.d.ts +4 -0
  102. package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.d.ts.map +1 -0
  103. package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts +54 -0
  104. package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts.map +1 -0
  105. package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts +8 -0
  106. package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts.map +1 -0
  107. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts +4 -0
  108. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts.map +1 -0
  109. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.d.ts +8 -0
  110. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.d.ts.map +1 -0
  111. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-lexical-this.d.ts +3 -0
  112. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-lexical-this.d.ts.map +1 -0
  113. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.d.ts +3 -0
  114. package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.d.ts.map +1 -0
  115. package/lib/rules/no-unused-angular-instance-fields/utils/angular-read-target.util.d.ts +4 -0
  116. package/lib/rules/no-unused-angular-instance-fields/utils/angular-read-target.util.d.ts.map +1 -0
  117. package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts +6 -0
  118. package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts.map +1 -0
  119. package/lib/typescript-consistency.d.ts +2 -0
  120. package/lib/typescript-consistency.d.ts.map +1 -0
  121. package/lib/typescript-imports.d.ts +2 -0
  122. package/lib/typescript-imports.d.ts.map +1 -0
  123. package/lib/typescript-local-plugin.d.ts +2 -0
  124. package/lib/typescript-local-plugin.d.ts.map +1 -0
  125. package/lib/typescript-overrides.d.ts +2 -0
  126. package/lib/typescript-overrides.d.ts.map +1 -0
  127. package/lib/typescript-recommended.d.ts +2 -0
  128. package/lib/typescript-recommended.d.ts.map +1 -0
  129. package/lib/typescript-safety.d.ts +2 -0
  130. package/lib/typescript-safety.d.ts.map +1 -0
  131. package/lib/typescript.d.ts +1 -0
  132. package/lib/typescript.d.ts.map +1 -1
  133. package/package.json +18 -14
  134. package/lib/rules/explicit-accessibility.d.ts +0 -12
  135. package/lib/rules/explicit-accessibility.d.ts.map +0 -1
  136. package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts +0 -8
  137. package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts.map +0 -1
  138. package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts +0 -3
  139. package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts.map +0 -1
  140. package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts +0 -10
  141. package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts.map +0 -1
  142. package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts +0 -7
  143. package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts.map +0 -1
  144. package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts +0 -2
  145. package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts.map +0 -1
  146. package/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.d.ts.map +0 -1
  147. package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts +0 -7
  148. package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts.map +0 -1
package/eslint.cjs CHANGED
@@ -52,10 +52,7 @@ var import_config = require("eslint/config");
52
52
  var angularTemplate = (0, import_config.defineConfig)([
53
53
  {
54
54
  files: ["**/*.html"],
55
- extends: [
56
- ...import_angular_eslint.configs.templateAccessibility,
57
- ...import_angular_eslint.configs.templateRecommended
58
- ],
55
+ extends: [...import_angular_eslint.configs.templateAccessibility, ...import_angular_eslint.configs.templateRecommended],
59
56
  rules: {
60
57
  "@angular-eslint/template/prefer-template-literal": "error",
61
58
  "@angular-eslint/template/no-any": "error",
@@ -124,50 +121,343 @@ var angularTemplate = (0, import_config.defineConfig)([
124
121
  ]);
125
122
 
126
123
  // packages/lint-suite/src/lib/angular.ts
127
- var import_globals = __toESM(require("globals"), 1);
128
124
  var import_angular_eslint2 = require("angular-eslint");
129
125
  var import_config2 = require("eslint/config");
126
+ var import_globals = __toESM(require("globals"), 1);
130
127
 
131
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
132
- var import_utils4 = require("@typescript-eslint/utils");
128
+ // packages/lint-suite/src/lib/rules/define-plugin.util.ts
129
+ var definePlugin = (name, rules) => {
130
+ const meta5 = { name };
131
+ const plugin = { meta: meta5, rules };
132
+ return plugin;
133
+ };
134
+
135
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.ts
136
+ var import_utils10 = require("@typescript-eslint/utils");
137
+
138
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.ts
139
+ var import_utils = require("@typescript-eslint/utils");
140
+ var calleeRoot = (node) => {
141
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) return node;
142
+ if (node.type !== import_utils.TSESTree.AST_NODE_TYPES.MemberExpression || node.object.type === import_utils.TSESTree.AST_NODE_TYPES.Super) {
143
+ return void 0;
144
+ }
145
+ return calleeRoot(node.object);
146
+ };
147
+ var angularName = (node, imports) => {
148
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
149
+ return imports.get(node.name);
150
+ }
151
+ if (node.type !== import_utils.TSESTree.AST_NODE_TYPES.MemberExpression || node.computed || node.property.type !== import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
152
+ return null;
153
+ }
154
+ if (node.object.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier) {
155
+ const namespaceAlias = imports.get(node.object.name);
156
+ if (namespaceAlias === null) return node.property.name;
157
+ }
158
+ return angularName(node.object, imports);
159
+ };
160
+ var isImportBinding = (node, sourceCode) => {
161
+ const root = calleeRoot(node);
162
+ if (!root) return false;
163
+ for (let scope = sourceCode.getScope(root); scope; scope = scope.upper) {
164
+ const variable = scope.set.get(root.name);
165
+ if (variable) return variable.defs[0]?.type === "ImportBinding";
166
+ }
167
+ return false;
168
+ };
169
+ var addAngularImport = (node, imports) => {
170
+ if (node.source.value !== "@angular/core" || node.importKind === "type") {
171
+ return;
172
+ }
173
+ for (const specifier of node.specifiers) {
174
+ if (specifier.type === import_utils.TSESTree.AST_NODE_TYPES.ImportNamespaceSpecifier) {
175
+ imports.set(specifier.local.name, null);
176
+ } else if (specifier.type === import_utils.TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type") {
177
+ const { imported } = specifier;
178
+ const isIdentifier8 = imported.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier;
179
+ const importedName = isIdentifier8 ? imported.name : imported.value;
180
+ imports.set(specifier.local.name, importedName);
181
+ }
182
+ }
183
+ };
184
+ var angularClassMetadata = (node, imports) => {
185
+ for (const decorator of node.decorators) {
186
+ if (decorator.expression.type !== import_utils.TSESTree.AST_NODE_TYPES.CallExpression) {
187
+ continue;
188
+ }
189
+ const kind = angularName(decorator.expression.callee, imports);
190
+ const metadata = decorator.expression.arguments.at(0);
191
+ const isComponentOrDirective = kind === "Component" || kind === "Directive";
192
+ if (isComponentOrDirective && metadata?.type === import_utils.TSESTree.AST_NODE_TYPES.ObjectExpression) {
193
+ const classMetadata = {
194
+ component: kind === "Component",
195
+ metadata
196
+ };
197
+ return classMetadata;
198
+ }
199
+ }
200
+ return null;
201
+ };
202
+ var angularClassImports = (ast) => {
203
+ const imports = /* @__PURE__ */ new Map();
204
+ for (const node of ast.body) {
205
+ if (node.type === import_utils.TSESTree.AST_NODE_TYPES.ImportDeclaration) {
206
+ addAngularImport(node, imports);
207
+ }
208
+ }
209
+ for (const imported of imports.values()) {
210
+ const isNamespaceImport = imported === null;
211
+ const isComponent = imported === "Component";
212
+ const isDirective = imported === "Directive";
213
+ const isAngularClassImport = isNamespaceImport || isComponent || isDirective;
214
+ if (isAngularClassImport) return imports;
215
+ }
216
+ return null;
217
+ };
218
+
219
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.ts
220
+ var import_utils3 = require("@typescript-eslint/utils");
133
221
 
134
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
222
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.ts
135
223
  var import_utils2 = require("@typescript-eslint/utils");
224
+ var managedApis = /* @__PURE__ */ new Set([
225
+ "input",
226
+ "model",
227
+ "output",
228
+ "viewChild",
229
+ "viewChildren",
230
+ "contentChild",
231
+ "contentChildren"
232
+ ]);
233
+ var hasAutomaticEffectCleanup = (node) => {
234
+ const options = node.arguments.at(1);
235
+ if (options === void 0) return true;
236
+ if (options.type !== import_utils2.TSESTree.AST_NODE_TYPES.ObjectExpression) return false;
237
+ return options.properties.every((property) => {
238
+ if (property.type !== import_utils2.TSESTree.AST_NODE_TYPES.Property || property.computed) {
239
+ return false;
240
+ }
241
+ 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";
242
+ return !manualCleanup || property.value.type === import_utils2.TSESTree.AST_NODE_TYPES.Literal && property.value.value === false;
243
+ });
244
+ };
245
+ var angularCoreImportedName = (definition) => {
246
+ if (definition?.type !== "ImportBinding") return null;
247
+ if (definition.node.type !== import_utils2.TSESTree.AST_NODE_TYPES.ImportSpecifier) {
248
+ return null;
249
+ }
250
+ if (definition.parent.type !== import_utils2.TSESTree.AST_NODE_TYPES.ImportDeclaration) {
251
+ return null;
252
+ }
253
+ if (definition.parent.source.value !== "@angular/core") return null;
254
+ const { imported } = definition.node;
255
+ if (imported.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
256
+ return imported.name;
257
+ }
258
+ return imported.value;
259
+ };
260
+ var isAngularComponentRefField = (node, sourceCode) => {
261
+ const type = node.typeAnnotation?.typeAnnotation;
262
+ if (type?.type !== import_utils2.TSESTree.AST_NODE_TYPES.TSTypeReference || type.typeName.type !== import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
263
+ return false;
264
+ }
265
+ const reference = sourceCode.getScope(type.typeName).references.find(({ identifier }) => identifier === type.typeName);
266
+ const definition = reference?.resolved?.defs[0];
267
+ return angularCoreImportedName(definition) === "ComponentRef";
268
+ };
269
+ var isManagedField = (node, imports, allowEffectFields, sourceCode) => {
270
+ if (node.value?.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) return false;
271
+ const name = angularName(node.value.callee, imports);
272
+ const isString = typeof name === "string";
273
+ if (!isString) return false;
274
+ const isManagedApi = managedApis.has(name);
275
+ if (isManagedApi) return true;
276
+ if (!allowEffectFields) return false;
277
+ if (name !== "effect") return false;
278
+ const isImported = isImportBinding(node.value.callee, sourceCode);
279
+ if (!isImported) return false;
280
+ return hasAutomaticEffectCleanup(node.value);
281
+ };
136
282
 
137
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
138
- var import_node_fs = require("node:fs");
283
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.ts
284
+ var lifecycleHooks = /* @__PURE__ */ new Set([
285
+ "ngOnChanges",
286
+ "ngOnInit",
287
+ "ngDoCheck",
288
+ "ngAfterContentInit",
289
+ "ngAfterContentChecked",
290
+ "ngAfterViewInit",
291
+ "ngAfterViewChecked",
292
+ "ngOnDestroy"
293
+ ]);
294
+ var formsInterfaceMethods = {
295
+ AsyncValidator: ["validate", "registerOnValidatorChange"],
296
+ ControlValueAccessor: [
297
+ "writeValue",
298
+ "registerOnChange",
299
+ "registerOnTouched",
300
+ "setDisabledState"
301
+ ],
302
+ Validator: ["validate", "registerOnValidatorChange"]
303
+ };
304
+ var isInstanceField = (node) => {
305
+ if (node.type !== import_utils3.TSESTree.AST_NODE_TYPES.PropertyDefinition) return false;
306
+ return node.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Identifier;
307
+ };
308
+ var isInstanceMethod = (node) => {
309
+ if (node.type !== import_utils3.TSESTree.AST_NODE_TYPES.MethodDefinition) return false;
310
+ return node.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Identifier;
311
+ };
312
+ var isExcludedField = (node, localPrivateOnly, sourceCode) => {
313
+ const isModified = node.static || node.declare || node.override;
314
+ const isDecorated = node.decorators.length > 0;
315
+ if (isModified || isDecorated) return true;
316
+ const isComponentRef = isAngularComponentRefField(node, sourceCode);
317
+ if (isComponentRef) return true;
318
+ const isNonPrivate = node.accessibility !== "private";
319
+ return localPrivateOnly && isNonPrivate;
320
+ };
321
+ var isExcludedMethod = (node, localPrivateOnly, implementedMethods) => {
322
+ const isModified = node.static || node.override || node.computed;
323
+ const isDecorated = node.decorators.length > 0;
324
+ const isPlainMethod = node.kind === "method";
325
+ if (isModified || isDecorated || !isPlainMethod) return true;
326
+ const hasNoBody = node.value.body === null;
327
+ const isLifecycleHook = lifecycleHooks.has(node.key.name);
328
+ if (hasNoBody || isLifecycleHook) return true;
329
+ const isImplemented = implementedMethods.has(node.key.name);
330
+ if (isImplemented) return true;
331
+ const isNonPrivate = node.accessibility !== "private";
332
+ return localPrivateOnly && isNonPrivate;
333
+ };
334
+ var implementedFormsMethods = (node) => {
335
+ const methods = /* @__PURE__ */ new Set();
336
+ for (const heritage of node.implements) {
337
+ if (heritage.expression.type !== import_utils3.TSESTree.AST_NODE_TYPES.Identifier) {
338
+ continue;
339
+ }
340
+ for (const name of formsInterfaceMethods[heritage.expression.name] ?? []) {
341
+ methods.add(name);
342
+ }
343
+ }
344
+ return methods;
345
+ };
346
+ var fieldCandidate = (node, options) => {
347
+ const isField = isInstanceField(node);
348
+ if (!isField) return null;
349
+ const { localPrivateOnly, sourceCode } = options;
350
+ const isExcluded = isExcludedField(node, localPrivateOnly, sourceCode);
351
+ if (isExcluded) return null;
352
+ const isManaged = isManagedField(
353
+ node,
354
+ options.imports,
355
+ options.allowEffectFields,
356
+ sourceCode
357
+ );
358
+ if (isManaged) return null;
359
+ const unusedFieldCandidate = {
360
+ messageId: "unusedField",
361
+ name: node.key.name,
362
+ node
363
+ };
364
+ return unusedFieldCandidate;
365
+ };
366
+ var methodCandidate = (node, localPrivateOnly, implementedMethods) => {
367
+ const isMethod = isInstanceMethod(node);
368
+ if (!isMethod) return null;
369
+ const isExcluded = isExcludedMethod(
370
+ node,
371
+ localPrivateOnly,
372
+ implementedMethods
373
+ );
374
+ if (isExcluded) return null;
375
+ const unusedMethodCandidate = {
376
+ messageId: "unusedMethod",
377
+ name: node.key.name,
378
+ node
379
+ };
380
+ return unusedMethodCandidate;
381
+ };
382
+
383
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
139
384
  var import_node_path = require("node:path");
385
+ var import_utils5 = require("@typescript-eslint/utils");
386
+
387
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.ts
388
+ var import_utils4 = require("@typescript-eslint/utils");
389
+ var text = (node) => {
390
+ if (node?.type === import_utils4.TSESTree.AST_NODE_TYPES.Literal && typeof node.value === "string") {
391
+ return node.value;
392
+ }
393
+ if (node?.type !== import_utils4.TSESTree.AST_NODE_TYPES.TemplateLiteral) return null;
394
+ const hasExpressions = node.expressions.length > 0;
395
+ if (hasExpressions) return null;
396
+ return node.quasis[0].value.cooked;
397
+ };
398
+ var key = (property) => {
399
+ if (property.type !== import_utils4.TSESTree.AST_NODE_TYPES.Property || property.computed) {
400
+ return null;
401
+ }
402
+ if (property.key.type === import_utils4.TSESTree.AST_NODE_TYPES.Identifier) {
403
+ return property.key.name;
404
+ }
405
+ return text(property.key);
406
+ };
407
+ var metadataValue = (metadata, name) => {
408
+ for (const property of metadata.properties) {
409
+ if (property.type !== import_utils4.TSESTree.AST_NODE_TYPES.Property) continue;
410
+ const propertyKey = key(property);
411
+ if (propertyKey === name) return property.value;
412
+ }
413
+ return void 0;
414
+ };
415
+
416
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.ts
417
+ var import_compiler3 = require("@angular/compiler");
418
+ var import_node_fs = require("node:fs");
419
+
420
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
140
421
  var import_compiler2 = require("@angular/compiler");
141
- var import_utils = require("@typescript-eslint/utils");
142
422
 
143
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.ts
423
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/utils/angular-read-target.util.ts
144
424
  var import_compiler = require("@angular/compiler");
145
- var ReadCollector = class extends import_compiler.CombinedRecursiveAstVisitor {
425
+ var isReadTarget = (node) => {
426
+ const isPropertyRead = node instanceof import_compiler.PropertyRead;
427
+ const isSafePropertyRead = node instanceof import_compiler.SafePropertyRead;
428
+ const isKeyedRead = node instanceof import_compiler.KeyedRead;
429
+ const isSafeKeyedRead = node instanceof import_compiler.SafeKeyedRead;
430
+ return isPropertyRead || isSafePropertyRead || isKeyedRead || isSafeKeyedRead;
431
+ };
432
+
433
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
434
+ var ReadCollector = class extends import_compiler2.CombinedRecursiveAstVisitor {
435
+ reads = /* @__PURE__ */ new Set();
436
+ boundTarget;
437
+ action;
146
438
  constructor(boundTarget, action) {
147
439
  super();
148
440
  this.boundTarget = boundTarget;
149
441
  this.action = action;
150
442
  }
151
- boundTarget;
152
- action;
153
- reads = /* @__PURE__ */ new Set();
154
443
  record(node) {
155
- if (node.receiver instanceof import_compiler.ThisReceiver) {
444
+ if (node.receiver instanceof import_compiler2.ThisReceiver) {
156
445
  this.reads.add(node.name);
157
446
  return;
158
447
  }
159
- if (node.receiver instanceof import_compiler.ImplicitReceiver && (!this.action || node.name !== "$event") && !this.boundTarget?.getExpressionTarget(node)) {
160
- this.reads.add(node.name);
161
- }
448
+ if (!(node.receiver instanceof import_compiler2.ImplicitReceiver)) return;
449
+ const isBindableName = !this.action || node.name !== "$event";
450
+ if (!isBindableName) return;
451
+ const expressionTarget = this.boundTarget?.getExpressionTarget(node);
452
+ if (expressionTarget) return;
453
+ this.reads.add(node.name);
162
454
  }
163
455
  visitBinary(node, context) {
164
- if (node.operation !== "=") {
165
- return super.visitBinary(node, context);
166
- }
167
- if (node.left instanceof import_compiler.PropertyRead || node.left instanceof import_compiler.SafePropertyRead || node.left instanceof import_compiler.KeyedRead || node.left instanceof import_compiler.SafeKeyedRead) {
456
+ if (node.operation !== "=") return super.visitBinary(node, context);
457
+ if (isReadTarget(node.left)) {
168
458
  this.visit(node.left.receiver);
169
459
  }
170
- if (node.left instanceof import_compiler.KeyedRead || node.left instanceof import_compiler.SafeKeyedRead) {
460
+ if (node.left instanceof import_compiler2.KeyedRead || node.left instanceof import_compiler2.SafeKeyedRead) {
171
461
  this.visit(node.left.key);
172
462
  }
173
463
  this.visit(node.right);
@@ -190,22 +480,14 @@ var collectAngularExpressionReads = (nodes, boundTarget, action) => {
190
480
  return collector.reads;
191
481
  };
192
482
 
193
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.ts
483
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.ts
194
484
  var externalTemplates = /* @__PURE__ */ new Map();
195
- var parser = new import_compiler2.Parser(new import_compiler2.Lexer());
196
- var templateBinder = new import_compiler2.R3TargetBinder(null);
197
- var text = (node) => {
198
- if (node?.type === import_utils.TSESTree.AST_NODE_TYPES.Literal && typeof node.value === "string") {
199
- return node.value;
200
- }
201
- return node?.type === import_utils.TSESTree.AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0 ? node.quasis[0].value.cooked : null;
202
- };
485
+ var parser = new import_compiler3.Parser(new import_compiler3.Lexer());
486
+ var templateBinder = new import_compiler3.R3TargetBinder(null);
203
487
  var templateReads = (template, filename) => {
204
488
  try {
205
- const result = (0, import_compiler2.parseTemplate)(template, filename);
206
- if (result.errors?.length) {
207
- return null;
208
- }
489
+ const result = (0, import_compiler3.parseTemplate)(template, filename);
490
+ if (result.errors?.length) return null;
209
491
  return collectAngularExpressionReads(
210
492
  result.nodes,
211
493
  templateBinder.bind({ template: result.nodes }),
@@ -220,9 +502,7 @@ var externalTemplateReads = (filename) => {
220
502
  const stats = (0, import_node_fs.statSync)(filename, { bigint: true });
221
503
  const version = `${stats.mtimeNs}:${stats.size}`;
222
504
  const cached = externalTemplates.get(filename);
223
- if (cached?.version === version) {
224
- return cached.reads;
225
- }
505
+ if (cached?.version === version) return cached.reads;
226
506
  const reads = templateReads((0, import_node_fs.readFileSync)(filename, "utf8"), filename);
227
507
  externalTemplates.set(filename, { reads, version });
228
508
  return reads;
@@ -230,82 +510,66 @@ var externalTemplateReads = (filename) => {
230
510
  return null;
231
511
  }
232
512
  };
513
+ var parseExpression = (expression, span, action) => {
514
+ if (action) return parser.parseAction(expression, span, 0);
515
+ return parser.parseBinding(expression, span, 0);
516
+ };
233
517
  var expressionReads = (expression, filename, action) => {
234
518
  try {
235
- const file = new import_compiler2.ParseSourceFile(expression, filename);
236
- const start = new import_compiler2.ParseLocation(file, 0, 0, 0);
237
- const span = new import_compiler2.ParseSourceSpan(start, start.moveBy(expression.length));
238
- const result = action ? parser.parseAction(expression, span, 0) : parser.parseBinding(expression, span, 0);
239
- if (result.errors.length > 0) {
240
- return null;
241
- }
519
+ const file = new import_compiler3.ParseSourceFile(expression, filename);
520
+ const start = new import_compiler3.ParseLocation(file, 0, 0, 0);
521
+ const span = new import_compiler3.ParseSourceSpan(start, start.moveBy(expression.length));
522
+ const result = parseExpression(expression, span, action);
523
+ if (result.errors.length > 0) return null;
242
524
  return collectAngularExpressionReads([result], void 0, action);
243
525
  } catch {
244
526
  return null;
245
527
  }
246
528
  };
529
+
530
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
247
531
  var addReads = (target, source) => {
248
- if (!source) {
249
- return false;
250
- }
532
+ if (!source) return false;
251
533
  for (const name of source) {
252
534
  target.add(name);
253
535
  }
254
536
  return true;
255
537
  };
256
- var key = (property) => {
257
- if (property.type !== import_utils.TSESTree.AST_NODE_TYPES.Property || property.computed) {
258
- return null;
259
- }
260
- return property.key.type === import_utils.TSESTree.AST_NODE_TYPES.Identifier ? property.key.name : text(property.key);
261
- };
262
- var metadataValue = (metadata, name) => {
263
- for (const property of metadata.properties) {
264
- if (property.type === import_utils.TSESTree.AST_NODE_TYPES.Property && key(property) === name) {
265
- return property.value;
266
- }
267
- }
268
- return void 0;
269
- };
270
538
  var hostPropertyReads = (property, reads, filename) => {
271
539
  const name = key(property);
272
540
  const expression = text(property.value);
273
- if (name === null || expression === null) {
274
- return false;
275
- }
276
- if (name.startsWith("[")) {
541
+ if (name === null || expression === null) return false;
542
+ const isPropertyBinding = name.startsWith("[");
543
+ if (isPropertyBinding) {
277
544
  return addReads(reads, expressionReads(expression, filename, false));
278
545
  }
279
- if (name.startsWith("(")) {
546
+ const isEventBinding = name.startsWith("(");
547
+ if (isEventBinding) {
280
548
  return addReads(reads, expressionReads(expression, filename, true));
281
549
  }
282
550
  return true;
283
551
  };
284
552
  var hostReads = (host, reads, filename) => {
285
- if (!host) {
286
- return true;
287
- }
288
- if (host.type !== import_utils.TSESTree.AST_NODE_TYPES.ObjectExpression || host.properties.some((property) => key(property) === null)) {
289
- return false;
290
- }
553
+ if (!host) return true;
554
+ if (host.type !== import_utils5.TSESTree.AST_NODE_TYPES.ObjectExpression) return false;
555
+ const hasUnreadableKey = host.properties.some(
556
+ (property) => key(property) === null
557
+ );
558
+ if (hasUnreadableKey) return false;
291
559
  for (const property of host.properties) {
292
- if (property.type !== import_utils.TSESTree.AST_NODE_TYPES.Property || !hostPropertyReads(property, reads, filename)) {
293
- return false;
294
- }
560
+ if (property.type !== import_utils5.TSESTree.AST_NODE_TYPES.Property) return false;
561
+ const hasPropertyReads = hostPropertyReads(property, reads, filename);
562
+ if (!hasPropertyReads) return false;
295
563
  }
296
564
  return true;
297
565
  };
298
566
  var inlineTemplateReads = (template, reads, filename) => {
299
- if (!template) {
300
- return true;
301
- }
567
+ if (!template) return true;
302
568
  const source = text(template);
303
569
  return source !== null && addReads(reads, templateReads(source, filename));
304
570
  };
305
571
  var externalTemplatePropertyReads = (templateUrl, reads, filename) => {
306
- if (!templateUrl) {
307
- return true;
308
- }
572
+ if (!templateUrl) return true;
309
573
  const url = text(templateUrl);
310
574
  return url !== null && addReads(reads, externalTemplateReads((0, import_node_path.resolve)((0, import_node_path.dirname)(filename), url)));
311
575
  };
@@ -314,156 +578,113 @@ var componentTemplateReads = (metadata, reads, filename) => {
314
578
  const templateUrl = metadataValue(metadata, "templateUrl");
315
579
  return inlineTemplateReads(template, reads, filename) && externalTemplatePropertyReads(templateUrl, reads, filename);
316
580
  };
317
- var metadataReads = (metadata, component, filename, remainingNames) => {
318
- if (metadata.properties.some((property) => key(property) === null)) {
319
- return null;
320
- }
581
+ var metadataReads = (options) => {
582
+ const { filename, metadata } = options;
583
+ const isUnreadableKey = (property) => {
584
+ return key(property) === null;
585
+ };
586
+ const hasUnreadableKey = metadata.properties.some(isUnreadableKey);
587
+ if (hasUnreadableKey) return null;
321
588
  const reads = /* @__PURE__ */ new Set();
322
- if (!hostReads(metadataValue(metadata, "host"), reads, filename)) {
323
- return null;
324
- }
325
- if (component && remainingNames.every((name) => reads.has(name)) || !component || componentTemplateReads(metadata, reads, filename)) {
326
- return reads;
327
- }
589
+ const hostValue = metadataValue(metadata, "host");
590
+ const hasHostReads = hostReads(hostValue, reads, filename);
591
+ if (!hasHostReads) return null;
592
+ if (!options.component) return reads;
593
+ const isRead = (name) => reads.has(name);
594
+ const hasRemainingReads = options.remainingNames.every(isRead);
595
+ if (hasRemainingReads) return reads;
596
+ const hasTemplateReads = componentTemplateReads(metadata, reads, filename);
597
+ if (hasTemplateReads) return reads;
598
+ if (!options.requireTemplate) return reads;
328
599
  return null;
329
600
  };
330
601
 
331
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/angular-class-fields.ts
332
- var managedApis = {
333
- input: true,
334
- model: true,
335
- output: true
336
- };
337
- var angularName = (node, imports) => {
338
- if (node.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
339
- return imports.get(node.name);
340
- }
341
- if (node.type !== import_utils2.TSESTree.AST_NODE_TYPES.MemberExpression || node.computed || node.property.type !== import_utils2.TSESTree.AST_NODE_TYPES.Identifier) {
342
- return null;
343
- }
344
- if (node.object.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier && imports.get(node.object.name) === null) {
345
- return node.property.name;
346
- }
347
- return angularName(node.object, imports);
348
- };
349
- var angularClass = (node, imports) => {
350
- for (const decorator of node.decorators) {
351
- if (decorator.expression.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
352
- continue;
353
- }
354
- const kind = angularName(decorator.expression.callee, imports);
355
- const metadata = decorator.expression.arguments[0];
356
- if ((kind === "Component" || kind === "Directive") && metadata?.type === import_utils2.TSESTree.AST_NODE_TYPES.ObjectExpression) {
357
- return {
358
- component: kind === "Component",
359
- metadata
360
- };
602
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.ts
603
+ var memberCandidates = (node, options) => {
604
+ const implementedMethods = implementedFormsMethods(node);
605
+ const members = [];
606
+ for (const element of node.body.body) {
607
+ const candidate = fieldCandidate(element, options) ?? methodCandidate(element, options.localPrivateOnly, implementedMethods);
608
+ if (candidate) {
609
+ members.push(candidate);
361
610
  }
362
611
  }
363
- return null;
364
- };
365
- var isInstanceField = (node) => node.type === import_utils2.TSESTree.AST_NODE_TYPES.PropertyDefinition && node.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier;
366
- var lifecycleHooks = {
367
- ngOnChanges: true,
368
- ngOnInit: true,
369
- ngDoCheck: true,
370
- ngAfterContentInit: true,
371
- ngAfterContentChecked: true,
372
- ngAfterViewInit: true,
373
- ngAfterViewChecked: true,
374
- ngOnDestroy: true
375
- };
376
- var isInstanceMethod = (node) => node.type === import_utils2.TSESTree.AST_NODE_TYPES.MethodDefinition && node.key.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier;
377
- var isExcludedField = (node, component) => node.static || node.declare || node.override || node.decorators.length > 0 || !component && node.accessibility !== "private";
378
- var isManagedField = (node, imports) => {
379
- if (node.value?.type !== import_utils2.TSESTree.AST_NODE_TYPES.CallExpression) {
380
- return false;
381
- }
382
- const name = angularName(node.value.callee, imports);
383
- return typeof name === "string" && managedApis[name] === true;
612
+ return members;
384
613
  };
385
- var field = (node, imports, component) => {
386
- if (isInstanceField(node) && !isExcludedField(node, component) && !isManagedField(node, imports)) {
387
- return { messageId: "unusedField", name: node.key.name, node };
388
- }
389
- return null;
614
+ var reportMember = (context, candidate) => {
615
+ const data = { name: candidate.name };
616
+ const report = {
617
+ data,
618
+ messageId: candidate.messageId,
619
+ node: candidate.node.key
620
+ };
621
+ context.report(report);
390
622
  };
391
- var isExcludedMethod = (node, component) => node.static || node.override || node.decorators.length > 0 || node.computed || node.kind !== "method" || node.value.body === null || lifecycleHooks[node.key.name] === true || !component && node.accessibility !== "private";
392
- var method = (node, component) => {
393
- if (isInstanceMethod(node) && !isExcludedMethod(node, component)) {
394
- return { messageId: "unusedMethod", name: node.key.name, node };
623
+ var reportUnreadMembers = (members, reads, options) => {
624
+ for (const candidate of members) {
625
+ const isTemplateRead = reads.has(candidate.name);
626
+ if (isTemplateRead) continue;
627
+ const isProjectUsed = options.projectMemberUsed?.(candidate.node) === true;
628
+ if (isProjectUsed) continue;
629
+ reportMember(options.context, candidate);
395
630
  }
396
- return null;
397
631
  };
398
- var addAngularImport = (node, imports) => {
399
- if (node.source.value !== "@angular/core" || node.importKind === "type") {
400
- return;
401
- }
402
- for (const specifier of node.specifiers) {
403
- if (specifier.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportNamespaceSpecifier) {
404
- imports.set(specifier.local.name, null);
405
- } else if (specifier.type === import_utils2.TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type") {
406
- const importedName = specifier.imported.type === import_utils2.TSESTree.AST_NODE_TYPES.Identifier ? specifier.imported.name : specifier.imported.value;
407
- imports.set(specifier.local.name, importedName);
408
- }
409
- }
632
+ var reportClassMembers = (entry, ngClass, report) => {
633
+ const { options, projectAnalysis } = report;
634
+ const isLocalOnlyClass = !ngClass.component || entry.node.abstract === true;
635
+ const candidateOptions = {
636
+ allowEffectFields: options.allowEffectFields,
637
+ imports: options.imports,
638
+ localPrivateOnly: !projectAnalysis && isLocalOnlyClass,
639
+ sourceCode: options.context.sourceCode
640
+ };
641
+ const members = memberCandidates(entry.node, candidateOptions);
642
+ const unreadMembers = members.filter(
643
+ (candidate) => !entry.reads.has(candidate.name)
644
+ );
645
+ if (unreadMembers.length === 0) return;
646
+ const remainingNames = unreadMembers.map((candidate) => candidate.name);
647
+ const readsOptions = {
648
+ component: ngClass.component && report.localTemplates,
649
+ filename: options.context.filename,
650
+ metadata: ngClass.metadata,
651
+ remainingNames,
652
+ requireTemplate: !projectAnalysis
653
+ };
654
+ const reads = metadataReads(readsOptions);
655
+ if (!reads) return;
656
+ reportUnreadMembers(unreadMembers, reads, options);
410
657
  };
411
- var reportUnusedMembers = (context, imports, classes, dynamicClasses) => {
412
- for (const entry of classes) {
413
- const ngClass = angularClass(entry.node, imports);
414
- if (!ngClass || dynamicClasses.has(entry)) {
415
- continue;
416
- }
417
- const members = [];
418
- for (const node of entry.node.body.body) {
419
- const candidate = field(node, imports, ngClass.component) ?? method(node, ngClass.component);
420
- if (candidate) {
421
- members.push(candidate);
422
- }
423
- }
424
- if (members.length === 0) {
425
- continue;
426
- }
427
- const unreadMembers = members.filter(
428
- (candidate) => !entry.reads.has(candidate.name)
429
- );
430
- if (unreadMembers.length === 0) {
431
- continue;
432
- }
433
- const reads = metadataReads(
434
- ngClass.metadata,
435
- ngClass.component,
436
- context.filename,
437
- unreadMembers.map((candidate) => candidate.name)
438
- );
439
- if (!reads) {
440
- continue;
441
- }
442
- for (const candidate of unreadMembers) {
443
- if (!reads.has(candidate.name)) {
444
- context.report({
445
- data: { name: candidate.name },
446
- messageId: candidate.messageId,
447
- node: candidate.node.key
448
- });
449
- }
450
- }
658
+ var reportUnusedMembers = (options) => {
659
+ const projectAnalysis = options.projectMemberUsed !== void 0;
660
+ const localTemplates = !projectAnalysis || !options.projectIndexed();
661
+ const report = {
662
+ localTemplates,
663
+ options,
664
+ projectAnalysis
665
+ };
666
+ for (const entry of options.classes) {
667
+ const ngClass = angularClassMetadata(entry.node, options.imports);
668
+ const isDynamicClass = options.dynamicClasses.has(entry);
669
+ if (!ngClass || isDynamicClass) continue;
670
+ reportClassMembers(entry, ngClass, report);
451
671
  }
452
672
  };
453
673
 
454
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.ts
455
- var import_utils3 = require("@typescript-eslint/utils");
674
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.ts
675
+ var import_utils9 = require("@typescript-eslint/utils");
676
+
677
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.ts
678
+ var import_utils6 = require("@typescript-eslint/utils");
679
+ var expressionWrapperTypes = /* @__PURE__ */ new Set([
680
+ import_utils6.TSESTree.AST_NODE_TYPES.TSAsExpression,
681
+ import_utils6.TSESTree.AST_NODE_TYPES.TSInstantiationExpression,
682
+ import_utils6.TSESTree.AST_NODE_TYPES.TSNonNullExpression,
683
+ import_utils6.TSESTree.AST_NODE_TYPES.TSSatisfiesExpression,
684
+ import_utils6.TSESTree.AST_NODE_TYPES.TSTypeAssertion
685
+ ]);
456
686
  var isTypeScriptExpressionWrapper = (node) => {
457
- switch (node.type) {
458
- case import_utils3.TSESTree.AST_NODE_TYPES.TSAsExpression:
459
- case import_utils3.TSESTree.AST_NODE_TYPES.TSInstantiationExpression:
460
- case import_utils3.TSESTree.AST_NODE_TYPES.TSNonNullExpression:
461
- case import_utils3.TSESTree.AST_NODE_TYPES.TSSatisfiesExpression:
462
- case import_utils3.TSESTree.AST_NODE_TYPES.TSTypeAssertion:
463
- return true;
464
- default:
465
- return false;
466
- }
687
+ return expressionWrapperTypes.has(node.type);
467
688
  };
468
689
  var unwrapTypeScriptExpression = (node) => {
469
690
  let current = node;
@@ -472,123 +693,215 @@ var unwrapTypeScriptExpression = (node) => {
472
693
  }
473
694
  return current;
474
695
  };
475
- var isThisExpression = (node) => unwrapTypeScriptExpression(node)?.type === import_utils3.TSESTree.AST_NODE_TYPES.ThisExpression;
476
- var isPatternTarget = (parent, child) => {
477
- switch (parent?.type) {
478
- case import_utils3.TSESTree.AST_NODE_TYPES.ArrayPattern:
479
- return parent.elements.some((element) => element === child);
480
- case import_utils3.TSESTree.AST_NODE_TYPES.AssignmentPattern:
481
- return parent.left === child;
482
- case import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern:
483
- return parent.properties.some((property) => property === child);
484
- case import_utils3.TSESTree.AST_NODE_TYPES.Property:
485
- return parent.value === child && parent.parent.type === import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern;
486
- case import_utils3.TSESTree.AST_NODE_TYPES.RestElement:
487
- return parent.argument === child;
488
- default:
489
- return false;
490
- }
491
- };
492
- var isSimpleAssignmentTarget = (parent, current) => parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.AssignmentExpression && parent.left === current && parent.operator === "=";
493
- var isLoopTarget = (parent, current) => (parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.ForInStatement || parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.ForOfStatement) && parent.left === current;
494
- var isDirectWrite = (node) => {
495
- let current = node;
496
- let parent = node.parent;
497
- while (parent && isTypeScriptExpressionWrapper(parent) && parent.expression === current) {
498
- current = parent;
499
- parent = parent.parent;
500
- }
501
- return isSimpleAssignmentTarget(parent, current) || parent?.type === import_utils3.TSESTree.AST_NODE_TYPES.UnaryExpression && parent.operator === "delete";
502
- };
503
- var isDestructuringOrLoopTarget = (node) => {
504
- let current = node;
505
- let parent = node.parent;
506
- let patternTarget = false;
507
- while (parent) {
508
- const wrapper = isTypeScriptExpressionWrapper(parent) && parent.expression === current;
509
- const pattern = isPatternTarget(parent, current);
510
- if (!wrapper && !pattern) {
511
- break;
512
- }
513
- if (pattern) {
514
- patternTarget = true;
515
- }
516
- current = parent;
517
- parent = parent.parent;
518
- }
519
- return patternTarget && isSimpleAssignmentTarget(parent, current) || isLoopTarget(parent, current);
696
+ var isThisExpression = (node) => {
697
+ const unwrapped = unwrapTypeScriptExpression(node);
698
+ return unwrapped?.type === import_utils6.TSESTree.AST_NODE_TYPES.ThisExpression;
520
699
  };
521
- var isWriteOnly = (node) => isDirectWrite(node) || isDestructuringOrLoopTarget(node);
522
700
  var destructuringParts = (node) => {
523
- if (node.type === import_utils3.TSESTree.AST_NODE_TYPES.VariableDeclarator) {
524
- return { pattern: node.id, source: node.init };
701
+ if (node.type === import_utils6.TSESTree.AST_NODE_TYPES.VariableDeclarator) {
702
+ const variableParts = {
703
+ pattern: node.id,
704
+ source: node.init
705
+ };
706
+ return variableParts;
525
707
  }
526
708
  if (node.operator === "=") {
527
- return { pattern: node.left, source: node.right };
709
+ const assignmentParts = {
710
+ pattern: node.left,
711
+ source: node.right
712
+ };
713
+ return assignmentParts;
528
714
  }
529
715
  return null;
530
716
  };
531
717
  var propertyName = (property) => {
532
- if (property.type !== import_utils3.TSESTree.AST_NODE_TYPES.Property || property.computed) {
718
+ if (property.type !== import_utils6.TSESTree.AST_NODE_TYPES.Property || property.computed) {
533
719
  return null;
534
720
  }
535
- if (property.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Identifier) {
721
+ if (property.key.type === import_utils6.TSESTree.AST_NODE_TYPES.Identifier) {
536
722
  return property.key.name;
537
723
  }
538
- return property.key.type === import_utils3.TSESTree.AST_NODE_TYPES.Literal && typeof property.key.value === "string" ? property.key.value : null;
724
+ const { value } = property.key;
725
+ if (typeof value !== "string") return null;
726
+ return value;
539
727
  };
540
728
  var destructuredThisReads = (node) => {
541
729
  const parts = destructuringParts(node);
542
- if (!parts || parts.pattern.type !== import_utils3.TSESTree.AST_NODE_TYPES.ObjectPattern || !isThisExpression(parts.source)) {
730
+ if (!parts) return void 0;
731
+ if (parts.pattern.type !== import_utils6.TSESTree.AST_NODE_TYPES.ObjectPattern) {
543
732
  return void 0;
544
733
  }
734
+ const isThisSource = isThisExpression(parts.source);
735
+ if (!isThisSource) return void 0;
545
736
  const reads = [];
546
737
  for (const property of parts.pattern.properties) {
547
738
  const name = propertyName(property);
548
- if (name === null) {
549
- return null;
550
- }
739
+ if (name === null) return null;
551
740
  reads.push(name);
552
741
  }
553
742
  return reads;
554
743
  };
555
744
 
556
- // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.ts
557
- var createRule = import_utils4.ESLintUtils.RuleCreator(
558
- () => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
559
- );
560
- var enterClass = (node, classes, stack, thisStack) => {
561
- const entry = {
562
- node,
563
- reads: /* @__PURE__ */ new Set()
564
- };
565
- classes.push(entry);
566
- stack.push(entry);
567
- thisStack.push(true);
745
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-lexical-this.ts
746
+ var import_utils7 = require("@typescript-eslint/utils");
747
+ var componentThis = (node, thisStack) => {
748
+ if (node.type === import_utils7.TSESTree.AST_NODE_TYPES.ArrowFunctionExpression) {
749
+ return thisStack.at(-1) ?? false;
750
+ }
751
+ const { parent } = node;
752
+ if (parent.type !== import_utils7.TSESTree.AST_NODE_TYPES.MethodDefinition) return false;
753
+ return !parent.static;
568
754
  };
569
- var componentThis = (node, thisStack) => node.type === import_utils4.TSESTree.AST_NODE_TYPES.ArrowFunctionExpression ? thisStack.at(-1) ?? false : node.parent.type === import_utils4.TSESTree.AST_NODE_TYPES.MethodDefinition && !node.parent.static;
570
- var trackMemberRead = (node, stack, thisStack, dynamicClasses) => {
571
- const current = stack.at(-1);
572
- if (!current || !thisStack.at(-1)) {
573
- return;
574
- }
575
- const receiverIsThis = isThisExpression(node.object);
576
- if (node.computed && receiverIsThis) {
577
- dynamicClasses.add(current);
755
+ var lexicalThisVisitor = (thisStack) => {
756
+ const listeners = {
757
+ FunctionDeclaration(node) {
758
+ thisStack.push(componentThis(node, thisStack));
759
+ },
760
+ FunctionExpression(node) {
761
+ thisStack.push(componentThis(node, thisStack));
762
+ },
763
+ ArrowFunctionExpression(node) {
764
+ thisStack.push(componentThis(node, thisStack));
765
+ },
766
+ "FunctionDeclaration:exit"() {
767
+ thisStack.pop();
768
+ },
769
+ "FunctionExpression:exit"() {
770
+ thisStack.pop();
771
+ },
772
+ "ArrowFunctionExpression:exit"() {
773
+ thisStack.pop();
774
+ },
775
+ StaticBlock() {
776
+ thisStack.push(false);
777
+ },
778
+ "StaticBlock:exit"() {
779
+ thisStack.pop();
780
+ },
781
+ PropertyDefinition(node) {
782
+ if (node.static) {
783
+ thisStack.push(false);
784
+ }
785
+ },
786
+ "PropertyDefinition:exit"(node) {
787
+ if (node.static) {
788
+ thisStack.pop();
789
+ }
790
+ }
791
+ };
792
+ return listeners;
793
+ };
794
+
795
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.ts
796
+ var import_utils8 = require("@typescript-eslint/utils");
797
+ var parentOf = (node) => {
798
+ if (node.type === import_utils8.TSESTree.AST_NODE_TYPES.Program) return void 0;
799
+ return node.parent;
800
+ };
801
+ var isPatternTarget = (parent, child) => {
802
+ if (parent === void 0) return false;
803
+ if (parent.type === import_utils8.TSESTree.AST_NODE_TYPES.ArrayPattern) {
804
+ return parent.elements.some((element) => element === child);
805
+ }
806
+ if (parent.type === import_utils8.TSESTree.AST_NODE_TYPES.AssignmentPattern) {
807
+ return parent.left === child;
808
+ }
809
+ if (parent.type === import_utils8.TSESTree.AST_NODE_TYPES.ObjectPattern) {
810
+ return parent.properties.some((property) => property === child);
811
+ }
812
+ if (parent.type === import_utils8.TSESTree.AST_NODE_TYPES.Property) {
813
+ const isObjectPattern = parent.parent.type === import_utils8.TSESTree.AST_NODE_TYPES.ObjectPattern;
814
+ return parent.value === child && isObjectPattern;
815
+ }
816
+ if (parent.type === import_utils8.TSESTree.AST_NODE_TYPES.RestElement) {
817
+ return parent.argument === child;
818
+ }
819
+ return false;
820
+ };
821
+ var isSimpleAssignmentTarget = (parent, current) => {
822
+ if (parent?.type !== import_utils8.TSESTree.AST_NODE_TYPES.AssignmentExpression) {
823
+ return false;
824
+ }
825
+ return parent.left === current && parent.operator === "=";
826
+ };
827
+ var isLoopTarget = (parent, current) => {
828
+ const isForIn = parent?.type === import_utils8.TSESTree.AST_NODE_TYPES.ForInStatement;
829
+ const isForOf = parent?.type === import_utils8.TSESTree.AST_NODE_TYPES.ForOfStatement;
830
+ const isLoop = isForIn || isForOf;
831
+ if (!isLoop) return false;
832
+ return parent.left === current;
833
+ };
834
+ var isWrapping = (parent, child) => {
835
+ const isWrapper = isTypeScriptExpressionWrapper(parent);
836
+ if (!isWrapper) return false;
837
+ return parent.expression === child;
838
+ };
839
+ var isDirectWrite = (node) => {
840
+ let current = node;
841
+ let parent = parentOf(node);
842
+ while (parent && isTypeScriptExpressionWrapper(parent) && parent.expression === current) {
843
+ current = parent;
844
+ parent = parentOf(parent);
845
+ }
846
+ const isDeleteExpression2 = parent?.type === import_utils8.TSESTree.AST_NODE_TYPES.UnaryExpression && parent.operator === "delete";
847
+ const isAssignment = isSimpleAssignmentTarget(parent, current);
848
+ return isAssignment || isDeleteExpression2;
849
+ };
850
+ var isDestructuringOrLoopTarget = (node) => {
851
+ let current = node;
852
+ let parent = parentOf(node);
853
+ let patternTarget = false;
854
+ while (parent) {
855
+ const wrapper = isWrapping(parent, current);
856
+ const pattern = isPatternTarget(parent, current);
857
+ if (!wrapper && !pattern) break;
858
+ if (pattern) {
859
+ patternTarget = true;
860
+ }
861
+ current = parent;
862
+ parent = parentOf(parent);
863
+ }
864
+ const isSimpleTarget = isSimpleAssignmentTarget(parent, current);
865
+ const isAssignedPattern = patternTarget && isSimpleTarget;
866
+ return isAssignedPattern || isLoopTarget(parent, current);
867
+ };
868
+ var isWriteOnly = (node) => {
869
+ const isWrite = isDirectWrite(node);
870
+ if (isWrite) return true;
871
+ return isDestructuringOrLoopTarget(node);
872
+ };
873
+
874
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.ts
875
+ var enterClass = (node, classes, stack, thisStack) => {
876
+ const entry = {
877
+ node,
878
+ reads: /* @__PURE__ */ new Set()
879
+ };
880
+ classes.push(entry);
881
+ stack.push(entry);
882
+ thisStack.push(true);
883
+ };
884
+ var trackMemberRead = (node, stack, thisStack, dynamicClasses) => {
885
+ const current = stack.at(-1);
886
+ const isComponentThis = thisStack.at(-1);
887
+ if (!current || !isComponentThis) return;
888
+ const receiverIsThis = isThisExpression(node.object);
889
+ if (node.computed && receiverIsThis) {
890
+ dynamicClasses.add(current);
578
891
  }
579
- if (receiverIsThis && !node.computed && node.property.type === import_utils4.TSESTree.AST_NODE_TYPES.Identifier && !isWriteOnly(node)) {
892
+ if (!receiverIsThis || node.computed) return;
893
+ const isWriteOnlyTarget = isWriteOnly(node);
894
+ if (isWriteOnlyTarget) return;
895
+ if (node.property.type === import_utils9.TSESTree.AST_NODE_TYPES.Identifier) {
580
896
  current.reads.add(node.property.name);
581
897
  }
582
898
  };
583
899
  var trackDestructuringRead = (node, stack, thisStack, dynamicClasses) => {
584
900
  const current = stack.at(-1);
585
- if (!current || !thisStack.at(-1)) {
586
- return;
587
- }
901
+ const isComponentThis = thisStack.at(-1);
902
+ if (!current || !isComponentThis) return;
588
903
  const reads = destructuredThisReads(node);
589
- if (reads === void 0) {
590
- return;
591
- }
904
+ if (reads === void 0) return;
592
905
  if (reads === null) {
593
906
  dynamicClasses.add(current);
594
907
  return;
@@ -597,45 +910,9 @@ var trackDestructuringRead = (node, stack, thisStack, dynamicClasses) => {
597
910
  current.reads.add(name);
598
911
  }
599
912
  };
600
- var lexicalThisVisitor = (thisStack) => ({
601
- FunctionDeclaration(node) {
602
- thisStack.push(componentThis(node, thisStack));
603
- },
604
- FunctionExpression(node) {
605
- thisStack.push(componentThis(node, thisStack));
606
- },
607
- ArrowFunctionExpression(node) {
608
- thisStack.push(componentThis(node, thisStack));
609
- },
610
- "FunctionDeclaration:exit"() {
611
- thisStack.pop();
612
- },
613
- "FunctionExpression:exit"() {
614
- thisStack.pop();
615
- },
616
- "ArrowFunctionExpression:exit"() {
617
- thisStack.pop();
618
- },
619
- StaticBlock() {
620
- thisStack.push(false);
621
- },
622
- "StaticBlock:exit"() {
623
- thisStack.pop();
624
- },
625
- PropertyDefinition(node) {
626
- if (node.static) {
627
- thisStack.push(false);
628
- }
629
- },
630
- "PropertyDefinition:exit"(node) {
631
- if (node.static) {
632
- thisStack.pop();
633
- }
634
- }
635
- });
636
- var visitor = (context, imports, classes, stack, dynamicClasses) => {
913
+ var classReadVisitor = (classes, stack, dynamicClasses) => {
637
914
  const thisStack = [];
638
- return {
915
+ const listeners = {
639
916
  ClassDeclaration(node) {
640
917
  enterClass(node, classes, stack, thisStack);
641
918
  },
@@ -659,183 +936,1887 @@ var visitor = (context, imports, classes, stack, dynamicClasses) => {
659
936
  },
660
937
  VariableDeclarator(node) {
661
938
  trackDestructuringRead(node, stack, thisStack, dynamicClasses);
662
- },
663
- "Program:exit"() {
664
- reportUnusedMembers(context, imports, classes, dynamicClasses);
665
939
  }
666
940
  };
941
+ return listeners;
667
942
  };
668
- var no_unused_angular_instance_fields_default = createRule({
669
- name: "no-unused-instance-fields",
670
- meta: {
671
- type: "problem",
672
- docs: {
673
- description: "Disallow unread instance fields and methods in Angular components and directives"
674
- },
675
- messages: {
676
- unusedField: "Angular instance field '{{name}}' is never read.",
677
- unusedMethod: "Angular instance method '{{name}}' is never read."
678
- },
679
- schema: []
680
- },
681
- defaultOptions: [],
682
- create(context) {
683
- const imports = /* @__PURE__ */ new Map();
684
- for (const node of context.sourceCode.ast.body) {
685
- if (node.type === import_utils4.TSESTree.AST_NODE_TYPES.ImportDeclaration) {
686
- addAngularImport(node, imports);
943
+
944
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
945
+ var import_typescript17 = require("typescript");
946
+
947
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.ts
948
+ var import_compiler4 = require("@angular/compiler");
949
+ var classShape = ({
950
+ component,
951
+ declaration,
952
+ exportAs,
953
+ hostDirectives,
954
+ name,
955
+ selector
956
+ }) => {
957
+ const fields = [
958
+ declaration.getSourceFile().fileName,
959
+ name,
960
+ String(component),
961
+ String(hostDirectives),
962
+ selector ?? "",
963
+ exportAs.join(",")
964
+ ];
965
+ return fields.join("\0");
966
+ };
967
+ var directiveShape = (classes) => {
968
+ const shapes = [...classes].map(classShape);
969
+ return shapes.sort().join("\n");
970
+ };
971
+ var parseSelector = (selector) => {
972
+ try {
973
+ return import_compiler4.CssSelector.parse(selector);
974
+ } catch {
975
+ return null;
976
+ }
977
+ };
978
+ var buildDirectiveIndex = (classes) => {
979
+ const byDeclaration = /* @__PURE__ */ new Map();
980
+ const byExportAs = /* @__PURE__ */ new Map();
981
+ const componentMatcher = new import_compiler4.SelectorMatcher();
982
+ for (const angularClass2 of classes) {
983
+ const { component, declaration, exportAs, selector } = angularClass2;
984
+ byDeclaration.set(declaration, angularClass2);
985
+ for (const name of exportAs) {
986
+ const declarations = byExportAs.get(name) ?? [];
987
+ declarations.push(declaration);
988
+ byExportAs.set(name, declarations);
989
+ }
990
+ if (component && selector !== null) {
991
+ const selectors = parseSelector(selector);
992
+ if (selectors) {
993
+ componentMatcher.addSelectables(selectors, [declaration]);
687
994
  }
688
995
  }
689
- if (imports.size === 0) {
690
- return {};
996
+ }
997
+ const directiveIndex = {
998
+ byDeclaration,
999
+ byExportAs,
1000
+ componentMatcher
1001
+ };
1002
+ return directiveIndex;
1003
+ };
1004
+
1005
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
1006
+ var import_node_fs2 = require("node:fs");
1007
+ var import_typescript3 = require("typescript");
1008
+
1009
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
1010
+ var import_compiler7 = require("@angular/compiler");
1011
+
1012
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.ts
1013
+ var import_typescript2 = require("typescript");
1014
+
1015
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.ts
1016
+ var import_typescript = require("typescript");
1017
+ var symbolsForName = (checker, type, name) => {
1018
+ const symbol = checker.getPropertyOfType(checker.getApparentType(type), name);
1019
+ if (symbol) return [symbol];
1020
+ const isUnionOrIntersection = type.isUnionOrIntersection();
1021
+ if (!isUnionOrIntersection) return [];
1022
+ const symbols = /* @__PURE__ */ new Set();
1023
+ for (const member of type.types) {
1024
+ for (const memberSymbol of symbolsForName(checker, member, name)) {
1025
+ symbols.add(memberSymbol);
691
1026
  }
692
- const classes = [];
693
- const stack = [];
694
- const dynamicClasses = /* @__PURE__ */ new Set();
695
- return visitor(context, imports, classes, stack, dynamicClasses);
696
1027
  }
697
- });
1028
+ return [...symbols];
1029
+ };
1030
+ var stringIndexTypes = (checker, type) => {
1031
+ const indexedType = checker.getIndexTypeOfType(
1032
+ checker.getApparentType(type),
1033
+ import_typescript.IndexKind.String
1034
+ );
1035
+ if (indexedType) return [indexedType];
1036
+ const isUnionOrIntersection = type.isUnionOrIntersection();
1037
+ if (!isUnionOrIntersection) return [];
1038
+ const indexedTypes = /* @__PURE__ */ new Set();
1039
+ for (const member of type.types) {
1040
+ for (const memberIndexedType of stringIndexTypes(checker, member)) {
1041
+ indexedTypes.add(memberIndexedType);
1042
+ }
1043
+ }
1044
+ return [...indexedTypes];
1045
+ };
698
1046
 
699
- // packages/lint-suite/src/lib/angular.ts
700
- var lintSuiteAngularPlugin = {
701
- rules: {
702
- "no-unused-instance-fields": no_unused_angular_instance_fields_default
1047
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.ts
1048
+ var hasAnyOrUnknownFlag = (type) => {
1049
+ const anyOrUnknown = import_typescript2.TypeFlags.Any | import_typescript2.TypeFlags.Unknown;
1050
+ return (type.flags & anyOrUnknown) !== 0;
1051
+ };
1052
+ var isAnyOrUnknown = (types) => {
1053
+ return types.some(hasAnyOrUnknownFlag);
1054
+ };
1055
+ var addTypes = (sink, types) => {
1056
+ for (const type of types) {
1057
+ sink.addType(type);
703
1058
  }
704
1059
  };
705
- var angular = (0, import_config2.defineConfig)([
706
- {
707
- files: ["**/*.ts"],
708
- extends: [...import_angular_eslint2.configs.tsRecommended],
709
- plugins: {
710
- "lint-suite-angular": lintSuiteAngularPlugin
711
- },
712
- languageOptions: {
713
- globals: {
714
- ...import_globals.default.browser,
715
- ...import_globals.default.es2025,
716
- ...import_globals.default.node
1060
+ var callReturnTypes = (checker, type) => {
1061
+ const signatures = checker.getSignaturesOfType(type, import_typescript2.SignatureKind.Call);
1062
+ return signatures.map((signature) => signature.getReturnType());
1063
+ };
1064
+ var memberTypes = (symbols, declaration, checker, sink) => {
1065
+ const types = [];
1066
+ for (const symbol of symbols) {
1067
+ for (const memberDeclaration of symbol.declarations ?? []) {
1068
+ sink.addDeclaration(memberDeclaration);
1069
+ }
1070
+ types.push(checker.getTypeOfSymbolAtLocation(symbol, declaration));
1071
+ }
1072
+ return types;
1073
+ };
1074
+ var addResolvedPath = ({
1075
+ allowMissingRoot,
1076
+ checker,
1077
+ declaration,
1078
+ names,
1079
+ sink
1080
+ }) => {
1081
+ let types = [checker.getTypeAtLocation(declaration)];
1082
+ const indexTypesOf = (type) => stringIndexTypes(checker, type);
1083
+ const returnTypesOf = (type) => callReturnTypes(checker, type);
1084
+ for (const [index, segment] of names.entries()) {
1085
+ addTypes(sink, types);
1086
+ const symbolsOf = (type) => {
1087
+ return symbolsForName(checker, type, segment.name);
1088
+ };
1089
+ const symbols = new Set(types.flatMap(symbolsOf));
1090
+ if (symbols.size === 0) {
1091
+ const indexedTypes = types.flatMap(indexTypesOf);
1092
+ if (indexedTypes.length > 0) {
1093
+ types = indexedTypes;
1094
+ continue;
717
1095
  }
718
- },
719
- processor: import_angular_eslint2.processInlineTemplates,
720
- rules: {
721
- "lint-suite-angular/no-unused-instance-fields": "error",
722
- "@angular-eslint/prefer-on-push-component-change-detection": "error",
723
- // v22: flags only explicit opt-out of OnPush (omission now means OnPush)
724
- "@angular-eslint/prefer-signals": "error",
725
- "@angular-eslint/use-injectable-provided-in": "error",
726
- "@angular-eslint/prefer-signal-model": "error",
727
- "@angular-eslint/no-uncalled-signals": "error",
728
- "@angular-eslint/prefer-host-metadata-property": "error",
729
- "@angular-eslint/no-implicit-take-until-destroyed": "error",
730
- // v21.2.0: Enforce explicit DestroyRef
731
- "@angular-eslint/no-async-lifecycle-method": "error",
732
- // Prevent async lifecycle hooks
733
- "@angular-eslint/prefer-output-readonly": "warn",
734
- // Prevent accidental reassignment
735
- "@angular-eslint/prefer-output-emitter-ref": "warn",
736
- // Modern output() function over @Output()
737
- "@angular-eslint/sort-lifecycle-methods": "warn",
738
- // Consistent lifecycle method ordering
739
- "@angular-eslint/computed-must-return": "error",
740
- // Catch silent computed() bugs missing a return
741
- "@angular-eslint/no-duplicates-in-metadata-arrays": "error",
742
- // Catch duplicate imports/providers in @Component/@NgModule
743
- "@angular-eslint/no-lifecycle-call": "error",
744
- // Forbid manual this.ngOnInit() calls
745
- "@angular-eslint/require-lifecycle-on-prototype": "error",
746
- // Lifecycle hooks must be methods, not arrow-fn fields
747
- "@angular-eslint/relative-url-prefix": "error",
748
- // Require ./ in templateUrl/styleUrl for portability
749
- "@angular-eslint/use-component-selector": "error",
750
- // All components must declare a selector
751
- "@angular-eslint/no-developer-preview": "warn",
752
- // Flag APIs marked @developerPreview (no breaking-change policy)
753
- "@angular-eslint/no-experimental": "warn"
754
- // Flag APIs marked @experimental
1096
+ const isAnyOrUnknownType = isAnyOrUnknown(types);
1097
+ if (isAnyOrUnknownType) return true;
1098
+ return index === 0 && allowMissingRoot;
1099
+ }
1100
+ types = memberTypes(symbols, declaration, checker, sink);
1101
+ if (segment.called) {
1102
+ const returnTypes = types.flatMap(returnTypesOf);
1103
+ if (returnTypes.length === 0) return isAnyOrUnknown(types);
1104
+ types = returnTypes;
755
1105
  }
756
1106
  }
757
- ]);
1107
+ return true;
1108
+ };
758
1109
 
759
- // packages/lint-suite/src/lib/base.ts
760
- var import_eslint_plugin = require("@nx/eslint-plugin");
761
- var import_eslint_plugin2 = __toESM(require("@stylistic/eslint-plugin"), 1);
762
- var import_eslint_plugin_import_x = __toESM(require("eslint-plugin-import-x"), 1);
763
- var import_config3 = require("eslint/config");
764
- var base = (0, import_config3.defineConfig)([
765
- { extends: [...import_eslint_plugin.configs["flat/base"]] },
766
- {
767
- files: [
768
- "**/*.js",
769
- "**/*.jsx",
770
- "**/*.cjs",
771
- "**/*.mjs",
772
- "**/*.ts",
773
- "**/*.tsx",
774
- "**/*.cts",
775
- "**/*.mts"
776
- ],
777
- extends: [import_eslint_plugin_import_x.default.flatConfigs.recommended]
778
- },
779
- {
780
- files: [
781
- "**/*.js",
782
- "**/*.jsx",
783
- "**/*.cjs",
784
- "**/*.mjs",
785
- "**/*.ts",
786
- "**/*.tsx",
787
- "**/*.cts",
788
- "**/*.mts"
789
- ],
790
- extends: [import_eslint_plugin2.default.configs.recommended]
791
- },
792
- {
793
- files: [
794
- "**/*.js",
795
- "**/*.jsx",
796
- "**/*.cjs",
797
- "**/*.mjs",
798
- "**/*.ts",
799
- "**/*.tsx",
800
- "**/*.cts",
801
- "**/*.mts"
802
- ],
803
- rules: {
804
- "no-param-reassign": "error",
805
- "no-alert": "error",
806
- "no-console": ["warn", { allow: ["warn", "error"] }],
807
- "no-debugger": "error",
808
- eqeqeq: ["error", "always", { null: "ignore" }],
809
- curly: ["error", "multi"],
810
- "prefer-const": ["error", { destructuring: "all" }],
811
- "no-var": "error",
812
- "object-shorthand": "error",
813
- "prefer-arrow-callback": "error",
814
- "no-useless-concat": "error",
815
- "prefer-template": "error",
816
- "no-nested-ternary": "error",
817
- "no-useless-assignment": "error",
818
- // NEW: Catch unused assignments (ESLint v9)
819
- "no-object-constructor": "error",
820
- // Disallow new Object() without arguments
821
- "no-else-return": ["error", { allowElseIf: false }],
822
- // Prefer early returns
823
- "no-multi-assign": "error",
824
- // Disallow chaining assignments
825
- radix: "error",
826
- // Require radix parameter for parseInt()
827
- yoda: "error",
828
- // Disallow yoda conditions (`if ("red" === color)`)
829
- complexity: ["warn", 10],
830
- // Warn if function complexity is high
831
- "max-depth": ["warn", 4],
832
- // Warn on deeply nested blocks
833
- "max-lines-per-function": [
834
- "warn",
835
- { max: 50, skipBlankLines: true, skipComments: true }
836
- ],
837
- // Warn on long functions
838
- "max-params": ["warn", 4],
1110
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-chains.ts
1111
+ var import_compiler5 = require("@angular/compiler");
1112
+ var isPropertyReadLike = (node) => {
1113
+ const isPlainRead = node instanceof import_compiler5.PropertyRead;
1114
+ const isSafeRead = node instanceof import_compiler5.SafePropertyRead;
1115
+ return isPlainRead || isSafeRead;
1116
+ };
1117
+ var isRootRead = (read) => {
1118
+ const isImplicitReceiver = read.receiver instanceof import_compiler5.ImplicitReceiver;
1119
+ const isThisReceiver = read.receiver instanceof import_compiler5.ThisReceiver;
1120
+ return isImplicitReceiver || isThisReceiver;
1121
+ };
1122
+ var chainStep = (read) => {
1123
+ const receiver = read.receiver;
1124
+ const isReadReceiver = isPropertyReadLike(receiver);
1125
+ if (isReadReceiver) {
1126
+ const readStep = { called: false, next: receiver };
1127
+ return readStep;
1128
+ }
1129
+ const isCallReceiver = receiver instanceof import_compiler5.Call;
1130
+ if (!isCallReceiver) return null;
1131
+ const target = receiver.receiver;
1132
+ const isReadLikeTarget = isPropertyReadLike(target);
1133
+ if (!isReadLikeTarget) return null;
1134
+ const calledStep = { called: true, next: target };
1135
+ return calledStep;
1136
+ };
1137
+ var readChain = (node) => {
1138
+ const leaf = { called: false, name: node.name };
1139
+ const names = [leaf];
1140
+ let current = node;
1141
+ while (!isRootRead(current)) {
1142
+ const step = chainStep(current);
1143
+ if (step === null) return null;
1144
+ current = step.next;
1145
+ names.unshift({ called: step.called, name: current.name });
1146
+ }
1147
+ if (!(current instanceof import_compiler5.PropertyRead)) return null;
1148
+ const chain = { names, root: current };
1149
+ return chain;
1150
+ };
1151
+ var ReadCollector2 = class extends import_compiler5.CombinedRecursiveAstVisitor {
1152
+ reads = [];
1153
+ referenceOwners = /* @__PURE__ */ new Map();
1154
+ record(node) {
1155
+ const chain = readChain(node);
1156
+ if (chain) {
1157
+ this.reads.push(chain);
1158
+ }
1159
+ }
1160
+ recordReferences(owner) {
1161
+ for (const reference of owner.references) {
1162
+ this.referenceOwners.set(reference, owner);
1163
+ }
1164
+ }
1165
+ visitElement(element) {
1166
+ this.recordReferences(element);
1167
+ super.visitElement(element);
1168
+ }
1169
+ visitTemplate(template) {
1170
+ this.recordReferences(template);
1171
+ super.visitTemplate(template);
1172
+ }
1173
+ visitComponent(component) {
1174
+ this.recordReferences(component);
1175
+ super.visitComponent(component);
1176
+ }
1177
+ visitDirective(directive) {
1178
+ this.recordReferences(directive);
1179
+ super.visitDirective(directive);
1180
+ }
1181
+ visitBinary(node, context) {
1182
+ if (node.operation !== "=") return super.visitBinary(node, context);
1183
+ if (isReadTarget(node.left)) {
1184
+ this.visit(node.left.receiver);
1185
+ }
1186
+ if (node.left instanceof import_compiler5.KeyedRead || node.left instanceof import_compiler5.SafeKeyedRead) {
1187
+ this.visit(node.left.key);
1188
+ }
1189
+ this.visit(node.right);
1190
+ return void 0;
1191
+ }
1192
+ visitPropertyRead(node, context) {
1193
+ this.record(node);
1194
+ return super.visitPropertyRead(node, context);
1195
+ }
1196
+ visitSafePropertyRead(node, context) {
1197
+ this.record(node);
1198
+ return super.visitSafePropertyRead(node, context);
1199
+ }
1200
+ };
1201
+
1202
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.ts
1203
+ var import_compiler6 = require("@angular/compiler");
1204
+
1205
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/read-chain-text.util.ts
1206
+ var segmentText = (segment) => {
1207
+ const call = segment.called ? "()" : "";
1208
+ return `${segment.name}${call}`;
1209
+ };
1210
+ var chainText = (names) => {
1211
+ const texts = names.map(segmentText);
1212
+ return texts.join(".");
1213
+ };
1214
+
1215
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.ts
1216
+ var referenceTargets = (reference, owner, directives, scope) => {
1217
+ const exportAs = reference.value.trim();
1218
+ let targets = [];
1219
+ if (exportAs !== "") {
1220
+ const exportedTargets = directives.byExportAs.get(exportAs) ?? [];
1221
+ targets = [...exportedTargets];
1222
+ } else if (owner instanceof import_compiler6.TmplAstElement) {
1223
+ directives.componentMatcher.match(
1224
+ (0, import_compiler6.createCssSelectorFromNode)(owner),
1225
+ (_selector, declarations) => {
1226
+ targets.push(...declarations);
1227
+ }
1228
+ );
1229
+ }
1230
+ const scoped = scope !== null && !scope.some(
1231
+ (declaration) => directives.byDeclaration.get(declaration)?.hostDirectives
1232
+ );
1233
+ if (!scoped) return targets;
1234
+ const scopedTargets = targets.filter((target) => scope.includes(target));
1235
+ return scopedTargets;
1236
+ };
1237
+ var addReferenceRead = (context, reference, owner, names) => {
1238
+ const { checker, className, directives, fileName, scope, sink } = context;
1239
+ const targets = referenceTargets(reference, owner, directives, scope);
1240
+ const isTargetResolved = (target) => {
1241
+ const options = {
1242
+ allowMissingRoot: false,
1243
+ checker,
1244
+ declaration: target,
1245
+ names,
1246
+ sink
1247
+ };
1248
+ return addResolvedPath(options);
1249
+ };
1250
+ const resolved = targets.map(isTargetResolved);
1251
+ const hasResolvedTarget = resolved.includes(true);
1252
+ if (resolved.length === 0) return;
1253
+ if (hasResolvedTarget) return;
1254
+ const fallbackNames = names.map((segment) => segment.name);
1255
+ const reason = `${fileName}: cannot resolve '#${reference.name}.${chainText(names)}' in ${className}`;
1256
+ sink.addFallbackNames(fallbackNames, reason);
1257
+ };
1258
+
1259
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
1260
+ var identifierNames = (text2) => {
1261
+ const matches = text2.match(/[A-Za-z_$][\w$]*/gu) ?? [];
1262
+ return new Set(matches);
1263
+ };
1264
+ var templateBinder2 = new import_compiler7.R3TargetBinder(null);
1265
+ var unparsedTemplateReads = (context, source, error) => {
1266
+ const names = identifierNames(source);
1267
+ const message = error ?? "unknown error";
1268
+ const reason = `${context.fileName}: template of ${context.className} does not parse (${message})`;
1269
+ context.sink.addFallbackNames(names, reason);
1270
+ const unparsedReads = { usedDirectiveIndex: false };
1271
+ return unparsedReads;
1272
+ };
1273
+ var addComponentRead = (context, names) => {
1274
+ const { checker, className, declaration, fileName, sink } = context;
1275
+ const options = {
1276
+ allowMissingRoot: true,
1277
+ checker,
1278
+ declaration,
1279
+ names,
1280
+ sink
1281
+ };
1282
+ const isResolved = addResolvedPath(options);
1283
+ if (isResolved) return;
1284
+ const fallbackNames = names.map((segment) => segment.name);
1285
+ const reason = `${fileName}: cannot resolve '${chainText(names)}' on ${className}`;
1286
+ sink.addFallbackNames(fallbackNames, reason);
1287
+ };
1288
+ var chainEntity = (boundTarget, chain) => {
1289
+ const isThisRead = chain.root.receiver instanceof import_compiler7.ThisReceiver;
1290
+ if (isThisRead) return null;
1291
+ return boundTarget.getExpressionTarget(chain.root);
1292
+ };
1293
+ var addChainRead = (context, reads, boundTarget, chain) => {
1294
+ const entity = chainEntity(boundTarget, chain);
1295
+ if (entity === null) {
1296
+ addComponentRead(context, chain.names);
1297
+ return false;
1298
+ }
1299
+ if (!(entity instanceof import_compiler7.TmplAstReference)) return false;
1300
+ const owner = reads.referenceOwners.get(entity);
1301
+ const names = chain.names.slice(1);
1302
+ addReferenceRead(context, entity, owner, names);
1303
+ return true;
1304
+ };
1305
+ var addTemplateReads = ({
1306
+ angularClass: angularClass2,
1307
+ checker,
1308
+ directives,
1309
+ fileName,
1310
+ sink,
1311
+ source
1312
+ }) => {
1313
+ const { declaration, scope } = angularClass2;
1314
+ const className = declaration.name?.text ?? "(anonymous)";
1315
+ const context = {
1316
+ checker,
1317
+ className,
1318
+ declaration,
1319
+ directives,
1320
+ fileName,
1321
+ scope,
1322
+ sink
1323
+ };
1324
+ const parsed = (0, import_compiler7.parseTemplate)(source, fileName);
1325
+ if (parsed.errors?.length) {
1326
+ const error = parsed.errors[0]?.msg;
1327
+ return unparsedTemplateReads(context, source, error);
1328
+ }
1329
+ const boundTarget = templateBinder2.bind({ template: parsed.nodes });
1330
+ const reads = new ReadCollector2();
1331
+ for (const node of parsed.nodes) {
1332
+ reads.visit(node);
1333
+ }
1334
+ let usedDirectiveIndex = false;
1335
+ for (const chain of reads.reads) {
1336
+ const usedIndex = addChainRead(context, reads, boundTarget, chain);
1337
+ usedDirectiveIndex ||= usedIndex;
1338
+ }
1339
+ const templateReads2 = { usedDirectiveIndex };
1340
+ return templateReads2;
1341
+ };
1342
+
1343
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
1344
+ var memberNameOf = (member) => {
1345
+ const name = member.name;
1346
+ if (!name) return [];
1347
+ const isIdentifierName = (0, import_typescript3.isIdentifier)(name);
1348
+ const isStringName = (0, import_typescript3.isStringLiteralLike)(name);
1349
+ const isTextName = isIdentifierName || isStringName;
1350
+ if (!isTextName) return [];
1351
+ const names = [name.text];
1352
+ return names;
1353
+ };
1354
+ var memberNames = (declaration) => {
1355
+ return declaration.members.flatMap(memberNameOf);
1356
+ };
1357
+ var unknownTemplateNames = ({ declaration, scope }, allNames) => {
1358
+ if (scope === null) return allNames;
1359
+ const scopeNames = scope.flatMap(memberNames);
1360
+ const names = [...memberNames(declaration), ...scopeNames];
1361
+ return names;
1362
+ };
1363
+ var templateFileVersion = (fileName) => {
1364
+ const { mtimeNs, size } = (0, import_node_fs2.statSync)(fileName, { bigint: true });
1365
+ const version = { fileName, mtimeNs, size };
1366
+ return version;
1367
+ };
1368
+ var templateFileIsCurrent = (version) => {
1369
+ try {
1370
+ const current = (0, import_node_fs2.statSync)(version.fileName, { bigint: true });
1371
+ return current.mtimeNs === version.mtimeNs && current.size === version.size;
1372
+ } catch {
1373
+ return false;
1374
+ }
1375
+ };
1376
+ var templateSourceOf = (angularClass2, allNames, sink, versions) => {
1377
+ const { declaration, template, valid } = angularClass2;
1378
+ const fileName = declaration.getSourceFile().fileName;
1379
+ const className = declaration.name?.text ?? "(anonymous)";
1380
+ if (!valid) {
1381
+ const names = unknownTemplateNames(angularClass2, allNames);
1382
+ const reason = `${fileName}: metadata of ${className} is not static (template, templateUrl)`;
1383
+ sink.addFallbackNames(names, reason);
1384
+ return null;
1385
+ }
1386
+ if (!template) return null;
1387
+ if (template.kind === "inline") {
1388
+ const inlineSource = { fileName, source: template.source };
1389
+ return inlineSource;
1390
+ }
1391
+ const templateFileName = template.fileName;
1392
+ try {
1393
+ versions.push(templateFileVersion(templateFileName));
1394
+ const source = (0, import_node_fs2.readFileSync)(templateFileName, "utf8");
1395
+ const externalSource = {
1396
+ fileName: templateFileName,
1397
+ source
1398
+ };
1399
+ return externalSource;
1400
+ } catch {
1401
+ const names = unknownTemplateNames(angularClass2, allNames);
1402
+ const reason = `${fileName}: templateUrl of ${className} cannot be read (${templateFileName})`;
1403
+ sink.addFallbackNames(names, reason);
1404
+ return null;
1405
+ }
1406
+ };
1407
+ var collectAngularTemplateReads = ({
1408
+ allNames,
1409
+ checker,
1410
+ classes,
1411
+ directives,
1412
+ sink
1413
+ }) => {
1414
+ const templateVersions = [];
1415
+ let usedDirectiveIndex = false;
1416
+ for (const angularClass2 of classes) {
1417
+ const template = templateSourceOf(
1418
+ angularClass2,
1419
+ allNames,
1420
+ sink,
1421
+ templateVersions
1422
+ );
1423
+ if (template === null) continue;
1424
+ const result = addTemplateReads({
1425
+ angularClass: angularClass2,
1426
+ checker,
1427
+ directives,
1428
+ fileName: template.fileName,
1429
+ sink,
1430
+ source: template.source
1431
+ });
1432
+ usedDirectiveIndex ||= result.usedDirectiveIndex;
1433
+ }
1434
+ const templateReads2 = {
1435
+ templateVersions,
1436
+ usedDirectiveIndex
1437
+ };
1438
+ return templateReads2;
1439
+ };
1440
+
1441
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
1442
+ var import_typescript10 = require("typescript");
1443
+
1444
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.ts
1445
+ var import_typescript5 = require("typescript");
1446
+
1447
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.ts
1448
+ var import_typescript4 = require("typescript");
1449
+ var aliasTarget = (checker, symbol) => {
1450
+ const isAlias = (symbol.flags & import_typescript4.SymbolFlags.Alias) !== 0;
1451
+ if (!isAlias) return symbol;
1452
+ return checker.getAliasedSymbol(symbol);
1453
+ };
1454
+ var addSymbolDeclarations = (checker, symbol, sink) => {
1455
+ const resolved = aliasTarget(checker, symbol);
1456
+ for (const declaration of resolved.declarations ?? []) {
1457
+ sink.addDeclaration(declaration);
1458
+ }
1459
+ };
1460
+ var allPropertySymbols = (checker, type) => {
1461
+ const symbols = new Set(
1462
+ checker.getPropertiesOfType(checker.getApparentType(type))
1463
+ );
1464
+ const isUnionOrIntersection = type.isUnionOrIntersection();
1465
+ if (isUnionOrIntersection) {
1466
+ for (const member of type.types) {
1467
+ for (const symbol of allPropertySymbols(checker, member)) {
1468
+ symbols.add(symbol);
1469
+ }
1470
+ }
1471
+ }
1472
+ return [...symbols];
1473
+ };
1474
+ var namedPropertySymbols = (checker, type, names) => {
1475
+ if (names === null) return allPropertySymbols(checker, type);
1476
+ return names.flatMap((name) => symbolsForName(checker, type, name));
1477
+ };
1478
+ var addNamedProperties = (checker, type, names, sink) => {
1479
+ sink.addType(type);
1480
+ const symbols = namedPropertySymbols(checker, type, names);
1481
+ for (const symbol of symbols) {
1482
+ addSymbolDeclarations(checker, symbol, sink);
1483
+ }
1484
+ return symbols;
1485
+ };
1486
+ var literalPropertyNames = (type) => {
1487
+ const isStringLiteral = type.isStringLiteral();
1488
+ const isNumberLiteral = type.isNumberLiteral();
1489
+ const isLiteralType = isStringLiteral || isNumberLiteral;
1490
+ if (isLiteralType) return [String(type.value)];
1491
+ const isUnion = type.isUnion();
1492
+ if (!isUnion) return null;
1493
+ const names = [];
1494
+ for (const member of type.types) {
1495
+ const memberNames2 = literalPropertyNames(member);
1496
+ if (!memberNames2) return null;
1497
+ names.push(...memberNames2);
1498
+ }
1499
+ return names;
1500
+ };
1501
+ var propertyName2 = (checker, node) => {
1502
+ const isIdentifierName = (0, import_typescript4.isIdentifier)(node);
1503
+ const isPrivateName = (0, import_typescript4.isPrivateIdentifier)(node);
1504
+ const isStringName = (0, import_typescript4.isStringLiteralLike)(node);
1505
+ const isNumericName = (0, import_typescript4.isNumericLiteral)(node);
1506
+ const isBigIntName = (0, import_typescript4.isBigIntLiteral)(node);
1507
+ const isLiteralName = isIdentifierName || isPrivateName || isStringName || isNumericName || isBigIntName;
1508
+ if (isLiteralName) return [node.text];
1509
+ return literalPropertyNames(checker.getTypeAtLocation(node.expression));
1510
+ };
1511
+
1512
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.ts
1513
+ var isAngularMethodSignature = (declaration) => {
1514
+ const isMethod = (0, import_typescript5.isMethodSignature)(declaration);
1515
+ if (!isMethod) return false;
1516
+ const fileName = declaration.getSourceFile().fileName.replaceAll("\\", "/");
1517
+ return fileName.includes("/node_modules/@angular/");
1518
+ };
1519
+ var isAngularInterfaceMethod = (symbol) => {
1520
+ const declarations = symbol.declarations ?? [];
1521
+ return declarations.some(isAngularMethodSignature);
1522
+ };
1523
+ var addImplementations = (heritageType, classType, checker, sink) => {
1524
+ for (const interfaceMethod of heritageType.getProperties()) {
1525
+ const isInterfaceMethod = isAngularInterfaceMethod(interfaceMethod);
1526
+ if (!isInterfaceMethod) continue;
1527
+ const implementation = classType.getProperty(interfaceMethod.name);
1528
+ if (implementation) {
1529
+ addSymbolDeclarations(checker, implementation, sink);
1530
+ }
1531
+ }
1532
+ };
1533
+ var collectAngularInterfaceMethods = (node, checker, sink) => {
1534
+ const heritageClauses = node.heritageClauses ?? [];
1535
+ const implementsClauses = heritageClauses.filter(
1536
+ (clause) => clause.token === import_typescript5.SyntaxKind.ImplementsKeyword
1537
+ );
1538
+ if (implementsClauses.length === 0) return;
1539
+ const classType = checker.getTypeAtLocation(node);
1540
+ for (const clause of implementsClauses) {
1541
+ for (const heritageType of clause.types) {
1542
+ const type = checker.getTypeAtLocation(heritageType);
1543
+ sink.addType(type);
1544
+ addImplementations(type, classType, checker, sink);
1545
+ }
1546
+ }
1547
+ };
1548
+
1549
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.ts
1550
+ var import_typescript8 = require("typescript");
1551
+
1552
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.ts
1553
+ var import_typescript6 = require("typescript");
1554
+ var nestedPattern = (expression) => {
1555
+ const isArrayLiteral = (0, import_typescript6.isArrayLiteralExpression)(expression);
1556
+ const isObjectLiteral = (0, import_typescript6.isObjectLiteralExpression)(expression);
1557
+ const isNested = isArrayLiteral || isObjectLiteral;
1558
+ if (!isNested) return null;
1559
+ return expression;
1560
+ };
1561
+ var nestedPropertyPattern = (property) => {
1562
+ const isAssignment = (0, import_typescript6.isPropertyAssignment)(property);
1563
+ if (!isAssignment) return null;
1564
+ return nestedPattern(property.initializer);
1565
+ };
1566
+ var arrayElementRead = (element, index) => {
1567
+ const isOmitted = (0, import_typescript6.isOmittedExpression)(element);
1568
+ if (isOmitted) return null;
1569
+ const isRestElement = (0, import_typescript6.isSpreadElement)(element);
1570
+ const indexNames = [String(index)];
1571
+ const names = isRestElement ? null : indexNames;
1572
+ const nested = nestedPattern(element);
1573
+ const read = {
1574
+ location: element,
1575
+ names,
1576
+ nested,
1577
+ rest: false
1578
+ };
1579
+ return read;
1580
+ };
1581
+ var propertyRead = (property, checker) => {
1582
+ const isRestProperty = (0, import_typescript6.isSpreadAssignment)(property);
1583
+ if (isRestProperty) {
1584
+ const restRead = {
1585
+ location: property,
1586
+ names: null,
1587
+ nested: null,
1588
+ rest: true
1589
+ };
1590
+ return restRead;
1591
+ }
1592
+ const read = {
1593
+ location: property,
1594
+ names: propertyName2(checker, property.name),
1595
+ nested: nestedPropertyPattern(property),
1596
+ rest: false
1597
+ };
1598
+ return read;
1599
+ };
1600
+ var assignmentPatternElements = (pattern, checker) => {
1601
+ const isArrayPattern = (0, import_typescript6.isArrayLiteralExpression)(pattern);
1602
+ if (isArrayPattern) {
1603
+ const reads = [];
1604
+ for (const [index, element] of pattern.elements.entries()) {
1605
+ const read = arrayElementRead(element, index);
1606
+ if (read !== null) {
1607
+ reads.push(read);
1608
+ }
1609
+ }
1610
+ return reads;
1611
+ }
1612
+ return pattern.properties.map((property) => propertyRead(property, checker));
1613
+ };
1614
+
1615
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.ts
1616
+ var import_typescript7 = require("typescript");
1617
+ var isBindingPattern = (node) => {
1618
+ const isArrayPattern = (0, import_typescript7.isArrayBindingPattern)(node);
1619
+ const isObjectPattern = (0, import_typescript7.isObjectBindingPattern)(node);
1620
+ return isArrayPattern || isObjectPattern;
1621
+ };
1622
+ var nestedPattern2 = (element) => {
1623
+ const isNested = isBindingPattern(element.name);
1624
+ if (!isNested) return null;
1625
+ return element.name;
1626
+ };
1627
+ var bindingNames = (checker, element) => {
1628
+ if (element.propertyName) return propertyName2(checker, element.propertyName);
1629
+ const isIdentifierName = (0, import_typescript7.isIdentifier)(element.name);
1630
+ if (!isIdentifierName) return null;
1631
+ return [element.name.text];
1632
+ };
1633
+ var arrayElementRead2 = (element, index) => {
1634
+ const isOmitted = (0, import_typescript7.isOmittedExpression)(element);
1635
+ if (isOmitted) return null;
1636
+ const isRestElement = Boolean(element.dotDotDotToken);
1637
+ const indexNames = [String(index)];
1638
+ const names = isRestElement ? null : indexNames;
1639
+ const nested = nestedPattern2(element);
1640
+ const read = {
1641
+ location: element,
1642
+ names,
1643
+ nested,
1644
+ rest: false
1645
+ };
1646
+ return read;
1647
+ };
1648
+ var objectElementRead = (element, checker) => {
1649
+ const isRestElement = Boolean(element.dotDotDotToken);
1650
+ if (isRestElement) {
1651
+ const restRead = {
1652
+ location: element,
1653
+ names: null,
1654
+ nested: null,
1655
+ rest: true
1656
+ };
1657
+ return restRead;
1658
+ }
1659
+ const read = {
1660
+ location: element,
1661
+ names: bindingNames(checker, element),
1662
+ nested: nestedPattern2(element),
1663
+ rest: false
1664
+ };
1665
+ return read;
1666
+ };
1667
+ var bindingPatternElements = (pattern, checker) => {
1668
+ const isArrayPattern = (0, import_typescript7.isArrayBindingPattern)(pattern);
1669
+ if (isArrayPattern) {
1670
+ const reads = [];
1671
+ for (const [index, element] of pattern.elements.entries()) {
1672
+ const read = arrayElementRead2(element, index);
1673
+ if (read !== null) {
1674
+ reads.push(read);
1675
+ }
1676
+ }
1677
+ return reads;
1678
+ }
1679
+ return pattern.elements.map((element) => objectElementRead(element, checker));
1680
+ };
1681
+
1682
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.ts
1683
+ var lazyType = (compute) => {
1684
+ let type;
1685
+ return () => type ??= compute();
1686
+ };
1687
+ var isSkippable = (read, candidateNames) => {
1688
+ if (read.nested !== null) return false;
1689
+ if (read.names === null) return false;
1690
+ const hasCandidateName = read.names.some((name) => candidateNames.has(name));
1691
+ return !hasCandidateName;
1692
+ };
1693
+ var patternElements = (pattern, checker) => {
1694
+ const isBinding = isBindingPattern(pattern);
1695
+ if (isBinding) return bindingPatternElements(pattern, checker);
1696
+ return assignmentPatternElements(pattern, checker);
1697
+ };
1698
+ var addRestReads = (type, consumed, context) => {
1699
+ context.sink.addType(type);
1700
+ for (const symbol of allPropertySymbols(context.checker, type)) {
1701
+ const isConsumed = consumed.has(symbol.name);
1702
+ if (isConsumed) continue;
1703
+ addSymbolDeclarations(context.checker, symbol, context.sink);
1704
+ }
1705
+ };
1706
+ var collectPatternReads = (pattern, type, context) => {
1707
+ const { checker, sink, candidateNames } = context;
1708
+ const consumed = /* @__PURE__ */ new Set();
1709
+ const reads = patternElements(pattern, checker);
1710
+ for (const read of reads) {
1711
+ if (read.rest) {
1712
+ addRestReads(type(), consumed, context);
1713
+ continue;
1714
+ }
1715
+ for (const name of read.names ?? []) {
1716
+ consumed.add(name);
1717
+ }
1718
+ const skip = isSkippable(read, candidateNames);
1719
+ if (skip) continue;
1720
+ const symbols = addNamedProperties(checker, type(), read.names, sink);
1721
+ const nested = read.nested;
1722
+ if (nested === null) continue;
1723
+ for (const symbol of symbols) {
1724
+ const nestedType = lazyType(() => {
1725
+ return checker.getTypeOfSymbolAtLocation(symbol, read.location);
1726
+ });
1727
+ collectPatternReads(nested, nestedType, context);
1728
+ }
1729
+ }
1730
+ };
1731
+ var collectBindingReads = (node, context) => {
1732
+ const isBinding = isBindingPattern(node);
1733
+ if (!isBinding) return;
1734
+ const isBindingElementParent = (0, import_typescript8.isBindingElement)(node.parent);
1735
+ const isNestedBindingName = isBindingElementParent && node.parent.name === node;
1736
+ if (isNestedBindingName) return;
1737
+ const declaration = node.parent;
1738
+ const isDeclaration = (0, import_typescript8.isVariableDeclaration)(declaration);
1739
+ const isInitializedDeclaration = isDeclaration && declaration.initializer !== void 0;
1740
+ const source = isInitializedDeclaration ? declaration.initializer : declaration;
1741
+ const sourceTypeOf = () => context.checker.getTypeAtLocation(source);
1742
+ const sourceType = lazyType(sourceTypeOf);
1743
+ collectPatternReads(node, sourceType, context);
1744
+ };
1745
+ var collectAssignmentReads = (node, context) => {
1746
+ const isBinary = (0, import_typescript8.isBinaryExpression)(node);
1747
+ if (!isBinary) return;
1748
+ const isEqualsAssignment = node.operatorToken.kind === import_typescript8.SyntaxKind.EqualsToken;
1749
+ if (!isEqualsAssignment) return;
1750
+ const isArrayTarget = (0, import_typescript8.isArrayLiteralExpression)(node.left);
1751
+ const isObjectTarget = (0, import_typescript8.isObjectLiteralExpression)(node.left);
1752
+ const isDestructuringAssignment = isArrayTarget || isObjectTarget;
1753
+ if (!isDestructuringAssignment) return;
1754
+ const rightTypeOf = () => context.checker.getTypeAtLocation(node.right);
1755
+ const sourceType = lazyType(rightTypeOf);
1756
+ collectPatternReads(node.left, sourceType, context);
1757
+ };
1758
+ var collectDestructuringReads = (node, checker, sink, candidateNames) => {
1759
+ const context = { checker, sink, candidateNames };
1760
+ collectBindingReads(node, context);
1761
+ collectAssignmentReads(node, context);
1762
+ };
1763
+
1764
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.ts
1765
+ var import_typescript9 = require("typescript");
1766
+ var isExpressionWrapper = (parent, child) => {
1767
+ const isParenthesized = (0, import_typescript9.isParenthesizedExpression)(parent);
1768
+ const isAs = (0, import_typescript9.isAsExpression)(parent);
1769
+ const isTypeAssertion = (0, import_typescript9.isTypeAssertionExpression)(parent);
1770
+ const isNonNull = (0, import_typescript9.isNonNullExpression)(parent);
1771
+ const isSatisfies = (0, import_typescript9.isSatisfiesExpression)(parent);
1772
+ const isCast = isAs || isTypeAssertion || isSatisfies;
1773
+ const isWrapper = isParenthesized || isNonNull || isCast;
1774
+ if (!isWrapper) return false;
1775
+ return parent.expression === child;
1776
+ };
1777
+ var isPatternContainer = (parent, child) => {
1778
+ const isArrayLiteral = (0, import_typescript9.isArrayLiteralExpression)(parent);
1779
+ if (isArrayLiteral) {
1780
+ return parent.elements.some((element) => element === child);
1781
+ }
1782
+ const isObjectLiteral = (0, import_typescript9.isObjectLiteralExpression)(parent);
1783
+ if (isObjectLiteral) {
1784
+ return parent.properties.some((property) => property === child);
1785
+ }
1786
+ const isAssignment = (0, import_typescript9.isPropertyAssignment)(parent);
1787
+ if (isAssignment) return parent.initializer === child;
1788
+ const isSpread = (0, import_typescript9.isSpreadAssignment)(parent);
1789
+ if (!isSpread) return false;
1790
+ return parent.expression === child;
1791
+ };
1792
+ var isWriteTarget = (parent, current) => {
1793
+ const isBinary = (0, import_typescript9.isBinaryExpression)(parent);
1794
+ const isBinaryTarget = isBinary && parent.left === current && parent.operatorToken.kind === import_typescript9.SyntaxKind.EqualsToken;
1795
+ if (isBinaryTarget) return true;
1796
+ const isDelete = (0, import_typescript9.isDeleteExpression)(parent);
1797
+ const isDeleteTarget = isDelete && parent.expression === current;
1798
+ if (isDeleteTarget) return true;
1799
+ const isForIn = (0, import_typescript9.isForInStatement)(parent);
1800
+ const isForOf = (0, import_typescript9.isForOfStatement)(parent);
1801
+ const isIteration = isForIn || isForOf;
1802
+ return isIteration && parent.initializer === current;
1803
+ };
1804
+ var isWriteOnly2 = (node) => {
1805
+ let current = node;
1806
+ let parent = node.parent;
1807
+ while (isExpressionWrapper(parent, current) || isPatternContainer(parent, current)) {
1808
+ current = parent;
1809
+ parent = parent.parent;
1810
+ }
1811
+ return isWriteTarget(parent, current);
1812
+ };
1813
+
1814
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
1815
+ var addPropertyAccessRead = (node, checker, sink, candidateNames) => {
1816
+ const isCandidateName = candidateNames.has(node.name.text);
1817
+ if (!isCandidateName) return;
1818
+ const isWriteTarget2 = isWriteOnly2(node);
1819
+ if (isWriteTarget2) return;
1820
+ sink.addType(checker.getTypeAtLocation(node.expression));
1821
+ const symbol = checker.getSymbolAtLocation(node.name);
1822
+ if (symbol) {
1823
+ addSymbolDeclarations(checker, symbol, sink);
1824
+ }
1825
+ };
1826
+ var addElementAccessRead = (node, checker, sink, candidateNames) => {
1827
+ const isWriteTarget2 = isWriteOnly2(node);
1828
+ if (isWriteTarget2) return;
1829
+ const argumentType = checker.getTypeAtLocation(node.argumentExpression);
1830
+ const names = literalPropertyNames(argumentType);
1831
+ if (names) {
1832
+ const hasCandidateName = names.some((name) => candidateNames.has(name));
1833
+ if (!hasCandidateName) return;
1834
+ }
1835
+ const targetType = checker.getTypeAtLocation(node.expression);
1836
+ addNamedProperties(checker, targetType, names, sink);
1837
+ };
1838
+ var collectTypeScriptReads = (sourceFile, checker, sink, candidateNames) => {
1839
+ const visit = (node) => {
1840
+ const isPropertyAccess = (0, import_typescript10.isPropertyAccessExpression)(node);
1841
+ const isElementAccess = (0, import_typescript10.isElementAccessExpression)(node);
1842
+ const isClass = (0, import_typescript10.isClassLike)(node);
1843
+ if (isPropertyAccess) {
1844
+ addPropertyAccessRead(node, checker, sink, candidateNames);
1845
+ } else if (isElementAccess) {
1846
+ addElementAccessRead(node, checker, sink, candidateNames);
1847
+ } else if (isClass) {
1848
+ collectAngularInterfaceMethods(node, checker, sink);
1849
+ }
1850
+ collectDestructuringReads(node, checker, sink, candidateNames);
1851
+ (0, import_typescript10.forEachChild)(node, visit);
1852
+ };
1853
+ visit(sourceFile);
1854
+ };
1855
+
1856
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-type-dependencies.ts
1857
+ var import_typescript11 = require("typescript");
1858
+ var isObjectType = (type) => {
1859
+ return (type.flags & import_typescript11.TypeFlags.Object) !== 0;
1860
+ };
1861
+ var isTypeReference = (type) => {
1862
+ return (type.objectFlags & import_typescript11.ObjectFlags.Reference) !== 0;
1863
+ };
1864
+ var isInterfaceType = (type) => {
1865
+ return (type.objectFlags & import_typescript11.ObjectFlags.ClassOrInterface) !== 0;
1866
+ };
1867
+ var addDeclarationFiles = (type, dependencies) => {
1868
+ for (const symbol of [type.getSymbol(), type.aliasSymbol]) {
1869
+ const declarations = symbol?.declarations ?? [];
1870
+ for (const declaration of declarations) {
1871
+ dependencies.add(declaration.getSourceFile());
1872
+ }
1873
+ }
1874
+ };
1875
+ var baseTypesOf = (checker, type) => {
1876
+ const isObject = isObjectType(type);
1877
+ if (!isObject) return [];
1878
+ const isReference = isTypeReference(type);
1879
+ const target = isReference ? type.target : type;
1880
+ const isClassOrInterface = isInterfaceType(target);
1881
+ if (!isClassOrInterface) return [];
1882
+ return checker.getBaseTypes(target);
1883
+ };
1884
+ var addTypeDependencies = (checker, type, dependencies, seen) => {
1885
+ const isSeen = seen.has(type);
1886
+ if (isSeen) return;
1887
+ seen.add(type);
1888
+ const isUnionOrIntersection = type.isUnionOrIntersection();
1889
+ if (isUnionOrIntersection) {
1890
+ for (const member of type.types) {
1891
+ addTypeDependencies(checker, member, dependencies, seen);
1892
+ }
1893
+ return;
1894
+ }
1895
+ addDeclarationFiles(type, dependencies);
1896
+ const isTypeParameter = (type.flags & import_typescript11.TypeFlags.TypeParameter) !== 0;
1897
+ if (isTypeParameter) {
1898
+ const constraint = checker.getBaseConstraintOfType(type);
1899
+ if (constraint) {
1900
+ addTypeDependencies(checker, constraint, dependencies, seen);
1901
+ }
1902
+ return;
1903
+ }
1904
+ for (const base2 of baseTypesOf(checker, type)) {
1905
+ addTypeDependencies(checker, base2, dependencies, seen);
1906
+ }
1907
+ };
1908
+
1909
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.ts
1910
+ var failureText = (error) => {
1911
+ if (error instanceof Error) return error.message;
1912
+ return String(error);
1913
+ };
1914
+ var collectFileReads = (index, sourceFile, checker, sink) => {
1915
+ try {
1916
+ collectTypeScriptReads(sourceFile, checker, sink, index.candidateNames);
1917
+ const classes = index.classes.get(sourceFile.fileName)?.classes ?? [];
1918
+ return collectAngularTemplateReads({
1919
+ allNames: index.candidateNames,
1920
+ checker,
1921
+ classes,
1922
+ directives: index.directives,
1923
+ sink
1924
+ });
1925
+ } catch (error) {
1926
+ const errorMessage = failureText(error);
1927
+ sink.addFallbackNames(
1928
+ index.candidateNames,
1929
+ `${sourceFile.fileName}: indexing failed (${errorMessage})`
1930
+ );
1931
+ const noTemplateReads = {
1932
+ templateVersions: [],
1933
+ usedDirectiveIndex: false
1934
+ };
1935
+ return noTemplateReads;
1936
+ }
1937
+ };
1938
+ var computeEntry = (index, sourceFile, checker) => {
1939
+ const declarations = /* @__PURE__ */ new Set();
1940
+ const dependencies = /* @__PURE__ */ new Set();
1941
+ const fallbackNames = /* @__PURE__ */ new Set();
1942
+ const seenTypes = /* @__PURE__ */ new Set();
1943
+ const sink = {
1944
+ addDeclaration: (declaration) => {
1945
+ declarations.add(declaration);
1946
+ dependencies.add(declaration.getSourceFile());
1947
+ },
1948
+ addFallbackNames: (names) => {
1949
+ for (const name of names) {
1950
+ fallbackNames.add(name);
1951
+ }
1952
+ },
1953
+ addType: (type) => {
1954
+ addTypeDependencies(checker, type, dependencies, seenTypes);
1955
+ }
1956
+ };
1957
+ const reads = collectFileReads(index, sourceFile, checker, sink);
1958
+ dependencies.delete(sourceFile);
1959
+ const fileEntry = {
1960
+ ...reads,
1961
+ declarations,
1962
+ dependencies,
1963
+ fallbackNames,
1964
+ sourceFile
1965
+ };
1966
+ return fileEntry;
1967
+ };
1968
+
1969
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.ts
1970
+ var import_typescript15 = require("typescript");
1971
+
1972
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.ts
1973
+ var import_typescript14 = require("typescript");
1974
+
1975
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-decorator-kind.ts
1976
+ var import_typescript12 = require("typescript");
1977
+ var decoratorKinds = [
1978
+ "Component",
1979
+ "Directive",
1980
+ "NgModule",
1981
+ "Pipe"
1982
+ ];
1983
+ var isDecoratorKind = (name) => {
1984
+ return decoratorKinds.some((kind) => kind === name);
1985
+ };
1986
+ var isAngularCoreFile = (declaration) => {
1987
+ const fileName = declaration.getSourceFile().fileName.replaceAll("\\", "/");
1988
+ return fileName.includes("/node_modules/@angular/core/");
1989
+ };
1990
+ var parentOf2 = (node) => {
1991
+ return node.parent;
1992
+ };
1993
+ var importedFromAngularCore = (declaration) => {
1994
+ let current = parentOf2(declaration);
1995
+ while (current) {
1996
+ if ((0, import_typescript12.isImportDeclaration)(current)) {
1997
+ return (0, import_typescript12.isStringLiteralLike)(current.moduleSpecifier) && current.moduleSpecifier.text === "@angular/core";
1998
+ }
1999
+ current = parentOf2(current);
2000
+ }
2001
+ return false;
2002
+ };
2003
+ var resolveAlias = (symbol, discovery) => {
2004
+ let current = symbol;
2005
+ for (let hop = 0; hop < 32; hop += 1) {
2006
+ for (const declaration of current.declarations ?? []) {
2007
+ discovery.dependencies.add(declaration.getSourceFile());
2008
+ }
2009
+ if ((current.flags & import_typescript12.SymbolFlags.Alias) === 0) return current;
2010
+ const next = discovery.checker.getImmediateAliasedSymbol(current);
2011
+ if (!next || next === current) return current;
2012
+ current = next;
2013
+ }
2014
+ return current;
2015
+ };
2016
+ var angularDecoratorKind = (expression, discovery) => {
2017
+ const unresolved = discovery.checker.getSymbolAtLocation(expression);
2018
+ if (!unresolved) return null;
2019
+ const symbol = resolveAlias(unresolved, discovery);
2020
+ const name = symbol.getName();
2021
+ const isKind = isDecoratorKind(name);
2022
+ if (!isKind) return null;
2023
+ const unresolvedDeclarations = unresolved.declarations ?? [];
2024
+ const symbolDeclarations = symbol.declarations ?? [];
2025
+ const isCoreImport = unresolvedDeclarations.some(importedFromAngularCore);
2026
+ const isCoreDeclaration = symbolDeclarations.some(isAngularCoreFile);
2027
+ const fromAngularCore = isCoreImport || isCoreDeclaration;
2028
+ if (!fromAngularCore) return null;
2029
+ return name;
2030
+ };
2031
+ var classDecoratorKind = (declaration, discovery) => {
2032
+ const hasDecorators = (0, import_typescript12.canHaveDecorators)(declaration);
2033
+ if (!hasDecorators) return null;
2034
+ for (const decorator of (0, import_typescript12.getDecorators)(declaration) ?? []) {
2035
+ const isDecoratorCall = (0, import_typescript12.isCallExpression)(decorator.expression);
2036
+ if (!isDecoratorCall) continue;
2037
+ const kind = angularDecoratorKind(
2038
+ decorator.expression.expression,
2039
+ discovery
2040
+ );
2041
+ if (kind !== null) return kind;
2042
+ }
2043
+ return null;
2044
+ };
2045
+
2046
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.ts
2047
+ var import_node_path2 = require("node:path");
2048
+ var import_typescript13 = require("typescript");
2049
+ var stringValue = (node, discovery) => {
2050
+ if (!node) return null;
2051
+ const isStringLiteral = (0, import_typescript13.isStringLiteralLike)(node);
2052
+ if (isStringLiteral) return node.text;
2053
+ const isIdentifierNode = (0, import_typescript13.isIdentifier)(node);
2054
+ const isPropertyAccessNode = (0, import_typescript13.isPropertyAccessExpression)(node);
2055
+ if (isIdentifierNode || isPropertyAccessNode) {
2056
+ const symbol = discovery.checker.getSymbolAtLocation(
2057
+ (0, import_typescript13.isIdentifier)(node) ? node : node.name
2058
+ );
2059
+ if (symbol) {
2060
+ resolveAlias(symbol, discovery);
2061
+ }
2062
+ }
2063
+ const type = discovery.checker.getTypeAtLocation(node);
2064
+ return type.isStringLiteral() ? type.value : null;
2065
+ };
2066
+ var metadataProperty = (metadata, name) => {
2067
+ for (const property of metadata.properties) {
2068
+ const isAssignment = (0, import_typescript13.isPropertyAssignment)(property);
2069
+ if (!isAssignment) continue;
2070
+ const isIdentifierName = (0, import_typescript13.isIdentifier)(property.name);
2071
+ const isStringName = (0, import_typescript13.isStringLiteralLike)(property.name);
2072
+ const isNumericName = (0, import_typescript13.isNumericLiteral)(property.name);
2073
+ const isLiteralName = isIdentifierName || isStringName || isNumericName;
2074
+ const isPropertyNamed = isLiteralName && property.name.text === name;
2075
+ if (isPropertyNamed) return property.initializer;
2076
+ }
2077
+ return void 0;
2078
+ };
2079
+ var templateOf = (metadata, fileName, discovery) => {
2080
+ const inline = metadataProperty(metadata, "template");
2081
+ if (inline) {
2082
+ const source = stringValue(inline, discovery);
2083
+ if (source === null) return void 0;
2084
+ const inlineTemplate = { kind: "inline", source };
2085
+ return inlineTemplate;
2086
+ }
2087
+ const url = metadataProperty(metadata, "templateUrl");
2088
+ if (url) {
2089
+ const text2 = stringValue(url, discovery);
2090
+ if (text2 === null) return void 0;
2091
+ const externalFileName = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(fileName), text2);
2092
+ const externalTemplate = {
2093
+ fileName: externalFileName,
2094
+ kind: "external"
2095
+ };
2096
+ return externalTemplate;
2097
+ }
2098
+ return null;
2099
+ };
2100
+ var exportAsOf = (metadata, discovery) => {
2101
+ const exportAsProperty = metadataProperty(metadata, "exportAs");
2102
+ const exportAs = stringValue(exportAsProperty, discovery) ?? "";
2103
+ const names = exportAs.split(",").map((name) => name.trim());
2104
+ return names.filter(Boolean);
2105
+ };
2106
+
2107
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.ts
2108
+ var booleanValue = (node) => {
2109
+ if (!node) return void 0;
2110
+ if (node.kind === import_typescript14.SyntaxKind.TrueKeyword) return true;
2111
+ if (node.kind === import_typescript14.SyntaxKind.FalseKeyword) return false;
2112
+ return void 0;
2113
+ };
2114
+ var classesOf = (symbol, discovery) => {
2115
+ const resolved = resolveAlias(symbol, discovery);
2116
+ const declarations = resolved.declarations ?? [];
2117
+ return declarations.filter(import_typescript14.isClassLike);
2118
+ };
2119
+ var scopedClasses = (classes, discovery) => {
2120
+ const scoped = [];
2121
+ for (const declaration of classes) {
2122
+ if (declaration.getSourceFile().isDeclarationFile) continue;
2123
+ const kind = classDecoratorKind(declaration, discovery);
2124
+ if (kind === "Pipe") continue;
2125
+ if (kind !== "Component" && kind !== "Directive") return null;
2126
+ scoped.push(declaration);
2127
+ }
2128
+ return scoped;
2129
+ };
2130
+ var importedClasses = (element, discovery) => {
2131
+ const isIdentifierElement = (0, import_typescript14.isIdentifier)(element);
2132
+ const isPropertyAccessElement = (0, import_typescript14.isPropertyAccessExpression)(element);
2133
+ if (!isIdentifierElement && !isPropertyAccessElement) return null;
2134
+ const target = isIdentifierElement ? element : element.name;
2135
+ const symbol = discovery.checker.getSymbolAtLocation(target);
2136
+ if (!symbol) return null;
2137
+ const classes = classesOf(symbol, discovery);
2138
+ if (classes.length === 0) return null;
2139
+ return scopedClasses(classes, discovery);
2140
+ };
2141
+ var scopeOf = (metadata, discovery) => {
2142
+ const standalone = booleanValue(metadataProperty(metadata, "standalone"));
2143
+ const imports = metadataProperty(metadata, "imports");
2144
+ const isModuleDeclared = standalone === void 0 && !imports;
2145
+ if (standalone === false || isModuleDeclared) return null;
2146
+ if (!imports) return [];
2147
+ const isImportsArray = (0, import_typescript14.isArrayLiteralExpression)(imports);
2148
+ if (!isImportsArray) return null;
2149
+ const scope = [];
2150
+ for (const element of imports.elements) {
2151
+ const classes = importedClasses(element, discovery);
2152
+ if (classes === null) return null;
2153
+ scope.push(...classes);
2154
+ }
2155
+ return scope;
2156
+ };
2157
+
2158
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.ts
2159
+ var describedClass = (base2, metadata, discovery) => {
2160
+ const selector = metadataProperty(metadata, "selector");
2161
+ const described = {
2162
+ ...base2,
2163
+ exportAs: exportAsOf(metadata, discovery),
2164
+ hostDirectives: metadataProperty(metadata, "hostDirectives") !== void 0,
2165
+ selector: stringValue(selector, discovery)
2166
+ };
2167
+ if (!base2.component) {
2168
+ const directiveDiscovery = { ...described, valid: true };
2169
+ return directiveDiscovery;
2170
+ }
2171
+ const fileName = base2.declaration.getSourceFile().fileName;
2172
+ const template = templateOf(metadata, fileName, discovery);
2173
+ const componentDiscovery = {
2174
+ ...described,
2175
+ scope: scopeOf(metadata, discovery),
2176
+ template: template ?? null,
2177
+ valid: template !== void 0
2178
+ };
2179
+ return componentDiscovery;
2180
+ };
2181
+ var decoratedClass = (declaration, call, discovery) => {
2182
+ const kind = angularDecoratorKind(call.expression, discovery);
2183
+ if (kind !== "Component" && kind !== "Directive") return null;
2184
+ const component = kind === "Component";
2185
+ const base2 = {
2186
+ component,
2187
+ declaration,
2188
+ exportAs: [],
2189
+ hostDirectives: false,
2190
+ name: declaration.name?.text ?? "",
2191
+ scope: null,
2192
+ selector: null,
2193
+ template: null
2194
+ };
2195
+ const metadata = call.arguments.at(0);
2196
+ if (metadata === void 0) {
2197
+ const bareDiscovery = { ...base2, valid: !component };
2198
+ return bareDiscovery;
2199
+ }
2200
+ const isMetadataObject = (0, import_typescript15.isObjectLiteralExpression)(metadata);
2201
+ if (!isMetadataObject) {
2202
+ const invalidDiscovery = { ...base2, valid: false };
2203
+ return invalidDiscovery;
2204
+ }
2205
+ return describedClass(base2, metadata, discovery);
2206
+ };
2207
+ var angularClass = (declaration, discovery) => {
2208
+ const hasDecorators = (0, import_typescript15.canHaveDecorators)(declaration);
2209
+ if (!hasDecorators) return null;
2210
+ for (const decorator of (0, import_typescript15.getDecorators)(declaration) ?? []) {
2211
+ const isDecoratorCall = (0, import_typescript15.isCallExpression)(decorator.expression);
2212
+ if (!isDecoratorCall) continue;
2213
+ const found = decoratedClass(declaration, decorator.expression, discovery);
2214
+ if (found) return found;
2215
+ }
2216
+ return null;
2217
+ };
2218
+ var angularClasses = (sourceFile, checker) => {
2219
+ const classes = [];
2220
+ const discovery = { checker, dependencies: /* @__PURE__ */ new Set() };
2221
+ const visit = (node) => {
2222
+ const isClass = (0, import_typescript15.isClassLike)(node);
2223
+ if (isClass) {
2224
+ const found = angularClass(node, discovery);
2225
+ if (found) {
2226
+ classes.push(found);
2227
+ }
2228
+ }
2229
+ (0, import_typescript15.forEachChild)(node, visit);
2230
+ };
2231
+ visit(sourceFile);
2232
+ discovery.dependencies.delete(sourceFile);
2233
+ const discovered = {
2234
+ classes,
2235
+ dependencies: discovery.dependencies
2236
+ };
2237
+ return discovered;
2238
+ };
2239
+
2240
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.util.ts
2241
+ var specFilePattern = /\.spec\.[cm]?[tj]sx?$/u;
2242
+ var isSpecFile = (fileName) => {
2243
+ return specFilePattern.test(fileName);
2244
+ };
2245
+
2246
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.ts
2247
+ var typeScriptFilePattern = /\.(?:[cm]?ts|tsx)$/u;
2248
+ var isIndexable = (program, sourceFile) => {
2249
+ if (sourceFile.isDeclarationFile) return false;
2250
+ const isExternal = program.isSourceFileFromExternalLibrary(sourceFile);
2251
+ if (isExternal) return false;
2252
+ const isSpec = isSpecFile(sourceFile.fileName);
2253
+ if (isSpec) return false;
2254
+ return typeScriptFilePattern.test(sourceFile.fileName);
2255
+ };
2256
+ var indexableSourceFiles = (program) => {
2257
+ const sourceFiles = program.getSourceFiles();
2258
+ return sourceFiles.filter((sourceFile) => isIndexable(program, sourceFile));
2259
+ };
2260
+ var sourceFileMaps = (program) => {
2261
+ const all = /* @__PURE__ */ new Map();
2262
+ const current = /* @__PURE__ */ new Map();
2263
+ for (const sourceFile of program.getSourceFiles()) {
2264
+ all.set(sourceFile.fileName, sourceFile);
2265
+ }
2266
+ for (const sourceFile of indexableSourceFiles(program)) {
2267
+ current.set(sourceFile.fileName, sourceFile);
2268
+ }
2269
+ const maps = { all, current };
2270
+ return maps;
2271
+ };
2272
+ var dropEntries = (index, stale) => {
2273
+ for (const [fileName, entry] of index.entries) {
2274
+ const isStale = stale(entry);
2275
+ if (isStale) {
2276
+ index.entries.delete(fileName);
2277
+ }
2278
+ }
2279
+ };
2280
+ var isReplaced = (sourceFile, dependencies, maps) => {
2281
+ const indexedSourceFile = maps.current.get(sourceFile.fileName);
2282
+ if (indexedSourceFile !== sourceFile) return true;
2283
+ for (const dependency of dependencies) {
2284
+ const indexedDependency = maps.all.get(dependency.fileName);
2285
+ if (indexedDependency !== dependency) return true;
2286
+ }
2287
+ return false;
2288
+ };
2289
+ var dropReplacedEntries = (index, maps) => {
2290
+ const isEntryReplaced = (entry) => {
2291
+ return isReplaced(entry.sourceFile, entry.dependencies, maps);
2292
+ };
2293
+ dropEntries(index, isEntryReplaced);
2294
+ };
2295
+ var dropEntriesMentioning = (index, names) => {
2296
+ if (names.size === 0) return;
2297
+ if (index.entries.size === 0) return;
2298
+ const nameList = [...names];
2299
+ const mentionsName = (entry) => {
2300
+ return nameList.some((name) => entry.sourceFile.text.includes(name));
2301
+ };
2302
+ dropEntries(index, mentionsName);
2303
+ };
2304
+ var templateVersionChecker = () => {
2305
+ const checked = /* @__PURE__ */ new Map();
2306
+ return (version) => {
2307
+ const key2 = `${version.fileName}\0${version.mtimeNs}\0${version.size}`;
2308
+ const known = checked.get(key2);
2309
+ if (known !== void 0) return known;
2310
+ const current = templateFileIsCurrent(version);
2311
+ checked.set(key2, current);
2312
+ return current;
2313
+ };
2314
+ };
2315
+ var dropStaleTemplateEntries = (index, force) => {
2316
+ const now = performance.now();
2317
+ const sinceLastCheck = now - index.templateCheckedAt;
2318
+ const isThrottled = !force && sinceLastCheck < index.templateCheckDuration * 100;
2319
+ if (isThrottled) return;
2320
+ const isCurrent = templateVersionChecker();
2321
+ const hasStaleTemplate = (entry) => {
2322
+ return !entry.templateVersions.every(isCurrent);
2323
+ };
2324
+ dropEntries(index, hasStaleTemplate);
2325
+ index.templateCheckedAt = now;
2326
+ index.templateCheckDuration = performance.now() - now;
2327
+ };
2328
+
2329
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-candidate-names.ts
2330
+ var import_typescript16 = require("typescript");
2331
+ var isDecoratedClass = (node) => {
2332
+ const isDecoratable = (0, import_typescript16.canHaveDecorators)(node);
2333
+ if (!isDecoratable) return false;
2334
+ const decorators = (0, import_typescript16.getDecorators)(node);
2335
+ const decoratorCount = decorators?.length ?? 0;
2336
+ return decoratorCount > 0;
2337
+ };
2338
+ var addMemberNames = (node, names) => {
2339
+ const isClass = (0, import_typescript16.isClassLike)(node);
2340
+ if (!isClass) return;
2341
+ const isDecorated = isDecoratedClass(node);
2342
+ if (!isDecorated) return;
2343
+ for (const member of node.members) {
2344
+ if (!member.name) continue;
2345
+ const isIdentifierName = (0, import_typescript16.isIdentifier)(member.name);
2346
+ const isStringName = (0, import_typescript16.isStringLiteralLike)(member.name);
2347
+ const isNamedMember = isIdentifierName || isStringName;
2348
+ if (isNamedMember) {
2349
+ names.add(member.name.text);
2350
+ }
2351
+ }
2352
+ };
2353
+ var collectCandidateNames = (sourceFile) => {
2354
+ const names = /* @__PURE__ */ new Set();
2355
+ const visit = (node) => {
2356
+ addMemberNames(node, names);
2357
+ (0, import_typescript16.forEachChild)(node, visit);
2358
+ };
2359
+ visit(sourceFile);
2360
+ return names;
2361
+ };
2362
+
2363
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.ts
2364
+ var dropReplacedClasses = (index, maps) => {
2365
+ let changed = false;
2366
+ for (const [fileName, fileClasses] of index.classes) {
2367
+ const replaced = isReplaced(
2368
+ fileClasses.sourceFile,
2369
+ fileClasses.dependencies,
2370
+ maps
2371
+ );
2372
+ if (!replaced) continue;
2373
+ index.classes.delete(fileName);
2374
+ changed = true;
2375
+ }
2376
+ return changed;
2377
+ };
2378
+ var addCandidateNames = (index, candidateNames, newNames) => {
2379
+ for (const name of candidateNames) {
2380
+ const isKnownName = index.candidateNames.has(name);
2381
+ if (isKnownName) continue;
2382
+ index.candidateNames.add(name);
2383
+ newNames.add(name);
2384
+ }
2385
+ };
2386
+ var indexFileClasses = (index, sourceFile, checker, newNames) => {
2387
+ const candidateNames = collectCandidateNames(sourceFile);
2388
+ addCandidateNames(index, candidateNames, newNames);
2389
+ const { classes, dependencies } = angularClasses(sourceFile, checker());
2390
+ const fileClasses = {
2391
+ candidateNames,
2392
+ classes,
2393
+ dependencies,
2394
+ sourceFile
2395
+ };
2396
+ index.classes.set(sourceFile.fileName, fileClasses);
2397
+ index.entries.delete(sourceFile.fileName);
2398
+ };
2399
+ var indexNewClasses = (index, current, checker, newNames) => {
2400
+ let changed = false;
2401
+ for (const [fileName, sourceFile] of current) {
2402
+ const isIndexed = index.classes.has(fileName);
2403
+ if (isIndexed) continue;
2404
+ indexFileClasses(index, sourceFile, checker, newNames);
2405
+ changed = true;
2406
+ }
2407
+ return changed;
2408
+ };
2409
+ var rebuildDirectives = (index) => {
2410
+ const fileClasses = [...index.classes.values()];
2411
+ const classes = fileClasses.flatMap((entry) => entry.classes);
2412
+ const shape = directiveShape(classes);
2413
+ index.directives = buildDirectiveIndex(classes);
2414
+ if (shape === index.directiveShape) return;
2415
+ index.directiveShape = shape;
2416
+ dropEntries(index, (entry) => entry.usedDirectiveIndex);
2417
+ };
2418
+ var reconcileClasses = (index, maps, checker) => {
2419
+ const newNames = /* @__PURE__ */ new Set();
2420
+ const droppedClasses = dropReplacedClasses(index, maps);
2421
+ const addedClasses = indexNewClasses(index, maps.current, checker, newNames);
2422
+ const changed = droppedClasses || addedClasses;
2423
+ if (changed) {
2424
+ rebuildDirectives(index);
2425
+ }
2426
+ return newNames;
2427
+ };
2428
+
2429
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.ts
2430
+ var lazyChecker = (program) => {
2431
+ let typeChecker;
2432
+ return () => typeChecker ??= program.getTypeChecker();
2433
+ };
2434
+ var indexMissingEntries = (index, sourceFiles, checker) => {
2435
+ for (const sourceFile of sourceFiles) {
2436
+ const isEntryIndexed = index.entries.has(sourceFile.fileName);
2437
+ if (isEntryIndexed) continue;
2438
+ const entry = computeEntry(index, sourceFile, checker());
2439
+ index.entries.set(sourceFile.fileName, entry);
2440
+ }
2441
+ };
2442
+ var reindexProgram = (index, program, checker) => {
2443
+ const maps = sourceFileMaps(program);
2444
+ dropReplacedEntries(index, maps);
2445
+ const newNames = reconcileClasses(index, maps, checker);
2446
+ dropEntriesMentioning(index, newNames);
2447
+ index.program = program;
2448
+ index.usage = void 0;
2449
+ dropStaleTemplateEntries(index, true);
2450
+ indexMissingEntries(index, maps.current.values(), checker);
2451
+ };
2452
+ var refreshTemplateEntries = (index, program, checker) => {
2453
+ const entryCount = index.entries.size;
2454
+ dropStaleTemplateEntries(index, false);
2455
+ const isUnchanged = index.entries.size === entryCount;
2456
+ if (isUnchanged) return;
2457
+ index.usage = void 0;
2458
+ indexMissingEntries(index, indexableSourceFiles(program), checker);
2459
+ };
2460
+ var reconcile = (index, program) => {
2461
+ const checker = lazyChecker(program);
2462
+ const isNewProgram = index.program !== program;
2463
+ if (isNewProgram) {
2464
+ reindexProgram(index, program, checker);
2465
+ return;
2466
+ }
2467
+ refreshTemplateEntries(index, program, checker);
2468
+ };
2469
+
2470
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
2471
+ var indexes = /* @__PURE__ */ new Map();
2472
+ var memberName = (node) => {
2473
+ const isMember = (0, import_typescript17.isClassElement)(node);
2474
+ if (!isMember) return null;
2475
+ if (!node.name) return null;
2476
+ const isIdentifierName = (0, import_typescript17.isIdentifier)(node.name);
2477
+ const isStringName = (0, import_typescript17.isStringLiteralLike)(node.name);
2478
+ const isNamedMember = isIdentifierName || isStringName;
2479
+ if (!isNamedMember) return null;
2480
+ return node.name.text;
2481
+ };
2482
+ var usageOf = (index) => {
2483
+ if (index.usage !== void 0) return index.usage;
2484
+ const declarations = /* @__PURE__ */ new Set();
2485
+ const fallbackNames = /* @__PURE__ */ new Set();
2486
+ for (const entry of index.entries.values()) {
2487
+ for (const declaration of entry.declarations) {
2488
+ declarations.add(declaration);
2489
+ }
2490
+ for (const name of entry.fallbackNames) {
2491
+ fallbackNames.add(name);
2492
+ }
2493
+ }
2494
+ index.usage = {
2495
+ has: (node) => {
2496
+ const hasDeclaration = declarations.has(node);
2497
+ if (hasDeclaration) return true;
2498
+ if (fallbackNames.size === 0) return false;
2499
+ const name = memberName(node);
2500
+ return name !== null && fallbackNames.has(name);
2501
+ }
2502
+ };
2503
+ return index.usage;
2504
+ };
2505
+ var createIndex = () => {
2506
+ const emptyIndex = {
2507
+ candidateNames: /* @__PURE__ */ new Set(),
2508
+ classes: /* @__PURE__ */ new Map(),
2509
+ directives: buildDirectiveIndex([]),
2510
+ directiveShape: "",
2511
+ entries: /* @__PURE__ */ new Map(),
2512
+ program: null,
2513
+ templateCheckDuration: 0,
2514
+ templateCheckedAt: 0,
2515
+ usage: void 0
2516
+ };
2517
+ return emptyIndex;
2518
+ };
2519
+ var projectUsageIsCurrent = (program) => {
2520
+ const configFilePath = program.getCompilerOptions()["configFilePath"];
2521
+ return typeof configFilePath === "string" && indexes.get(configFilePath)?.program === program;
2522
+ };
2523
+ var projectUsage = (program) => {
2524
+ const configFilePath = program.getCompilerOptions()["configFilePath"];
2525
+ if (typeof configFilePath !== "string") return null;
2526
+ let index = indexes.get(configFilePath);
2527
+ if (!index) {
2528
+ index = createIndex();
2529
+ indexes.set(configFilePath, index);
2530
+ }
2531
+ try {
2532
+ reconcile(index, program);
2533
+ return usageOf(index);
2534
+ } catch {
2535
+ indexes.delete(configFilePath);
2536
+ return null;
2537
+ }
2538
+ };
2539
+
2540
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.ts
2541
+ var docs = {
2542
+ description: "Disallow unread instance fields and methods in Angular components and directives"
2543
+ };
2544
+ var messages = {
2545
+ unusedField: "Angular instance field '{{name}}' is never read.",
2546
+ unusedMethod: "Angular instance method '{{name}}' is never read."
2547
+ };
2548
+ var allowEffectFieldsSchema = {
2549
+ type: "boolean",
2550
+ description: "Allow Angular effect() fields with automatic cleanup."
2551
+ };
2552
+ var analysisSchema = {
2553
+ type: "string",
2554
+ enum: ["local", "project"],
2555
+ description: "Choose local-file or typed whole-project analysis."
2556
+ };
2557
+ var properties = {
2558
+ allowEffectFields: allowEffectFieldsSchema,
2559
+ analysis: analysisSchema
2560
+ };
2561
+ var optionsSchema = {
2562
+ type: "object",
2563
+ properties,
2564
+ additionalProperties: false
2565
+ };
2566
+ var schema = [optionsSchema];
2567
+ var meta = {
2568
+ type: "problem",
2569
+ docs,
2570
+ schema,
2571
+ messages
2572
+ };
2573
+ var ruleDefaults = {
2574
+ allowEffectFields: false,
2575
+ analysis: "local"
2576
+ };
2577
+ var defaultOptions = [ruleDefaults];
2578
+ var createRule = import_utils10.ESLintUtils.RuleCreator(
2579
+ () => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
2580
+ );
2581
+ var projectParserServices = (context, analysis) => {
2582
+ if (analysis !== "project") return void 0;
2583
+ try {
2584
+ return import_utils10.ESLintUtils.getParserServices(context);
2585
+ } catch {
2586
+ throw new Error(
2587
+ "Project analysis requires parser services with type information."
2588
+ );
2589
+ }
2590
+ };
2591
+ var projectMemberUsedFor = (parserServices) => {
2592
+ if (parserServices === void 0) return void 0;
2593
+ let usage;
2594
+ const memberUsed = (node) => {
2595
+ if (usage === void 0) {
2596
+ usage = projectUsage(parserServices.program);
2597
+ }
2598
+ return usage?.has(parserServices.esTreeNodeToTSNodeMap.get(node)) ?? true;
2599
+ };
2600
+ return memberUsed;
2601
+ };
2602
+ var no_unused_angular_instance_fields_default = createRule({
2603
+ name: "no-unused-instance-fields",
2604
+ meta,
2605
+ defaultOptions,
2606
+ create(context, [options]) {
2607
+ const analysis = options.analysis ?? "local";
2608
+ const isSpec = isSpecFile(context.filename);
2609
+ const noListeners = {};
2610
+ if (analysis === "project" && isSpec) return noListeners;
2611
+ const parserServices = projectParserServices(context, analysis);
2612
+ const imports = angularClassImports(context.sourceCode.ast);
2613
+ if (!imports) return noListeners;
2614
+ const classes = [];
2615
+ const stack = [];
2616
+ const dynamicClasses = /* @__PURE__ */ new Set();
2617
+ const projectIndexed = () => {
2618
+ if (parserServices === void 0) return false;
2619
+ return projectUsageIsCurrent(parserServices.program);
2620
+ };
2621
+ const reportOptions = {
2622
+ allowEffectFields: options.allowEffectFields ?? false,
2623
+ classes,
2624
+ context,
2625
+ dynamicClasses,
2626
+ imports,
2627
+ projectIndexed,
2628
+ projectMemberUsed: projectMemberUsedFor(parserServices)
2629
+ };
2630
+ const readListeners = classReadVisitor(classes, stack, dynamicClasses);
2631
+ const listeners = {
2632
+ ...readListeners,
2633
+ "Program:exit"() {
2634
+ reportUnusedMembers(reportOptions);
2635
+ }
2636
+ };
2637
+ return listeners;
2638
+ }
2639
+ });
2640
+
2641
+ // packages/lint-suite/src/lib/angular.ts
2642
+ var lintSuiteAngularPlugin = definePlugin("lint-suite-angular", {
2643
+ "no-unused-instance-fields": no_unused_angular_instance_fields_default
2644
+ });
2645
+ var angular = (0, import_config2.defineConfig)([
2646
+ {
2647
+ files: ["**/*.ts"],
2648
+ extends: [...import_angular_eslint2.configs.tsRecommended],
2649
+ plugins: {
2650
+ "lint-suite-angular": lintSuiteAngularPlugin
2651
+ },
2652
+ languageOptions: {
2653
+ globals: {
2654
+ ...import_globals.default.browser,
2655
+ ...import_globals.default.es2025,
2656
+ ...import_globals.default.node
2657
+ },
2658
+ parserOptions: {
2659
+ projectService: true
2660
+ }
2661
+ },
2662
+ processor: import_angular_eslint2.processInlineTemplates,
2663
+ rules: {
2664
+ "lint-suite-angular/no-unused-instance-fields": [
2665
+ "error",
2666
+ { analysis: "project" }
2667
+ ],
2668
+ "@angular-eslint/prefer-on-push-component-change-detection": "error",
2669
+ // v22: flags only explicit opt-out of OnPush (omission now means OnPush)
2670
+ "@angular-eslint/prefer-signals": "error",
2671
+ "@angular-eslint/use-injectable-provided-in": "error",
2672
+ "@angular-eslint/prefer-signal-model": "error",
2673
+ "@angular-eslint/no-uncalled-signals": "error",
2674
+ "@angular-eslint/prefer-host-metadata-property": "error",
2675
+ "@angular-eslint/no-implicit-take-until-destroyed": "error",
2676
+ // v21.2.0: Enforce explicit DestroyRef
2677
+ "@angular-eslint/no-async-lifecycle-method": "error",
2678
+ // Prevent async lifecycle hooks
2679
+ "@angular-eslint/prefer-output-readonly": "warn",
2680
+ // Prevent accidental reassignment
2681
+ "@angular-eslint/prefer-output-emitter-ref": "warn",
2682
+ // Modern output() function over @Output()
2683
+ "@angular-eslint/sort-lifecycle-methods": "warn",
2684
+ // Consistent lifecycle method ordering
2685
+ "@angular-eslint/computed-must-return": "error",
2686
+ // Catch silent computed() bugs missing a return
2687
+ "@angular-eslint/no-duplicates-in-metadata-arrays": "error",
2688
+ // Catch duplicate imports/providers in @Component/@NgModule
2689
+ "@angular-eslint/no-lifecycle-call": "error",
2690
+ // Forbid manual this.ngOnInit() calls
2691
+ "@angular-eslint/require-lifecycle-on-prototype": "error",
2692
+ // Lifecycle hooks must be methods, not arrow-fn fields
2693
+ "@angular-eslint/relative-url-prefix": "error",
2694
+ // Require ./ in templateUrl/styleUrl for portability
2695
+ "@angular-eslint/use-component-selector": "error",
2696
+ // All components must declare a selector
2697
+ "@angular-eslint/no-developer-preview": "warn",
2698
+ // Flag APIs marked @developerPreview (no breaking-change policy)
2699
+ "@angular-eslint/no-experimental": "warn"
2700
+ // Flag APIs marked @experimental
2701
+ }
2702
+ }
2703
+ ]);
2704
+
2705
+ // packages/lint-suite/src/lib/base.ts
2706
+ var import_config6 = require("eslint/config");
2707
+
2708
+ // packages/lint-suite/src/lib/base-limits.ts
2709
+ var import_config3 = require("eslint/config");
2710
+ var baseLimits = (0, import_config3.defineConfig)([
2711
+ {
2712
+ files: [
2713
+ "**/*.js",
2714
+ "**/*.jsx",
2715
+ "**/*.cjs",
2716
+ "**/*.mjs",
2717
+ "**/*.ts",
2718
+ "**/*.tsx",
2719
+ "**/*.cts",
2720
+ "**/*.mts",
2721
+ "**/*.html"
2722
+ ],
2723
+ rules: {
2724
+ "max-lines": [
2725
+ "error",
2726
+ {
2727
+ max: 150,
2728
+ skipBlankLines: true,
2729
+ skipComments: true
2730
+ }
2731
+ ]
2732
+ }
2733
+ },
2734
+ {
2735
+ files: [
2736
+ "**/*.spec.ts",
2737
+ "**/*.test.ts",
2738
+ "**/*.spec.js",
2739
+ "**/*.test.js",
2740
+ "**/*.e2e.ts",
2741
+ "**/*.e2e.js"
2742
+ ],
2743
+ rules: {
2744
+ "max-lines-per-function": "off",
2745
+ complexity: ["warn", { max: 3 }],
2746
+ "max-lines": [
2747
+ "error",
2748
+ {
2749
+ max: 300,
2750
+ skipBlankLines: true,
2751
+ skipComments: true
2752
+ }
2753
+ ]
2754
+ }
2755
+ },
2756
+ {
2757
+ files: ["**/*.action.ts"],
2758
+ rules: {
2759
+ "max-classes-per-file": "off"
2760
+ }
2761
+ },
2762
+ {
2763
+ files: ["**/*.state.ts"],
2764
+ rules: {
2765
+ "class-methods-use-this": "off"
2766
+ }
2767
+ }
2768
+ ]);
2769
+
2770
+ // packages/lint-suite/src/lib/base-practices.ts
2771
+ var import_config4 = require("eslint/config");
2772
+ var basePractices = (0, import_config4.defineConfig)([
2773
+ {
2774
+ files: [
2775
+ "**/*.js",
2776
+ "**/*.jsx",
2777
+ "**/*.cjs",
2778
+ "**/*.mjs",
2779
+ "**/*.ts",
2780
+ "**/*.tsx",
2781
+ "**/*.cts",
2782
+ "**/*.mts"
2783
+ ],
2784
+ rules: {
2785
+ "no-param-reassign": "error",
2786
+ "no-alert": "error",
2787
+ "no-console": ["warn", { allow: ["warn", "error"] }],
2788
+ "no-debugger": "error",
2789
+ eqeqeq: ["error", "always", { null: "ignore" }],
2790
+ curly: ["error", "multi-line"],
2791
+ "prefer-const": ["error", { destructuring: "all" }],
2792
+ "no-var": "error",
2793
+ "object-shorthand": "error",
2794
+ "prefer-arrow-callback": "error",
2795
+ "no-useless-concat": "error",
2796
+ "prefer-template": "error",
2797
+ "no-nested-ternary": "error",
2798
+ "no-useless-assignment": "error",
2799
+ // NEW: Catch unused assignments (ESLint v9)
2800
+ "no-object-constructor": "error",
2801
+ // Disallow new Object() without arguments
2802
+ "no-else-return": ["error", { allowElseIf: false }],
2803
+ // Prefer early returns
2804
+ "no-multi-assign": "error",
2805
+ // Disallow chaining assignments
2806
+ radix: "error",
2807
+ // Require radix parameter for parseInt()
2808
+ yoda: "error",
2809
+ // Disallow yoda conditions (`if ("red" === color)`)
2810
+ complexity: ["warn", 10],
2811
+ // Warn if function complexity is high
2812
+ "max-depth": ["warn", 4],
2813
+ // Warn on deeply nested blocks
2814
+ "max-lines-per-function": [
2815
+ "warn",
2816
+ { max: 50, skipBlankLines: true, skipComments: true }
2817
+ ],
2818
+ // Warn on long functions
2819
+ "max-params": ["warn", 4],
839
2820
  // Warn on functions with many parameters
840
2821
  "no-lonely-if": "error",
841
2822
  // Disallow if statements as the only statement in an else block
@@ -915,7 +2896,16 @@ var base = (0, import_config3.defineConfig)([
915
2896
  }
916
2897
  ]
917
2898
  }
918
- },
2899
+ }
2900
+ ]);
2901
+
2902
+ // packages/lint-suite/src/lib/base-recommended.ts
2903
+ var import_eslint_plugin = require("@nx/eslint-plugin");
2904
+ var import_eslint_plugin2 = __toESM(require("@stylistic/eslint-plugin"), 1);
2905
+ var import_config5 = require("eslint/config");
2906
+ var import_eslint_plugin_import_x = __toESM(require("eslint-plugin-import-x"), 1);
2907
+ var baseRecommended = (0, import_config5.defineConfig)([
2908
+ { extends: [...import_eslint_plugin.configs["flat/base"]] },
919
2909
  {
920
2910
  files: [
921
2911
  "**/*.js",
@@ -925,68 +2915,161 @@ var base = (0, import_config3.defineConfig)([
925
2915
  "**/*.ts",
926
2916
  "**/*.tsx",
927
2917
  "**/*.cts",
928
- "**/*.mts",
929
- "**/*.html"
2918
+ "**/*.mts"
930
2919
  ],
931
- rules: {
932
- "max-lines": [
933
- "error",
934
- {
935
- max: 150,
936
- skipBlankLines: true,
937
- skipComments: true
938
- }
939
- ]
940
- }
2920
+ extends: [import_eslint_plugin_import_x.default.flatConfigs.recommended]
941
2921
  },
942
2922
  {
943
2923
  files: [
944
- "**/*.spec.ts",
945
- "**/*.test.ts",
946
- "**/*.spec.js",
947
- "**/*.test.js",
948
- "**/*.e2e.ts",
949
- "**/*.e2e.js"
2924
+ "**/*.js",
2925
+ "**/*.jsx",
2926
+ "**/*.cjs",
2927
+ "**/*.mjs",
2928
+ "**/*.ts",
2929
+ "**/*.tsx",
2930
+ "**/*.cts",
2931
+ "**/*.mts"
2932
+ ],
2933
+ extends: [import_eslint_plugin2.default.configs.recommended]
2934
+ }
2935
+ ]);
2936
+
2937
+ // packages/lint-suite/src/lib/base.ts
2938
+ var base = (0, import_config6.defineConfig)([
2939
+ ...baseRecommended,
2940
+ ...basePractices,
2941
+ ...baseLimits
2942
+ ]);
2943
+
2944
+ // packages/lint-suite/src/lib/boundaries.ts
2945
+ var import_config7 = require("eslint/config");
2946
+ var import_eslint_plugin_boundaries = __toESM(require("eslint-plugin-boundaries"), 1);
2947
+ var boundaries = (0, import_config7.defineConfig)([
2948
+ {
2949
+ files: [
2950
+ "**/*.js",
2951
+ "**/*.jsx",
2952
+ "**/*.ts",
2953
+ "**/*.tsx",
2954
+ "**/*.cts",
2955
+ "**/*.mts"
950
2956
  ],
2957
+ plugins: {
2958
+ boundaries: import_eslint_plugin_boundaries.default
2959
+ },
2960
+ settings: {
2961
+ "boundaries/elements": [
2962
+ {
2963
+ type: "feature",
2964
+ pattern: "**/feature/**"
2965
+ },
2966
+ {
2967
+ type: "data-access",
2968
+ pattern: "**/data-access/**"
2969
+ },
2970
+ {
2971
+ type: "domain-logic",
2972
+ pattern: "**/domain-logic/**"
2973
+ },
2974
+ {
2975
+ type: "ui",
2976
+ pattern: "**/ui/**"
2977
+ },
2978
+ {
2979
+ type: "common",
2980
+ pattern: "**/common/**"
2981
+ },
2982
+ {
2983
+ type: "utils",
2984
+ pattern: "**/utils/**"
2985
+ }
2986
+ ],
2987
+ "import/resolver": {
2988
+ typescript: {
2989
+ alwaysTryTypes: true
2990
+ }
2991
+ }
2992
+ },
951
2993
  rules: {
952
- "max-lines-per-function": "off",
953
- complexity: ["warn", { max: 3 }],
954
- "max-lines": [
2994
+ ...import_eslint_plugin_boundaries.default.configs.recommended.rules,
2995
+ "boundaries/dependencies": [
955
2996
  "error",
956
2997
  {
957
- max: 300,
958
- skipBlankLines: true,
959
- skipComments: true
2998
+ default: "disallow",
2999
+ message: "{{to.element.types}} is not allowed to be imported in {{from.element.types}}",
3000
+ policies: [
3001
+ {
3002
+ from: { element: { type: "feature" } },
3003
+ allow: [
3004
+ { to: { element: { type: "feature" } } },
3005
+ { to: { element: { type: "ui" } } },
3006
+ { to: { element: { type: "domain-logic" } } },
3007
+ { to: { element: { type: "utils" } } },
3008
+ { to: { element: { type: "common" } } }
3009
+ ]
3010
+ },
3011
+ {
3012
+ from: { element: { type: "domain-logic" } },
3013
+ allow: [
3014
+ { to: { element: { type: "domain-logic" } } },
3015
+ { to: { element: { type: "data-access" } } },
3016
+ { to: { element: { type: "utils" } } },
3017
+ { to: { element: { type: "common" } } }
3018
+ ]
3019
+ },
3020
+ {
3021
+ from: { element: { type: "data-access" } },
3022
+ allow: [
3023
+ { to: { element: { type: "data-access" } } },
3024
+ { to: { element: { type: "utils" } } },
3025
+ { to: { element: { type: "common" } } }
3026
+ ]
3027
+ },
3028
+ {
3029
+ from: { element: { type: "ui" } },
3030
+ allow: [
3031
+ { to: { element: { type: "ui" } } },
3032
+ { to: { element: { type: "utils" } } },
3033
+ { to: { element: { type: "common" } } }
3034
+ ]
3035
+ },
3036
+ {
3037
+ from: { element: { type: "utils" } },
3038
+ allow: [
3039
+ { to: { element: { type: "utils" } } },
3040
+ { to: { element: { type: "common" } } }
3041
+ ]
3042
+ },
3043
+ {
3044
+ from: { element: { type: "common" } },
3045
+ allow: [{ to: { element: { type: "common" } } }]
3046
+ }
3047
+ ]
960
3048
  }
961
3049
  ]
962
3050
  }
963
3051
  },
964
3052
  {
965
- files: ["**/*.action.ts"],
966
- rules: {
967
- "max-classes-per-file": "off"
968
- }
969
- },
970
- {
971
- files: ["**/*.state.ts"],
3053
+ files: ["**/*.stories.ts"],
972
3054
  rules: {
973
- "class-methods-use-this": "off"
3055
+ "boundaries/dependencies": "off"
974
3056
  }
975
3057
  }
976
3058
  ]);
977
3059
 
978
3060
  // packages/lint-suite/src/lib/javascript.ts
979
3061
  var import_eslint_plugin3 = require("@nx/eslint-plugin");
980
- var import_config4 = require("eslint/config");
981
- var javascript = (0, import_config4.defineConfig)({
3062
+ var import_config8 = require("eslint/config");
3063
+ var nxJavascript = import_eslint_plugin3.configs["flat/javascript"];
3064
+ var javascript = (0, import_config8.defineConfig)({
982
3065
  files: ["**/*.js", "**/*.jsx", "**/*.cjs", "**/*.mjs"],
983
- extends: [...import_eslint_plugin3.configs["flat/javascript"]]
3066
+ extends: nxJavascript
984
3067
  });
985
3068
 
986
3069
  // packages/lint-suite/src/lib/json.ts
987
3070
  var import_json = __toESM(require("@eslint/json"), 1);
988
- var import_config5 = require("eslint/config");
989
- var json = (0, import_config5.defineConfig)([
3071
+ var import_config9 = require("eslint/config");
3072
+ var json = (0, import_config9.defineConfig)([
990
3073
  {
991
3074
  plugins: { json: import_json.default }
992
3075
  },
@@ -997,15 +3080,40 @@ var json = (0, import_config5.defineConfig)([
997
3080
  }
998
3081
  ]);
999
3082
 
3083
+ // packages/lint-suite/src/lib/playwright.ts
3084
+ var import_config10 = require("eslint/config");
3085
+ var import_eslint_plugin_playwright = __toESM(require("eslint-plugin-playwright"), 1);
3086
+ var playwright = (0, import_config10.defineConfig)([
3087
+ {
3088
+ ...import_eslint_plugin_playwright.default.configs["flat/recommended"],
3089
+ files: ["**/*.e2e.ts", "**/*.e2e.js"],
3090
+ rules: {
3091
+ ...import_eslint_plugin_playwright.default.configs["flat/recommended"].rules,
3092
+ // Locator best practices
3093
+ "playwright/prefer-locator": "error",
3094
+ "playwright/prefer-native-locators": "error",
3095
+ "playwright/no-nth-methods": "warn",
3096
+ // Matcher improvements
3097
+ "playwright/prefer-to-be": "error",
3098
+ "playwright/prefer-to-have-count": "error",
3099
+ "playwright/prefer-to-have-length": "error",
3100
+ "playwright/prefer-comparison-matcher": "error",
3101
+ // Test structure
3102
+ "playwright/prefer-hooks-on-top": "error",
3103
+ "playwright/require-top-level-describe": "warn"
3104
+ }
3105
+ }
3106
+ ]);
3107
+
1000
3108
  // packages/lint-suite/src/lib/prettier.ts
3109
+ var import_config11 = require("eslint/config");
1001
3110
  var import_eslint_config_prettier = __toESM(require("eslint-config-prettier"), 1);
1002
- var import_config6 = require("eslint/config");
1003
- var prettier = (0, import_config6.defineConfig)([import_eslint_config_prettier.default]);
3111
+ var prettier = (0, import_config11.defineConfig)([import_eslint_config_prettier.default]);
1004
3112
 
1005
3113
  // packages/lint-suite/src/lib/rxjs.ts
1006
3114
  var import_eslint_plugin_rxjs = __toESM(require("@smarttools/eslint-plugin-rxjs"), 1);
1007
- var import_config7 = require("eslint/config");
1008
- var rxjs = (0, import_config7.defineConfig)([
3115
+ var import_config12 = require("eslint/config");
3116
+ var rxjs = (0, import_config12.defineConfig)([
1009
3117
  {
1010
3118
  files: [
1011
3119
  "**/*.js",
@@ -1080,9 +3188,9 @@ var rxjs = (0, import_config7.defineConfig)([
1080
3188
  ]);
1081
3189
 
1082
3190
  // packages/lint-suite/src/lib/storybook.ts
3191
+ var import_config13 = require("eslint/config");
1083
3192
  var import_eslint_plugin_storybook = __toESM(require("eslint-plugin-storybook"), 1);
1084
- var import_config8 = require("eslint/config");
1085
- var storybook = (0, import_config8.defineConfig)([
3193
+ var storybook = (0, import_config13.defineConfig)([
1086
3194
  {
1087
3195
  ignores: ["!.storybook"],
1088
3196
  files: ["**/*.stories.ts"],
@@ -1097,263 +3205,14 @@ var storybook = (0, import_config8.defineConfig)([
1097
3205
  ]);
1098
3206
 
1099
3207
  // packages/lint-suite/src/lib/typescript.ts
1100
- var import_eslint_plugin4 = require("@nx/eslint-plugin");
1101
- var import_eslint_import_resolver_typescript = require("eslint-import-resolver-typescript");
1102
- var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"), 1);
1103
- var import_config9 = require("eslint/config");
1104
-
1105
- // packages/lint-suite/src/lib/rules/explicit-accessibility.ts
1106
- var import_utils5 = require("@typescript-eslint/utils");
1107
- var createRule2 = import_utils5.ESLintUtils.RuleCreator(
1108
- () => "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
1109
- );
1110
- var defaultOptions = {
1111
- defaultAccessibility: "private"
1112
- };
1113
- var getNodeName = (node) => {
1114
- if (!node) {
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>";
1125
- }
1126
- if ("kind" in node && node.kind === "constructor") {
1127
- return "constructor";
1128
- }
1129
- if (node.type === import_utils5.TSESTree.AST_NODE_TYPES.TSParameterProperty) {
1130
- const param = node.parameter;
1131
- if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
1132
- return param.name;
1133
- }
1134
- if (param.type === import_utils5.TSESTree.AST_NODE_TYPES.AssignmentPattern) {
1135
- if (param.left.type === import_utils5.TSESTree.AST_NODE_TYPES.Identifier) {
1136
- return param.left.name;
1137
- }
1138
- return "<destructured parameter>";
1139
- }
1140
- return "<complex parameter>";
1141
- }
1142
- return "<unknown>";
1143
- };
1144
- var explicit_accessibility_default = createRule2({
1145
- name: "explicit-accessibility",
1146
- meta: {
1147
- type: "suggestion",
1148
- docs: {
1149
- description: "Require explicit accessibility modifiers on class members"
1150
- },
1151
- fixable: "code",
1152
- schema: [
1153
- {
1154
- type: "object",
1155
- properties: {
1156
- defaultAccessibility: {
1157
- type: "string",
1158
- enum: ["public", "private", "protected"],
1159
- description: "The accessibility modifier to add if one is missing."
1160
- }
1161
- },
1162
- additionalProperties: false
1163
- }
1164
- ],
1165
- messages: {
1166
- missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected)."
1167
- }
1168
- },
1169
- defaultOptions: [defaultOptions],
1170
- create(context, [options]) {
1171
- const { defaultAccessibility } = { ...defaultOptions, ...options };
1172
- const sourceCode = context.sourceCode;
1173
- function checkNode(node) {
1174
- if (node.accessibility) {
1175
- return;
1176
- }
1177
- let reportNode = node;
1178
- const name = getNodeName(node);
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
- }
1189
- context.report({
1190
- node: reportNode ?? node,
1191
- messageId: "missingAccessibility",
1192
- data: { name },
1193
- fix(fixer) {
1194
- let insertText = `${defaultAccessibility} `;
1195
- let tokenToInsertBefore;
1196
- if (node.decorators.length > 0) {
1197
- const lastDecorator = node.decorators[node.decorators.length - 1];
1198
- tokenToInsertBefore = sourceCode.getTokenAfter(lastDecorator);
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
- }
1222
- });
1223
- }
1224
- return {
1225
- MethodDefinition(node) {
1226
- checkNode(node);
1227
- },
1228
- PropertyDefinition(node) {
1229
- checkNode(node);
1230
- },
1231
- TSParameterProperty(node) {
1232
- checkNode(node);
1233
- }
1234
- };
1235
- }
1236
- });
3208
+ var import_config19 = require("eslint/config");
1237
3209
 
1238
- // packages/lint-suite/src/lib/typescript.ts
1239
- var localTypescriptRules = {
1240
- rules: {
1241
- "explicit-accessibility": explicit_accessibility_default
1242
- }
1243
- };
1244
- var typescript = (0, import_config9.defineConfig)([
1245
- // NOTE: Checks for 'prettier' and 'eslint-plugin-prettier'
1246
- {
1247
- files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
1248
- extends: [
1249
- import_eslint_plugin_import_x2.default.flatConfigs.typescript,
1250
- ...import_eslint_plugin4.configs["flat/typescript"]
1251
- ]
1252
- },
3210
+ // packages/lint-suite/src/lib/typescript-consistency.ts
3211
+ var import_config14 = require("eslint/config");
3212
+ var typescriptConsistency = (0, import_config14.defineConfig)([
1253
3213
  {
1254
3214
  files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
1255
- plugins: { local: localTypescriptRules },
1256
3215
  rules: {
1257
- "local/explicit-accessibility": "error",
1258
- "@typescript-eslint/explicit-member-accessibility": "error",
1259
- "@typescript-eslint/explicit-function-return-type": "error",
1260
- "@typescript-eslint/no-empty-function": "error",
1261
- "@typescript-eslint/no-unused-vars": "error",
1262
- "@typescript-eslint/no-use-before-define": "error",
1263
- // A. Eliminating `any` (already covered by strict-type-checked, but explicit for clarity)
1264
- "@typescript-eslint/no-explicit-any": "error",
1265
- "@typescript-eslint/no-unsafe-assignment": "error",
1266
- "@typescript-eslint/no-unsafe-call": "error",
1267
- "@typescript-eslint/no-unsafe-member-access": "error",
1268
- "@typescript-eslint/no-unsafe-return": "error",
1269
- "@typescript-eslint/no-unsafe-argument": "error",
1270
- // New v8 type-safety rules (replacements for deprecated ban-types)
1271
- "@typescript-eslint/no-empty-object-type": "error",
1272
- // Bans confusing {} type
1273
- "@typescript-eslint/no-unsafe-function-type": "error",
1274
- // Bans Function type
1275
- "@typescript-eslint/no-wrapper-object-types": "error",
1276
- // Bans Number, String, Boolean wrappers
1277
- // B. Explicit Annotations (partially covered, explicit module boundaries is key)
1278
- "@typescript-eslint/explicit-module-boundary-types": "error",
1279
- // Consider enabling if maximum explicitness is desired, even if verbose:
1280
- // C. Null/Undefined Safety (Requires strictNullChecks)
1281
- "@typescript-eslint/no-non-null-assertion": "error",
1282
- "@typescript-eslint/prefer-nullish-coalescing": "error",
1283
- "@typescript-eslint/prefer-optional-chain": "error",
1284
- // D. Promise Handling (Supplementing plugin:promise/recommended)
1285
- "@typescript-eslint/no-floating-promises": [
1286
- "error",
1287
- { ignoreVoid: true }
1288
- ],
1289
- "@typescript-eslint/no-misused-promises": "warn",
1290
- // Already in recommended-type-checked
1291
- "@typescript-eslint/promise-function-async": "error",
1292
- "@typescript-eslint/await-thenable": "error",
1293
- // Already in recommended-type-checked
1294
- // E. Best Practices & Potential Errors (Some covered by presets, fine-tuning here)
1295
- "@typescript-eslint/no-inferrable-types": "warn",
1296
- // Keep as warn or disable if inference is preferred
1297
- "@typescript-eslint/no-require-imports": "error",
1298
- // Use ES modules (replaces deprecated no-var-requires)
1299
- "@typescript-eslint/only-throw-error": "error",
1300
- // Replaces deprecated no-throw-literal
1301
- "@typescript-eslint/no-array-delete": "error",
1302
- // Prevents delete arr[0]
1303
- "@typescript-eslint/return-await": ["error", "in-try-catch"],
1304
- // Better stack traces in try/catch
1305
- "@typescript-eslint/require-await": "error",
1306
- "@typescript-eslint/restrict-template-expressions": [
1307
- "error",
1308
- { allowNumber: true, allowBoolean: true }
1309
- ],
1310
- // Allow numbers/booleans in templates
1311
- "@typescript-eslint/restrict-plus-operands": "error",
1312
- // Enforce consistent types for '+'
1313
- "@typescript-eslint/prefer-as-const": "error",
1314
- "@typescript-eslint/no-shadow": "error",
1315
- "@typescript-eslint/switch-exhaustiveness-check": "error",
1316
- // Ensure switch on unions is exhaustive
1317
- "@typescript-eslint/no-unused-expressions": [
1318
- "error",
1319
- { allowShortCircuit: true, allowTernary: true }
1320
- ],
1321
- "@typescript-eslint/no-useless-constructor": "error",
1322
- "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
1323
- // Prefer dot notation where possible
1324
- // Strict type-checked rules
1325
- "@typescript-eslint/no-unnecessary-condition": "error",
1326
- // Catches always-true/false conditions
1327
- "@typescript-eslint/no-confusing-void-expression": [
1328
- "error",
1329
- { ignoreArrowShorthand: true, ignoreVoidOperator: true }
1330
- ],
1331
- // Prevent confusing void usage
1332
- "@typescript-eslint/no-dynamic-delete": "error",
1333
- // Use Map instead of delete obj[key]
1334
- "@typescript-eslint/no-extraneous-class": [
1335
- "error",
1336
- { allowWithDecorator: true }
1337
- ],
1338
- // Allow Angular classes
1339
- "@typescript-eslint/no-invalid-void-type": "error",
1340
- // Restrict void to return types
1341
- "@typescript-eslint/unified-signatures": "error",
1342
- // Merge overloads where possible
1343
- "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
1344
- // Forbids foo! ?? bar
1345
- // Stylistic type-checked rules
1346
- "@typescript-eslint/prefer-find": "error",
1347
- // Use find() instead of filter()[0]
1348
- "@typescript-eslint/prefer-for-of": "error",
1349
- // Modern iteration
1350
- "@typescript-eslint/prefer-includes": "error",
1351
- // indexOf() → includes()
1352
- "@typescript-eslint/prefer-string-starts-ends-with": "error",
1353
- // Modern string methods
1354
- "@typescript-eslint/prefer-regexp-exec": "error",
1355
- // Better regex performance
1356
- // F. Consistency & Style (Some covered by stylistic-type-checked)
1357
3216
  "@typescript-eslint/consistent-type-assertions": [
1358
3217
  "error",
1359
3218
  { assertionStyle: "as", objectLiteralTypeAssertions: "never" }
@@ -1366,10 +3225,14 @@ var typescript = (0, import_config9.defineConfig)([
1366
3225
  "@typescript-eslint/naming-convention": [
1367
3226
  "error",
1368
3227
  {
1369
- selector: "objectLiteralProperty",
3228
+ selector: ["objectLiteralProperty", "objectLiteralMethod"],
1370
3229
  modifiers: ["requiresQuotes"],
1371
3230
  format: null
1372
3231
  },
3232
+ {
3233
+ selector: "objectLiteralMethod",
3234
+ format: ["camelCase", "PascalCase"]
3235
+ },
1373
3236
  {
1374
3237
  selector: "objectLiteralProperty",
1375
3238
  format: ["camelCase", "snake_case", "PascalCase"]
@@ -1392,7 +3255,28 @@ var typescript = (0, import_config9.defineConfig)([
1392
3255
  selector: "property",
1393
3256
  format: ["camelCase", "PascalCase", "snake_case"]
1394
3257
  }
1395
- ],
3258
+ ]
3259
+ }
3260
+ }
3261
+ ]);
3262
+
3263
+ // packages/lint-suite/src/lib/typescript-imports.ts
3264
+ var import_config15 = require("eslint/config");
3265
+ var import_eslint_import_resolver_typescript = require("eslint-import-resolver-typescript");
3266
+ var pathGroups = [
3267
+ { pattern: "@angular/**", group: "builtin", position: "before" },
3268
+ { pattern: "@nestjs/**", group: "builtin", position: "before" },
3269
+ { pattern: "@shared/**", group: "internal", position: "before" },
3270
+ { pattern: "@backend/**", group: "internal", position: "before" },
3271
+ { pattern: "@frontend/**", group: "internal", position: "before" },
3272
+ { pattern: "@*/shared/**", group: "internal", position: "before" },
3273
+ { pattern: "@*/frontend/**", group: "internal", position: "after" },
3274
+ { pattern: "@*/backend/**", group: "internal", position: "after" }
3275
+ ];
3276
+ var typescriptImports = (0, import_config15.defineConfig)([
3277
+ {
3278
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
3279
+ rules: {
1396
3280
  "import-x/order": [
1397
3281
  "error",
1398
3282
  {
@@ -1404,53 +3288,17 @@ var typescript = (0, import_config9.defineConfig)([
1404
3288
  "index",
1405
3289
  "unknown"
1406
3290
  ],
1407
- pathGroups: [
1408
- {
1409
- pattern: "@angular/**",
1410
- group: "builtin",
1411
- position: "before"
1412
- },
1413
- {
1414
- pattern: "@nestjs/**",
1415
- group: "builtin",
1416
- position: "before"
1417
- },
1418
- {
1419
- pattern: "@shared/**",
1420
- group: "internal",
1421
- position: "before"
1422
- },
1423
- {
1424
- pattern: "@backend/**",
1425
- group: "internal",
1426
- position: "before"
1427
- },
1428
- {
1429
- pattern: "@frontend/**",
1430
- group: "internal",
1431
- position: "before"
1432
- },
1433
- {
1434
- pattern: "@*/shared/**",
1435
- group: "internal",
1436
- position: "before"
1437
- },
1438
- {
1439
- pattern: "@*/frontend/**",
1440
- group: "internal",
1441
- position: "after"
1442
- },
1443
- {
1444
- pattern: "@*/backend/**",
1445
- group: "internal",
1446
- position: "after"
1447
- }
1448
- ],
3291
+ pathGroups,
1449
3292
  pathGroupsExcludedImportTypes: ["builtin"],
1450
3293
  "newlines-between": "always",
1451
3294
  alphabetize: { order: "asc", caseInsensitive: true }
1452
3295
  }
1453
3296
  ],
3297
+ // TypeScript already checks these four; import-x would re-parse every import with a parser resolved by name, which fails under pnpm.
3298
+ "import-x/namespace": "off",
3299
+ "import-x/default": "off",
3300
+ "import-x/no-named-as-default": "off",
3301
+ "import-x/no-named-as-default-member": "off",
1454
3302
  "import-x/no-unresolved": "error",
1455
3303
  "import-x/no-duplicates": "error",
1456
3304
  "import-x/prefer-default-export": "off",
@@ -1459,13 +3307,9 @@ var typescript = (0, import_config9.defineConfig)([
1459
3307
  "import-x/first": "error",
1460
3308
  "import-x/no-mutable-exports": "error",
1461
3309
  "import-x/no-self-import": "error",
1462
- // Prevents modules importing themselves
1463
3310
  "import-x/no-cycle": ["error", { maxDepth: 2, ignoreExternal: true }],
1464
- // Prevents circular dependencies
1465
3311
  "import-x/consistent-type-specifier-style": ["error", "prefer-top-level"],
1466
- // Consistent type imports
1467
3312
  "import-x/no-anonymous-default-export": "error"
1468
- // Improve code searchability
1469
3313
  },
1470
3314
  settings: {
1471
3315
  "import-x/resolver-next": [
@@ -1474,7 +3318,12 @@ var typescript = (0, import_config9.defineConfig)([
1474
3318
  })
1475
3319
  ]
1476
3320
  }
1477
- },
3321
+ }
3322
+ ]);
3323
+
3324
+ // packages/lint-suite/src/lib/typescript-overrides.ts
3325
+ var import_config16 = require("eslint/config");
3326
+ var typescriptOverrides = (0, import_config16.defineConfig)([
1478
3327
  {
1479
3328
  files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
1480
3329
  languageOptions: {
@@ -1507,23 +3356,402 @@ var typescript = (0, import_config9.defineConfig)([
1507
3356
  "@typescript-eslint/unbound-method": "off",
1508
3357
  "@typescript-eslint/consistent-type-assertions": "off"
1509
3358
  }
1510
- },
3359
+ },
3360
+ {
3361
+ files: ["**/*.stories.ts"],
3362
+ rules: {
3363
+ "@typescript-eslint/consistent-type-assertions": "off",
3364
+ "@typescript-eslint/naming-convention": "off"
3365
+ }
3366
+ }
3367
+ ]);
3368
+
3369
+ // packages/lint-suite/src/lib/typescript-recommended.ts
3370
+ var import_eslint_plugin4 = require("@nx/eslint-plugin");
3371
+ var import_config17 = require("eslint/config");
3372
+ var import_eslint_plugin_import_x2 = __toESM(require("eslint-plugin-import-x"), 1);
3373
+ var nxTypescript = import_eslint_plugin4.configs["flat/typescript"];
3374
+ var typescriptRecommended = (0, import_config17.defineConfig)([
3375
+ {
3376
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
3377
+ extends: [import_eslint_plugin_import_x2.default.flatConfigs.typescript, ...nxTypescript]
3378
+ }
3379
+ ]);
3380
+
3381
+ // packages/lint-suite/src/lib/typescript-safety.ts
3382
+ var import_config18 = require("eslint/config");
3383
+
3384
+ // packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
3385
+ var import_utils11 = require("@typescript-eslint/utils");
3386
+
3387
+ // packages/lint-suite/src/lib/rules/explicit-accessibility/common/explicit-accessibility.const.ts
3388
+ var accessibilities = [
3389
+ "public",
3390
+ "private",
3391
+ "protected"
3392
+ ];
3393
+ var docs2 = {
3394
+ description: "Require explicit accessibility modifiers on class members"
3395
+ };
3396
+ var messages2 = {
3397
+ missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected).",
3398
+ setAccessibility: "Add the '{{ accessibility }}' modifier."
3399
+ };
3400
+ var defaultAccessibilitySchema = {
3401
+ type: "string",
3402
+ enum: ["public", "private", "protected", "none"],
3403
+ 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."
3404
+ };
3405
+ var properties2 = {
3406
+ defaultAccessibility: defaultAccessibilitySchema
3407
+ };
3408
+ var optionsSchema2 = {
3409
+ type: "object",
3410
+ properties: properties2,
3411
+ additionalProperties: false
3412
+ };
3413
+ var schema2 = [optionsSchema2];
3414
+ var meta2 = {
3415
+ type: "suggestion",
3416
+ docs: docs2,
3417
+ fixable: "code",
3418
+ hasSuggestions: true,
3419
+ schema: schema2,
3420
+ messages: messages2
3421
+ };
3422
+ var defaultOptions2 = [{ defaultAccessibility: "public" }];
3423
+
3424
+ // packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
3425
+ var createRule2 = import_utils11.ESLintUtils.RuleCreator(
3426
+ () => "https://github.com/F0rty-Tw0/lint-suite#explicit-accessibility"
3427
+ );
3428
+ var isPrivateMember = (node) => {
3429
+ if (node.type === import_utils11.TSESTree.AST_NODE_TYPES.TSParameterProperty) return false;
3430
+ return node.key.type === import_utils11.TSESTree.AST_NODE_TYPES.PrivateIdentifier;
3431
+ };
3432
+ var isConstructor = (node) => {
3433
+ if (node.type !== import_utils11.TSESTree.AST_NODE_TYPES.MethodDefinition) return false;
3434
+ return node.kind === "constructor";
3435
+ };
3436
+ var reportTarget = (node) => {
3437
+ if (node.type !== import_utils11.TSESTree.AST_NODE_TYPES.TSParameterProperty) {
3438
+ return node.key;
3439
+ }
3440
+ const { parameter } = node;
3441
+ if (parameter.type === import_utils11.TSESTree.AST_NODE_TYPES.AssignmentPattern) {
3442
+ return parameter.left;
3443
+ }
3444
+ return parameter;
3445
+ };
3446
+ var memberName2 = (target, sourceCode) => {
3447
+ if (target.type === import_utils11.TSESTree.AST_NODE_TYPES.Identifier) return target.name;
3448
+ return sourceCode.getText(target);
3449
+ };
3450
+ var modifierToken = (node, sourceCode) => {
3451
+ const lastDecorator = node.decorators.at(-1);
3452
+ if (!lastDecorator) return sourceCode.getFirstToken(node);
3453
+ return sourceCode.getTokenAfter(lastDecorator);
3454
+ };
3455
+ var insertModifier = (node, accessibility, sourceCode) => {
3456
+ const token = modifierToken(node, sourceCode);
3457
+ if (!token) return () => null;
3458
+ const lastDecorator = node.decorators.at(-1);
3459
+ const adjacentToDecorator = lastDecorator?.range[1] === token.range[0];
3460
+ const text2 = `${adjacentToDecorator ? " " : ""}${accessibility} `;
3461
+ return (fixer) => fixer.insertTextBefore(token, text2);
3462
+ };
3463
+ var autoFixOf = (node, accessibility, sourceCode) => {
3464
+ if (accessibility === "none") {
3465
+ const noAutoFix = {};
3466
+ return noAutoFix;
3467
+ }
3468
+ const fix = insertModifier(node, accessibility, sourceCode);
3469
+ const autoFix = { fix };
3470
+ return autoFix;
3471
+ };
3472
+ var suggestionOf = (node, accessibility, sourceCode) => {
3473
+ const data = { accessibility };
3474
+ const fix = insertModifier(node, accessibility, sourceCode);
3475
+ const suggestion = {
3476
+ messageId: "setAccessibility",
3477
+ data,
3478
+ fix
3479
+ };
3480
+ return suggestion;
3481
+ };
3482
+ var suggestionsOf = (node, fixAccessibility, sourceCode) => {
3483
+ const isOtherAccessibility = (accessibility) => {
3484
+ return accessibility !== fixAccessibility;
3485
+ };
3486
+ const suggestionFor = (accessibility) => {
3487
+ return suggestionOf(node, accessibility, sourceCode);
3488
+ };
3489
+ return accessibilities.filter(isOtherAccessibility).map(suggestionFor);
3490
+ };
3491
+ var explicit_accessibility_default = createRule2({
3492
+ name: "explicit-accessibility",
3493
+ meta: meta2,
3494
+ defaultOptions: defaultOptions2,
3495
+ create(context, [{ defaultAccessibility = "public" }]) {
3496
+ const { sourceCode } = context;
3497
+ const check = (node) => {
3498
+ const isPrivate = isPrivateMember(node);
3499
+ if (node.accessibility || isPrivate) return;
3500
+ const target = reportTarget(node);
3501
+ const isConstructorMember = isConstructor(node);
3502
+ const usesPublic = isConstructorMember && defaultAccessibility !== "none";
3503
+ const fixAccessibility = usesPublic ? "public" : defaultAccessibility;
3504
+ const autoFix = autoFixOf(node, fixAccessibility, sourceCode);
3505
+ const name = memberName2(target, sourceCode);
3506
+ const data = { name };
3507
+ const suggest = suggestionsOf(node, fixAccessibility, sourceCode);
3508
+ const report = {
3509
+ node: target,
3510
+ messageId: "missingAccessibility",
3511
+ data,
3512
+ ...autoFix,
3513
+ suggest
3514
+ };
3515
+ context.report(report);
3516
+ };
3517
+ const listeners = {
3518
+ AccessorProperty: check,
3519
+ MethodDefinition: check,
3520
+ PropertyDefinition: check,
3521
+ TSAbstractAccessorProperty: check,
3522
+ TSAbstractMethodDefinition: check,
3523
+ TSAbstractPropertyDefinition: check,
3524
+ TSParameterProperty: check
3525
+ };
3526
+ return listeners;
3527
+ }
3528
+ });
3529
+
3530
+ // packages/lint-suite/src/lib/rules/no-inline-object-types/no-inline-object-types.ts
3531
+ var import_utils12 = require("@typescript-eslint/utils");
3532
+ var docs3 = {
3533
+ description: "Require nested object types inside a type alias to be extracted to a named type alias"
3534
+ };
3535
+ var messages3 = {
3536
+ inlineObjectType: "Inline object type must be extracted to a named type alias."
3537
+ };
3538
+ var meta3 = {
3539
+ type: "suggestion",
3540
+ docs: docs3,
3541
+ schema: [],
3542
+ messages: messages3
3543
+ };
3544
+ var createRule3 = import_utils12.ESLintUtils.RuleCreator(
3545
+ () => "https://github.com/F0rty-Tw0/lint-suite#no-inline-object-types"
3546
+ );
3547
+ var enclosingTypeAlias = (node) => {
3548
+ let current = node.parent;
3549
+ while (current && current.type !== import_utils12.TSESTree.AST_NODE_TYPES.Program) {
3550
+ if (current.type === import_utils12.TSESTree.AST_NODE_TYPES.TSTypeAliasDeclaration) {
3551
+ return current;
3552
+ }
3553
+ current = current.parent;
3554
+ }
3555
+ return void 0;
3556
+ };
3557
+ var no_inline_object_types_default = createRule3({
3558
+ name: "no-inline-object-types",
3559
+ meta: meta3,
3560
+ defaultOptions: [],
3561
+ create(context) {
3562
+ const listeners = {
3563
+ TSTypeLiteral(node) {
3564
+ const isAliasBody = node.parent.type === import_utils12.TSESTree.AST_NODE_TYPES.TSTypeAliasDeclaration;
3565
+ if (isAliasBody) return;
3566
+ const enclosingAlias = enclosingTypeAlias(node);
3567
+ if (!enclosingAlias) return;
3568
+ const report = {
3569
+ node,
3570
+ messageId: "inlineObjectType"
3571
+ };
3572
+ context.report(report);
3573
+ }
3574
+ };
3575
+ return listeners;
3576
+ }
3577
+ });
3578
+
3579
+ // packages/lint-suite/src/lib/rules/readonly-type-properties/readonly-type-properties.ts
3580
+ var import_utils13 = require("@typescript-eslint/utils");
3581
+ var docs4 = {
3582
+ description: "Require readonly on primitive-typed type and interface properties"
3583
+ };
3584
+ var messages4 = {
3585
+ missingReadonly: "Type property '{{ name }}' should be readonly. Disable this rule on the line if mutation is required."
3586
+ };
3587
+ var meta4 = {
3588
+ type: "suggestion",
3589
+ docs: docs4,
3590
+ fixable: "code",
3591
+ schema: [],
3592
+ messages: messages4
3593
+ };
3594
+ var createRule4 = import_utils13.ESLintUtils.RuleCreator(
3595
+ () => "https://github.com/F0rty-Tw0/lint-suite#readonly-type-properties"
3596
+ );
3597
+ var propertyName3 = (node, sourceCode) => {
3598
+ if (node.key.type === import_utils13.TSESTree.AST_NODE_TYPES.Identifier) {
3599
+ return node.key.name;
3600
+ }
3601
+ return sourceCode.getText(node.key);
3602
+ };
3603
+ var PRIMITIVE_KEYWORDS = /* @__PURE__ */ new Set([
3604
+ import_utils13.TSESTree.AST_NODE_TYPES.TSStringKeyword,
3605
+ import_utils13.TSESTree.AST_NODE_TYPES.TSNumberKeyword,
3606
+ import_utils13.TSESTree.AST_NODE_TYPES.TSBooleanKeyword,
3607
+ import_utils13.TSESTree.AST_NODE_TYPES.TSBigIntKeyword,
3608
+ import_utils13.TSESTree.AST_NODE_TYPES.TSSymbolKeyword,
3609
+ import_utils13.TSESTree.AST_NODE_TYPES.TSNullKeyword,
3610
+ import_utils13.TSESTree.AST_NODE_TYPES.TSUndefinedKeyword
3611
+ ]);
3612
+ var isPrimitive = (type) => {
3613
+ const isPrimitiveKeyword = PRIMITIVE_KEYWORDS.has(type.type);
3614
+ if (isPrimitiveKeyword) return true;
3615
+ if (type.type === import_utils13.TSESTree.AST_NODE_TYPES.TSLiteralType || type.type === import_utils13.TSESTree.AST_NODE_TYPES.TSTemplateLiteralType) {
3616
+ return true;
3617
+ }
3618
+ if (type.type === import_utils13.TSESTree.AST_NODE_TYPES.TSUnionType || type.type === import_utils13.TSESTree.AST_NODE_TYPES.TSIntersectionType) {
3619
+ return type.types.every(isPrimitive);
3620
+ }
3621
+ return false;
3622
+ };
3623
+ var readonlyFix = (node, sourceCode) => {
3624
+ return (fixer) => {
3625
+ const firstToken = sourceCode.getFirstToken(node);
3626
+ if (!firstToken) return null;
3627
+ return fixer.insertTextBefore(firstToken, "readonly ");
3628
+ };
3629
+ };
3630
+ var readonly_type_properties_default = createRule4({
3631
+ name: "readonly-type-properties",
3632
+ meta: meta4,
3633
+ defaultOptions: [],
3634
+ create(context) {
3635
+ const { sourceCode } = context;
3636
+ const listeners = {
3637
+ TSPropertySignature(node) {
3638
+ if (node.readonly || !node.typeAnnotation) return;
3639
+ const isPrimitiveType = isPrimitive(node.typeAnnotation.typeAnnotation);
3640
+ if (!isPrimitiveType) return;
3641
+ const name = propertyName3(node, sourceCode);
3642
+ const data = { name };
3643
+ const fix = readonlyFix(node, sourceCode);
3644
+ const report = {
3645
+ node: node.key,
3646
+ messageId: "missingReadonly",
3647
+ data,
3648
+ fix
3649
+ };
3650
+ context.report(report);
3651
+ }
3652
+ };
3653
+ return listeners;
3654
+ }
3655
+ });
3656
+
3657
+ // packages/lint-suite/src/lib/typescript-local-plugin.ts
3658
+ var localPlugin = definePlugin("local", {
3659
+ "explicit-accessibility": explicit_accessibility_default,
3660
+ "readonly-type-properties": readonly_type_properties_default,
3661
+ "no-inline-object-types": no_inline_object_types_default
3662
+ });
3663
+
3664
+ // packages/lint-suite/src/lib/typescript-safety.ts
3665
+ var typescriptSafety = (0, import_config18.defineConfig)([
1511
3666
  {
1512
- files: ["**/*.stories.ts"],
3667
+ files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
3668
+ plugins: { local: localPlugin },
1513
3669
  rules: {
1514
- "@typescript-eslint/consistent-type-assertions": "off",
1515
- "@typescript-eslint/naming-convention": "off"
3670
+ "local/explicit-accessibility": "error",
3671
+ "local/readonly-type-properties": "error",
3672
+ "local/no-inline-object-types": "error",
3673
+ "@typescript-eslint/explicit-function-return-type": "error",
3674
+ "@typescript-eslint/no-empty-function": "error",
3675
+ "@typescript-eslint/no-unused-vars": "error",
3676
+ "@typescript-eslint/no-use-before-define": "error",
3677
+ "@typescript-eslint/no-explicit-any": "error",
3678
+ "@typescript-eslint/no-unsafe-assignment": "error",
3679
+ "@typescript-eslint/no-unsafe-call": "error",
3680
+ "@typescript-eslint/no-unsafe-member-access": "error",
3681
+ "@typescript-eslint/no-unsafe-return": "error",
3682
+ "@typescript-eslint/no-unsafe-argument": "error",
3683
+ "@typescript-eslint/no-empty-object-type": "error",
3684
+ "@typescript-eslint/no-unsafe-function-type": "error",
3685
+ "@typescript-eslint/no-wrapper-object-types": "error",
3686
+ "@typescript-eslint/explicit-module-boundary-types": "error",
3687
+ "@typescript-eslint/no-non-null-assertion": "error",
3688
+ "@typescript-eslint/prefer-nullish-coalescing": "error",
3689
+ "@typescript-eslint/prefer-optional-chain": "error",
3690
+ "@typescript-eslint/no-floating-promises": [
3691
+ "error",
3692
+ { ignoreVoid: true }
3693
+ ],
3694
+ "@typescript-eslint/no-misused-promises": "warn",
3695
+ "@typescript-eslint/promise-function-async": "error",
3696
+ "@typescript-eslint/await-thenable": "error",
3697
+ "@typescript-eslint/no-inferrable-types": "warn",
3698
+ "@typescript-eslint/no-require-imports": "error",
3699
+ "@typescript-eslint/only-throw-error": "error",
3700
+ "@typescript-eslint/no-array-delete": "error",
3701
+ "@typescript-eslint/return-await": ["error", "in-try-catch"],
3702
+ "@typescript-eslint/require-await": "error",
3703
+ "@typescript-eslint/restrict-template-expressions": [
3704
+ "error",
3705
+ { allowNumber: true, allowBoolean: true }
3706
+ ],
3707
+ "@typescript-eslint/restrict-plus-operands": "error",
3708
+ "@typescript-eslint/prefer-as-const": "error",
3709
+ "@typescript-eslint/no-shadow": "error",
3710
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
3711
+ "@typescript-eslint/no-unused-expressions": [
3712
+ "error",
3713
+ { allowShortCircuit: true, allowTernary: true }
3714
+ ],
3715
+ "@typescript-eslint/no-useless-constructor": "error",
3716
+ "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
3717
+ "@typescript-eslint/no-unnecessary-condition": "error",
3718
+ "@typescript-eslint/no-confusing-void-expression": [
3719
+ "error",
3720
+ { ignoreArrowShorthand: true, ignoreVoidOperator: true }
3721
+ ],
3722
+ "@typescript-eslint/no-dynamic-delete": "error",
3723
+ "@typescript-eslint/no-extraneous-class": [
3724
+ "error",
3725
+ { allowWithDecorator: true }
3726
+ ],
3727
+ "@typescript-eslint/no-invalid-void-type": "error",
3728
+ "@typescript-eslint/unified-signatures": "error",
3729
+ "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
3730
+ "@typescript-eslint/prefer-find": "error",
3731
+ "@typescript-eslint/prefer-for-of": "error",
3732
+ "@typescript-eslint/prefer-includes": "error",
3733
+ "@typescript-eslint/prefer-string-starts-ends-with": "error",
3734
+ "@typescript-eslint/prefer-regexp-exec": "error"
1516
3735
  }
1517
3736
  }
1518
3737
  ]);
1519
3738
 
3739
+ // packages/lint-suite/src/lib/typescript.ts
3740
+ var typescript = (0, import_config19.defineConfig)([
3741
+ ...typescriptRecommended,
3742
+ ...typescriptSafety,
3743
+ ...typescriptConsistency,
3744
+ ...typescriptImports,
3745
+ ...typescriptOverrides
3746
+ ]);
3747
+
1520
3748
  // packages/lint-suite/src/lib/vitest.ts
1521
3749
  var import_eslint_plugin5 = __toESM(require("@vitest/eslint-plugin"), 1);
1522
- var import_config10 = require("eslint/config");
3750
+ var import_config20 = require("eslint/config");
1523
3751
  var vitestPlugin = {
1524
3752
  vitest: import_eslint_plugin5.default
1525
3753
  };
1526
- var vitest = (0, import_config10.defineConfig)([
3754
+ var vitest = (0, import_config20.defineConfig)([
1527
3755
  {
1528
3756
  files: ["**/*.spec.ts", "**/*.spec.js", "**/*.test.ts", "**/*.test.js"],
1529
3757
  plugins: vitestPlugin,
@@ -1546,147 +3774,6 @@ var vitest = (0, import_config10.defineConfig)([
1546
3774
  }
1547
3775
  ]);
1548
3776
 
1549
- // packages/lint-suite/src/lib/playwright.ts
1550
- var import_eslint_plugin_playwright = __toESM(require("eslint-plugin-playwright"), 1);
1551
- var import_config11 = require("eslint/config");
1552
- var playwright = (0, import_config11.defineConfig)([
1553
- {
1554
- ...import_eslint_plugin_playwright.default.configs["flat/recommended"],
1555
- files: ["**/*.e2e.ts", "**/*.e2e.js"],
1556
- rules: {
1557
- ...import_eslint_plugin_playwright.default.configs["flat/recommended"].rules,
1558
- // Locator best practices
1559
- "playwright/prefer-locator": "error",
1560
- "playwright/prefer-native-locators": "error",
1561
- "playwright/no-nth-methods": "warn",
1562
- // Matcher improvements
1563
- "playwright/prefer-to-be": "error",
1564
- "playwright/prefer-to-have-count": "error",
1565
- "playwright/prefer-to-have-length": "error",
1566
- "playwright/prefer-comparison-matcher": "error",
1567
- // Test structure
1568
- "playwright/prefer-hooks-on-top": "error",
1569
- "playwright/require-top-level-describe": "warn"
1570
- }
1571
- }
1572
- ]);
1573
-
1574
- // packages/lint-suite/src/lib/boundaries.ts
1575
- var import_eslint_plugin_boundaries = __toESM(require("eslint-plugin-boundaries"), 1);
1576
- var import_config12 = require("eslint/config");
1577
- var boundaries = (0, import_config12.defineConfig)([
1578
- {
1579
- files: [
1580
- "**/*.js",
1581
- "**/*.jsx",
1582
- "**/*.ts",
1583
- "**/*.tsx",
1584
- "**/*.cts",
1585
- "**/*.mts"
1586
- ],
1587
- plugins: {
1588
- boundaries: import_eslint_plugin_boundaries.default
1589
- },
1590
- settings: {
1591
- "boundaries/elements": [
1592
- {
1593
- type: "feature",
1594
- pattern: "**/feature/**"
1595
- },
1596
- {
1597
- type: "data-access",
1598
- pattern: "**/data-access/**"
1599
- },
1600
- {
1601
- type: "domain-logic",
1602
- pattern: "**/domain-logic/**"
1603
- },
1604
- {
1605
- type: "ui",
1606
- pattern: "**/ui/**"
1607
- },
1608
- {
1609
- type: "common",
1610
- pattern: "**/common/**"
1611
- },
1612
- {
1613
- type: "utils",
1614
- pattern: "**/utils/**"
1615
- }
1616
- ],
1617
- "import/resolver": {
1618
- typescript: {
1619
- alwaysTryTypes: true
1620
- }
1621
- }
1622
- },
1623
- rules: {
1624
- ...import_eslint_plugin_boundaries.default.configs.recommended.rules,
1625
- "boundaries/dependencies": [
1626
- "error",
1627
- {
1628
- default: "disallow",
1629
- message: "{{to.element.types}} is not allowed to be imported in {{from.element.types}}",
1630
- policies: [
1631
- {
1632
- from: { element: { type: "feature" } },
1633
- allow: [
1634
- { to: { element: { type: "feature" } } },
1635
- { to: { element: { type: "ui" } } },
1636
- { to: { element: { type: "domain-logic" } } },
1637
- { to: { element: { type: "utils" } } },
1638
- { to: { element: { type: "common" } } }
1639
- ]
1640
- },
1641
- {
1642
- from: { element: { type: "domain-logic" } },
1643
- allow: [
1644
- { to: { element: { type: "domain-logic" } } },
1645
- { to: { element: { type: "data-access" } } },
1646
- { to: { element: { type: "utils" } } },
1647
- { to: { element: { type: "common" } } }
1648
- ]
1649
- },
1650
- {
1651
- from: { element: { type: "data-access" } },
1652
- allow: [
1653
- { to: { element: { type: "data-access" } } },
1654
- { to: { element: { type: "utils" } } },
1655
- { to: { element: { type: "common" } } }
1656
- ]
1657
- },
1658
- {
1659
- from: { element: { type: "ui" } },
1660
- allow: [
1661
- { to: { element: { type: "ui" } } },
1662
- { to: { element: { type: "utils" } } },
1663
- { to: { element: { type: "common" } } }
1664
- ]
1665
- },
1666
- {
1667
- from: { element: { type: "utils" } },
1668
- allow: [
1669
- { to: { element: { type: "utils" } } },
1670
- { to: { element: { type: "common" } } }
1671
- ]
1672
- },
1673
- {
1674
- from: { element: { type: "common" } },
1675
- allow: [{ to: { element: { type: "common" } } }]
1676
- }
1677
- ]
1678
- }
1679
- ]
1680
- }
1681
- },
1682
- {
1683
- files: ["**/*.stories.ts"],
1684
- rules: {
1685
- "boundaries/dependencies": "off"
1686
- }
1687
- }
1688
- ]);
1689
-
1690
3777
  // packages/lint-suite/src/eslint.ts
1691
3778
  var recommended = [
1692
3779
  ...base,