@esportsplus/reactivity 0.29.13 → 0.29.14
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/object.d.ts +1 -1
- package/build/compiler/object.js +51 -24
- package/package.json +1 -1
- package/src/compiler/object.ts +71 -36
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
3
|
import type { Bindings } from './types.js';
|
|
4
4
|
type ObjectTransformResult = {
|
package/build/compiler/object.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { code } from '@esportsplus/typescript/compiler';
|
|
1
2
|
import { ts } from '@esportsplus/typescript';
|
|
2
3
|
import { uid } from '@esportsplus/typescript/compiler';
|
|
3
4
|
import { NAMESPACE, TYPES } from './constants.js';
|
|
@@ -28,12 +29,21 @@ function analyzeProperty(prop, sourceFile) {
|
|
|
28
29
|
}
|
|
29
30
|
return { isStatic, key, type: TYPES.Array, valueText };
|
|
30
31
|
}
|
|
31
|
-
return {
|
|
32
|
+
return {
|
|
33
|
+
isStatic: isStaticValue(value),
|
|
34
|
+
key,
|
|
35
|
+
type: TYPES.Signal,
|
|
36
|
+
valueText
|
|
37
|
+
};
|
|
32
38
|
}
|
|
33
|
-
function buildClassCode(
|
|
34
|
-
let accessors = [], body = [], fields = [], generics = [], parameters = [], setters = 0;
|
|
39
|
+
function buildClassCode(classname, properties, typehint) {
|
|
40
|
+
let accessors = [], body = [], constraint = [], fields = [], generics = [], parameters = [], setters = 0;
|
|
35
41
|
for (let i = 0, n = properties.length; i < n; i++) {
|
|
36
|
-
let { isStatic, key, type, valueText } = properties[i], generic = `T${parameters.length}`, parameter = `_p${parameters.length}`;
|
|
42
|
+
let { isStatic, key, type, valueText } = properties[i], generic = typehint ? `T['${key}']` : `T${parameters.length}`, parameter = `_p${parameters.length}`;
|
|
43
|
+
if (typehint && type === TYPES.Signal) {
|
|
44
|
+
constraint.push(`'${key}'?: unknown`);
|
|
45
|
+
isStatic = false;
|
|
46
|
+
}
|
|
37
47
|
if (type === TYPES.Signal) {
|
|
38
48
|
let value = `_v${setters++}`;
|
|
39
49
|
if (isStatic) {
|
|
@@ -58,11 +68,16 @@ function buildClassCode(className, properties) {
|
|
|
58
68
|
`);
|
|
59
69
|
body.push(`this.#${key} = this[${NAMESPACE}.SIGNAL](${parameter});`);
|
|
60
70
|
fields.push(`#${key};`);
|
|
61
|
-
|
|
71
|
+
if (!typehint) {
|
|
72
|
+
generics.push(generic);
|
|
73
|
+
}
|
|
62
74
|
parameters.push(`${parameter}: ${generic}`);
|
|
63
75
|
}
|
|
64
76
|
}
|
|
65
77
|
else if (type === TYPES.Array) {
|
|
78
|
+
if (typehint) {
|
|
79
|
+
constraint.push(`'${key}'?: unknown[]`);
|
|
80
|
+
}
|
|
66
81
|
accessors.push(`
|
|
67
82
|
get ${key}() {
|
|
68
83
|
return this.#${key};
|
|
@@ -70,10 +85,15 @@ function buildClassCode(className, properties) {
|
|
|
70
85
|
`);
|
|
71
86
|
body.push(`this.#${key} = this[${NAMESPACE}.REACTIVE_ARRAY](${parameter});`);
|
|
72
87
|
fields.push(`#${key};`);
|
|
73
|
-
|
|
88
|
+
if (!typehint) {
|
|
89
|
+
generics.push(`${generic} extends unknown[]`);
|
|
90
|
+
}
|
|
74
91
|
parameters.push(`${parameter}: ${generic}`);
|
|
75
92
|
}
|
|
76
93
|
else if (type === TYPES.Computed) {
|
|
94
|
+
if (typehint) {
|
|
95
|
+
constraint.push(`'${key}'?: unknown`);
|
|
96
|
+
}
|
|
77
97
|
accessors.push(`
|
|
78
98
|
get ${key}() {
|
|
79
99
|
return ${NAMESPACE}.read(this.#${key});
|
|
@@ -81,34 +101,35 @@ function buildClassCode(className, properties) {
|
|
|
81
101
|
`);
|
|
82
102
|
body.push(`this.#${key} = this[${NAMESPACE}.COMPUTED](${parameter});`);
|
|
83
103
|
fields.push(`#${key};`);
|
|
84
|
-
|
|
104
|
+
if (!typehint) {
|
|
105
|
+
generics.push(`${generic} extends ${NAMESPACE}.Computed<ReturnType<${generic}>>['fn']`);
|
|
106
|
+
}
|
|
85
107
|
parameters.push(`${parameter}: ${generic}`);
|
|
86
108
|
}
|
|
87
109
|
}
|
|
88
|
-
return `
|
|
89
|
-
class ${
|
|
110
|
+
return code `
|
|
111
|
+
class ${classname}${typehint
|
|
112
|
+
? `<T extends { ${constraint.join(', ')} }>`
|
|
113
|
+
: generics.length && `<${generics.join(', ')}>`} extends ${NAMESPACE}.ReactiveObject<any> {
|
|
90
114
|
${fields.join('\n')}
|
|
115
|
+
|
|
91
116
|
constructor(${parameters.join(', ')}) {
|
|
92
117
|
super(null);
|
|
93
118
|
${body.join('\n')}
|
|
94
119
|
}
|
|
120
|
+
|
|
95
121
|
${accessors.join('\n')}
|
|
96
122
|
}
|
|
97
123
|
`;
|
|
98
124
|
}
|
|
99
125
|
function isStaticValue(node) {
|
|
100
|
-
|
|
126
|
+
return ts.isNumericLiteral(node) ||
|
|
101
127
|
ts.isStringLiteral(node) ||
|
|
102
128
|
node.kind === ts.SyntaxKind.TrueKeyword ||
|
|
103
129
|
node.kind === ts.SyntaxKind.FalseKeyword ||
|
|
104
130
|
node.kind === ts.SyntaxKind.NullKeyword ||
|
|
105
|
-
node.kind === ts.SyntaxKind.UndefinedKeyword
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
if (ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand)) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
return false;
|
|
131
|
+
node.kind === ts.SyntaxKind.UndefinedKeyword ||
|
|
132
|
+
(ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand));
|
|
112
133
|
}
|
|
113
134
|
function visit(ctx, node) {
|
|
114
135
|
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'reactive') {
|
|
@@ -136,9 +157,10 @@ function visit(ctx, node) {
|
|
|
136
157
|
}
|
|
137
158
|
}
|
|
138
159
|
ctx.calls.push({
|
|
139
|
-
|
|
160
|
+
classname: uid('ReactiveObject'),
|
|
140
161
|
node,
|
|
141
162
|
properties,
|
|
163
|
+
typehint: node.typeArguments?.[0]?.getText(ctx.sourceFile) ?? null,
|
|
142
164
|
varname
|
|
143
165
|
});
|
|
144
166
|
}
|
|
@@ -154,13 +176,18 @@ export default (sourceFile, bindings) => {
|
|
|
154
176
|
visit(ctx, sourceFile);
|
|
155
177
|
let prepend = [], replacements = [];
|
|
156
178
|
for (let i = 0, n = ctx.calls.length; i < n; i++) {
|
|
157
|
-
let call = ctx.calls[i];
|
|
158
|
-
prepend.push(buildClassCode(call.
|
|
179
|
+
let call = ctx.calls[i], typehint = call.typehint;
|
|
180
|
+
prepend.push(buildClassCode(call.classname, call.properties, typehint));
|
|
159
181
|
replacements.push({
|
|
160
|
-
generate: () =>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
182
|
+
generate: () => {
|
|
183
|
+
let args = call.properties
|
|
184
|
+
.filter(({ isStatic, type }) => typehint || !isStatic || type === TYPES.Computed)
|
|
185
|
+
.map(p => p.valueText)
|
|
186
|
+
.join(', ');
|
|
187
|
+
return typehint
|
|
188
|
+
? ` new ${call.classname}<${typehint}>(${args})`
|
|
189
|
+
: ` new ${call.classname}(${args})`;
|
|
190
|
+
},
|
|
164
191
|
node: call.node,
|
|
165
192
|
});
|
|
166
193
|
}
|
package/package.json
CHANGED
package/src/compiler/object.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { code, type ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
3
|
import { uid } from '@esportsplus/typescript/compiler';
|
|
4
4
|
import { NAMESPACE, TYPES } from './constants';
|
|
@@ -12,10 +12,16 @@ interface AnalyzedProperty {
|
|
|
12
12
|
valueText: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
type ObjectTransformResult = {
|
|
16
|
+
prepend: string[];
|
|
17
|
+
replacements: ReplacementIntent[];
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
interface ReactiveObjectCall {
|
|
16
|
-
|
|
21
|
+
classname: string;
|
|
17
22
|
node: ts.CallExpression;
|
|
18
23
|
properties: AnalyzedProperty[];
|
|
24
|
+
typehint: string | null;
|
|
19
25
|
varname: string | null;
|
|
20
26
|
}
|
|
21
27
|
|
|
@@ -65,12 +71,18 @@ function analyzeProperty(prop: ts.ObjectLiteralElementLike, sourceFile: ts.Sourc
|
|
|
65
71
|
return { isStatic, key, type: TYPES.Array, valueText };
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
return {
|
|
74
|
+
return {
|
|
75
|
+
isStatic: isStaticValue(value),
|
|
76
|
+
key,
|
|
77
|
+
type: TYPES.Signal,
|
|
78
|
+
valueText
|
|
79
|
+
};
|
|
69
80
|
}
|
|
70
81
|
|
|
71
|
-
function buildClassCode(
|
|
82
|
+
function buildClassCode(classname: string, properties: AnalyzedProperty[], typehint: string | null): string {
|
|
72
83
|
let accessors: string[] = [],
|
|
73
84
|
body: string[] = [],
|
|
85
|
+
constraint: string[] = [],
|
|
74
86
|
fields: string[] = [],
|
|
75
87
|
generics: string[] = [],
|
|
76
88
|
parameters: string[] = [],
|
|
@@ -78,9 +90,15 @@ function buildClassCode(className: string, properties: AnalyzedProperty[]): stri
|
|
|
78
90
|
|
|
79
91
|
for (let i = 0, n = properties.length; i < n; i++) {
|
|
80
92
|
let { isStatic, key, type, valueText } = properties[i],
|
|
81
|
-
generic = `T${parameters.length}`,
|
|
93
|
+
generic = typehint ? `T['${key}']` : `T${parameters.length}`,
|
|
82
94
|
parameter = `_p${parameters.length}`;
|
|
83
95
|
|
|
96
|
+
// When typehint is present, treat signal properties as non-static to preserve types
|
|
97
|
+
if (typehint && type === TYPES.Signal) {
|
|
98
|
+
constraint.push(`'${key}'?: unknown`);
|
|
99
|
+
isStatic = false;
|
|
100
|
+
}
|
|
101
|
+
|
|
84
102
|
if (type === TYPES.Signal) {
|
|
85
103
|
let value = `_v${setters++}`;
|
|
86
104
|
|
|
@@ -106,11 +124,19 @@ function buildClassCode(className: string, properties: AnalyzedProperty[]): stri
|
|
|
106
124
|
`);
|
|
107
125
|
body.push(`this.#${key} = this[${NAMESPACE}.SIGNAL](${parameter});`);
|
|
108
126
|
fields.push(`#${key};`);
|
|
109
|
-
|
|
127
|
+
|
|
128
|
+
if (!typehint) {
|
|
129
|
+
generics.push(generic);
|
|
130
|
+
}
|
|
131
|
+
|
|
110
132
|
parameters.push(`${parameter}: ${generic}`);
|
|
111
133
|
}
|
|
112
134
|
}
|
|
113
135
|
else if (type === TYPES.Array) {
|
|
136
|
+
if (typehint) {
|
|
137
|
+
constraint.push(`'${key}'?: unknown[]`);
|
|
138
|
+
}
|
|
139
|
+
|
|
114
140
|
accessors.push(`
|
|
115
141
|
get ${key}() {
|
|
116
142
|
return this.#${key};
|
|
@@ -118,10 +144,18 @@ function buildClassCode(className: string, properties: AnalyzedProperty[]): stri
|
|
|
118
144
|
`);
|
|
119
145
|
body.push(`this.#${key} = this[${NAMESPACE}.REACTIVE_ARRAY](${parameter});`);
|
|
120
146
|
fields.push(`#${key};`);
|
|
121
|
-
|
|
147
|
+
|
|
148
|
+
if (!typehint) {
|
|
149
|
+
generics.push(`${generic} extends unknown[]`);
|
|
150
|
+
}
|
|
151
|
+
|
|
122
152
|
parameters.push(`${parameter}: ${generic}`);
|
|
123
153
|
}
|
|
124
154
|
else if (type === TYPES.Computed) {
|
|
155
|
+
if (typehint) {
|
|
156
|
+
constraint.push(`'${key}'?: unknown`);
|
|
157
|
+
}
|
|
158
|
+
|
|
125
159
|
accessors.push(`
|
|
126
160
|
get ${key}() {
|
|
127
161
|
return ${NAMESPACE}.read(this.#${key});
|
|
@@ -129,40 +163,41 @@ function buildClassCode(className: string, properties: AnalyzedProperty[]): stri
|
|
|
129
163
|
`);
|
|
130
164
|
body.push(`this.#${key} = this[${NAMESPACE}.COMPUTED](${parameter});`);
|
|
131
165
|
fields.push(`#${key};`);
|
|
132
|
-
|
|
166
|
+
|
|
167
|
+
if (!typehint) {
|
|
168
|
+
generics.push(`${generic} extends ${NAMESPACE}.Computed<ReturnType<${generic}>>['fn']`);
|
|
169
|
+
}
|
|
170
|
+
|
|
133
171
|
parameters.push(`${parameter}: ${generic}`);
|
|
134
172
|
}
|
|
135
173
|
}
|
|
136
174
|
|
|
137
|
-
return `
|
|
138
|
-
class ${
|
|
175
|
+
return code`
|
|
176
|
+
class ${classname}${
|
|
177
|
+
typehint
|
|
178
|
+
? `<T extends { ${constraint.join(', ')} }>`
|
|
179
|
+
: generics.length && `<${generics.join(', ')}>`
|
|
180
|
+
} extends ${NAMESPACE}.ReactiveObject<any> {
|
|
139
181
|
${fields.join('\n')}
|
|
182
|
+
|
|
140
183
|
constructor(${parameters.join(', ')}) {
|
|
141
184
|
super(null);
|
|
142
185
|
${body.join('\n')}
|
|
143
186
|
}
|
|
187
|
+
|
|
144
188
|
${accessors.join('\n')}
|
|
145
189
|
}
|
|
146
190
|
`;
|
|
147
191
|
}
|
|
148
192
|
|
|
149
193
|
function isStaticValue(node: ts.Node): boolean {
|
|
150
|
-
|
|
151
|
-
ts.isNumericLiteral(node) ||
|
|
194
|
+
return ts.isNumericLiteral(node) ||
|
|
152
195
|
ts.isStringLiteral(node) ||
|
|
153
196
|
node.kind === ts.SyntaxKind.TrueKeyword ||
|
|
154
197
|
node.kind === ts.SyntaxKind.FalseKeyword ||
|
|
155
198
|
node.kind === ts.SyntaxKind.NullKeyword ||
|
|
156
|
-
node.kind === ts.SyntaxKind.UndefinedKeyword
|
|
157
|
-
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand)) {
|
|
162
|
-
return true;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return false;
|
|
199
|
+
node.kind === ts.SyntaxKind.UndefinedKeyword ||
|
|
200
|
+
(ts.isPrefixUnaryExpression(node) && ts.isNumericLiteral(node.operand));
|
|
166
201
|
}
|
|
167
202
|
|
|
168
203
|
function visit(ctx: VisitContext, node: ts.Node): void {
|
|
@@ -202,9 +237,10 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
202
237
|
}
|
|
203
238
|
|
|
204
239
|
ctx.calls.push({
|
|
205
|
-
|
|
240
|
+
classname: uid('ReactiveObject'),
|
|
206
241
|
node,
|
|
207
242
|
properties,
|
|
243
|
+
typehint: node.typeArguments?.[0]?.getText(ctx.sourceFile) ?? null,
|
|
208
244
|
varname
|
|
209
245
|
});
|
|
210
246
|
}
|
|
@@ -214,12 +250,6 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
214
250
|
}
|
|
215
251
|
|
|
216
252
|
|
|
217
|
-
type ObjectTransformResult = {
|
|
218
|
-
prepend: string[];
|
|
219
|
-
replacements: ReplacementIntent[];
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
|
|
223
253
|
export default (sourceFile: ts.SourceFile, bindings: Bindings): ObjectTransformResult => {
|
|
224
254
|
let ctx: VisitContext = {
|
|
225
255
|
bindings,
|
|
@@ -233,16 +263,21 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings): ObjectTransformR
|
|
|
233
263
|
replacements: ReplacementIntent[] = [];
|
|
234
264
|
|
|
235
265
|
for (let i = 0, n = ctx.calls.length; i < n; i++) {
|
|
236
|
-
let call = ctx.calls[i]
|
|
266
|
+
let call = ctx.calls[i],
|
|
267
|
+
typehint = call.typehint;
|
|
237
268
|
|
|
238
|
-
prepend.push(buildClassCode(call.
|
|
269
|
+
prepend.push(buildClassCode(call.classname, call.properties, typehint));
|
|
239
270
|
replacements.push({
|
|
240
|
-
generate: () =>
|
|
241
|
-
call.properties
|
|
242
|
-
.filter(({ isStatic, type }) => !isStatic || type === TYPES.Computed)
|
|
271
|
+
generate: () => {
|
|
272
|
+
let args = call.properties
|
|
273
|
+
.filter(({ isStatic, type }) => typehint || !isStatic || type === TYPES.Computed)
|
|
243
274
|
.map(p => p.valueText)
|
|
244
|
-
.join(', ')
|
|
245
|
-
|
|
275
|
+
.join(', ');
|
|
276
|
+
|
|
277
|
+
return typehint
|
|
278
|
+
? ` new ${call.classname}<${typehint}>(${args})`
|
|
279
|
+
: ` new ${call.classname}(${args})`;
|
|
280
|
+
},
|
|
246
281
|
node: call.node,
|
|
247
282
|
});
|
|
248
283
|
}
|