@cplieger/deadset-ts 7.2.0-dev.4 → 8.0.0-dev.10
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 +1 -1
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/analysis.js +245 -309
- package/dist/src/augmentations.js +124 -18
- package/dist/src/automatic-types.js +170 -0
- package/dist/src/build-scripts.js +425 -0
- package/dist/src/component-layer.js +4 -2
- package/dist/src/components.js +9 -9
- package/dist/src/config.js +6 -81
- package/dist/src/configuration-files.js +78 -188
- package/dist/src/configured-declarations.js +15 -20
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/consumers.js +3 -30
- package/dist/src/contextual-uses.js +56 -9
- package/dist/src/contract/config.generated.js +558 -0
- package/dist/src/contract/contract.generated.js +1244 -0
- package/dist/src/contract/report.generated.js +862 -0
- package/dist/src/convention-rows.js +146 -1
- package/dist/src/conventions.js +136 -70
- package/dist/src/decorator.js +21 -18
- package/dist/src/dependencies.js +280 -62
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +4 -6
- package/dist/src/entry-point-gaps.js +9 -18
- package/dist/src/entry-points.js +106 -21
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -40
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +2 -25
- package/dist/src/findings/completion.js +225 -63
- package/dist/src/findings/dependencies-and-module-machinery.js +72 -27
- package/dist/src/findings/emitters.js +6 -6
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +53 -19
- package/dist/src/findings/non-code-artifacts.js +71 -39
- package/dist/src/findings/reads-and-writes.js +16 -13
- package/dist/src/findings/self-check.js +10 -12
- package/dist/src/findings/unused-declarations.js +57 -28
- package/dist/src/findings/visibility-narrowing.js +40 -18
- package/dist/src/findings-pass.js +8 -15
- package/dist/src/framework-lifecycle.js +7 -7
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +72 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +18 -4
- package/dist/src/git-ignore.js +99 -0
- package/dist/src/graph.js +9 -4
- package/dist/src/html-entries.js +6 -33
- package/dist/src/import-bindings.js +97 -0
- package/dist/src/in-operands.js +2 -1
- package/dist/src/index.js +1 -1
- package/dist/src/indexed-access.js +130 -28
- package/dist/src/injection-container.js +1 -1
- package/dist/src/interface-satisfaction.js +30 -12
- package/dist/src/intra-function-parts.js +341 -69
- package/dist/src/inventory.js +54 -29
- package/dist/src/javascript-file.js +33 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +4 -6
- package/dist/src/kinds.js +3 -366
- package/dist/src/load/classify.js +270 -0
- package/dist/src/load/diagnostics.js +80 -0
- package/dist/src/load/discover.js +277 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +115 -0
- package/dist/src/load/synthesize.js +140 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +88 -61
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +60 -59
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/manifest.js +49 -54
- package/dist/src/matrix.js +94 -13
- package/dist/src/mdx-entries.js +174 -0
- package/dist/src/module-declarations.js +9 -13
- package/dist/src/outside-tests.js +1 -1
- package/dist/src/overrides.js +41 -10
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +26 -15
- package/dist/src/position.js +2 -1
- package/dist/src/print.js +11 -78
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +1 -0
- package/dist/src/ref.js +11 -0
- package/dist/src/references.js +52 -31
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +59 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +245 -727
- package/dist/src/roots.js +374 -116
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -342
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +649 -29
- package/dist/src/session.js +41 -29
- package/dist/src/source-files.js +40 -15
- package/dist/src/suppress-file.js +34 -29
- package/dist/src/suppress-inline.js +21 -4
- package/dist/src/suppress.js +40 -56
- package/dist/src/sweep.js +32 -17
- package/dist/src/symbol-keys.js +105 -6
- package/dist/src/template-field.js +9 -19
- package/dist/src/test-support.js +119 -18
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +54 -0
- package/dist/src/text/shell.js +159 -0
- package/dist/src/text/yaml.js +393 -0
- package/dist/src/type-errors.js +27 -221
- package/dist/src/type-parameter-reads.js +172 -0
- package/dist/src/unseen-loads.js +100 -0
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/verbs/analyze.js +181 -125
- package/dist/src/verbs/describe.js +9 -16
- package/dist/src/verbs/explain.js +14 -9
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +4 -2
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/dist/src/workflow-steps.js +128 -33
- package/jsr.json +1 -1
- package/package.json +5 -4
- package/src/analysis.ts +333 -457
- package/src/augmentations.ts +152 -23
- package/src/automatic-types.ts +228 -0
- package/src/build-scripts.ts +543 -0
- package/src/component-layer.ts +4 -2
- package/src/components.ts +9 -10
- package/src/config.ts +31 -299
- package/src/configuration-files.ts +100 -191
- package/src/configured-declarations.ts +18 -23
- package/src/conformance-record.ts +2 -2
- package/src/consumers.ts +6 -57
- package/src/contextual-uses.ts +64 -12
- package/src/contract/config.generated.ts +818 -0
- package/src/contract/contract.generated.ts +1308 -0
- package/src/contract/report.generated.ts +1237 -0
- package/src/convention-rows.ts +186 -1
- package/src/conventions.ts +166 -90
- package/src/decorator.ts +28 -18
- package/src/dependencies.ts +356 -78
- package/src/edges.ts +41 -140
- package/src/element-access.ts +4 -7
- package/src/entry-point-gaps.ts +11 -20
- package/src/entry-points.ts +124 -28
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +36 -50
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +9 -24
- package/src/finding.ts +24 -9
- package/src/findings/boundary.ts +2 -0
- package/src/findings/completion.ts +297 -77
- package/src/findings/dependencies-and-module-machinery.ts +90 -31
- package/src/findings/emitter.ts +8 -9
- package/src/findings/emitters.ts +8 -8
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +64 -20
- package/src/findings/non-code-artifacts.ts +88 -50
- package/src/findings/reads-and-writes.ts +20 -16
- package/src/findings/self-check.ts +11 -17
- package/src/findings/unused-declarations.ts +65 -28
- package/src/findings/visibility-narrowing.ts +51 -19
- package/src/findings-pass.ts +10 -19
- package/src/framework-lifecycle.ts +7 -7
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +92 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +23 -4
- package/src/git-ignore.ts +122 -0
- package/src/graph.ts +11 -3
- package/src/host.ts +17 -14
- package/src/html-entries.ts +6 -33
- package/src/import-bindings.ts +128 -0
- package/src/in-operands.ts +2 -1
- package/src/index.ts +1 -1
- package/src/indexed-access.ts +152 -30
- package/src/injection-container.ts +1 -1
- package/src/interface-satisfaction.ts +33 -13
- package/src/intra-function-parts.ts +449 -85
- package/src/inventory.ts +73 -27
- package/src/javascript-file.ts +37 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +3 -7
- package/src/kinds.ts +5 -413
- package/src/load/classify.ts +397 -0
- package/src/load/diagnostics.ts +144 -0
- package/src/load/discover.ts +455 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +188 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/plan.ts +504 -0
- package/src/load/specifiers.ts +168 -0
- package/src/load/synthesize.ts +211 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +127 -80
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +73 -64
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/manifest.ts +81 -75
- package/src/matrix.ts +154 -18
- package/src/mdx-entries.ts +218 -0
- package/src/module-declarations.ts +11 -13
- package/src/outside-tests.ts +1 -1
- package/src/overrides.ts +51 -12
- package/src/partial.ts +3 -2
- package/src/paths.ts +27 -15
- package/src/position.ts +2 -1
- package/src/print.ts +12 -91
- package/src/product.ts +18 -0
- package/src/query.ts +11 -0
- package/src/ref.ts +13 -0
- package/src/references.ts +62 -32
- package/src/report-schema.ts +68 -0
- package/src/report.ts +105 -215
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +283 -1111
- package/src/roots.ts +490 -137
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -387
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +818 -26
- package/src/session.ts +77 -54
- package/src/source-files.ts +67 -17
- package/src/suppress-file.ts +36 -34
- package/src/suppress-inline.ts +20 -3
- package/src/suppress.ts +52 -63
- package/src/sweep.ts +53 -18
- package/src/symbol-keys.ts +131 -7
- package/src/template-field.ts +15 -25
- package/src/test-support.ts +155 -18
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.inputs.json +1522 -0
- package/src/text/named-files.ts +68 -0
- package/src/text/shell.ts +161 -0
- package/src/text/yaml.ts +423 -0
- package/src/type-errors.ts +35 -273
- package/src/type-parameter-reads.ts +227 -0
- package/src/unseen-loads.ts +134 -0
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/verbs/analyze.ts +245 -161
- package/src/verbs/describe.ts +14 -15
- package/src/verbs/explain.ts +15 -13
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +4 -2
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/src/workflow-steps.ts +149 -34
- package/dist/src/discover.js +0 -347
- package/dist/src/glob.js +0 -65
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/src/discover.ts +0 -510
- package/src/glob.ts +0 -67
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
package/src/edges.ts
CHANGED
|
@@ -5,15 +5,18 @@
|
|
|
5
5
|
* pairing is a use, and the merge reads the two evaluations together.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { EDGES_SCHEMA } from "./contract/config.generated.ts";
|
|
9
9
|
import type { Finding } from "./finding.ts";
|
|
10
10
|
import type { EdgeSide, EdgeSideName } from "./findings/boundary.ts";
|
|
11
|
+
import { readTargetDocument } from "./fs/document.ts";
|
|
11
12
|
import type { Host } from "./host.ts";
|
|
12
13
|
import type { InventorySymbol } from "./inventory.ts";
|
|
13
|
-
import { positionAt,
|
|
14
|
-
import { joinPath } from "./paths.ts";
|
|
14
|
+
import { dotted, placeIn, positionAt, readStrict, StrictJSONError } from "./json-document.ts";
|
|
15
15
|
import { positionKey } from "./position.ts";
|
|
16
|
+
import { firstRefusal } from "./schema.ts";
|
|
16
17
|
import { isPartSubject } from "./suppress.ts";
|
|
18
|
+
import { bytewise } from "./text/compare.ts";
|
|
19
|
+
import { UsageError } from "./usage.ts";
|
|
17
20
|
|
|
18
21
|
/** The name and the location the Contract fixes for the edges document. */
|
|
19
22
|
export const EDGES_FILE = "deadset-edges.json";
|
|
@@ -21,155 +24,61 @@ export const EDGES_FILE = "deadset-edges.json";
|
|
|
21
24
|
/** The language prefix of every reference this analyzer evaluates. */
|
|
22
25
|
const OWN_PREFIX = "ts://";
|
|
23
26
|
|
|
24
|
-
/** The closed key list of the document and of one edge. */
|
|
25
|
-
const DOCUMENT_KEYS: ReadonlySet<string> = new Set(["description", "edges"]);
|
|
26
|
-
const EDGE_KEYS: ReadonlySet<string> = new Set(["id", "because", "provides", "used_by"]);
|
|
27
|
-
|
|
28
|
-
/** An edge identifier: solidus-separated segments of ASCII letters, digits, `_`, `.` and `-`. */
|
|
29
|
-
const ID_FORM = /^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*$/u;
|
|
30
|
-
|
|
31
|
-
/** A reference naming one symbol of some language: `<language>://<scope>#<fragment>`. */
|
|
32
|
-
const REFERENCE_FORM = /^[a-z][a-z0-9]*:\/\/[^ \t\r\n#]+#[^ \t\r\n]*$/u;
|
|
33
|
-
|
|
34
|
-
const DOCUMENT_WANT = "an object carrying the edges array, and an optional description";
|
|
35
|
-
const EDGE_WANT = "an edge naming id, provides and used_by, each a string, and an optional because";
|
|
36
|
-
const ID_WANT =
|
|
37
|
-
"one or more solidus-separated segments of ASCII letters, digits, underscore, full stop and hyphen";
|
|
38
|
-
const REFERENCE_WANT =
|
|
39
|
-
"a stable symbol reference naming one symbol exactly, <language>://<scope>#<fragment>";
|
|
40
|
-
|
|
41
27
|
/** An edges document the Contract refuses: a malformed input, answered with the usage code. */
|
|
42
|
-
class EdgesError extends
|
|
43
|
-
constructor(at: string,
|
|
44
|
-
super(
|
|
28
|
+
class EdgesError extends UsageError {
|
|
29
|
+
constructor(at: string, reason: string) {
|
|
30
|
+
super(`${at}: ${reason}`);
|
|
45
31
|
this.name = "EdgesError";
|
|
46
32
|
}
|
|
47
33
|
}
|
|
48
34
|
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
* would name a set of symbols rather than one.
|
|
52
|
-
*/
|
|
53
|
-
function carriesWildcard(ref: string): boolean {
|
|
54
|
-
let quoted = false;
|
|
55
|
-
let computed = false;
|
|
56
|
-
let escaped = false;
|
|
57
|
-
for (const char of ref) {
|
|
58
|
-
if (escaped) {
|
|
59
|
-
escaped = false;
|
|
60
|
-
} else if (quoted && char === "\\") {
|
|
61
|
-
escaped = true;
|
|
62
|
-
} else if (quoted) {
|
|
63
|
-
quoted = char !== "'";
|
|
64
|
-
} else if (computed) {
|
|
65
|
-
computed = char !== "]";
|
|
66
|
-
} else if (char === "'") {
|
|
67
|
-
quoted = true;
|
|
68
|
-
} else if (char === "[") {
|
|
69
|
-
computed = true;
|
|
70
|
-
} else if (char === "*") {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
78
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** One edge, checked: the closed key list, the value types and the value forms. */
|
|
82
|
-
function readEdge(value: unknown, at: string): { id: string; provides: string; usedBy: string } {
|
|
83
|
-
const refuse = (text: string, want: string): never => {
|
|
84
|
-
throw new EdgesError(at, text, want);
|
|
85
|
-
};
|
|
86
|
-
if (!isObject(value)) {
|
|
87
|
-
return refuse(JSON.stringify(value), EDGE_WANT);
|
|
88
|
-
}
|
|
89
|
-
for (const [key, held] of Object.entries(value)) {
|
|
90
|
-
if (!EDGE_KEYS.has(key) || typeof held !== "string") {
|
|
91
|
-
refuse(`the member ${JSON.stringify(key)} holding ${JSON.stringify(held)}`, EDGE_WANT);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const edge = value as Readonly<Record<string, string | undefined>>;
|
|
95
|
-
const id = edge["id"] ?? refuse("an edge naming no id", EDGE_WANT);
|
|
96
|
-
const provides = edge["provides"] ?? refuse("an edge naming no provides side", EDGE_WANT);
|
|
97
|
-
const usedBy = edge["used_by"] ?? refuse("an edge naming no used_by side", EDGE_WANT);
|
|
98
|
-
if (!ID_FORM.test(id)) {
|
|
99
|
-
refuse(JSON.stringify(id), ID_WANT);
|
|
100
|
-
}
|
|
101
|
-
for (const ref of [provides, usedBy]) {
|
|
102
|
-
if (!REFERENCE_FORM.test(ref) || carriesWildcard(ref)) {
|
|
103
|
-
refuse(JSON.stringify(ref), REFERENCE_WANT);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return { id, provides, usedBy };
|
|
107
|
-
}
|
|
35
|
+
/** The sides of one edge, in the order a reader yields them. */
|
|
36
|
+
const SIDE_NAMES: readonly EdgeSideName[] = ["provides", "used_by"];
|
|
108
37
|
|
|
109
38
|
/**
|
|
110
39
|
* Every side of a declared edge that names a symbol of this language, in document order,
|
|
111
40
|
* `provides` before `used_by` within an edge. An absent document declares no edge. The
|
|
112
|
-
* document is strict JSON
|
|
113
|
-
* {@link EdgesError}.
|
|
41
|
+
* document is strict JSON held to the Contract's edges schema, and a defect in it is an
|
|
42
|
+
* {@link EdgesError} at the line and column of the edge it is in, where it is in one.
|
|
114
43
|
*/
|
|
115
44
|
export function readEdgeSides(host: Host, targetRoot: string): readonly EdgeSide[] {
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
45
|
+
const text = readTargetDocument(host, targetRoot, EDGES_FILE);
|
|
46
|
+
if (text === undefined) {
|
|
118
47
|
return [];
|
|
119
48
|
}
|
|
120
|
-
|
|
121
|
-
let parsed: unknown;
|
|
49
|
+
let read;
|
|
122
50
|
try {
|
|
123
|
-
|
|
51
|
+
read = readStrict(text, "edges");
|
|
124
52
|
} catch (error: unknown) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
if (!isObject(parsed)) {
|
|
132
|
-
throw new EdgesError(EDGES_FILE, JSON.stringify(parsed), DOCUMENT_WANT);
|
|
133
|
-
}
|
|
134
|
-
const walk = walkDocument(text, "edges");
|
|
135
|
-
if (walk.twice !== undefined) {
|
|
136
|
-
throw new EdgesError(
|
|
137
|
-
positionKey(positionAt(text, EDGES_FILE, walk.twice.offset)),
|
|
138
|
-
`the member ${JSON.stringify(walk.twice.name)} is written twice, so neither value is chosen`,
|
|
139
|
-
DOCUMENT_WANT,
|
|
140
|
-
);
|
|
53
|
+
if (!(error instanceof StrictJSONError)) {
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
throw new EdgesError(positionKey(positionAt(text, EDGES_FILE, error.offset)), error.message);
|
|
141
57
|
}
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
throw new EdgesError(
|
|
151
|
-
EDGES_FILE,
|
|
152
|
-
unknown === undefined ? EDGES_FILE : `the member ${JSON.stringify(unknown)}`,
|
|
153
|
-
DOCUMENT_WANT,
|
|
154
|
-
);
|
|
58
|
+
const value = read.value;
|
|
59
|
+
const refused = firstRefusal(EDGES_SCHEMA, value);
|
|
60
|
+
if (refused !== undefined) {
|
|
61
|
+
const place = placeIn(value, refused.pointer, refused.member);
|
|
62
|
+
const offset = place.length > 1 ? read.starts.get(place[1] ?? "") : undefined;
|
|
63
|
+
const at =
|
|
64
|
+
offset === undefined ? EDGES_FILE : positionKey(positionAt(text, EDGES_FILE, offset));
|
|
65
|
+
const where = dotted(place);
|
|
66
|
+
throw new EdgesError(at, where === "" ? refused.reason : `${where}: ${refused.reason}`);
|
|
155
67
|
}
|
|
68
|
+
const edges = (
|
|
69
|
+
value as { readonly edges: Readonly<Record<string, Record<EdgeSideName, string>>> }
|
|
70
|
+
).edges;
|
|
156
71
|
|
|
157
72
|
const sides: EdgeSide[] = [];
|
|
158
|
-
(
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
["provides", edge.provides],
|
|
165
|
-
["used_by", edge.usedBy],
|
|
166
|
-
];
|
|
167
|
-
for (const [side, symbol] of named) {
|
|
168
|
-
if (symbol.startsWith(OWN_PREFIX)) {
|
|
169
|
-
sides.push({ edge: edge.id, side, symbol });
|
|
73
|
+
for (const id of read.starts.keys()) {
|
|
74
|
+
const edge = String(id);
|
|
75
|
+
for (const side of SIDE_NAMES) {
|
|
76
|
+
const symbol = edges[edge]?.[side];
|
|
77
|
+
if (symbol?.startsWith(OWN_PREFIX) === true) {
|
|
78
|
+
sides.push({ edge, side, symbol });
|
|
170
79
|
}
|
|
171
80
|
}
|
|
172
|
-
}
|
|
81
|
+
}
|
|
173
82
|
return sides;
|
|
174
83
|
}
|
|
175
84
|
|
|
@@ -190,14 +99,6 @@ interface Evaluated<F extends Finding> {
|
|
|
190
99
|
readonly evaluations: readonly EdgeEvaluation<F>[];
|
|
191
100
|
}
|
|
192
101
|
|
|
193
|
-
/** Two strings ordered bytewise. */
|
|
194
|
-
function compare(a: string, b: string): number {
|
|
195
|
-
if (a === b) {
|
|
196
|
-
return 0;
|
|
197
|
-
}
|
|
198
|
-
return a < b ? -1 : 1;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
102
|
/**
|
|
202
103
|
* Evaluates every declared side of this language over the run's findings. A side naming a
|
|
203
104
|
* symbol the run enumerates nothing under is `absent`; otherwise it is evaluated once per
|
|
@@ -242,6 +143,6 @@ export function evaluateEdges<F extends Finding>(
|
|
|
242
143
|
return { ...side, state: "dead", finding };
|
|
243
144
|
});
|
|
244
145
|
});
|
|
245
|
-
evaluations.sort((a, b) =>
|
|
146
|
+
evaluations.sort((a, b) => bytewise(a.edge, b.edge) || bytewise(a.side, b.side));
|
|
246
147
|
return { findings: findings.filter((_finding, at) => !pending.has(at)), evaluations };
|
|
247
148
|
}
|
package/src/element-access.ts
CHANGED
|
@@ -47,6 +47,7 @@ import { renderPosition } from "./position.ts";
|
|
|
47
47
|
import { UNANSWERED } from "./query.ts";
|
|
48
48
|
import type { Reference } from "./references.ts";
|
|
49
49
|
import type { ProjectView } from "./session.ts";
|
|
50
|
+
import { parenthesesRemoved } from "./unwrap.ts";
|
|
50
51
|
|
|
51
52
|
type Use = "read" | "write" | "both";
|
|
52
53
|
|
|
@@ -93,13 +94,9 @@ function useOf(node: Node): Use {
|
|
|
93
94
|
return "read";
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
function unwrapped(node: Expression): Expression {
|
|
97
|
-
return isParenthesizedExpression(node) ? unwrapped(node.expression) : node;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
97
|
/** Whether an index is a literal the checker resolves to a member by its own text. */
|
|
101
98
|
function isLiteralIndex(node: Expression): boolean {
|
|
102
|
-
const at =
|
|
99
|
+
const at = parenthesesRemoved(node);
|
|
103
100
|
return isStringLiteral(at) || isNumericLiteral(at) || isNoSubstitutionTemplateLiteral(at);
|
|
104
101
|
}
|
|
105
102
|
|
|
@@ -293,7 +290,7 @@ export function elementAccessReferences<Brand>(
|
|
|
293
290
|
const parameterOf = new Map<Candidate, { callable: Callable; at: number }>();
|
|
294
291
|
const byCallable = new Map<Identifier, Candidate[]>();
|
|
295
292
|
for (const candidate of candidates) {
|
|
296
|
-
const index =
|
|
293
|
+
const index = parenthesesRemoved(candidate.access.argumentExpression);
|
|
297
294
|
const fn = isIdentifier(index) ? enclosingFunction(candidate.access) : undefined;
|
|
298
295
|
const callable = fn === undefined ? undefined : callableOf(fn);
|
|
299
296
|
if (callable === undefined || !isIdentifier(index)) {
|
|
@@ -353,7 +350,7 @@ export function elementAccessReferences<Brand>(
|
|
|
353
350
|
continue;
|
|
354
351
|
}
|
|
355
352
|
// An object that is a parameter too is read as the argument each call passes there.
|
|
356
|
-
const object =
|
|
353
|
+
const object = parenthesesRemoved(candidate.access.expression);
|
|
357
354
|
const objectAt = isIdentifier(object)
|
|
358
355
|
? deferred.callable.parameters.findIndex(
|
|
359
356
|
(parameter) => isIdentifier(parameter.name) && parameter.name.text === object.text,
|
package/src/entry-point-gaps.ts
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* one at a time: beside a finding, or in a report's declared gaps.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { bytewise } from "./text/compare.ts";
|
|
12
|
+
|
|
11
13
|
/** One declined entry-point convention. */
|
|
12
14
|
export interface DeclinedConvention {
|
|
13
15
|
/** The tool the convention belongs to, by the name of the package or service. */
|
|
@@ -58,7 +60,6 @@ const UNREAD_TOOLS: readonly string[] = [
|
|
|
58
60
|
"cypress",
|
|
59
61
|
"danger",
|
|
60
62
|
"dependency-cruiser",
|
|
61
|
-
"docusaurus",
|
|
62
63
|
"dotenv",
|
|
63
64
|
"drizzle",
|
|
64
65
|
"electron-vite",
|
|
@@ -112,14 +113,12 @@ const UNREAD_TOOLS: readonly string[] = [
|
|
|
112
113
|
"nuxtjs-i18n",
|
|
113
114
|
"nx",
|
|
114
115
|
"nyc",
|
|
115
|
-
"oclif",
|
|
116
116
|
"openapi-ts",
|
|
117
117
|
"openclaw",
|
|
118
118
|
"orval",
|
|
119
119
|
"oxfmt",
|
|
120
120
|
"oxlint",
|
|
121
121
|
"panda-css",
|
|
122
|
-
"parcel",
|
|
123
122
|
"payload",
|
|
124
123
|
"pino",
|
|
125
124
|
"playwright-ct",
|
|
@@ -164,7 +163,6 @@ const UNREAD_TOOLS: readonly string[] = [
|
|
|
164
163
|
"swc",
|
|
165
164
|
"syncpack",
|
|
166
165
|
"tailwind",
|
|
167
|
-
"tanstack-router",
|
|
168
166
|
"taskfile",
|
|
169
167
|
"tauri",
|
|
170
168
|
"temporal",
|
|
@@ -210,18 +208,19 @@ const UNREAD_TOOLS: readonly string[] = [
|
|
|
210
208
|
/** The conventions declined for a tool some of whose conventions are entered. */
|
|
211
209
|
const PARTLY_ENTERED: readonly DeclinedConvention[] = [
|
|
212
210
|
{
|
|
213
|
-
tool: "
|
|
214
|
-
convention: "a
|
|
211
|
+
tool: "docusaurus",
|
|
212
|
+
convention: "a page or theme directory a plugin's configuration moves, and the docs",
|
|
215
213
|
reason:
|
|
216
|
-
"
|
|
217
|
-
"
|
|
214
|
+
"The convention row reads src/pages and src/theme only, and a document's imports are " +
|
|
215
|
+
"read from every Markdown and MDX file, so a module only a moved directory holds is " +
|
|
216
|
+
"reported as never imported unless ts.entry_files names it.",
|
|
218
217
|
},
|
|
219
218
|
{
|
|
220
219
|
tool: "eslint",
|
|
221
|
-
convention: "a
|
|
220
|
+
convention: "a legacy configuration written in YAML or in JSON with comments",
|
|
222
221
|
reason:
|
|
223
|
-
"
|
|
224
|
-
"dependency only a
|
|
222
|
+
"Only a configuration module and a strict JSON configuration file are read, so a " +
|
|
223
|
+
"dependency only such a file names is reported as unused.",
|
|
225
224
|
},
|
|
226
225
|
{
|
|
227
226
|
tool: "playwright",
|
|
@@ -326,16 +325,8 @@ const PARTLY_ENTERED: readonly DeclinedConvention[] = [
|
|
|
326
325
|
},
|
|
327
326
|
];
|
|
328
327
|
|
|
329
|
-
/** Two strings ordered bytewise. */
|
|
330
|
-
function compare(a: string, b: string): number {
|
|
331
|
-
if (a === b) {
|
|
332
|
-
return 0;
|
|
333
|
-
}
|
|
334
|
-
return a < b ? -1 : 1;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
328
|
/** Every declined entry-point convention, ordered by tool and then by convention. */
|
|
338
329
|
export const DECLINED_CONVENTIONS: readonly DeclinedConvention[] = [
|
|
339
330
|
...UNREAD_TOOLS.map((tool) => ({ tool, convention: EVERY_CONVENTION, reason: UNREAD })),
|
|
340
331
|
...PARTLY_ENTERED,
|
|
341
|
-
].sort((a, b) =>
|
|
332
|
+
].sort((a, b) => bytewise(a.tool, b.tool) || bytewise(a.convention, b.convention));
|
package/src/entry-points.ts
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
isArrayLiteralExpression,
|
|
16
|
-
isAsExpression,
|
|
17
16
|
isCallExpression,
|
|
18
17
|
isExportAssignment,
|
|
19
18
|
isIdentifier,
|
|
@@ -21,11 +20,10 @@ import {
|
|
|
21
20
|
isNewExpression,
|
|
22
21
|
isNoSubstitutionTemplateLiteral,
|
|
23
22
|
isObjectLiteralExpression,
|
|
24
|
-
isParenthesizedExpression,
|
|
25
23
|
isPropertyAccessExpression,
|
|
26
24
|
isPropertyAssignment,
|
|
27
|
-
isSatisfiesExpression,
|
|
28
25
|
isStringLiteral,
|
|
26
|
+
SyntaxKind,
|
|
29
27
|
type Node,
|
|
30
28
|
type SourceFile,
|
|
31
29
|
} from "@typescript/native/ast";
|
|
@@ -37,14 +35,18 @@ import {
|
|
|
37
35
|
type ParseFile,
|
|
38
36
|
} from "./configuration-files.ts";
|
|
39
37
|
import type { Selected } from "./conventions.ts";
|
|
40
|
-
import {
|
|
38
|
+
import { buildScriptEntries } from "./build-scripts.ts";
|
|
41
39
|
import type { Host } from "./host.ts";
|
|
42
40
|
import { htmlEntries } from "./html-entries.ts";
|
|
41
|
+
import { documentEntries } from "./mdx-entries.ts";
|
|
43
42
|
import { dirnamePath, relativePath, resolvePath } from "./paths.ts";
|
|
44
43
|
import { UNANSWERED } from "./query.ts";
|
|
45
44
|
import type { ProjectView } from "./session.ts";
|
|
46
45
|
import type { SourceFiles } from "./source-files.ts";
|
|
46
|
+
import { computedLoadDirectory, leadingLiteral } from "./unseen-loads.ts";
|
|
47
47
|
import { workflowEntries } from "./workflow-steps.ts";
|
|
48
|
+
import { unwrapped } from "./unwrap.ts";
|
|
49
|
+
import { globExpression } from "./text/glob.ts";
|
|
48
50
|
|
|
49
51
|
/** Which rule entered a file. */
|
|
50
52
|
export type EntryRule =
|
|
@@ -52,6 +54,8 @@ export type EntryRule =
|
|
|
52
54
|
| "configuration-file"
|
|
53
55
|
/** A file a relative string of a configuration module or a JSON configuration file names. */
|
|
54
56
|
| "configuration-string"
|
|
57
|
+
/** An entry a build script's bundler call names, whose exports the bundle exposes. */
|
|
58
|
+
| "bundler-entry"
|
|
55
59
|
/** The test runner: its workspace configuration, its setup files and the test files. */
|
|
56
60
|
| "test-runner"
|
|
57
61
|
/** The test files below the browser-test runner's test directory. */
|
|
@@ -61,7 +65,15 @@ export type EntryRule =
|
|
|
61
65
|
/** A file a module script of an HTML file below the target root loads. */
|
|
62
66
|
| "html-entry"
|
|
63
67
|
/** A file a `run:` step of a workflow in the target root's `.github/workflows` names. */
|
|
64
|
-
| "workflow-step"
|
|
68
|
+
| "workflow-step"
|
|
69
|
+
/**
|
|
70
|
+
* A file a load whose path is computed may name: below the directory the literal
|
|
71
|
+
* start of an `import()` or `require()` argument names, or matched by the literal
|
|
72
|
+
* glob of `import.meta.glob`.
|
|
73
|
+
*/
|
|
74
|
+
| "computed-import"
|
|
75
|
+
/** A file an import line of a Markdown or MDX document below the target root names. */
|
|
76
|
+
| "document-import";
|
|
65
77
|
|
|
66
78
|
/** One file a rule enters. */
|
|
67
79
|
interface EntryPoint {
|
|
@@ -78,6 +90,8 @@ interface EntryPoint {
|
|
|
78
90
|
* level and names none of its exports.
|
|
79
91
|
*/
|
|
80
92
|
readonly exports: boolean;
|
|
93
|
+
/** Where the file is entered for some of its exports only, their export names. */
|
|
94
|
+
readonly names?: readonly string[];
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
/** One file-name convention: the stems a tool looks for, under each extension it loads. */
|
|
@@ -114,8 +128,11 @@ const SETUP_MEMBERS = ["setupFiles", "globalSetup"] as const;
|
|
|
114
128
|
/** A member that moves the directory every path of a test-runner configuration is read from. */
|
|
115
129
|
const ROOT_MEMBER = "root";
|
|
116
130
|
|
|
117
|
-
/**
|
|
118
|
-
|
|
131
|
+
/**
|
|
132
|
+
* A URL reference's scheme. A reference with none that does not start with a solidus is
|
|
133
|
+
* relative, the bare name included: https://url.spec.whatwg.org/#relative-url-string
|
|
134
|
+
*/
|
|
135
|
+
const URL_SCHEME = /^[a-z][a-z\d+.-]*:/iu;
|
|
119
136
|
|
|
120
137
|
/** The constructors whose first argument addresses a worker script. */
|
|
121
138
|
const WORKER_CONSTRUCTORS: ReadonlySet<string> = new Set(["Worker", "SharedWorker"]);
|
|
@@ -147,15 +164,6 @@ function literalOf(node: Node | undefined): string | undefined {
|
|
|
147
164
|
return undefined;
|
|
148
165
|
}
|
|
149
166
|
|
|
150
|
-
/** The expression a wrapper that changes no value holds: parentheses and type assertions. */
|
|
151
|
-
function unwrapped(node: Node): Node {
|
|
152
|
-
let at = node;
|
|
153
|
-
while (isParenthesizedExpression(at) || isAsExpression(at) || isSatisfiesExpression(at)) {
|
|
154
|
-
at = at.expression;
|
|
155
|
-
}
|
|
156
|
-
return at;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
167
|
/**
|
|
160
168
|
* The object literals one configuration file's default export is written as: the
|
|
161
169
|
* literal itself, or each literal argument of the call it is, at any depth of calls.
|
|
@@ -228,9 +236,17 @@ function literalsOf(value: Node): readonly string[] | undefined {
|
|
|
228
236
|
return found;
|
|
229
237
|
}
|
|
230
238
|
|
|
231
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Whether a literal is a relative URL reference, which is also how the test runner reads a
|
|
241
|
+
* setup file's path against its root.
|
|
242
|
+
*/
|
|
232
243
|
function isRelative(text: string): boolean {
|
|
233
|
-
return
|
|
244
|
+
return text !== "" && !text.startsWith("/") && !URL_SCHEME.test(text);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Whether a module specifier is relative, which a bare name is not: it names a package. */
|
|
248
|
+
function isModuleRelative(text: string): boolean {
|
|
249
|
+
return text.startsWith("./") || text.startsWith("../");
|
|
234
250
|
}
|
|
235
251
|
|
|
236
252
|
/** A URL reference with its query and its fragment removed, which name no part of the file. */
|
|
@@ -299,10 +315,7 @@ function configurationEntries(
|
|
|
299
315
|
strings(dirnamePath(document.path), unselectedIn(document.path, document.strings));
|
|
300
316
|
}
|
|
301
317
|
for (const { file } of outside) {
|
|
302
|
-
strings(
|
|
303
|
-
dirnamePath(file.fileName),
|
|
304
|
-
moduleStrings(file).map((one) => one.text),
|
|
305
|
-
);
|
|
318
|
+
strings(dirnamePath(file.fileName), unselected(file));
|
|
306
319
|
}
|
|
307
320
|
return found;
|
|
308
321
|
}
|
|
@@ -470,10 +483,10 @@ function workerSitesOf(file: SourceFile): readonly WorkerSite[] {
|
|
|
470
483
|
}
|
|
471
484
|
|
|
472
485
|
/**
|
|
473
|
-
* The workers one file addresses. A call's names must resolve to the platform
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
486
|
+
* The workers one file addresses. A call's names must resolve to a symbol the platform
|
|
487
|
+
* declares, which a file of the target may augment and no import brings in; a name only
|
|
488
|
+
* the target declares is the target's own constructor or object, which addresses no
|
|
489
|
+
* worker this rule knows. One batch per file that writes such a call.
|
|
477
490
|
*/
|
|
478
491
|
function workersOf<Brand>(
|
|
479
492
|
project: ProjectView<Brand>,
|
|
@@ -498,8 +511,7 @@ function workersOf<Brand>(
|
|
|
498
511
|
if (
|
|
499
512
|
symbol !== undefined &&
|
|
500
513
|
(symbol.flags & SymbolFlags.Alias) === 0 &&
|
|
501
|
-
symbol.declarations.
|
|
502
|
-
symbol.declarations.every((handle) => !files.byName.has(handle.path))
|
|
514
|
+
symbol.declarations.some((handle) => !files.byName.has(handle.path))
|
|
503
515
|
) {
|
|
504
516
|
platform.add(name);
|
|
505
517
|
}
|
|
@@ -517,6 +529,77 @@ function workersOf<Brand>(
|
|
|
517
529
|
return found;
|
|
518
530
|
}
|
|
519
531
|
|
|
532
|
+
/** Whether one call is `import.meta.glob(...)`. */
|
|
533
|
+
function isMetaGlob(node: Node): boolean {
|
|
534
|
+
if (!isCallExpression(node) || !isPropertyAccessExpression(node.expression)) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
const { expression, name } = node.expression;
|
|
538
|
+
return (
|
|
539
|
+
isIdentifier(name) &&
|
|
540
|
+
name.text === "glob" &&
|
|
541
|
+
isMetaProperty(expression) &&
|
|
542
|
+
expression.keywordToken === SyntaxKind.ImportKeyword
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* The files one file loads by a computed path, each with what exports: every own file
|
|
548
|
+
* below the directory a relative literal start of an `import()` or `require()` argument
|
|
549
|
+
* names, other than the calling file's own directory or one holding it, which would name
|
|
550
|
+
* every sibling, and
|
|
551
|
+
* every own file a relative literal glob of `import.meta.glob` matches, both read against
|
|
552
|
+
* the calling file's directory, as a bundler's context module reads them.
|
|
553
|
+
*/
|
|
554
|
+
function computedImportsOf(file: SourceFile, files: SourceFiles): readonly EntryPoint[] {
|
|
555
|
+
const dir = dirnamePath(file.fileName);
|
|
556
|
+
const found: EntryPoint[] = [];
|
|
557
|
+
const below = (prefix: string): void => {
|
|
558
|
+
const target = computedLoadDirectory(dir, prefix);
|
|
559
|
+
if (target === undefined) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
for (const candidate of files.byName.values()) {
|
|
563
|
+
if (candidate !== file && relativePath(target, candidate.fileName) !== undefined) {
|
|
564
|
+
found.push({ file: candidate, rule: "computed-import", source: prefix, exports: true });
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
const globbed = (pattern: string): void => {
|
|
569
|
+
if (!isModuleRelative(pattern)) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const expression = globExpression(resolvePath(dir, pattern));
|
|
573
|
+
for (const candidate of files.byName.values()) {
|
|
574
|
+
if (candidate !== file && expression.test(candidate.fileName)) {
|
|
575
|
+
found.push({ file: candidate, rule: "computed-import", source: pattern, exports: true });
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
const visit = (node: Node): void => {
|
|
580
|
+
if (isCallExpression(node)) {
|
|
581
|
+
const [first] = node.arguments;
|
|
582
|
+
const callee = node.expression;
|
|
583
|
+
const loads =
|
|
584
|
+
callee.kind === SyntaxKind.ImportKeyword ||
|
|
585
|
+
(isIdentifier(callee) && callee.text === "require");
|
|
586
|
+
if (loads && first !== undefined) {
|
|
587
|
+
const prefix = leadingLiteral(first);
|
|
588
|
+
if (prefix !== undefined) {
|
|
589
|
+
below(prefix);
|
|
590
|
+
}
|
|
591
|
+
} else if (isMetaGlob(node) && first !== undefined) {
|
|
592
|
+
for (const pattern of literalsOf(first) ?? []) {
|
|
593
|
+
globbed(pattern);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
node.forEachChild(visit);
|
|
598
|
+
};
|
|
599
|
+
file.forEachChild(visit);
|
|
600
|
+
return found;
|
|
601
|
+
}
|
|
602
|
+
|
|
520
603
|
/**
|
|
521
604
|
* Every file of one project the rules enter, in no particular order and possibly more
|
|
522
605
|
* than once: a file two rules enter appears once per rule.
|
|
@@ -554,10 +637,23 @@ export function entryPoints<Brand>(
|
|
|
554
637
|
}
|
|
555
638
|
}
|
|
556
639
|
found.push(...workersOf(project, file, files));
|
|
640
|
+
found.push(...computedImportsOf(file, files));
|
|
557
641
|
}
|
|
558
642
|
for (const { file, source } of htmlEntries(host, targetRoot, files, parse)) {
|
|
559
643
|
found.push({ file, rule: "html-entry", source, exports: true });
|
|
560
644
|
}
|
|
645
|
+
for (const { file, source, names } of documentEntries(host, targetRoot, files)) {
|
|
646
|
+
found.push({
|
|
647
|
+
file,
|
|
648
|
+
rule: "document-import",
|
|
649
|
+
source,
|
|
650
|
+
exports: true,
|
|
651
|
+
...(names === undefined ? {} : { names }),
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
for (const { file, source } of buildScriptEntries(host, targetRoot, files, parse)) {
|
|
655
|
+
found.push({ file, rule: "bundler-entry", source, exports: true });
|
|
656
|
+
}
|
|
561
657
|
for (const { file, source } of workflowEntries(host, targetRoot, files)) {
|
|
562
658
|
found.push({ file, rule: "workflow-step", source, exports: true });
|
|
563
659
|
}
|
package/src/enum-group.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
isIdentifier,
|
|
19
19
|
isMethodDeclaration,
|
|
20
20
|
isNoSubstitutionTemplateLiteral,
|
|
21
|
-
isParenthesizedExpression,
|
|
22
21
|
isParenthesizedTypeNode,
|
|
23
22
|
isPropertyAccessExpression,
|
|
24
23
|
isReturnStatement,
|
|
@@ -28,6 +27,7 @@ import {
|
|
|
28
27
|
type Node,
|
|
29
28
|
type SourceFile,
|
|
30
29
|
} from "@typescript/native/ast";
|
|
30
|
+
import { parenthesesRemoved } from "./unwrap.ts";
|
|
31
31
|
import { TypeFlags, type Type } from "@typescript/native/sync";
|
|
32
32
|
import { aliasChains } from "./alias-chain.ts";
|
|
33
33
|
import type { DetectorInput, Evidence } from "./exempt.ts";
|
|
@@ -55,15 +55,6 @@ interface Site {
|
|
|
55
55
|
readonly at: Node;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
/** The expression one node is, through however many parentheses are written around it. */
|
|
59
|
-
function unparenthesized(node: Node): Node {
|
|
60
|
-
let held = node;
|
|
61
|
-
while (isParenthesizedExpression(held)) {
|
|
62
|
-
held = held.expression;
|
|
63
|
-
}
|
|
64
|
-
return held;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
58
|
/**
|
|
68
59
|
* The name node a type node names its declaration by: the identifier of a type
|
|
69
60
|
* reference, the right side of a qualified one, through parentheses. A type that is no
|
|
@@ -86,7 +77,7 @@ function typeName(type: Node | undefined): Node | undefined {
|
|
|
86
77
|
|
|
87
78
|
/** The name node an expression names an object by: an identifier, or a property access's name. */
|
|
88
79
|
function objectName(expression: Node): Node | undefined {
|
|
89
|
-
const held =
|
|
80
|
+
const held = parenthesesRemoved(expression);
|
|
90
81
|
if (isIdentifier(held)) {
|
|
91
82
|
return held;
|
|
92
83
|
}
|