@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.
Files changed (72) hide show
  1. package/dist/src/alias-chain.js +33 -2
  2. package/dist/src/analysis.js +18 -77
  3. package/dist/src/conformance-record.js +2 -2
  4. package/dist/src/contract/contract.generated.js +5 -4
  5. package/dist/src/dependencies.js +1 -1
  6. package/dist/src/exemptions/argument-places.js +131 -0
  7. package/dist/src/{calls.js → exemptions/calls.js} +126 -179
  8. package/dist/src/{exempt-classes.js → exemptions/classes.js} +1 -1
  9. package/dist/src/{decorator.js → exemptions/decorator.js} +19 -30
  10. package/dist/src/exemptions/detectors.js +48 -0
  11. package/dist/src/{enum-group.js → exemptions/enum-group.js} +7 -7
  12. package/dist/src/{erased-stores.js → exemptions/erased-stores.js} +4 -6
  13. package/dist/src/{framework-lifecycle.js → exemptions/framework-lifecycle.js} +31 -36
  14. package/dist/src/{generated-file.js → exemptions/generated-file.js} +4 -4
  15. package/dist/src/{injection-container.js → exemptions/injection-container.js} +19 -25
  16. package/dist/src/exemptions/installed-globals.js +173 -0
  17. package/dist/src/{interface-satisfaction.js → exemptions/interface-satisfaction.js} +52 -121
  18. package/dist/src/exemptions/lifecycle.js +150 -0
  19. package/dist/src/{reflective-lookup.js → exemptions/reflective-lookup.js} +3 -3
  20. package/dist/src/{serialization-contract.js → exemptions/serialization-contract.js} +415 -329
  21. package/dist/src/exemptions/sites.js +182 -0
  22. package/dist/src/{template-field.js → exemptions/template-field.js} +7 -7
  23. package/dist/src/{value-reach.js → exemptions/value-reach.js} +14 -7
  24. package/dist/src/findings/intra-function.js +50 -37
  25. package/dist/src/index/sites.js +1 -1
  26. package/dist/src/index/values.js +124 -0
  27. package/dist/src/intra-function-parts.js +1149 -222
  28. package/dist/src/liveness/sweep.js +2 -2
  29. package/dist/src/query.js +48 -0
  30. package/dist/src/roots/configured-declarations.js +1 -1
  31. package/dist/src/verbs/print-retained.js +23 -1
  32. package/jsr.json +1 -1
  33. package/package.json +2 -2
  34. package/src/alias-chain.ts +38 -2
  35. package/src/analysis.ts +19 -100
  36. package/src/bindings.ts +1 -1
  37. package/src/conformance-record.ts +2 -2
  38. package/src/contract/contract.generated.ts +5 -4
  39. package/src/dependencies.ts +1 -1
  40. package/src/exemptions/argument-places.ts +198 -0
  41. package/src/{calls.ts → exemptions/calls.ts} +190 -224
  42. package/src/{exempt-classes.ts → exemptions/classes.ts} +1 -1
  43. package/src/exemptions/decorator.ts +56 -0
  44. package/src/exemptions/detectors.ts +75 -0
  45. package/src/{enum-group.ts → exemptions/enum-group.ts} +9 -9
  46. package/src/{erased-stores.ts → exemptions/erased-stores.ts} +5 -8
  47. package/src/{framework-lifecycle.ts → exemptions/framework-lifecycle.ts} +39 -48
  48. package/src/{generated-file.ts → exemptions/generated-file.ts} +6 -6
  49. package/src/{injection-container.ts → exemptions/injection-container.ts} +28 -33
  50. package/src/exemptions/installed-globals.ts +255 -0
  51. package/src/{interface-satisfaction.ts → exemptions/interface-satisfaction.ts} +69 -160
  52. package/src/exemptions/lifecycle.ts +286 -0
  53. package/src/{reflective-lookup.ts → exemptions/reflective-lookup.ts} +5 -5
  54. package/src/{serialization-contract.ts → exemptions/serialization-contract.ts} +563 -429
  55. package/src/exemptions/sites.ts +293 -0
  56. package/src/{template-field.ts → exemptions/template-field.ts} +11 -11
  57. package/src/{value-reach.ts → exemptions/value-reach.ts} +16 -8
  58. package/src/facts.ts +1 -1
  59. package/src/findings/intra-function.ts +59 -37
  60. package/src/index/sites.ts +1 -1
  61. package/src/index/values.ts +170 -0
  62. package/src/intra-function-parts.ts +1435 -247
  63. package/src/liveness/sweep.ts +2 -2
  64. package/src/query.ts +109 -10
  65. package/src/roots/configured-declarations.ts +1 -2
  66. package/src/stores.ts +1 -1
  67. package/src/verbs/print-retained.ts +29 -1
  68. package/dist/src/exempt.js +0 -164
  69. package/dist/src/value-flow.js +0 -74
  70. package/src/decorator.ts +0 -78
  71. package/src/exempt.ts +0 -295
  72. package/src/value-flow.ts +0 -104
@@ -0,0 +1,170 @@
1
+ /**
2
+ * What a written expression evaluates to, the one definition every pass shares: the
3
+ * values it can be, the values a call's argument carries inside the literals it writes,
4
+ * and the positions a program hands a value to that the checker types from their context.
5
+ */
6
+
7
+ import {
8
+ isArrayLiteralExpression,
9
+ isArrowFunction,
10
+ isAsExpression,
11
+ isBinaryExpression,
12
+ isCallExpression,
13
+ isConditionalExpression,
14
+ isIdentifier,
15
+ isNewExpression,
16
+ isNonNullExpression,
17
+ isObjectLiteralExpression,
18
+ isOmittedExpression,
19
+ isParameterDeclaration,
20
+ isParenthesizedExpression,
21
+ isPropertyAccessExpression,
22
+ isPropertyAssignment,
23
+ isPropertyDeclaration,
24
+ isReturnStatement,
25
+ isSatisfiesExpression,
26
+ isShorthandPropertyAssignment,
27
+ isSpreadAssignment,
28
+ isSpreadElement,
29
+ isVariableDeclaration,
30
+ SyntaxKind,
31
+ type Expression,
32
+ type Node,
33
+ } from "@typescript/native/ast";
34
+
35
+ /** The operators of an assignment whose right side is stored into the left side's type. */
36
+ const STORES: ReadonlySet<SyntaxKind> = new Set([
37
+ SyntaxKind.EqualsToken,
38
+ SyntaxKind.QuestionQuestionEqualsToken,
39
+ SyntaxKind.BarBarEqualsToken,
40
+ SyntaxKind.AmpersandAmpersandEqualsToken,
41
+ ]);
42
+
43
+ /** Whether a declaration writes its type, so its initializer is read in that type's context. */
44
+ function writesType(node: Node): boolean {
45
+ return (node as { readonly type?: Node }).type !== undefined;
46
+ }
47
+
48
+ /**
49
+ * The expressions one written value can evaluate to, each read alone because the checker
50
+ * reduces a union by subtype, so the type at the whole drops a class another branch's
51
+ * extends: the operand of a spread, of parentheses and of `!`, each branch of a
52
+ * conditional, each operand of `??` and `||`, and the right operand of `&&` and of a
53
+ * comma. The left operand of `&&` is its value only where it is falsy, which no object
54
+ * is. An assertion is a value of its own, whose type its reader decides.
55
+ */
56
+ export function valuesOf(expression: Expression): readonly Expression[] {
57
+ if (isSpreadElement(expression) || isParenthesizedExpression(expression)) {
58
+ return valuesOf(expression.expression);
59
+ }
60
+ if (isNonNullExpression(expression)) {
61
+ return valuesOf(expression.expression);
62
+ }
63
+ if (isConditionalExpression(expression)) {
64
+ return [...valuesOf(expression.whenTrue), ...valuesOf(expression.whenFalse)];
65
+ }
66
+ if (isBinaryExpression(expression)) {
67
+ const operator = expression.operatorToken.kind;
68
+ if (operator === SyntaxKind.QuestionQuestionToken || operator === SyntaxKind.BarBarToken) {
69
+ return [...valuesOf(expression.left), ...valuesOf(expression.right)];
70
+ }
71
+ if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.CommaToken) {
72
+ return valuesOf(expression.right);
73
+ }
74
+ }
75
+ return [expression];
76
+ }
77
+
78
+ /** The name node a callee, a decorator expression or a value resolves through, where it has one. */
79
+ export function nameOf(expression: Expression): Node | undefined {
80
+ if (isParenthesizedExpression(expression)) {
81
+ return nameOf(expression.expression);
82
+ }
83
+ if (isPropertyAccessExpression(expression)) {
84
+ return expression.name;
85
+ }
86
+ return isIdentifier(expression) ? expression : undefined;
87
+ }
88
+
89
+ /** One value an argument carries, and the node its declaration is resolved from. */
90
+ export interface CarriedValue {
91
+ /** Where the value is written, which is where a record of it sits. */
92
+ readonly site: Node;
93
+ /** The name the value is resolved through, the shorthand assignment that holds it, or none. */
94
+ readonly name: Node | undefined;
95
+ readonly shorthand: boolean;
96
+ }
97
+
98
+ /**
99
+ * The values one argument carries: each value it can be ({@link valuesOf}), or what an
100
+ * array or object literal it can be holds, at any depth, through spreads and shorthand
101
+ * properties. Each value is read inside every assertion around it.
102
+ */
103
+ export function carriedValues(argument: Expression): readonly CarriedValue[] {
104
+ return valuesOf(argument).flatMap((value): readonly CarriedValue[] => {
105
+ let at = value;
106
+ while (isAsExpression(at) || isSatisfiesExpression(at)) {
107
+ at = at.expression;
108
+ }
109
+ if (at !== value) {
110
+ return carriedValues(at);
111
+ }
112
+ if (isArrayLiteralExpression(value)) {
113
+ return value.elements.flatMap(carriedValues);
114
+ }
115
+ if (isObjectLiteralExpression(value)) {
116
+ return value.properties.flatMap((property): readonly CarriedValue[] => {
117
+ if (isPropertyAssignment(property)) {
118
+ return carriedValues(property.initializer);
119
+ }
120
+ if (isSpreadAssignment(property)) {
121
+ return carriedValues(property.expression);
122
+ }
123
+ return isShorthandPropertyAssignment(property)
124
+ ? [{ site: property.name, name: property, shorthand: true }]
125
+ : [];
126
+ });
127
+ }
128
+ return isOmittedExpression(value)
129
+ ? []
130
+ : [{ site: value, name: nameOf(value), shorthand: false }];
131
+ });
132
+ }
133
+
134
+ /** The expressions one node hands to a position typed by its context. */
135
+ export function handedOn(node: Node): readonly Expression[] {
136
+ if (
137
+ (isVariableDeclaration(node) || isPropertyDeclaration(node) || isParameterDeclaration(node)) &&
138
+ node.initializer !== undefined &&
139
+ writesType(node)
140
+ ) {
141
+ return [node.initializer];
142
+ }
143
+ if (isBinaryExpression(node) && STORES.has(node.operatorToken.kind)) {
144
+ return [node.right];
145
+ }
146
+ if (isCallExpression(node) || isNewExpression(node)) {
147
+ return (node.arguments ?? []).filter((argument) => !isSpreadElement(argument));
148
+ }
149
+ if (isReturnStatement(node)) {
150
+ return node.expression === undefined ? [] : [node.expression];
151
+ }
152
+ if (isArrowFunction(node)) {
153
+ return node.body.kind === SyntaxKind.Block ? [] : [node.body];
154
+ }
155
+ if (isArrayLiteralExpression(node)) {
156
+ return node.elements.filter(
157
+ (element) => !isSpreadElement(element) && element.kind !== SyntaxKind.OmittedExpression,
158
+ );
159
+ }
160
+ if (isPropertyAssignment(node)) {
161
+ return [node.initializer];
162
+ }
163
+ if (isShorthandPropertyAssignment(node)) {
164
+ return isIdentifier(node.name) ? [node.name] : [];
165
+ }
166
+ if (isAsExpression(node) || isSatisfiesExpression(node)) {
167
+ return [node.expression];
168
+ }
169
+ return [];
170
+ }