@esportsplus/reactivity 0.37.2 → 0.38.1
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/build/compiler/array.d.ts +8 -1
- package/build/compiler/array.js +111 -93
- package/build/compiler/bindings.d.ts +18 -12
- package/build/compiler/bindings.js +172 -52
- package/build/compiler/constants.d.ts +1 -0
- package/build/compiler/constants.js +1 -0
- package/build/compiler/index.d.ts +11 -3
- package/build/compiler/index.js +96 -34
- package/build/compiler/object.js +11 -14
- package/build/compiler/plugins/vite.d.ts +14 -0
- package/build/compiler/primitives.d.ts +6 -0
- package/build/compiler/primitives.js +99 -67
- package/build/compiler/types.d.ts +5 -4
- package/build/types.d.ts +1 -1
- package/package.json +2 -2
- package/pnpm-workspace.yaml +1 -1
- package/src/compiler/array.ts +166 -120
- package/src/compiler/bindings.ts +259 -56
- package/src/compiler/constants.ts +1 -0
- package/src/compiler/index.ts +142 -46
- package/src/compiler/object.ts +17 -17
- package/src/compiler/primitives.ts +139 -88
- package/src/compiler/types.ts +7 -4
- package/src/types.ts +2 -1
- package/test/compiler/compiler.test.ts +166 -48
- package/test/compiler/coverage.test.ts +164 -0
package/src/compiler/object.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { code, uid } from '@esportsplus/typescript/compiler';
|
|
|
3
3
|
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
4
4
|
import { NAMESPACE, TYPES } from './constants';
|
|
5
5
|
import type { Bindings, IsReactiveCall } from './types';
|
|
6
|
-
import scope from './bindings';
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
interface AnalyzedProperty {
|
|
@@ -34,7 +33,9 @@ interface VisitContext {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
|
|
37
|
-
function analyzeProperty(prop: ts.ObjectLiteralElementLike,
|
|
36
|
+
function analyzeProperty(prop: ts.ObjectLiteralElementLike, bindings: Bindings): AnalyzedProperty | null {
|
|
37
|
+
let sourceFile = bindings.sourceFile;
|
|
38
|
+
|
|
38
39
|
if (!ts.isPropertyAssignment(prop)) {
|
|
39
40
|
return null;
|
|
40
41
|
}
|
|
@@ -88,6 +89,14 @@ function analyzeProperty(prop: ts.ObjectLiteralElementLike, sourceFile: ts.Sourc
|
|
|
88
89
|
return { isStatic, key, type: TYPES.Array, valueText };
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
// A non-literal array is typed Reactive<T[]> on the object, so it must become a ReactiveArray
|
|
93
|
+
// exactly like a literal one
|
|
94
|
+
let type = isStaticValue(unwrapped) ? undefined : bindings.checker.getTypeAtLocation(value);
|
|
95
|
+
|
|
96
|
+
if (type && (bindings.checker.isArrayType(type) || bindings.checker.isTupleType(type))) {
|
|
97
|
+
return { isStatic: false, key, type: TYPES.Array, valueText };
|
|
98
|
+
}
|
|
99
|
+
|
|
91
100
|
return {
|
|
92
101
|
isStatic: isStaticValue(value),
|
|
93
102
|
key,
|
|
@@ -224,10 +233,9 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
224
233
|
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
225
234
|
let properties: AnalyzedProperty[] = [],
|
|
226
235
|
props = arg.properties,
|
|
227
|
-
|
|
228
|
-
? node.parent.name
|
|
229
|
-
: null
|
|
230
|
-
varname = target?.text ?? null;
|
|
236
|
+
varname = node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)
|
|
237
|
+
? node.parent.name.text
|
|
238
|
+
: null;
|
|
231
239
|
|
|
232
240
|
for (let i = 0, n = props.length; i < n; i++) {
|
|
233
241
|
let prop = props[i];
|
|
@@ -237,7 +245,7 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
237
245
|
return;
|
|
238
246
|
}
|
|
239
247
|
|
|
240
|
-
let analyzed = analyzeProperty(prop, ctx.
|
|
248
|
+
let analyzed = analyzeProperty(prop, ctx.bindings);
|
|
241
249
|
|
|
242
250
|
if (!analyzed) {
|
|
243
251
|
node.forEachChild(n => visit(ctx, n));
|
|
@@ -247,15 +255,6 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
247
255
|
properties.push(analyzed);
|
|
248
256
|
}
|
|
249
257
|
|
|
250
|
-
// Declared only once every property analyzed: a bailed object stays a runtime reactive()
|
|
251
|
-
if (target) {
|
|
252
|
-
for (let i = 0, n = properties.length; i < n; i++) {
|
|
253
|
-
if (properties[i].type === TYPES.Array) {
|
|
254
|
-
scope.declarePath(ctx.bindings, target, properties[i].key);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
258
|
ctx.calls.push({
|
|
260
259
|
classname: uid('ReactiveObject'),
|
|
261
260
|
node,
|
|
@@ -290,8 +289,9 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: I
|
|
|
290
289
|
prepend.push(buildClassCode(call.classname, call.properties, typehint));
|
|
291
290
|
replacements.push({
|
|
292
291
|
generate: () => {
|
|
292
|
+
// Every property but a static signal (baked into its field) is a constructor parameter
|
|
293
293
|
let args = call.properties
|
|
294
|
-
.filter(({ isStatic, type }) => typehint || !isStatic || type
|
|
294
|
+
.filter(({ isStatic, type }) => typehint || !isStatic || type !== TYPES.Signal)
|
|
295
295
|
.map(p => p.valueText)
|
|
296
296
|
.join(', ');
|
|
297
297
|
|
|
@@ -5,68 +5,64 @@ import type { Bindings, IsReactiveCall } from './types';
|
|
|
5
5
|
import scope from './bindings';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
// Something the compiler cannot lower; reported (every one of them) as a build error
|
|
9
|
+
type Failure = { message: string; node: ts.Node };
|
|
10
|
+
|
|
8
11
|
type PrimitivesTransformResult = {
|
|
9
12
|
calls: ts.CallExpression[];
|
|
13
|
+
failures: Failure[];
|
|
10
14
|
replacements: ReplacementIntent[];
|
|
11
15
|
};
|
|
12
16
|
|
|
13
17
|
type TransformContext = {
|
|
14
18
|
bindings: Bindings;
|
|
15
19
|
calls: ts.CallExpression[];
|
|
20
|
+
failures: Failure[];
|
|
16
21
|
isReactiveCall: IsReactiveCall;
|
|
17
22
|
replacements: ReplacementIntent[];
|
|
18
23
|
tmpCounter: number;
|
|
19
24
|
};
|
|
20
25
|
|
|
21
26
|
|
|
22
|
-
// Pass 1:
|
|
23
|
-
//
|
|
27
|
+
// Pass 1: lower every reactive() call. A signal or computed is only ever reached through the
|
|
28
|
+
// variable it initializes (every read of that variable is rewritten), so anywhere else its signal
|
|
29
|
+
// would leak unread and the call is rejected.
|
|
24
30
|
function declare(ctx: TransformContext, node: ts.Node): void {
|
|
25
31
|
if (ctx.isReactiveCall(node)) {
|
|
26
|
-
let call = node
|
|
32
|
+
let call = node,
|
|
33
|
+
kind = scope.classify(ctx.bindings, call);
|
|
27
34
|
|
|
28
35
|
ctx.calls.push(call);
|
|
29
36
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (ts.isArrayLiteralExpression(unwrapped) || ts.isObjectLiteralExpression(unwrapped)) {
|
|
45
|
-
classification = null;
|
|
46
|
-
}
|
|
47
|
-
// Dynamic expression - use runtime reactive via namespace
|
|
48
|
-
else if (ts.isCallExpression(unwrapped) || ts.isIdentifier(unwrapped)) {
|
|
49
|
-
classification = null;
|
|
50
|
-
ctx.replacements.push({
|
|
51
|
-
generate: () => `${NAMESPACE}.reactive`,
|
|
52
|
-
node: call.expression
|
|
53
|
-
});
|
|
54
|
-
}
|
|
37
|
+
if (kind === null) {
|
|
38
|
+
ctx.failures.push({
|
|
39
|
+
message: 'reactive() takes one argument whose kind (value, computed, array or object) is provable; ' +
|
|
40
|
+
'pass a literal or give the argument a concrete type (not any, unknown or a mixed union)',
|
|
41
|
+
node: call
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (kind === TYPES.Signal || kind === TYPES.Computed) {
|
|
45
|
+
if (!isBound(call)) {
|
|
46
|
+
ctx.failures.push({
|
|
47
|
+
message: `a reactive ${kind === TYPES.Signal ? 'value' : 'computed'} must initialize a variable (or be a module's ` +
|
|
48
|
+
'default export); anywhere else its signal is never read',
|
|
49
|
+
node: call
|
|
50
|
+
});
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
ctx.replacements.push({
|
|
54
|
+
generate: () => kind === TYPES.Computed ? `${NAMESPACE}.computed` : `${NAMESPACE}.signal`,
|
|
55
|
+
node: call.expression
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
let arg = scope.unwrap(call.arguments[0]);
|
|
64
60
|
|
|
65
|
-
|
|
61
|
+
// Literals are lowered by the array and object transforms; any other array or object
|
|
62
|
+
// is built by the runtime constructor
|
|
63
|
+
if (!ts.isArrayLiteralExpression(arg) && !ts.isObjectLiteralExpression(arg)) {
|
|
66
64
|
ctx.replacements.push({
|
|
67
|
-
generate: () =>
|
|
68
|
-
? `${NAMESPACE}.computed`
|
|
69
|
-
: `${NAMESPACE}.signal`,
|
|
65
|
+
generate: () => `${NAMESPACE}.reactive`,
|
|
70
66
|
node: call.expression
|
|
71
67
|
});
|
|
72
68
|
}
|
|
@@ -76,22 +72,51 @@ function declare(ctx: TransformContext, node: ts.Node): void {
|
|
|
76
72
|
node.forEachChild(child => declare(ctx, child));
|
|
77
73
|
}
|
|
78
74
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
75
|
+
// `let x = reactive(...)`, `x = reactive(...)` or `export default reactive(...)`
|
|
76
|
+
function isBound(call: ts.CallExpression): boolean {
|
|
77
|
+
let node: ts.Node = call,
|
|
78
|
+
parent = node.parent;
|
|
79
|
+
|
|
80
|
+
while (
|
|
81
|
+
parent &&
|
|
82
|
+
(ts.isAsExpression(parent) || ts.isNonNullExpression(parent) || ts.isParenthesizedExpression(parent) || ts.isSatisfiesExpression(parent))
|
|
83
|
+
) {
|
|
84
|
+
node = parent;
|
|
85
|
+
parent = node.parent;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!parent) {
|
|
85
89
|
return false;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
|
|
92
|
+
if (ts.isVariableDeclaration(parent)) {
|
|
93
|
+
return parent.initializer === node && ts.isIdentifier(parent.name);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (ts.isBinaryExpression(parent)) {
|
|
97
|
+
return parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.right === node && ts.isIdentifier(parent.left);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return ts.isExportAssignment(parent);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// A module namespace object: `import * as ns` (or an alias of it) or an `await import(...)`
|
|
104
|
+
function isNamespace(bindings: Bindings, expression: ts.Expression): boolean {
|
|
105
|
+
let value = scope.unwrap(expression);
|
|
106
|
+
|
|
107
|
+
if (ts.isAwaitExpression(value)) {
|
|
108
|
+
value = scope.unwrap(value.expression);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (ts.isCallExpression(value)) {
|
|
112
|
+
return value.expression.kind === ts.SyntaxKind.ImportKeyword;
|
|
113
|
+
}
|
|
89
114
|
|
|
90
|
-
return
|
|
115
|
+
return ts.isIdentifier(value) && scope.origin(bindings, value)?.declaration.kind === ts.SyntaxKind.SourceFile;
|
|
91
116
|
}
|
|
92
117
|
|
|
93
118
|
// Destructuring assignment targets (`({ count } = o)`, `[count] = xs`) write through a pattern
|
|
94
|
-
// that has no per-signal rewrite
|
|
119
|
+
// that has no per-signal rewrite
|
|
95
120
|
function isPatternTarget(node: ts.Node): boolean {
|
|
96
121
|
let current = node;
|
|
97
122
|
|
|
@@ -119,32 +144,42 @@ function isPatternTarget(node: ts.Node): boolean {
|
|
|
119
144
|
((ts.isForOfStatement(parent) || ts.isForInStatement(parent)) && parent.initializer === current);
|
|
120
145
|
}
|
|
121
146
|
|
|
122
|
-
|
|
147
|
+
// A binding read as `ns.count` / `ns['count']` is rewritten as a whole
|
|
148
|
+
function readNode(identifier: ts.Node): ts.Expression {
|
|
149
|
+
let parent = identifier.parent!;
|
|
150
|
+
|
|
151
|
+
if (
|
|
152
|
+
(ts.isPropertyAccessExpression(parent) && parent.name === identifier) ||
|
|
153
|
+
(ts.isElementAccessExpression(parent) && parent.argumentExpression === identifier)
|
|
154
|
+
) {
|
|
155
|
+
return parent;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return identifier as ts.Expression;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function reference(ctx: TransformContext, node: ts.Expression, kind: TYPES): void {
|
|
123
162
|
let parent = node.parent;
|
|
124
163
|
|
|
125
|
-
if (!parent
|
|
164
|
+
if (!parent) {
|
|
126
165
|
return;
|
|
127
166
|
}
|
|
128
167
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (!binding || binding.type === TYPES.Array) {
|
|
168
|
+
// `x = reactive(...)` replaces the signal itself
|
|
169
|
+
if (ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.left === node && ctx.isReactiveCall(scope.unwrap(parent.right))) {
|
|
132
170
|
return;
|
|
133
171
|
}
|
|
134
172
|
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
(ts.isTypeOfExpression(parent) && parent.expression === node) ||
|
|
138
|
-
isPatternTarget(node)
|
|
139
|
-
) {
|
|
173
|
+
if (isPatternTarget(node)) {
|
|
174
|
+
ctx.failures.push({ message: 'a reactive binding cannot be assigned through a destructuring pattern; assign it directly', node });
|
|
140
175
|
return;
|
|
141
176
|
}
|
|
142
177
|
|
|
143
|
-
let
|
|
178
|
+
let text = node.getText(ctx.bindings.sourceFile);
|
|
144
179
|
|
|
145
180
|
if (ts.isShorthandPropertyAssignment(parent)) {
|
|
146
181
|
ctx.replacements.push({
|
|
147
|
-
generate: () => `${
|
|
182
|
+
generate: () => `${text}: ${NAMESPACE}.read(${text})`,
|
|
148
183
|
node: parent
|
|
149
184
|
});
|
|
150
185
|
|
|
@@ -173,14 +208,15 @@ function reference(ctx: TransformContext, node: ts.Identifier): void {
|
|
|
173
208
|
|
|
174
209
|
if (!writeCtx) {
|
|
175
210
|
ctx.replacements.push({
|
|
176
|
-
generate: () => `${NAMESPACE}.read(${
|
|
211
|
+
generate: () => `${NAMESPACE}.read(${text})`,
|
|
177
212
|
node
|
|
178
213
|
});
|
|
179
214
|
|
|
180
215
|
return;
|
|
181
216
|
}
|
|
182
217
|
|
|
183
|
-
if (
|
|
218
|
+
if (kind === TYPES.Computed) {
|
|
219
|
+
ctx.failures.push({ message: 'a reactive computed is read-only', node });
|
|
184
220
|
return;
|
|
185
221
|
}
|
|
186
222
|
|
|
@@ -188,7 +224,7 @@ function reference(ctx: TransformContext, node: ts.Identifier): void {
|
|
|
188
224
|
let right = parent.right;
|
|
189
225
|
|
|
190
226
|
ctx.replacements.push({
|
|
191
|
-
generate: (sf) => `${NAMESPACE}.write(${
|
|
227
|
+
generate: (sf) => `${NAMESPACE}.write(${text}, ${right.getText(sf)})`,
|
|
192
228
|
node: parent
|
|
193
229
|
});
|
|
194
230
|
}
|
|
@@ -197,7 +233,7 @@ function reference(ctx: TransformContext, node: ts.Identifier): void {
|
|
|
197
233
|
right = parent.right;
|
|
198
234
|
|
|
199
235
|
ctx.replacements.push({
|
|
200
|
-
generate: (sf) => `${NAMESPACE}.write(${
|
|
236
|
+
generate: (sf) => `${NAMESPACE}.write(${text}, ${text}.value ${op} ${right.getText(sf)})`,
|
|
201
237
|
node: parent
|
|
202
238
|
});
|
|
203
239
|
}
|
|
@@ -207,13 +243,13 @@ function reference(ctx: TransformContext, node: ts.Identifier): void {
|
|
|
207
243
|
|
|
208
244
|
if (ts.isExpressionStatement(unary.parent)) {
|
|
209
245
|
ctx.replacements.push({
|
|
210
|
-
generate: () => `${NAMESPACE}.write(${
|
|
246
|
+
generate: () => `${NAMESPACE}.write(${text}, ${text}.value ${delta})`,
|
|
211
247
|
node: unary
|
|
212
248
|
});
|
|
213
249
|
}
|
|
214
250
|
else if (ts.isPrefixUnaryExpression(unary)) {
|
|
215
251
|
ctx.replacements.push({
|
|
216
|
-
generate: () => `(${NAMESPACE}.write(${
|
|
252
|
+
generate: () => `(${NAMESPACE}.write(${text}, ${text}.value ${delta}), ${text}.value)`,
|
|
217
253
|
node: unary
|
|
218
254
|
});
|
|
219
255
|
}
|
|
@@ -221,42 +257,55 @@ function reference(ctx: TransformContext, node: ts.Identifier): void {
|
|
|
221
257
|
let tmp = `_t${ctx.tmpCounter++}`;
|
|
222
258
|
|
|
223
259
|
ctx.replacements.push({
|
|
224
|
-
generate: () => `((${tmp}) => (${NAMESPACE}.write(${
|
|
260
|
+
generate: () => `((${tmp}) => (${NAMESPACE}.write(${text}, ${tmp} ${delta}), ${tmp}))(${text}.value)`,
|
|
225
261
|
node: unary
|
|
226
262
|
});
|
|
227
263
|
}
|
|
228
264
|
}
|
|
229
265
|
}
|
|
230
266
|
|
|
231
|
-
// Pass 2: rewrite
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
267
|
+
// Pass 2: rewrite every read and write of a signal or computed binding, resolved by declaration so
|
|
268
|
+
// a binding imported from another module (named, default, namespace, through a barrel) compiles
|
|
269
|
+
// exactly like a local one. Destructuring one out of a module namespace would copy its signal.
|
|
270
|
+
function rewrite(ctx: TransformContext): void {
|
|
271
|
+
let { bindings } = ctx;
|
|
237
272
|
|
|
238
|
-
|
|
239
|
-
|
|
273
|
+
for (let [identifier, found] of bindings.origins) {
|
|
274
|
+
let kind = scope.kind(bindings, found);
|
|
240
275
|
|
|
241
|
-
|
|
276
|
+
if (kind !== TYPES.Signal && kind !== TYPES.Computed) {
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let parent = identifier.parent!;
|
|
281
|
+
|
|
282
|
+
if (ts.isBindingElement(parent) && parent.propertyName === identifier) {
|
|
283
|
+
ctx.failures.push({ message: 'a reactive binding cannot be destructured (it would copy its signal); read it through the namespace', node: identifier });
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
reference(ctx, readNode(identifier), kind);
|
|
242
288
|
}
|
|
243
289
|
|
|
244
|
-
|
|
290
|
+
unpacked(ctx, bindings.sourceFile);
|
|
245
291
|
}
|
|
246
292
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
293
|
+
// `const { count } = ns` names no property to resolve, so each element of a pattern destructuring
|
|
294
|
+
// a module namespace is resolved as the export it copies
|
|
295
|
+
function unpacked(ctx: TransformContext, node: ts.Node): void {
|
|
296
|
+
if (ts.isBindingElement(node) && !node.propertyName && ts.isObjectBindingPattern(node.parent)) {
|
|
297
|
+
let initializer = (node.parent.parent as { initializer?: ts.Expression }).initializer;
|
|
250
298
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
299
|
+
if (initializer && isNamespace(ctx.bindings, initializer)) {
|
|
300
|
+
let kind = scope.kind(ctx.bindings, scope.origin(ctx.bindings, node));
|
|
254
301
|
|
|
255
|
-
|
|
256
|
-
|
|
302
|
+
if (kind === TYPES.Signal || kind === TYPES.Computed) {
|
|
303
|
+
ctx.failures.push({ message: 'a reactive binding cannot be destructured (it would copy its signal); read it through the namespace', node });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
257
306
|
}
|
|
258
307
|
|
|
259
|
-
|
|
308
|
+
node.forEachChild(child => unpacked(ctx, child));
|
|
260
309
|
}
|
|
261
310
|
|
|
262
311
|
|
|
@@ -264,13 +313,15 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: I
|
|
|
264
313
|
let ctx: TransformContext = {
|
|
265
314
|
bindings,
|
|
266
315
|
calls: [],
|
|
316
|
+
failures: [],
|
|
267
317
|
isReactiveCall,
|
|
268
318
|
replacements: [],
|
|
269
319
|
tmpCounter: 0
|
|
270
320
|
};
|
|
271
321
|
|
|
272
322
|
declare(ctx, sourceFile);
|
|
273
|
-
rewrite(ctx
|
|
323
|
+
rewrite(ctx);
|
|
274
324
|
|
|
275
|
-
return { calls: ctx.calls, replacements: ctx.replacements };
|
|
325
|
+
return { calls: ctx.calls, failures: ctx.failures, replacements: ctx.replacements };
|
|
276
326
|
};
|
|
327
|
+
export type { Failure };
|
package/src/compiler/types.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { ts } from '@esportsplus/typescript';
|
|
2
|
-
import type {
|
|
2
|
+
import type { Origin } from '@esportsplus/typescript/compiler';
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
// What a file is compiled against: its values resolved to their declarations, and the
|
|
6
|
+
// declarations `reactive` resolves to (one per installed copy of the package)
|
|
5
7
|
type Bindings = {
|
|
6
8
|
checker: ts.Checker;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
entries: Set<string>;
|
|
10
|
+
origins: Map<ts.Node, Origin>;
|
|
11
|
+
program: ts.Program;
|
|
12
|
+
sourceFile: ts.SourceFile;
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
type IsReactiveCall = (node: ts.Node) => node is ts.CallExpression;
|
package/src/types.ts
CHANGED
|
@@ -43,7 +43,8 @@ declare const READONLY: unique symbol;
|
|
|
43
43
|
type Reactive<T> = T extends (...args: never[]) => infer R
|
|
44
44
|
? Settled<R> & { readonly [READONLY]: true }
|
|
45
45
|
: T extends (infer U)[]
|
|
46
|
-
|
|
46
|
+
// `$length` / `$set` are what the compiler lowers `.length` and element writes to
|
|
47
|
+
? U[] & Pick<ReactiveArray<U>, '$length' | '$set' | 'clear' | 'dispose' | 'on' | 'once'>
|
|
47
48
|
: T extends Record<PropertyKey, unknown>
|
|
48
49
|
? { [K in keyof T]: T[K] extends (infer U)[] ? Reactive<U[]> : T[K]; } & { dispose: VoidFunction }
|
|
49
50
|
: T;
|