@esportsplus/reactivity 0.24.1 → 0.24.3
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/transformer/factory.d.ts +13 -0
- package/build/transformer/factory.js +36 -0
- package/build/transformer/index.d.ts +4 -6
- package/build/transformer/index.js +99 -39
- package/build/transformer/plugins/vite.js +7 -4
- package/build/transformer/transforms/array.d.ts +2 -2
- package/build/transformer/transforms/array.js +20 -22
- package/build/transformer/transforms/object.d.ts +9 -3
- package/build/transformer/transforms/object.js +88 -99
- package/build/transformer/transforms/primitives.d.ts +3 -3
- package/build/transformer/transforms/primitives.js +131 -184
- package/build/types.d.ts +6 -7
- package/package.json +1 -1
- package/src/transformer/factory.ts +141 -0
- package/src/transformer/index.ts +172 -45
- package/src/transformer/plugins/vite.ts +13 -5
- package/src/transformer/transforms/array.ts +35 -31
- package/src/transformer/transforms/object.ts +292 -137
- package/src/transformer/transforms/primitives.ts +230 -236
- package/src/types.ts +8 -9
- 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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
declare function createReadCall(factory: ts.NodeFactory, ns: string, expr: ts.Expression): ts.CallExpression;
|
|
3
|
+
declare function createSetCall(factory: ts.NodeFactory, ns: string, target: ts.Expression, value: ts.Expression): ts.CallExpression;
|
|
4
|
+
declare function createSignalCall(factory: ts.NodeFactory, ns: string, initialValue: ts.Expression): ts.CallExpression;
|
|
5
|
+
declare function createComputedCall(factory: ts.NodeFactory, ns: string, fn: ts.Expression): ts.CallExpression;
|
|
6
|
+
declare function createArrayLengthCall(factory: ts.NodeFactory, arrayExpr: ts.Expression): ts.CallExpression;
|
|
7
|
+
declare function createArraySetCall(factory: ts.NodeFactory, arrayExpr: ts.Expression, index: ts.Expression, value: ts.Expression): ts.CallExpression;
|
|
8
|
+
declare function createReactiveArrayNew(factory: ts.NodeFactory, ns: string, elements: ts.Expression[]): ts.NewExpression;
|
|
9
|
+
declare function createDisposeCall(factory: ts.NodeFactory, ns: string, expr: ts.Expression): ts.CallExpression;
|
|
10
|
+
declare function createBinaryExpr(factory: ts.NodeFactory, left: ts.Expression, op: ts.BinaryOperator, right: ts.Expression): ts.BinaryExpression;
|
|
11
|
+
declare function createCommaExpr(factory: ts.NodeFactory, first: ts.Expression, second: ts.Expression): ts.ParenthesizedExpression;
|
|
12
|
+
declare function createPostfixIncrementExpr(factory: ts.NodeFactory, ns: string, tmpName: string, signalName: string, op: ts.SyntaxKind.PlusToken | ts.SyntaxKind.MinusToken): ts.CallExpression;
|
|
13
|
+
export { createArrayLengthCall, createArraySetCall, createBinaryExpr, createCommaExpr, createComputedCall, createDisposeCall, createPostfixIncrementExpr, createReactiveArrayNew, createReadCall, createSetCall, createSignalCall };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
function createReadCall(factory, ns, expr) {
|
|
3
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'read'), undefined, [expr]);
|
|
4
|
+
}
|
|
5
|
+
function createSetCall(factory, ns, target, value) {
|
|
6
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'set'), undefined, [target, value]);
|
|
7
|
+
}
|
|
8
|
+
function createSignalCall(factory, ns, initialValue) {
|
|
9
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'signal'), undefined, [initialValue]);
|
|
10
|
+
}
|
|
11
|
+
function createComputedCall(factory, ns, fn) {
|
|
12
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'computed'), undefined, [fn]);
|
|
13
|
+
}
|
|
14
|
+
function createArrayLengthCall(factory, arrayExpr) {
|
|
15
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(arrayExpr, '$length'), undefined, []);
|
|
16
|
+
}
|
|
17
|
+
function createArraySetCall(factory, arrayExpr, index, value) {
|
|
18
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(arrayExpr, '$set'), undefined, [index, value]);
|
|
19
|
+
}
|
|
20
|
+
function createReactiveArrayNew(factory, ns, elements) {
|
|
21
|
+
return factory.createNewExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'ReactiveArray'), undefined, elements);
|
|
22
|
+
}
|
|
23
|
+
function createDisposeCall(factory, ns, expr) {
|
|
24
|
+
return factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ns), 'dispose'), undefined, [expr]);
|
|
25
|
+
}
|
|
26
|
+
function createBinaryExpr(factory, left, op, right) {
|
|
27
|
+
return factory.createBinaryExpression(left, op, right);
|
|
28
|
+
}
|
|
29
|
+
function createCommaExpr(factory, first, second) {
|
|
30
|
+
return factory.createParenthesizedExpression(factory.createBinaryExpression(first, ts.SyntaxKind.CommaToken, second));
|
|
31
|
+
}
|
|
32
|
+
function createPostfixIncrementExpr(factory, ns, tmpName, signalName, op) {
|
|
33
|
+
let tmpIdent = factory.createIdentifier(tmpName), signalIdent = factory.createIdentifier(signalName);
|
|
34
|
+
return factory.createCallExpression(factory.createParenthesizedExpression(factory.createArrowFunction(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, tmpIdent)], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), createCommaExpr(factory, createSetCall(factory, ns, signalIdent, factory.createBinaryExpression(tmpIdent, op, factory.createNumericLiteral(1))), tmpIdent))), undefined, [factory.createPropertyAccessExpression(signalIdent, 'value')]);
|
|
35
|
+
}
|
|
36
|
+
export { createArrayLengthCall, createArraySetCall, createBinaryExpr, createCommaExpr, createComputedCall, createDisposeCall, createPostfixIncrementExpr, createReactiveArrayNew, createReadCall, createSetCall, createSignalCall };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import type { TransformResult } from '../types.js';
|
|
2
1
|
import { mightNeedTransform } from './detector.js';
|
|
3
2
|
import { ts } from '@esportsplus/typescript';
|
|
4
3
|
declare const createTransformer: () => ts.TransformerFactory<ts.SourceFile>;
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export { transformReactivePrimitives } from './transforms/primitives.js';
|
|
4
|
+
export { createTransformer, mightNeedTransform };
|
|
5
|
+
export { createArrayTransformer } from './transforms/array.js';
|
|
6
|
+
export { createObjectTransformer } from './transforms/object.js';
|
|
7
|
+
export { createPrimitivesTransformer } from './transforms/primitives.js';
|
|
@@ -1,46 +1,106 @@
|
|
|
1
|
+
import { uid } from '@esportsplus/typescript/transformer';
|
|
2
|
+
import { createArrayTransformer } from './transforms/array.js';
|
|
3
|
+
import { createObjectTransformer } from './transforms/object.js';
|
|
4
|
+
import { createPrimitivesTransformer } from './transforms/primitives.js';
|
|
1
5
|
import { mightNeedTransform } from './detector.js';
|
|
2
|
-
import { transformReactiveArrays } from './transforms/array.js';
|
|
3
|
-
import { transformReactiveObjects } from './transforms/object.js';
|
|
4
|
-
import { transformReactivePrimitives } from './transforms/primitives.js';
|
|
5
6
|
import { ts } from '@esportsplus/typescript';
|
|
6
|
-
|
|
7
|
-
return () => {
|
|
7
|
+
function addImportsTransformer(neededImports, ns) {
|
|
8
|
+
return (context) => {
|
|
8
9
|
return (sourceFile) => {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
if (neededImports.size === 0) {
|
|
11
|
+
return sourceFile;
|
|
12
|
+
}
|
|
13
|
+
let factory = context.factory, needsArray = false, needsConstants = false, needsReactivity = false, newStatements = [];
|
|
14
|
+
for (let imp of neededImports) {
|
|
15
|
+
if (imp === 'ReactiveArray') {
|
|
16
|
+
needsArray = true;
|
|
17
|
+
}
|
|
18
|
+
else if (imp === 'REACTIVE_OBJECT') {
|
|
19
|
+
needsConstants = true;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
needsReactivity = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (needsReactivity) {
|
|
26
|
+
newStatements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(ns.reactivity))), factory.createStringLiteral('@esportsplus/reactivity')));
|
|
27
|
+
}
|
|
28
|
+
if (needsArray) {
|
|
29
|
+
newStatements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(ns.array))), factory.createStringLiteral('@esportsplus/reactivity/reactive/array')));
|
|
30
|
+
}
|
|
31
|
+
if (needsConstants) {
|
|
32
|
+
newStatements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(ns.constants))), factory.createStringLiteral('@esportsplus/reactivity/constants')));
|
|
33
|
+
}
|
|
34
|
+
let insertIndex = 0, statements = sourceFile.statements;
|
|
35
|
+
for (let i = 0, n = statements.length; i < n; i++) {
|
|
36
|
+
if (ts.isImportDeclaration(statements[i])) {
|
|
37
|
+
insertIndex = i + 1;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
let updatedStatements = [
|
|
44
|
+
...statements.slice(0, insertIndex),
|
|
45
|
+
...newStatements,
|
|
46
|
+
...statements.slice(insertIndex)
|
|
47
|
+
];
|
|
48
|
+
return factory.updateSourceFile(sourceFile, updatedStatements);
|
|
11
49
|
};
|
|
12
50
|
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
}
|
|
52
|
+
function insertClassesTransformer(generatedClasses) {
|
|
53
|
+
return (context) => {
|
|
54
|
+
return (sourceFile) => {
|
|
55
|
+
if (generatedClasses.length === 0) {
|
|
56
|
+
return sourceFile;
|
|
57
|
+
}
|
|
58
|
+
let factory = context.factory;
|
|
59
|
+
let insertIndex = 0, statements = sourceFile.statements;
|
|
60
|
+
for (let i = 0, n = statements.length; i < n; i++) {
|
|
61
|
+
if (ts.isImportDeclaration(statements[i])) {
|
|
62
|
+
insertIndex = i + 1;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
let classDecls = generatedClasses.map(gc => gc.classDecl), updatedStatements = [
|
|
69
|
+
...statements.slice(0, insertIndex),
|
|
70
|
+
...classDecls,
|
|
71
|
+
...statements.slice(insertIndex)
|
|
72
|
+
];
|
|
73
|
+
return factory.updateSourceFile(sourceFile, updatedStatements);
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const createTransformer = () => {
|
|
78
|
+
return (context) => {
|
|
79
|
+
return (sourceFile) => {
|
|
80
|
+
let code = sourceFile.getFullText();
|
|
81
|
+
if (!mightNeedTransform(code)) {
|
|
82
|
+
return sourceFile;
|
|
83
|
+
}
|
|
84
|
+
let bindings = new Map(), generatedClasses = [], neededImports = new Set(), ns = {
|
|
85
|
+
array: uid('ra'),
|
|
86
|
+
constants: uid('rc'),
|
|
87
|
+
reactivity: uid('r')
|
|
88
|
+
};
|
|
89
|
+
let objectTransformer = createObjectTransformer(bindings, neededImports, generatedClasses, ns)(context);
|
|
90
|
+
sourceFile = objectTransformer(sourceFile);
|
|
91
|
+
let arrayTransformer = createArrayTransformer(bindings)(context);
|
|
92
|
+
sourceFile = arrayTransformer(sourceFile);
|
|
93
|
+
let primitivesTransformer = createPrimitivesTransformer(bindings, neededImports, ns)(context);
|
|
94
|
+
sourceFile = primitivesTransformer(sourceFile);
|
|
95
|
+
let classInserter = insertClassesTransformer(generatedClasses)(context);
|
|
96
|
+
sourceFile = classInserter(sourceFile);
|
|
97
|
+
let importAdder = addImportsTransformer(neededImports, ns)(context);
|
|
98
|
+
sourceFile = importAdder(sourceFile);
|
|
99
|
+
return sourceFile;
|
|
100
|
+
};
|
|
41
101
|
};
|
|
42
102
|
};
|
|
43
|
-
export { createTransformer, mightNeedTransform
|
|
44
|
-
export {
|
|
45
|
-
export {
|
|
46
|
-
export {
|
|
103
|
+
export { createTransformer, mightNeedTransform };
|
|
104
|
+
export { createArrayTransformer } from './transforms/array.js';
|
|
105
|
+
export { createObjectTransformer } from './transforms/object.js';
|
|
106
|
+
export { createPrimitivesTransformer } from './transforms/primitives.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TRANSFORM_PATTERN } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import {
|
|
2
|
+
import { createTransformer, mightNeedTransform } from '../../transformer/index.js';
|
|
3
3
|
import { ts } from '@esportsplus/typescript';
|
|
4
4
|
export default () => {
|
|
5
5
|
return {
|
|
@@ -13,11 +13,14 @@ export default () => {
|
|
|
13
13
|
return null;
|
|
14
14
|
}
|
|
15
15
|
try {
|
|
16
|
-
let sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true), result = transform(sourceFile);
|
|
17
|
-
if (
|
|
16
|
+
let printer = ts.createPrinter(), sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true), transformer = createTransformer(), result = ts.transform(sourceFile, [transformer]), transformed = result.transformed[0];
|
|
17
|
+
if (transformed === sourceFile) {
|
|
18
|
+
result.dispose();
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
+
let output = printer.printFile(transformed);
|
|
22
|
+
result.dispose();
|
|
23
|
+
return { code: output, map: null };
|
|
21
24
|
}
|
|
22
25
|
catch (error) {
|
|
23
26
|
console.error(`@esportsplus/reactivity: Error transforming ${id}:`, error);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Bindings } from '../../types.js';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
|
-
declare const
|
|
4
|
-
export {
|
|
3
|
+
declare const createArrayTransformer: (bindings: Bindings) => (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile;
|
|
4
|
+
export { createArrayTransformer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createArrayLengthCall, createArraySetCall } from '../factory.js';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
3
|
function getExpressionName(node) {
|
|
4
4
|
if (ts.isIdentifier(node)) {
|
|
@@ -23,6 +23,9 @@ function getPropertyPath(node) {
|
|
|
23
23
|
}
|
|
24
24
|
function isAssignmentTarget(node) {
|
|
25
25
|
let parent = node.parent;
|
|
26
|
+
if (!parent) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
26
29
|
if ((ts.isBinaryExpression(parent) && parent.left === node) ||
|
|
27
30
|
ts.isPostfixUnaryExpression(parent) ||
|
|
28
31
|
ts.isPrefixUnaryExpression(parent)) {
|
|
@@ -58,12 +61,8 @@ function visit(ctx, node) {
|
|
|
58
61
|
!isAssignmentTarget(node)) {
|
|
59
62
|
let name = getExpressionName(node.expression);
|
|
60
63
|
if (name && ctx.bindings.get(name) === 'array') {
|
|
61
|
-
let
|
|
62
|
-
ctx.
|
|
63
|
-
end: node.end,
|
|
64
|
-
newText: `${objText}.$length()`,
|
|
65
|
-
start: node.pos
|
|
66
|
-
});
|
|
64
|
+
let transformedExpr = ts.visitEachChild(node.expression, n => visit(ctx, n), ctx.context);
|
|
65
|
+
return createArrayLengthCall(ctx.factory, transformedExpr);
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
if (ts.isBinaryExpression(node) &&
|
|
@@ -71,23 +70,22 @@ function visit(ctx, node) {
|
|
|
71
70
|
ts.isElementAccessExpression(node.left)) {
|
|
72
71
|
let elemAccess = node.left, objName = getExpressionName(elemAccess.expression);
|
|
73
72
|
if (objName && ctx.bindings.get(objName) === 'array') {
|
|
74
|
-
let
|
|
75
|
-
ctx.
|
|
76
|
-
end: node.end,
|
|
77
|
-
newText: `${objText}.$set(${indexText}, ${valueText})`,
|
|
78
|
-
start: node.pos
|
|
79
|
-
});
|
|
73
|
+
let transformedArray = ts.visitEachChild(elemAccess.expression, n => visit(ctx, n), ctx.context), transformedIndex = ts.visitEachChild(elemAccess.argumentExpression, n => visit(ctx, n), ctx.context), transformedValue = ts.visitEachChild(node.right, n => visit(ctx, n), ctx.context);
|
|
74
|
+
return createArraySetCall(ctx.factory, transformedArray, transformedIndex, transformedValue);
|
|
80
75
|
}
|
|
81
76
|
}
|
|
82
|
-
ts.
|
|
77
|
+
return ts.visitEachChild(node, n => visit(ctx, n), ctx.context);
|
|
83
78
|
}
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
const createArrayTransformer = (bindings) => {
|
|
80
|
+
return (context) => {
|
|
81
|
+
return (sourceFile) => {
|
|
82
|
+
let ctx = {
|
|
83
|
+
bindings,
|
|
84
|
+
context,
|
|
85
|
+
factory: context.factory
|
|
86
|
+
};
|
|
87
|
+
return ts.visitNode(sourceFile, n => visit(ctx, n));
|
|
88
|
+
};
|
|
89
89
|
};
|
|
90
|
-
visit(ctx, sourceFile);
|
|
91
|
-
return applyReplacements(code, ctx.replacements);
|
|
92
90
|
};
|
|
93
|
-
export {
|
|
91
|
+
export { createArrayTransformer };
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type { Bindings } from '../../types.js';
|
|
1
|
+
import type { Bindings, Namespaces } from '../../types.js';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
interface GeneratedClass {
|
|
4
|
+
classDecl: ts.ClassDeclaration;
|
|
5
|
+
className: string;
|
|
6
|
+
needsImports: Set<string>;
|
|
7
|
+
}
|
|
8
|
+
declare const createObjectTransformer: (bindings: Bindings, neededImports: Set<string>, generatedClasses: GeneratedClass[], ns: Namespaces) => (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile;
|
|
9
|
+
export { createObjectTransformer };
|
|
10
|
+
export type { GeneratedClass };
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { uid } from '@esportsplus/typescript/transformer';
|
|
2
|
-
import { addMissingImports, applyReplacements } from './utilities.js';
|
|
3
2
|
import { ts } from '@esportsplus/typescript';
|
|
4
|
-
|
|
5
|
-
const EXTRA_IMPORTS = [
|
|
6
|
-
{ module: '@esportsplus/reactivity/constants', specifier: 'REACTIVE_OBJECT' },
|
|
7
|
-
{ module: '@esportsplus/reactivity/reactive/array', specifier: 'ReactiveArray' }
|
|
8
|
-
];
|
|
9
|
-
function analyzeProperty(prop, sourceFile) {
|
|
3
|
+
function analyzeProperty(prop) {
|
|
10
4
|
if (!ts.isPropertyAssignment(prop)) {
|
|
11
5
|
return null;
|
|
12
6
|
}
|
|
@@ -17,51 +11,71 @@ function analyzeProperty(prop, sourceFile) {
|
|
|
17
11
|
else {
|
|
18
12
|
return null;
|
|
19
13
|
}
|
|
20
|
-
let value = prop.initializer
|
|
14
|
+
let value = prop.initializer;
|
|
21
15
|
if (ts.isArrowFunction(value) || ts.isFunctionExpression(value)) {
|
|
22
|
-
return { key, type: 'computed',
|
|
16
|
+
return { key, type: 'computed', value };
|
|
23
17
|
}
|
|
24
18
|
if (ts.isArrayLiteralExpression(value)) {
|
|
25
|
-
return { key, type: 'array',
|
|
19
|
+
return { elements: [...value.elements], key, type: 'array', value };
|
|
26
20
|
}
|
|
27
|
-
return { key, type: 'signal',
|
|
21
|
+
return { key, type: 'signal', value };
|
|
28
22
|
}
|
|
29
|
-
function
|
|
30
|
-
let
|
|
31
|
-
|
|
23
|
+
function buildReactiveClass(ctx, className, properties, varName) {
|
|
24
|
+
let factory = ctx.factory, members = [], needsImports = new Set();
|
|
25
|
+
needsImports.add('REACTIVE_OBJECT');
|
|
26
|
+
members.push(factory.createPropertyDeclaration(undefined, factory.createComputedPropertyName(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.constants), 'REACTIVE_OBJECT')), undefined, undefined, factory.createTrue()));
|
|
27
|
+
let disposeStatements = [];
|
|
32
28
|
for (let i = 0, n = properties.length; i < n; i++) {
|
|
33
|
-
let
|
|
34
|
-
if (type === 'signal') {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
let prop = properties[i];
|
|
30
|
+
if (prop.type === 'signal') {
|
|
31
|
+
needsImports.add('read');
|
|
32
|
+
needsImports.add('set');
|
|
33
|
+
needsImports.add('signal');
|
|
34
|
+
let privateName = factory.createPrivateIdentifier(`#${prop.key}`), paramName = uid('v');
|
|
35
|
+
members.push(factory.createPropertyDeclaration(undefined, privateName, undefined, undefined, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'signal'), undefined, [prop.value])));
|
|
36
|
+
members.push(factory.createGetAccessorDeclaration(undefined, factory.createIdentifier(prop.key), [], undefined, factory.createBlock([
|
|
37
|
+
factory.createReturnStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'read'), undefined, [factory.createPropertyAccessExpression(factory.createThis(), privateName)]))
|
|
38
|
+
], true)));
|
|
39
|
+
members.push(factory.createSetAccessorDeclaration(undefined, factory.createIdentifier(prop.key), [factory.createParameterDeclaration(undefined, undefined, paramName)], factory.createBlock([
|
|
40
|
+
factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'set'), undefined, [
|
|
41
|
+
factory.createPropertyAccessExpression(factory.createThis(), privateName),
|
|
42
|
+
factory.createIdentifier(paramName)
|
|
43
|
+
]))
|
|
44
|
+
], true)));
|
|
39
45
|
}
|
|
40
|
-
else if (type === 'array') {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
else if (prop.type === 'array') {
|
|
47
|
+
needsImports.add('ReactiveArray');
|
|
48
|
+
members.push(factory.createPropertyDeclaration(undefined, factory.createIdentifier(prop.key), undefined, undefined, factory.createNewExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.array), 'ReactiveArray'), undefined, prop.elements || [])));
|
|
49
|
+
if (varName) {
|
|
50
|
+
ctx.bindings.set(`${varName}.${prop.key}`, 'array');
|
|
51
|
+
}
|
|
52
|
+
disposeStatements.push(factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createPropertyAccessExpression(factory.createThis(), prop.key), 'dispose'), undefined, [])));
|
|
44
53
|
}
|
|
45
|
-
else if (type === 'computed') {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
else if (prop.type === 'computed') {
|
|
55
|
+
needsImports.add('computed');
|
|
56
|
+
needsImports.add('dispose');
|
|
57
|
+
needsImports.add('read');
|
|
58
|
+
let privateName = factory.createPrivateIdentifier(`#${prop.key}`);
|
|
59
|
+
members.push(factory.createPropertyDeclaration(undefined, privateName, undefined, factory.createUnionTypeNode([
|
|
60
|
+
factory.createTypeReferenceNode('Computed', [
|
|
61
|
+
factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)
|
|
62
|
+
]),
|
|
63
|
+
factory.createLiteralTypeNode(factory.createNull())
|
|
64
|
+
]), factory.createNull()));
|
|
65
|
+
members.push(factory.createGetAccessorDeclaration(undefined, factory.createIdentifier(prop.key), [], undefined, factory.createBlock([
|
|
66
|
+
factory.createReturnStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'read'), undefined, [
|
|
67
|
+
factory.createBinaryExpression(factory.createPropertyAccessExpression(factory.createThis(), privateName), ts.SyntaxKind.QuestionQuestionEqualsToken, factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'computed'), undefined, [prop.value]))
|
|
68
|
+
]))
|
|
69
|
+
], true)));
|
|
70
|
+
disposeStatements.push(factory.createIfStatement(factory.createPropertyAccessExpression(factory.createThis(), privateName), factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier(ctx.ns.reactivity), 'dispose'), undefined, [factory.createPropertyAccessExpression(factory.createThis(), privateName)]))));
|
|
49
71
|
}
|
|
50
72
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
${accessors.join('\n')}
|
|
55
|
-
|
|
56
|
-
dispose() {
|
|
57
|
-
${disposeStatements.length > 0 ? disposeStatements.join('\n') : ''}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
`;
|
|
73
|
+
members.push(factory.createMethodDeclaration(undefined, undefined, 'dispose', undefined, undefined, [], undefined, factory.createBlock(disposeStatements, true)));
|
|
74
|
+
needsImports.forEach(imp => ctx.neededImports.add(imp));
|
|
75
|
+
return factory.createClassDeclaration(undefined, className, undefined, undefined, members);
|
|
61
76
|
}
|
|
62
77
|
function visit(ctx, node) {
|
|
63
78
|
if (ts.isImportDeclaration(node)) {
|
|
64
|
-
ctx.lastImportEnd = node.end;
|
|
65
79
|
if (ts.isStringLiteral(node.moduleSpecifier) &&
|
|
66
80
|
node.moduleSpecifier.text.includes('@esportsplus/reactivity')) {
|
|
67
81
|
let clause = node.importClause;
|
|
@@ -81,83 +95,58 @@ function visit(ctx, node) {
|
|
|
81
95
|
ts.isIdentifier(node.expression) &&
|
|
82
96
|
node.expression.text === 'reactive') {
|
|
83
97
|
let arg = node.arguments[0];
|
|
98
|
+
if (arg && ts.isArrayLiteralExpression(arg)) {
|
|
99
|
+
let varName = null;
|
|
100
|
+
if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
101
|
+
varName = node.parent.name.text;
|
|
102
|
+
ctx.bindings.set(varName, 'array');
|
|
103
|
+
}
|
|
104
|
+
ctx.neededImports.add('ReactiveArray');
|
|
105
|
+
return ctx.factory.createNewExpression(ctx.factory.createPropertyAccessExpression(ctx.factory.createIdentifier(ctx.ns.array), 'ReactiveArray'), undefined, [...arg.elements]);
|
|
106
|
+
}
|
|
84
107
|
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
85
108
|
let varName = null;
|
|
86
109
|
if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
|
|
87
110
|
varName = node.parent.name.text;
|
|
88
111
|
ctx.bindings.set(varName, 'object');
|
|
89
112
|
}
|
|
90
|
-
let
|
|
91
|
-
needsImports.add('REACTIVE_OBJECT');
|
|
92
|
-
let props = arg.properties;
|
|
113
|
+
let properties = [], props = arg.properties;
|
|
93
114
|
for (let i = 0, n = props.length; i < n; i++) {
|
|
94
115
|
let prop = props[i];
|
|
95
116
|
if (ts.isSpreadAssignment(prop)) {
|
|
96
|
-
ts.
|
|
97
|
-
return;
|
|
117
|
+
return ts.visitEachChild(node, n => visit(ctx, n), ctx.context);
|
|
98
118
|
}
|
|
99
|
-
let analyzed = analyzeProperty(prop
|
|
119
|
+
let analyzed = analyzeProperty(prop);
|
|
100
120
|
if (!analyzed) {
|
|
101
|
-
ts.
|
|
102
|
-
return;
|
|
121
|
+
return ts.visitEachChild(node, n => visit(ctx, n), ctx.context);
|
|
103
122
|
}
|
|
104
123
|
properties.push(analyzed);
|
|
105
|
-
if (analyzed.type === 'signal') {
|
|
106
|
-
needsImports.add('read');
|
|
107
|
-
needsImports.add('set');
|
|
108
|
-
needsImports.add('signal');
|
|
109
|
-
}
|
|
110
|
-
else if (analyzed.type === 'array') {
|
|
111
|
-
needsImports.add('ReactiveArray');
|
|
112
|
-
if (varName) {
|
|
113
|
-
ctx.bindings.set(`${varName}.${analyzed.key}`, 'array');
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
else if (analyzed.type === 'computed') {
|
|
117
|
-
needsImports.add('computed');
|
|
118
|
-
needsImports.add('dispose');
|
|
119
|
-
needsImports.add('read');
|
|
120
|
-
}
|
|
121
124
|
}
|
|
122
|
-
|
|
123
|
-
ctx.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
needsImports
|
|
127
|
-
start: node.pos,
|
|
128
|
-
varName
|
|
125
|
+
let className = uid('ReactiveObject'), classDecl = buildReactiveClass(ctx, className, properties, varName);
|
|
126
|
+
ctx.generatedClasses.push({
|
|
127
|
+
classDecl,
|
|
128
|
+
className,
|
|
129
|
+
needsImports: new Set(ctx.neededImports)
|
|
129
130
|
});
|
|
131
|
+
return ctx.factory.createNewExpression(ctx.factory.createIdentifier(className), undefined, []);
|
|
130
132
|
}
|
|
131
133
|
}
|
|
132
|
-
ts.
|
|
134
|
+
return ts.visitEachChild(node, n => visit(ctx, n), ctx.context);
|
|
133
135
|
}
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
const createObjectTransformer = (bindings, neededImports, generatedClasses, ns) => {
|
|
137
|
+
return (context) => {
|
|
138
|
+
return (sourceFile) => {
|
|
139
|
+
let ctx = {
|
|
140
|
+
bindings,
|
|
141
|
+
context,
|
|
142
|
+
factory: context.factory,
|
|
143
|
+
generatedClasses,
|
|
144
|
+
hasReactiveImport: false,
|
|
145
|
+
neededImports,
|
|
146
|
+
ns
|
|
147
|
+
};
|
|
148
|
+
return ts.visitNode(sourceFile, n => visit(ctx, n));
|
|
149
|
+
};
|
|
142
150
|
};
|
|
143
|
-
visit(ctx, sourceFile);
|
|
144
|
-
if (ctx.calls.length === 0) {
|
|
145
|
-
return code;
|
|
146
|
-
}
|
|
147
|
-
let replacements = [];
|
|
148
|
-
replacements.push({
|
|
149
|
-
end: ctx.lastImportEnd,
|
|
150
|
-
newText: code.substring(0, ctx.lastImportEnd) + '\n' + ctx.calls.map(c => c.generatedClass).join('\n') + '\n',
|
|
151
|
-
start: 0
|
|
152
|
-
});
|
|
153
|
-
for (let i = 0, n = ctx.calls.length; i < n; i++) {
|
|
154
|
-
let call = ctx.calls[i], classMatch = call.generatedClass.match(CLASS_NAME_REGEX);
|
|
155
|
-
replacements.push({
|
|
156
|
-
end: call.end,
|
|
157
|
-
newText: ` new ${classMatch ? classMatch[1] : 'ReactiveObject'}()`,
|
|
158
|
-
start: call.start
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
return addMissingImports(applyReplacements(code, replacements), ctx.allNeededImports, EXTRA_IMPORTS);
|
|
162
151
|
};
|
|
163
|
-
export {
|
|
152
|
+
export { createObjectTransformer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Bindings } from '../../types.js';
|
|
1
|
+
import type { Bindings, Namespaces } from '../../types.js';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
|
-
declare const
|
|
4
|
-
export {
|
|
3
|
+
declare const createPrimitivesTransformer: (bindings: Bindings, neededImports: Set<string>, ns: Namespaces) => (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile;
|
|
4
|
+
export { createPrimitivesTransformer };
|