@esportsplus/reactivity 0.24.5 → 0.25.0
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/reactive/index.d.ts +9 -4
- package/build/transformer/index.d.ts +6 -4
- package/build/transformer/index.js +39 -106
- package/build/transformer/plugins/vite.js +4 -7
- package/build/transformer/transforms/array.d.ts +2 -2
- package/build/transformer/transforms/array.js +22 -23
- package/build/transformer/transforms/object.d.ts +3 -9
- package/build/transformer/transforms/object.js +99 -89
- package/build/transformer/transforms/primitives.d.ts +3 -3
- package/build/transformer/transforms/primitives.js +193 -142
- package/build/transformer/transforms/utilities.d.ts +8 -0
- package/build/transformer/transforms/utilities.js +27 -0
- package/build/types.d.ts +7 -6
- package/package.json +1 -1
- package/src/reactive/index.ts +24 -6
- package/src/transformer/index.ts +45 -187
- package/src/transformer/plugins/vite.ts +5 -13
- package/src/transformer/transforms/array.ts +31 -40
- package/src/transformer/transforms/object.ts +137 -294
- package/src/transformer/transforms/primitives.ts +245 -242
- package/src/transformer/transforms/utilities.ts +45 -0
- package/src/types.ts +9 -8
- package/test/vite.config.ts +1 -1
- package/build/transformer/factory.d.ts +0 -13
- package/build/transformer/factory.js +0 -36
- package/src/transformer/factory.ts +0 -141
package/src/transformer/index.ts
CHANGED
|
@@ -1,209 +1,67 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Bindings, Namespaces } from '~/types';
|
|
3
|
-
import { createArrayTransformer } from './transforms/array';
|
|
4
|
-
import { createObjectTransformer, type GeneratedClass } from './transforms/object';
|
|
5
|
-
import { createPrimitivesTransformer } from './transforms/primitives';
|
|
1
|
+
import type { Bindings, TransformResult } from '~/types';
|
|
6
2
|
import { mightNeedTransform } from './detector';
|
|
3
|
+
import { transformReactiveArrays } from './transforms/array';
|
|
4
|
+
import { transformReactiveObjects } from './transforms/object';
|
|
5
|
+
import { transformReactivePrimitives } from './transforms/primitives';
|
|
7
6
|
import { ts } from '@esportsplus/typescript';
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ns: Namespaces
|
|
13
|
-
): (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile {
|
|
14
|
-
return (context: ts.TransformationContext) => {
|
|
15
|
-
return (sourceFile: ts.SourceFile): ts.SourceFile => {
|
|
16
|
-
if (neededImports.size === 0) {
|
|
17
|
-
return sourceFile;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let factory = context.factory,
|
|
21
|
-
needsArray = false,
|
|
22
|
-
needsConstants = false,
|
|
23
|
-
needsReactivity = false,
|
|
24
|
-
newStatements: ts.Statement[] = [];
|
|
25
|
-
|
|
26
|
-
for (let imp of neededImports) {
|
|
27
|
-
if (imp === 'ReactiveArray') {
|
|
28
|
-
needsArray = true;
|
|
29
|
-
}
|
|
30
|
-
else if (imp === 'REACTIVE_OBJECT') {
|
|
31
|
-
needsConstants = true;
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
needsReactivity = true;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Add namespace imports
|
|
39
|
-
if (needsReactivity) {
|
|
40
|
-
newStatements.push(
|
|
41
|
-
factory.createImportDeclaration(
|
|
42
|
-
undefined,
|
|
43
|
-
factory.createImportClause(
|
|
44
|
-
false,
|
|
45
|
-
undefined,
|
|
46
|
-
factory.createNamespaceImport(factory.createIdentifier(ns.reactivity))
|
|
47
|
-
),
|
|
48
|
-
factory.createStringLiteral('@esportsplus/reactivity')
|
|
49
|
-
)
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (needsArray) {
|
|
54
|
-
newStatements.push(
|
|
55
|
-
factory.createImportDeclaration(
|
|
56
|
-
undefined,
|
|
57
|
-
factory.createImportClause(
|
|
58
|
-
false,
|
|
59
|
-
undefined,
|
|
60
|
-
factory.createNamespaceImport(factory.createIdentifier(ns.array))
|
|
61
|
-
),
|
|
62
|
-
factory.createStringLiteral('@esportsplus/reactivity/reactive/array')
|
|
63
|
-
)
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (needsConstants) {
|
|
68
|
-
newStatements.push(
|
|
69
|
-
factory.createImportDeclaration(
|
|
70
|
-
undefined,
|
|
71
|
-
factory.createImportClause(
|
|
72
|
-
false,
|
|
73
|
-
undefined,
|
|
74
|
-
factory.createNamespaceImport(factory.createIdentifier(ns.constants))
|
|
75
|
-
),
|
|
76
|
-
factory.createStringLiteral('@esportsplus/reactivity/constants')
|
|
77
|
-
)
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Filter out original @esportsplus/reactivity imports (they lose symbol bindings)
|
|
82
|
-
let filteredStatements: ts.Statement[] = [],
|
|
83
|
-
insertIndex = 0,
|
|
84
|
-
statements = sourceFile.statements;
|
|
85
|
-
|
|
86
|
-
for (let i = 0, n = statements.length; i < n; i++) {
|
|
87
|
-
let stmt = statements[i];
|
|
88
|
-
|
|
89
|
-
if (ts.isImportDeclaration(stmt)) {
|
|
90
|
-
insertIndex = filteredStatements.length + 1;
|
|
91
|
-
|
|
92
|
-
// Skip imports from @esportsplus/reactivity packages
|
|
93
|
-
if (ts.isStringLiteral(stmt.moduleSpecifier)) {
|
|
94
|
-
let module = stmt.moduleSpecifier.text;
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
module === '@esportsplus/reactivity' ||
|
|
98
|
-
module === '@esportsplus/reactivity/reactive/array' ||
|
|
99
|
-
module === '@esportsplus/reactivity/constants'
|
|
100
|
-
) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
filteredStatements.push(stmt);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
let updatedStatements = [
|
|
110
|
-
...filteredStatements.slice(0, insertIndex),
|
|
111
|
-
...newStatements,
|
|
112
|
-
...filteredStatements.slice(insertIndex)
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
return factory.updateSourceFile(sourceFile, updatedStatements);
|
|
116
|
-
};
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function insertClassesTransformer(
|
|
121
|
-
generatedClasses: GeneratedClass[]
|
|
122
|
-
): (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile {
|
|
123
|
-
return (context: ts.TransformationContext) => {
|
|
9
|
+
const createTransformer = (): ts.TransformerFactory<ts.SourceFile> => {
|
|
10
|
+
return () => {
|
|
124
11
|
return (sourceFile: ts.SourceFile): ts.SourceFile => {
|
|
125
|
-
|
|
126
|
-
return sourceFile;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
let factory = context.factory;
|
|
130
|
-
|
|
131
|
-
// Find position after imports
|
|
132
|
-
let insertIndex = 0,
|
|
133
|
-
statements = sourceFile.statements;
|
|
12
|
+
let result = transform(sourceFile);
|
|
134
13
|
|
|
135
|
-
|
|
136
|
-
if (ts.isImportDeclaration(statements[i])) {
|
|
137
|
-
insertIndex = i + 1;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
let classDecls = generatedClasses.map(gc => gc.classDecl),
|
|
145
|
-
updatedStatements = [
|
|
146
|
-
...statements.slice(0, insertIndex),
|
|
147
|
-
...classDecls,
|
|
148
|
-
...statements.slice(insertIndex)
|
|
149
|
-
];
|
|
150
|
-
|
|
151
|
-
return factory.updateSourceFile(sourceFile, updatedStatements);
|
|
14
|
+
return result.transformed ? result.sourceFile : sourceFile;
|
|
152
15
|
};
|
|
153
16
|
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const createTransformer = (): ts.TransformerFactory<ts.SourceFile> => {
|
|
158
|
-
return (context: ts.TransformationContext) => {
|
|
159
|
-
return (sourceFile: ts.SourceFile): ts.SourceFile => {
|
|
160
|
-
let code = sourceFile.getFullText();
|
|
161
|
-
|
|
162
|
-
if (!mightNeedTransform(code)) {
|
|
163
|
-
return sourceFile;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
let bindings: Bindings = new Map(),
|
|
167
|
-
generatedClasses: GeneratedClass[] = [],
|
|
168
|
-
neededImports = new Set<string>(),
|
|
169
|
-
ns: Namespaces = {
|
|
170
|
-
array: uid('ra'),
|
|
171
|
-
constants: uid('rc'),
|
|
172
|
-
reactivity: uid('r')
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
// Run object transformer first (generates classes, tracks array bindings)
|
|
176
|
-
let objectTransformer = createObjectTransformer(bindings, neededImports, generatedClasses, ns)(context);
|
|
17
|
+
};
|
|
177
18
|
|
|
178
|
-
|
|
19
|
+
const transform = (sourceFile: ts.SourceFile): TransformResult => {
|
|
20
|
+
let bindings: Bindings = new Map(),
|
|
21
|
+
code = sourceFile.getFullText(),
|
|
22
|
+
current = sourceFile,
|
|
23
|
+
original = code,
|
|
24
|
+
result: string;
|
|
179
25
|
|
|
180
|
-
|
|
181
|
-
|
|
26
|
+
if (!mightNeedTransform(code)) {
|
|
27
|
+
return { code, sourceFile, transformed: false };
|
|
28
|
+
}
|
|
182
29
|
|
|
183
|
-
|
|
30
|
+
// Run all transforms, only re-parse between transforms if code changed
|
|
31
|
+
result = transformReactiveObjects(current, bindings);
|
|
184
32
|
|
|
185
|
-
|
|
186
|
-
|
|
33
|
+
if (result !== code) {
|
|
34
|
+
current = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
35
|
+
code = result;
|
|
36
|
+
}
|
|
187
37
|
|
|
188
|
-
|
|
38
|
+
result = transformReactiveArrays(current, bindings);
|
|
189
39
|
|
|
190
|
-
|
|
191
|
-
|
|
40
|
+
if (result !== code) {
|
|
41
|
+
current = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
42
|
+
code = result;
|
|
43
|
+
}
|
|
192
44
|
|
|
193
|
-
|
|
45
|
+
result = transformReactivePrimitives(current, bindings);
|
|
194
46
|
|
|
195
|
-
|
|
196
|
-
|
|
47
|
+
if (result !== code) {
|
|
48
|
+
current = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
49
|
+
code = result;
|
|
50
|
+
}
|
|
197
51
|
|
|
198
|
-
|
|
52
|
+
if (code === original) {
|
|
53
|
+
return { code, sourceFile, transformed: false };
|
|
54
|
+
}
|
|
199
55
|
|
|
200
|
-
|
|
201
|
-
|
|
56
|
+
return {
|
|
57
|
+
code,
|
|
58
|
+
sourceFile: current,
|
|
59
|
+
transformed: true
|
|
202
60
|
};
|
|
203
61
|
};
|
|
204
62
|
|
|
205
63
|
|
|
206
|
-
export { createTransformer, mightNeedTransform };
|
|
207
|
-
export {
|
|
208
|
-
export {
|
|
209
|
-
export {
|
|
64
|
+
export { createTransformer, mightNeedTransform, transform };
|
|
65
|
+
export { transformReactiveArrays } from './transforms/array';
|
|
66
|
+
export { transformReactiveObjects } from './transforms/object';
|
|
67
|
+
export { transformReactivePrimitives } from './transforms/primitives';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TRANSFORM_PATTERN } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import {
|
|
2
|
+
import { mightNeedTransform, transform } from '~/transformer';
|
|
3
3
|
import type { Plugin } from 'vite';
|
|
4
4
|
import { ts } from '@esportsplus/typescript';
|
|
5
5
|
|
|
@@ -19,22 +19,14 @@ export default (): Plugin => {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
|
-
let
|
|
23
|
-
|
|
24
|
-
transformer = createTransformer(),
|
|
25
|
-
result = ts.transform(sourceFile, [transformer]),
|
|
26
|
-
transformed = result.transformed[0];
|
|
22
|
+
let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true),
|
|
23
|
+
result = transform(sourceFile);
|
|
27
24
|
|
|
28
|
-
if (transformed
|
|
29
|
-
result.dispose();
|
|
25
|
+
if (!result.transformed) {
|
|
30
26
|
return null;
|
|
31
27
|
}
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
result.dispose();
|
|
36
|
-
|
|
37
|
-
return { code: output, map: null };
|
|
29
|
+
return { code: result.code, map: null };
|
|
38
30
|
}
|
|
39
31
|
catch (error) {
|
|
40
32
|
console.error(`@esportsplus/reactivity: Error transforming ${id}:`, error);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Bindings } from '~/types';
|
|
2
|
-
import {
|
|
2
|
+
import { applyReplacements, Replacement } from './utilities';
|
|
3
3
|
import { ts } from '@esportsplus/typescript';
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
interface TransformContext {
|
|
7
7
|
bindings: Bindings;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
replacements: Replacement[];
|
|
9
|
+
sourceFile: ts.SourceFile;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
|
|
@@ -42,10 +42,6 @@ function getPropertyPath(node: ts.PropertyAccessExpression): string | null {
|
|
|
42
42
|
function isAssignmentTarget(node: ts.Node): boolean {
|
|
43
43
|
let parent = node.parent;
|
|
44
44
|
|
|
45
|
-
if (!parent) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
45
|
if (
|
|
50
46
|
(ts.isBinaryExpression(parent) && parent.left === node) ||
|
|
51
47
|
ts.isPostfixUnaryExpression(parent) ||
|
|
@@ -57,13 +53,7 @@ function isAssignmentTarget(node: ts.Node): boolean {
|
|
|
57
53
|
return false;
|
|
58
54
|
}
|
|
59
55
|
|
|
60
|
-
function visit(ctx: TransformContext, node: ts.Node):
|
|
61
|
-
// Skip import declarations - don't visit their children
|
|
62
|
-
if (ts.isImportDeclaration(node)) {
|
|
63
|
-
return node;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Track array bindings from variable declarations
|
|
56
|
+
function visit(ctx: TransformContext, node: ts.Node): void {
|
|
67
57
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
68
58
|
if (ts.isIdentifier(node.initializer) && ctx.bindings.get(node.initializer.text) === 'array') {
|
|
69
59
|
ctx.bindings.set(node.name.text, 'array');
|
|
@@ -78,7 +68,6 @@ function visit(ctx: TransformContext, node: ts.Node): ts.Node {
|
|
|
78
68
|
}
|
|
79
69
|
}
|
|
80
70
|
|
|
81
|
-
// Track array bindings from function parameters with ReactiveArray type
|
|
82
71
|
if ((ts.isFunctionDeclaration(node) || ts.isArrowFunction(node)) && node.parameters) {
|
|
83
72
|
for (let i = 0, n = node.parameters.length; i < n; i++) {
|
|
84
73
|
let param = node.parameters[i];
|
|
@@ -94,7 +83,6 @@ function visit(ctx: TransformContext, node: ts.Node): ts.Node {
|
|
|
94
83
|
}
|
|
95
84
|
}
|
|
96
85
|
|
|
97
|
-
// Transform array.length → array.$length()
|
|
98
86
|
if (
|
|
99
87
|
ts.isPropertyAccessExpression(node) &&
|
|
100
88
|
node.name.text === 'length' &&
|
|
@@ -103,14 +91,16 @@ function visit(ctx: TransformContext, node: ts.Node): ts.Node {
|
|
|
103
91
|
let name = getExpressionName(node.expression);
|
|
104
92
|
|
|
105
93
|
if (name && ctx.bindings.get(name) === 'array') {
|
|
106
|
-
|
|
107
|
-
let transformedExpr = ts.visitEachChild(node.expression, n => visit(ctx, n), ctx.context) as ts.Expression;
|
|
94
|
+
let objText = node.expression.getText(ctx.sourceFile);
|
|
108
95
|
|
|
109
|
-
|
|
96
|
+
ctx.replacements.push({
|
|
97
|
+
end: node.end,
|
|
98
|
+
newText: `${objText}.$length()`,
|
|
99
|
+
start: node.pos
|
|
100
|
+
});
|
|
110
101
|
}
|
|
111
102
|
}
|
|
112
103
|
|
|
113
|
-
// Transform array[index] = value → array.$set(index, value)
|
|
114
104
|
if (
|
|
115
105
|
ts.isBinaryExpression(node) &&
|
|
116
106
|
node.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
@@ -120,33 +110,34 @@ function visit(ctx: TransformContext, node: ts.Node): ts.Node {
|
|
|
120
110
|
objName = getExpressionName(elemAccess.expression);
|
|
121
111
|
|
|
122
112
|
if (objName && ctx.bindings.get(objName) === 'array') {
|
|
123
|
-
let
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
113
|
+
let indexText = elemAccess.argumentExpression.getText(ctx.sourceFile),
|
|
114
|
+
objText = elemAccess.expression.getText(ctx.sourceFile),
|
|
115
|
+
valueText = node.right.getText(ctx.sourceFile);
|
|
116
|
+
|
|
117
|
+
ctx.replacements.push({
|
|
118
|
+
end: node.end,
|
|
119
|
+
newText: `${objText}.$set(${indexText}, ${valueText})`,
|
|
120
|
+
start: node.pos
|
|
121
|
+
});
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
124
|
|
|
131
|
-
|
|
125
|
+
ts.forEachChild(node, n => visit(ctx, n));
|
|
132
126
|
}
|
|
133
127
|
|
|
134
128
|
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
bindings,
|
|
142
|
-
context,
|
|
143
|
-
factory: context.factory
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
return ts.visitNode(sourceFile, n => visit(ctx, n)) as ts.SourceFile;
|
|
129
|
+
const transformReactiveArrays = (sourceFile: ts.SourceFile, bindings: Bindings): string => {
|
|
130
|
+
let code = sourceFile.getFullText(),
|
|
131
|
+
ctx: TransformContext = {
|
|
132
|
+
bindings,
|
|
133
|
+
replacements: [],
|
|
134
|
+
sourceFile
|
|
147
135
|
};
|
|
148
|
-
|
|
136
|
+
|
|
137
|
+
visit(ctx, sourceFile);
|
|
138
|
+
|
|
139
|
+
return applyReplacements(code, ctx.replacements);
|
|
149
140
|
};
|
|
150
141
|
|
|
151
142
|
|
|
152
|
-
export {
|
|
143
|
+
export { transformReactiveArrays };
|