@cplieger/deadset-ts 8.0.0-dev.20 → 8.0.0-dev.22
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/dist/src/alias-chain.js +33 -2
- package/dist/src/analysis.js +18 -77
- package/dist/src/conformance-record.js +2 -2
- package/dist/src/contract/contract.generated.js +5 -4
- package/dist/src/dependencies.js +1 -1
- package/dist/src/exemptions/argument-places.js +131 -0
- package/dist/src/{calls.js → exemptions/calls.js} +126 -179
- package/dist/src/{exempt-classes.js → exemptions/classes.js} +1 -1
- package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
- package/dist/src/exemptions/detectors.js +48 -0
- package/dist/src/{enum-group.js → exemptions/enum-group.js} +7 -7
- package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +4 -6
- package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +31 -36
- package/dist/src/{generated-file.js → exemptions/generated-file.js} +4 -4
- package/dist/src/{injection-container.js → exemptions/injection-container.js} +19 -25
- package/dist/src/exemptions/installed-globals.js +173 -0
- package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
- package/dist/src/exemptions/lifecycle.js +150 -0
- package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
- package/dist/src/{serialization-contract.js → exemptions/serialization-contract.js} +415 -329
- package/dist/src/exemptions/sites.js +182 -0
- package/dist/src/{template-field.js → exemptions/template-field.js} +7 -7
- package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
- package/dist/src/findings/intra-function.js +50 -37
- package/dist/src/index/sites.js +1 -1
- package/dist/src/index/values.js +124 -0
- package/dist/src/intra-function-parts.js +1149 -222
- package/dist/src/liveness/sweep.js +2 -2
- package/dist/src/query.js +48 -0
- package/dist/src/roots/configured-declarations.js +1 -1
- package/dist/src/verbs/print-retained.js +23 -1
- package/jsr.json +1 -1
- package/package.json +2 -2
- package/src/alias-chain.ts +38 -2
- package/src/analysis.ts +19 -100
- package/src/bindings.ts +1 -1
- package/src/conformance-record.ts +2 -2
- package/src/contract/contract.generated.ts +5 -4
- package/src/dependencies.ts +1 -1
- package/src/exemptions/argument-places.ts +198 -0
- package/src/{calls.ts → exemptions/calls.ts} +190 -224
- package/src/{exempt-classes.ts → exemptions/classes.ts} +1 -1
- package/src/exemptions/decorator.ts +56 -0
- package/src/exemptions/detectors.ts +75 -0
- package/src/{enum-group.ts → exemptions/enum-group.ts} +9 -9
- package/src/{erased-stores.ts → exemptions/erased-stores.ts} +5 -8
- package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +39 -48
- package/src/{generated-file.ts → exemptions/generated-file.ts} +6 -6
- package/src/{injection-container.ts → exemptions/injection-container.ts} +28 -33
- package/src/exemptions/installed-globals.ts +255 -0
- package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
- package/src/exemptions/lifecycle.ts +286 -0
- package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
- package/src/{serialization-contract.ts → exemptions/serialization-contract.ts} +563 -429
- package/src/exemptions/sites.ts +293 -0
- package/src/{template-field.ts → exemptions/template-field.ts} +11 -11
- package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
- package/src/facts.ts +1 -1
- package/src/findings/intra-function.ts +59 -37
- package/src/index/sites.ts +1 -1
- package/src/index/values.ts +170 -0
- package/src/intra-function-parts.ts +1435 -247
- package/src/liveness/sweep.ts +2 -2
- package/src/query.ts +109 -10
- package/src/roots/configured-declarations.ts +1 -2
- package/src/stores.ts +1 -1
- package/src/verbs/print-retained.ts +29 -1
- package/dist/src/exempt.js +0 -164
- package/dist/src/value-flow.js +0 -74
- package/src/decorator.ts +0 -78
- package/src/exempt.ts +0 -295
- package/src/value-flow.ts +0 -104
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which parameter place each argument of a call binds, the one reading every question
|
|
3
|
+
* about a call's arguments asks. A plain argument fills the next place, and a spread or
|
|
4
|
+
* an `apply` list typed as a tuple whose elements are all required fills one place per
|
|
5
|
+
* element. Any other spread or list has no known length: from its first place on, each of
|
|
6
|
+
* its element types, and every later argument, may fill any place, so a value is never
|
|
7
|
+
* read as missing a parameter only because its place could not be read. The type at each
|
|
8
|
+
* place is the checker's answer for it, so this reading names places and never types them.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { isSpreadElement, type Expression } from "@typescript/native/ast";
|
|
12
|
+
import { ElementFlags, type Signature, type Type } from "@typescript/native/sync";
|
|
13
|
+
import { must } from "../query.ts";
|
|
14
|
+
import type { ProjectView } from "../session.ts";
|
|
15
|
+
|
|
16
|
+
/** The places one argument fills. */
|
|
17
|
+
export interface Span {
|
|
18
|
+
/** The argument's index among the invocation's arguments. */
|
|
19
|
+
readonly argument: number;
|
|
20
|
+
/** The first place it can fill. */
|
|
21
|
+
readonly first: number;
|
|
22
|
+
/** The type at each place from `first` on, or, where `open`, at any place from it on. */
|
|
23
|
+
readonly given: readonly (Type | undefined)[];
|
|
24
|
+
/** Whether the argument's length, or the length of a spread before it, is unknown. */
|
|
25
|
+
readonly open: boolean;
|
|
26
|
+
/** Whether the argument is a spread or a list, whose value is its elements. */
|
|
27
|
+
readonly spread: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** One argument at one parameter place, with the type it gives there. */
|
|
31
|
+
export interface Placed {
|
|
32
|
+
readonly argument: number;
|
|
33
|
+
/** The index in the argument's span `given` of the type it gives there. */
|
|
34
|
+
readonly element: number;
|
|
35
|
+
readonly place: number;
|
|
36
|
+
readonly given: Type | undefined;
|
|
37
|
+
/** Whether the signature has no such place, so it says nothing of what the argument keeps. */
|
|
38
|
+
readonly uncovered: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether it stands for every place of a rest from `place` on, an argument of unknown
|
|
41
|
+
* length there taking any type the rest's element type holds.
|
|
42
|
+
*/
|
|
43
|
+
readonly rest: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* How many places a signature has. Where it `repeats`, its rest has no fixed length and
|
|
48
|
+
* `count` ends at the rest's first place: the checker answers each place past it, and an
|
|
49
|
+
* argument of unknown length meets every one of them.
|
|
50
|
+
*/
|
|
51
|
+
export interface Layout {
|
|
52
|
+
readonly count: number;
|
|
53
|
+
readonly repeats: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The element flags of a tuple type; none for another type. */
|
|
57
|
+
function elementFlags<Brand>(project: ProjectView<Brand>, type: Type): readonly ElementFlags[] {
|
|
58
|
+
const target = type.isTupleType() ? must(project.queries.targetOf(type)) : undefined;
|
|
59
|
+
return target?.isTupleTypeTarget() === true ? target.elementFlags : [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** What a spread argument puts at the places it fills, and how many it fills at least. */
|
|
63
|
+
function spread<Brand>(
|
|
64
|
+
project: ProjectView<Brand>,
|
|
65
|
+
type: Type | undefined,
|
|
66
|
+
): {
|
|
67
|
+
readonly types: readonly (Type | undefined)[];
|
|
68
|
+
readonly fixed: boolean;
|
|
69
|
+
readonly least: number;
|
|
70
|
+
} {
|
|
71
|
+
const { queries } = project;
|
|
72
|
+
if (type === undefined) {
|
|
73
|
+
return { types: [undefined], fixed: false, least: 0 };
|
|
74
|
+
}
|
|
75
|
+
if (type.isTupleType()) {
|
|
76
|
+
const flags = elementFlags(project, type);
|
|
77
|
+
return {
|
|
78
|
+
types: must(queries.typeArguments(type)).slice(0, flags.length),
|
|
79
|
+
fixed: flags.every((flag) => (flag & ElementFlags.Required) !== 0),
|
|
80
|
+
least: flags.filter((flag) => (flag & ElementFlags.Required) !== 0).length,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (must(queries.isArray(type))) {
|
|
84
|
+
return { types: must(queries.typeArguments(type)), fixed: false, least: 0 };
|
|
85
|
+
}
|
|
86
|
+
// Another iterable's elements are read off its type arguments, as `Set<T>` holds `T`.
|
|
87
|
+
return { types: [type, ...must(queries.typeArguments(type))], fixed: false, least: 0 };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The element types of a tuple of `count` required elements; none for another type. */
|
|
91
|
+
export function knownElements<Brand>(
|
|
92
|
+
project: ProjectView<Brand>,
|
|
93
|
+
type: Type,
|
|
94
|
+
count: number,
|
|
95
|
+
): readonly (Type | undefined)[] | undefined {
|
|
96
|
+
if (!type.isTupleType()) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const elements = spread(project, type);
|
|
100
|
+
return elements.fixed && elements.types.length === count ? elements.types : undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The places each argument fills, `types` holding the type of each argument's value; it
|
|
105
|
+
* may be empty where no argument is a spread and no given type is read. `listed` reads
|
|
106
|
+
* the last argument as a list whose elements the places bind.
|
|
107
|
+
*/
|
|
108
|
+
export function spansOf<Brand>(
|
|
109
|
+
project: ProjectView<Brand>,
|
|
110
|
+
args: readonly Expression[],
|
|
111
|
+
listed: boolean,
|
|
112
|
+
types: readonly (Type | undefined)[],
|
|
113
|
+
): readonly Span[] {
|
|
114
|
+
const spans: Span[] = [];
|
|
115
|
+
let place = 0;
|
|
116
|
+
let open = false;
|
|
117
|
+
for (const [at, argument] of args.entries()) {
|
|
118
|
+
const type = types[at];
|
|
119
|
+
if (!isSpreadElement(argument) && !(listed && at === args.length - 1)) {
|
|
120
|
+
spans.push({ argument: at, first: place, given: [type], open, spread: false });
|
|
121
|
+
place += 1;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const elements = spread(project, type);
|
|
125
|
+
open ||= !elements.fixed;
|
|
126
|
+
spans.push({ argument: at, first: place, given: elements.types, open, spread: true });
|
|
127
|
+
place += elements.least;
|
|
128
|
+
}
|
|
129
|
+
return spans;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The places of one signature as the checker counts them: one per parameter, and in
|
|
134
|
+
* place of a rest as many as the `length` the checker answers for its type, where that
|
|
135
|
+
* is a number literal or a union of them. Any other `length`, an array's or an array-like
|
|
136
|
+
* interface's `number` among them, leaves the rest open.
|
|
137
|
+
*/
|
|
138
|
+
export function layoutOf<Brand>(project: ProjectView<Brand>, signature: Signature): Layout {
|
|
139
|
+
const { queries } = project;
|
|
140
|
+
const fixed = signature.parameters.length;
|
|
141
|
+
const rest = must(queries.restTypeOf(signature));
|
|
142
|
+
if (rest === undefined) {
|
|
143
|
+
return { count: fixed, repeats: false };
|
|
144
|
+
}
|
|
145
|
+
const length = must(queries.propertyTypeOf(rest, "length"));
|
|
146
|
+
const lengths = length === undefined ? [] : must(queries.constituents(length));
|
|
147
|
+
const bounds = lengths.flatMap((one) => (one.isNumberLiteralType() ? [one.value] : []));
|
|
148
|
+
if (bounds.length > 0 && bounds.length === lengths.length) {
|
|
149
|
+
return { count: fixed - 1 + Math.max(...bounds), repeats: false };
|
|
150
|
+
}
|
|
151
|
+
return { count: fixed, repeats: true };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The parameter place each argument binds in a signature of `layout`, with the type it
|
|
156
|
+
* gives there. A span of unknown length binds every place from its first to the last the
|
|
157
|
+
* layout counts, and past them, where the rest is open, one `rest` placement for every
|
|
158
|
+
* later place, or else its first place alone. A place past every place of a layout that
|
|
159
|
+
* does not repeat is `uncovered`.
|
|
160
|
+
*/
|
|
161
|
+
export function placesIn(spans: readonly Span[], layout: Layout): readonly Placed[] {
|
|
162
|
+
const placed: Placed[] = [];
|
|
163
|
+
const add = (span: Span, place: number, rest: boolean): void => {
|
|
164
|
+
const uncovered = place >= layout.count && !layout.repeats;
|
|
165
|
+
const elements = span.open
|
|
166
|
+
? span.given.map((given, element) => ({ given, element }))
|
|
167
|
+
: [{ given: span.given[place - span.first], element: place - span.first }];
|
|
168
|
+
placed.push(
|
|
169
|
+
...elements.map((one) => ({ argument: span.argument, place, uncovered, rest, ...one })),
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
for (const span of spans) {
|
|
173
|
+
const open = span.open && layout.repeats;
|
|
174
|
+
const end = !span.open
|
|
175
|
+
? span.first + span.given.length
|
|
176
|
+
: Math.max(layout.count, open ? span.first : span.first + 1);
|
|
177
|
+
for (let place = span.first; place < end; place += 1) {
|
|
178
|
+
add(span, place, false);
|
|
179
|
+
}
|
|
180
|
+
if (open) {
|
|
181
|
+
add(span, Math.max(layout.count, span.first), true);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return placed;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Whether a span fills the parameter declared at `index`, a rest parameter every place
|
|
189
|
+
* from it on; with `element`, whether that element of a span that is not open does.
|
|
190
|
+
*/
|
|
191
|
+
export function fills(span: Span, index: number, rest: boolean, element?: number): boolean {
|
|
192
|
+
if (element !== undefined && !span.open) {
|
|
193
|
+
const place = span.first + element;
|
|
194
|
+
return rest ? place >= index : place === index;
|
|
195
|
+
}
|
|
196
|
+
const last = span.open ? Number.POSITIVE_INFINITY : span.first + span.given.length - 1;
|
|
197
|
+
return rest ? last >= index : span.first <= index && index <= last;
|
|
198
|
+
}
|