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.
- package/README.md +161 -16
- package/eslint.cjs +3085 -998
- package/eslint.cjs.map +4 -4
- package/eslint.d.ts +13 -13
- package/eslint.d.ts.map +1 -1
- package/eslint.js +3173 -990
- package/eslint.js.map +4 -4
- package/lib/angular-template.d.ts.map +1 -1
- package/lib/angular.d.ts +1 -0
- package/lib/angular.d.ts.map +1 -1
- package/lib/base-limits.d.ts +2 -0
- package/lib/base-limits.d.ts.map +1 -0
- package/lib/base-practices.d.ts +2 -0
- package/lib/base-practices.d.ts.map +1 -0
- package/lib/base-recommended.d.ts +2 -0
- package/lib/base-recommended.d.ts.map +1 -0
- package/lib/base.d.ts.map +1 -1
- package/lib/javascript.d.ts.map +1 -1
- package/lib/rules/define-plugin.util.d.ts +6 -0
- package/lib/rules/define-plugin.util.d.ts.map +1 -0
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts +6 -0
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts.map +1 -0
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts +14 -0
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts.map +1 -0
- package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts +7 -0
- package/lib/rules/explicit-accessibility/explicit-accessibility.d.ts.map +1 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts +6 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-discovery.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.d.ts +9 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-decorator-kind.d.ts +10 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-decorator-kind.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.d.ts +12 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-chains.d.ts +17 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-chains.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts +6 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts +54 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts +116 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts +10 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts +17 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.d.ts +6 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-candidate-names.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-candidate-names.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-type-dependencies.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-type-dependencies.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.d.ts +7 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/read-chain-text.util.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/read-chain-text.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.util.d.ts +2 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/spec-file.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/{utils/angular-expression-reads.util.d.ts → rule/angular/angular-expression-reads.d.ts} +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts +9 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.d.ts +6 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-member-candidates.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.d.ts +9 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-template-parsing.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts +54 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.d.ts +8 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-field-reads.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-lexical-this.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-lexical-this.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.d.ts +3 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-read-target.util.d.ts +4 -0
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-read-target.util.d.ts.map +1 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts +6 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts.map +1 -0
- package/lib/typescript-consistency.d.ts +2 -0
- package/lib/typescript-consistency.d.ts.map +1 -0
- package/lib/typescript-imports.d.ts +2 -0
- package/lib/typescript-imports.d.ts.map +1 -0
- package/lib/typescript-local-plugin.d.ts +2 -0
- package/lib/typescript-local-plugin.d.ts.map +1 -0
- package/lib/typescript-overrides.d.ts +2 -0
- package/lib/typescript-overrides.d.ts.map +1 -0
- package/lib/typescript-recommended.d.ts +2 -0
- package/lib/typescript-recommended.d.ts.map +1 -0
- package/lib/typescript-safety.d.ts +2 -0
- package/lib/typescript-safety.d.ts.map +1 -0
- package/lib/typescript.d.ts +1 -0
- package/lib/typescript.d.ts.map +1 -1
- package/package.json +18 -14
- package/lib/rules/explicit-accessibility.d.ts +0 -12
- package/lib/rules/explicit-accessibility.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts +0 -8
- package/lib/rules/no-unused-angular-instance-fields/angular-class-fields.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts +0 -3
- package/lib/rules/no-unused-angular-instance-fields/angular-metadata-reads.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts +0 -10
- package/lib/rules/no-unused-angular-instance-fields/common/no-unused-angular-instance-fields.type.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts +0 -7
- package/lib/rules/no-unused-angular-instance-fields/no-unused-angular-instance-fields.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts +0 -2
- package/lib/rules/no-unused-angular-instance-fields/no-unused-instance-fields.spec.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/utils/angular-expression-reads.util.d.ts.map +0 -1
- package/lib/rules/no-unused-angular-instance-fields/utils/typescript-field-reads.util.d.ts +0 -7
- 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/
|
|
132
|
-
var
|
|
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-
|
|
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-
|
|
138
|
-
var
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
160
|
-
|
|
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
|
-
|
|
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
|
|
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-
|
|
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
|
|
196
|
-
var templateBinder = new
|
|
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,
|
|
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
|
|
236
|
-
const start = new
|
|
237
|
-
const span = new
|
|
238
|
-
const result =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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 !==
|
|
293
|
-
|
|
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 = (
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (component
|
|
326
|
-
|
|
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
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
|
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
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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 = (
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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/
|
|
455
|
-
var
|
|
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
|
-
|
|
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) =>
|
|
476
|
-
|
|
477
|
-
|
|
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 ===
|
|
524
|
-
|
|
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
|
-
|
|
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 !==
|
|
718
|
+
if (property.type !== import_utils6.TSESTree.AST_NODE_TYPES.Property || property.computed) {
|
|
533
719
|
return null;
|
|
534
720
|
}
|
|
535
|
-
if (property.key.type ===
|
|
721
|
+
if (property.key.type === import_utils6.TSESTree.AST_NODE_TYPES.Identifier) {
|
|
536
722
|
return property.key.name;
|
|
537
723
|
}
|
|
538
|
-
|
|
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
|
|
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/
|
|
557
|
-
var
|
|
558
|
-
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
|
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
|
-
|
|
586
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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
|
-
|
|
690
|
-
|
|
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
|
|
701
|
-
|
|
702
|
-
|
|
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
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
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/
|
|
760
|
-
var
|
|
761
|
-
var
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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
|
-
|
|
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
|
-
"**/*.
|
|
945
|
-
"**/*.
|
|
946
|
-
"**/*.
|
|
947
|
-
"**/*.
|
|
948
|
-
"**/*.
|
|
949
|
-
"**/*.
|
|
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
|
-
|
|
953
|
-
|
|
954
|
-
"max-lines": [
|
|
2994
|
+
...import_eslint_plugin_boundaries.default.configs.recommended.rules,
|
|
2995
|
+
"boundaries/dependencies": [
|
|
955
2996
|
"error",
|
|
956
2997
|
{
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
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: ["**/*.
|
|
966
|
-
rules: {
|
|
967
|
-
"max-classes-per-file": "off"
|
|
968
|
-
}
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
files: ["**/*.state.ts"],
|
|
3053
|
+
files: ["**/*.stories.ts"],
|
|
972
3054
|
rules: {
|
|
973
|
-
"
|
|
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
|
|
981
|
-
var
|
|
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:
|
|
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
|
|
989
|
-
var json = (0,
|
|
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
|
|
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
|
|
1008
|
-
var rxjs = (0,
|
|
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
|
|
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
|
|
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
|
|
1240
|
-
|
|
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: ["**/*.
|
|
3667
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
|
|
3668
|
+
plugins: { local: localPlugin },
|
|
1513
3669
|
rules: {
|
|
1514
|
-
"
|
|
1515
|
-
"
|
|
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
|
|
3750
|
+
var import_config20 = require("eslint/config");
|
|
1523
3751
|
var vitestPlugin = {
|
|
1524
3752
|
vitest: import_eslint_plugin5.default
|
|
1525
3753
|
};
|
|
1526
|
-
var vitest = (0,
|
|
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,
|