@defold-typescript/transpiler 0.5.0 → 0.5.2
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/dist/index.js +51 -1
- package/package.json +2 -2
- package/src/lifecycle-erasure.ts +99 -0
package/dist/index.js
CHANGED
|
@@ -9,11 +9,20 @@ import * as tstl2 from "typescript-to-lua";
|
|
|
9
9
|
import * as ts from "typescript";
|
|
10
10
|
import {
|
|
11
11
|
createAssignmentStatement,
|
|
12
|
+
createBinaryExpression,
|
|
12
13
|
createBlock,
|
|
14
|
+
createCallExpression,
|
|
13
15
|
createExpressionStatement,
|
|
16
|
+
createForInStatement,
|
|
14
17
|
createFunctionExpression,
|
|
15
18
|
createIdentifier,
|
|
16
|
-
|
|
19
|
+
createIfStatement,
|
|
20
|
+
createNilLiteral,
|
|
21
|
+
createReturnStatement,
|
|
22
|
+
createTableIndexExpression,
|
|
23
|
+
createVariableDeclarationStatement,
|
|
24
|
+
NodeFlags,
|
|
25
|
+
SyntaxKind as SyntaxKind2
|
|
17
26
|
} from "typescript-to-lua";
|
|
18
27
|
var FACTORY_MODULE = "@defold-typescript/types";
|
|
19
28
|
var FACTORY_NAMES = new Set(["defineScript", "defineGuiScript", "defineRenderScript"]);
|
|
@@ -65,6 +74,43 @@ function transformHookBody(fn, context) {
|
|
|
65
74
|
}
|
|
66
75
|
return [createExpressionStatement(context.transformExpression(fn.body))];
|
|
67
76
|
}
|
|
77
|
+
function crossesFunctionBoundary(node) {
|
|
78
|
+
return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
79
|
+
}
|
|
80
|
+
function initReturnsValue(fn) {
|
|
81
|
+
if (!ts.isBlock(fn.body)) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
let found = false;
|
|
85
|
+
const visit = (node) => {
|
|
86
|
+
if (found || crossesFunctionBoundary(node)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (ts.isReturnStatement(node) && node.expression !== undefined) {
|
|
90
|
+
found = true;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
ts.forEachChild(node, visit);
|
|
94
|
+
};
|
|
95
|
+
ts.forEachChild(fn.body, visit);
|
|
96
|
+
return found;
|
|
97
|
+
}
|
|
98
|
+
function initBuilderBody(fn, context) {
|
|
99
|
+
if (ts.isBlock(fn.body)) {
|
|
100
|
+
return context.transformStatements(fn.body.statements);
|
|
101
|
+
}
|
|
102
|
+
return [createReturnStatement([context.transformExpression(fn.body)])];
|
|
103
|
+
}
|
|
104
|
+
function emitInitMerge(fn, context, property) {
|
|
105
|
+
const builder = createFunctionExpression(createBlock(initBuilderBody(fn, context)), [], undefined, NodeFlags.Declaration, fn);
|
|
106
|
+
const builderDecl = createVariableDeclarationStatement(createIdentifier("____init"), builder);
|
|
107
|
+
const stateDecl = createVariableDeclarationStatement(createIdentifier("____s"), createCallExpression(createIdentifier("____init"), []));
|
|
108
|
+
const mergeAssignment = createAssignmentStatement(createTableIndexExpression(createIdentifier("self"), createIdentifier("____k")), createIdentifier("____v"));
|
|
109
|
+
const forIn = createForInStatement(createBlock([mergeAssignment]), [createIdentifier("____k"), createIdentifier("____v")], [createCallExpression(createIdentifier("pairs"), [createIdentifier("____s")])]);
|
|
110
|
+
const guard = createIfStatement(createBinaryExpression(createIdentifier("____s"), createNilLiteral(), SyntaxKind2.InequalityOperator), createBlock([forIn]));
|
|
111
|
+
const initFn = createFunctionExpression(createBlock([stateDecl, guard]), [createIdentifier("self")], undefined, NodeFlags.Declaration, fn);
|
|
112
|
+
return [builderDecl, createAssignmentStatement(createIdentifier("init"), initFn, property)];
|
|
113
|
+
}
|
|
68
114
|
function eraseFactoryCall(expression, context) {
|
|
69
115
|
if (!ts.isCallExpression(expression)) {
|
|
70
116
|
return;
|
|
@@ -83,6 +129,10 @@ function eraseFactoryCall(expression, context) {
|
|
|
83
129
|
if (name === undefined || fn === undefined) {
|
|
84
130
|
continue;
|
|
85
131
|
}
|
|
132
|
+
if (name === "init" && initReturnsValue(fn)) {
|
|
133
|
+
statements.push(...emitInitMerge(fn, context, property));
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
86
136
|
const params = fn.parameters.filter((param) => !isThisParameter(param) && ts.isIdentifier(param.name)).map((param) => context.transformExpression(param.name));
|
|
87
137
|
const fnExpression = createFunctionExpression(createBlock(transformHookBody(fn, context)), params, undefined, NodeFlags.Declaration, fn);
|
|
88
138
|
statements.push(createAssignmentStatement(createIdentifier(name), fnExpression, property));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defold-typescript/transpiler",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "TypeScript-to-Lua build pipeline tuned for Defold's runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"test": "bun test"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@defold-typescript/types": "0.5.
|
|
31
|
+
"@defold-typescript/types": "0.5.2",
|
|
32
32
|
"@typescript-to-lua/language-extensions": "1.19.0",
|
|
33
33
|
"typescript-to-lua": "^1.36.0"
|
|
34
34
|
}
|
package/src/lifecycle-erasure.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
2
|
import {
|
|
3
3
|
createAssignmentStatement,
|
|
4
|
+
createBinaryExpression,
|
|
4
5
|
createBlock,
|
|
6
|
+
createCallExpression,
|
|
5
7
|
createExpressionStatement,
|
|
8
|
+
createForInStatement,
|
|
6
9
|
createFunctionExpression,
|
|
7
10
|
createIdentifier,
|
|
11
|
+
createIfStatement,
|
|
12
|
+
createNilLiteral,
|
|
13
|
+
createReturnStatement,
|
|
14
|
+
createTableIndexExpression,
|
|
15
|
+
createVariableDeclarationStatement,
|
|
8
16
|
type Identifier,
|
|
9
17
|
NodeFlags,
|
|
10
18
|
type Plugin,
|
|
11
19
|
type Statement,
|
|
20
|
+
SyntaxKind,
|
|
12
21
|
type TransformationContext,
|
|
13
22
|
} from "typescript-to-lua";
|
|
14
23
|
|
|
@@ -75,6 +84,92 @@ function transformHookBody(fn: HookFunction, context: TransformationContext): St
|
|
|
75
84
|
return [createExpressionStatement(context.transformExpression(fn.body))];
|
|
76
85
|
}
|
|
77
86
|
|
|
87
|
+
function crossesFunctionBoundary(node: ts.Node): boolean {
|
|
88
|
+
return (
|
|
89
|
+
ts.isFunctionDeclaration(node) ||
|
|
90
|
+
ts.isFunctionExpression(node) ||
|
|
91
|
+
ts.isArrowFunction(node) ||
|
|
92
|
+
ts.isMethodDeclaration(node) ||
|
|
93
|
+
ts.isGetAccessorDeclaration(node) ||
|
|
94
|
+
ts.isSetAccessorDeclaration(node)
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function initReturnsValue(fn: HookFunction): boolean {
|
|
99
|
+
if (!ts.isBlock(fn.body)) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
let found = false;
|
|
103
|
+
const visit = (node: ts.Node): void => {
|
|
104
|
+
if (found || crossesFunctionBoundary(node)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (ts.isReturnStatement(node) && node.expression !== undefined) {
|
|
108
|
+
found = true;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
ts.forEachChild(node, visit);
|
|
112
|
+
};
|
|
113
|
+
ts.forEachChild(fn.body, visit);
|
|
114
|
+
return found;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function initBuilderBody(fn: HookFunction, context: TransformationContext): Statement[] {
|
|
118
|
+
if (ts.isBlock(fn.body)) {
|
|
119
|
+
return context.transformStatements(fn.body.statements);
|
|
120
|
+
}
|
|
121
|
+
return [createReturnStatement([context.transformExpression(fn.body)])];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// init-merge: Defold owns `self` (a userdata-backed table) and a script can
|
|
125
|
+
// populate but not replace it, so a returning `init(): TSelf` can't be emitted
|
|
126
|
+
// verbatim. Wrap the body in a `____init` builder and merge its result onto the
|
|
127
|
+
// engine `self`; a `nil` return (stateless script) merges nothing.
|
|
128
|
+
function emitInitMerge(
|
|
129
|
+
fn: HookFunction,
|
|
130
|
+
context: TransformationContext,
|
|
131
|
+
property: ts.ObjectLiteralElementLike,
|
|
132
|
+
): Statement[] {
|
|
133
|
+
const builder = createFunctionExpression(
|
|
134
|
+
createBlock(initBuilderBody(fn, context)),
|
|
135
|
+
[],
|
|
136
|
+
undefined,
|
|
137
|
+
NodeFlags.Declaration,
|
|
138
|
+
fn,
|
|
139
|
+
);
|
|
140
|
+
const builderDecl = createVariableDeclarationStatement(createIdentifier("____init"), builder);
|
|
141
|
+
|
|
142
|
+
const stateDecl = createVariableDeclarationStatement(
|
|
143
|
+
createIdentifier("____s"),
|
|
144
|
+
createCallExpression(createIdentifier("____init"), []),
|
|
145
|
+
);
|
|
146
|
+
const mergeAssignment = createAssignmentStatement(
|
|
147
|
+
createTableIndexExpression(createIdentifier("self"), createIdentifier("____k")),
|
|
148
|
+
createIdentifier("____v"),
|
|
149
|
+
);
|
|
150
|
+
const forIn = createForInStatement(
|
|
151
|
+
createBlock([mergeAssignment]),
|
|
152
|
+
[createIdentifier("____k"), createIdentifier("____v")],
|
|
153
|
+
[createCallExpression(createIdentifier("pairs"), [createIdentifier("____s")])],
|
|
154
|
+
);
|
|
155
|
+
const guard = createIfStatement(
|
|
156
|
+
createBinaryExpression(
|
|
157
|
+
createIdentifier("____s"),
|
|
158
|
+
createNilLiteral(),
|
|
159
|
+
SyntaxKind.InequalityOperator,
|
|
160
|
+
),
|
|
161
|
+
createBlock([forIn]),
|
|
162
|
+
);
|
|
163
|
+
const initFn = createFunctionExpression(
|
|
164
|
+
createBlock([stateDecl, guard]),
|
|
165
|
+
[createIdentifier("self")],
|
|
166
|
+
undefined,
|
|
167
|
+
NodeFlags.Declaration,
|
|
168
|
+
fn,
|
|
169
|
+
);
|
|
170
|
+
return [builderDecl, createAssignmentStatement(createIdentifier("init"), initFn, property)];
|
|
171
|
+
}
|
|
172
|
+
|
|
78
173
|
function eraseFactoryCall(
|
|
79
174
|
expression: ts.Expression,
|
|
80
175
|
context: TransformationContext,
|
|
@@ -96,6 +191,10 @@ function eraseFactoryCall(
|
|
|
96
191
|
if (name === undefined || fn === undefined) {
|
|
97
192
|
continue;
|
|
98
193
|
}
|
|
194
|
+
if (name === "init" && initReturnsValue(fn)) {
|
|
195
|
+
statements.push(...emitInitMerge(fn, context, property));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
99
198
|
const params: Identifier[] = fn.parameters
|
|
100
199
|
.filter((param) => !isThisParameter(param) && ts.isIdentifier(param.name))
|
|
101
200
|
.map((param) => context.transformExpression(param.name as ts.Identifier) as Identifier);
|