@esportsplus/reactivity 0.25.2 → 0.25.4
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/constants.d.ts +8 -1
- package/build/constants.js +8 -1
- package/build/index.d.ts +2 -2
- package/build/index.js +2 -2
- package/build/reactive/array.js +18 -27
- package/build/reactive/index.d.ts +14 -15
- package/build/reactive/index.js +2 -2
- package/build/system.d.ts +2 -2
- package/build/system.js +10 -10
- package/build/transformer/detector.d.ts +2 -2
- package/build/transformer/detector.js +14 -14
- package/build/transformer/index.d.ts +3 -7
- package/build/transformer/index.js +21 -39
- package/build/transformer/plugins/tsc.js +7 -2
- package/build/transformer/plugins/vite.js +7 -9
- package/build/transformer/transforms/array.d.ts +3 -3
- package/build/transformer/transforms/array.js +16 -19
- package/build/transformer/transforms/object.d.ts +3 -3
- package/build/transformer/transforms/object.js +41 -57
- package/build/transformer/transforms/primitives.d.ts +3 -3
- package/build/transformer/transforms/primitives.js +60 -117
- package/build/types.d.ts +2 -2
- package/package.json +6 -6
- package/readme.md +5 -5
- package/src/constants.ts +20 -13
- package/src/index.ts +2 -2
- package/src/reactive/array.ts +18 -32
- package/src/reactive/index.ts +18 -19
- package/src/system.ts +14 -21
- package/src/transformer/detector.ts +16 -25
- package/src/transformer/index.ts +24 -46
- package/src/transformer/plugins/tsc.ts +8 -2
- package/src/transformer/plugins/vite.ts +9 -12
- package/src/transformer/transforms/array.ts +20 -33
- package/src/transformer/transforms/object.ts +55 -79
- package/src/transformer/transforms/primitives.ts +70 -144
- package/src/types.ts +5 -3
- package/test/vite.config.ts +1 -1
- package/build/transformer/transforms/utilities.d.ts +0 -8
- package/build/transformer/transforms/utilities.js +0 -27
- package/src/transformer/transforms/utilities.ts +0 -45
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import { uid } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import type { Bindings } from '~/types';
|
|
3
|
-
import { addMissingImports, applyReplacements, ExtraImport, Replacement } from './utilities';
|
|
4
1
|
import { ts } from '@esportsplus/typescript';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const EXTRA_IMPORTS: ExtraImport[] = [
|
|
10
|
-
{ module: '@esportsplus/reactivity/constants', specifier: 'REACTIVE_OBJECT' },
|
|
11
|
-
{ module: '@esportsplus/reactivity/reactive/array', specifier: 'ReactiveArray' }
|
|
12
|
-
];
|
|
2
|
+
import { code as c, type Replacement } from '@esportsplus/typescript/transformer';
|
|
3
|
+
import { COMPILATION_TYPE_ARRAY, COMPILATION_TYPE_COMPUTED, COMPILATION_TYPE_SIGNAL, PACKAGE } from '~/constants';
|
|
4
|
+
import type { Bindings } from '~/types';
|
|
13
5
|
|
|
14
6
|
|
|
15
7
|
interface AnalyzedProperty {
|
|
@@ -19,19 +11,20 @@ interface AnalyzedProperty {
|
|
|
19
11
|
}
|
|
20
12
|
|
|
21
13
|
interface ReactiveObjectCall {
|
|
14
|
+
className: string;
|
|
22
15
|
end: number;
|
|
23
|
-
|
|
24
|
-
needsImports: Set<string>;
|
|
16
|
+
properties: AnalyzedProperty[];
|
|
25
17
|
start: number;
|
|
26
18
|
varName: string | null;
|
|
27
19
|
}
|
|
28
20
|
|
|
29
21
|
interface TransformContext {
|
|
30
|
-
allNeededImports: Set<string>;
|
|
31
22
|
bindings: Bindings;
|
|
32
23
|
calls: ReactiveObjectCall[];
|
|
24
|
+
classCounter: number;
|
|
33
25
|
hasReactiveImport: boolean;
|
|
34
26
|
lastImportEnd: number;
|
|
27
|
+
ns: string;
|
|
35
28
|
sourceFile: ts.SourceFile;
|
|
36
29
|
}
|
|
37
30
|
|
|
@@ -54,43 +47,53 @@ function analyzeProperty(prop: ts.ObjectLiteralElementLike, sourceFile: ts.Sourc
|
|
|
54
47
|
valueText = value.getText(sourceFile);
|
|
55
48
|
|
|
56
49
|
if (ts.isArrowFunction(value) || ts.isFunctionExpression(value)) {
|
|
57
|
-
return { key, type:
|
|
50
|
+
return { key, type: COMPILATION_TYPE_COMPUTED, valueText };
|
|
58
51
|
}
|
|
59
52
|
|
|
60
53
|
if (ts.isArrayLiteralExpression(value)) {
|
|
61
|
-
|
|
54
|
+
let elements = value.elements,
|
|
55
|
+
elementsText = '';
|
|
56
|
+
|
|
57
|
+
for (let i = 0, n = elements.length; i < n; i++) {
|
|
58
|
+
if (i > 0) {
|
|
59
|
+
elementsText += ', ';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
elementsText += elements[i].getText(sourceFile);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { key, type: COMPILATION_TYPE_ARRAY, valueText: elementsText };
|
|
62
66
|
}
|
|
63
67
|
|
|
64
|
-
return { key, type:
|
|
68
|
+
return { key, type: COMPILATION_TYPE_SIGNAL, valueText };
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
function buildClassCode(className: string, properties: AnalyzedProperty[]): string {
|
|
71
|
+
function buildClassCode(className: string, properties: AnalyzedProperty[], ns: string): string {
|
|
68
72
|
let accessors: string[] = [],
|
|
69
73
|
disposeStatements: string[] = [],
|
|
70
|
-
fields: string[] = []
|
|
74
|
+
fields: string[] = [],
|
|
75
|
+
paramCounter = 0;
|
|
71
76
|
|
|
72
|
-
fields.push(`[REACTIVE_OBJECT] = true;`);
|
|
77
|
+
fields.push(`[${ns}.REACTIVE_OBJECT] = true;`);
|
|
73
78
|
|
|
74
79
|
for (let i = 0, n = properties.length; i < n; i++) {
|
|
75
80
|
let { key, type, valueText } = properties[i];
|
|
76
81
|
|
|
77
|
-
if (type ===
|
|
78
|
-
let param =
|
|
82
|
+
if (type === COMPILATION_TYPE_SIGNAL) {
|
|
83
|
+
let param = `_v${paramCounter++}`;
|
|
79
84
|
|
|
80
|
-
fields.push(`#${key} = signal(${valueText});`);
|
|
81
|
-
accessors.push(`get ${key}() { return read(this.#${key}); }`);
|
|
82
|
-
accessors.push(`set ${key}(${param}) {
|
|
85
|
+
fields.push(`#${key} = ${ns}.signal(${valueText});`);
|
|
86
|
+
accessors.push(`get ${key}() { return ${ns}.read(this.#${key}); }`);
|
|
87
|
+
accessors.push(`set ${key}(${param}) { ${ns}.write(this.#${key}, ${param}); }`);
|
|
83
88
|
}
|
|
84
|
-
else if (type ===
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
fields.push(`${key} = new ReactiveArray(${elements});`);
|
|
89
|
+
else if (type === COMPILATION_TYPE_ARRAY) {
|
|
90
|
+
fields.push(`${key} = new ${ns}.ReactiveArray(${valueText});`);
|
|
88
91
|
disposeStatements.push(`this.${key}.dispose();`);
|
|
89
92
|
}
|
|
90
|
-
else if (type ===
|
|
91
|
-
fields.push(`#${key}
|
|
92
|
-
accessors.push(`get ${key}() { return read(this.#${key} ??= computed(${valueText})); }`);
|
|
93
|
-
disposeStatements.push(`if (this.#${key}) dispose(this.#${key});`);
|
|
93
|
+
else if (type === COMPILATION_TYPE_COMPUTED) {
|
|
94
|
+
fields.push(`#${key} = null;`);
|
|
95
|
+
accessors.push(`get ${key}() { return ${ns}.read(this.#${key} ??= ${ns}.computed(${valueText})); }`);
|
|
96
|
+
disposeStatements.push(`if (this.#${key}) ${ns}.dispose(this.#${key});`);
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
@@ -112,7 +115,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
112
115
|
|
|
113
116
|
if (
|
|
114
117
|
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
115
|
-
node.moduleSpecifier.text.includes(
|
|
118
|
+
node.moduleSpecifier.text.includes(PACKAGE)
|
|
116
119
|
) {
|
|
117
120
|
let clause = node.importClause;
|
|
118
121
|
|
|
@@ -138,20 +141,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
138
141
|
let arg = node.arguments[0];
|
|
139
142
|
|
|
140
143
|
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
141
|
-
let
|
|
144
|
+
let properties: AnalyzedProperty[] = [],
|
|
145
|
+
props = arg.properties,
|
|
146
|
+
varName: string | null = null;
|
|
142
147
|
|
|
143
|
-
if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
148
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
144
149
|
varName = node.parent.name.text;
|
|
145
150
|
ctx.bindings.set(varName, 'object');
|
|
146
151
|
}
|
|
147
152
|
|
|
148
|
-
let needsImports = new Set<string>(),
|
|
149
|
-
properties: AnalyzedProperty[] = [];
|
|
150
|
-
|
|
151
|
-
needsImports.add('REACTIVE_OBJECT');
|
|
152
|
-
|
|
153
|
-
let props = arg.properties;
|
|
154
|
-
|
|
155
153
|
for (let i = 0, n = props.length; i < n; i++) {
|
|
156
154
|
let prop = props[i];
|
|
157
155
|
|
|
@@ -169,31 +167,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
169
167
|
|
|
170
168
|
properties.push(analyzed);
|
|
171
169
|
|
|
172
|
-
if (analyzed.type ===
|
|
173
|
-
|
|
174
|
-
needsImports.add('set');
|
|
175
|
-
needsImports.add('signal');
|
|
176
|
-
}
|
|
177
|
-
else if (analyzed.type === 'array') {
|
|
178
|
-
needsImports.add('ReactiveArray');
|
|
179
|
-
|
|
180
|
-
if (varName) {
|
|
181
|
-
ctx.bindings.set(`${varName}.${analyzed.key}`, 'array');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else if (analyzed.type === 'computed') {
|
|
185
|
-
needsImports.add('computed');
|
|
186
|
-
needsImports.add('dispose');
|
|
187
|
-
needsImports.add('read');
|
|
170
|
+
if (analyzed.type === COMPILATION_TYPE_ARRAY && varName) {
|
|
171
|
+
ctx.bindings.set(`${varName}.${analyzed.key}`, COMPILATION_TYPE_ARRAY);
|
|
188
172
|
}
|
|
189
173
|
}
|
|
190
174
|
|
|
191
|
-
needsImports.forEach(imp => ctx.allNeededImports.add(imp));
|
|
192
|
-
|
|
193
175
|
ctx.calls.push({
|
|
176
|
+
className: `_RO${ctx.classCounter++}`,
|
|
194
177
|
end: node.end,
|
|
195
|
-
|
|
196
|
-
needsImports,
|
|
178
|
+
properties,
|
|
197
179
|
start: node.pos,
|
|
198
180
|
varName
|
|
199
181
|
});
|
|
@@ -204,14 +186,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
204
186
|
}
|
|
205
187
|
|
|
206
188
|
|
|
207
|
-
|
|
189
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
|
|
208
190
|
let code = sourceFile.getFullText(),
|
|
209
191
|
ctx: TransformContext = {
|
|
210
|
-
allNeededImports: new Set<string>(),
|
|
211
192
|
bindings,
|
|
212
193
|
calls: [],
|
|
194
|
+
classCounter: 0,
|
|
213
195
|
hasReactiveImport: false,
|
|
214
196
|
lastImportEnd: 0,
|
|
197
|
+
ns,
|
|
215
198
|
sourceFile
|
|
216
199
|
};
|
|
217
200
|
|
|
@@ -221,31 +204,24 @@ const transformReactiveObjects = (sourceFile: ts.SourceFile, bindings: Bindings)
|
|
|
221
204
|
return code;
|
|
222
205
|
}
|
|
223
206
|
|
|
224
|
-
let
|
|
207
|
+
let classes = ctx.calls.map(c => buildClassCode(c.className, c.properties, ns)).join('\n'),
|
|
208
|
+
replacements: Replacement[] = [];
|
|
225
209
|
|
|
226
210
|
replacements.push({
|
|
227
211
|
end: ctx.lastImportEnd,
|
|
228
|
-
newText: code.substring(0, ctx.lastImportEnd) + '\n' +
|
|
212
|
+
newText: code.substring(0, ctx.lastImportEnd) + '\n' + classes + '\n',
|
|
229
213
|
start: 0
|
|
230
214
|
});
|
|
231
215
|
|
|
232
216
|
for (let i = 0, n = ctx.calls.length; i < n; i++) {
|
|
233
|
-
let call = ctx.calls[i]
|
|
234
|
-
classMatch = call.generatedClass.match(CLASS_NAME_REGEX);
|
|
217
|
+
let call = ctx.calls[i];
|
|
235
218
|
|
|
236
219
|
replacements.push({
|
|
237
220
|
end: call.end,
|
|
238
|
-
newText: ` new ${
|
|
221
|
+
newText: ` new ${call.className}()`,
|
|
239
222
|
start: call.start
|
|
240
223
|
});
|
|
241
224
|
}
|
|
242
225
|
|
|
243
|
-
return
|
|
244
|
-
|
|
245
|
-
ctx.allNeededImports,
|
|
246
|
-
EXTRA_IMPORTS
|
|
247
|
-
);
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
export { transformReactiveObjects };
|
|
226
|
+
return c.replace(code, replacements);
|
|
227
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { uid, type Range } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import type { BindingType, Bindings } from '~/types';
|
|
3
|
-
import { addMissingImports, applyReplacements, Replacement } from './utilities';
|
|
4
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
import { code as c, type Range, type Replacement } from '@esportsplus/typescript/transformer';
|
|
3
|
+
import type { BindingType, Bindings } from '~/types';
|
|
4
|
+
import { COMPILATION_TYPE_COMPUTED, COMPILATION_ENTRYPOINT, COMPILATION_TYPE_SIGNAL, PACKAGE } from '~/constants';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
interface ArgContext {
|
|
8
8
|
argStart: number;
|
|
9
9
|
innerReplacements: Replacement[];
|
|
10
|
-
|
|
10
|
+
ns: string;
|
|
11
11
|
scopedBindings: ScopeBinding[];
|
|
12
12
|
sourceFile: ts.SourceFile;
|
|
13
13
|
}
|
|
@@ -22,23 +22,43 @@ interface TransformContext {
|
|
|
22
22
|
bindings: Bindings;
|
|
23
23
|
computedArgRanges: Range[];
|
|
24
24
|
hasReactiveImport: boolean;
|
|
25
|
-
|
|
25
|
+
ns: string;
|
|
26
26
|
replacements: Replacement[];
|
|
27
27
|
scopedBindings: ScopeBinding[];
|
|
28
28
|
sourceFile: ts.SourceFile;
|
|
29
|
+
tmpCounter: number;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
let COMPOUND_OPERATORS = new Map<ts.SyntaxKind, string>([
|
|
34
|
+
[ts.SyntaxKind.AmpersandAmpersandEqualsToken, '&&'],
|
|
35
|
+
[ts.SyntaxKind.AmpersandEqualsToken, '&'],
|
|
36
|
+
[ts.SyntaxKind.AsteriskAsteriskEqualsToken, '**'],
|
|
37
|
+
[ts.SyntaxKind.AsteriskEqualsToken, '*'],
|
|
38
|
+
[ts.SyntaxKind.BarBarEqualsToken, '||'],
|
|
39
|
+
[ts.SyntaxKind.BarEqualsToken, '|'],
|
|
40
|
+
[ts.SyntaxKind.CaretEqualsToken, '^'],
|
|
41
|
+
[ts.SyntaxKind.GreaterThanGreaterThanEqualsToken, '>>'],
|
|
42
|
+
[ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, '>>>'],
|
|
43
|
+
[ts.SyntaxKind.LessThanLessThanEqualsToken, '<<'],
|
|
44
|
+
[ts.SyntaxKind.MinusEqualsToken, '-'],
|
|
45
|
+
[ts.SyntaxKind.PercentEqualsToken, '%'],
|
|
46
|
+
[ts.SyntaxKind.PlusEqualsToken, '+'],
|
|
47
|
+
[ts.SyntaxKind.QuestionQuestionEqualsToken, '??'],
|
|
48
|
+
[ts.SyntaxKind.SlashEqualsToken, '/']
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
function classifyReactiveArg(arg: ts.Expression): BindingType | null {
|
|
33
53
|
if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
34
|
-
return
|
|
54
|
+
return COMPILATION_TYPE_COMPUTED;
|
|
35
55
|
}
|
|
36
56
|
|
|
37
57
|
if (ts.isObjectLiteralExpression(arg) || ts.isArrayLiteralExpression(arg)) {
|
|
38
58
|
return null;
|
|
39
59
|
}
|
|
40
60
|
|
|
41
|
-
return
|
|
61
|
+
return COMPILATION_TYPE_SIGNAL;
|
|
42
62
|
}
|
|
43
63
|
|
|
44
64
|
function findBinding(bindings: ScopeBinding[], name: string, node: ts.Node): ScopeBinding | undefined {
|
|
@@ -76,57 +96,6 @@ function findEnclosingScope(node: ts.Node): ts.Node {
|
|
|
76
96
|
return node.getSourceFile();
|
|
77
97
|
}
|
|
78
98
|
|
|
79
|
-
function getCompoundOperator(kind: ts.SyntaxKind): string {
|
|
80
|
-
if (kind === ts.SyntaxKind.PlusEqualsToken) {
|
|
81
|
-
return '+';
|
|
82
|
-
}
|
|
83
|
-
else if (kind === ts.SyntaxKind.MinusEqualsToken) {
|
|
84
|
-
return '-';
|
|
85
|
-
}
|
|
86
|
-
else if (kind === ts.SyntaxKind.AsteriskEqualsToken) {
|
|
87
|
-
return '*';
|
|
88
|
-
}
|
|
89
|
-
else if (kind === ts.SyntaxKind.SlashEqualsToken) {
|
|
90
|
-
return '/';
|
|
91
|
-
}
|
|
92
|
-
else if (kind === ts.SyntaxKind.PercentEqualsToken) {
|
|
93
|
-
return '%';
|
|
94
|
-
}
|
|
95
|
-
else if (kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
|
|
96
|
-
return '**';
|
|
97
|
-
}
|
|
98
|
-
else if (kind === ts.SyntaxKind.AmpersandEqualsToken) {
|
|
99
|
-
return '&';
|
|
100
|
-
}
|
|
101
|
-
else if (kind === ts.SyntaxKind.BarEqualsToken) {
|
|
102
|
-
return '|';
|
|
103
|
-
}
|
|
104
|
-
else if (kind === ts.SyntaxKind.CaretEqualsToken) {
|
|
105
|
-
return '^';
|
|
106
|
-
}
|
|
107
|
-
else if (kind === ts.SyntaxKind.LessThanLessThanEqualsToken) {
|
|
108
|
-
return '<<';
|
|
109
|
-
}
|
|
110
|
-
else if (kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken) {
|
|
111
|
-
return '>>';
|
|
112
|
-
}
|
|
113
|
-
else if (kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
|
|
114
|
-
return '>>>';
|
|
115
|
-
}
|
|
116
|
-
else if (kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
|
|
117
|
-
return '&&';
|
|
118
|
-
}
|
|
119
|
-
else if (kind === ts.SyntaxKind.BarBarEqualsToken) {
|
|
120
|
-
return '||';
|
|
121
|
-
}
|
|
122
|
-
else if (kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
|
|
123
|
-
return '??';
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
return '+';
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
99
|
function isInComputedRange(ranges: Range[], start: number, end: number): boolean {
|
|
131
100
|
for (let i = 0, n = ranges.length; i < n; i++) {
|
|
132
101
|
let r = ranges[i];
|
|
@@ -142,11 +111,7 @@ function isInComputedRange(ranges: Range[], start: number, end: number): boolean
|
|
|
142
111
|
function isInDeclarationInit(node: ts.Node): boolean {
|
|
143
112
|
let parent = node.parent;
|
|
144
113
|
|
|
145
|
-
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return false;
|
|
114
|
+
return ts.isVariableDeclaration(parent) && parent.initializer === node;
|
|
150
115
|
}
|
|
151
116
|
|
|
152
117
|
function isInScope(reference: ts.Node, binding: ScopeBinding): boolean {
|
|
@@ -172,7 +137,7 @@ function isReactiveReassignment(node: ts.Node): boolean {
|
|
|
172
137
|
parent.right === node &&
|
|
173
138
|
ts.isCallExpression(node) &&
|
|
174
139
|
ts.isIdentifier((node as ts.CallExpression).expression) &&
|
|
175
|
-
((node as ts.CallExpression).expression as ts.Identifier).text ===
|
|
140
|
+
((node as ts.CallExpression).expression as ts.Identifier).text === COMPILATION_ENTRYPOINT
|
|
176
141
|
) {
|
|
177
142
|
return true;
|
|
178
143
|
}
|
|
@@ -190,15 +155,7 @@ function isWriteContext(node: ts.Identifier): 'simple' | 'compound' | 'increment
|
|
|
190
155
|
return 'simple';
|
|
191
156
|
}
|
|
192
157
|
|
|
193
|
-
if (
|
|
194
|
-
return 'compound';
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
op === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
199
|
-
op === ts.SyntaxKind.BarBarEqualsToken ||
|
|
200
|
-
op === ts.SyntaxKind.QuestionQuestionEqualsToken
|
|
201
|
-
) {
|
|
158
|
+
if (COMPOUND_OPERATORS.has(op)) {
|
|
202
159
|
return 'compound';
|
|
203
160
|
}
|
|
204
161
|
}
|
|
@@ -218,13 +175,13 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
218
175
|
if (
|
|
219
176
|
ts.isImportDeclaration(node) &&
|
|
220
177
|
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
221
|
-
node.moduleSpecifier.text.includes(
|
|
178
|
+
node.moduleSpecifier.text.includes(PACKAGE)
|
|
222
179
|
) {
|
|
223
180
|
let clause = node.importClause;
|
|
224
181
|
|
|
225
182
|
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
226
183
|
for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
|
|
227
|
-
if (clause.namedBindings.elements[i].name.text ===
|
|
184
|
+
if (clause.namedBindings.elements[i].name.text === COMPILATION_ENTRYPOINT) {
|
|
228
185
|
ctx.hasReactiveImport = true;
|
|
229
186
|
break;
|
|
230
187
|
}
|
|
@@ -236,7 +193,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
236
193
|
ctx.hasReactiveImport &&
|
|
237
194
|
ts.isCallExpression(node) &&
|
|
238
195
|
ts.isIdentifier(node.expression) &&
|
|
239
|
-
node.expression.text ===
|
|
196
|
+
node.expression.text === COMPILATION_ENTRYPOINT &&
|
|
240
197
|
node.arguments.length > 0
|
|
241
198
|
) {
|
|
242
199
|
let arg = node.arguments[0],
|
|
@@ -245,10 +202,11 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
245
202
|
if (classification) {
|
|
246
203
|
let varName: string | null = null;
|
|
247
204
|
|
|
248
|
-
if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
205
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
249
206
|
varName = node.parent.name.text;
|
|
250
207
|
}
|
|
251
208
|
else if (
|
|
209
|
+
node.parent &&
|
|
252
210
|
ts.isBinaryExpression(node.parent) &&
|
|
253
211
|
node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
254
212
|
ts.isIdentifier(node.parent.left)
|
|
@@ -263,47 +221,40 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
263
221
|
ctx.bindings.set(varName, classification);
|
|
264
222
|
}
|
|
265
223
|
|
|
266
|
-
if (classification ===
|
|
267
|
-
ctx.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
});
|
|
224
|
+
if (classification === COMPILATION_TYPE_COMPUTED) {
|
|
225
|
+
let argStart = arg.getStart(ctx.sourceFile);
|
|
226
|
+
|
|
227
|
+
ctx.computedArgRanges.push({ end: arg.end, start: argStart });
|
|
271
228
|
|
|
272
229
|
let argCtx: ArgContext = {
|
|
273
|
-
argStart
|
|
230
|
+
argStart,
|
|
274
231
|
innerReplacements: [],
|
|
275
|
-
|
|
232
|
+
ns: ctx.ns,
|
|
276
233
|
scopedBindings: ctx.scopedBindings,
|
|
277
234
|
sourceFile: ctx.sourceFile
|
|
278
235
|
};
|
|
279
236
|
|
|
280
237
|
visitArg(argCtx, arg);
|
|
281
238
|
|
|
282
|
-
let argText =
|
|
239
|
+
let argText = c.replace(arg.getText(ctx.sourceFile), argCtx.innerReplacements);
|
|
283
240
|
|
|
284
241
|
ctx.replacements.push({
|
|
285
242
|
end: node.end,
|
|
286
|
-
newText:
|
|
243
|
+
newText: `${ctx.ns}.computed(${argText})`,
|
|
287
244
|
start: node.pos
|
|
288
245
|
});
|
|
289
|
-
|
|
290
|
-
ctx.neededImports.add('computed');
|
|
291
246
|
}
|
|
292
247
|
else {
|
|
293
|
-
let argText = arg.getText(ctx.sourceFile);
|
|
294
|
-
|
|
295
248
|
ctx.replacements.push({
|
|
296
249
|
end: node.end,
|
|
297
|
-
newText:
|
|
250
|
+
newText: `${ctx.ns}.signal(${arg.getText(ctx.sourceFile)})`,
|
|
298
251
|
start: node.pos
|
|
299
252
|
});
|
|
300
|
-
|
|
301
|
-
ctx.neededImports.add('signal');
|
|
302
253
|
}
|
|
303
254
|
}
|
|
304
255
|
}
|
|
305
256
|
|
|
306
|
-
if (ts.isIdentifier(node) && !isInDeclarationInit(node.parent)) {
|
|
257
|
+
if (ts.isIdentifier(node) && node.parent && !isInDeclarationInit(node.parent)) {
|
|
307
258
|
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
|
308
259
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
309
260
|
return;
|
|
@@ -319,7 +270,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
319
270
|
let binding = findBinding(ctx.scopedBindings, node.text, node),
|
|
320
271
|
name = node.text;
|
|
321
272
|
|
|
322
|
-
if (binding) {
|
|
273
|
+
if (binding && node.parent) {
|
|
323
274
|
if (
|
|
324
275
|
!isReactiveReassignment(node.parent) &&
|
|
325
276
|
!(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)
|
|
@@ -327,55 +278,49 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
327
278
|
let writeCtx = isWriteContext(node);
|
|
328
279
|
|
|
329
280
|
if (writeCtx) {
|
|
330
|
-
if (binding.type !==
|
|
331
|
-
ctx.neededImports.add('set');
|
|
332
|
-
|
|
281
|
+
if (binding.type !== COMPILATION_TYPE_COMPUTED) {
|
|
333
282
|
let parent = node.parent;
|
|
334
283
|
|
|
335
284
|
if (writeCtx === 'simple' && ts.isBinaryExpression(parent)) {
|
|
336
|
-
let valueText = parent.right.getText(ctx.sourceFile);
|
|
337
|
-
|
|
338
285
|
ctx.replacements.push({
|
|
339
286
|
end: parent.end,
|
|
340
|
-
newText:
|
|
287
|
+
newText: `${ctx.ns}.write(${name}, ${parent.right.getText(ctx.sourceFile)})`,
|
|
341
288
|
start: parent.pos
|
|
342
289
|
});
|
|
343
290
|
}
|
|
344
291
|
else if (writeCtx === 'compound' && ts.isBinaryExpression(parent)) {
|
|
345
|
-
let op =
|
|
346
|
-
valueText = parent.right.getText(ctx.sourceFile);
|
|
292
|
+
let op = COMPOUND_OPERATORS.get(parent.operatorToken.kind) ?? '+';
|
|
347
293
|
|
|
348
294
|
ctx.replacements.push({
|
|
349
295
|
end: parent.end,
|
|
350
|
-
newText:
|
|
296
|
+
newText: `${ctx.ns}.write(${name}, ${name}.value ${op} ${parent.right.getText(ctx.sourceFile)})`,
|
|
351
297
|
start: parent.pos
|
|
352
298
|
});
|
|
353
299
|
}
|
|
354
300
|
else if (writeCtx === 'increment') {
|
|
355
|
-
let
|
|
356
|
-
|
|
357
|
-
delta = op === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1';
|
|
301
|
+
let delta = (parent as ts.PrefixUnaryExpression | ts.PostfixUnaryExpression).operator === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1',
|
|
302
|
+
isPrefix = ts.isPrefixUnaryExpression(parent);
|
|
358
303
|
|
|
359
304
|
if (ts.isExpressionStatement(parent.parent)) {
|
|
360
305
|
ctx.replacements.push({
|
|
361
306
|
end: parent.end,
|
|
362
|
-
newText:
|
|
307
|
+
newText: `${ctx.ns}.write(${name}, ${name}.value ${delta})`,
|
|
363
308
|
start: parent.pos
|
|
364
309
|
});
|
|
365
310
|
}
|
|
366
311
|
else if (isPrefix) {
|
|
367
312
|
ctx.replacements.push({
|
|
368
313
|
end: parent.end,
|
|
369
|
-
newText: `(
|
|
314
|
+
newText: `(${ctx.ns}.write(${name}, ${name}.value ${delta}), ${name}.value)`,
|
|
370
315
|
start: parent.pos
|
|
371
316
|
});
|
|
372
317
|
}
|
|
373
318
|
else {
|
|
374
|
-
let tmp =
|
|
319
|
+
let tmp = `_t${ctx.tmpCounter++}`;
|
|
375
320
|
|
|
376
321
|
ctx.replacements.push({
|
|
377
322
|
end: parent.end,
|
|
378
|
-
newText: `((${tmp}) => (
|
|
323
|
+
newText: `((${tmp}) => (${ctx.ns}.write(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
|
|
379
324
|
start: parent.pos
|
|
380
325
|
});
|
|
381
326
|
}
|
|
@@ -383,11 +328,9 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
383
328
|
}
|
|
384
329
|
}
|
|
385
330
|
else {
|
|
386
|
-
ctx.neededImports.add('read');
|
|
387
|
-
|
|
388
331
|
ctx.replacements.push({
|
|
389
332
|
end: node.end,
|
|
390
|
-
newText:
|
|
333
|
+
newText: `${ctx.ns}.read(${name})`,
|
|
391
334
|
start: node.pos
|
|
392
335
|
});
|
|
393
336
|
}
|
|
@@ -399,25 +342,19 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
399
342
|
}
|
|
400
343
|
|
|
401
344
|
function visitArg(ctx: ArgContext, node: ts.Node): void {
|
|
402
|
-
if (ts.isIdentifier(node)) {
|
|
403
|
-
if (
|
|
404
|
-
ts.
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (ts.isCallExpression(node.parent) && node.parent.expression === node) {
|
|
345
|
+
if (ts.isIdentifier(node) && node.parent) {
|
|
346
|
+
if (
|
|
347
|
+
(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) ||
|
|
348
|
+
(ts.isCallExpression(node.parent) && node.parent.expression === node)
|
|
349
|
+
) {
|
|
409
350
|
ts.forEachChild(node, n => visitArg(ctx, n));
|
|
410
351
|
return;
|
|
411
352
|
}
|
|
412
353
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if (binding) {
|
|
416
|
-
ctx.neededImports.add('read');
|
|
417
|
-
|
|
354
|
+
if (findBinding(ctx.scopedBindings, node.text, node)) {
|
|
418
355
|
ctx.innerReplacements.push({
|
|
419
356
|
end: node.end - ctx.argStart,
|
|
420
|
-
newText:
|
|
357
|
+
newText: `${ctx.ns}.read(${node.text})`,
|
|
421
358
|
start: node.getStart(ctx.sourceFile) - ctx.argStart
|
|
422
359
|
});
|
|
423
360
|
}
|
|
@@ -427,19 +364,17 @@ function visitArg(ctx: ArgContext, node: ts.Node): void {
|
|
|
427
364
|
}
|
|
428
365
|
|
|
429
366
|
|
|
430
|
-
|
|
431
|
-
sourceFile: ts.SourceFile,
|
|
432
|
-
bindings: Bindings
|
|
433
|
-
): string => {
|
|
367
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
|
|
434
368
|
let code = sourceFile.getFullText(),
|
|
435
369
|
ctx: TransformContext = {
|
|
436
370
|
bindings,
|
|
437
371
|
computedArgRanges: [],
|
|
438
372
|
hasReactiveImport: false,
|
|
439
|
-
|
|
373
|
+
ns,
|
|
440
374
|
replacements: [],
|
|
441
375
|
scopedBindings: [],
|
|
442
|
-
sourceFile
|
|
376
|
+
sourceFile,
|
|
377
|
+
tmpCounter: 0
|
|
443
378
|
};
|
|
444
379
|
|
|
445
380
|
visit(ctx, sourceFile);
|
|
@@ -448,14 +383,5 @@ const transformReactivePrimitives = (
|
|
|
448
383
|
return code;
|
|
449
384
|
}
|
|
450
385
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (ctx.neededImports.size > 0) {
|
|
454
|
-
result = addMissingImports(result, ctx.neededImports);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
return result;
|
|
386
|
+
return c.replace(code, ctx.replacements);
|
|
458
387
|
};
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
export { transformReactivePrimitives };
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
|
|
2
|
-
import { ReactiveArray, ReactiveObject } from './reactive';
|
|
3
2
|
import { ts } from '@esportsplus/typescript';
|
|
4
3
|
|
|
5
4
|
|
|
@@ -36,6 +35,10 @@ interface Link {
|
|
|
36
35
|
version: number;
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
// If we expose internals optimizing compiler may break api.
|
|
39
|
+
// Instead we will use this as a shim.
|
|
40
|
+
type Reactive<T> = T;
|
|
41
|
+
|
|
39
42
|
type Signal<T> = {
|
|
40
43
|
subs: Link | null;
|
|
41
44
|
subsTail: Link | null;
|
|
@@ -55,8 +58,7 @@ export type {
|
|
|
55
58
|
Bindings,
|
|
56
59
|
Computed,
|
|
57
60
|
Link,
|
|
58
|
-
|
|
59
|
-
ReactiveObject,
|
|
61
|
+
Reactive,
|
|
60
62
|
Signal,
|
|
61
63
|
TransformResult
|
|
62
64
|
};
|