lint-suite 1.6.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -20
- package/eslint.cjs +3312 -492
- package/eslint.cjs.map +4 -4
- package/eslint.js +3304 -445
- package/eslint.js.map +4 -4
- package/lib/angular-template.d.ts +0 -1
- package/lib/angular-template.d.ts.map +1 -1
- package/lib/angular.d.ts +0 -1
- package/lib/angular.d.ts.map +1 -1
- package/lib/base-limits.d.ts.map +1 -1
- package/lib/rules/arrow-body-fits-line/arrow-body-fits-line.d.ts +6 -0
- package/lib/rules/arrow-body-fits-line/arrow-body-fits-line.d.ts.map +1 -0
- package/lib/rules/chain-fits-line/chain-fits-line.d.ts +6 -0
- package/lib/rules/chain-fits-line/chain-fits-line.d.ts.map +1 -0
- package/lib/rules/chain-receiver-is-name/chain-receiver-is-name.d.ts +7 -0
- package/lib/rules/chain-receiver-is-name/chain-receiver-is-name.d.ts.map +1 -0
- package/lib/rules/common/class-usage.type.d.ts +1 -0
- package/lib/rules/common/class-usage.type.d.ts.map +1 -1
- package/lib/rules/common/file-cache.type.d.ts +11 -0
- package/lib/rules/common/file-cache.type.d.ts.map +1 -0
- package/lib/rules/common/glob-matcher.type.d.ts +2 -0
- package/lib/rules/common/glob-matcher.type.d.ts.map +1 -0
- package/lib/rules/component-metadata.d.ts +2 -4
- package/lib/rules/component-metadata.d.ts.map +1 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts +1 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts.map +1 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts +4 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts.map +1 -1
- package/lib/rules/file-cache.d.ts +14 -0
- package/lib/rules/file-cache.d.ts.map +1 -0
- package/lib/rules/max-condition-operands/max-condition-operands.d.ts +10 -0
- package/lib/rules/max-condition-operands/max-condition-operands.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.const.d.ts +6 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.const.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.type.d.ts +21 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.type.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/no-call-in-condition.d.ts +7 -0
- package/lib/rules/no-call-in-condition/no-call-in-condition.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/utils/call-exemptions.util.d.ts +4 -0
- package/lib/rules/no-call-in-condition/utils/call-exemptions.util.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/utils/condition-calls.util.d.ts +7 -0
- package/lib/rules/no-call-in-condition/utils/condition-calls.util.d.ts.map +1 -0
- package/lib/rules/no-grouped-condition/no-grouped-condition.d.ts +7 -0
- package/lib/rules/no-grouped-condition/no-grouped-condition.d.ts.map +1 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts.map +1 -1
- package/lib/rules/no-inline-return-object/no-inline-return-object.d.ts +6 -0
- package/lib/rules/no-inline-return-object/no-inline-return-object.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.const.d.ts +5 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.const.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.type.d.ts +7 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.type.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/no-nested-object-value.d.ts +7 -0
- package/lib/rules/no-nested-object-value/no-nested-object-value.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/utils/decorator-config.util.d.ts +3 -0
- package/lib/rules/no-nested-object-value/utils/decorator-config.util.d.ts.map +1 -0
- package/lib/rules/no-spread-expression/no-spread-expression.d.ts +6 -0
- package/lib/rules/no-spread-expression/no-spread-expression.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/no-unstyled-classes.d.ts.map +1 -1
- package/lib/rules/no-unstyled-classes/styles/component-stylesheets.d.ts.map +1 -1
- package/lib/rules/no-unstyled-classes/styles/linked-stylesheets.d.ts +3 -0
- package/lib/rules/no-unstyled-classes/styles/linked-stylesheets.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-classes.d.ts.map +1 -1
- package/lib/rules/no-unstyled-classes/styles/template-stylesheets.d.ts +1 -1
- package/lib/rules/no-unstyled-classes/styles/template-stylesheets.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts +0 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts +6 -8
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts +3 -14
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts +3 -2
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts +8 -4
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts +3 -2
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/class-members.util.d.ts +10 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/class-members.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts +2 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts.map +1 -1
- package/lib/rules/no-unused-classes/no-unused-classes.d.ts.map +1 -1
- package/lib/rules/no-unused-classes/styles/linked-templates.d.ts +9 -0
- package/lib/rules/no-unused-classes/styles/linked-templates.d.ts.map +1 -0
- package/lib/rules/no-unused-classes/styles/stylesheet-components.d.ts.map +1 -1
- package/lib/rules/no-unused-classes/template/template-usage.d.ts.map +1 -1
- package/lib/rules/no-unused-exports/common/no-unused-exports.const.d.ts +7 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.const.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts +70 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/export-index.d.ts +6 -0
- package/lib/rules/no-unused-exports/export-index.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/no-unused-exports.d.ts +7 -0
- package/lib/rules/no-unused-exports/no-unused-exports.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/report-unused-exports.d.ts +12 -0
- package/lib/rules/no-unused-exports/report-unused-exports.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/aggregate-update.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/aggregate-update.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-edges.util.d.ts +5 -0
- package/lib/rules/no-unused-exports/utils/export-edges.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-nodes.util.d.ts +5 -0
- package/lib/rules/no-unused-exports/utils/export-nodes.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-usage.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/export-usage.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/exported-names.util.d.ts +3 -0
- package/lib/rules/no-unused-exports/utils/exported-names.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/file-changes.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/file-changes.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/module-target.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/module-target.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/public-exports.util.d.ts +3 -0
- package/lib/rules/no-unused-exports/utils/public-exports.util.d.ts.map +1 -0
- package/lib/rules/one-line-guard/one-line-guard.d.ts.map +1 -1
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts +2 -1
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts.map +1 -1
- package/lib/rules/{utils/selector-classes.util.d.ts → selector-classes.d.ts} +2 -2
- package/lib/rules/selector-classes.d.ts.map +1 -0
- package/lib/rules/ternary-branch-shape/ternary-branch-shape.d.ts +6 -0
- package/lib/rules/ternary-branch-shape/ternary-branch-shape.d.ts.map +1 -0
- package/lib/rules/test-file-shape/common/test-file-shape.const.d.ts +14 -0
- package/lib/rules/test-file-shape/common/test-file-shape.const.d.ts.map +1 -0
- package/lib/rules/test-file-shape/common/test-file-shape.type.d.ts +7 -0
- package/lib/rules/test-file-shape/common/test-file-shape.type.d.ts.map +1 -0
- package/lib/rules/test-file-shape/mock-exports.d.ts +7 -0
- package/lib/rules/test-file-shape/mock-exports.d.ts.map +1 -0
- package/lib/rules/test-file-shape/stub-exports.d.ts +7 -0
- package/lib/rules/test-file-shape/stub-exports.d.ts.map +1 -0
- package/lib/rules/test-file-shape/test-file-shape.d.ts +7 -0
- package/lib/rules/test-file-shape/test-file-shape.d.ts.map +1 -0
- package/lib/rules/type-placement/common/type-placement.const.d.ts +5 -0
- package/lib/rules/type-placement/common/type-placement.const.d.ts.map +1 -0
- package/lib/rules/type-placement/common/type-placement.type.d.ts +7 -0
- package/lib/rules/type-placement/common/type-placement.type.d.ts.map +1 -0
- package/lib/rules/type-placement/type-placement.d.ts +7 -0
- package/lib/rules/type-placement/type-placement.d.ts.map +1 -0
- package/lib/rules/util-purity/common/util-purity.const.d.ts +10 -0
- package/lib/rules/util-purity/common/util-purity.const.d.ts.map +1 -0
- package/lib/rules/util-purity/common/util-purity.type.d.ts +7 -0
- package/lib/rules/util-purity/common/util-purity.type.d.ts.map +1 -0
- package/lib/rules/util-purity/util-purity.d.ts +7 -0
- package/lib/rules/util-purity/util-purity.d.ts.map +1 -0
- package/lib/rules/utils/class-expression-literals.util.d.ts.map +1 -1
- package/lib/rules/utils/enclosing-statement.util.d.ts +3 -0
- package/lib/rules/utils/enclosing-statement.util.d.ts.map +1 -0
- package/lib/rules/utils/glob-matcher.util.d.ts +3 -0
- package/lib/rules/utils/glob-matcher.util.d.ts.map +1 -0
- package/lib/rules/utils/indent-of.util.d.ts +3 -0
- package/lib/rules/utils/indent-of.util.d.ts.map +1 -0
- package/lib/rules/utils/template-classes.util.d.ts.map +1 -1
- package/lib/rules/utils/template-links.util.d.ts +2 -0
- package/lib/rules/utils/template-links.util.d.ts.map +1 -0
- package/lib/rules/utils/to-regexp.util.d.ts +2 -0
- package/lib/rules/utils/to-regexp.util.d.ts.map +1 -0
- package/lib/typescript-local-plugin.d.ts.map +1 -1
- package/lib/typescript-safety.d.ts.map +1 -1
- package/lib/typescript.d.ts +0 -1
- package/lib/typescript.d.ts.map +1 -1
- package/lib/vitest.d.ts.map +1 -1
- package/package.json +1 -1
- package/stylelint.cjs +303 -99
- package/stylelint.cjs.map +4 -4
- package/stylelint.d.ts.map +1 -1
- package/stylelint.js +321 -111
- package/stylelint.js.map +4 -4
- package/lib/rules/no-unused-classes/styles/component-descriptors.d.ts +0 -3
- package/lib/rules/no-unused-classes/styles/component-descriptors.d.ts.map +0 -1
- package/lib/rules/utils/selector-classes.util.d.ts.map +0 -1
package/eslint.js
CHANGED
|
@@ -4,8 +4,8 @@ import { defineConfig } from "eslint/config";
|
|
|
4
4
|
|
|
5
5
|
// packages/lint-suite/src/lib/rules/define-plugin.util.ts
|
|
6
6
|
var definePlugin = (name, rules) => {
|
|
7
|
-
const
|
|
8
|
-
const plugin = { meta:
|
|
7
|
+
const meta21 = { name };
|
|
8
|
+
const plugin = { meta: meta21, rules };
|
|
9
9
|
return plugin;
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -14,10 +14,9 @@ import { ESLintUtils } from "@typescript-eslint/utils";
|
|
|
14
14
|
|
|
15
15
|
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/component-stylesheets.ts
|
|
16
16
|
import { existsSync } from "node:fs";
|
|
17
|
-
import { dirname, resolve } from "node:path";
|
|
17
|
+
import { dirname as dirname2, resolve } from "node:path";
|
|
18
18
|
|
|
19
19
|
// packages/lint-suite/src/lib/rules/component-metadata.ts
|
|
20
|
-
import { readFileSync } from "node:fs";
|
|
21
20
|
import {
|
|
22
21
|
ScriptTarget,
|
|
23
22
|
canHaveDecorators,
|
|
@@ -31,6 +30,114 @@ import {
|
|
|
31
30
|
isPropertyAssignment,
|
|
32
31
|
isStringLiteralLike
|
|
33
32
|
} from "typescript";
|
|
33
|
+
|
|
34
|
+
// packages/lint-suite/src/lib/rules/file-cache.ts
|
|
35
|
+
import {
|
|
36
|
+
mkdirSync,
|
|
37
|
+
readFileSync,
|
|
38
|
+
renameSync,
|
|
39
|
+
statSync,
|
|
40
|
+
writeFileSync
|
|
41
|
+
} from "node:fs";
|
|
42
|
+
import { dirname, join } from "node:path";
|
|
43
|
+
var CACHE_FORMAT_VERSION = 1;
|
|
44
|
+
var caches = /* @__PURE__ */ new Set();
|
|
45
|
+
var isFlushRegistered = false;
|
|
46
|
+
var cacheDirectory = () => {
|
|
47
|
+
const { LINT_SUITE_CACHE, LINT_SUITE_CACHE_DIR } = process.env;
|
|
48
|
+
const isDisabled = LINT_SUITE_CACHE === "0";
|
|
49
|
+
if (isDisabled) return null;
|
|
50
|
+
if (LINT_SUITE_CACHE_DIR) return LINT_SUITE_CACHE_DIR;
|
|
51
|
+
return join(process.cwd(), "node_modules", ".cache", "lint-suite");
|
|
52
|
+
};
|
|
53
|
+
var cacheFile = (name) => {
|
|
54
|
+
const directory = cacheDirectory();
|
|
55
|
+
if (directory === null) return null;
|
|
56
|
+
return join(directory, `${name}.v${CACHE_FORMAT_VERSION}.json`);
|
|
57
|
+
};
|
|
58
|
+
var isCachedFile = (value) => {
|
|
59
|
+
const isObject = typeof value === "object" && value !== null;
|
|
60
|
+
if (!isObject) return false;
|
|
61
|
+
const hasVersion = "version" in value && typeof value.version === "string";
|
|
62
|
+
return hasVersion && "value" in value;
|
|
63
|
+
};
|
|
64
|
+
var storedEntries = (text2) => {
|
|
65
|
+
const entries = /* @__PURE__ */ new Map();
|
|
66
|
+
const parsed = JSON.parse(text2);
|
|
67
|
+
const isRecord = typeof parsed === "object" && parsed !== null;
|
|
68
|
+
if (!isRecord) return entries;
|
|
69
|
+
for (const [path, entry] of Object.entries(parsed)) {
|
|
70
|
+
if (isCachedFile(entry)) entries.set(path, entry);
|
|
71
|
+
}
|
|
72
|
+
return entries;
|
|
73
|
+
};
|
|
74
|
+
var load = (cache2) => {
|
|
75
|
+
cache2.loaded = true;
|
|
76
|
+
const file = cacheFile(cache2.name);
|
|
77
|
+
if (file === null) return;
|
|
78
|
+
try {
|
|
79
|
+
const stored = storedEntries(readFileSync(file, "utf8"));
|
|
80
|
+
for (const [path, entry] of stored) cache2.entries.set(path, entry);
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var write = (cache2) => {
|
|
86
|
+
const file = cacheFile(cache2.name);
|
|
87
|
+
if (file === null) return;
|
|
88
|
+
try {
|
|
89
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
90
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
91
|
+
const stored = Object.fromEntries(cache2.entries);
|
|
92
|
+
writeFileSync(temporary, JSON.stringify(stored));
|
|
93
|
+
renameSync(temporary, file);
|
|
94
|
+
} catch {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var flushFileCaches = () => {
|
|
99
|
+
for (const cache2 of caches) {
|
|
100
|
+
if (!cache2.dirty) continue;
|
|
101
|
+
write(cache2);
|
|
102
|
+
cache2.dirty = false;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
var registerFlush = () => {
|
|
106
|
+
if (isFlushRegistered) return;
|
|
107
|
+
isFlushRegistered = true;
|
|
108
|
+
process.once("exit", flushFileCaches);
|
|
109
|
+
};
|
|
110
|
+
var createFileCache = (name) => {
|
|
111
|
+
const cache2 = {
|
|
112
|
+
name,
|
|
113
|
+
entries: /* @__PURE__ */ new Map(),
|
|
114
|
+
loaded: false,
|
|
115
|
+
dirty: false
|
|
116
|
+
};
|
|
117
|
+
caches.add(cache2);
|
|
118
|
+
registerFlush();
|
|
119
|
+
return cache2;
|
|
120
|
+
};
|
|
121
|
+
var readCached = (cache2, path, parse2) => {
|
|
122
|
+
if (!cache2.loaded) load(cache2);
|
|
123
|
+
try {
|
|
124
|
+
const stats = statSync(path, { bigint: true });
|
|
125
|
+
const version = `${stats.mtimeNs}:${stats.size}`;
|
|
126
|
+
const cached = cache2.entries.get(path);
|
|
127
|
+
if (cached?.version === version) return cached.value;
|
|
128
|
+
const value = parse2(readFileSync(path, "utf8"), path);
|
|
129
|
+
const fresh = { value, version };
|
|
130
|
+
cache2.entries.set(path, fresh);
|
|
131
|
+
cache2.dirty = true;
|
|
132
|
+
return value;
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// packages/lint-suite/src/lib/rules/component-metadata.ts
|
|
139
|
+
var COMPONENT_MARKER = "@Component";
|
|
140
|
+
var cache = createFileCache("component-metadata");
|
|
34
141
|
var componentArgument = (decorator) => {
|
|
35
142
|
const { expression } = decorator;
|
|
36
143
|
if (!isCallExpression(expression)) return null;
|
|
@@ -51,25 +158,6 @@ var decoratedMetadata = (node) => {
|
|
|
51
158
|
}
|
|
52
159
|
return null;
|
|
53
160
|
};
|
|
54
|
-
var parseComponentMetadata = (text2, path) => {
|
|
55
|
-
const found = [];
|
|
56
|
-
const visit = (node) => {
|
|
57
|
-
const metadata = decoratedMetadata(node);
|
|
58
|
-
if (metadata !== null) found.push(metadata);
|
|
59
|
-
forEachChild(node, visit);
|
|
60
|
-
};
|
|
61
|
-
const source = createSourceFile(path, text2, ScriptTarget.Latest, true);
|
|
62
|
-
forEachChild(source, visit);
|
|
63
|
-
return found;
|
|
64
|
-
};
|
|
65
|
-
var componentMetadata = (path) => {
|
|
66
|
-
try {
|
|
67
|
-
const text2 = readFileSync(path, "utf8");
|
|
68
|
-
return parseComponentMetadata(text2, path);
|
|
69
|
-
} catch {
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
161
|
var literalText = (node) => {
|
|
74
162
|
if (!isStringLiteralLike(node)) return null;
|
|
75
163
|
return node.text;
|
|
@@ -99,21 +187,51 @@ var metadataTexts = (metadata, name) => {
|
|
|
99
187
|
if (value === null) return [];
|
|
100
188
|
return literalTexts(value);
|
|
101
189
|
};
|
|
190
|
+
var toDescriptor = (metadata) => {
|
|
191
|
+
const [templateUrl] = metadataTexts(metadata, "templateUrl");
|
|
192
|
+
const [template] = metadataTexts(metadata, "template");
|
|
193
|
+
const styleUrl = metadataTexts(metadata, "styleUrl");
|
|
194
|
+
const listedStyleUrls = metadataTexts(metadata, "styleUrls");
|
|
195
|
+
const styleUrls = [...styleUrl, ...listedStyleUrls];
|
|
196
|
+
const styles = metadataTexts(metadata, "styles");
|
|
197
|
+
const descriptor = {
|
|
198
|
+
templateUrl: templateUrl ?? null,
|
|
199
|
+
template: template ?? null,
|
|
200
|
+
styleUrls,
|
|
201
|
+
styles
|
|
202
|
+
};
|
|
203
|
+
return descriptor;
|
|
204
|
+
};
|
|
205
|
+
var parseComponentMetadata = (text2, path) => {
|
|
206
|
+
const found = [];
|
|
207
|
+
const hasComponent = text2.includes(COMPONENT_MARKER);
|
|
208
|
+
if (!hasComponent) return found;
|
|
209
|
+
const visit = (node) => {
|
|
210
|
+
const metadata = decoratedMetadata(node);
|
|
211
|
+
if (metadata !== null) found.push(toDescriptor(metadata));
|
|
212
|
+
forEachChild(node, visit);
|
|
213
|
+
};
|
|
214
|
+
const source = createSourceFile(path, text2, ScriptTarget.Latest, true);
|
|
215
|
+
forEachChild(source, visit);
|
|
216
|
+
return found;
|
|
217
|
+
};
|
|
218
|
+
var componentMetadata = (path) => {
|
|
219
|
+
return readCached(cache, path, parseComponentMetadata) ?? [];
|
|
220
|
+
};
|
|
102
221
|
|
|
103
222
|
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/component-stylesheets.ts
|
|
104
223
|
var SIBLING_EXTENSIONS = [".scss", ".css"];
|
|
105
224
|
var HTML_EXTENSION = /\.html$/iu;
|
|
106
225
|
var matchesTemplate = (metadata, directory, templateFilename) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
if (templateUrl === void 0) return false;
|
|
226
|
+
const { templateUrl } = metadata;
|
|
227
|
+
if (templateUrl === null) return false;
|
|
110
228
|
const declared = resolve(directory, templateUrl);
|
|
111
229
|
const linted = resolve(templateFilename);
|
|
112
230
|
return declared === linted;
|
|
113
231
|
};
|
|
114
232
|
var templateMetadata = (componentPath, templateFilename) => {
|
|
115
233
|
const components = componentMetadata(componentPath);
|
|
116
|
-
const directory =
|
|
234
|
+
const directory = dirname2(componentPath);
|
|
117
235
|
const matches = (metadata) => {
|
|
118
236
|
return matchesTemplate(metadata, directory, templateFilename);
|
|
119
237
|
};
|
|
@@ -149,20 +267,16 @@ var inlineSources = (styles, componentPath) => {
|
|
|
149
267
|
var metadataSources = (componentPath, templateFilename) => {
|
|
150
268
|
const metadata = templateMetadata(componentPath, templateFilename);
|
|
151
269
|
if (metadata === null) return [];
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const directory = dirname(componentPath);
|
|
156
|
-
const urls = [...singleUrl, ...listedUrls];
|
|
157
|
-
const files = stylesheetFiles(urls, directory);
|
|
158
|
-
const inline = inlineSources(styles, componentPath);
|
|
270
|
+
const directory = dirname2(componentPath);
|
|
271
|
+
const files = stylesheetFiles(metadata.styleUrls, directory);
|
|
272
|
+
const inline = inlineSources(metadata.styles, componentPath);
|
|
159
273
|
return [...files, ...inline];
|
|
160
274
|
};
|
|
161
275
|
var siblingSources = (templateFilename) => {
|
|
162
276
|
const base2 = templateFilename.replace(HTML_EXTENSION, "");
|
|
163
277
|
const candidateOf = (extension) => `${base2}${extension}`;
|
|
164
278
|
const candidates = SIBLING_EXTENSIONS.map(candidateOf);
|
|
165
|
-
return stylesheetFiles(candidates,
|
|
279
|
+
return stylesheetFiles(candidates, dirname2(templateFilename));
|
|
166
280
|
};
|
|
167
281
|
var componentStylesheets = (templateFilename) => {
|
|
168
282
|
const componentPath = templateFilename.replace(HTML_EXTENSION, ".ts");
|
|
@@ -171,14 +285,40 @@ var componentStylesheets = (templateFilename) => {
|
|
|
171
285
|
return siblingSources(templateFilename);
|
|
172
286
|
};
|
|
173
287
|
|
|
174
|
-
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/
|
|
175
|
-
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
288
|
+
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/linked-stylesheets.ts
|
|
176
289
|
import { dirname as dirname3 } from "node:path";
|
|
290
|
+
|
|
291
|
+
// packages/lint-suite/src/lib/rules/utils/template-links.util.ts
|
|
292
|
+
var LINK_TAG = /<link\b[^>]*>/giu;
|
|
293
|
+
var STYLESHEET_REL = /\brel\s*=\s*["']stylesheet["']/iu;
|
|
294
|
+
var HREF = /\bhref\s*=\s*["']([^"']*)["']/iu;
|
|
295
|
+
var UNRESOLVABLE = /^(?:\/|[^:/?#]+:)/u;
|
|
296
|
+
var hrefOf = (tag) => {
|
|
297
|
+
const isStylesheet = STYLESHEET_REL.test(tag);
|
|
298
|
+
if (!isStylesheet) return null;
|
|
299
|
+
const href = HREF.exec(tag)?.[1] ?? "";
|
|
300
|
+
const isUnresolvable = UNRESOLVABLE.test(href);
|
|
301
|
+
const isLocal = href.length > 0 && !isUnresolvable;
|
|
302
|
+
return isLocal ? href : null;
|
|
303
|
+
};
|
|
304
|
+
var linkedStylesheetHrefs = (template) => {
|
|
305
|
+
const tags = template.match(LINK_TAG) ?? [];
|
|
306
|
+
return tags.map(hrefOf).filter((href) => href !== null);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/linked-stylesheets.ts
|
|
310
|
+
var linkedStylesheets = (template, templateFilename) => {
|
|
311
|
+
const hrefs = linkedStylesheetHrefs(template);
|
|
312
|
+
return stylesheetFiles(hrefs, dirname3(templateFilename));
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/stylesheet-classes.ts
|
|
316
|
+
import { dirname as dirname5 } from "node:path";
|
|
177
317
|
import { parse } from "postcss-scss";
|
|
178
318
|
|
|
179
319
|
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/stylesheet-imports.ts
|
|
180
320
|
import { existsSync as existsSync2 } from "node:fs";
|
|
181
|
-
import { basename, dirname as
|
|
321
|
+
import { basename, dirname as dirname4, join as join2, resolve as resolve2 } from "node:path";
|
|
182
322
|
var QUOTED = /'([^']*)'|"([^"]*)"/u;
|
|
183
323
|
var SKIPPED_PREFIXES = ["sass:", "http", "url("];
|
|
184
324
|
var specifierOf = (params) => {
|
|
@@ -197,13 +337,13 @@ var isResolvable = (specifier) => {
|
|
|
197
337
|
};
|
|
198
338
|
var candidatesOf = (path) => {
|
|
199
339
|
const isStylesheet = path.endsWith(".scss");
|
|
200
|
-
if (isStylesheet) return [path,
|
|
201
|
-
const partial =
|
|
340
|
+
if (isStylesheet) return [path, join2(dirname4(path), `_${basename(path)}`)];
|
|
341
|
+
const partial = join2(dirname4(path), `_${basename(path)}.scss`);
|
|
202
342
|
return [
|
|
203
343
|
`${path}.scss`,
|
|
204
344
|
partial,
|
|
205
|
-
|
|
206
|
-
|
|
345
|
+
join2(path, "index.scss"),
|
|
346
|
+
join2(path, "_index.scss")
|
|
207
347
|
];
|
|
208
348
|
};
|
|
209
349
|
var resolveStylesheetImport = (params, directory) => {
|
|
@@ -217,7 +357,7 @@ var resolveStylesheetImport = (params, directory) => {
|
|
|
217
357
|
return existing ?? null;
|
|
218
358
|
};
|
|
219
359
|
|
|
220
|
-
// packages/lint-suite/src/lib/rules/
|
|
360
|
+
// packages/lint-suite/src/lib/rules/selector-classes.ts
|
|
221
361
|
import selectorParser from "postcss-selector-parser";
|
|
222
362
|
var INTERPOLATION_TOKEN = "zzinterpzz";
|
|
223
363
|
var PARENT_TOKEN = "zzparentzz";
|
|
@@ -335,78 +475,104 @@ var collectStylesheet = (root, directory) => {
|
|
|
335
475
|
return entry;
|
|
336
476
|
};
|
|
337
477
|
|
|
478
|
+
// packages/lint-suite/src/lib/rules/utils/to-regexp.util.ts
|
|
479
|
+
var toRegExp = (pattern) => new RegExp(pattern, "u");
|
|
480
|
+
|
|
338
481
|
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/stylesheet-classes.ts
|
|
339
|
-
var
|
|
340
|
-
var
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
};
|
|
482
|
+
var EMPTY_ENTRY = { classes: [], patterns: [], imports: [] };
|
|
483
|
+
var stylesheets = createFileCache("stylesheets");
|
|
484
|
+
var inlineStylesheets = /* @__PURE__ */ new Map();
|
|
485
|
+
var merged = /* @__PURE__ */ new Map();
|
|
344
486
|
var parseStylesheet = (source, path) => {
|
|
345
487
|
try {
|
|
346
488
|
const root = parse(source, { from: path });
|
|
347
|
-
return collectStylesheet(root,
|
|
489
|
+
return collectStylesheet(root, dirname5(path));
|
|
348
490
|
} catch {
|
|
349
|
-
return
|
|
491
|
+
return EMPTY_ENTRY;
|
|
350
492
|
}
|
|
351
493
|
};
|
|
352
494
|
var fileEntry = (path) => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
} catch {
|
|
363
|
-
return emptyEntry();
|
|
364
|
-
}
|
|
495
|
+
return readCached(stylesheets, path, parseStylesheet) ?? EMPTY_ENTRY;
|
|
496
|
+
};
|
|
497
|
+
var inlineEntry = (source, path) => {
|
|
498
|
+
const key2 = `${path}\0${source}`;
|
|
499
|
+
const cached = inlineStylesheets.get(key2);
|
|
500
|
+
if (cached !== void 0) return cached;
|
|
501
|
+
const entry = parseStylesheet(source, path);
|
|
502
|
+
inlineStylesheets.set(key2, entry);
|
|
503
|
+
return entry;
|
|
365
504
|
};
|
|
366
|
-
var
|
|
367
|
-
for (const name of entry.classes) sink.exact.add(name);
|
|
368
|
-
sink.patterns.push(...entry.patterns);
|
|
505
|
+
var collectImports = (entry, chain, visited) => {
|
|
369
506
|
for (const imported of entry.imports) {
|
|
370
507
|
const isVisited = visited.has(imported);
|
|
371
508
|
if (isVisited) continue;
|
|
372
509
|
visited.add(imported);
|
|
373
|
-
|
|
510
|
+
const importedEntry = fileEntry(imported);
|
|
511
|
+
chain.push(importedEntry);
|
|
512
|
+
collectImports(importedEntry, chain, visited);
|
|
374
513
|
}
|
|
375
514
|
};
|
|
376
|
-
var
|
|
515
|
+
var entryOf = (source) => {
|
|
516
|
+
if (source.kind === "file") return fileEntry(source.path);
|
|
517
|
+
return inlineEntry(source.source, source.path);
|
|
518
|
+
};
|
|
519
|
+
var collectChain = (source, chain, visited) => {
|
|
377
520
|
if (source.kind === "file") {
|
|
378
521
|
const isVisited = visited.has(source.path);
|
|
379
522
|
if (isVisited) return;
|
|
380
523
|
visited.add(source.path);
|
|
381
|
-
addEntry(fileEntry(source.path), sink, visited);
|
|
382
|
-
return;
|
|
383
524
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return new RegExp(pattern, "u");
|
|
525
|
+
const entry = entryOf(source);
|
|
526
|
+
chain.push(entry);
|
|
527
|
+
collectImports(entry, chain, visited);
|
|
388
528
|
};
|
|
389
|
-
var
|
|
529
|
+
var mergeChain = (chain) => {
|
|
390
530
|
const exact = /* @__PURE__ */ new Set();
|
|
391
531
|
const patterns = [];
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
532
|
+
for (const entry of chain) {
|
|
533
|
+
for (const name of entry.classes) exact.add(name);
|
|
534
|
+
patterns.push(...entry.patterns);
|
|
535
|
+
}
|
|
395
536
|
const compiled = patterns.map(toRegExp);
|
|
396
537
|
const has = classMatcher(exact, compiled);
|
|
397
538
|
const size = exact.size + compiled.length;
|
|
398
539
|
const classes = { has, size };
|
|
399
540
|
return classes;
|
|
400
541
|
};
|
|
542
|
+
var isCurrentChain = (cached, chain) => {
|
|
543
|
+
if (cached === void 0) return false;
|
|
544
|
+
if (cached.chain.length !== chain.length) return false;
|
|
545
|
+
return cached.chain.every((entry, position) => entry === chain[position]);
|
|
546
|
+
};
|
|
547
|
+
var sourceKey = (source) => {
|
|
548
|
+
if (source.kind === "file") return source.path;
|
|
549
|
+
return `${source.path}\0${source.source}`;
|
|
550
|
+
};
|
|
551
|
+
var keyOf = (sources) => {
|
|
552
|
+
return sources.map(sourceKey).join("\n");
|
|
553
|
+
};
|
|
554
|
+
var stylesheetClasses = (sources) => {
|
|
555
|
+
const chain = [];
|
|
556
|
+
const visited = /* @__PURE__ */ new Set();
|
|
557
|
+
for (const source of sources) collectChain(source, chain, visited);
|
|
558
|
+
const key2 = keyOf(sources);
|
|
559
|
+
const cached = merged.get(key2);
|
|
560
|
+
if (isCurrentChain(cached, chain)) return cached.classes;
|
|
561
|
+
const classes = mergeChain(chain);
|
|
562
|
+
const fresh = { chain, classes };
|
|
563
|
+
merged.set(key2, fresh);
|
|
564
|
+
return classes;
|
|
565
|
+
};
|
|
401
566
|
|
|
402
567
|
// packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/template-stylesheets.ts
|
|
403
|
-
var templateStylesheets = (templateFilename, cwd, globalStyles) => {
|
|
568
|
+
var templateStylesheets = (templateFilename, template, cwd, globalStyles) => {
|
|
404
569
|
let known = null;
|
|
405
570
|
const lookup = () => {
|
|
406
571
|
if (known !== null) return known;
|
|
407
572
|
const component = componentStylesheets(templateFilename);
|
|
573
|
+
const linked = linkedStylesheets(template, templateFilename);
|
|
408
574
|
const global = stylesheetFiles(globalStyles, cwd);
|
|
409
|
-
const sources = [...component, ...global];
|
|
575
|
+
const sources = [...component, ...linked, ...global];
|
|
410
576
|
known = stylesheetClasses(sources);
|
|
411
577
|
return known;
|
|
412
578
|
};
|
|
@@ -497,7 +663,8 @@ var classExpressionLiterals = (source) => {
|
|
|
497
663
|
if (ast === null) return [];
|
|
498
664
|
const names = [];
|
|
499
665
|
collect(ast, names);
|
|
500
|
-
|
|
666
|
+
const uniqueNames = new Set(names);
|
|
667
|
+
return [...uniqueNames];
|
|
501
668
|
};
|
|
502
669
|
|
|
503
670
|
// packages/lint-suite/src/lib/rules/utils/template-classes.util.ts
|
|
@@ -560,10 +727,14 @@ var templateClasses = (node) => {
|
|
|
560
727
|
const classes = [];
|
|
561
728
|
for (const attribute of node.attributes) {
|
|
562
729
|
const isClassName = attribute.name === CLASS_ATTRIBUTE;
|
|
563
|
-
if (isClassName)
|
|
730
|
+
if (isClassName) {
|
|
731
|
+
const found = staticClasses(attribute);
|
|
732
|
+
classes.push(...found);
|
|
733
|
+
}
|
|
564
734
|
}
|
|
565
735
|
for (const input of node.inputs) {
|
|
566
|
-
|
|
736
|
+
const found = inputClasses(input);
|
|
737
|
+
classes.push(...found);
|
|
567
738
|
}
|
|
568
739
|
return classes;
|
|
569
740
|
};
|
|
@@ -615,7 +786,6 @@ var isTemplateServices = (services) => {
|
|
|
615
786
|
if (!("convertNodeSourceSpanToLoc" in services)) return false;
|
|
616
787
|
return typeof services.convertNodeSourceSpanToLoc === "function";
|
|
617
788
|
};
|
|
618
|
-
var toRegExp2 = (pattern) => new RegExp(pattern, "u");
|
|
619
789
|
var no_unstyled_classes_default = createRule({
|
|
620
790
|
name: "no-unstyled-classes",
|
|
621
791
|
meta,
|
|
@@ -624,9 +794,10 @@ var no_unstyled_classes_default = createRule({
|
|
|
624
794
|
const { parserServices } = context.sourceCode;
|
|
625
795
|
if (parserServices === void 0) throw new Error(PARSER_REQUIRED);
|
|
626
796
|
if (!isTemplateServices(parserServices)) throw new Error(PARSER_REQUIRED);
|
|
627
|
-
const ignored = options.ignoreClassPatterns.map(
|
|
797
|
+
const ignored = options.ignoreClassPatterns.map(toRegExp);
|
|
628
798
|
const stylesheets2 = templateStylesheets(
|
|
629
799
|
context.filename,
|
|
800
|
+
context.sourceCode.text,
|
|
630
801
|
context.cwd,
|
|
631
802
|
options.globalStyles
|
|
632
803
|
);
|
|
@@ -645,12 +816,12 @@ var no_unstyled_classes_default = createRule({
|
|
|
645
816
|
if (isStyled) continue;
|
|
646
817
|
const loc = parserServices.convertNodeSourceSpanToLoc(span);
|
|
647
818
|
const data = { name };
|
|
648
|
-
const
|
|
819
|
+
const report3 = {
|
|
649
820
|
loc,
|
|
650
821
|
messageId: "unstyledClass",
|
|
651
822
|
data
|
|
652
823
|
};
|
|
653
|
-
context.report(
|
|
824
|
+
context.report(report3);
|
|
654
825
|
}
|
|
655
826
|
}
|
|
656
827
|
};
|
|
@@ -671,6 +842,14 @@ var angularTemplate = defineConfig([
|
|
|
671
842
|
"lint-suite-angular-template": lintSuiteAngularTemplatePlugin
|
|
672
843
|
},
|
|
673
844
|
rules: {
|
|
845
|
+
"max-lines": [
|
|
846
|
+
"error",
|
|
847
|
+
{ max: 150, skipBlankLines: true, skipComments: true }
|
|
848
|
+
],
|
|
849
|
+
// A template class name no stylesheet of the component selects is
|
|
850
|
+
// reported.
|
|
851
|
+
// Bad: class="ghost" with no .ghost rule
|
|
852
|
+
// Good: add .ghost, or drop the class
|
|
674
853
|
"lint-suite-angular-template/no-unstyled-classes": "error",
|
|
675
854
|
"@angular-eslint/template/prefer-template-literal": "error",
|
|
676
855
|
"@angular-eslint/template/no-any": "error",
|
|
@@ -786,8 +965,8 @@ var addAngularImport = (node, imports) => {
|
|
|
786
965
|
imports.set(specifier.local.name, null);
|
|
787
966
|
} else if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.importKind !== "type") {
|
|
788
967
|
const { imported } = specifier;
|
|
789
|
-
const
|
|
790
|
-
const importedName =
|
|
968
|
+
const isIdentifier11 = imported.type === TSESTree.AST_NODE_TYPES.Identifier;
|
|
969
|
+
const importedName = isIdentifier11 ? imported.name : imported.value;
|
|
791
970
|
imports.set(specifier.local.name, importedName);
|
|
792
971
|
}
|
|
793
972
|
}
|
|
@@ -818,10 +997,10 @@ var angularClassImports = (ast) => {
|
|
|
818
997
|
}
|
|
819
998
|
}
|
|
820
999
|
for (const imported of imports.values()) {
|
|
821
|
-
const
|
|
1000
|
+
const isNamespaceImport2 = imported === null;
|
|
822
1001
|
const isComponent = imported === "Component";
|
|
823
1002
|
const isDirective = imported === "Directive";
|
|
824
|
-
const isAngularClassImport =
|
|
1003
|
+
const isAngularClassImport = isNamespaceImport2 || isComponent || isDirective;
|
|
825
1004
|
if (isAngularClassImport) return imports;
|
|
826
1005
|
}
|
|
827
1006
|
return null;
|
|
@@ -841,17 +1020,20 @@ var managedApis = /* @__PURE__ */ new Set([
|
|
|
841
1020
|
"contentChild",
|
|
842
1021
|
"contentChildren"
|
|
843
1022
|
]);
|
|
1023
|
+
var isManualCleanupDisabledProperty = (property) => {
|
|
1024
|
+
if (property.type !== TSESTree2.AST_NODE_TYPES.Property || property.computed) {
|
|
1025
|
+
return false;
|
|
1026
|
+
}
|
|
1027
|
+
const isIdentifierManualCleanup = property.key.type === TSESTree2.AST_NODE_TYPES.Identifier && property.key.name === "manualCleanup";
|
|
1028
|
+
const isLiteralManualCleanup = property.key.type === TSESTree2.AST_NODE_TYPES.Literal && property.key.value === "manualCleanup";
|
|
1029
|
+
const manualCleanup = isIdentifierManualCleanup || isLiteralManualCleanup;
|
|
1030
|
+
return !manualCleanup || property.value.type === TSESTree2.AST_NODE_TYPES.Literal && property.value.value === false;
|
|
1031
|
+
};
|
|
844
1032
|
var hasAutomaticEffectCleanup = (node) => {
|
|
845
1033
|
const options = node.arguments.at(1);
|
|
846
1034
|
if (options === void 0) return true;
|
|
847
1035
|
if (options.type !== TSESTree2.AST_NODE_TYPES.ObjectExpression) return false;
|
|
848
|
-
return options.properties.every(
|
|
849
|
-
if (property.type !== TSESTree2.AST_NODE_TYPES.Property || property.computed) {
|
|
850
|
-
return false;
|
|
851
|
-
}
|
|
852
|
-
const manualCleanup = property.key.type === TSESTree2.AST_NODE_TYPES.Identifier && property.key.name === "manualCleanup" || property.key.type === TSESTree2.AST_NODE_TYPES.Literal && property.key.value === "manualCleanup";
|
|
853
|
-
return !manualCleanup || property.value.type === TSESTree2.AST_NODE_TYPES.Literal && property.value.value === false;
|
|
854
|
-
});
|
|
1036
|
+
return options.properties.every(isManualCleanupDisabledProperty);
|
|
855
1037
|
};
|
|
856
1038
|
var angularCoreImportedName = (definition) => {
|
|
857
1039
|
if (definition?.type !== "ImportBinding") return null;
|
|
@@ -873,7 +1055,10 @@ var isAngularComponentRefField = (node, sourceCode) => {
|
|
|
873
1055
|
if (type?.type !== TSESTree2.AST_NODE_TYPES.TSTypeReference || type.typeName.type !== TSESTree2.AST_NODE_TYPES.Identifier) {
|
|
874
1056
|
return false;
|
|
875
1057
|
}
|
|
876
|
-
const
|
|
1058
|
+
const scope = sourceCode.getScope(type.typeName);
|
|
1059
|
+
const reference = scope.references.find(
|
|
1060
|
+
({ identifier }) => identifier === type.typeName
|
|
1061
|
+
);
|
|
877
1062
|
const definition = reference?.resolved?.defs[0];
|
|
878
1063
|
return angularCoreImportedName(definition) === "ComponentRef";
|
|
879
1064
|
};
|
|
@@ -992,7 +1177,7 @@ var methodCandidate = (node, localPrivateOnly, implementedMethods) => {
|
|
|
992
1177
|
};
|
|
993
1178
|
|
|
994
1179
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
|
|
995
|
-
import { dirname as
|
|
1180
|
+
import { dirname as dirname6, resolve as resolve3 } from "node:path";
|
|
996
1181
|
import { TSESTree as TSESTree5 } from "@typescript-eslint/utils";
|
|
997
1182
|
|
|
998
1183
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.ts
|
|
@@ -1036,7 +1221,7 @@ import {
|
|
|
1036
1221
|
R3TargetBinder,
|
|
1037
1222
|
parseTemplate
|
|
1038
1223
|
} from "@angular/compiler";
|
|
1039
|
-
import { readFileSync as
|
|
1224
|
+
import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
1040
1225
|
|
|
1041
1226
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
|
|
1042
1227
|
import {
|
|
@@ -1135,7 +1320,7 @@ var externalTemplateReads = (filename) => {
|
|
|
1135
1320
|
const version = `${stats.mtimeNs}:${stats.size}`;
|
|
1136
1321
|
const cached = externalTemplates.get(filename);
|
|
1137
1322
|
if (cached?.version === version) return cached.reads;
|
|
1138
|
-
const reads = templateReads(
|
|
1323
|
+
const reads = templateReads(readFileSync2(filename, "utf8"), filename);
|
|
1139
1324
|
externalTemplates.set(filename, { reads, version });
|
|
1140
1325
|
return reads;
|
|
1141
1326
|
} catch {
|
|
@@ -1203,7 +1388,7 @@ var inlineTemplateReads = (template, reads, filename) => {
|
|
|
1203
1388
|
var externalTemplatePropertyReads = (templateUrl, reads, filename) => {
|
|
1204
1389
|
if (!templateUrl) return true;
|
|
1205
1390
|
const url = text(templateUrl);
|
|
1206
|
-
return url !== null && addReads(reads, externalTemplateReads(resolve3(
|
|
1391
|
+
return url !== null && addReads(reads, externalTemplateReads(resolve3(dirname6(filename), url)));
|
|
1207
1392
|
};
|
|
1208
1393
|
var componentTemplateReads = (metadata, reads, filename) => {
|
|
1209
1394
|
const template = metadataValue2(metadata, "template");
|
|
@@ -1236,7 +1421,13 @@ var memberCandidates = (node, options) => {
|
|
|
1236
1421
|
const implementedMethods = implementedFormsMethods(node);
|
|
1237
1422
|
const members = [];
|
|
1238
1423
|
for (const element of node.body.body) {
|
|
1239
|
-
const
|
|
1424
|
+
const fieldMatch = fieldCandidate(element, options);
|
|
1425
|
+
const methodMatch = methodCandidate(
|
|
1426
|
+
element,
|
|
1427
|
+
options.localPrivateOnly,
|
|
1428
|
+
implementedMethods
|
|
1429
|
+
);
|
|
1430
|
+
const candidate = fieldMatch ?? methodMatch;
|
|
1240
1431
|
if (candidate) {
|
|
1241
1432
|
members.push(candidate);
|
|
1242
1433
|
}
|
|
@@ -1245,12 +1436,12 @@ var memberCandidates = (node, options) => {
|
|
|
1245
1436
|
};
|
|
1246
1437
|
var reportMember = (context, candidate) => {
|
|
1247
1438
|
const data = { name: candidate.name };
|
|
1248
|
-
const
|
|
1439
|
+
const report3 = {
|
|
1249
1440
|
data,
|
|
1250
1441
|
messageId: candidate.messageId,
|
|
1251
1442
|
node: candidate.node.key
|
|
1252
1443
|
};
|
|
1253
|
-
context.report(
|
|
1444
|
+
context.report(report3);
|
|
1254
1445
|
};
|
|
1255
1446
|
var reportUnreadMembers = (members, reads, options) => {
|
|
1256
1447
|
for (const candidate of members) {
|
|
@@ -1261,8 +1452,8 @@ var reportUnreadMembers = (members, reads, options) => {
|
|
|
1261
1452
|
reportMember(options.context, candidate);
|
|
1262
1453
|
}
|
|
1263
1454
|
};
|
|
1264
|
-
var reportClassMembers = (entry, ngClass,
|
|
1265
|
-
const { options, projectAnalysis } =
|
|
1455
|
+
var reportClassMembers = (entry, ngClass, report3) => {
|
|
1456
|
+
const { options, projectAnalysis } = report3;
|
|
1266
1457
|
const isLocalOnlyClass = !ngClass.component || entry.node.abstract === true;
|
|
1267
1458
|
const candidateOptions = {
|
|
1268
1459
|
allowEffectFields: options.allowEffectFields,
|
|
@@ -1277,7 +1468,7 @@ var reportClassMembers = (entry, ngClass, report) => {
|
|
|
1277
1468
|
if (unreadMembers.length === 0) return;
|
|
1278
1469
|
const remainingNames = unreadMembers.map((candidate) => candidate.name);
|
|
1279
1470
|
const readsOptions = {
|
|
1280
|
-
component: ngClass.component &&
|
|
1471
|
+
component: ngClass.component && report3.localTemplates,
|
|
1281
1472
|
filename: options.context.filename,
|
|
1282
1473
|
metadata: ngClass.metadata,
|
|
1283
1474
|
remainingNames,
|
|
@@ -1290,7 +1481,7 @@ var reportClassMembers = (entry, ngClass, report) => {
|
|
|
1290
1481
|
var reportUnusedMembers = (options) => {
|
|
1291
1482
|
const projectAnalysis = options.projectMemberUsed !== void 0;
|
|
1292
1483
|
const localTemplates = !projectAnalysis || !options.projectIndexed();
|
|
1293
|
-
const
|
|
1484
|
+
const report3 = {
|
|
1294
1485
|
localTemplates,
|
|
1295
1486
|
options,
|
|
1296
1487
|
projectAnalysis
|
|
@@ -1299,7 +1490,7 @@ var reportUnusedMembers = (options) => {
|
|
|
1299
1490
|
const ngClass = angularClassMetadata(entry.node, options.imports);
|
|
1300
1491
|
const isDynamicClass = options.dynamicClasses.has(entry);
|
|
1301
1492
|
if (!ngClass || isDynamicClass) continue;
|
|
1302
|
-
reportClassMembers(entry, ngClass,
|
|
1493
|
+
reportClassMembers(entry, ngClass, report3);
|
|
1303
1494
|
}
|
|
1304
1495
|
};
|
|
1305
1496
|
|
|
@@ -1544,6 +1735,7 @@ var trackDestructuringRead = (node, stack, thisStack, dynamicClasses) => {
|
|
|
1544
1735
|
};
|
|
1545
1736
|
var classReadVisitor = (classes, stack, dynamicClasses) => {
|
|
1546
1737
|
const thisStack = [];
|
|
1738
|
+
const lexicalThisListeners = lexicalThisVisitor(thisStack);
|
|
1547
1739
|
const listeners = {
|
|
1548
1740
|
ClassDeclaration(node) {
|
|
1549
1741
|
enterClass(node, classes, stack, thisStack);
|
|
@@ -1559,7 +1751,7 @@ var classReadVisitor = (classes, stack, dynamicClasses) => {
|
|
|
1559
1751
|
stack.pop();
|
|
1560
1752
|
thisStack.pop();
|
|
1561
1753
|
},
|
|
1562
|
-
...
|
|
1754
|
+
...lexicalThisListeners,
|
|
1563
1755
|
AssignmentExpression(node) {
|
|
1564
1756
|
trackDestructuringRead(node, stack, thisStack, dynamicClasses);
|
|
1565
1757
|
},
|
|
@@ -1574,7 +1766,7 @@ var classReadVisitor = (classes, stack, dynamicClasses) => {
|
|
|
1574
1766
|
};
|
|
1575
1767
|
|
|
1576
1768
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
|
|
1577
|
-
import { isClassElement, isIdentifier as
|
|
1769
|
+
import { isClassElement, isIdentifier as isIdentifier9, isStringLiteralLike as isStringLiteralLike8 } from "typescript";
|
|
1578
1770
|
|
|
1579
1771
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.ts
|
|
1580
1772
|
import { CssSelector, SelectorMatcher } from "@angular/compiler";
|
|
@@ -1597,7 +1789,8 @@ var classShape = ({
|
|
|
1597
1789
|
return fields.join("\0");
|
|
1598
1790
|
};
|
|
1599
1791
|
var directiveShape = (classes) => {
|
|
1600
|
-
const
|
|
1792
|
+
const classList = [...classes];
|
|
1793
|
+
const shapes = classList.map(classShape);
|
|
1601
1794
|
return shapes.sort().join("\n");
|
|
1602
1795
|
};
|
|
1603
1796
|
var parseSelector = (selector) => {
|
|
@@ -1607,10 +1800,21 @@ var parseSelector = (selector) => {
|
|
|
1607
1800
|
return null;
|
|
1608
1801
|
}
|
|
1609
1802
|
};
|
|
1803
|
+
var slotsOf = /* @__PURE__ */ new WeakMap();
|
|
1804
|
+
var classKey = ({ declaration, name }) => {
|
|
1805
|
+
return `${declaration.getSourceFile().fileName}\0${name}`;
|
|
1806
|
+
};
|
|
1807
|
+
var addSlot = (slots, angularClass2, holder) => {
|
|
1808
|
+
const key2 = classKey(angularClass2);
|
|
1809
|
+
const holders = slots.get(key2) ?? [];
|
|
1810
|
+
holders.push(holder);
|
|
1811
|
+
slots.set(key2, holders);
|
|
1812
|
+
};
|
|
1610
1813
|
var buildDirectiveIndex = (classes) => {
|
|
1611
1814
|
const byDeclaration = /* @__PURE__ */ new Map();
|
|
1612
1815
|
const byExportAs = /* @__PURE__ */ new Map();
|
|
1613
1816
|
const componentMatcher = new SelectorMatcher();
|
|
1817
|
+
const slots = /* @__PURE__ */ new Map();
|
|
1614
1818
|
for (const angularClass2 of classes) {
|
|
1615
1819
|
const { component, declaration, exportAs, selector } = angularClass2;
|
|
1616
1820
|
byDeclaration.set(declaration, angularClass2);
|
|
@@ -1618,11 +1822,14 @@ var buildDirectiveIndex = (classes) => {
|
|
|
1618
1822
|
const declarations = byExportAs.get(name) ?? [];
|
|
1619
1823
|
declarations.push(declaration);
|
|
1620
1824
|
byExportAs.set(name, declarations);
|
|
1825
|
+
addSlot(slots, angularClass2, declarations);
|
|
1621
1826
|
}
|
|
1622
1827
|
if (component && selector !== null) {
|
|
1623
1828
|
const selectors = parseSelector(selector);
|
|
1624
1829
|
if (selectors) {
|
|
1625
|
-
|
|
1830
|
+
const holder = [declaration];
|
|
1831
|
+
componentMatcher.addSelectables(selectors, holder);
|
|
1832
|
+
addSlot(slots, angularClass2, holder);
|
|
1626
1833
|
}
|
|
1627
1834
|
}
|
|
1628
1835
|
}
|
|
@@ -1631,12 +1838,39 @@ var buildDirectiveIndex = (classes) => {
|
|
|
1631
1838
|
byExportAs,
|
|
1632
1839
|
componentMatcher
|
|
1633
1840
|
};
|
|
1841
|
+
slotsOf.set(directiveIndex, slots);
|
|
1634
1842
|
return directiveIndex;
|
|
1635
1843
|
};
|
|
1844
|
+
var repointHolders = (holders, previous, next) => {
|
|
1845
|
+
for (const holder of holders) {
|
|
1846
|
+
const position = holder.indexOf(previous);
|
|
1847
|
+
if (position >= 0) holder[position] = next;
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
var replaceDeclarations = (index, previous, next) => {
|
|
1851
|
+
const slots = slotsOf.get(index) ?? /* @__PURE__ */ new Map();
|
|
1852
|
+
const nextByKey = /* @__PURE__ */ new Map();
|
|
1853
|
+
for (const angularClass2 of next) {
|
|
1854
|
+
nextByKey.set(classKey(angularClass2), angularClass2);
|
|
1855
|
+
}
|
|
1856
|
+
for (const angularClass2 of previous) {
|
|
1857
|
+
const key2 = classKey(angularClass2);
|
|
1858
|
+
const replacement = nextByKey.get(key2);
|
|
1859
|
+
if (!replacement) continue;
|
|
1860
|
+
const holders = slots.get(key2) ?? [];
|
|
1861
|
+
repointHolders(holders, angularClass2.declaration, replacement.declaration);
|
|
1862
|
+
index.byDeclaration.delete(angularClass2.declaration);
|
|
1863
|
+
index.byDeclaration.set(replacement.declaration, replacement);
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
|
|
1867
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.ts
|
|
1868
|
+
import { dirname as dirname9, normalize as normalize2 } from "node:path";
|
|
1636
1869
|
|
|
1637
1870
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
|
|
1638
|
-
import { readFileSync as
|
|
1639
|
-
import {
|
|
1871
|
+
import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
|
|
1872
|
+
import { dirname as dirname7, normalize } from "node:path";
|
|
1873
|
+
import { isIdentifier as isIdentifier3, isStringLiteralLike as isStringLiteralLike3 } from "typescript";
|
|
1640
1874
|
|
|
1641
1875
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
|
|
1642
1876
|
import {
|
|
@@ -1649,6 +1883,66 @@ import {
|
|
|
1649
1883
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.ts
|
|
1650
1884
|
import { SignatureKind, TypeFlags } from "typescript";
|
|
1651
1885
|
|
|
1886
|
+
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/class-members.util.ts
|
|
1887
|
+
import {
|
|
1888
|
+
SyntaxKind,
|
|
1889
|
+
isClassLike,
|
|
1890
|
+
isFunctionDeclaration,
|
|
1891
|
+
isFunctionExpression,
|
|
1892
|
+
isGetAccessor,
|
|
1893
|
+
isIdentifier as isIdentifier2,
|
|
1894
|
+
isMethodDeclaration,
|
|
1895
|
+
isObjectLiteralExpression as isObjectLiteralExpression2,
|
|
1896
|
+
isPrivateIdentifier,
|
|
1897
|
+
isSetAccessor,
|
|
1898
|
+
isSourceFile,
|
|
1899
|
+
isStringLiteralLike as isStringLiteralLike2
|
|
1900
|
+
} from "typescript";
|
|
1901
|
+
var memberNameOf = (member) => {
|
|
1902
|
+
const { name } = member;
|
|
1903
|
+
if (!name) return null;
|
|
1904
|
+
const isIdentifierName = isIdentifier2(name);
|
|
1905
|
+
const isPrivateName = isPrivateIdentifier(name);
|
|
1906
|
+
const isStringName = isStringLiteralLike2(name);
|
|
1907
|
+
const isTextName = isIdentifierName || isPrivateName || isStringName;
|
|
1908
|
+
if (!isTextName) return null;
|
|
1909
|
+
return name.text;
|
|
1910
|
+
};
|
|
1911
|
+
var ownMembersNamed = (declaration, name) => {
|
|
1912
|
+
const isNamed = (member) => {
|
|
1913
|
+
return memberNameOf(member) === name;
|
|
1914
|
+
};
|
|
1915
|
+
return declaration.members.filter(isNamed);
|
|
1916
|
+
};
|
|
1917
|
+
var isObjectLiteralMember = (node) => {
|
|
1918
|
+
const isMethod = isMethodDeclaration(node);
|
|
1919
|
+
const isGetter = isGetAccessor(node);
|
|
1920
|
+
const isSetter = isSetAccessor(node);
|
|
1921
|
+
const isMember = isMethod || isGetter || isSetter;
|
|
1922
|
+
if (!isMember) return false;
|
|
1923
|
+
return isObjectLiteralExpression2(node.parent);
|
|
1924
|
+
};
|
|
1925
|
+
var isThisBoundary = (node) => {
|
|
1926
|
+
const isDeclaration = isFunctionDeclaration(node);
|
|
1927
|
+
const isExpression = isFunctionExpression(node);
|
|
1928
|
+
const isFunction = isDeclaration || isExpression;
|
|
1929
|
+
if (isFunction) return true;
|
|
1930
|
+
return isObjectLiteralMember(node);
|
|
1931
|
+
};
|
|
1932
|
+
var thisClassOf = (node) => {
|
|
1933
|
+
let current = node.parent;
|
|
1934
|
+
while (!isSourceFile(current)) {
|
|
1935
|
+
if (isClassLike(current)) return current;
|
|
1936
|
+
const isBoundary = isThisBoundary(current);
|
|
1937
|
+
if (isBoundary) return null;
|
|
1938
|
+
current = current.parent;
|
|
1939
|
+
}
|
|
1940
|
+
return null;
|
|
1941
|
+
};
|
|
1942
|
+
var isThisExpression2 = (node) => {
|
|
1943
|
+
return node.kind === SyntaxKind.ThisKeyword;
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1652
1946
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/utils/type-property-symbols.util.ts
|
|
1653
1947
|
import { IndexKind } from "typescript";
|
|
1654
1948
|
var symbolsForName = (checker, type, name) => {
|
|
@@ -1708,6 +2002,15 @@ var memberTypes = (symbols, declaration, checker, sink) => {
|
|
|
1708
2002
|
}
|
|
1709
2003
|
return types;
|
|
1710
2004
|
};
|
|
2005
|
+
var addOwnMemberPath = (declaration, names, sink) => {
|
|
2006
|
+
const [only] = names;
|
|
2007
|
+
const isSingle = names.length === 1 && only !== void 0;
|
|
2008
|
+
if (!isSingle) return false;
|
|
2009
|
+
const members = ownMembersNamed(declaration, only.name);
|
|
2010
|
+
if (members.length === 0) return false;
|
|
2011
|
+
for (const member of members) sink.addDeclaration(member);
|
|
2012
|
+
return true;
|
|
2013
|
+
};
|
|
1711
2014
|
var addResolvedPath = ({
|
|
1712
2015
|
allowMissingRoot,
|
|
1713
2016
|
checker,
|
|
@@ -1715,6 +2018,8 @@ var addResolvedPath = ({
|
|
|
1715
2018
|
names,
|
|
1716
2019
|
sink
|
|
1717
2020
|
}) => {
|
|
2021
|
+
const isOwnMember = addOwnMemberPath(declaration, names, sink);
|
|
2022
|
+
if (isOwnMember) return true;
|
|
1718
2023
|
let types = [checker.getTypeAtLocation(declaration)];
|
|
1719
2024
|
const indexTypesOf = (type) => stringIndexTypes(checker, type);
|
|
1720
2025
|
const returnTypesOf = (type) => callReturnTypes(checker, type);
|
|
@@ -1868,14 +2173,13 @@ var referenceTargets = (reference, owner, directives, scope) => {
|
|
|
1868
2173
|
} else if (owner instanceof TmplAstElement) {
|
|
1869
2174
|
directives.componentMatcher.match(
|
|
1870
2175
|
createCssSelectorFromNode(owner),
|
|
1871
|
-
(_selector, declarations) =>
|
|
1872
|
-
targets.push(...declarations);
|
|
1873
|
-
}
|
|
2176
|
+
(_selector, declarations) => targets.push(...declarations)
|
|
1874
2177
|
);
|
|
1875
2178
|
}
|
|
1876
|
-
const
|
|
2179
|
+
const hostDirectiveInScope = scope?.some(
|
|
1877
2180
|
(declaration) => directives.byDeclaration.get(declaration)?.hostDirectives
|
|
1878
|
-
);
|
|
2181
|
+
) ?? false;
|
|
2182
|
+
const scoped = scope !== null && !hostDirectiveInScope;
|
|
1879
2183
|
if (!scoped) return targets;
|
|
1880
2184
|
const scopedTargets = targets.filter((target) => scope.includes(target));
|
|
1881
2185
|
return scopedTargets;
|
|
@@ -1948,6 +2252,23 @@ var addChainRead = (context, reads, boundTarget, chain) => {
|
|
|
1948
2252
|
addReferenceRead(context, entity, owner, names);
|
|
1949
2253
|
return true;
|
|
1950
2254
|
};
|
|
2255
|
+
var PARSE_OPTIONS = {
|
|
2256
|
+
leadingTriviaChars: [],
|
|
2257
|
+
preserveWhitespaces: true
|
|
2258
|
+
};
|
|
2259
|
+
var PARSE_CACHE_SIZE = 64;
|
|
2260
|
+
var parsedTemplates = /* @__PURE__ */ new Map();
|
|
2261
|
+
var parsedTemplate = (source, fileName) => {
|
|
2262
|
+
const key2 = `${fileName}\0${source}`;
|
|
2263
|
+
const cached = parsedTemplates.get(key2);
|
|
2264
|
+
if (cached !== void 0) return cached;
|
|
2265
|
+
const parsed = parseTemplate2(source, fileName, PARSE_OPTIONS);
|
|
2266
|
+
const isFull = parsedTemplates.size >= PARSE_CACHE_SIZE;
|
|
2267
|
+
const [oldest] = parsedTemplates.keys();
|
|
2268
|
+
if (isFull && oldest !== void 0) parsedTemplates.delete(oldest);
|
|
2269
|
+
parsedTemplates.set(key2, parsed);
|
|
2270
|
+
return parsed;
|
|
2271
|
+
};
|
|
1951
2272
|
var addTemplateReads = ({
|
|
1952
2273
|
angularClass: angularClass2,
|
|
1953
2274
|
checker,
|
|
@@ -1967,7 +2288,7 @@ var addTemplateReads = ({
|
|
|
1967
2288
|
scope,
|
|
1968
2289
|
sink
|
|
1969
2290
|
};
|
|
1970
|
-
const parsed =
|
|
2291
|
+
const parsed = parsedTemplate(source, fileName);
|
|
1971
2292
|
if (parsed.errors?.length) {
|
|
1972
2293
|
const error = parsed.errors[0]?.msg;
|
|
1973
2294
|
return unparsedTemplateReads(context, source, error);
|
|
@@ -1987,28 +2308,34 @@ var addTemplateReads = ({
|
|
|
1987
2308
|
};
|
|
1988
2309
|
|
|
1989
2310
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
|
|
1990
|
-
var
|
|
2311
|
+
var memberNameOf2 = (member) => {
|
|
1991
2312
|
const name = member.name;
|
|
1992
2313
|
if (!name) return [];
|
|
1993
|
-
const isIdentifierName =
|
|
1994
|
-
const isStringName =
|
|
2314
|
+
const isIdentifierName = isIdentifier3(name);
|
|
2315
|
+
const isStringName = isStringLiteralLike3(name);
|
|
1995
2316
|
const isTextName = isIdentifierName || isStringName;
|
|
1996
2317
|
if (!isTextName) return [];
|
|
1997
2318
|
const names = [name.text];
|
|
1998
2319
|
return names;
|
|
1999
2320
|
};
|
|
2000
2321
|
var memberNames = (declaration) => {
|
|
2001
|
-
return declaration.members.flatMap(
|
|
2322
|
+
return declaration.members.flatMap(memberNameOf2);
|
|
2002
2323
|
};
|
|
2003
2324
|
var unknownTemplateNames = ({ declaration, scope }, allNames) => {
|
|
2004
2325
|
if (scope === null) return allNames;
|
|
2005
2326
|
const scopeNames = scope.flatMap(memberNames);
|
|
2006
|
-
const
|
|
2327
|
+
const declarationNames = memberNames(declaration);
|
|
2328
|
+
const names = [...declarationNames, ...scopeNames];
|
|
2007
2329
|
return names;
|
|
2008
2330
|
};
|
|
2331
|
+
var IDENTIFIER = /[A-Za-z_$][\w$]*/gu;
|
|
2332
|
+
var addTemplateMentions = (source, sink) => {
|
|
2333
|
+
for (const [name] of source.matchAll(IDENTIFIER)) sink.addMention(name);
|
|
2334
|
+
};
|
|
2009
2335
|
var templateFileVersion = (fileName) => {
|
|
2010
2336
|
const { mtimeNs, size } = statSync3(fileName, { bigint: true });
|
|
2011
|
-
const
|
|
2337
|
+
const directory = dirname7(normalize(fileName));
|
|
2338
|
+
const version = { directory, fileName, mtimeNs, size };
|
|
2012
2339
|
return version;
|
|
2013
2340
|
};
|
|
2014
2341
|
var templateFileIsCurrent = (version) => {
|
|
@@ -2037,7 +2364,7 @@ var templateSourceOf = (angularClass2, allNames, sink, versions) => {
|
|
|
2037
2364
|
const templateFileName = template.fileName;
|
|
2038
2365
|
try {
|
|
2039
2366
|
versions.push(templateFileVersion(templateFileName));
|
|
2040
|
-
const source =
|
|
2367
|
+
const source = readFileSync3(templateFileName, "utf8");
|
|
2041
2368
|
const externalSource = {
|
|
2042
2369
|
fileName: templateFileName,
|
|
2043
2370
|
source
|
|
@@ -2067,6 +2394,7 @@ var collectAngularTemplateReads = ({
|
|
|
2067
2394
|
templateVersions
|
|
2068
2395
|
);
|
|
2069
2396
|
if (template === null) continue;
|
|
2397
|
+
addTemplateMentions(template.source, sink);
|
|
2070
2398
|
const result = addTemplateReads({
|
|
2071
2399
|
angularClass: angularClass2,
|
|
2072
2400
|
checker,
|
|
@@ -2087,22 +2415,22 @@ var collectAngularTemplateReads = ({
|
|
|
2087
2415
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
|
|
2088
2416
|
import {
|
|
2089
2417
|
forEachChild as forEachChild2,
|
|
2090
|
-
isClassLike,
|
|
2418
|
+
isClassLike as isClassLike2,
|
|
2091
2419
|
isElementAccessExpression,
|
|
2092
2420
|
isPropertyAccessExpression
|
|
2093
2421
|
} from "typescript";
|
|
2094
2422
|
|
|
2095
2423
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-angular-interface-methods.ts
|
|
2096
|
-
import { SyntaxKind, isMethodSignature } from "typescript";
|
|
2424
|
+
import { SyntaxKind as SyntaxKind2, isMethodSignature } from "typescript";
|
|
2097
2425
|
|
|
2098
2426
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-symbol-reads.ts
|
|
2099
2427
|
import {
|
|
2100
2428
|
SymbolFlags,
|
|
2101
2429
|
isBigIntLiteral,
|
|
2102
|
-
isIdentifier as
|
|
2430
|
+
isIdentifier as isIdentifier4,
|
|
2103
2431
|
isNumericLiteral,
|
|
2104
|
-
isPrivateIdentifier,
|
|
2105
|
-
isStringLiteralLike as
|
|
2432
|
+
isPrivateIdentifier as isPrivateIdentifier2,
|
|
2433
|
+
isStringLiteralLike as isStringLiteralLike4
|
|
2106
2434
|
} from "typescript";
|
|
2107
2435
|
var aliasTarget = (checker, symbol) => {
|
|
2108
2436
|
const isAlias = (symbol.flags & SymbolFlags.Alias) !== 0;
|
|
@@ -2157,9 +2485,9 @@ var literalPropertyNames = (type) => {
|
|
|
2157
2485
|
return names;
|
|
2158
2486
|
};
|
|
2159
2487
|
var propertyName2 = (checker, node) => {
|
|
2160
|
-
const isIdentifierName =
|
|
2161
|
-
const isPrivateName =
|
|
2162
|
-
const isStringName =
|
|
2488
|
+
const isIdentifierName = isIdentifier4(node);
|
|
2489
|
+
const isPrivateName = isPrivateIdentifier2(node);
|
|
2490
|
+
const isStringName = isStringLiteralLike4(node);
|
|
2163
2491
|
const isNumericName = isNumericLiteral(node);
|
|
2164
2492
|
const isBigIntName = isBigIntLiteral(node);
|
|
2165
2493
|
const isLiteralName = isIdentifierName || isPrivateName || isStringName || isNumericName || isBigIntName;
|
|
@@ -2191,7 +2519,7 @@ var addImplementations = (heritageType, classType, checker, sink) => {
|
|
|
2191
2519
|
var collectAngularInterfaceMethods = (node, checker, sink) => {
|
|
2192
2520
|
const heritageClauses = node.heritageClauses ?? [];
|
|
2193
2521
|
const implementsClauses = heritageClauses.filter(
|
|
2194
|
-
(clause) => clause.token ===
|
|
2522
|
+
(clause) => clause.token === SyntaxKind2.ImplementsKeyword
|
|
2195
2523
|
);
|
|
2196
2524
|
if (implementsClauses.length === 0) return;
|
|
2197
2525
|
const classType = checker.getTypeAtLocation(node);
|
|
@@ -2206,18 +2534,18 @@ var collectAngularInterfaceMethods = (node, checker, sink) => {
|
|
|
2206
2534
|
|
|
2207
2535
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.ts
|
|
2208
2536
|
import {
|
|
2209
|
-
SyntaxKind as
|
|
2537
|
+
SyntaxKind as SyntaxKind3,
|
|
2210
2538
|
isArrayLiteralExpression as isArrayLiteralExpression3,
|
|
2211
2539
|
isBinaryExpression,
|
|
2212
2540
|
isBindingElement,
|
|
2213
|
-
isObjectLiteralExpression as
|
|
2541
|
+
isObjectLiteralExpression as isObjectLiteralExpression4,
|
|
2214
2542
|
isVariableDeclaration
|
|
2215
2543
|
} from "typescript";
|
|
2216
2544
|
|
|
2217
2545
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-assignment-pattern-elements.ts
|
|
2218
2546
|
import {
|
|
2219
2547
|
isArrayLiteralExpression as isArrayLiteralExpression2,
|
|
2220
|
-
isObjectLiteralExpression as
|
|
2548
|
+
isObjectLiteralExpression as isObjectLiteralExpression3,
|
|
2221
2549
|
isOmittedExpression,
|
|
2222
2550
|
isPropertyAssignment as isPropertyAssignment2,
|
|
2223
2551
|
isSpreadAssignment,
|
|
@@ -2225,7 +2553,7 @@ import {
|
|
|
2225
2553
|
} from "typescript";
|
|
2226
2554
|
var nestedPattern = (expression) => {
|
|
2227
2555
|
const isArrayLiteral = isArrayLiteralExpression2(expression);
|
|
2228
|
-
const isObjectLiteral =
|
|
2556
|
+
const isObjectLiteral = isObjectLiteralExpression3(expression);
|
|
2229
2557
|
const isNested = isArrayLiteral || isObjectLiteral;
|
|
2230
2558
|
if (!isNested) return null;
|
|
2231
2559
|
return expression;
|
|
@@ -2287,7 +2615,7 @@ var assignmentPatternElements = (pattern, checker) => {
|
|
|
2287
2615
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-binding-pattern-elements.ts
|
|
2288
2616
|
import {
|
|
2289
2617
|
isArrayBindingPattern,
|
|
2290
|
-
isIdentifier as
|
|
2618
|
+
isIdentifier as isIdentifier5,
|
|
2291
2619
|
isObjectBindingPattern,
|
|
2292
2620
|
isOmittedExpression as isOmittedExpression2
|
|
2293
2621
|
} from "typescript";
|
|
@@ -2303,7 +2631,7 @@ var nestedPattern2 = (element) => {
|
|
|
2303
2631
|
};
|
|
2304
2632
|
var bindingNames = (checker, element) => {
|
|
2305
2633
|
if (element.propertyName) return propertyName2(checker, element.propertyName);
|
|
2306
|
-
const isIdentifierName =
|
|
2634
|
+
const isIdentifierName = isIdentifier5(element.name);
|
|
2307
2635
|
if (!isIdentifierName) return null;
|
|
2308
2636
|
return [element.name.text];
|
|
2309
2637
|
};
|
|
@@ -2391,6 +2719,7 @@ var collectPatternReads = (pattern, type, context) => {
|
|
|
2391
2719
|
}
|
|
2392
2720
|
for (const name of read.names ?? []) {
|
|
2393
2721
|
consumed.add(name);
|
|
2722
|
+
sink.addMention(name);
|
|
2394
2723
|
}
|
|
2395
2724
|
const skip = isSkippable(read, candidateNames);
|
|
2396
2725
|
if (skip) continue;
|
|
@@ -2398,9 +2727,8 @@ var collectPatternReads = (pattern, type, context) => {
|
|
|
2398
2727
|
const nested = read.nested;
|
|
2399
2728
|
if (nested === null) continue;
|
|
2400
2729
|
for (const symbol of symbols) {
|
|
2401
|
-
const
|
|
2402
|
-
|
|
2403
|
-
});
|
|
2730
|
+
const nestedTypeOf = () => checker.getTypeOfSymbolAtLocation(symbol, read.location);
|
|
2731
|
+
const nestedType = lazyType(nestedTypeOf);
|
|
2404
2732
|
collectPatternReads(nested, nestedType, context);
|
|
2405
2733
|
}
|
|
2406
2734
|
}
|
|
@@ -2422,10 +2750,10 @@ var collectBindingReads = (node, context) => {
|
|
|
2422
2750
|
var collectAssignmentReads = (node, context) => {
|
|
2423
2751
|
const isBinary = isBinaryExpression(node);
|
|
2424
2752
|
if (!isBinary) return;
|
|
2425
|
-
const isEqualsAssignment = node.operatorToken.kind ===
|
|
2753
|
+
const isEqualsAssignment = node.operatorToken.kind === SyntaxKind3.EqualsToken;
|
|
2426
2754
|
if (!isEqualsAssignment) return;
|
|
2427
2755
|
const isArrayTarget = isArrayLiteralExpression3(node.left);
|
|
2428
|
-
const isObjectTarget =
|
|
2756
|
+
const isObjectTarget = isObjectLiteralExpression4(node.left);
|
|
2429
2757
|
const isDestructuringAssignment = isArrayTarget || isObjectTarget;
|
|
2430
2758
|
if (!isDestructuringAssignment) return;
|
|
2431
2759
|
const rightTypeOf = () => context.checker.getTypeAtLocation(node.right);
|
|
@@ -2440,7 +2768,7 @@ var collectDestructuringReads = (node, checker, sink, candidateNames) => {
|
|
|
2440
2768
|
|
|
2441
2769
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-write-targets.ts
|
|
2442
2770
|
import {
|
|
2443
|
-
SyntaxKind as
|
|
2771
|
+
SyntaxKind as SyntaxKind4,
|
|
2444
2772
|
isArrayLiteralExpression as isArrayLiteralExpression4,
|
|
2445
2773
|
isAsExpression,
|
|
2446
2774
|
isBinaryExpression as isBinaryExpression2,
|
|
@@ -2448,7 +2776,7 @@ import {
|
|
|
2448
2776
|
isForInStatement,
|
|
2449
2777
|
isForOfStatement,
|
|
2450
2778
|
isNonNullExpression,
|
|
2451
|
-
isObjectLiteralExpression as
|
|
2779
|
+
isObjectLiteralExpression as isObjectLiteralExpression5,
|
|
2452
2780
|
isParenthesizedExpression,
|
|
2453
2781
|
isPropertyAssignment as isPropertyAssignment3,
|
|
2454
2782
|
isSatisfiesExpression,
|
|
@@ -2471,7 +2799,7 @@ var isPatternContainer = (parent, child) => {
|
|
|
2471
2799
|
if (isArrayLiteral) {
|
|
2472
2800
|
return parent.elements.some((element) => element === child);
|
|
2473
2801
|
}
|
|
2474
|
-
const isObjectLiteral =
|
|
2802
|
+
const isObjectLiteral = isObjectLiteralExpression5(parent);
|
|
2475
2803
|
if (isObjectLiteral) {
|
|
2476
2804
|
return parent.properties.some((property) => property === child);
|
|
2477
2805
|
}
|
|
@@ -2483,7 +2811,7 @@ var isPatternContainer = (parent, child) => {
|
|
|
2483
2811
|
};
|
|
2484
2812
|
var isWriteTarget = (parent, current) => {
|
|
2485
2813
|
const isBinary = isBinaryExpression2(parent);
|
|
2486
|
-
const isBinaryTarget = isBinary && parent.left === current && parent.operatorToken.kind ===
|
|
2814
|
+
const isBinaryTarget = isBinary && parent.left === current && parent.operatorToken.kind === SyntaxKind4.EqualsToken;
|
|
2487
2815
|
if (isBinaryTarget) return true;
|
|
2488
2816
|
const isDelete = isDeleteExpression(parent);
|
|
2489
2817
|
const isDeleteTarget = isDelete && parent.expression === current;
|
|
@@ -2504,11 +2832,24 @@ var isWriteOnly2 = (node) => {
|
|
|
2504
2832
|
};
|
|
2505
2833
|
|
|
2506
2834
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
|
|
2835
|
+
var addOwnMemberRead = (node, sink) => {
|
|
2836
|
+
const isThisAccess = isThisExpression2(node.expression);
|
|
2837
|
+
if (!isThisAccess) return false;
|
|
2838
|
+
const owner = thisClassOf(node);
|
|
2839
|
+
if (owner === null) return false;
|
|
2840
|
+
const members = ownMembersNamed(owner, node.name.text);
|
|
2841
|
+
if (members.length === 0) return false;
|
|
2842
|
+
for (const member of members) sink.addDeclaration(member);
|
|
2843
|
+
return true;
|
|
2844
|
+
};
|
|
2507
2845
|
var addPropertyAccessRead = (node, checker, sink, candidateNames) => {
|
|
2846
|
+
sink.addMention(node.name.text);
|
|
2508
2847
|
const isCandidateName = candidateNames.has(node.name.text);
|
|
2509
2848
|
if (!isCandidateName) return;
|
|
2510
2849
|
const isWriteTarget2 = isWriteOnly2(node);
|
|
2511
2850
|
if (isWriteTarget2) return;
|
|
2851
|
+
const isOwnMember = addOwnMemberRead(node, sink);
|
|
2852
|
+
if (isOwnMember) return;
|
|
2512
2853
|
sink.addType(checker.getTypeAtLocation(node.expression));
|
|
2513
2854
|
const symbol = checker.getSymbolAtLocation(node.name);
|
|
2514
2855
|
if (symbol) {
|
|
@@ -2520,6 +2861,7 @@ var addElementAccessRead = (node, checker, sink, candidateNames) => {
|
|
|
2520
2861
|
if (isWriteTarget2) return;
|
|
2521
2862
|
const argumentType = checker.getTypeAtLocation(node.argumentExpression);
|
|
2522
2863
|
const names = literalPropertyNames(argumentType);
|
|
2864
|
+
for (const name of names ?? []) sink.addMention(name);
|
|
2523
2865
|
if (names) {
|
|
2524
2866
|
const hasCandidateName = names.some((name) => candidateNames.has(name));
|
|
2525
2867
|
if (!hasCandidateName) return;
|
|
@@ -2531,7 +2873,7 @@ var collectTypeScriptReads = (sourceFile, checker, sink, candidateNames) => {
|
|
|
2531
2873
|
const visit = (node) => {
|
|
2532
2874
|
const isPropertyAccess = isPropertyAccessExpression(node);
|
|
2533
2875
|
const isElementAccess = isElementAccessExpression(node);
|
|
2534
|
-
const isClass =
|
|
2876
|
+
const isClass = isClassLike2(node);
|
|
2535
2877
|
if (isPropertyAccess) {
|
|
2536
2878
|
addPropertyAccessRead(node, checker, sink, candidateNames);
|
|
2537
2879
|
} else if (isElementAccess) {
|
|
@@ -2631,6 +2973,7 @@ var computeEntry = (index, sourceFile, checker) => {
|
|
|
2631
2973
|
const declarations = /* @__PURE__ */ new Set();
|
|
2632
2974
|
const dependencies = /* @__PURE__ */ new Set();
|
|
2633
2975
|
const fallbackNames = /* @__PURE__ */ new Set();
|
|
2976
|
+
const mentionedNames = /* @__PURE__ */ new Set();
|
|
2634
2977
|
const seenTypes = /* @__PURE__ */ new Set();
|
|
2635
2978
|
const sink = {
|
|
2636
2979
|
addDeclaration: (declaration) => {
|
|
@@ -2642,6 +2985,9 @@ var computeEntry = (index, sourceFile, checker) => {
|
|
|
2642
2985
|
fallbackNames.add(name);
|
|
2643
2986
|
}
|
|
2644
2987
|
},
|
|
2988
|
+
addMention: (name) => {
|
|
2989
|
+
mentionedNames.add(name);
|
|
2990
|
+
},
|
|
2645
2991
|
addType: (type) => {
|
|
2646
2992
|
addTypeDependencies(checker, type, dependencies, seenTypes);
|
|
2647
2993
|
}
|
|
@@ -2653,6 +2999,7 @@ var computeEntry = (index, sourceFile, checker) => {
|
|
|
2653
2999
|
declarations,
|
|
2654
3000
|
dependencies,
|
|
2655
3001
|
fallbackNames,
|
|
3002
|
+
mentionedNames,
|
|
2656
3003
|
sourceFile
|
|
2657
3004
|
};
|
|
2658
3005
|
return fileEntry2;
|
|
@@ -2664,16 +3011,16 @@ import {
|
|
|
2664
3011
|
forEachChild as forEachChild3,
|
|
2665
3012
|
getDecorators as getDecorators3,
|
|
2666
3013
|
isCallExpression as isCallExpression3,
|
|
2667
|
-
isClassLike as
|
|
2668
|
-
isObjectLiteralExpression as
|
|
3014
|
+
isClassLike as isClassLike4,
|
|
3015
|
+
isObjectLiteralExpression as isObjectLiteralExpression6
|
|
2669
3016
|
} from "typescript";
|
|
2670
3017
|
|
|
2671
3018
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.ts
|
|
2672
3019
|
import {
|
|
2673
|
-
SyntaxKind as
|
|
3020
|
+
SyntaxKind as SyntaxKind5,
|
|
2674
3021
|
isArrayLiteralExpression as isArrayLiteralExpression5,
|
|
2675
|
-
isClassLike as
|
|
2676
|
-
isIdentifier as
|
|
3022
|
+
isClassLike as isClassLike3,
|
|
3023
|
+
isIdentifier as isIdentifier7,
|
|
2677
3024
|
isPropertyAccessExpression as isPropertyAccessExpression3
|
|
2678
3025
|
} from "typescript";
|
|
2679
3026
|
|
|
@@ -2684,7 +3031,7 @@ import {
|
|
|
2684
3031
|
getDecorators as getDecorators2,
|
|
2685
3032
|
isCallExpression as isCallExpression2,
|
|
2686
3033
|
isImportDeclaration,
|
|
2687
|
-
isStringLiteralLike as
|
|
3034
|
+
isStringLiteralLike as isStringLiteralLike5
|
|
2688
3035
|
} from "typescript";
|
|
2689
3036
|
var decoratorKinds = [
|
|
2690
3037
|
"Component",
|
|
@@ -2706,7 +3053,7 @@ var importedFromAngularCore = (declaration) => {
|
|
|
2706
3053
|
let current = parentOf2(declaration);
|
|
2707
3054
|
while (current) {
|
|
2708
3055
|
if (isImportDeclaration(current)) {
|
|
2709
|
-
return
|
|
3056
|
+
return isStringLiteralLike5(current.moduleSpecifier) && current.moduleSpecifier.text === "@angular/core";
|
|
2710
3057
|
}
|
|
2711
3058
|
current = parentOf2(current);
|
|
2712
3059
|
}
|
|
@@ -2756,23 +3103,23 @@ var classDecoratorKind = (declaration, discovery) => {
|
|
|
2756
3103
|
};
|
|
2757
3104
|
|
|
2758
3105
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.ts
|
|
2759
|
-
import { dirname as
|
|
3106
|
+
import { dirname as dirname8, resolve as resolve4 } from "node:path";
|
|
2760
3107
|
import {
|
|
2761
|
-
isIdentifier as
|
|
3108
|
+
isIdentifier as isIdentifier6,
|
|
2762
3109
|
isNumericLiteral as isNumericLiteral2,
|
|
2763
3110
|
isPropertyAccessExpression as isPropertyAccessExpression2,
|
|
2764
3111
|
isPropertyAssignment as isPropertyAssignment4,
|
|
2765
|
-
isStringLiteralLike as
|
|
3112
|
+
isStringLiteralLike as isStringLiteralLike6
|
|
2766
3113
|
} from "typescript";
|
|
2767
3114
|
var stringValue = (node, discovery) => {
|
|
2768
3115
|
if (!node) return null;
|
|
2769
|
-
const isStringLiteral =
|
|
3116
|
+
const isStringLiteral = isStringLiteralLike6(node);
|
|
2770
3117
|
if (isStringLiteral) return node.text;
|
|
2771
|
-
const isIdentifierNode =
|
|
3118
|
+
const isIdentifierNode = isIdentifier6(node);
|
|
2772
3119
|
const isPropertyAccessNode = isPropertyAccessExpression2(node);
|
|
2773
3120
|
if (isIdentifierNode || isPropertyAccessNode) {
|
|
2774
3121
|
const symbol = discovery.checker.getSymbolAtLocation(
|
|
2775
|
-
|
|
3122
|
+
isIdentifier6(node) ? node : node.name
|
|
2776
3123
|
);
|
|
2777
3124
|
if (symbol) {
|
|
2778
3125
|
resolveAlias(symbol, discovery);
|
|
@@ -2785,8 +3132,8 @@ var metadataProperty = (metadata, name) => {
|
|
|
2785
3132
|
for (const property of metadata.properties) {
|
|
2786
3133
|
const isAssignment = isPropertyAssignment4(property);
|
|
2787
3134
|
if (!isAssignment) continue;
|
|
2788
|
-
const isIdentifierName =
|
|
2789
|
-
const isStringName =
|
|
3135
|
+
const isIdentifierName = isIdentifier6(property.name);
|
|
3136
|
+
const isStringName = isStringLiteralLike6(property.name);
|
|
2790
3137
|
const isNumericName = isNumericLiteral2(property.name);
|
|
2791
3138
|
const isLiteralName = isIdentifierName || isStringName || isNumericName;
|
|
2792
3139
|
const isPropertyNamed = isLiteralName && property.name.text === name;
|
|
@@ -2806,7 +3153,7 @@ var templateOf = (metadata, fileName, discovery) => {
|
|
|
2806
3153
|
if (url) {
|
|
2807
3154
|
const text2 = stringValue(url, discovery);
|
|
2808
3155
|
if (text2 === null) return void 0;
|
|
2809
|
-
const externalFileName = resolve4(
|
|
3156
|
+
const externalFileName = resolve4(dirname8(fileName), text2);
|
|
2810
3157
|
const externalTemplate = {
|
|
2811
3158
|
fileName: externalFileName,
|
|
2812
3159
|
kind: "external"
|
|
@@ -2825,14 +3172,14 @@ var exportAsOf = (metadata, discovery) => {
|
|
|
2825
3172
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-component-scope.ts
|
|
2826
3173
|
var booleanValue = (node) => {
|
|
2827
3174
|
if (!node) return void 0;
|
|
2828
|
-
if (node.kind ===
|
|
2829
|
-
if (node.kind ===
|
|
3175
|
+
if (node.kind === SyntaxKind5.TrueKeyword) return true;
|
|
3176
|
+
if (node.kind === SyntaxKind5.FalseKeyword) return false;
|
|
2830
3177
|
return void 0;
|
|
2831
3178
|
};
|
|
2832
3179
|
var classesOf = (symbol, discovery) => {
|
|
2833
3180
|
const resolved = resolveAlias(symbol, discovery);
|
|
2834
3181
|
const declarations = resolved.declarations ?? [];
|
|
2835
|
-
return declarations.filter(
|
|
3182
|
+
return declarations.filter(isClassLike3);
|
|
2836
3183
|
};
|
|
2837
3184
|
var scopedClasses = (classes, discovery) => {
|
|
2838
3185
|
const scoped = [];
|
|
@@ -2846,7 +3193,7 @@ var scopedClasses = (classes, discovery) => {
|
|
|
2846
3193
|
return scoped;
|
|
2847
3194
|
};
|
|
2848
3195
|
var importedClasses = (element, discovery) => {
|
|
2849
|
-
const isIdentifierElement =
|
|
3196
|
+
const isIdentifierElement = isIdentifier7(element);
|
|
2850
3197
|
const isPropertyAccessElement = isPropertyAccessExpression3(element);
|
|
2851
3198
|
if (!isIdentifierElement && !isPropertyAccessElement) return null;
|
|
2852
3199
|
const target = isIdentifierElement ? element : element.name;
|
|
@@ -2915,7 +3262,7 @@ var decoratedClass = (declaration, call, discovery) => {
|
|
|
2915
3262
|
const bareDiscovery = { ...base2, valid: !component };
|
|
2916
3263
|
return bareDiscovery;
|
|
2917
3264
|
}
|
|
2918
|
-
const isMetadataObject =
|
|
3265
|
+
const isMetadataObject = isObjectLiteralExpression6(metadata);
|
|
2919
3266
|
if (!isMetadataObject) {
|
|
2920
3267
|
const invalidDiscovery = { ...base2, valid: false };
|
|
2921
3268
|
return invalidDiscovery;
|
|
@@ -2937,7 +3284,7 @@ var angularClasses = (sourceFile, checker) => {
|
|
|
2937
3284
|
const classes = [];
|
|
2938
3285
|
const discovery = { checker, dependencies: /* @__PURE__ */ new Set() };
|
|
2939
3286
|
const visit = (node) => {
|
|
2940
|
-
const isClass =
|
|
3287
|
+
const isClass = isClassLike4(node);
|
|
2941
3288
|
if (isClass) {
|
|
2942
3289
|
const found = angularClass(node, discovery);
|
|
2943
3290
|
if (found) {
|
|
@@ -2975,38 +3322,51 @@ var indexableSourceFiles = (program) => {
|
|
|
2975
3322
|
const sourceFiles = program.getSourceFiles();
|
|
2976
3323
|
return sourceFiles.filter((sourceFile) => isIndexable(program, sourceFile));
|
|
2977
3324
|
};
|
|
2978
|
-
var
|
|
2979
|
-
const
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3325
|
+
var adjustCounts = (counts, keys, delta) => {
|
|
3326
|
+
for (const key2 of keys) {
|
|
3327
|
+
const current = counts.get(key2) ?? 0;
|
|
3328
|
+
const count = current + delta;
|
|
3329
|
+
if (count > 0) {
|
|
3330
|
+
counts.set(key2, count);
|
|
3331
|
+
} else {
|
|
3332
|
+
counts.delete(key2);
|
|
3333
|
+
}
|
|
2986
3334
|
}
|
|
2987
|
-
|
|
2988
|
-
|
|
3335
|
+
};
|
|
3336
|
+
var removeEntry = (index, fileName) => {
|
|
3337
|
+
const entry = index.entries.get(fileName);
|
|
3338
|
+
if (!entry) return;
|
|
3339
|
+
index.entries.delete(fileName);
|
|
3340
|
+
adjustCounts(index.declarationCounts, entry.declarations, -1);
|
|
3341
|
+
adjustCounts(index.fallbackNameCounts, entry.fallbackNames, -1);
|
|
3342
|
+
};
|
|
3343
|
+
var addEntry = (index, entry) => {
|
|
3344
|
+
removeEntry(index, entry.sourceFile.fileName);
|
|
3345
|
+
index.entries.set(entry.sourceFile.fileName, entry);
|
|
3346
|
+
adjustCounts(index.declarationCounts, entry.declarations, 1);
|
|
3347
|
+
adjustCounts(index.fallbackNameCounts, entry.fallbackNames, 1);
|
|
2989
3348
|
};
|
|
2990
3349
|
var dropEntries = (index, stale) => {
|
|
2991
3350
|
for (const [fileName, entry] of index.entries) {
|
|
2992
3351
|
const isStale = stale(entry);
|
|
2993
|
-
if (isStale)
|
|
2994
|
-
index.entries.delete(fileName);
|
|
2995
|
-
}
|
|
3352
|
+
if (isStale) removeEntry(index, fileName);
|
|
2996
3353
|
}
|
|
2997
3354
|
};
|
|
2998
|
-
var
|
|
2999
|
-
|
|
3000
|
-
|
|
3355
|
+
var currentSourceFiles = (program) => {
|
|
3356
|
+
return new Set(program.getSourceFiles());
|
|
3357
|
+
};
|
|
3358
|
+
var isReplaced = (sourceFile, dependencies, current) => {
|
|
3359
|
+
const isCurrent = current.has(sourceFile);
|
|
3360
|
+
if (!isCurrent) return true;
|
|
3001
3361
|
for (const dependency of dependencies) {
|
|
3002
|
-
const
|
|
3003
|
-
if (
|
|
3362
|
+
const isDependencyCurrent = current.has(dependency);
|
|
3363
|
+
if (!isDependencyCurrent) return true;
|
|
3004
3364
|
}
|
|
3005
3365
|
return false;
|
|
3006
3366
|
};
|
|
3007
|
-
var dropReplacedEntries = (index,
|
|
3367
|
+
var dropReplacedEntries = (index, current) => {
|
|
3008
3368
|
const isEntryReplaced = (entry) => {
|
|
3009
|
-
return isReplaced(entry.sourceFile, entry.dependencies,
|
|
3369
|
+
return isReplaced(entry.sourceFile, entry.dependencies, current);
|
|
3010
3370
|
};
|
|
3011
3371
|
dropEntries(index, isEntryReplaced);
|
|
3012
3372
|
};
|
|
@@ -3015,7 +3375,7 @@ var dropEntriesMentioning = (index, names) => {
|
|
|
3015
3375
|
if (index.entries.size === 0) return;
|
|
3016
3376
|
const nameList = [...names];
|
|
3017
3377
|
const mentionsName = (entry) => {
|
|
3018
|
-
return nameList.some((name) => entry.
|
|
3378
|
+
return nameList.some((name) => entry.mentionedNames.has(name));
|
|
3019
3379
|
};
|
|
3020
3380
|
dropEntries(index, mentionsName);
|
|
3021
3381
|
};
|
|
@@ -3030,16 +3390,19 @@ var templateVersionChecker = () => {
|
|
|
3030
3390
|
return current;
|
|
3031
3391
|
};
|
|
3032
3392
|
};
|
|
3393
|
+
var hasStaleTemplate = (entry) => {
|
|
3394
|
+
return !entry.templateVersions.every(templateFileIsCurrent);
|
|
3395
|
+
};
|
|
3033
3396
|
var dropStaleTemplateEntries = (index, force) => {
|
|
3034
3397
|
const now = performance.now();
|
|
3035
3398
|
const sinceLastCheck = now - index.templateCheckedAt;
|
|
3036
3399
|
const isThrottled = !force && sinceLastCheck < index.templateCheckDuration * 100;
|
|
3037
3400
|
if (isThrottled) return;
|
|
3038
3401
|
const isCurrent = templateVersionChecker();
|
|
3039
|
-
const
|
|
3402
|
+
const isStale = (entry) => {
|
|
3040
3403
|
return !entry.templateVersions.every(isCurrent);
|
|
3041
3404
|
};
|
|
3042
|
-
dropEntries(index,
|
|
3405
|
+
dropEntries(index, isStale);
|
|
3043
3406
|
index.templateCheckedAt = now;
|
|
3044
3407
|
index.templateCheckDuration = performance.now() - now;
|
|
3045
3408
|
};
|
|
@@ -3049,9 +3412,9 @@ import {
|
|
|
3049
3412
|
canHaveDecorators as canHaveDecorators4,
|
|
3050
3413
|
forEachChild as forEachChild4,
|
|
3051
3414
|
getDecorators as getDecorators4,
|
|
3052
|
-
isClassLike as
|
|
3053
|
-
isIdentifier as
|
|
3054
|
-
isStringLiteralLike as
|
|
3415
|
+
isClassLike as isClassLike5,
|
|
3416
|
+
isIdentifier as isIdentifier8,
|
|
3417
|
+
isStringLiteralLike as isStringLiteralLike7
|
|
3055
3418
|
} from "typescript";
|
|
3056
3419
|
var isDecoratedClass = (node) => {
|
|
3057
3420
|
const isDecoratable = canHaveDecorators4(node);
|
|
@@ -3061,14 +3424,14 @@ var isDecoratedClass = (node) => {
|
|
|
3061
3424
|
return decoratorCount > 0;
|
|
3062
3425
|
};
|
|
3063
3426
|
var addMemberNames = (node, names) => {
|
|
3064
|
-
const isClass =
|
|
3427
|
+
const isClass = isClassLike5(node);
|
|
3065
3428
|
if (!isClass) return;
|
|
3066
3429
|
const isDecorated = isDecoratedClass(node);
|
|
3067
3430
|
if (!isDecorated) return;
|
|
3068
3431
|
for (const member of node.members) {
|
|
3069
3432
|
if (!member.name) continue;
|
|
3070
|
-
const isIdentifierName =
|
|
3071
|
-
const isStringName =
|
|
3433
|
+
const isIdentifierName = isIdentifier8(member.name);
|
|
3434
|
+
const isStringName = isStringLiteralLike7(member.name);
|
|
3072
3435
|
const isNamedMember = isIdentifierName || isStringName;
|
|
3073
3436
|
if (isNamedMember) {
|
|
3074
3437
|
names.add(member.name.text);
|
|
@@ -3086,19 +3449,19 @@ var collectCandidateNames = (sourceFile) => {
|
|
|
3086
3449
|
};
|
|
3087
3450
|
|
|
3088
3451
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.ts
|
|
3089
|
-
var dropReplacedClasses = (index,
|
|
3090
|
-
|
|
3452
|
+
var dropReplacedClasses = (index, current) => {
|
|
3453
|
+
const dropped = [];
|
|
3091
3454
|
for (const [fileName, fileClasses] of index.classes) {
|
|
3092
3455
|
const replaced = isReplaced(
|
|
3093
3456
|
fileClasses.sourceFile,
|
|
3094
3457
|
fileClasses.dependencies,
|
|
3095
|
-
|
|
3458
|
+
current
|
|
3096
3459
|
);
|
|
3097
3460
|
if (!replaced) continue;
|
|
3098
3461
|
index.classes.delete(fileName);
|
|
3099
|
-
|
|
3462
|
+
dropped.push(fileClasses);
|
|
3100
3463
|
}
|
|
3101
|
-
return
|
|
3464
|
+
return dropped;
|
|
3102
3465
|
};
|
|
3103
3466
|
var addCandidateNames = (index, candidateNames, newNames) => {
|
|
3104
3467
|
for (const name of candidateNames) {
|
|
@@ -3112,27 +3475,30 @@ var indexFileClasses = (index, sourceFile, checker, newNames) => {
|
|
|
3112
3475
|
const candidateNames = collectCandidateNames(sourceFile);
|
|
3113
3476
|
addCandidateNames(index, candidateNames, newNames);
|
|
3114
3477
|
const { classes, dependencies } = angularClasses(sourceFile, checker());
|
|
3478
|
+
const shape = directiveShape(classes);
|
|
3115
3479
|
const fileClasses = {
|
|
3116
3480
|
candidateNames,
|
|
3117
3481
|
classes,
|
|
3118
3482
|
dependencies,
|
|
3483
|
+
shape,
|
|
3119
3484
|
sourceFile
|
|
3120
3485
|
};
|
|
3121
3486
|
index.classes.set(sourceFile.fileName, fileClasses);
|
|
3122
|
-
index
|
|
3487
|
+
removeEntry(index, sourceFile.fileName);
|
|
3488
|
+
return fileClasses;
|
|
3123
3489
|
};
|
|
3124
3490
|
var indexNewClasses = (index, current, checker, newNames) => {
|
|
3125
|
-
|
|
3126
|
-
for (const
|
|
3127
|
-
const isIndexed = index.classes.has(fileName);
|
|
3491
|
+
const added = [];
|
|
3492
|
+
for (const sourceFile of current) {
|
|
3493
|
+
const isIndexed = index.classes.has(sourceFile.fileName);
|
|
3128
3494
|
if (isIndexed) continue;
|
|
3129
|
-
indexFileClasses(index, sourceFile, checker, newNames);
|
|
3130
|
-
changed = true;
|
|
3495
|
+
added.push(indexFileClasses(index, sourceFile, checker, newNames));
|
|
3131
3496
|
}
|
|
3132
|
-
return
|
|
3497
|
+
return added;
|
|
3133
3498
|
};
|
|
3134
3499
|
var rebuildDirectives = (index) => {
|
|
3135
|
-
const
|
|
3500
|
+
const classesValues = index.classes.values();
|
|
3501
|
+
const fileClasses = [...classesValues];
|
|
3136
3502
|
const classes = fileClasses.flatMap((entry) => entry.classes);
|
|
3137
3503
|
const shape = directiveShape(classes);
|
|
3138
3504
|
index.directives = buildDirectiveIndex(classes);
|
|
@@ -3140,12 +3506,26 @@ var rebuildDirectives = (index) => {
|
|
|
3140
3506
|
index.directiveShape = shape;
|
|
3141
3507
|
dropEntries(index, (entry) => entry.usedDirectiveIndex);
|
|
3142
3508
|
};
|
|
3143
|
-
var
|
|
3509
|
+
var shapesOf = (files) => {
|
|
3510
|
+
return files.map((file) => file.shape).sort().join("\n");
|
|
3511
|
+
};
|
|
3512
|
+
var repointDirectives = (index, dropped, added) => {
|
|
3513
|
+
const previous = dropped.flatMap((file) => file.classes);
|
|
3514
|
+
const next = added.flatMap((file) => file.classes);
|
|
3515
|
+
replaceDeclarations(index.directives, previous, next);
|
|
3516
|
+
};
|
|
3517
|
+
var reconcileClasses = (index, indexable, current, checker) => {
|
|
3144
3518
|
const newNames = /* @__PURE__ */ new Set();
|
|
3145
|
-
const
|
|
3146
|
-
const
|
|
3147
|
-
const
|
|
3148
|
-
if (
|
|
3519
|
+
const dropped = dropReplacedClasses(index, current);
|
|
3520
|
+
const added = indexNewClasses(index, indexable, checker, newNames);
|
|
3521
|
+
const isUntouched = dropped.length === 0 && added.length === 0;
|
|
3522
|
+
if (isUntouched) return newNames;
|
|
3523
|
+
const droppedShape = shapesOf(dropped);
|
|
3524
|
+
const addedShape = shapesOf(added);
|
|
3525
|
+
const isSameShape = droppedShape === addedShape;
|
|
3526
|
+
if (isSameShape) {
|
|
3527
|
+
repointDirectives(index, dropped, added);
|
|
3528
|
+
} else {
|
|
3149
3529
|
rebuildDirectives(index);
|
|
3150
3530
|
}
|
|
3151
3531
|
return newNames;
|
|
@@ -3160,36 +3540,59 @@ var indexMissingEntries = (index, sourceFiles, checker) => {
|
|
|
3160
3540
|
for (const sourceFile of sourceFiles) {
|
|
3161
3541
|
const isEntryIndexed = index.entries.has(sourceFile.fileName);
|
|
3162
3542
|
if (isEntryIndexed) continue;
|
|
3163
|
-
|
|
3164
|
-
index.entries.set(sourceFile.fileName, entry);
|
|
3543
|
+
addEntry(index, computeEntry(index, sourceFile, checker()));
|
|
3165
3544
|
}
|
|
3166
3545
|
};
|
|
3167
3546
|
var reindexProgram = (index, program, checker) => {
|
|
3168
|
-
const
|
|
3169
|
-
|
|
3170
|
-
|
|
3547
|
+
const indexable = indexableSourceFiles(program);
|
|
3548
|
+
const current = currentSourceFiles(program);
|
|
3549
|
+
dropReplacedEntries(index, current);
|
|
3550
|
+
const newNames = reconcileClasses(index, indexable, current, checker);
|
|
3171
3551
|
dropEntriesMentioning(index, newNames);
|
|
3172
3552
|
index.program = program;
|
|
3173
|
-
index
|
|
3174
|
-
|
|
3175
|
-
indexMissingEntries(index, maps.current.values(), checker);
|
|
3553
|
+
dropStaleTemplateEntries(index, false);
|
|
3554
|
+
indexMissingEntries(index, indexable, checker);
|
|
3176
3555
|
};
|
|
3177
3556
|
var refreshTemplateEntries = (index, program, checker) => {
|
|
3178
3557
|
const entryCount = index.entries.size;
|
|
3179
3558
|
dropStaleTemplateEntries(index, false);
|
|
3180
3559
|
const isUnchanged = index.entries.size === entryCount;
|
|
3181
3560
|
if (isUnchanged) return;
|
|
3182
|
-
index.usage = void 0;
|
|
3183
3561
|
indexMissingEntries(index, indexableSourceFiles(program), checker);
|
|
3184
3562
|
};
|
|
3185
|
-
var
|
|
3563
|
+
var isLocalEntry = (entry, sourceFile, directory) => {
|
|
3564
|
+
const isOwn = entry.sourceFile === sourceFile;
|
|
3565
|
+
if (isOwn) return true;
|
|
3566
|
+
const isNearby = (version) => {
|
|
3567
|
+
return version.directory === directory;
|
|
3568
|
+
};
|
|
3569
|
+
return entry.templateVersions.some(isNearby);
|
|
3570
|
+
};
|
|
3571
|
+
var refreshLocalEntries = (index, program, fileName, checker) => {
|
|
3572
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
3573
|
+
if (!sourceFile) return;
|
|
3574
|
+
const directory = dirname9(normalize2(sourceFile.fileName));
|
|
3575
|
+
const stale = [];
|
|
3576
|
+
for (const entry of index.entries.values()) {
|
|
3577
|
+
if (entry.templateVersions.length === 0) continue;
|
|
3578
|
+
const isLocal = isLocalEntry(entry, sourceFile, directory);
|
|
3579
|
+
if (!isLocal) continue;
|
|
3580
|
+
const isStale = hasStaleTemplate(entry);
|
|
3581
|
+
if (isStale) stale.push(entry);
|
|
3582
|
+
}
|
|
3583
|
+
for (const entry of stale) {
|
|
3584
|
+
addEntry(index, computeEntry(index, entry.sourceFile, checker()));
|
|
3585
|
+
}
|
|
3586
|
+
};
|
|
3587
|
+
var reconcile = (index, program, fileName) => {
|
|
3186
3588
|
const checker = lazyChecker(program);
|
|
3187
3589
|
const isNewProgram = index.program !== program;
|
|
3188
3590
|
if (isNewProgram) {
|
|
3189
3591
|
reindexProgram(index, program, checker);
|
|
3190
|
-
|
|
3592
|
+
} else {
|
|
3593
|
+
refreshTemplateEntries(index, program, checker);
|
|
3191
3594
|
}
|
|
3192
|
-
|
|
3595
|
+
refreshLocalEntries(index, program, fileName, checker);
|
|
3193
3596
|
};
|
|
3194
3597
|
|
|
3195
3598
|
// packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.ts
|
|
@@ -3198,46 +3601,36 @@ var memberName = (node) => {
|
|
|
3198
3601
|
const isMember = isClassElement(node);
|
|
3199
3602
|
if (!isMember) return null;
|
|
3200
3603
|
if (!node.name) return null;
|
|
3201
|
-
const isIdentifierName =
|
|
3202
|
-
const isStringName =
|
|
3604
|
+
const isIdentifierName = isIdentifier9(node.name);
|
|
3605
|
+
const isStringName = isStringLiteralLike8(node.name);
|
|
3203
3606
|
const isNamedMember = isIdentifierName || isStringName;
|
|
3204
3607
|
if (!isNamedMember) return null;
|
|
3205
3608
|
return node.name.text;
|
|
3206
3609
|
};
|
|
3207
3610
|
var usageOf = (index) => {
|
|
3208
|
-
|
|
3209
|
-
const
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
for (const name of entry.fallbackNames) {
|
|
3216
|
-
fallbackNames.add(name);
|
|
3217
|
-
}
|
|
3218
|
-
}
|
|
3219
|
-
index.usage = {
|
|
3220
|
-
has: (node) => {
|
|
3221
|
-
const hasDeclaration = declarations.has(node);
|
|
3222
|
-
if (hasDeclaration) return true;
|
|
3223
|
-
if (fallbackNames.size === 0) return false;
|
|
3224
|
-
const name = memberName(node);
|
|
3225
|
-
return name !== null && fallbackNames.has(name);
|
|
3226
|
-
}
|
|
3611
|
+
const { declarationCounts, fallbackNameCounts } = index;
|
|
3612
|
+
const has = (node) => {
|
|
3613
|
+
const hasDeclaration = declarationCounts.has(node);
|
|
3614
|
+
if (hasDeclaration) return true;
|
|
3615
|
+
if (fallbackNameCounts.size === 0) return false;
|
|
3616
|
+
const name = memberName(node);
|
|
3617
|
+
return name !== null && fallbackNameCounts.has(name);
|
|
3227
3618
|
};
|
|
3228
|
-
|
|
3619
|
+
const usage = { has };
|
|
3620
|
+
return usage;
|
|
3229
3621
|
};
|
|
3230
3622
|
var createIndex = () => {
|
|
3231
3623
|
const emptyIndex = {
|
|
3232
3624
|
candidateNames: /* @__PURE__ */ new Set(),
|
|
3233
3625
|
classes: /* @__PURE__ */ new Map(),
|
|
3626
|
+
declarationCounts: /* @__PURE__ */ new Map(),
|
|
3234
3627
|
directives: buildDirectiveIndex([]),
|
|
3235
3628
|
directiveShape: "",
|
|
3236
3629
|
entries: /* @__PURE__ */ new Map(),
|
|
3630
|
+
fallbackNameCounts: /* @__PURE__ */ new Map(),
|
|
3237
3631
|
program: null,
|
|
3238
3632
|
templateCheckDuration: 0,
|
|
3239
|
-
templateCheckedAt: 0
|
|
3240
|
-
usage: void 0
|
|
3633
|
+
templateCheckedAt: 0
|
|
3241
3634
|
};
|
|
3242
3635
|
return emptyIndex;
|
|
3243
3636
|
};
|
|
@@ -3245,7 +3638,7 @@ var projectUsageIsCurrent = (program) => {
|
|
|
3245
3638
|
const configFilePath = program.getCompilerOptions()["configFilePath"];
|
|
3246
3639
|
return typeof configFilePath === "string" && indexes.get(configFilePath)?.program === program;
|
|
3247
3640
|
};
|
|
3248
|
-
var projectUsage = (program) => {
|
|
3641
|
+
var projectUsage = (program, fileName) => {
|
|
3249
3642
|
const configFilePath = program.getCompilerOptions()["configFilePath"];
|
|
3250
3643
|
if (typeof configFilePath !== "string") return null;
|
|
3251
3644
|
let index = indexes.get(configFilePath);
|
|
@@ -3254,7 +3647,7 @@ var projectUsage = (program) => {
|
|
|
3254
3647
|
indexes.set(configFilePath, index);
|
|
3255
3648
|
}
|
|
3256
3649
|
try {
|
|
3257
|
-
reconcile(index, program);
|
|
3650
|
+
reconcile(index, program, fileName);
|
|
3258
3651
|
return usageOf(index);
|
|
3259
3652
|
} catch {
|
|
3260
3653
|
indexes.delete(configFilePath);
|
|
@@ -3313,12 +3706,12 @@ var projectParserServices = (context, analysis) => {
|
|
|
3313
3706
|
);
|
|
3314
3707
|
}
|
|
3315
3708
|
};
|
|
3316
|
-
var projectMemberUsedFor = (parserServices) => {
|
|
3709
|
+
var projectMemberUsedFor = (parserServices, fileName) => {
|
|
3317
3710
|
if (parserServices === void 0) return void 0;
|
|
3318
3711
|
let usage;
|
|
3319
3712
|
const memberUsed = (node) => {
|
|
3320
3713
|
if (usage === void 0) {
|
|
3321
|
-
usage = projectUsage(parserServices.program);
|
|
3714
|
+
usage = projectUsage(parserServices.program, fileName);
|
|
3322
3715
|
}
|
|
3323
3716
|
return usage?.has(parserServices.esTreeNodeToTSNodeMap.get(node)) ?? true;
|
|
3324
3717
|
};
|
|
@@ -3350,7 +3743,7 @@ var no_unused_angular_instance_fields_default = createRule2({
|
|
|
3350
3743
|
dynamicClasses,
|
|
3351
3744
|
imports,
|
|
3352
3745
|
projectIndexed,
|
|
3353
|
-
projectMemberUsed: projectMemberUsedFor(parserServices)
|
|
3746
|
+
projectMemberUsed: projectMemberUsedFor(parserServices, context.filename)
|
|
3354
3747
|
};
|
|
3355
3748
|
const readListeners = classReadVisitor(classes, stack, dynamicClasses);
|
|
3356
3749
|
const listeners = {
|
|
@@ -3389,6 +3782,10 @@ var angular = defineConfig2([
|
|
|
3389
3782
|
},
|
|
3390
3783
|
...inlineTemplates,
|
|
3391
3784
|
rules: {
|
|
3785
|
+
// Component and directive members nothing reads (class, template, host)
|
|
3786
|
+
// are dead.
|
|
3787
|
+
// Bad: private unused = 1; read nowhere
|
|
3788
|
+
// Good: delete it, or read it in the template
|
|
3392
3789
|
"lint-suite-angular/no-unused-instance-fields": [
|
|
3393
3790
|
"error",
|
|
3394
3791
|
{ analysis: "project" }
|
|
@@ -3445,8 +3842,7 @@ var baseLimits = defineConfig3([
|
|
|
3445
3842
|
"**/*.ts",
|
|
3446
3843
|
"**/*.tsx",
|
|
3447
3844
|
"**/*.cts",
|
|
3448
|
-
"**/*.mts"
|
|
3449
|
-
"**/*.html"
|
|
3845
|
+
"**/*.mts"
|
|
3450
3846
|
],
|
|
3451
3847
|
rules: {
|
|
3452
3848
|
"max-lines": [
|
|
@@ -3948,7 +4344,7 @@ var typescriptConsistency = defineConfig14([
|
|
|
3948
4344
|
rules: {
|
|
3949
4345
|
"@typescript-eslint/consistent-type-assertions": [
|
|
3950
4346
|
"error",
|
|
3951
|
-
{ assertionStyle: "
|
|
4347
|
+
{ assertionStyle: "never" }
|
|
3952
4348
|
],
|
|
3953
4349
|
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
|
|
3954
4350
|
"@typescript-eslint/consistent-type-imports": [
|
|
@@ -4114,71 +4510,286 @@ var typescriptRecommended = defineConfig17([
|
|
|
4114
4510
|
// packages/lint-suite/src/lib/typescript-safety.ts
|
|
4115
4511
|
import { defineConfig as defineConfig18 } from "eslint/config";
|
|
4116
4512
|
|
|
4117
|
-
// packages/lint-suite/src/lib/rules/
|
|
4118
|
-
import { ESLintUtils as ESLintUtils3, TSESTree as TSESTree10 } from "@typescript-eslint/utils";
|
|
4119
|
-
|
|
4120
|
-
// packages/lint-suite/src/lib/rules/explicit-accessibility/common/explicit-accessibility.const.ts
|
|
4121
|
-
var accessibilities = [
|
|
4122
|
-
"public",
|
|
4123
|
-
"private",
|
|
4124
|
-
"protected"
|
|
4125
|
-
];
|
|
4513
|
+
// packages/lint-suite/src/lib/rules/arrow-body-fits-line/arrow-body-fits-line.ts
|
|
4514
|
+
import { ASTUtils, ESLintUtils as ESLintUtils3, TSESTree as TSESTree10 } from "@typescript-eslint/utils";
|
|
4126
4515
|
var docs3 = {
|
|
4127
|
-
description: "Require
|
|
4516
|
+
description: "Require an expression-bodied arrow function to fit on one line"
|
|
4128
4517
|
};
|
|
4129
4518
|
var messages3 = {
|
|
4130
|
-
|
|
4131
|
-
setAccessibility: "Add the '{{ accessibility }}' modifier."
|
|
4132
|
-
};
|
|
4133
|
-
var defaultAccessibilitySchema = {
|
|
4134
|
-
type: "string",
|
|
4135
|
-
enum: ["public", "private", "protected", "none"],
|
|
4136
|
-
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."
|
|
4137
|
-
};
|
|
4138
|
-
var properties3 = {
|
|
4139
|
-
defaultAccessibility: defaultAccessibilitySchema
|
|
4140
|
-
};
|
|
4141
|
-
var optionsSchema3 = {
|
|
4142
|
-
type: "object",
|
|
4143
|
-
properties: properties3,
|
|
4144
|
-
additionalProperties: false
|
|
4519
|
+
arrowBodyWrapped: "Expression body of this arrow function spans multiple lines; wrap it in a block with an explicit return."
|
|
4145
4520
|
};
|
|
4146
|
-
var schema3 = [
|
|
4521
|
+
var schema3 = [];
|
|
4147
4522
|
var meta3 = {
|
|
4148
4523
|
type: "suggestion",
|
|
4149
4524
|
docs: docs3,
|
|
4150
4525
|
fixable: "code",
|
|
4151
|
-
hasSuggestions: true,
|
|
4152
4526
|
schema: schema3,
|
|
4153
4527
|
messages: messages3
|
|
4154
4528
|
};
|
|
4155
|
-
var defaultOptions3 = [{ defaultAccessibility: "public" }];
|
|
4156
|
-
|
|
4157
|
-
// packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
|
|
4158
4529
|
var createRule3 = ESLintUtils3.RuleCreator(
|
|
4159
|
-
() => "https://github.com/F0rty-Tw0/lint-suite#
|
|
4530
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#arrow-body-fits-line"
|
|
4160
4531
|
);
|
|
4161
|
-
var
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
}
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4532
|
+
var isMultiLine = (body) => body.loc.start.line !== body.loc.end.line;
|
|
4533
|
+
var arrowIndent = (node, sourceCode) => {
|
|
4534
|
+
const line = sourceCode.lines[node.loc.start.line - 1] ?? "";
|
|
4535
|
+
const leadingWhitespace = /^\s*/u.exec(line);
|
|
4536
|
+
return leadingWhitespace ? leadingWhitespace[0] : "";
|
|
4537
|
+
};
|
|
4538
|
+
var wrappedBody = (indent, bodyText) => {
|
|
4539
|
+
const innerIndent = `${indent} `;
|
|
4540
|
+
return `{
|
|
4541
|
+
${innerIndent}return ${bodyText};
|
|
4542
|
+
${indent}}`;
|
|
4543
|
+
};
|
|
4544
|
+
var replacementRange = (node, sourceCode) => {
|
|
4545
|
+
const isParenthesized = ASTUtils.isParenthesized(node.body, sourceCode);
|
|
4546
|
+
if (!isParenthesized) return node.body.range;
|
|
4547
|
+
const openParen = sourceCode.getTokenBefore(node.body);
|
|
4548
|
+
const closeParen = sourceCode.getTokenAfter(node.body);
|
|
4549
|
+
if (!openParen || !closeParen) return node.body.range;
|
|
4550
|
+
return [openParen.range[0], closeParen.range[1]];
|
|
4551
|
+
};
|
|
4552
|
+
var arrow_body_fits_line_default = createRule3({
|
|
4553
|
+
name: "arrow-body-fits-line",
|
|
4554
|
+
meta: meta3,
|
|
4555
|
+
defaultOptions: [],
|
|
4556
|
+
create(context) {
|
|
4557
|
+
const { sourceCode } = context;
|
|
4558
|
+
const listeners = {
|
|
4559
|
+
"ArrowFunctionExpression[expression=true]"(node) {
|
|
4560
|
+
const isObjectBody = node.body.type === TSESTree10.AST_NODE_TYPES.ObjectExpression;
|
|
4561
|
+
if (isObjectBody) return;
|
|
4562
|
+
const isMultiLineBody = isMultiLine(node.body);
|
|
4563
|
+
if (!isMultiLineBody) return;
|
|
4564
|
+
const indent = arrowIndent(node, sourceCode);
|
|
4565
|
+
const bodyText = sourceCode.getText(node.body);
|
|
4566
|
+
const range = replacementRange(node, sourceCode);
|
|
4567
|
+
const fix = (fixer) => fixer.replaceTextRange(range, wrappedBody(indent, bodyText));
|
|
4568
|
+
const report3 = {
|
|
4569
|
+
node,
|
|
4570
|
+
messageId: "arrowBodyWrapped",
|
|
4571
|
+
fix
|
|
4572
|
+
};
|
|
4573
|
+
context.report(report3);
|
|
4574
|
+
}
|
|
4575
|
+
};
|
|
4576
|
+
return listeners;
|
|
4176
4577
|
}
|
|
4177
|
-
|
|
4578
|
+
});
|
|
4579
|
+
|
|
4580
|
+
// packages/lint-suite/src/lib/rules/chain-fits-line/chain-fits-line.ts
|
|
4581
|
+
import { ESLintUtils as ESLintUtils4, TSESTree as TSESTree11 } from "@typescript-eslint/utils";
|
|
4582
|
+
var docs4 = {
|
|
4583
|
+
description: "Require every call in a member call chain to keep its property on the same line"
|
|
4178
4584
|
};
|
|
4179
|
-
var
|
|
4180
|
-
|
|
4181
|
-
|
|
4585
|
+
var messages4 = {
|
|
4586
|
+
chainWrapped: "Call chain is wrapped across lines; keep every call on the same line or name intermediate steps."
|
|
4587
|
+
};
|
|
4588
|
+
var meta4 = {
|
|
4589
|
+
type: "suggestion",
|
|
4590
|
+
docs: docs4,
|
|
4591
|
+
schema: [],
|
|
4592
|
+
messages: messages4
|
|
4593
|
+
};
|
|
4594
|
+
var createRule4 = ESLintUtils4.RuleCreator(
|
|
4595
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#chain-fits-line"
|
|
4596
|
+
);
|
|
4597
|
+
var isMemberCall = (node) => {
|
|
4598
|
+
if (node.type !== TSESTree11.AST_NODE_TYPES.CallExpression) return false;
|
|
4599
|
+
return node.callee.type === TSESTree11.AST_NODE_TYPES.MemberExpression;
|
|
4600
|
+
};
|
|
4601
|
+
var spinePropertyLines = (node) => {
|
|
4602
|
+
const lines = [node.callee.property.loc.start.line];
|
|
4603
|
+
let current = node.callee.object;
|
|
4604
|
+
for (; ; ) {
|
|
4605
|
+
if (isMemberCall(current)) {
|
|
4606
|
+
lines.push(current.callee.property.loc.start.line);
|
|
4607
|
+
current = current.callee.object;
|
|
4608
|
+
continue;
|
|
4609
|
+
}
|
|
4610
|
+
if (current.type === TSESTree11.AST_NODE_TYPES.MemberExpression) {
|
|
4611
|
+
current = current.object;
|
|
4612
|
+
continue;
|
|
4613
|
+
}
|
|
4614
|
+
break;
|
|
4615
|
+
}
|
|
4616
|
+
return lines;
|
|
4617
|
+
};
|
|
4618
|
+
var chain_fits_line_default = createRule4({
|
|
4619
|
+
name: "chain-fits-line",
|
|
4620
|
+
meta: meta4,
|
|
4621
|
+
defaultOptions: [],
|
|
4622
|
+
create(context) {
|
|
4623
|
+
const listeners = {
|
|
4624
|
+
CallExpression(node) {
|
|
4625
|
+
if (!isMemberCall(node)) return;
|
|
4626
|
+
const isOutermost = node.parent.type !== TSESTree11.AST_NODE_TYPES.MemberExpression;
|
|
4627
|
+
if (!isOutermost) return;
|
|
4628
|
+
const lines = spinePropertyLines(node);
|
|
4629
|
+
if (lines.length < 2) return;
|
|
4630
|
+
const isWrapped = new Set(lines).size > 1;
|
|
4631
|
+
if (!isWrapped) return;
|
|
4632
|
+
const report3 = {
|
|
4633
|
+
node,
|
|
4634
|
+
messageId: "chainWrapped"
|
|
4635
|
+
};
|
|
4636
|
+
context.report(report3);
|
|
4637
|
+
}
|
|
4638
|
+
};
|
|
4639
|
+
return listeners;
|
|
4640
|
+
}
|
|
4641
|
+
});
|
|
4642
|
+
|
|
4643
|
+
// packages/lint-suite/src/lib/rules/chain-receiver-is-name/chain-receiver-is-name.ts
|
|
4644
|
+
import { ESLintUtils as ESLintUtils5, TSESTree as TSESTree12 } from "@typescript-eslint/utils";
|
|
4645
|
+
|
|
4646
|
+
// packages/lint-suite/src/lib/rules/utils/indent-of.util.ts
|
|
4647
|
+
var indentOf = (node, sourceCode) => {
|
|
4648
|
+
const line = sourceCode.lines[node.loc.start.line - 1] ?? "";
|
|
4649
|
+
const [leading] = /^[ \t]*/.exec(line) ?? [""];
|
|
4650
|
+
return leading;
|
|
4651
|
+
};
|
|
4652
|
+
|
|
4653
|
+
// packages/lint-suite/src/lib/rules/chain-receiver-is-name/chain-receiver-is-name.ts
|
|
4654
|
+
var docs5 = {
|
|
4655
|
+
description: "Require a call chain to start from a name, not an inline expression"
|
|
4656
|
+
};
|
|
4657
|
+
var messages5 = {
|
|
4658
|
+
chainReceiver: "Call chain starts from an inline expression; extract it to a named constant first.",
|
|
4659
|
+
extractReceiver: "Extract the receiver to a 'value' constant."
|
|
4660
|
+
};
|
|
4661
|
+
var meta5 = {
|
|
4662
|
+
type: "suggestion",
|
|
4663
|
+
docs: docs5,
|
|
4664
|
+
hasSuggestions: true,
|
|
4665
|
+
schema: [],
|
|
4666
|
+
messages: messages5
|
|
4667
|
+
};
|
|
4668
|
+
var createRule5 = ESLintUtils5.RuleCreator(
|
|
4669
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#chain-receiver-is-name"
|
|
4670
|
+
);
|
|
4671
|
+
var UNNAMED_RECEIVER_TYPES = /* @__PURE__ */ new Set([
|
|
4672
|
+
TSESTree12.AST_NODE_TYPES.LogicalExpression,
|
|
4673
|
+
TSESTree12.AST_NODE_TYPES.ConditionalExpression,
|
|
4674
|
+
TSESTree12.AST_NODE_TYPES.ObjectExpression,
|
|
4675
|
+
TSESTree12.AST_NODE_TYPES.ArrayExpression,
|
|
4676
|
+
TSESTree12.AST_NODE_TYPES.AwaitExpression,
|
|
4677
|
+
TSESTree12.AST_NODE_TYPES.BinaryExpression,
|
|
4678
|
+
TSESTree12.AST_NODE_TYPES.TemplateLiteral
|
|
4679
|
+
]);
|
|
4680
|
+
var enclosingStatement = (node) => {
|
|
4681
|
+
let current = node;
|
|
4682
|
+
while (current.parent.type !== TSESTree12.AST_NODE_TYPES.BlockStatement && current.parent.type !== TSESTree12.AST_NODE_TYPES.Program) {
|
|
4683
|
+
current = current.parent;
|
|
4684
|
+
}
|
|
4685
|
+
return current;
|
|
4686
|
+
};
|
|
4687
|
+
var suggestionOf = (node, sourceCode) => {
|
|
4688
|
+
const statement = enclosingStatement(node);
|
|
4689
|
+
const indent = indentOf(statement, sourceCode);
|
|
4690
|
+
const objectText = sourceCode.getText(node.object);
|
|
4691
|
+
const declaration = `const value = ${objectText};
|
|
4692
|
+
${indent}`;
|
|
4693
|
+
const fix = (fixer) => {
|
|
4694
|
+
const hoisted = fixer.insertTextBefore(statement, declaration);
|
|
4695
|
+
const replaced = fixer.replaceText(node.object, "value");
|
|
4696
|
+
const fixes = [hoisted, replaced];
|
|
4697
|
+
return fixes;
|
|
4698
|
+
};
|
|
4699
|
+
const suggestion = {
|
|
4700
|
+
messageId: "extractReceiver",
|
|
4701
|
+
fix
|
|
4702
|
+
};
|
|
4703
|
+
return suggestion;
|
|
4704
|
+
};
|
|
4705
|
+
var chain_receiver_is_name_default = createRule5({
|
|
4706
|
+
name: "chain-receiver-is-name",
|
|
4707
|
+
meta: meta5,
|
|
4708
|
+
defaultOptions: [],
|
|
4709
|
+
create(context) {
|
|
4710
|
+
const { sourceCode } = context;
|
|
4711
|
+
const listeners = {
|
|
4712
|
+
MemberExpression(node) {
|
|
4713
|
+
const isUnnamedReceiver = UNNAMED_RECEIVER_TYPES.has(node.object.type);
|
|
4714
|
+
if (!isUnnamedReceiver) return;
|
|
4715
|
+
const suggest = [suggestionOf(node, sourceCode)];
|
|
4716
|
+
const report3 = {
|
|
4717
|
+
node,
|
|
4718
|
+
messageId: "chainReceiver",
|
|
4719
|
+
suggest
|
|
4720
|
+
};
|
|
4721
|
+
context.report(report3);
|
|
4722
|
+
}
|
|
4723
|
+
};
|
|
4724
|
+
return listeners;
|
|
4725
|
+
}
|
|
4726
|
+
});
|
|
4727
|
+
|
|
4728
|
+
// packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
|
|
4729
|
+
import { ESLintUtils as ESLintUtils6, TSESTree as TSESTree13 } from "@typescript-eslint/utils";
|
|
4730
|
+
|
|
4731
|
+
// packages/lint-suite/src/lib/rules/explicit-accessibility/common/explicit-accessibility.const.ts
|
|
4732
|
+
var accessibilities = [
|
|
4733
|
+
"public",
|
|
4734
|
+
"private",
|
|
4735
|
+
"protected"
|
|
4736
|
+
];
|
|
4737
|
+
var docs6 = {
|
|
4738
|
+
description: "Require explicit accessibility modifiers on class members"
|
|
4739
|
+
};
|
|
4740
|
+
var messages6 = {
|
|
4741
|
+
missingAccessibility: "Class member '{{ name }}' is missing an explicit accessibility modifier (public/private/protected).",
|
|
4742
|
+
setAccessibility: "Add the '{{ accessibility }}' modifier."
|
|
4743
|
+
};
|
|
4744
|
+
var defaultAccessibilitySchema = {
|
|
4745
|
+
type: "string",
|
|
4746
|
+
enum: ["public", "private", "protected", "none"],
|
|
4747
|
+
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."
|
|
4748
|
+
};
|
|
4749
|
+
var properties3 = {
|
|
4750
|
+
defaultAccessibility: defaultAccessibilitySchema
|
|
4751
|
+
};
|
|
4752
|
+
var optionsSchema3 = {
|
|
4753
|
+
type: "object",
|
|
4754
|
+
properties: properties3,
|
|
4755
|
+
additionalProperties: false
|
|
4756
|
+
};
|
|
4757
|
+
var schema4 = [optionsSchema3];
|
|
4758
|
+
var meta6 = {
|
|
4759
|
+
type: "suggestion",
|
|
4760
|
+
docs: docs6,
|
|
4761
|
+
fixable: "code",
|
|
4762
|
+
hasSuggestions: true,
|
|
4763
|
+
schema: schema4,
|
|
4764
|
+
messages: messages6
|
|
4765
|
+
};
|
|
4766
|
+
var defaultOptions3 = [{ defaultAccessibility: "public" }];
|
|
4767
|
+
|
|
4768
|
+
// packages/lint-suite/src/lib/rules/explicit-accessibility/explicit-accessibility.ts
|
|
4769
|
+
var createRule6 = ESLintUtils6.RuleCreator(
|
|
4770
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#explicit-accessibility"
|
|
4771
|
+
);
|
|
4772
|
+
var isPrivateMember = (node) => {
|
|
4773
|
+
if (node.type === TSESTree13.AST_NODE_TYPES.TSParameterProperty) return false;
|
|
4774
|
+
return node.key.type === TSESTree13.AST_NODE_TYPES.PrivateIdentifier;
|
|
4775
|
+
};
|
|
4776
|
+
var isConstructor = (node) => {
|
|
4777
|
+
if (node.type !== TSESTree13.AST_NODE_TYPES.MethodDefinition) return false;
|
|
4778
|
+
return node.kind === "constructor";
|
|
4779
|
+
};
|
|
4780
|
+
var reportTarget = (node) => {
|
|
4781
|
+
if (node.type !== TSESTree13.AST_NODE_TYPES.TSParameterProperty) {
|
|
4782
|
+
return node.key;
|
|
4783
|
+
}
|
|
4784
|
+
const { parameter } = node;
|
|
4785
|
+
if (parameter.type === TSESTree13.AST_NODE_TYPES.AssignmentPattern) {
|
|
4786
|
+
return parameter.left;
|
|
4787
|
+
}
|
|
4788
|
+
return parameter;
|
|
4789
|
+
};
|
|
4790
|
+
var memberName2 = (target, sourceCode) => {
|
|
4791
|
+
if (target.type === TSESTree13.AST_NODE_TYPES.Identifier) return target.name;
|
|
4792
|
+
return sourceCode.getText(target);
|
|
4182
4793
|
};
|
|
4183
4794
|
var modifierToken = (node, sourceCode) => {
|
|
4184
4795
|
const lastDecorator = node.decorators.at(-1);
|
|
@@ -4202,7 +4813,7 @@ var autoFixOf = (node, accessibility, sourceCode) => {
|
|
|
4202
4813
|
const autoFix = { fix };
|
|
4203
4814
|
return autoFix;
|
|
4204
4815
|
};
|
|
4205
|
-
var
|
|
4816
|
+
var suggestionOf2 = (node, accessibility, sourceCode) => {
|
|
4206
4817
|
const data = { accessibility };
|
|
4207
4818
|
const fix = insertModifier(node, accessibility, sourceCode);
|
|
4208
4819
|
const suggestion = {
|
|
@@ -4216,93 +4827,1602 @@ var suggestionsOf = (node, fixAccessibility, sourceCode) => {
|
|
|
4216
4827
|
const isOtherAccessibility = (accessibility) => {
|
|
4217
4828
|
return accessibility !== fixAccessibility;
|
|
4218
4829
|
};
|
|
4219
|
-
const
|
|
4220
|
-
return
|
|
4830
|
+
const suggestionFor2 = (accessibility) => {
|
|
4831
|
+
return suggestionOf2(node, accessibility, sourceCode);
|
|
4832
|
+
};
|
|
4833
|
+
return accessibilities.filter(isOtherAccessibility).map(suggestionFor2);
|
|
4834
|
+
};
|
|
4835
|
+
var explicit_accessibility_default = createRule6({
|
|
4836
|
+
name: "explicit-accessibility",
|
|
4837
|
+
meta: meta6,
|
|
4838
|
+
defaultOptions: defaultOptions3,
|
|
4839
|
+
create(context, [{ defaultAccessibility = "public" }]) {
|
|
4840
|
+
const { sourceCode } = context;
|
|
4841
|
+
const check = (node) => {
|
|
4842
|
+
const isPrivate = isPrivateMember(node);
|
|
4843
|
+
if (node.accessibility || isPrivate) return;
|
|
4844
|
+
const target = reportTarget(node);
|
|
4845
|
+
const isConstructorMember = isConstructor(node);
|
|
4846
|
+
const usesPublic = isConstructorMember && defaultAccessibility !== "none";
|
|
4847
|
+
const fixAccessibility = usesPublic ? "public" : defaultAccessibility;
|
|
4848
|
+
const autoFix = autoFixOf(node, fixAccessibility, sourceCode);
|
|
4849
|
+
const name = memberName2(target, sourceCode);
|
|
4850
|
+
const data = { name };
|
|
4851
|
+
const suggest = suggestionsOf(node, fixAccessibility, sourceCode);
|
|
4852
|
+
const report3 = {
|
|
4853
|
+
node: target,
|
|
4854
|
+
messageId: "missingAccessibility",
|
|
4855
|
+
data,
|
|
4856
|
+
...autoFix,
|
|
4857
|
+
suggest
|
|
4858
|
+
};
|
|
4859
|
+
context.report(report3);
|
|
4860
|
+
};
|
|
4861
|
+
const listeners = {
|
|
4862
|
+
AccessorProperty: check,
|
|
4863
|
+
MethodDefinition: check,
|
|
4864
|
+
PropertyDefinition: check,
|
|
4865
|
+
TSAbstractAccessorProperty: check,
|
|
4866
|
+
TSAbstractMethodDefinition: check,
|
|
4867
|
+
TSAbstractPropertyDefinition: check,
|
|
4868
|
+
TSParameterProperty: check
|
|
4869
|
+
};
|
|
4870
|
+
return listeners;
|
|
4871
|
+
}
|
|
4872
|
+
});
|
|
4873
|
+
|
|
4874
|
+
// packages/lint-suite/src/lib/rules/max-condition-operands/max-condition-operands.ts
|
|
4875
|
+
import { ESLintUtils as ESLintUtils7, TSESTree as TSESTree14 } from "@typescript-eslint/utils";
|
|
4876
|
+
var docs7 = {
|
|
4877
|
+
description: "Limit the number of operands in an if statement condition to keep it readable"
|
|
4878
|
+
};
|
|
4879
|
+
var messages7 = {
|
|
4880
|
+
tooManyOperands: "This condition has {{ count }} operands; extract it into a named const when it exceeds {{ max }}."
|
|
4881
|
+
};
|
|
4882
|
+
var maxSchema = { type: "integer", minimum: 1 };
|
|
4883
|
+
var properties4 = {
|
|
4884
|
+
max: maxSchema
|
|
4885
|
+
};
|
|
4886
|
+
var optionsSchema4 = {
|
|
4887
|
+
type: "object",
|
|
4888
|
+
properties: properties4,
|
|
4889
|
+
additionalProperties: false
|
|
4890
|
+
};
|
|
4891
|
+
var schema5 = [optionsSchema4];
|
|
4892
|
+
var meta7 = {
|
|
4893
|
+
type: "suggestion",
|
|
4894
|
+
docs: docs7,
|
|
4895
|
+
schema: schema5,
|
|
4896
|
+
messages: messages7
|
|
4897
|
+
};
|
|
4898
|
+
var createRule7 = ESLintUtils7.RuleCreator(
|
|
4899
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#max-condition-operands"
|
|
4900
|
+
);
|
|
4901
|
+
var countOperands = (node) => {
|
|
4902
|
+
if (node.type !== TSESTree14.AST_NODE_TYPES.LogicalExpression) return 1;
|
|
4903
|
+
return countOperands(node.left) + countOperands(node.right);
|
|
4904
|
+
};
|
|
4905
|
+
var defaultOptions4 = [{ max: 3 }];
|
|
4906
|
+
var max_condition_operands_default = createRule7({
|
|
4907
|
+
name: "max-condition-operands",
|
|
4908
|
+
meta: meta7,
|
|
4909
|
+
defaultOptions: defaultOptions4,
|
|
4910
|
+
create(context, [{ max }]) {
|
|
4911
|
+
const listeners = {
|
|
4912
|
+
IfStatement(node) {
|
|
4913
|
+
const count = countOperands(node.test);
|
|
4914
|
+
if (count <= max) return;
|
|
4915
|
+
const data = { count, max };
|
|
4916
|
+
const report3 = {
|
|
4917
|
+
node: node.test,
|
|
4918
|
+
messageId: "tooManyOperands",
|
|
4919
|
+
data
|
|
4920
|
+
};
|
|
4921
|
+
context.report(report3);
|
|
4922
|
+
}
|
|
4923
|
+
};
|
|
4924
|
+
return listeners;
|
|
4925
|
+
}
|
|
4926
|
+
});
|
|
4927
|
+
|
|
4928
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/no-call-in-condition.ts
|
|
4929
|
+
import { ESLintUtils as ESLintUtils8, TSESTree as TSESTree17 } from "@typescript-eslint/utils";
|
|
4930
|
+
|
|
4931
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/common/no-call-in-condition.const.ts
|
|
4932
|
+
var PREDICATE_PATTERNS = ["^(is|has)[A-Z]"];
|
|
4933
|
+
var docs8 = {
|
|
4934
|
+
description: "Disallow a function call inside an if condition or a boolean const that feeds one"
|
|
4935
|
+
};
|
|
4936
|
+
var messages8 = {
|
|
4937
|
+
callInCondition: "Call '{{ callee }}' decides inside a condition; assign it to a named const first.",
|
|
4938
|
+
hoistCall: "Assign the call to '{{ name }}' above the statement."
|
|
4939
|
+
};
|
|
4940
|
+
var patternSchema = { type: "string" };
|
|
4941
|
+
var allowPredicatesSchema = {
|
|
4942
|
+
type: "array",
|
|
4943
|
+
items: patternSchema,
|
|
4944
|
+
description: "Regular expression sources for callee names treated as type predicates when no TypeScript program is available."
|
|
4945
|
+
};
|
|
4946
|
+
var properties5 = {
|
|
4947
|
+
allowPredicates: allowPredicatesSchema
|
|
4948
|
+
};
|
|
4949
|
+
var optionsSchema5 = {
|
|
4950
|
+
type: "object",
|
|
4951
|
+
properties: properties5,
|
|
4952
|
+
additionalProperties: false
|
|
4953
|
+
};
|
|
4954
|
+
var schema6 = [optionsSchema5];
|
|
4955
|
+
var meta8 = {
|
|
4956
|
+
type: "suggestion",
|
|
4957
|
+
docs: docs8,
|
|
4958
|
+
hasSuggestions: true,
|
|
4959
|
+
schema: schema6,
|
|
4960
|
+
messages: messages8
|
|
4961
|
+
};
|
|
4962
|
+
var ruleDefaults3 = {
|
|
4963
|
+
allowPredicates: PREDICATE_PATTERNS
|
|
4964
|
+
};
|
|
4965
|
+
var defaultOptions5 = [ruleDefaults3];
|
|
4966
|
+
|
|
4967
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/utils/call-exemptions.util.ts
|
|
4968
|
+
import { ASTUtils as ASTUtils3, TSESTree as TSESTree16 } from "@typescript-eslint/utils";
|
|
4969
|
+
|
|
4970
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/utils/condition-calls.util.ts
|
|
4971
|
+
import { ASTUtils as ASTUtils2, TSESTree as TSESTree15 } from "@typescript-eslint/utils";
|
|
4972
|
+
var collectParts = (node, parts) => {
|
|
4973
|
+
if (node.type === TSESTree15.AST_NODE_TYPES.CallExpression) {
|
|
4974
|
+
parts.calls.push(node);
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4977
|
+
if (node.type === TSESTree15.AST_NODE_TYPES.Identifier) {
|
|
4978
|
+
parts.identifiers.push(node);
|
|
4979
|
+
return;
|
|
4980
|
+
}
|
|
4981
|
+
if (node.type === TSESTree15.AST_NODE_TYPES.UnaryExpression) {
|
|
4982
|
+
collectParts(node.argument, parts);
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4985
|
+
const isLogical = node.type === TSESTree15.AST_NODE_TYPES.LogicalExpression;
|
|
4986
|
+
const isBinary = node.type === TSESTree15.AST_NODE_TYPES.BinaryExpression;
|
|
4987
|
+
if (!isLogical && !isBinary) return;
|
|
4988
|
+
collectParts(node.left, parts);
|
|
4989
|
+
collectParts(node.right, parts);
|
|
4990
|
+
};
|
|
4991
|
+
var conditionParts = (node) => {
|
|
4992
|
+
const parts = { calls: [], identifiers: [] };
|
|
4993
|
+
collectParts(node, parts);
|
|
4994
|
+
return parts;
|
|
4995
|
+
};
|
|
4996
|
+
var calleeName = (callee) => {
|
|
4997
|
+
if (callee.type === TSESTree15.AST_NODE_TYPES.Identifier) return callee.name;
|
|
4998
|
+
if (callee.type !== TSESTree15.AST_NODE_TYPES.MemberExpression) {
|
|
4999
|
+
return void 0;
|
|
5000
|
+
}
|
|
5001
|
+
const { property } = callee;
|
|
5002
|
+
if (property.type !== TSESTree15.AST_NODE_TYPES.Identifier) return void 0;
|
|
5003
|
+
return property.name;
|
|
5004
|
+
};
|
|
5005
|
+
var constFeed = (identifier, scope) => {
|
|
5006
|
+
const variable = ASTUtils2.findVariable(scope, identifier);
|
|
5007
|
+
if (variable?.defs.length !== 1) return void 0;
|
|
5008
|
+
const definition = variable.defs.at(0);
|
|
5009
|
+
if (!definition) return void 0;
|
|
5010
|
+
const declaration = definition.parent;
|
|
5011
|
+
if (declaration?.type !== TSESTree15.AST_NODE_TYPES.VariableDeclaration) {
|
|
5012
|
+
return void 0;
|
|
5013
|
+
}
|
|
5014
|
+
if (declaration.kind !== "const") return void 0;
|
|
5015
|
+
const { node } = definition;
|
|
5016
|
+
if (node.type !== TSESTree15.AST_NODE_TYPES.VariableDeclarator) {
|
|
5017
|
+
return void 0;
|
|
5018
|
+
}
|
|
5019
|
+
const { init } = node;
|
|
5020
|
+
if (!init) return void 0;
|
|
5021
|
+
if (init.type === TSESTree15.AST_NODE_TYPES.CallExpression) return void 0;
|
|
5022
|
+
const feed = { init, statement: declaration };
|
|
5023
|
+
return feed;
|
|
5024
|
+
};
|
|
5025
|
+
|
|
5026
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/utils/call-exemptions.util.ts
|
|
5027
|
+
var PREDICATE_HOLDERS = [
|
|
5028
|
+
TSESTree16.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
5029
|
+
TSESTree16.AST_NODE_TYPES.FunctionDeclaration,
|
|
5030
|
+
TSESTree16.AST_NODE_TYPES.FunctionExpression,
|
|
5031
|
+
TSESTree16.AST_NODE_TYPES.TSDeclareFunction
|
|
5032
|
+
];
|
|
5033
|
+
var isPredicateHolder = ASTUtils3.isNodeOfTypes(PREDICATE_HOLDERS);
|
|
5034
|
+
var hasPredicateReturn = (node) => {
|
|
5035
|
+
if (!isPredicateHolder(node)) return false;
|
|
5036
|
+
const returned = node.returnType?.typeAnnotation.type;
|
|
5037
|
+
return returned === TSESTree16.AST_NODE_TYPES.TSTypePredicate;
|
|
5038
|
+
};
|
|
5039
|
+
var declaredFunction = (definition) => {
|
|
5040
|
+
const { node } = definition;
|
|
5041
|
+
if (node.type !== TSESTree16.AST_NODE_TYPES.VariableDeclarator) return node;
|
|
5042
|
+
return node.init ?? void 0;
|
|
5043
|
+
};
|
|
5044
|
+
var isThisSignalRead = (call) => {
|
|
5045
|
+
if (call.arguments.length > 0) return false;
|
|
5046
|
+
const { callee } = call;
|
|
5047
|
+
if (callee.type !== TSESTree16.AST_NODE_TYPES.MemberExpression) return false;
|
|
5048
|
+
if (callee.computed) return false;
|
|
5049
|
+
return callee.object.type === TSESTree16.AST_NODE_TYPES.ThisExpression;
|
|
5050
|
+
};
|
|
5051
|
+
var isScopePredicate = (callee, scope) => {
|
|
5052
|
+
if (callee.type !== TSESTree16.AST_NODE_TYPES.Identifier) return false;
|
|
5053
|
+
const variable = ASTUtils3.findVariable(scope, callee);
|
|
5054
|
+
const definition = variable?.defs.at(0);
|
|
5055
|
+
if (!definition) return false;
|
|
5056
|
+
const declaration = declaredFunction(definition);
|
|
5057
|
+
if (!declaration) return false;
|
|
5058
|
+
return hasPredicateReturn(declaration);
|
|
5059
|
+
};
|
|
5060
|
+
var isCheckerPredicate = (callee, services) => {
|
|
5061
|
+
const checker = services.program.getTypeChecker();
|
|
5062
|
+
const calleeType = services.getTypeAtLocation(callee);
|
|
5063
|
+
const signatures = calleeType.getCallSignatures();
|
|
5064
|
+
const isPredicateSignature = (signature) => {
|
|
5065
|
+
const predicate = checker.getTypePredicateOfSignature(signature);
|
|
5066
|
+
return predicate !== void 0;
|
|
5067
|
+
};
|
|
5068
|
+
return signatures.some(isPredicateSignature);
|
|
5069
|
+
};
|
|
5070
|
+
var isAllowedName = (callee, allowed) => {
|
|
5071
|
+
const name = calleeName(callee);
|
|
5072
|
+
if (name === void 0) return false;
|
|
5073
|
+
return allowed.some((pattern) => pattern.test(name));
|
|
5074
|
+
};
|
|
5075
|
+
var isExemptCall = (call, exemptions) => {
|
|
5076
|
+
const isSignalRead = isThisSignalRead(call);
|
|
5077
|
+
if (isSignalRead) return true;
|
|
5078
|
+
const { allowed, scope, services } = exemptions;
|
|
5079
|
+
const { callee } = call;
|
|
5080
|
+
const isDeclaredPredicate = isScopePredicate(callee, scope);
|
|
5081
|
+
if (isDeclaredPredicate) return true;
|
|
5082
|
+
if (services) return isCheckerPredicate(callee, services);
|
|
5083
|
+
return isAllowedName(callee, allowed);
|
|
5084
|
+
};
|
|
5085
|
+
|
|
5086
|
+
// packages/lint-suite/src/lib/rules/no-call-in-condition/no-call-in-condition.ts
|
|
5087
|
+
var createRule8 = ESLintUtils8.RuleCreator(
|
|
5088
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-call-in-condition"
|
|
5089
|
+
);
|
|
5090
|
+
var HOISTABLE_PARENTS = /* @__PURE__ */ new Set([
|
|
5091
|
+
TSESTree17.AST_NODE_TYPES.BlockStatement,
|
|
5092
|
+
TSESTree17.AST_NODE_TYPES.Program,
|
|
5093
|
+
TSESTree17.AST_NODE_TYPES.StaticBlock,
|
|
5094
|
+
TSESTree17.AST_NODE_TYPES.SwitchCase,
|
|
5095
|
+
TSESTree17.AST_NODE_TYPES.TSModuleBlock
|
|
5096
|
+
]);
|
|
5097
|
+
var INDENT_PATTERN = /^[\t ]*/u;
|
|
5098
|
+
var typedServices = (context) => {
|
|
5099
|
+
const { parserServices } = context.sourceCode;
|
|
5100
|
+
if (!parserServices?.program) return void 0;
|
|
5101
|
+
return ESLintUtils8.getParserServices(context);
|
|
5102
|
+
};
|
|
5103
|
+
var statementIndent = (statement, sourceCode) => {
|
|
5104
|
+
const line = sourceCode.lines[statement.loc.start.line - 1] ?? "";
|
|
5105
|
+
const indent = INDENT_PATTERN.exec(line)?.[0];
|
|
5106
|
+
return indent ?? "";
|
|
5107
|
+
};
|
|
5108
|
+
var suggestionsOf2 = (call, statement, sourceCode) => {
|
|
5109
|
+
const empty = [];
|
|
5110
|
+
const isHoistable = HOISTABLE_PARENTS.has(statement.parent.type);
|
|
5111
|
+
if (!isHoistable) return empty;
|
|
5112
|
+
const name = calleeName(call.callee);
|
|
5113
|
+
if (name === void 0) return empty;
|
|
5114
|
+
const constName = `${name}Result`;
|
|
5115
|
+
const callText = sourceCode.getText(call);
|
|
5116
|
+
const indent = statementIndent(statement, sourceCode);
|
|
5117
|
+
const declaration = `const ${constName} = ${callText};
|
|
5118
|
+
${indent}`;
|
|
5119
|
+
const fix = (fixer) => {
|
|
5120
|
+
const hoisted = fixer.insertTextBefore(statement, declaration);
|
|
5121
|
+
const replaced = fixer.replaceText(call, constName);
|
|
5122
|
+
const fixes = [hoisted, replaced];
|
|
5123
|
+
return fixes;
|
|
5124
|
+
};
|
|
5125
|
+
const data = { name: constName };
|
|
5126
|
+
const suggestion = {
|
|
5127
|
+
messageId: "hoistCall",
|
|
5128
|
+
data,
|
|
5129
|
+
fix
|
|
5130
|
+
};
|
|
5131
|
+
const suggestions = [suggestion];
|
|
5132
|
+
return suggestions;
|
|
5133
|
+
};
|
|
5134
|
+
var reportOf = (call, statement, sourceCode) => {
|
|
5135
|
+
const suggest = suggestionsOf2(call, statement, sourceCode);
|
|
5136
|
+
const callee = sourceCode.getText(call.callee);
|
|
5137
|
+
const data = { callee };
|
|
5138
|
+
const report3 = {
|
|
5139
|
+
node: call,
|
|
5140
|
+
messageId: "callInCondition",
|
|
5141
|
+
data,
|
|
5142
|
+
suggest
|
|
5143
|
+
};
|
|
5144
|
+
return report3;
|
|
5145
|
+
};
|
|
5146
|
+
var no_call_in_condition_default = createRule8({
|
|
5147
|
+
name: "no-call-in-condition",
|
|
5148
|
+
meta: meta8,
|
|
5149
|
+
defaultOptions: defaultOptions5,
|
|
5150
|
+
create(context, [{ allowPredicates = PREDICATE_PATTERNS }]) {
|
|
5151
|
+
const { sourceCode } = context;
|
|
5152
|
+
const services = typedServices(context);
|
|
5153
|
+
const allowed = allowPredicates.map(toRegExp);
|
|
5154
|
+
const reported = /* @__PURE__ */ new Set();
|
|
5155
|
+
const reportCalls = (calls, statement, exemptions) => {
|
|
5156
|
+
for (const call of calls) {
|
|
5157
|
+
const isReported = reported.has(call);
|
|
5158
|
+
if (isReported) continue;
|
|
5159
|
+
const isExempt = isExemptCall(call, exemptions);
|
|
5160
|
+
if (isExempt) continue;
|
|
5161
|
+
reported.add(call);
|
|
5162
|
+
const report3 = reportOf(call, statement, sourceCode);
|
|
5163
|
+
context.report(report3);
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5166
|
+
const listeners = {
|
|
5167
|
+
IfStatement(node) {
|
|
5168
|
+
const { calls, identifiers } = conditionParts(node.test);
|
|
5169
|
+
const isEmpty = calls.length === 0 && identifiers.length === 0;
|
|
5170
|
+
if (isEmpty) return;
|
|
5171
|
+
const scope = sourceCode.getScope(node);
|
|
5172
|
+
const exemptions = { allowed, scope, services };
|
|
5173
|
+
reportCalls(calls, node, exemptions);
|
|
5174
|
+
for (const identifier of identifiers) {
|
|
5175
|
+
const feed = constFeed(identifier, scope);
|
|
5176
|
+
if (feed) {
|
|
5177
|
+
const fed = conditionParts(feed.init);
|
|
5178
|
+
reportCalls(fed.calls, feed.statement, exemptions);
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
}
|
|
5182
|
+
};
|
|
5183
|
+
return listeners;
|
|
5184
|
+
}
|
|
5185
|
+
});
|
|
5186
|
+
|
|
5187
|
+
// packages/lint-suite/src/lib/rules/no-grouped-condition/no-grouped-condition.ts
|
|
5188
|
+
import { ESLintUtils as ESLintUtils9, TSESTree as TSESTree18 } from "@typescript-eslint/utils";
|
|
5189
|
+
var docs9 = {
|
|
5190
|
+
description: "Require a mixed-operator group inside a logical condition to be hoisted into a named const"
|
|
5191
|
+
};
|
|
5192
|
+
var messages9 = {
|
|
5193
|
+
groupedCondition: "This group mixes a different operator than its enclosing condition; hoist it into a named const.",
|
|
5194
|
+
hoistGroup: "Extract the group into a named const."
|
|
5195
|
+
};
|
|
5196
|
+
var meta9 = {
|
|
5197
|
+
type: "suggestion",
|
|
5198
|
+
docs: docs9,
|
|
5199
|
+
hasSuggestions: true,
|
|
5200
|
+
schema: [],
|
|
5201
|
+
messages: messages9
|
|
5202
|
+
};
|
|
5203
|
+
var createRule9 = ESLintUtils9.RuleCreator(
|
|
5204
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-grouped-condition"
|
|
5205
|
+
);
|
|
5206
|
+
var GROUP_NAME = "isGroup";
|
|
5207
|
+
var outermostLogical = (node) => {
|
|
5208
|
+
let current = node;
|
|
5209
|
+
while (current.parent.type === TSESTree18.AST_NODE_TYPES.LogicalExpression) {
|
|
5210
|
+
current = current.parent;
|
|
5211
|
+
}
|
|
5212
|
+
return current;
|
|
5213
|
+
};
|
|
5214
|
+
var reportRootOf = (node) => {
|
|
5215
|
+
const outermost = outermostLogical(node);
|
|
5216
|
+
const { parent } = outermost;
|
|
5217
|
+
if (parent.type === TSESTree18.AST_NODE_TYPES.IfStatement) {
|
|
5218
|
+
if (parent.test !== outermost) return void 0;
|
|
5219
|
+
const reportRoot2 = { statement: parent };
|
|
5220
|
+
return reportRoot2;
|
|
5221
|
+
}
|
|
5222
|
+
if (parent.type !== TSESTree18.AST_NODE_TYPES.VariableDeclarator) {
|
|
5223
|
+
return void 0;
|
|
5224
|
+
}
|
|
5225
|
+
const isConstInit = parent.init === outermost && parent.parent.kind === "const";
|
|
5226
|
+
if (!isConstInit) return void 0;
|
|
5227
|
+
const reportRoot = { statement: parent.parent };
|
|
5228
|
+
return reportRoot;
|
|
5229
|
+
};
|
|
5230
|
+
var suggestionFor = (node, statement, sourceCode) => {
|
|
5231
|
+
const groupText = sourceCode.getText(node);
|
|
5232
|
+
const line = sourceCode.lines[statement.loc.start.line - 1] ?? "";
|
|
5233
|
+
const indent = line.slice(0, statement.loc.start.column);
|
|
5234
|
+
const declaration = `const ${GROUP_NAME} = ${groupText};
|
|
5235
|
+
${indent}`;
|
|
5236
|
+
const fix = (fixer) => {
|
|
5237
|
+
const hoisted = fixer.insertTextBefore(statement, declaration);
|
|
5238
|
+
const replaced = fixer.replaceText(node, GROUP_NAME);
|
|
5239
|
+
const fixes = [hoisted, replaced];
|
|
5240
|
+
return fixes;
|
|
5241
|
+
};
|
|
5242
|
+
const suggestion = {
|
|
5243
|
+
messageId: "hoistGroup",
|
|
5244
|
+
fix
|
|
5245
|
+
};
|
|
5246
|
+
return suggestion;
|
|
5247
|
+
};
|
|
5248
|
+
var no_grouped_condition_default = createRule9({
|
|
5249
|
+
name: "no-grouped-condition",
|
|
5250
|
+
meta: meta9,
|
|
5251
|
+
defaultOptions: [],
|
|
5252
|
+
create(context) {
|
|
5253
|
+
const { sourceCode } = context;
|
|
5254
|
+
const listeners = {
|
|
5255
|
+
"LogicalExpression > LogicalExpression"(node) {
|
|
5256
|
+
const { parent } = node;
|
|
5257
|
+
if (parent.type !== TSESTree18.AST_NODE_TYPES.LogicalExpression) return;
|
|
5258
|
+
const hasSameOperator = node.operator === parent.operator;
|
|
5259
|
+
if (hasSameOperator) return;
|
|
5260
|
+
const reportRoot = reportRootOf(node);
|
|
5261
|
+
if (!reportRoot) return;
|
|
5262
|
+
const suggestion = suggestionFor(
|
|
5263
|
+
node,
|
|
5264
|
+
reportRoot.statement,
|
|
5265
|
+
sourceCode
|
|
5266
|
+
);
|
|
5267
|
+
const report3 = {
|
|
5268
|
+
node,
|
|
5269
|
+
messageId: "groupedCondition",
|
|
5270
|
+
suggest: [suggestion]
|
|
5271
|
+
};
|
|
5272
|
+
context.report(report3);
|
|
5273
|
+
}
|
|
5274
|
+
};
|
|
5275
|
+
return listeners;
|
|
5276
|
+
}
|
|
5277
|
+
});
|
|
5278
|
+
|
|
5279
|
+
// packages/lint-suite/src/lib/rules/no-inline-object-types/no-inline-object-types.ts
|
|
5280
|
+
import { ESLintUtils as ESLintUtils10, TSESTree as TSESTree19 } from "@typescript-eslint/utils";
|
|
5281
|
+
var docs10 = {
|
|
5282
|
+
description: "Require every object type literal to be the body of a named type alias"
|
|
5283
|
+
};
|
|
5284
|
+
var messages10 = {
|
|
5285
|
+
inlineObjectType: "Object type literal must be the body of a named type alias."
|
|
5286
|
+
};
|
|
5287
|
+
var meta10 = {
|
|
5288
|
+
type: "suggestion",
|
|
5289
|
+
docs: docs10,
|
|
5290
|
+
schema: [],
|
|
5291
|
+
messages: messages10
|
|
5292
|
+
};
|
|
5293
|
+
var createRule10 = ESLintUtils10.RuleCreator(
|
|
5294
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-inline-object-types"
|
|
5295
|
+
);
|
|
5296
|
+
var no_inline_object_types_default = createRule10({
|
|
5297
|
+
name: "no-inline-object-types",
|
|
5298
|
+
meta: meta10,
|
|
5299
|
+
defaultOptions: [],
|
|
5300
|
+
create(context) {
|
|
5301
|
+
const listeners = {
|
|
5302
|
+
TSTypeLiteral(node) {
|
|
5303
|
+
const isAliasBody = node.parent.type === TSESTree19.AST_NODE_TYPES.TSTypeAliasDeclaration;
|
|
5304
|
+
if (isAliasBody) return;
|
|
5305
|
+
const report3 = {
|
|
5306
|
+
node,
|
|
5307
|
+
messageId: "inlineObjectType"
|
|
5308
|
+
};
|
|
5309
|
+
context.report(report3);
|
|
5310
|
+
}
|
|
5311
|
+
};
|
|
5312
|
+
return listeners;
|
|
5313
|
+
}
|
|
5314
|
+
});
|
|
5315
|
+
|
|
5316
|
+
// packages/lint-suite/src/lib/rules/no-inline-return-object/no-inline-return-object.ts
|
|
5317
|
+
import { ESLintUtils as ESLintUtils11, TSESTree as TSESTree20 } from "@typescript-eslint/utils";
|
|
5318
|
+
var docs11 = {
|
|
5319
|
+
description: "Require an inline returned object literal to be named as a constant first"
|
|
5320
|
+
};
|
|
5321
|
+
var messages11 = {
|
|
5322
|
+
inlineReturnObject: "Object literal is returned inline; name it as a constant first."
|
|
5323
|
+
};
|
|
5324
|
+
var meta11 = {
|
|
5325
|
+
type: "suggestion",
|
|
5326
|
+
docs: docs11,
|
|
5327
|
+
hasSuggestions: true,
|
|
5328
|
+
schema: [],
|
|
5329
|
+
messages: messages11
|
|
5330
|
+
};
|
|
5331
|
+
var createRule11 = ESLintUtils11.RuleCreator(
|
|
5332
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-inline-return-object"
|
|
5333
|
+
);
|
|
5334
|
+
var wrappingRange = (objectExpression, sourceCode) => {
|
|
5335
|
+
const before = sourceCode.getTokenBefore(objectExpression);
|
|
5336
|
+
const after = sourceCode.getTokenAfter(objectExpression);
|
|
5337
|
+
const isWrapped = before?.value === "(" && after?.value === ")";
|
|
5338
|
+
if (!isWrapped) return objectExpression.range;
|
|
5339
|
+
return [before.range[0], after.range[1]];
|
|
5340
|
+
};
|
|
5341
|
+
var returnSuggestion = (node, objectExpression, sourceCode) => {
|
|
5342
|
+
const indent = indentOf(node, sourceCode);
|
|
5343
|
+
const objectText = sourceCode.getText(objectExpression);
|
|
5344
|
+
const fix = (fixer) => {
|
|
5345
|
+
const declaration = fixer.insertTextBefore(
|
|
5346
|
+
node,
|
|
5347
|
+
`const result = ${objectText};
|
|
5348
|
+
|
|
5349
|
+
${indent}`
|
|
5350
|
+
);
|
|
5351
|
+
const replaced = fixer.replaceText(objectExpression, "result");
|
|
5352
|
+
const fixes = [declaration, replaced];
|
|
5353
|
+
return fixes;
|
|
5354
|
+
};
|
|
5355
|
+
const suggestion = {
|
|
5356
|
+
messageId: "inlineReturnObject",
|
|
5357
|
+
fix
|
|
5358
|
+
};
|
|
5359
|
+
return suggestion;
|
|
5360
|
+
};
|
|
5361
|
+
var arrowSuggestion = (node, objectExpression, sourceCode) => {
|
|
5362
|
+
const indent = indentOf(node, sourceCode);
|
|
5363
|
+
const bodyIndent = `${indent} `;
|
|
5364
|
+
const objectText = sourceCode.getText(objectExpression);
|
|
5365
|
+
const replacement = `{
|
|
5366
|
+
${bodyIndent}const result = ${objectText};
|
|
5367
|
+
|
|
5368
|
+
${bodyIndent}return result;
|
|
5369
|
+
${indent}}`;
|
|
5370
|
+
const range = wrappingRange(objectExpression, sourceCode);
|
|
5371
|
+
const fix = (fixer) => fixer.replaceTextRange(range, replacement);
|
|
5372
|
+
const suggestion = {
|
|
5373
|
+
messageId: "inlineReturnObject",
|
|
5374
|
+
fix
|
|
5375
|
+
};
|
|
5376
|
+
return suggestion;
|
|
5377
|
+
};
|
|
5378
|
+
var no_inline_return_object_default = createRule11({
|
|
5379
|
+
name: "no-inline-return-object",
|
|
5380
|
+
meta: meta11,
|
|
5381
|
+
defaultOptions: [],
|
|
5382
|
+
create(context) {
|
|
5383
|
+
const { sourceCode } = context;
|
|
5384
|
+
const listeners = {
|
|
5385
|
+
ReturnStatement(node) {
|
|
5386
|
+
if (node.argument?.type !== TSESTree20.AST_NODE_TYPES.ObjectExpression) {
|
|
5387
|
+
return;
|
|
5388
|
+
}
|
|
5389
|
+
const objectExpression = node.argument;
|
|
5390
|
+
const suggest = [returnSuggestion(node, objectExpression, sourceCode)];
|
|
5391
|
+
const report3 = {
|
|
5392
|
+
node,
|
|
5393
|
+
messageId: "inlineReturnObject",
|
|
5394
|
+
suggest
|
|
5395
|
+
};
|
|
5396
|
+
context.report(report3);
|
|
5397
|
+
},
|
|
5398
|
+
ArrowFunctionExpression(node) {
|
|
5399
|
+
if (!node.expression) return;
|
|
5400
|
+
if (node.body.type !== TSESTree20.AST_NODE_TYPES.ObjectExpression) return;
|
|
5401
|
+
const objectExpression = node.body;
|
|
5402
|
+
const suggest = [arrowSuggestion(node, objectExpression, sourceCode)];
|
|
5403
|
+
const report3 = {
|
|
5404
|
+
node,
|
|
5405
|
+
messageId: "inlineReturnObject",
|
|
5406
|
+
suggest
|
|
5407
|
+
};
|
|
5408
|
+
context.report(report3);
|
|
5409
|
+
}
|
|
5410
|
+
};
|
|
5411
|
+
return listeners;
|
|
5412
|
+
}
|
|
5413
|
+
});
|
|
5414
|
+
|
|
5415
|
+
// packages/lint-suite/src/lib/rules/no-nested-object-value/no-nested-object-value.ts
|
|
5416
|
+
import { ESLintUtils as ESLintUtils12, TSESTree as TSESTree23 } from "@typescript-eslint/utils";
|
|
5417
|
+
|
|
5418
|
+
// packages/lint-suite/src/lib/rules/utils/glob-matcher.util.ts
|
|
5419
|
+
var GLOB_TOKEN = /\*\*\/|\*\*|\*|\?|\{[^}]*\}|[^*?{]+/gu;
|
|
5420
|
+
var REGEXP_ESCAPE = /[.*+?^${}()|[\]\\]/gu;
|
|
5421
|
+
var escapeLiteral = (value) => value.replaceAll(REGEXP_ESCAPE, "\\$&");
|
|
5422
|
+
var braceAlternatives = (token) => {
|
|
5423
|
+
const inner = token.slice(1, -1);
|
|
5424
|
+
const alternatives = inner.split(",").map(escapeLiteral);
|
|
5425
|
+
return `(?:${alternatives.join("|")})`;
|
|
5426
|
+
};
|
|
5427
|
+
var translateToken = (token) => {
|
|
5428
|
+
if (token === "**/") return "(?:.*/)?";
|
|
5429
|
+
if (token === "**") return ".*";
|
|
5430
|
+
if (token === "*") return "[^/]*";
|
|
5431
|
+
if (token === "?") return "[^/]";
|
|
5432
|
+
const startsWithBrace = token.startsWith("{");
|
|
5433
|
+
const endsWithBrace = token.endsWith("}");
|
|
5434
|
+
if (startsWithBrace && endsWithBrace) return braceAlternatives(token);
|
|
5435
|
+
return escapeLiteral(token);
|
|
5436
|
+
};
|
|
5437
|
+
var globSource = (pattern) => {
|
|
5438
|
+
const tokens = pattern.match(GLOB_TOKEN) ?? [];
|
|
5439
|
+
return tokens.map(translateToken).join("");
|
|
5440
|
+
};
|
|
5441
|
+
var ALL_DEPTH_PREFIX = "**/";
|
|
5442
|
+
var ALL_DEPTH_GROUP = "(?:.*/)?";
|
|
5443
|
+
var stripAllDepthPrefix = (pattern) => {
|
|
5444
|
+
const hasPrefix = pattern.startsWith(ALL_DEPTH_PREFIX);
|
|
5445
|
+
if (!hasPrefix) return pattern;
|
|
5446
|
+
return pattern.slice(ALL_DEPTH_PREFIX.length);
|
|
5447
|
+
};
|
|
5448
|
+
var sharesAllDepthPrefix = (patterns) => patterns.every((pattern) => pattern.startsWith(ALL_DEPTH_PREFIX));
|
|
5449
|
+
var combinedSource = (patterns) => {
|
|
5450
|
+
const hoistPrefix = sharesAllDepthPrefix(patterns);
|
|
5451
|
+
if (!hoistPrefix) {
|
|
5452
|
+
const sources2 = patterns.map(globSource);
|
|
5453
|
+
return `(?:${sources2.join("|")})`;
|
|
5454
|
+
}
|
|
5455
|
+
const bodies = patterns.map(stripAllDepthPrefix);
|
|
5456
|
+
const sources = bodies.map(globSource);
|
|
5457
|
+
return `${ALL_DEPTH_GROUP}(?:${sources.join("|")})`;
|
|
5458
|
+
};
|
|
5459
|
+
var compileGlobs = (patterns) => {
|
|
5460
|
+
const source = combinedSource(patterns);
|
|
5461
|
+
const combined = new RegExp(`^${source}$`, "u");
|
|
5462
|
+
const matchPath = (path) => {
|
|
5463
|
+
const normalised = path.replaceAll("\\", "/");
|
|
5464
|
+
return combined.test(normalised);
|
|
5465
|
+
};
|
|
5466
|
+
return matchPath;
|
|
5467
|
+
};
|
|
5468
|
+
|
|
5469
|
+
// packages/lint-suite/src/lib/rules/no-nested-object-value/common/no-nested-object-value.const.ts
|
|
5470
|
+
var DEFAULT_CONFIG_FILES = [
|
|
5471
|
+
"**/*.config.{ts,js,mjs,cjs}",
|
|
5472
|
+
"**/eslint.config.*",
|
|
5473
|
+
"**/*.schema.ts"
|
|
5474
|
+
];
|
|
5475
|
+
var docs12 = {
|
|
5476
|
+
description: "Require a nested object literal, array of objects, conditional, or chained call used as a property value to be named as a constant first"
|
|
5477
|
+
};
|
|
5478
|
+
var messages12 = {
|
|
5479
|
+
nestedValue: "Property '{{ key }}' holds a nested value inline; name it as a constant first."
|
|
5480
|
+
};
|
|
5481
|
+
var configFilesItemsSchema = { type: "string" };
|
|
5482
|
+
var configFilesSchema = {
|
|
5483
|
+
type: "array",
|
|
5484
|
+
items: configFilesItemsSchema
|
|
5485
|
+
};
|
|
5486
|
+
var properties6 = {
|
|
5487
|
+
configFiles: configFilesSchema
|
|
5488
|
+
};
|
|
5489
|
+
var optionsSchema6 = {
|
|
5490
|
+
type: "object",
|
|
5491
|
+
properties: properties6,
|
|
5492
|
+
additionalProperties: false
|
|
5493
|
+
};
|
|
5494
|
+
var schema7 = [optionsSchema6];
|
|
5495
|
+
var meta12 = {
|
|
5496
|
+
type: "suggestion",
|
|
5497
|
+
docs: docs12,
|
|
5498
|
+
hasSuggestions: true,
|
|
5499
|
+
schema: schema7,
|
|
5500
|
+
messages: messages12
|
|
5501
|
+
};
|
|
5502
|
+
var defaultOptions6 = [{ configFiles: DEFAULT_CONFIG_FILES }];
|
|
5503
|
+
|
|
5504
|
+
// packages/lint-suite/src/lib/rules/no-nested-object-value/utils/decorator-config.util.ts
|
|
5505
|
+
import { TSESTree as TSESTree21 } from "@typescript-eslint/utils";
|
|
5506
|
+
var MAX_DECORATOR_OBJECT_HOPS = 3;
|
|
5507
|
+
var isDecoratorArgument = (node) => {
|
|
5508
|
+
const { parent } = node;
|
|
5509
|
+
if (parent.type !== TSESTree21.AST_NODE_TYPES.CallExpression) return false;
|
|
5510
|
+
const { parent: grandparent } = parent;
|
|
5511
|
+
return grandparent.type === TSESTree21.AST_NODE_TYPES.Decorator;
|
|
5512
|
+
};
|
|
5513
|
+
var isInsideDecoratorConfig = (objectExpression, ancestors) => {
|
|
5514
|
+
let objectHops = 0;
|
|
5515
|
+
const isDecoratorConfig = isDecoratorArgument(objectExpression);
|
|
5516
|
+
if (isDecoratorConfig) return true;
|
|
5517
|
+
for (let index = ancestors.length - 1; index >= 0; index -= 1) {
|
|
5518
|
+
const ancestor = ancestors[index];
|
|
5519
|
+
if (ancestor?.type !== TSESTree21.AST_NODE_TYPES.ObjectExpression) continue;
|
|
5520
|
+
objectHops += 1;
|
|
5521
|
+
const isAncestorDecoratorConfig = isDecoratorArgument(ancestor);
|
|
5522
|
+
if (isAncestorDecoratorConfig) return true;
|
|
5523
|
+
if (objectHops >= MAX_DECORATOR_OBJECT_HOPS) return false;
|
|
5524
|
+
}
|
|
5525
|
+
return false;
|
|
5526
|
+
};
|
|
5527
|
+
|
|
5528
|
+
// packages/lint-suite/src/lib/rules/utils/enclosing-statement.util.ts
|
|
5529
|
+
import { TSESTree as TSESTree22 } from "@typescript-eslint/utils";
|
|
5530
|
+
var isBodyContainer = (node) => {
|
|
5531
|
+
return node.type === TSESTree22.AST_NODE_TYPES.Program || node.type === TSESTree22.AST_NODE_TYPES.BlockStatement || node.type === TSESTree22.AST_NODE_TYPES.StaticBlock;
|
|
5532
|
+
};
|
|
5533
|
+
var enclosingStatement2 = (node) => {
|
|
5534
|
+
let current = node;
|
|
5535
|
+
for (; ; ) {
|
|
5536
|
+
const { parent } = current;
|
|
5537
|
+
if (!parent || isBodyContainer(parent)) return current;
|
|
5538
|
+
current = parent;
|
|
5539
|
+
}
|
|
5540
|
+
};
|
|
5541
|
+
|
|
5542
|
+
// packages/lint-suite/src/lib/rules/no-nested-object-value/no-nested-object-value.ts
|
|
5543
|
+
var createRule12 = ESLintUtils12.RuleCreator(
|
|
5544
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-nested-object-value"
|
|
5545
|
+
);
|
|
5546
|
+
var isChainedCall = (node) => {
|
|
5547
|
+
const { callee } = node;
|
|
5548
|
+
if (callee.type !== TSESTree23.AST_NODE_TYPES.MemberExpression) return false;
|
|
5549
|
+
return callee.object.type === TSESTree23.AST_NODE_TYPES.CallExpression;
|
|
5550
|
+
};
|
|
5551
|
+
var isObjectElement = (element) => {
|
|
5552
|
+
return element?.type === TSESTree23.AST_NODE_TYPES.ObjectExpression;
|
|
5553
|
+
};
|
|
5554
|
+
var hasNestedObjectElement = (node) => {
|
|
5555
|
+
return node.elements.some(isObjectElement);
|
|
5556
|
+
};
|
|
5557
|
+
var isNestedValue = (value) => {
|
|
5558
|
+
if (value.type === TSESTree23.AST_NODE_TYPES.ObjectExpression) {
|
|
5559
|
+
return value.properties.length > 0;
|
|
5560
|
+
}
|
|
5561
|
+
if (value.type === TSESTree23.AST_NODE_TYPES.ArrayExpression) {
|
|
5562
|
+
return hasNestedObjectElement(value);
|
|
5563
|
+
}
|
|
5564
|
+
if (value.type === TSESTree23.AST_NODE_TYPES.ConditionalExpression) return true;
|
|
5565
|
+
if (value.type === TSESTree23.AST_NODE_TYPES.CallExpression) {
|
|
5566
|
+
return isChainedCall(value);
|
|
5567
|
+
}
|
|
5568
|
+
return false;
|
|
5569
|
+
};
|
|
5570
|
+
var CONFIG_FILE_MATCHERS = /* @__PURE__ */ new WeakMap();
|
|
5571
|
+
var configFileMatcher = (configFiles) => {
|
|
5572
|
+
const cached = CONFIG_FILE_MATCHERS.get(configFiles);
|
|
5573
|
+
if (cached) return cached;
|
|
5574
|
+
const matcher = compileGlobs(configFiles);
|
|
5575
|
+
CONFIG_FILE_MATCHERS.set(configFiles, matcher);
|
|
5576
|
+
return matcher;
|
|
5577
|
+
};
|
|
5578
|
+
var isConfigFile = (filename, configFiles) => {
|
|
5579
|
+
const matchesConfig = configFileMatcher(configFiles);
|
|
5580
|
+
return matchesConfig(filename);
|
|
5581
|
+
};
|
|
5582
|
+
var suggestionsFor = (property, key2, sourceCode) => {
|
|
5583
|
+
const empty = [];
|
|
5584
|
+
const isNamedKey = property.key.type === TSESTree23.AST_NODE_TYPES.Identifier && !property.computed;
|
|
5585
|
+
if (!isNamedKey) return empty;
|
|
5586
|
+
const statement = enclosingStatement2(property);
|
|
5587
|
+
const indent = indentOf(statement, sourceCode);
|
|
5588
|
+
const valueText = sourceCode.getText(property.value);
|
|
5589
|
+
const fix = (fixer) => {
|
|
5590
|
+
const declaration = fixer.insertTextBefore(
|
|
5591
|
+
statement,
|
|
5592
|
+
`const ${key2} = ${valueText};
|
|
5593
|
+
${indent}`
|
|
5594
|
+
);
|
|
5595
|
+
const replaced = fixer.replaceText(property.value, key2);
|
|
5596
|
+
const fixes = [declaration, replaced];
|
|
5597
|
+
return fixes;
|
|
5598
|
+
};
|
|
5599
|
+
const data = { key: key2 };
|
|
5600
|
+
const suggestion = {
|
|
5601
|
+
messageId: "nestedValue",
|
|
5602
|
+
data,
|
|
5603
|
+
fix
|
|
5604
|
+
};
|
|
5605
|
+
const suggestions = [
|
|
5606
|
+
suggestion
|
|
5607
|
+
];
|
|
5608
|
+
return suggestions;
|
|
5609
|
+
};
|
|
5610
|
+
var no_nested_object_value_default = createRule12({
|
|
5611
|
+
name: "no-nested-object-value",
|
|
5612
|
+
meta: meta12,
|
|
5613
|
+
defaultOptions: defaultOptions6,
|
|
5614
|
+
create(context, [{ configFiles }]) {
|
|
5615
|
+
const isExemptFile2 = isConfigFile(context.filename, configFiles);
|
|
5616
|
+
if (isExemptFile2) {
|
|
5617
|
+
const noListeners = {};
|
|
5618
|
+
return noListeners;
|
|
5619
|
+
}
|
|
5620
|
+
const { sourceCode } = context;
|
|
5621
|
+
const listeners = {
|
|
5622
|
+
Property(node) {
|
|
5623
|
+
if (node.parent.type !== TSESTree23.AST_NODE_TYPES.ObjectExpression)
|
|
5624
|
+
return;
|
|
5625
|
+
const isNested = isNestedValue(node.value);
|
|
5626
|
+
if (!isNested) return;
|
|
5627
|
+
const ancestors = sourceCode.getAncestors(node.parent);
|
|
5628
|
+
const isDecoratorConfig = isInsideDecoratorConfig(
|
|
5629
|
+
node.parent,
|
|
5630
|
+
ancestors
|
|
5631
|
+
);
|
|
5632
|
+
if (isDecoratorConfig) return;
|
|
5633
|
+
const key2 = sourceCode.getText(node.key);
|
|
5634
|
+
const suggest = suggestionsFor(node, key2, sourceCode);
|
|
5635
|
+
const data = { key: key2 };
|
|
5636
|
+
const report3 = {
|
|
5637
|
+
node,
|
|
5638
|
+
messageId: "nestedValue",
|
|
5639
|
+
data,
|
|
5640
|
+
suggest
|
|
5641
|
+
};
|
|
5642
|
+
context.report(report3);
|
|
5643
|
+
}
|
|
5644
|
+
};
|
|
5645
|
+
return listeners;
|
|
5646
|
+
}
|
|
5647
|
+
});
|
|
5648
|
+
|
|
5649
|
+
// packages/lint-suite/src/lib/rules/no-spread-expression/no-spread-expression.ts
|
|
5650
|
+
import { ESLintUtils as ESLintUtils13, TSESTree as TSESTree24 } from "@typescript-eslint/utils";
|
|
5651
|
+
var docs13 = {
|
|
5652
|
+
description: "Require a spread argument to be an identifier or member access, not an inline expression"
|
|
5653
|
+
};
|
|
5654
|
+
var messages13 = {
|
|
5655
|
+
spreadExpression: "Spread argument is an inline expression; name it as a constant first."
|
|
5656
|
+
};
|
|
5657
|
+
var meta13 = {
|
|
5658
|
+
type: "suggestion",
|
|
5659
|
+
docs: docs13,
|
|
5660
|
+
hasSuggestions: true,
|
|
5661
|
+
schema: [],
|
|
5662
|
+
messages: messages13
|
|
5663
|
+
};
|
|
5664
|
+
var createRule13 = ESLintUtils13.RuleCreator(
|
|
5665
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-spread-expression"
|
|
5666
|
+
);
|
|
5667
|
+
var ALLOWED_ARGUMENT_TYPES = /* @__PURE__ */ new Set([
|
|
5668
|
+
TSESTree24.AST_NODE_TYPES.Identifier,
|
|
5669
|
+
TSESTree24.AST_NODE_TYPES.MemberExpression
|
|
5670
|
+
]);
|
|
5671
|
+
var no_spread_expression_default = createRule13({
|
|
5672
|
+
name: "no-spread-expression",
|
|
5673
|
+
meta: meta13,
|
|
5674
|
+
defaultOptions: [],
|
|
5675
|
+
create(context) {
|
|
5676
|
+
const { sourceCode } = context;
|
|
5677
|
+
const listeners = {
|
|
5678
|
+
SpreadElement(node) {
|
|
5679
|
+
const isAllowed = ALLOWED_ARGUMENT_TYPES.has(node.argument.type);
|
|
5680
|
+
if (isAllowed) return;
|
|
5681
|
+
const statement = enclosingStatement2(node);
|
|
5682
|
+
const indent = indentOf(statement, sourceCode);
|
|
5683
|
+
const argumentText = sourceCode.getText(node.argument);
|
|
5684
|
+
const fix = (fixer) => {
|
|
5685
|
+
const declaration = fixer.insertTextBefore(
|
|
5686
|
+
statement,
|
|
5687
|
+
`const spread = ${argumentText};
|
|
5688
|
+
${indent}`
|
|
5689
|
+
);
|
|
5690
|
+
const replaced = fixer.replaceText(node.argument, "spread");
|
|
5691
|
+
const fixes = [declaration, replaced];
|
|
5692
|
+
return fixes;
|
|
5693
|
+
};
|
|
5694
|
+
const suggestion = {
|
|
5695
|
+
messageId: "spreadExpression",
|
|
5696
|
+
fix
|
|
5697
|
+
};
|
|
5698
|
+
const report3 = {
|
|
5699
|
+
node,
|
|
5700
|
+
messageId: "spreadExpression",
|
|
5701
|
+
suggest: [suggestion]
|
|
5702
|
+
};
|
|
5703
|
+
context.report(report3);
|
|
5704
|
+
}
|
|
5705
|
+
};
|
|
5706
|
+
return listeners;
|
|
5707
|
+
}
|
|
5708
|
+
});
|
|
5709
|
+
|
|
5710
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/no-unused-exports.ts
|
|
5711
|
+
import { ESLintUtils as ESLintUtils14 } from "@typescript-eslint/utils";
|
|
5712
|
+
|
|
5713
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/common/no-unused-exports.const.ts
|
|
5714
|
+
var entryPointDefaults = [
|
|
5715
|
+
"**/main.ts",
|
|
5716
|
+
"**/main.*.ts",
|
|
5717
|
+
"**/public-api.ts",
|
|
5718
|
+
"**/index.ts",
|
|
5719
|
+
"**/*.config.ts",
|
|
5720
|
+
"**/*.config.mts",
|
|
5721
|
+
"**/*.config.cts",
|
|
5722
|
+
"**/*.spec.ts",
|
|
5723
|
+
"**/*.spec.util.ts",
|
|
5724
|
+
"**/*.stub.ts",
|
|
5725
|
+
"**/*.mock.ts",
|
|
5726
|
+
"**/*.d.ts",
|
|
5727
|
+
"**/*.stories.ts",
|
|
5728
|
+
"**/environment*.ts"
|
|
5729
|
+
];
|
|
5730
|
+
var STAR_NAME = "*";
|
|
5731
|
+
var docs14 = {
|
|
5732
|
+
description: "Disallow exports that no other file in the TypeScript program imports"
|
|
5733
|
+
};
|
|
5734
|
+
var messages14 = {
|
|
5735
|
+
unusedExport: "Export '{{ name }}' is never imported by another file.",
|
|
5736
|
+
unusedModule: "This module exports names but is never imported."
|
|
5737
|
+
};
|
|
5738
|
+
var entryPointItemsSchema = { type: "string" };
|
|
5739
|
+
var entryPointsSchema = {
|
|
5740
|
+
type: "array",
|
|
5741
|
+
items: entryPointItemsSchema,
|
|
5742
|
+
description: "Globs whose files are treated as project entry points."
|
|
5743
|
+
};
|
|
5744
|
+
var properties7 = {
|
|
5745
|
+
entryPoints: entryPointsSchema
|
|
5746
|
+
};
|
|
5747
|
+
var optionsSchema7 = {
|
|
5748
|
+
type: "object",
|
|
5749
|
+
properties: properties7,
|
|
5750
|
+
additionalProperties: false
|
|
5751
|
+
};
|
|
5752
|
+
var schema8 = [optionsSchema7];
|
|
5753
|
+
var meta14 = {
|
|
5754
|
+
type: "problem",
|
|
5755
|
+
docs: docs14,
|
|
5756
|
+
schema: schema8,
|
|
5757
|
+
messages: messages14
|
|
5758
|
+
};
|
|
5759
|
+
var ruleDefaults4 = { entryPoints: [...entryPointDefaults] };
|
|
5760
|
+
var defaultOptions7 = [ruleDefaults4];
|
|
5761
|
+
|
|
5762
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/export-index.ts
|
|
5763
|
+
import { dirname as dirname10 } from "node:path";
|
|
5764
|
+
|
|
5765
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/export-usage.util.ts
|
|
5766
|
+
var MAX_DEPTH = 50;
|
|
5767
|
+
var reExportIndex = (byFile) => {
|
|
5768
|
+
const index = /* @__PURE__ */ new Map();
|
|
5769
|
+
for (const [fileName, edges] of byFile) {
|
|
5770
|
+
const names = /* @__PURE__ */ new Map();
|
|
5771
|
+
for (const edge of edges.reExports) {
|
|
5772
|
+
names.set(edge.exported, edge);
|
|
5773
|
+
}
|
|
5774
|
+
index.set(fileName, names);
|
|
5775
|
+
}
|
|
5776
|
+
return index;
|
|
5777
|
+
};
|
|
5778
|
+
var push = (walk, fileName, name) => {
|
|
5779
|
+
const key2 = { fileName, name };
|
|
5780
|
+
walk.keys.push(key2);
|
|
5781
|
+
};
|
|
5782
|
+
var deeper = (walk) => {
|
|
5783
|
+
const next = {
|
|
5784
|
+
visited: walk.visited,
|
|
5785
|
+
depth: walk.depth + 1,
|
|
5786
|
+
keys: walk.keys
|
|
5787
|
+
};
|
|
5788
|
+
return next;
|
|
5789
|
+
};
|
|
5790
|
+
var isNewStep = (walk, key2) => {
|
|
5791
|
+
if (walk.depth > MAX_DEPTH) return false;
|
|
5792
|
+
const isVisited = walk.visited.has(key2);
|
|
5793
|
+
if (isVisited) return false;
|
|
5794
|
+
walk.visited.add(key2);
|
|
5795
|
+
return true;
|
|
5796
|
+
};
|
|
5797
|
+
var markName = (context, fileName, name, walk) => {
|
|
5798
|
+
const isNew = isNewStep(walk, `${fileName} ${name}`);
|
|
5799
|
+
if (!isNew) return;
|
|
5800
|
+
const edges = context.byFile.get(fileName);
|
|
5801
|
+
if (!edges) return;
|
|
5802
|
+
push(walk, fileName, name);
|
|
5803
|
+
const reExport = context.reExportsByName.get(fileName)?.get(name);
|
|
5804
|
+
if (reExport) {
|
|
5805
|
+
markName(context, reExport.target, reExport.source, deeper(walk));
|
|
5806
|
+
}
|
|
5807
|
+
const isDeclaredLocally = edges.declared.has(name);
|
|
5808
|
+
if (isDeclaredLocally) return;
|
|
5809
|
+
for (const target of edges.starTargets) {
|
|
5810
|
+
markName(context, target, name, deeper(walk));
|
|
5811
|
+
}
|
|
5812
|
+
};
|
|
5813
|
+
var markAll = (context, fileName, walk) => {
|
|
5814
|
+
const isNew = isNewStep(walk, `${fileName} ${STAR_NAME}`);
|
|
5815
|
+
if (!isNew) return;
|
|
5816
|
+
const edges = context.byFile.get(fileName);
|
|
5817
|
+
if (!edges) return;
|
|
5818
|
+
for (const name of edges.exports) {
|
|
5819
|
+
push(walk, fileName, name);
|
|
5820
|
+
}
|
|
5821
|
+
for (const edge of edges.reExports) {
|
|
5822
|
+
markName(context, edge.target, edge.source, deeper(walk));
|
|
5823
|
+
}
|
|
5824
|
+
for (const target of edges.starTargets) {
|
|
5825
|
+
markAll(context, target, deeper(walk));
|
|
5826
|
+
}
|
|
5827
|
+
};
|
|
5828
|
+
var markUsage = (context, target, name) => {
|
|
5829
|
+
const keys = [];
|
|
5830
|
+
const walk = { visited: /* @__PURE__ */ new Set(), depth: 0, keys };
|
|
5831
|
+
if (name === STAR_NAME) {
|
|
5832
|
+
markAll(context, target, walk);
|
|
5833
|
+
return keys;
|
|
5834
|
+
}
|
|
5835
|
+
markName(context, target, name, walk);
|
|
5836
|
+
return keys;
|
|
5837
|
+
};
|
|
5838
|
+
|
|
5839
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/aggregate-update.util.ts
|
|
5840
|
+
var countDelta = (counts, key2, delta) => {
|
|
5841
|
+
const current = counts.get(key2);
|
|
5842
|
+
const next = (current ?? 0) + delta;
|
|
5843
|
+
if (next > 0) {
|
|
5844
|
+
counts.set(key2, next);
|
|
5845
|
+
return;
|
|
5846
|
+
}
|
|
5847
|
+
counts.delete(key2);
|
|
5848
|
+
};
|
|
5849
|
+
var usageDelta = (usage, key2, delta) => {
|
|
5850
|
+
const existing = usage.get(key2.fileName);
|
|
5851
|
+
const names = existing ?? /* @__PURE__ */ new Map();
|
|
5852
|
+
const current = names.get(key2.name);
|
|
5853
|
+
const next = (current ?? 0) + delta;
|
|
5854
|
+
if (next > 0) names.set(key2.name, next);
|
|
5855
|
+
else names.delete(key2.name);
|
|
5856
|
+
if (names.size > 0) usage.set(key2.fileName, names);
|
|
5857
|
+
else usage.delete(key2.fileName);
|
|
5858
|
+
};
|
|
5859
|
+
var fileContribution = (context, edges) => {
|
|
5860
|
+
const usage = [];
|
|
5861
|
+
const imported = [];
|
|
5862
|
+
const starTouched = [];
|
|
5863
|
+
for (const edge of edges.imports) {
|
|
5864
|
+
imported.push(edge.target);
|
|
5865
|
+
for (const name of edge.names) {
|
|
5866
|
+
if (name === STAR_NAME) starTouched.push(edge.target);
|
|
5867
|
+
const keys = markUsage(context, edge.target, name);
|
|
5868
|
+
for (const key2 of keys) usage.push(key2);
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5871
|
+
for (const edge of edges.reExports) {
|
|
5872
|
+
imported.push(edge.target);
|
|
5873
|
+
starTouched.push(edge.target);
|
|
5874
|
+
}
|
|
5875
|
+
for (const target of edges.starTargets) {
|
|
5876
|
+
imported.push(target);
|
|
5877
|
+
starTouched.push(target);
|
|
5878
|
+
}
|
|
5879
|
+
const contribution = { usage, imported, starTouched };
|
|
5880
|
+
return contribution;
|
|
5881
|
+
};
|
|
5882
|
+
var applyContribution = (aggregate, contribution, delta) => {
|
|
5883
|
+
for (const key2 of contribution.usage) {
|
|
5884
|
+
usageDelta(aggregate.usage, key2, delta);
|
|
5885
|
+
}
|
|
5886
|
+
for (const target of contribution.imported) {
|
|
5887
|
+
countDelta(aggregate.imported, target, delta);
|
|
5888
|
+
}
|
|
5889
|
+
for (const target of contribution.starTouched) {
|
|
5890
|
+
countDelta(aggregate.starTouched, target, delta);
|
|
5891
|
+
}
|
|
5892
|
+
};
|
|
5893
|
+
var contextOf = (aggregate) => {
|
|
5894
|
+
const context = {
|
|
5895
|
+
byFile: aggregate.byFile,
|
|
5896
|
+
reExportsByName: aggregate.reExportsByName
|
|
5897
|
+
};
|
|
5898
|
+
return context;
|
|
5899
|
+
};
|
|
5900
|
+
var addFile = (aggregate, edges) => {
|
|
5901
|
+
const context = contextOf(aggregate);
|
|
5902
|
+
const contribution = fileContribution(context, edges);
|
|
5903
|
+
aggregate.contributions.set(edges.fileName, contribution);
|
|
5904
|
+
applyContribution(aggregate, contribution, 1);
|
|
5905
|
+
};
|
|
5906
|
+
var buildAggregate = (byFile) => {
|
|
5907
|
+
const aggregate = {
|
|
5908
|
+
byFile,
|
|
5909
|
+
usage: /* @__PURE__ */ new Map(),
|
|
5910
|
+
imported: /* @__PURE__ */ new Map(),
|
|
5911
|
+
reExportsByName: reExportIndex(byFile),
|
|
5912
|
+
contributions: /* @__PURE__ */ new Map(),
|
|
5913
|
+
starTouched: /* @__PURE__ */ new Map()
|
|
5914
|
+
};
|
|
5915
|
+
for (const edges of byFile.values()) {
|
|
5916
|
+
addFile(aggregate, edges);
|
|
5917
|
+
}
|
|
5918
|
+
return aggregate;
|
|
5919
|
+
};
|
|
5920
|
+
var dropFile = (aggregate, fileName) => {
|
|
5921
|
+
const contribution = aggregate.contributions.get(fileName);
|
|
5922
|
+
if (!contribution) return;
|
|
5923
|
+
applyContribution(aggregate, contribution, -1);
|
|
5924
|
+
aggregate.contributions.delete(fileName);
|
|
5925
|
+
};
|
|
5926
|
+
var replaceEdges = (aggregate, change) => {
|
|
5927
|
+
if (!change.after) {
|
|
5928
|
+
aggregate.byFile.delete(change.fileName);
|
|
5929
|
+
aggregate.reExportsByName.delete(change.fileName);
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
aggregate.byFile.set(change.fileName, change.after);
|
|
5933
|
+
aggregate.reExportsByName.set(change.fileName, /* @__PURE__ */ new Map());
|
|
5934
|
+
};
|
|
5935
|
+
var updateAggregate = (aggregate, changes) => {
|
|
5936
|
+
for (const change of changes) {
|
|
5937
|
+
dropFile(aggregate, change.fileName);
|
|
5938
|
+
replaceEdges(aggregate, change);
|
|
5939
|
+
}
|
|
5940
|
+
for (const change of changes) {
|
|
5941
|
+
if (change.after) addFile(aggregate, change.after);
|
|
5942
|
+
}
|
|
5943
|
+
};
|
|
5944
|
+
|
|
5945
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/file-changes.util.ts
|
|
5946
|
+
var fileChanges = (before, after) => {
|
|
5947
|
+
const changes = [];
|
|
5948
|
+
for (const [fileName, edges] of after) {
|
|
5949
|
+
const previous = before.get(fileName);
|
|
5950
|
+
if (previous === edges) continue;
|
|
5951
|
+
const change = { fileName, before: previous, after: edges };
|
|
5952
|
+
changes.push(change);
|
|
5953
|
+
}
|
|
5954
|
+
for (const [fileName, edges] of before) {
|
|
5955
|
+
const isKept = after.has(fileName);
|
|
5956
|
+
if (isKept) continue;
|
|
5957
|
+
const change = { fileName, before: edges, after: void 0 };
|
|
5958
|
+
changes.push(change);
|
|
5959
|
+
}
|
|
5960
|
+
return changes;
|
|
5961
|
+
};
|
|
5962
|
+
var isBarrel = (edges) => {
|
|
5963
|
+
if (!edges) return false;
|
|
5964
|
+
const hasStarTargets = edges.starTargets.length > 0;
|
|
5965
|
+
return edges.reExports.length > 0 || hasStarTargets;
|
|
5966
|
+
};
|
|
5967
|
+
var hasSameExports = (change) => {
|
|
5968
|
+
const before = change.before?.exports ?? [];
|
|
5969
|
+
const after = change.after?.exports ?? [];
|
|
5970
|
+
if (before.length !== after.length) return false;
|
|
5971
|
+
return before.every((name, index) => name === after[index]);
|
|
5972
|
+
};
|
|
5973
|
+
var isIncremental = (changes, starTouched) => {
|
|
5974
|
+
for (const change of changes) {
|
|
5975
|
+
const wasBarrel = isBarrel(change.before);
|
|
5976
|
+
const isNowBarrel = isBarrel(change.after);
|
|
5977
|
+
const touchesBarrel = wasBarrel || isNowBarrel;
|
|
5978
|
+
if (touchesBarrel) return false;
|
|
5979
|
+
const isStarTouched = starTouched.has(change.fileName);
|
|
5980
|
+
if (!isStarTouched) continue;
|
|
5981
|
+
const sameExports = hasSameExports(change);
|
|
5982
|
+
if (!sameExports) return false;
|
|
5983
|
+
}
|
|
5984
|
+
return true;
|
|
5985
|
+
};
|
|
5986
|
+
|
|
5987
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-edges.util.ts
|
|
5988
|
+
import {
|
|
5989
|
+
SyntaxKind as SyntaxKind7,
|
|
5990
|
+
forEachChild as forEachChild5,
|
|
5991
|
+
isCallExpression as isCallExpression4,
|
|
5992
|
+
isExportAssignment,
|
|
5993
|
+
isExportDeclaration,
|
|
5994
|
+
isImportDeclaration as isImportDeclaration2,
|
|
5995
|
+
isModuleDeclaration,
|
|
5996
|
+
isNamespaceImport
|
|
5997
|
+
} from "typescript";
|
|
5998
|
+
|
|
5999
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/export-edges.util.ts
|
|
6000
|
+
import { isNamespaceExport } from "typescript";
|
|
6001
|
+
var addNamespaceExport = (clause, edges, target) => {
|
|
6002
|
+
const exported = clause.name.text;
|
|
6003
|
+
edges.exports.push(exported);
|
|
6004
|
+
edges.declared.add(exported);
|
|
6005
|
+
if (target === void 0) return;
|
|
6006
|
+
const edge = { target, names: ["*"] };
|
|
6007
|
+
edges.imports.push(edge);
|
|
6008
|
+
};
|
|
6009
|
+
var addExportFrom = (statement, edges, resolve5) => {
|
|
6010
|
+
const target = resolve5(statement.moduleSpecifier);
|
|
6011
|
+
const clause = statement.exportClause;
|
|
6012
|
+
if (!clause) {
|
|
6013
|
+
if (target !== void 0) edges.starTargets.push(target);
|
|
6014
|
+
return;
|
|
6015
|
+
}
|
|
6016
|
+
if (isNamespaceExport(clause)) {
|
|
6017
|
+
addNamespaceExport(clause, edges, target);
|
|
6018
|
+
return;
|
|
6019
|
+
}
|
|
6020
|
+
for (const element of clause.elements) {
|
|
6021
|
+
const origin = element.propertyName ?? element.name;
|
|
6022
|
+
const exported = element.name.text;
|
|
6023
|
+
edges.exports.push(exported);
|
|
6024
|
+
if (target === void 0) continue;
|
|
6025
|
+
const edge = { target, source: origin.text, exported };
|
|
6026
|
+
edges.reExports.push(edge);
|
|
6027
|
+
}
|
|
6028
|
+
};
|
|
6029
|
+
var addLocalExport = (statement, edges) => {
|
|
6030
|
+
const clause = statement.exportClause;
|
|
6031
|
+
if (!clause) return;
|
|
6032
|
+
if (isNamespaceExport(clause)) return;
|
|
6033
|
+
for (const element of clause.elements) {
|
|
6034
|
+
const exported = element.name.text;
|
|
6035
|
+
edges.exports.push(exported);
|
|
6036
|
+
edges.declared.add(exported);
|
|
6037
|
+
}
|
|
6038
|
+
};
|
|
6039
|
+
|
|
6040
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/exported-names.util.ts
|
|
6041
|
+
import {
|
|
6042
|
+
SyntaxKind as SyntaxKind6,
|
|
6043
|
+
canHaveModifiers,
|
|
6044
|
+
getModifiers,
|
|
6045
|
+
isClassDeclaration,
|
|
6046
|
+
isEnumDeclaration,
|
|
6047
|
+
isFunctionDeclaration as isFunctionDeclaration2,
|
|
6048
|
+
isIdentifier as isIdentifier10,
|
|
6049
|
+
isInterfaceDeclaration,
|
|
6050
|
+
isTypeAliasDeclaration,
|
|
6051
|
+
isVariableStatement
|
|
6052
|
+
} from "typescript";
|
|
6053
|
+
var hasModifier = (statement, kind) => {
|
|
6054
|
+
if (!canHaveModifiers(statement)) return false;
|
|
6055
|
+
const modifiers = getModifiers(statement);
|
|
6056
|
+
const matched = modifiers?.some((modifier) => modifier.kind === kind);
|
|
6057
|
+
return matched === true;
|
|
6058
|
+
};
|
|
6059
|
+
var variableNames = (statement) => {
|
|
6060
|
+
const names = [];
|
|
6061
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
6062
|
+
if (!isIdentifier10(declaration.name)) continue;
|
|
6063
|
+
names.push(declaration.name.text);
|
|
6064
|
+
}
|
|
6065
|
+
return names;
|
|
6066
|
+
};
|
|
6067
|
+
var declaredName = (statement) => {
|
|
6068
|
+
if (isFunctionDeclaration2(statement)) return statement.name?.text;
|
|
6069
|
+
if (isClassDeclaration(statement)) return statement.name?.text;
|
|
6070
|
+
if (isTypeAliasDeclaration(statement)) return statement.name.text;
|
|
6071
|
+
if (isInterfaceDeclaration(statement)) return statement.name.text;
|
|
6072
|
+
if (isEnumDeclaration(statement)) return statement.name.text;
|
|
6073
|
+
return void 0;
|
|
6074
|
+
};
|
|
6075
|
+
var exportedNames = (statement) => {
|
|
6076
|
+
const isExported = hasModifier(statement, SyntaxKind6.ExportKeyword);
|
|
6077
|
+
if (!isExported) return [];
|
|
6078
|
+
const isDefault = hasModifier(statement, SyntaxKind6.DefaultKeyword);
|
|
6079
|
+
if (isDefault) return ["default"];
|
|
6080
|
+
if (isVariableStatement(statement)) return variableNames(statement);
|
|
6081
|
+
const name = declaredName(statement);
|
|
6082
|
+
if (name === void 0) return [];
|
|
6083
|
+
return [name];
|
|
6084
|
+
};
|
|
6085
|
+
|
|
6086
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-target.util.ts
|
|
6087
|
+
var declarationOf = (specifier, checker) => {
|
|
6088
|
+
const symbol = checker.getSymbolAtLocation(specifier);
|
|
6089
|
+
if (!symbol) return void 0;
|
|
6090
|
+
return symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
6091
|
+
};
|
|
6092
|
+
var moduleTarget = (specifier, checker, isExternal) => {
|
|
6093
|
+
if (!specifier) return void 0;
|
|
6094
|
+
const declaration = declarationOf(specifier, checker);
|
|
6095
|
+
if (!declaration) return void 0;
|
|
6096
|
+
const sourceFile = declaration.getSourceFile();
|
|
6097
|
+
if (sourceFile.isDeclarationFile) return void 0;
|
|
6098
|
+
const isSourceExternal = isExternal(sourceFile);
|
|
6099
|
+
if (isSourceExternal) return void 0;
|
|
6100
|
+
return sourceFile.fileName;
|
|
6101
|
+
};
|
|
6102
|
+
|
|
6103
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-edges.util.ts
|
|
6104
|
+
var importNames = (clause) => {
|
|
6105
|
+
if (!clause) return [];
|
|
6106
|
+
const names = [];
|
|
6107
|
+
if (clause.name) names.push("default");
|
|
6108
|
+
const bindings = clause.namedBindings;
|
|
6109
|
+
if (!bindings) return names;
|
|
6110
|
+
if (isNamespaceImport(bindings)) {
|
|
6111
|
+
names.push("*");
|
|
6112
|
+
return names;
|
|
6113
|
+
}
|
|
6114
|
+
for (const element of bindings.elements) {
|
|
6115
|
+
const origin = element.propertyName ?? element.name;
|
|
6116
|
+
names.push(origin.text);
|
|
6117
|
+
}
|
|
6118
|
+
return names;
|
|
6119
|
+
};
|
|
6120
|
+
var addImport2 = (statement, edges, resolve5) => {
|
|
6121
|
+
const target = resolve5(statement.moduleSpecifier);
|
|
6122
|
+
if (target === void 0) return;
|
|
6123
|
+
const names = importNames(statement.importClause);
|
|
6124
|
+
const edge = { target, names };
|
|
6125
|
+
edges.imports.push(edge);
|
|
6126
|
+
};
|
|
6127
|
+
var DYNAMIC_IMPORT_TEXT = "import(";
|
|
6128
|
+
var dynamicImportTarget = (node, resolve5) => {
|
|
6129
|
+
if (!isCallExpression4(node)) return void 0;
|
|
6130
|
+
const isDynamicImport = node.expression.kind === SyntaxKind7.ImportKeyword;
|
|
6131
|
+
if (!isDynamicImport) return void 0;
|
|
6132
|
+
return resolve5(node.arguments[0]);
|
|
6133
|
+
};
|
|
6134
|
+
var collectDynamicImports = (node, resolve5, targets) => {
|
|
6135
|
+
const target = dynamicImportTarget(node, resolve5);
|
|
6136
|
+
if (target !== void 0) targets.push(target);
|
|
6137
|
+
forEachChild5(node, (child) => {
|
|
6138
|
+
collectDynamicImports(child, resolve5, targets);
|
|
6139
|
+
});
|
|
6140
|
+
};
|
|
6141
|
+
var addDynamicImports = (sourceFile, edges, resolve5) => {
|
|
6142
|
+
const hasDynamicImport = sourceFile.text.includes(DYNAMIC_IMPORT_TEXT);
|
|
6143
|
+
if (!hasDynamicImport) return;
|
|
6144
|
+
const targets = [];
|
|
6145
|
+
collectDynamicImports(sourceFile, resolve5, targets);
|
|
6146
|
+
for (const target of targets) {
|
|
6147
|
+
const edge = { target, names: ["*"] };
|
|
6148
|
+
edges.imports.push(edge);
|
|
6149
|
+
}
|
|
6150
|
+
};
|
|
6151
|
+
var addDefaultExport = (edges) => {
|
|
6152
|
+
edges.exports.push("default");
|
|
6153
|
+
edges.declared.add("default");
|
|
6154
|
+
};
|
|
6155
|
+
var addDeclaredExports = (statement, edges) => {
|
|
6156
|
+
for (const name of exportedNames(statement)) {
|
|
6157
|
+
edges.exports.push(name);
|
|
6158
|
+
edges.declared.add(name);
|
|
6159
|
+
}
|
|
6160
|
+
};
|
|
6161
|
+
var emptyEdges = () => {
|
|
6162
|
+
const edges = {
|
|
6163
|
+
exports: [],
|
|
6164
|
+
declared: /* @__PURE__ */ new Set(),
|
|
6165
|
+
imports: [],
|
|
6166
|
+
reExports: [],
|
|
6167
|
+
starTargets: []
|
|
6168
|
+
};
|
|
6169
|
+
return edges;
|
|
6170
|
+
};
|
|
6171
|
+
var moduleEdges = (sourceFile, checker, isExternal) => {
|
|
6172
|
+
const resolve5 = (specifier) => moduleTarget(specifier, checker, isExternal);
|
|
6173
|
+
const edges = emptyEdges();
|
|
6174
|
+
let skipped = false;
|
|
6175
|
+
for (const statement of sourceFile.statements) {
|
|
6176
|
+
if (isImportDeclaration2(statement)) {
|
|
6177
|
+
addImport2(statement, edges, resolve5);
|
|
6178
|
+
} else if (isExportDeclaration(statement)) {
|
|
6179
|
+
if (statement.moduleSpecifier) addExportFrom(statement, edges, resolve5);
|
|
6180
|
+
else addLocalExport(statement, edges);
|
|
6181
|
+
} else if (isExportAssignment(statement)) {
|
|
6182
|
+
if (statement.isExportEquals) skipped = true;
|
|
6183
|
+
else addDefaultExport(edges);
|
|
6184
|
+
} else if (isModuleDeclaration(statement)) {
|
|
6185
|
+
skipped = true;
|
|
6186
|
+
} else {
|
|
6187
|
+
addDeclaredExports(statement, edges);
|
|
6188
|
+
}
|
|
6189
|
+
}
|
|
6190
|
+
addDynamicImports(sourceFile, edges, resolve5);
|
|
6191
|
+
const fileEdges2 = {
|
|
6192
|
+
fileName: sourceFile.fileName,
|
|
6193
|
+
...edges,
|
|
6194
|
+
skipped
|
|
6195
|
+
};
|
|
6196
|
+
return fileEdges2;
|
|
6197
|
+
};
|
|
6198
|
+
|
|
6199
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/public-exports.util.ts
|
|
6200
|
+
var publicExports = (context, entryFiles) => {
|
|
6201
|
+
const index = /* @__PURE__ */ new Map();
|
|
6202
|
+
for (const entryFile of entryFiles) {
|
|
6203
|
+
const keys = markUsage(context, entryFile, STAR_NAME);
|
|
6204
|
+
for (const key2 of keys) {
|
|
6205
|
+
const names = index.get(key2.fileName) ?? /* @__PURE__ */ new Set();
|
|
6206
|
+
names.add(key2.name);
|
|
6207
|
+
index.set(key2.fileName, names);
|
|
6208
|
+
}
|
|
6209
|
+
}
|
|
6210
|
+
return index;
|
|
6211
|
+
};
|
|
6212
|
+
|
|
6213
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/export-index.ts
|
|
6214
|
+
var FILE_EDGES = /* @__PURE__ */ new WeakMap();
|
|
6215
|
+
var AGGREGATES = /* @__PURE__ */ new WeakMap();
|
|
6216
|
+
var PUBLIC = /* @__PURE__ */ new WeakMap();
|
|
6217
|
+
var LAST_AGGREGATE = /* @__PURE__ */ new Map();
|
|
6218
|
+
var projectKey = (program) => {
|
|
6219
|
+
const configFilePath = program.getCompilerOptions()["configFilePath"];
|
|
6220
|
+
if (typeof configFilePath === "string") return configFilePath;
|
|
6221
|
+
const directories = program.getRootFileNames().map(dirname10);
|
|
6222
|
+
const uniqueDirectorySet = new Set(directories);
|
|
6223
|
+
const uniqueDirectories = [...uniqueDirectorySet];
|
|
6224
|
+
const sortedDirectories = uniqueDirectories.sort();
|
|
6225
|
+
return sortedDirectories.join("|");
|
|
6226
|
+
};
|
|
6227
|
+
var fileEdges = (sourceFile, checker, isExternal) => {
|
|
6228
|
+
const cached = FILE_EDGES.get(sourceFile);
|
|
6229
|
+
if (cached) return cached;
|
|
6230
|
+
const edges = moduleEdges(sourceFile, checker, isExternal);
|
|
6231
|
+
FILE_EDGES.set(sourceFile, edges);
|
|
6232
|
+
return edges;
|
|
6233
|
+
};
|
|
6234
|
+
var programEdges = (program) => {
|
|
6235
|
+
const checker = program.getTypeChecker();
|
|
6236
|
+
const isExternal = (sourceFile) => program.isSourceFileFromExternalLibrary(sourceFile);
|
|
6237
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6238
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
6239
|
+
if (sourceFile.isDeclarationFile) continue;
|
|
6240
|
+
const isSourceExternal = isExternal(sourceFile);
|
|
6241
|
+
if (isSourceExternal) continue;
|
|
6242
|
+
byFile.set(sourceFile.fileName, fileEdges(sourceFile, checker, isExternal));
|
|
6243
|
+
}
|
|
6244
|
+
return byFile;
|
|
6245
|
+
};
|
|
6246
|
+
var nextAggregate = (byFile, previous) => {
|
|
6247
|
+
if (!previous) return buildAggregate(byFile);
|
|
6248
|
+
const changes = fileChanges(previous.byFile, byFile);
|
|
6249
|
+
const isPatchable = isIncremental(changes, previous.starTouched);
|
|
6250
|
+
if (!isPatchable) return buildAggregate(byFile);
|
|
6251
|
+
updateAggregate(previous, changes);
|
|
6252
|
+
PUBLIC.delete(previous);
|
|
6253
|
+
return previous;
|
|
6254
|
+
};
|
|
6255
|
+
var exportIndex = (program) => {
|
|
6256
|
+
const cached = AGGREGATES.get(program);
|
|
6257
|
+
if (cached) return cached;
|
|
6258
|
+
const key2 = projectKey(program);
|
|
6259
|
+
const byFile = programEdges(program);
|
|
6260
|
+
const aggregate = nextAggregate(byFile, LAST_AGGREGATE.get(key2));
|
|
6261
|
+
AGGREGATES.set(program, aggregate);
|
|
6262
|
+
LAST_AGGREGATE.set(key2, aggregate);
|
|
6263
|
+
return aggregate;
|
|
6264
|
+
};
|
|
6265
|
+
var publicExportIndex = (aggregate, isEntry) => {
|
|
6266
|
+
const byMatcher = PUBLIC.get(aggregate) ?? /* @__PURE__ */ new WeakMap();
|
|
6267
|
+
const cached = byMatcher.get(isEntry);
|
|
6268
|
+
if (cached) return cached;
|
|
6269
|
+
const keys = aggregate.byFile.keys();
|
|
6270
|
+
const fileNames = [...keys];
|
|
6271
|
+
const entryFiles = fileNames.filter(isEntry);
|
|
6272
|
+
const context = {
|
|
6273
|
+
byFile: aggregate.byFile,
|
|
6274
|
+
reExportsByName: aggregate.reExportsByName
|
|
4221
6275
|
};
|
|
4222
|
-
|
|
6276
|
+
const index = publicExports(context, entryFiles);
|
|
6277
|
+
byMatcher.set(isEntry, index);
|
|
6278
|
+
PUBLIC.set(aggregate, byMatcher);
|
|
6279
|
+
return index;
|
|
4223
6280
|
};
|
|
4224
|
-
var explicit_accessibility_default = createRule3({
|
|
4225
|
-
name: "explicit-accessibility",
|
|
4226
|
-
meta: meta3,
|
|
4227
|
-
defaultOptions: defaultOptions3,
|
|
4228
|
-
create(context, [{ defaultAccessibility = "public" }]) {
|
|
4229
|
-
const { sourceCode } = context;
|
|
4230
|
-
const check = (node) => {
|
|
4231
|
-
const isPrivate = isPrivateMember(node);
|
|
4232
|
-
if (node.accessibility || isPrivate) return;
|
|
4233
|
-
const target = reportTarget(node);
|
|
4234
|
-
const isConstructorMember = isConstructor(node);
|
|
4235
|
-
const usesPublic = isConstructorMember && defaultAccessibility !== "none";
|
|
4236
|
-
const fixAccessibility = usesPublic ? "public" : defaultAccessibility;
|
|
4237
|
-
const autoFix = autoFixOf(node, fixAccessibility, sourceCode);
|
|
4238
|
-
const name = memberName2(target, sourceCode);
|
|
4239
|
-
const data = { name };
|
|
4240
|
-
const suggest = suggestionsOf(node, fixAccessibility, sourceCode);
|
|
4241
|
-
const report = {
|
|
4242
|
-
node: target,
|
|
4243
|
-
messageId: "missingAccessibility",
|
|
4244
|
-
data,
|
|
4245
|
-
...autoFix,
|
|
4246
|
-
suggest
|
|
4247
|
-
};
|
|
4248
|
-
context.report(report);
|
|
4249
|
-
};
|
|
4250
|
-
const listeners = {
|
|
4251
|
-
AccessorProperty: check,
|
|
4252
|
-
MethodDefinition: check,
|
|
4253
|
-
PropertyDefinition: check,
|
|
4254
|
-
TSAbstractAccessorProperty: check,
|
|
4255
|
-
TSAbstractMethodDefinition: check,
|
|
4256
|
-
TSAbstractPropertyDefinition: check,
|
|
4257
|
-
TSParameterProperty: check
|
|
4258
|
-
};
|
|
4259
|
-
return listeners;
|
|
4260
|
-
}
|
|
4261
|
-
});
|
|
4262
6281
|
|
|
4263
|
-
// packages/lint-suite/src/lib/rules/no-
|
|
4264
|
-
import {
|
|
4265
|
-
var
|
|
4266
|
-
|
|
6282
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/utils/export-nodes.util.ts
|
|
6283
|
+
import { TSESTree as TSESTree25 } from "@typescript-eslint/utils";
|
|
6284
|
+
var { AST_NODE_TYPES } = TSESTree25;
|
|
6285
|
+
var exportedName = (exported) => {
|
|
6286
|
+
if (exported.type === AST_NODE_TYPES.Identifier) return exported.name;
|
|
6287
|
+
return exported.value;
|
|
6288
|
+
};
|
|
6289
|
+
var addVariableNodes = (declaration, nodes) => {
|
|
6290
|
+
for (const declarator of declaration.declarations) {
|
|
6291
|
+
const { id } = declarator;
|
|
6292
|
+
if (id.type !== AST_NODE_TYPES.Identifier) continue;
|
|
6293
|
+
nodes.set(id.name, id);
|
|
6294
|
+
}
|
|
6295
|
+
};
|
|
6296
|
+
var addNamedDeclarationNode = (declaration, nodes) => {
|
|
6297
|
+
const { id } = declaration;
|
|
6298
|
+
if (!id) return;
|
|
6299
|
+
if (id.type !== AST_NODE_TYPES.Identifier) return;
|
|
6300
|
+
nodes.set(id.name, id);
|
|
6301
|
+
};
|
|
6302
|
+
var addNamedExportNodes = (statement, nodes) => {
|
|
6303
|
+
for (const specifier of statement.specifiers) {
|
|
6304
|
+
const name = exportedName(specifier.exported);
|
|
6305
|
+
nodes.set(name, specifier);
|
|
6306
|
+
}
|
|
6307
|
+
const { declaration } = statement;
|
|
6308
|
+
if (!declaration) return;
|
|
6309
|
+
if (declaration.type === AST_NODE_TYPES.VariableDeclaration) {
|
|
6310
|
+
addVariableNodes(declaration, nodes);
|
|
6311
|
+
return;
|
|
6312
|
+
}
|
|
6313
|
+
addNamedDeclarationNode(declaration, nodes);
|
|
4267
6314
|
};
|
|
4268
|
-
var
|
|
4269
|
-
|
|
6315
|
+
var exportNodes = (program) => {
|
|
6316
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
6317
|
+
for (const statement of program.body) {
|
|
6318
|
+
if (statement.type === AST_NODE_TYPES.ExportDefaultDeclaration) {
|
|
6319
|
+
nodes.set("default", statement);
|
|
6320
|
+
continue;
|
|
6321
|
+
}
|
|
6322
|
+
if (statement.type !== AST_NODE_TYPES.ExportNamedDeclaration) continue;
|
|
6323
|
+
addNamedExportNodes(statement, nodes);
|
|
6324
|
+
}
|
|
6325
|
+
return nodes;
|
|
4270
6326
|
};
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
6327
|
+
|
|
6328
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/report-unused-exports.ts
|
|
6329
|
+
var reportModule = (context, node) => {
|
|
6330
|
+
const report3 = {
|
|
6331
|
+
node,
|
|
6332
|
+
messageId: "unusedModule"
|
|
6333
|
+
};
|
|
6334
|
+
context.report(report3);
|
|
6335
|
+
};
|
|
6336
|
+
var reportNames = ({
|
|
6337
|
+
context,
|
|
6338
|
+
edges,
|
|
6339
|
+
node,
|
|
6340
|
+
publicNames,
|
|
6341
|
+
used
|
|
6342
|
+
}) => {
|
|
6343
|
+
const nodes = exportNodes(node);
|
|
6344
|
+
const uniqueExports = new Set(edges.exports);
|
|
6345
|
+
for (const name of uniqueExports) {
|
|
6346
|
+
const count = used?.get(name) ?? 0;
|
|
6347
|
+
const isPublic = publicNames?.has(name) ?? false;
|
|
6348
|
+
if (count > 0 || isPublic) continue;
|
|
6349
|
+
const data = { name };
|
|
6350
|
+
const target = nodes.get(name) ?? node;
|
|
6351
|
+
const report3 = {
|
|
6352
|
+
node: target,
|
|
6353
|
+
messageId: "unusedExport",
|
|
6354
|
+
data
|
|
6355
|
+
};
|
|
6356
|
+
context.report(report3);
|
|
6357
|
+
}
|
|
4276
6358
|
};
|
|
4277
|
-
var
|
|
4278
|
-
|
|
6359
|
+
var reportUnusedExports = ({
|
|
6360
|
+
context,
|
|
6361
|
+
isEntry,
|
|
6362
|
+
node,
|
|
6363
|
+
services
|
|
6364
|
+
}) => {
|
|
6365
|
+
const sourceFile = services.esTreeNodeToTSNodeMap.get(node);
|
|
6366
|
+
const aggregate = exportIndex(services.program);
|
|
6367
|
+
const edges = aggregate.byFile.get(sourceFile.fileName);
|
|
6368
|
+
if (!edges) return;
|
|
6369
|
+
if (edges.skipped) return;
|
|
6370
|
+
const hasStarExports = edges.starTargets.length > 0;
|
|
6371
|
+
const hasExports = edges.exports.length > 0 || hasStarExports;
|
|
6372
|
+
if (!hasExports) return;
|
|
6373
|
+
const isImported = aggregate.imported.has(edges.fileName);
|
|
6374
|
+
if (!isImported) {
|
|
6375
|
+
reportModule(context, node);
|
|
6376
|
+
return;
|
|
6377
|
+
}
|
|
6378
|
+
const used = aggregate.usage.get(edges.fileName);
|
|
6379
|
+
const publicIndex = publicExportIndex(aggregate, isEntry);
|
|
6380
|
+
const publicNames = publicIndex.get(edges.fileName);
|
|
6381
|
+
const nameOptions = {
|
|
6382
|
+
context,
|
|
6383
|
+
edges,
|
|
6384
|
+
node,
|
|
6385
|
+
publicNames,
|
|
6386
|
+
used
|
|
6387
|
+
};
|
|
6388
|
+
reportNames(nameOptions);
|
|
6389
|
+
};
|
|
6390
|
+
|
|
6391
|
+
// packages/lint-suite/src/lib/rules/no-unused-exports/no-unused-exports.ts
|
|
6392
|
+
var createRule14 = ESLintUtils14.RuleCreator(
|
|
6393
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#no-unused-exports"
|
|
4279
6394
|
);
|
|
4280
|
-
var
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
if (
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
6395
|
+
var typedParserServices = (context) => {
|
|
6396
|
+
try {
|
|
6397
|
+
const services = ESLintUtils14.getParserServices(context, true);
|
|
6398
|
+
if (!services.program) return void 0;
|
|
6399
|
+
return services;
|
|
6400
|
+
} catch {
|
|
6401
|
+
return void 0;
|
|
4287
6402
|
}
|
|
4288
|
-
return void 0;
|
|
4289
6403
|
};
|
|
4290
|
-
var
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
6404
|
+
var ENTRY_POINT_MATCHERS = /* @__PURE__ */ new WeakMap();
|
|
6405
|
+
var entryPointMatcher = (entryPoints) => {
|
|
6406
|
+
const cached = ENTRY_POINT_MATCHERS.get(entryPoints);
|
|
6407
|
+
if (cached) return cached;
|
|
6408
|
+
const matcher = compileGlobs(entryPoints);
|
|
6409
|
+
ENTRY_POINT_MATCHERS.set(entryPoints, matcher);
|
|
6410
|
+
return matcher;
|
|
6411
|
+
};
|
|
6412
|
+
var no_unused_exports_default = createRule14({
|
|
6413
|
+
name: "no-unused-exports",
|
|
6414
|
+
meta: meta14,
|
|
6415
|
+
defaultOptions: defaultOptions7,
|
|
6416
|
+
create(context, [{ entryPoints }]) {
|
|
6417
|
+
const noListeners = {};
|
|
6418
|
+
const isEntry = entryPointMatcher(entryPoints);
|
|
6419
|
+
const isEntryFile = isEntry(context.filename);
|
|
6420
|
+
if (isEntryFile) return noListeners;
|
|
6421
|
+
const services = typedParserServices(context);
|
|
6422
|
+
if (!services) return noListeners;
|
|
4295
6423
|
const listeners = {
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
if (isAliasBody) return;
|
|
4299
|
-
const enclosingAlias = enclosingTypeAlias(node);
|
|
4300
|
-
if (!enclosingAlias) return;
|
|
4301
|
-
const report = {
|
|
4302
|
-
node,
|
|
4303
|
-
messageId: "inlineObjectType"
|
|
4304
|
-
};
|
|
4305
|
-
context.report(report);
|
|
6424
|
+
Program(node) {
|
|
6425
|
+
reportUnusedExports({ context, isEntry, node, services });
|
|
4306
6426
|
}
|
|
4307
6427
|
};
|
|
4308
6428
|
return listeners;
|
|
@@ -4310,40 +6430,45 @@ var no_inline_object_types_default = createRule4({
|
|
|
4310
6430
|
});
|
|
4311
6431
|
|
|
4312
6432
|
// packages/lint-suite/src/lib/rules/one-line-guard/one-line-guard.ts
|
|
4313
|
-
import { ESLintUtils as
|
|
4314
|
-
var
|
|
6433
|
+
import { ESLintUtils as ESLintUtils15, TSESTree as TSESTree26 } from "@typescript-eslint/utils";
|
|
6434
|
+
var docs15 = {
|
|
4315
6435
|
description: "Require a lone return/throw/continue/break guard to drop its braces when the whole if statement fits on one line"
|
|
4316
6436
|
};
|
|
4317
|
-
var
|
|
6437
|
+
var messages15 = {
|
|
4318
6438
|
oneLineGuard: "Lone {{ keyword }} guard fits within {{ max }} columns; write it on one line without braces."
|
|
4319
6439
|
};
|
|
4320
|
-
var
|
|
6440
|
+
var maxLineLengthSchema = {
|
|
6441
|
+
type: "integer",
|
|
6442
|
+
minimum: 1
|
|
6443
|
+
};
|
|
6444
|
+
var properties8 = {
|
|
6445
|
+
maxLineLength: maxLineLengthSchema
|
|
6446
|
+
};
|
|
6447
|
+
var schema9 = [
|
|
4321
6448
|
{
|
|
4322
6449
|
type: "object",
|
|
4323
|
-
properties:
|
|
4324
|
-
maxLineLength: { type: "integer", minimum: 1 }
|
|
4325
|
-
},
|
|
6450
|
+
properties: properties8,
|
|
4326
6451
|
additionalProperties: false
|
|
4327
6452
|
}
|
|
4328
6453
|
];
|
|
4329
|
-
var
|
|
6454
|
+
var meta15 = {
|
|
4330
6455
|
type: "suggestion",
|
|
4331
|
-
docs:
|
|
6456
|
+
docs: docs15,
|
|
4332
6457
|
fixable: "code",
|
|
4333
|
-
schema:
|
|
4334
|
-
messages:
|
|
6458
|
+
schema: schema9,
|
|
6459
|
+
messages: messages15
|
|
4335
6460
|
};
|
|
4336
|
-
var
|
|
6461
|
+
var createRule15 = ESLintUtils15.RuleCreator(
|
|
4337
6462
|
() => "https://github.com/F0rty-Tw0/lint-suite#one-line-guard"
|
|
4338
6463
|
);
|
|
4339
6464
|
var GUARD_KEYWORDS = /* @__PURE__ */ new Set([
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
6465
|
+
TSESTree26.AST_NODE_TYPES.ReturnStatement,
|
|
6466
|
+
TSESTree26.AST_NODE_TYPES.ThrowStatement,
|
|
6467
|
+
TSESTree26.AST_NODE_TYPES.ContinueStatement,
|
|
6468
|
+
TSESTree26.AST_NODE_TYPES.BreakStatement
|
|
4344
6469
|
]);
|
|
4345
6470
|
var soleStatement = (body) => {
|
|
4346
|
-
if (body.type !==
|
|
6471
|
+
if (body.type !== TSESTree26.AST_NODE_TYPES.BlockStatement) return void 0;
|
|
4347
6472
|
if (body.body.length !== 1) return void 0;
|
|
4348
6473
|
return body.body[0];
|
|
4349
6474
|
};
|
|
@@ -4356,17 +6481,21 @@ var guardStatement = (node) => {
|
|
|
4356
6481
|
return statement;
|
|
4357
6482
|
};
|
|
4358
6483
|
var headText = (node, sourceCode) => {
|
|
4359
|
-
|
|
6484
|
+
const start = node.range[0];
|
|
6485
|
+
const end = node.consequent.range[0];
|
|
6486
|
+
const rawHead = sourceCode.text.slice(start, end);
|
|
6487
|
+
return rawHead.trimEnd();
|
|
4360
6488
|
};
|
|
4361
6489
|
var collapsedLine = (node, head, bodyText, sourceCode) => {
|
|
4362
6490
|
const line = sourceCode.lines[node.loc.start.line - 1] ?? "";
|
|
4363
6491
|
const prefix = line.slice(0, node.loc.start.column);
|
|
4364
6492
|
return `${prefix}${head} ${bodyText}`;
|
|
4365
6493
|
};
|
|
4366
|
-
var
|
|
6494
|
+
var defaultOptions8 = [{ maxLineLength: 80 }];
|
|
6495
|
+
var one_line_guard_default = createRule15({
|
|
4367
6496
|
name: "one-line-guard",
|
|
4368
|
-
meta:
|
|
4369
|
-
defaultOptions:
|
|
6497
|
+
meta: meta15,
|
|
6498
|
+
defaultOptions: defaultOptions8,
|
|
4370
6499
|
create(context, [{ maxLineLength }]) {
|
|
4371
6500
|
const { sourceCode } = context;
|
|
4372
6501
|
const listeners = {
|
|
@@ -4388,13 +6517,13 @@ var one_line_guard_default = createRule5({
|
|
|
4388
6517
|
const keyword = keywordToken.value;
|
|
4389
6518
|
const data = { keyword, max: maxLineLength };
|
|
4390
6519
|
const fix = (fixer) => fixer.replaceText(node.consequent, bodyText);
|
|
4391
|
-
const
|
|
6520
|
+
const report3 = {
|
|
4392
6521
|
node,
|
|
4393
6522
|
messageId: "oneLineGuard",
|
|
4394
6523
|
data,
|
|
4395
6524
|
fix
|
|
4396
6525
|
};
|
|
4397
|
-
context.report(
|
|
6526
|
+
context.report(report3);
|
|
4398
6527
|
}
|
|
4399
6528
|
};
|
|
4400
6529
|
return listeners;
|
|
@@ -4402,45 +6531,46 @@ var one_line_guard_default = createRule5({
|
|
|
4402
6531
|
});
|
|
4403
6532
|
|
|
4404
6533
|
// packages/lint-suite/src/lib/rules/readonly-type-properties/readonly-type-properties.ts
|
|
4405
|
-
import { ESLintUtils as
|
|
4406
|
-
var
|
|
4407
|
-
description: "Require readonly on primitive-typed type and interface properties"
|
|
6534
|
+
import { ESLintUtils as ESLintUtils16, TSESTree as TSESTree27 } from "@typescript-eslint/utils";
|
|
6535
|
+
var docs16 = {
|
|
6536
|
+
description: "Require readonly on primitive-typed type and interface properties, and require array types to be written as T[] instead of readonly T[] or ReadonlyArray<T>"
|
|
4408
6537
|
};
|
|
4409
|
-
var
|
|
4410
|
-
missingReadonly: "Type property '{{ name }}' should be readonly. Disable this rule on the line if mutation is required."
|
|
6538
|
+
var messages16 = {
|
|
6539
|
+
missingReadonly: "Type property '{{ name }}' should be readonly. Disable this rule on the line if mutation is required.",
|
|
6540
|
+
readonlyArray: "Write a readonly array type as T[]."
|
|
4411
6541
|
};
|
|
4412
|
-
var
|
|
6542
|
+
var meta16 = {
|
|
4413
6543
|
type: "suggestion",
|
|
4414
|
-
docs:
|
|
6544
|
+
docs: docs16,
|
|
4415
6545
|
fixable: "code",
|
|
4416
6546
|
schema: [],
|
|
4417
|
-
messages:
|
|
6547
|
+
messages: messages16
|
|
4418
6548
|
};
|
|
4419
|
-
var
|
|
6549
|
+
var createRule16 = ESLintUtils16.RuleCreator(
|
|
4420
6550
|
() => "https://github.com/F0rty-Tw0/lint-suite#readonly-type-properties"
|
|
4421
6551
|
);
|
|
4422
6552
|
var propertyName3 = (node, sourceCode) => {
|
|
4423
|
-
if (node.key.type ===
|
|
6553
|
+
if (node.key.type === TSESTree27.AST_NODE_TYPES.Identifier) {
|
|
4424
6554
|
return node.key.name;
|
|
4425
6555
|
}
|
|
4426
6556
|
return sourceCode.getText(node.key);
|
|
4427
6557
|
};
|
|
4428
6558
|
var PRIMITIVE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
6559
|
+
TSESTree27.AST_NODE_TYPES.TSStringKeyword,
|
|
6560
|
+
TSESTree27.AST_NODE_TYPES.TSNumberKeyword,
|
|
6561
|
+
TSESTree27.AST_NODE_TYPES.TSBooleanKeyword,
|
|
6562
|
+
TSESTree27.AST_NODE_TYPES.TSBigIntKeyword,
|
|
6563
|
+
TSESTree27.AST_NODE_TYPES.TSSymbolKeyword,
|
|
6564
|
+
TSESTree27.AST_NODE_TYPES.TSNullKeyword,
|
|
6565
|
+
TSESTree27.AST_NODE_TYPES.TSUndefinedKeyword
|
|
4436
6566
|
]);
|
|
4437
6567
|
var isPrimitive = (type) => {
|
|
4438
6568
|
const isPrimitiveKeyword = PRIMITIVE_KEYWORDS.has(type.type);
|
|
4439
6569
|
if (isPrimitiveKeyword) return true;
|
|
4440
|
-
if (type.type ===
|
|
6570
|
+
if (type.type === TSESTree27.AST_NODE_TYPES.TSLiteralType || type.type === TSESTree27.AST_NODE_TYPES.TSTemplateLiteralType) {
|
|
4441
6571
|
return true;
|
|
4442
6572
|
}
|
|
4443
|
-
if (type.type ===
|
|
6573
|
+
if (type.type === TSESTree27.AST_NODE_TYPES.TSUnionType || type.type === TSESTree27.AST_NODE_TYPES.TSIntersectionType) {
|
|
4444
6574
|
return type.types.every(isPrimitive);
|
|
4445
6575
|
}
|
|
4446
6576
|
return false;
|
|
@@ -4452,9 +6582,29 @@ var readonlyFix = (node, sourceCode) => {
|
|
|
4452
6582
|
return fixer.insertTextBefore(firstToken, "readonly ");
|
|
4453
6583
|
};
|
|
4454
6584
|
};
|
|
4455
|
-
var
|
|
6585
|
+
var NEEDS_PARENS = /* @__PURE__ */ new Set([
|
|
6586
|
+
TSESTree27.AST_NODE_TYPES.TSUnionType,
|
|
6587
|
+
TSESTree27.AST_NODE_TYPES.TSIntersectionType,
|
|
6588
|
+
TSESTree27.AST_NODE_TYPES.TSFunctionType,
|
|
6589
|
+
TSESTree27.AST_NODE_TYPES.TSConditionalType
|
|
6590
|
+
]);
|
|
6591
|
+
var arrayTypeText = (argument, sourceCode) => {
|
|
6592
|
+
const argumentText = sourceCode.getText(argument);
|
|
6593
|
+
const needsParens = NEEDS_PARENS.has(argument.type);
|
|
6594
|
+
if (needsParens) return `(${argumentText})[]`;
|
|
6595
|
+
return `${argumentText}[]`;
|
|
6596
|
+
};
|
|
6597
|
+
var readonlyArrayReport = (node, fix) => {
|
|
6598
|
+
const report3 = {
|
|
6599
|
+
node,
|
|
6600
|
+
messageId: "readonlyArray",
|
|
6601
|
+
fix
|
|
6602
|
+
};
|
|
6603
|
+
return report3;
|
|
6604
|
+
};
|
|
6605
|
+
var readonly_type_properties_default = createRule16({
|
|
4456
6606
|
name: "readonly-type-properties",
|
|
4457
|
-
meta:
|
|
6607
|
+
meta: meta16,
|
|
4458
6608
|
defaultOptions: [],
|
|
4459
6609
|
create(context) {
|
|
4460
6610
|
const { sourceCode } = context;
|
|
@@ -4466,13 +6616,629 @@ var readonly_type_properties_default = createRule6({
|
|
|
4466
6616
|
const name = propertyName3(node, sourceCode);
|
|
4467
6617
|
const data = { name };
|
|
4468
6618
|
const fix = readonlyFix(node, sourceCode);
|
|
4469
|
-
const
|
|
6619
|
+
const report3 = {
|
|
4470
6620
|
node: node.key,
|
|
4471
6621
|
messageId: "missingReadonly",
|
|
4472
6622
|
data,
|
|
4473
6623
|
fix
|
|
4474
6624
|
};
|
|
4475
|
-
context.report(
|
|
6625
|
+
context.report(report3);
|
|
6626
|
+
},
|
|
6627
|
+
TSTypeOperator(node) {
|
|
6628
|
+
if (node.operator !== "readonly" || !node.typeAnnotation) return;
|
|
6629
|
+
const isArray = node.typeAnnotation.type === TSESTree27.AST_NODE_TYPES.TSArrayType;
|
|
6630
|
+
if (!isArray) return;
|
|
6631
|
+
const replacement = sourceCode.getText(node.typeAnnotation);
|
|
6632
|
+
const fix = (fixer) => fixer.replaceText(node, replacement);
|
|
6633
|
+
context.report(readonlyArrayReport(node, fix));
|
|
6634
|
+
},
|
|
6635
|
+
TSTypeReference(node) {
|
|
6636
|
+
if (node.typeName.type !== TSESTree27.AST_NODE_TYPES.Identifier) return;
|
|
6637
|
+
if (node.typeName.name !== "ReadonlyArray") return;
|
|
6638
|
+
const params = node.typeArguments?.params ?? [];
|
|
6639
|
+
if (params.length !== 1) return;
|
|
6640
|
+
const [argument] = params;
|
|
6641
|
+
if (!argument) return;
|
|
6642
|
+
const replacement = arrayTypeText(argument, sourceCode);
|
|
6643
|
+
const fix = (fixer) => fixer.replaceText(node, replacement);
|
|
6644
|
+
context.report(readonlyArrayReport(node, fix));
|
|
6645
|
+
}
|
|
6646
|
+
};
|
|
6647
|
+
return listeners;
|
|
6648
|
+
}
|
|
6649
|
+
});
|
|
6650
|
+
|
|
6651
|
+
// packages/lint-suite/src/lib/rules/ternary-branch-shape/ternary-branch-shape.ts
|
|
6652
|
+
import { ESLintUtils as ESLintUtils17, TSESTree as TSESTree28 } from "@typescript-eslint/utils";
|
|
6653
|
+
var docs17 = {
|
|
6654
|
+
description: "Require ternary branches to hold only names, literals, or plain member access"
|
|
6655
|
+
};
|
|
6656
|
+
var messages17 = {
|
|
6657
|
+
ternaryBranch: "Ternary {{ branch }} must be a name, literal, or plain member access; name the expression first."
|
|
6658
|
+
};
|
|
6659
|
+
var meta17 = {
|
|
6660
|
+
type: "suggestion",
|
|
6661
|
+
docs: docs17,
|
|
6662
|
+
schema: [],
|
|
6663
|
+
messages: messages17
|
|
6664
|
+
};
|
|
6665
|
+
var createRule17 = ESLintUtils17.RuleCreator(
|
|
6666
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#ternary-branch-shape"
|
|
6667
|
+
);
|
|
6668
|
+
var isPlainMemberAccess = (node) => {
|
|
6669
|
+
let current = node;
|
|
6670
|
+
while (current.type === TSESTree28.AST_NODE_TYPES.MemberExpression) {
|
|
6671
|
+
current = current.object;
|
|
6672
|
+
}
|
|
6673
|
+
return current.type !== TSESTree28.AST_NODE_TYPES.CallExpression;
|
|
6674
|
+
};
|
|
6675
|
+
var isAllowedBranch = (node) => {
|
|
6676
|
+
if (node.type === TSESTree28.AST_NODE_TYPES.Identifier) return true;
|
|
6677
|
+
if (node.type === TSESTree28.AST_NODE_TYPES.Literal) return true;
|
|
6678
|
+
if (node.type === TSESTree28.AST_NODE_TYPES.TemplateLiteral) return true;
|
|
6679
|
+
if (node.type === TSESTree28.AST_NODE_TYPES.UnaryExpression) {
|
|
6680
|
+
return node.argument.type === TSESTree28.AST_NODE_TYPES.Literal;
|
|
6681
|
+
}
|
|
6682
|
+
if (node.type === TSESTree28.AST_NODE_TYPES.MemberExpression) {
|
|
6683
|
+
return isPlainMemberAccess(node);
|
|
6684
|
+
}
|
|
6685
|
+
return false;
|
|
6686
|
+
};
|
|
6687
|
+
var ternary_branch_shape_default = createRule17({
|
|
6688
|
+
name: "ternary-branch-shape",
|
|
6689
|
+
meta: meta17,
|
|
6690
|
+
defaultOptions: [],
|
|
6691
|
+
create(context) {
|
|
6692
|
+
const check = (node, branch) => {
|
|
6693
|
+
const isAllowed = isAllowedBranch(node);
|
|
6694
|
+
if (isAllowed) return;
|
|
6695
|
+
const data = { branch };
|
|
6696
|
+
const report3 = {
|
|
6697
|
+
node,
|
|
6698
|
+
messageId: "ternaryBranch",
|
|
6699
|
+
data
|
|
6700
|
+
};
|
|
6701
|
+
context.report(report3);
|
|
6702
|
+
};
|
|
6703
|
+
const listeners = {
|
|
6704
|
+
ConditionalExpression(node) {
|
|
6705
|
+
check(node.consequent, "consequent");
|
|
6706
|
+
check(node.alternate, "alternate");
|
|
6707
|
+
}
|
|
6708
|
+
};
|
|
6709
|
+
return listeners;
|
|
6710
|
+
}
|
|
6711
|
+
});
|
|
6712
|
+
|
|
6713
|
+
// packages/lint-suite/src/lib/rules/test-file-shape/test-file-shape.ts
|
|
6714
|
+
import { ESLintUtils as ESLintUtils18 } from "@typescript-eslint/utils";
|
|
6715
|
+
|
|
6716
|
+
// packages/lint-suite/src/lib/rules/test-file-shape/common/test-file-shape.const.ts
|
|
6717
|
+
var docs18 = {
|
|
6718
|
+
description: "Restrict test-support file shapes and enforce naming and typing on stub and mock exports"
|
|
6719
|
+
};
|
|
6720
|
+
var messages18 = {
|
|
6721
|
+
forbiddenTestFile: "Test-support file shape '{{ shape }}' is not allowed; test-only files live under test/stubs, test/mocks, test/fixtures, or test/utils.",
|
|
6722
|
+
stubName: "Stub export '{{ name }}' must be named in SCREAMING_SNAKE_CASE ending in '_STUB'.",
|
|
6723
|
+
stubType: "Stub export '{{ name }}' is missing an explicit type annotation.",
|
|
6724
|
+
mockName: "Mock export '{{ name }}' must be a camelCase name ending in 'Mock'.",
|
|
6725
|
+
mockFactory: "Mock export '{{ name }}' must be a function that returns fresh spies.",
|
|
6726
|
+
mockReturnType: "Mock export '{{ name }}' is missing an explicit return type."
|
|
6727
|
+
};
|
|
6728
|
+
var meta18 = {
|
|
6729
|
+
type: "problem",
|
|
6730
|
+
docs: docs18,
|
|
6731
|
+
schema: [],
|
|
6732
|
+
messages: messages18
|
|
6733
|
+
};
|
|
6734
|
+
var defaultOptions9 = [];
|
|
6735
|
+
var FORBIDDEN_SHAPES = [
|
|
6736
|
+
{ pattern: /\.spec-support\.ts$/, shape: ".spec-support.ts" },
|
|
6737
|
+
{ pattern: /\.spec-helper\.ts$/, shape: ".spec-helper.ts" },
|
|
6738
|
+
{ pattern: /\.test-utils\.ts$/, shape: ".test-utils.ts" },
|
|
6739
|
+
{ pattern: /-fixture\.ts$/, shape: "-fixture.ts" },
|
|
6740
|
+
{ pattern: /\/__mocks__\//, shape: "__mocks__/" },
|
|
6741
|
+
{ pattern: /\/helpers\//, shape: "helpers/" },
|
|
6742
|
+
{ pattern: /\/common\/stubs\//, shape: "common/stubs/" }
|
|
6743
|
+
];
|
|
6744
|
+
var STUB_FILE_PATTERN = /\/test\/stubs\/.+\.stub\.ts$/;
|
|
6745
|
+
var MOCK_FILE_PATTERN = /\/test\/mocks\/.+\.mock\.ts$/;
|
|
6746
|
+
var SPEC_UTIL_FILE_PATTERN = /\/test\/utils\/.+\.spec\.util\.ts$/;
|
|
6747
|
+
var TESTING_LIB_SEGMENT = "/testing/";
|
|
6748
|
+
var TEST_FIXTURES_SEGMENT = "/test/fixtures/";
|
|
6749
|
+
var FIXTURES_SEGMENT = /\/fixtures\//;
|
|
6750
|
+
var STUB_NAME_PATTERN = /^[A-Z0-9]+(_[A-Z0-9]+)*_STUB$/;
|
|
6751
|
+
var MOCK_NAME_PATTERN = /^[a-z][A-Za-z0-9]*Mock$/;
|
|
6752
|
+
|
|
6753
|
+
// packages/lint-suite/src/lib/rules/test-file-shape/mock-exports.ts
|
|
6754
|
+
import { TSESTree as TSESTree29 } from "@typescript-eslint/utils";
|
|
6755
|
+
var isMockFile = (filename) => {
|
|
6756
|
+
const isUnderTestMocks = MOCK_FILE_PATTERN.test(filename);
|
|
6757
|
+
if (isUnderTestMocks) return true;
|
|
6758
|
+
const isUnderTestingLib2 = filename.includes(TESTING_LIB_SEGMENT);
|
|
6759
|
+
return isUnderTestingLib2 && filename.endsWith(".mock.ts");
|
|
6760
|
+
};
|
|
6761
|
+
var isMockIdentifier = (id) => id.type === TSESTree29.AST_NODE_TYPES.Identifier;
|
|
6762
|
+
var isMockFunction = (init) => {
|
|
6763
|
+
if (init === null) return false;
|
|
6764
|
+
const { type } = init;
|
|
6765
|
+
if (type === TSESTree29.AST_NODE_TYPES.ArrowFunctionExpression) return true;
|
|
6766
|
+
return type === TSESTree29.AST_NODE_TYPES.FunctionExpression;
|
|
6767
|
+
};
|
|
6768
|
+
var isConstVariableDeclaration = (declaration) => {
|
|
6769
|
+
if (declaration.type !== TSESTree29.AST_NODE_TYPES.VariableDeclaration) {
|
|
6770
|
+
return false;
|
|
6771
|
+
}
|
|
6772
|
+
return declaration.kind === "const";
|
|
6773
|
+
};
|
|
6774
|
+
var declarationName = (context, declaration) => {
|
|
6775
|
+
if (declaration.type === TSESTree29.AST_NODE_TYPES.VariableDeclaration) {
|
|
6776
|
+
const [firstDeclarator] = declaration.declarations;
|
|
6777
|
+
return context.sourceCode.getText(firstDeclarator.id);
|
|
6778
|
+
}
|
|
6779
|
+
if ("id" in declaration && declaration.id !== null) {
|
|
6780
|
+
return context.sourceCode.getText(declaration.id);
|
|
6781
|
+
}
|
|
6782
|
+
return context.sourceCode.getText(declaration);
|
|
6783
|
+
};
|
|
6784
|
+
var reportMock = (context, node, messageId, name) => {
|
|
6785
|
+
const data = { name };
|
|
6786
|
+
const descriptor = {
|
|
6787
|
+
node,
|
|
6788
|
+
messageId,
|
|
6789
|
+
data
|
|
6790
|
+
};
|
|
6791
|
+
context.report(descriptor);
|
|
6792
|
+
};
|
|
6793
|
+
var checkMockDeclarator = (context, node) => {
|
|
6794
|
+
const fallbackName = context.sourceCode.getText(node.id);
|
|
6795
|
+
const name = isMockIdentifier(node.id) ? node.id.name : fallbackName;
|
|
6796
|
+
const hasValidPattern = MOCK_NAME_PATTERN.test(name);
|
|
6797
|
+
const hasValidName = isMockIdentifier(node.id) && hasValidPattern;
|
|
6798
|
+
if (!hasValidName) {
|
|
6799
|
+
reportMock(context, node.id, "mockName", name);
|
|
6800
|
+
}
|
|
6801
|
+
if (!isMockFunction(node.init)) {
|
|
6802
|
+
reportMock(context, node.id, "mockFactory", name);
|
|
6803
|
+
return;
|
|
6804
|
+
}
|
|
6805
|
+
const hasReturnType = node.init.returnType !== void 0;
|
|
6806
|
+
if (hasReturnType) return;
|
|
6807
|
+
reportMock(context, node.id, "mockReturnType", name);
|
|
6808
|
+
};
|
|
6809
|
+
var mockExportListeners = (context) => {
|
|
6810
|
+
const listeners = {
|
|
6811
|
+
ExportNamedDeclaration(node) {
|
|
6812
|
+
if (node.declaration === null) return;
|
|
6813
|
+
const { declaration } = node;
|
|
6814
|
+
const isConstVar = isConstVariableDeclaration(declaration);
|
|
6815
|
+
if (!isConstVar) {
|
|
6816
|
+
const name = declarationName(context, declaration);
|
|
6817
|
+
reportMock(context, node, "mockFactory", name);
|
|
6818
|
+
return;
|
|
6819
|
+
}
|
|
6820
|
+
for (const declarator of declaration.declarations) {
|
|
6821
|
+
checkMockDeclarator(context, declarator);
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
};
|
|
6825
|
+
return listeners;
|
|
6826
|
+
};
|
|
6827
|
+
|
|
6828
|
+
// packages/lint-suite/src/lib/rules/test-file-shape/stub-exports.ts
|
|
6829
|
+
import { TSESTree as TSESTree30 } from "@typescript-eslint/utils";
|
|
6830
|
+
var isStubFile = (filename) => {
|
|
6831
|
+
const isUnderTestStubs = STUB_FILE_PATTERN.test(filename);
|
|
6832
|
+
if (isUnderTestStubs) return true;
|
|
6833
|
+
const isUnderTestingLib2 = filename.includes(TESTING_LIB_SEGMENT);
|
|
6834
|
+
return isUnderTestingLib2 && filename.endsWith(".stub.ts");
|
|
6835
|
+
};
|
|
6836
|
+
var isStubIdentifier = (id) => id.type === TSESTree30.AST_NODE_TYPES.Identifier;
|
|
6837
|
+
var checkStubDeclarator = (context, node) => {
|
|
6838
|
+
const fallbackName = context.sourceCode.getText(node.id);
|
|
6839
|
+
const name = isStubIdentifier(node.id) ? node.id.name : fallbackName;
|
|
6840
|
+
const hasValidPattern = STUB_NAME_PATTERN.test(name);
|
|
6841
|
+
const hasValidName = isStubIdentifier(node.id) && hasValidPattern;
|
|
6842
|
+
if (!hasValidName) {
|
|
6843
|
+
const nameData = { name };
|
|
6844
|
+
const nameReport = {
|
|
6845
|
+
node: node.id,
|
|
6846
|
+
messageId: "stubName",
|
|
6847
|
+
data: nameData
|
|
6848
|
+
};
|
|
6849
|
+
context.report(nameReport);
|
|
6850
|
+
}
|
|
6851
|
+
const hasTypeAnnotation = node.id.typeAnnotation !== void 0;
|
|
6852
|
+
if (hasTypeAnnotation) return;
|
|
6853
|
+
const typeData = { name };
|
|
6854
|
+
const typeReport = {
|
|
6855
|
+
node: node.id,
|
|
6856
|
+
messageId: "stubType",
|
|
6857
|
+
data: typeData
|
|
6858
|
+
};
|
|
6859
|
+
context.report(typeReport);
|
|
6860
|
+
};
|
|
6861
|
+
var stubExportListeners = (context) => {
|
|
6862
|
+
const listeners = {
|
|
6863
|
+
"ExportNamedDeclaration > VariableDeclaration > VariableDeclarator"(node) {
|
|
6864
|
+
checkStubDeclarator(context, node);
|
|
6865
|
+
}
|
|
6866
|
+
};
|
|
6867
|
+
return listeners;
|
|
6868
|
+
};
|
|
6869
|
+
|
|
6870
|
+
// packages/lint-suite/src/lib/rules/test-file-shape/test-file-shape.ts
|
|
6871
|
+
var createRule18 = ESLintUtils18.RuleCreator(
|
|
6872
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#test-file-shape"
|
|
6873
|
+
);
|
|
6874
|
+
var isUnderTestingLib = (filename) => filename.includes(TESTING_LIB_SEGMENT);
|
|
6875
|
+
var misplacedFixtures = (filename) => {
|
|
6876
|
+
const hasFixturesSegment = FIXTURES_SEGMENT.test(filename);
|
|
6877
|
+
if (!hasFixturesSegment) return void 0;
|
|
6878
|
+
const isTestFixtures = filename.includes(TEST_FIXTURES_SEGMENT);
|
|
6879
|
+
if (isTestFixtures) return void 0;
|
|
6880
|
+
return "fixtures/ outside test/fixtures/";
|
|
6881
|
+
};
|
|
6882
|
+
var misplacedShape = (filename) => {
|
|
6883
|
+
const isTestingLib = isUnderTestingLib(filename);
|
|
6884
|
+
if (isTestingLib) return void 0;
|
|
6885
|
+
const isStub = filename.endsWith(".stub.ts");
|
|
6886
|
+
const isPlacedStub = STUB_FILE_PATTERN.test(filename);
|
|
6887
|
+
if (isStub && !isPlacedStub) return ".stub.ts outside test/stubs/";
|
|
6888
|
+
const isMock = filename.endsWith(".mock.ts");
|
|
6889
|
+
const isPlacedMock = MOCK_FILE_PATTERN.test(filename);
|
|
6890
|
+
if (isMock && !isPlacedMock) return ".mock.ts outside test/mocks/";
|
|
6891
|
+
const isSpecUtil = filename.endsWith(".spec.util.ts");
|
|
6892
|
+
const isPlacedSpecUtil = SPEC_UTIL_FILE_PATTERN.test(filename);
|
|
6893
|
+
if (isSpecUtil && !isPlacedSpecUtil) {
|
|
6894
|
+
return ".spec.util.ts outside test/utils/";
|
|
6895
|
+
}
|
|
6896
|
+
return misplacedFixtures(filename);
|
|
6897
|
+
};
|
|
6898
|
+
var forbiddenShape = (filename) => {
|
|
6899
|
+
const match = FORBIDDEN_SHAPES.find((entry) => entry.pattern.test(filename));
|
|
6900
|
+
if (match) return match.shape;
|
|
6901
|
+
return misplacedShape(filename);
|
|
6902
|
+
};
|
|
6903
|
+
var forbiddenTestFileListeners = (context, shape) => {
|
|
6904
|
+
const listeners = {
|
|
6905
|
+
Program(node) {
|
|
6906
|
+
const data = { shape };
|
|
6907
|
+
const report3 = {
|
|
6908
|
+
node,
|
|
6909
|
+
messageId: "forbiddenTestFile",
|
|
6910
|
+
data
|
|
6911
|
+
};
|
|
6912
|
+
context.report(report3);
|
|
6913
|
+
}
|
|
6914
|
+
};
|
|
6915
|
+
return listeners;
|
|
6916
|
+
};
|
|
6917
|
+
var test_file_shape_default = createRule18({
|
|
6918
|
+
name: "test-file-shape",
|
|
6919
|
+
meta: meta18,
|
|
6920
|
+
defaultOptions: defaultOptions9,
|
|
6921
|
+
create(context) {
|
|
6922
|
+
const filename = context.filename.replaceAll("\\", "/");
|
|
6923
|
+
const shape = forbiddenShape(filename);
|
|
6924
|
+
if (shape) return forbiddenTestFileListeners(context, shape);
|
|
6925
|
+
const isStub = isStubFile(filename);
|
|
6926
|
+
if (isStub) return stubExportListeners(context);
|
|
6927
|
+
const isMock = isMockFile(filename);
|
|
6928
|
+
if (isMock) return mockExportListeners(context);
|
|
6929
|
+
const noListeners = {};
|
|
6930
|
+
return noListeners;
|
|
6931
|
+
}
|
|
6932
|
+
});
|
|
6933
|
+
|
|
6934
|
+
// packages/lint-suite/src/lib/rules/type-placement/type-placement.ts
|
|
6935
|
+
import { ESLintUtils as ESLintUtils19, TSESTree as TSESTree31 } from "@typescript-eslint/utils";
|
|
6936
|
+
|
|
6937
|
+
// packages/lint-suite/src/lib/rules/type-placement/common/type-placement.const.ts
|
|
6938
|
+
var DEFAULT_INTERNAL_PATTERNS = [];
|
|
6939
|
+
var docs19 = {
|
|
6940
|
+
description: "Require types to live in common/*.type.ts files, *.const.ts files to export only consts, and type-only imports to come from *.type.ts files or a common barrel"
|
|
6941
|
+
};
|
|
6942
|
+
var messages19 = {
|
|
6943
|
+
typeOutsideTypeFile: "Exported type '{{ name }}' belongs in a common/*.type.ts or test/common/*.type.ts file, not here.",
|
|
6944
|
+
valueInTypeFile: "A *.type.ts file may only export type aliases and interfaces.",
|
|
6945
|
+
nonConstInConstFile: "A *.const.ts file may only export const variable declarations.",
|
|
6946
|
+
typeImportNotFromTypeFile: "Type-only import from '{{ source }}' must come from a *.type.ts file or a common barrel."
|
|
6947
|
+
};
|
|
6948
|
+
var stringItems2 = { type: "string" };
|
|
6949
|
+
var internalPatternsSchema = {
|
|
6950
|
+
type: "array",
|
|
6951
|
+
items: stringItems2,
|
|
6952
|
+
description: "Regular expressions matching internal, non-relative import sources that must point at a *.type.ts file. Empty by default: a workspace alias resolves to a library entry point, never to a type file."
|
|
6953
|
+
};
|
|
6954
|
+
var properties9 = {
|
|
6955
|
+
internalPatterns: internalPatternsSchema
|
|
6956
|
+
};
|
|
6957
|
+
var optionsSchema8 = {
|
|
6958
|
+
type: "object",
|
|
6959
|
+
properties: properties9,
|
|
6960
|
+
additionalProperties: false
|
|
6961
|
+
};
|
|
6962
|
+
var schema10 = [optionsSchema8];
|
|
6963
|
+
var meta19 = {
|
|
6964
|
+
type: "problem",
|
|
6965
|
+
docs: docs19,
|
|
6966
|
+
schema: schema10,
|
|
6967
|
+
messages: messages19
|
|
6968
|
+
};
|
|
6969
|
+
var defaultOptions10 = [
|
|
6970
|
+
{ internalPatterns: DEFAULT_INTERNAL_PATTERNS }
|
|
6971
|
+
];
|
|
6972
|
+
|
|
6973
|
+
// packages/lint-suite/src/lib/rules/type-placement/type-placement.ts
|
|
6974
|
+
var TYPE_FILE_SUFFIX = ".type.ts";
|
|
6975
|
+
var CONST_FILE_SUFFIX = ".const.ts";
|
|
6976
|
+
var COMMON_SEGMENT = "/common/";
|
|
6977
|
+
var EXEMPT_FILE = /\.(spec|stub|d)\.ts$/;
|
|
6978
|
+
var STATE_TYPE_FILE = /(^|[./])state\.type\.ts$/;
|
|
6979
|
+
var FIXTURES_SEGMENT2 = "/fixtures/";
|
|
6980
|
+
var TYPE_FILE_SEGMENT = /\.type(\.ts)?$/;
|
|
6981
|
+
var COMMON_BARREL = /(^|\/)common(\/index(\.ts)?)?$/;
|
|
6982
|
+
var createRule19 = ESLintUtils19.RuleCreator(
|
|
6983
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#type-placement"
|
|
6984
|
+
);
|
|
6985
|
+
var isExemptFile = (filename) => {
|
|
6986
|
+
const isExemptSuffix = EXEMPT_FILE.test(filename);
|
|
6987
|
+
if (isExemptSuffix) return true;
|
|
6988
|
+
const isStateTypeFile = STATE_TYPE_FILE.test(filename);
|
|
6989
|
+
if (isStateTypeFile) return true;
|
|
6990
|
+
return filename.includes(FIXTURES_SEGMENT2);
|
|
6991
|
+
};
|
|
6992
|
+
var lastSegment = (source) => {
|
|
6993
|
+
const segments = source.split("/");
|
|
6994
|
+
return segments[segments.length - 1] ?? source;
|
|
6995
|
+
};
|
|
6996
|
+
var isTypeOnlySource = (source) => {
|
|
6997
|
+
const isCommonBarrel = COMMON_BARREL.test(source);
|
|
6998
|
+
if (isCommonBarrel) return true;
|
|
6999
|
+
return TYPE_FILE_SEGMENT.test(lastSegment(source));
|
|
7000
|
+
};
|
|
7001
|
+
var isInternalSource = (source, patterns) => {
|
|
7002
|
+
const isRelative = source.startsWith(".");
|
|
7003
|
+
if (isRelative) return true;
|
|
7004
|
+
return patterns.some((pattern) => pattern.test(source));
|
|
7005
|
+
};
|
|
7006
|
+
var isTypeDeclaration = (declaration) => {
|
|
7007
|
+
const { type } = declaration;
|
|
7008
|
+
if (type === TSESTree31.AST_NODE_TYPES.TSTypeAliasDeclaration) return true;
|
|
7009
|
+
return type === TSESTree31.AST_NODE_TYPES.TSInterfaceDeclaration;
|
|
7010
|
+
};
|
|
7011
|
+
var isConstVariableDeclaration2 = (declaration) => {
|
|
7012
|
+
if (declaration.type !== TSESTree31.AST_NODE_TYPES.VariableDeclaration) {
|
|
7013
|
+
return false;
|
|
7014
|
+
}
|
|
7015
|
+
return declaration.kind === "const";
|
|
7016
|
+
};
|
|
7017
|
+
var report = (context, node, messageId, data) => {
|
|
7018
|
+
const base2 = { node, messageId };
|
|
7019
|
+
if (data === void 0) {
|
|
7020
|
+
context.report(base2);
|
|
7021
|
+
return;
|
|
7022
|
+
}
|
|
7023
|
+
const withData = {
|
|
7024
|
+
node,
|
|
7025
|
+
messageId,
|
|
7026
|
+
data
|
|
7027
|
+
};
|
|
7028
|
+
context.report(withData);
|
|
7029
|
+
};
|
|
7030
|
+
var handleExport = (context, node, shape) => {
|
|
7031
|
+
if (node.declaration === null) return;
|
|
7032
|
+
const { declaration } = node;
|
|
7033
|
+
if (isTypeDeclaration(declaration)) {
|
|
7034
|
+
const isCommonTypeFile = shape.isTypeFile && shape.inCommon;
|
|
7035
|
+
if (!isCommonTypeFile) {
|
|
7036
|
+
const data = { name: declaration.id.name };
|
|
7037
|
+
report(context, node, "typeOutsideTypeFile", data);
|
|
7038
|
+
}
|
|
7039
|
+
} else if (shape.isTypeFile) {
|
|
7040
|
+
report(context, node, "valueInTypeFile", void 0);
|
|
7041
|
+
}
|
|
7042
|
+
const isConstVar = isConstVariableDeclaration2(declaration);
|
|
7043
|
+
if (shape.isConstFile && !isConstVar) {
|
|
7044
|
+
report(context, node, "nonConstInConstFile", void 0);
|
|
7045
|
+
}
|
|
7046
|
+
};
|
|
7047
|
+
var handleTypeImport = (context, node, patterns) => {
|
|
7048
|
+
const { value: source } = node.source;
|
|
7049
|
+
const isInternal = isInternalSource(source, patterns);
|
|
7050
|
+
if (!isInternal) return;
|
|
7051
|
+
const isTypeSource = isTypeOnlySource(source);
|
|
7052
|
+
if (isTypeSource) return;
|
|
7053
|
+
report(context, node, "typeImportNotFromTypeFile", { source });
|
|
7054
|
+
};
|
|
7055
|
+
var type_placement_default = createRule19({
|
|
7056
|
+
name: "type-placement",
|
|
7057
|
+
meta: meta19,
|
|
7058
|
+
defaultOptions: defaultOptions10,
|
|
7059
|
+
create(context, [{ internalPatterns }]) {
|
|
7060
|
+
const filename = context.filename.replaceAll("\\", "/");
|
|
7061
|
+
const isExempt = isExemptFile(filename);
|
|
7062
|
+
if (isExempt) {
|
|
7063
|
+
const noListeners = {};
|
|
7064
|
+
return noListeners;
|
|
7065
|
+
}
|
|
7066
|
+
const isTypeFile = filename.endsWith(TYPE_FILE_SUFFIX);
|
|
7067
|
+
const isConstFile = filename.endsWith(CONST_FILE_SUFFIX);
|
|
7068
|
+
const inCommon = filename.includes(COMMON_SEGMENT);
|
|
7069
|
+
const shape = { isTypeFile, isConstFile, inCommon };
|
|
7070
|
+
const internalPatternRegexes = internalPatterns.map(toRegExp);
|
|
7071
|
+
const listeners = {
|
|
7072
|
+
ExportNamedDeclaration(node) {
|
|
7073
|
+
handleExport(context, node, shape);
|
|
7074
|
+
},
|
|
7075
|
+
'ImportDeclaration[importKind="type"]'(node) {
|
|
7076
|
+
handleTypeImport(context, node, internalPatternRegexes);
|
|
7077
|
+
}
|
|
7078
|
+
};
|
|
7079
|
+
return listeners;
|
|
7080
|
+
}
|
|
7081
|
+
});
|
|
7082
|
+
|
|
7083
|
+
// packages/lint-suite/src/lib/rules/util-purity/util-purity.ts
|
|
7084
|
+
import { ESLintUtils as ESLintUtils20, TSESTree as TSESTree32 } from "@typescript-eslint/utils";
|
|
7085
|
+
|
|
7086
|
+
// packages/lint-suite/src/lib/rules/util-purity/common/util-purity.const.ts
|
|
7087
|
+
var DEFAULT_BANNED_MODULES = [
|
|
7088
|
+
"node:fs",
|
|
7089
|
+
"fs",
|
|
7090
|
+
"node:fs/promises",
|
|
7091
|
+
"fs/promises",
|
|
7092
|
+
"node:child_process",
|
|
7093
|
+
"child_process",
|
|
7094
|
+
"node:os",
|
|
7095
|
+
"os",
|
|
7096
|
+
"node:process",
|
|
7097
|
+
"process",
|
|
7098
|
+
"node:http",
|
|
7099
|
+
"http",
|
|
7100
|
+
"node:https",
|
|
7101
|
+
"https",
|
|
7102
|
+
"node:net",
|
|
7103
|
+
"net",
|
|
7104
|
+
"node:worker_threads",
|
|
7105
|
+
"worker_threads"
|
|
7106
|
+
];
|
|
7107
|
+
var docs20 = {
|
|
7108
|
+
description: "Disallow impure, I/O-touching, or nondeterministic code inside *.util.ts files"
|
|
7109
|
+
};
|
|
7110
|
+
var messages20 = {
|
|
7111
|
+
impureImport: "Importing '{{ source }}' makes this util impure; utils must not perform I/O.",
|
|
7112
|
+
moduleLet: "Module-level `let` creates mutable shared state; utils must be pure.",
|
|
7113
|
+
moduleState: "Module-level Map/Set/WeakMap/WeakSet is mutable shared state; utils must be pure.",
|
|
7114
|
+
ambientAccess: "Accessing ambient '{{ name }}' makes this util impure and environment-dependent.",
|
|
7115
|
+
nondeterministic: "'{{ name }}' is nondeterministic; a util must return the same output for the same input.",
|
|
7116
|
+
impureCall: "Calling '{{ name }}' makes this util impure or side-effecting."
|
|
7117
|
+
};
|
|
7118
|
+
var stringItems3 = { type: "string" };
|
|
7119
|
+
var bannedModulesSchema = {
|
|
7120
|
+
type: "array",
|
|
7121
|
+
items: stringItems3,
|
|
7122
|
+
description: "Import sources that are forbidden inside util files."
|
|
7123
|
+
};
|
|
7124
|
+
var properties10 = {
|
|
7125
|
+
bannedModules: bannedModulesSchema
|
|
7126
|
+
};
|
|
7127
|
+
var optionsSchema9 = {
|
|
7128
|
+
type: "object",
|
|
7129
|
+
properties: properties10,
|
|
7130
|
+
additionalProperties: false
|
|
7131
|
+
};
|
|
7132
|
+
var schema11 = [optionsSchema9];
|
|
7133
|
+
var meta20 = {
|
|
7134
|
+
type: "problem",
|
|
7135
|
+
docs: docs20,
|
|
7136
|
+
schema: schema11,
|
|
7137
|
+
messages: messages20
|
|
7138
|
+
};
|
|
7139
|
+
var defaultOptions11 = [
|
|
7140
|
+
{ bannedModules: DEFAULT_BANNED_MODULES }
|
|
7141
|
+
];
|
|
7142
|
+
var MODULE_LET_SELECTOR = 'Program > VariableDeclaration[kind="let"]';
|
|
7143
|
+
var MODULE_STATE_SELECTOR = "Program > VariableDeclaration > VariableDeclarator > NewExpression[callee.name=/^(Map|Set|WeakMap|WeakSet)$/]";
|
|
7144
|
+
var AMBIENT_SELECTOR = "MemberExpression[object.name=/^(process|globalThis|window|document|localStorage|sessionStorage|console)$/]";
|
|
7145
|
+
var NONDETERMINISTIC_SELECTORS = [
|
|
7146
|
+
'MemberExpression[object.name="Date"][property.name="now"]',
|
|
7147
|
+
'MemberExpression[object.name="Math"][property.name="random"]',
|
|
7148
|
+
'MemberExpression[object.name="performance"][property.name="now"]',
|
|
7149
|
+
'MemberExpression[object.name="crypto"][property.name="randomUUID"]'
|
|
7150
|
+
];
|
|
7151
|
+
var NONDETERMINISTIC_SELECTOR = NONDETERMINISTIC_SELECTORS.join(", ");
|
|
7152
|
+
var CALL_SELECTOR = "CallExpression[callee.name=/^(setTimeout|setInterval|fetch|inject|require)$/]";
|
|
7153
|
+
|
|
7154
|
+
// packages/lint-suite/src/lib/rules/util-purity/util-purity.ts
|
|
7155
|
+
var UTIL_FILE = /\/utils\/[^/]+\.util\.ts$/;
|
|
7156
|
+
var TEST_SEGMENT = "/test/";
|
|
7157
|
+
var TESTING_SEGMENT = "/testing/";
|
|
7158
|
+
var createRule20 = ESLintUtils20.RuleCreator(
|
|
7159
|
+
() => "https://github.com/F0rty-Tw0/lint-suite#util-purity"
|
|
7160
|
+
);
|
|
7161
|
+
var isUtilFile = (filename) => {
|
|
7162
|
+
const isUtilPath = UTIL_FILE.test(filename);
|
|
7163
|
+
if (!isUtilPath) return false;
|
|
7164
|
+
const isUnderTest = filename.includes(TEST_SEGMENT) || filename.includes(TESTING_SEGMENT);
|
|
7165
|
+
return !isUnderTest;
|
|
7166
|
+
};
|
|
7167
|
+
var identifierName = (node) => {
|
|
7168
|
+
if (node.type !== TSESTree32.AST_NODE_TYPES.Identifier) return void 0;
|
|
7169
|
+
return node.name;
|
|
7170
|
+
};
|
|
7171
|
+
var memberName3 = (node) => {
|
|
7172
|
+
const objectName = identifierName(node.object);
|
|
7173
|
+
if (objectName === void 0) return void 0;
|
|
7174
|
+
const propertyName4 = identifierName(node.property);
|
|
7175
|
+
if (propertyName4 === void 0) return void 0;
|
|
7176
|
+
return `${objectName}.${propertyName4}`;
|
|
7177
|
+
};
|
|
7178
|
+
var report2 = (context, node, messageId, data) => {
|
|
7179
|
+
const base2 = { node, messageId };
|
|
7180
|
+
if (data === void 0) {
|
|
7181
|
+
context.report(base2);
|
|
7182
|
+
return;
|
|
7183
|
+
}
|
|
7184
|
+
const withData = {
|
|
7185
|
+
node,
|
|
7186
|
+
messageId,
|
|
7187
|
+
data
|
|
7188
|
+
};
|
|
7189
|
+
context.report(withData);
|
|
7190
|
+
};
|
|
7191
|
+
var reportAmbient = (context, node) => {
|
|
7192
|
+
const name = identifierName(node.object);
|
|
7193
|
+
if (name === void 0) return;
|
|
7194
|
+
report2(context, node, "ambientAccess", { name });
|
|
7195
|
+
};
|
|
7196
|
+
var reportNondeterministic = (context, node) => {
|
|
7197
|
+
const name = memberName3(node);
|
|
7198
|
+
if (name === void 0) return;
|
|
7199
|
+
report2(context, node, "nondeterministic", { name });
|
|
7200
|
+
};
|
|
7201
|
+
var reportCall = (context, node) => {
|
|
7202
|
+
const name = identifierName(node.callee);
|
|
7203
|
+
if (name === void 0) return;
|
|
7204
|
+
report2(context, node, "impureCall", { name });
|
|
7205
|
+
};
|
|
7206
|
+
var handleImport = (context, node, banned) => {
|
|
7207
|
+
const { source } = node;
|
|
7208
|
+
const isBanned = banned.has(source.value);
|
|
7209
|
+
if (!isBanned) return;
|
|
7210
|
+
report2(context, node, "impureImport", { source: source.value });
|
|
7211
|
+
};
|
|
7212
|
+
var util_purity_default = createRule20({
|
|
7213
|
+
name: "util-purity",
|
|
7214
|
+
meta: meta20,
|
|
7215
|
+
defaultOptions: defaultOptions11,
|
|
7216
|
+
create(context, [{ bannedModules }]) {
|
|
7217
|
+
const filename = context.filename.replaceAll("\\", "/");
|
|
7218
|
+
const isUtil = isUtilFile(filename);
|
|
7219
|
+
if (!isUtil) {
|
|
7220
|
+
const noListeners = {};
|
|
7221
|
+
return noListeners;
|
|
7222
|
+
}
|
|
7223
|
+
const banned = new Set(bannedModules);
|
|
7224
|
+
const listeners = {
|
|
7225
|
+
ImportDeclaration(node) {
|
|
7226
|
+
handleImport(context, node, banned);
|
|
7227
|
+
},
|
|
7228
|
+
[MODULE_LET_SELECTOR](node) {
|
|
7229
|
+
report2(context, node, "moduleLet", void 0);
|
|
7230
|
+
},
|
|
7231
|
+
[MODULE_STATE_SELECTOR](node) {
|
|
7232
|
+
report2(context, node, "moduleState", void 0);
|
|
7233
|
+
},
|
|
7234
|
+
[AMBIENT_SELECTOR](node) {
|
|
7235
|
+
reportAmbient(context, node);
|
|
7236
|
+
},
|
|
7237
|
+
[NONDETERMINISTIC_SELECTOR](node) {
|
|
7238
|
+
reportNondeterministic(context, node);
|
|
7239
|
+
},
|
|
7240
|
+
[CALL_SELECTOR](node) {
|
|
7241
|
+
reportCall(context, node);
|
|
4476
7242
|
}
|
|
4477
7243
|
};
|
|
4478
7244
|
return listeners;
|
|
@@ -4481,10 +7247,24 @@ var readonly_type_properties_default = createRule6({
|
|
|
4481
7247
|
|
|
4482
7248
|
// packages/lint-suite/src/lib/typescript-local-plugin.ts
|
|
4483
7249
|
var localPlugin = definePlugin("local", {
|
|
7250
|
+
"arrow-body-fits-line": arrow_body_fits_line_default,
|
|
7251
|
+
"chain-fits-line": chain_fits_line_default,
|
|
7252
|
+
"chain-receiver-is-name": chain_receiver_is_name_default,
|
|
4484
7253
|
"explicit-accessibility": explicit_accessibility_default,
|
|
4485
|
-
"
|
|
7254
|
+
"max-condition-operands": max_condition_operands_default,
|
|
7255
|
+
"no-call-in-condition": no_call_in_condition_default,
|
|
7256
|
+
"no-grouped-condition": no_grouped_condition_default,
|
|
4486
7257
|
"no-inline-object-types": no_inline_object_types_default,
|
|
4487
|
-
"
|
|
7258
|
+
"no-inline-return-object": no_inline_return_object_default,
|
|
7259
|
+
"no-nested-object-value": no_nested_object_value_default,
|
|
7260
|
+
"no-spread-expression": no_spread_expression_default,
|
|
7261
|
+
"no-unused-exports": no_unused_exports_default,
|
|
7262
|
+
"one-line-guard": one_line_guard_default,
|
|
7263
|
+
"readonly-type-properties": readonly_type_properties_default,
|
|
7264
|
+
"ternary-branch-shape": ternary_branch_shape_default,
|
|
7265
|
+
"test-file-shape": test_file_shape_default,
|
|
7266
|
+
"type-placement": type_placement_default,
|
|
7267
|
+
"util-purity": util_purity_default
|
|
4488
7268
|
});
|
|
4489
7269
|
|
|
4490
7270
|
// packages/lint-suite/src/lib/typescript-safety.ts
|
|
@@ -4493,11 +7273,82 @@ var typescriptSafety = defineConfig18([
|
|
|
4493
7273
|
files: ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts"],
|
|
4494
7274
|
plugins: { local: localPlugin },
|
|
4495
7275
|
rules: {
|
|
7276
|
+
// Expression arrow whose body wraps gets a block body. Fixes.
|
|
7277
|
+
// Bad: (x) => a && b on two lines Good: (x) => { return a && b; }
|
|
7278
|
+
"local/arrow-body-fits-line": "error",
|
|
7279
|
+
// Two or more calls in one chain stay on one line.
|
|
7280
|
+
// Bad: a .b() .c() over three lines Good: const b = a.b(); b.c();
|
|
7281
|
+
"local/chain-fits-line": "error",
|
|
7282
|
+
// A member chain starts on a name, never on an inline expression.
|
|
7283
|
+
// Bad: (a ?? b).c Good: const ab = a ?? b; ab.c
|
|
7284
|
+
"local/chain-receiver-is-name": "error",
|
|
7285
|
+
// Every class member states public, private, or protected. Fixes.
|
|
7286
|
+
// Bad: field = 1; Good: private field = 1;
|
|
4496
7287
|
"local/explicit-accessibility": "error",
|
|
4497
|
-
|
|
7288
|
+
// An if condition holds at most 3 operands joined by && or ||.
|
|
7289
|
+
// Bad: if (a && b && c && d) Good: const isAll = a && b && c && d;
|
|
7290
|
+
"local/max-condition-operands": "error",
|
|
7291
|
+
// No call inside an if; type predicates and this.x() reads are exempt.
|
|
7292
|
+
// Bad: if (validate(o)) Good: const isValid = validate(o); if (isValid)
|
|
7293
|
+
"local/no-call-in-condition": "error",
|
|
7294
|
+
// No parenthesised group with a different operator inside an if.
|
|
7295
|
+
// Bad: if (a && (b || c)) Good: const isBOrC = b || c; if (a && isBOrC)
|
|
7296
|
+
"local/no-grouped-condition": "error",
|
|
7297
|
+
// An object type literal appears only as the body of a type alias.
|
|
7298
|
+
// Bad: (f: { a: string }) Good: type F = { a: string }; (f: F)
|
|
4498
7299
|
"local/no-inline-object-types": "error",
|
|
7300
|
+
// Never return an object literal inline; name it first.
|
|
7301
|
+
// Bad: return { a: 1 }; Good: const result = { a: 1 }; return result;
|
|
7302
|
+
"local/no-inline-return-object": "error",
|
|
7303
|
+
// A nested object, array of objects, ternary, or chain as a value gets a
|
|
7304
|
+
// name.
|
|
7305
|
+
// Bad: { a: { b: 1 } } Good: const a = { b: 1 }; { a }
|
|
7306
|
+
"local/no-nested-object-value": "error",
|
|
7307
|
+
// Spread only a name or a member access.
|
|
7308
|
+
// Bad: f(...getArgs()) Good: const args = getArgs(); f(...args)
|
|
7309
|
+
"local/no-spread-expression": "error",
|
|
7310
|
+
// An export no file in the program imports is dead; entry points exempt.
|
|
7311
|
+
// Bad: export const unused = 1; Good: delete it, or import it
|
|
7312
|
+
"local/no-unused-exports": "error",
|
|
7313
|
+
// A lone return/throw/continue/break guard drops braces when it fits.
|
|
7314
|
+
// Bad: braced three-line if (x) { return; } Good: if (x) return;
|
|
4499
7315
|
"local/one-line-guard": ["error", { maxLineLength: MAX_LINE_LENGTH }],
|
|
7316
|
+
// Type properties are readonly; arrays stay T[], never readonly T[].
|
|
7317
|
+
// Fixes.
|
|
7318
|
+
// Bad: { id: string; items: readonly T[] }
|
|
7319
|
+
// Good: { readonly id: string; readonly items: T[] }
|
|
7320
|
+
"local/readonly-type-properties": "error",
|
|
7321
|
+
// A ternary branch is a name, literal, or plain member access.
|
|
7322
|
+
// Bad: c ? foo() : b Good: const called = foo(); c ? called : b
|
|
7323
|
+
"local/ternary-branch-shape": "error",
|
|
7324
|
+
// No spec-support, helpers, or __mocks__ files; stubs, mocks, and
|
|
7325
|
+
// spec utils live under test/; stubs are UPPER_SNAKE_STUB: Type.
|
|
7326
|
+
// Bad: user.spec-helper.ts, common/stubs/user.stub.ts
|
|
7327
|
+
// Good: test/utils/user.spec.util.ts, test/stubs USER_STUB: User
|
|
7328
|
+
"local/test-file-shape": "error",
|
|
7329
|
+
// Exported types live in common/*.type.ts; type-only imports come from
|
|
7330
|
+
// there.
|
|
7331
|
+
// Bad: export type Order in order.ts
|
|
7332
|
+
// Good: export type Order in common/order.type.ts
|
|
7333
|
+
"local/type-placement": "error",
|
|
7334
|
+
// utils/*.util.ts hold pure code: no fs, process, Date.now, module-level
|
|
7335
|
+
// let or Map. Files under test/ or testing/ are exempt.
|
|
7336
|
+
// Bad: const cache = new Map(); at module level
|
|
7337
|
+
// Good: pass the state in as an argument
|
|
7338
|
+
"local/util-purity": "error",
|
|
4500
7339
|
"@typescript-eslint/explicit-function-return-type": "error",
|
|
7340
|
+
"@typescript-eslint/parameter-properties": "error",
|
|
7341
|
+
"no-restricted-syntax": [
|
|
7342
|
+
"error",
|
|
7343
|
+
{
|
|
7344
|
+
selector: "TSEnumDeclaration[declare!=true]",
|
|
7345
|
+
message: "enum is not erasable syntax; use a union of literals or an as-const object."
|
|
7346
|
+
},
|
|
7347
|
+
{
|
|
7348
|
+
selector: 'TSModuleDeclaration[kind="namespace"][declare!=true]',
|
|
7349
|
+
message: "namespace is not erasable syntax; use a module."
|
|
7350
|
+
}
|
|
7351
|
+
],
|
|
4501
7352
|
"@typescript-eslint/no-empty-function": "error",
|
|
4502
7353
|
"@typescript-eslint/no-unused-vars": "error",
|
|
4503
7354
|
"@typescript-eslint/no-use-before-define": "error",
|
|
@@ -4560,6 +7411,13 @@ var typescriptSafety = defineConfig18([
|
|
|
4560
7411
|
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
|
4561
7412
|
"@typescript-eslint/prefer-regexp-exec": "error"
|
|
4562
7413
|
}
|
|
7414
|
+
},
|
|
7415
|
+
{
|
|
7416
|
+
files: ["**/*.action.ts"],
|
|
7417
|
+
rules: {
|
|
7418
|
+
// Class actions carry their payload as constructor parameter properties.
|
|
7419
|
+
"@typescript-eslint/parameter-properties": "off"
|
|
7420
|
+
}
|
|
4563
7421
|
}
|
|
4564
7422
|
]);
|
|
4565
7423
|
|
|
@@ -4576,7 +7434,8 @@ var typescript = defineConfig19([
|
|
|
4576
7434
|
import vitestEslint from "@vitest/eslint-plugin";
|
|
4577
7435
|
import { defineConfig as defineConfig20 } from "eslint/config";
|
|
4578
7436
|
var vitestPlugin = {
|
|
4579
|
-
vitest: vitestEslint
|
|
7437
|
+
vitest: vitestEslint,
|
|
7438
|
+
local: localPlugin
|
|
4580
7439
|
};
|
|
4581
7440
|
var vitest = defineConfig20([
|
|
4582
7441
|
{
|