@defold-typescript/transpiler 0.35.0 → 0.36.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/dist/companion-closure.d.ts +57 -0
- package/dist/companion-emit.d.ts +21 -0
- package/dist/emitted-requires.d.ts +7 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +2300 -1246
- package/dist/lifecycle-erasure.d.ts +1 -0
- package/dist/lua-require-scan.d.ts +17 -0
- package/dist/output-paths.d.ts +9 -0
- package/dist/require-rewrite.d.ts +13 -0
- package/dist/timers-lowering.d.ts +1 -1
- package/dist/transpile.d.ts +2 -1
- package/package.json +2 -2
- package/src/companion-closure.ts +761 -0
- package/src/companion-emit.ts +660 -0
- package/src/emitted-requires.ts +31 -0
- package/src/index.ts +11 -0
- package/src/lifecycle-erasure.ts +1 -1
- package/src/lua-require-scan.ts +0 -0
- package/src/output-paths.ts +20 -0
- package/src/require-rewrite.ts +36 -0
- package/src/session.ts +32 -24
- package/src/timers-lowering.ts +10 -1
- package/src/timers-runtime.ts +4 -3
- package/src/transpile.ts +27 -5
package/dist/index.js
CHANGED
|
@@ -1,1342 +1,1963 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
// src/companion-closure.ts
|
|
2
|
+
import * as ts3 from "typescript";
|
|
3
|
+
|
|
4
|
+
// src/lifecycle-erasure.ts
|
|
5
|
+
import * as ts2 from "typescript";
|
|
6
|
+
import {
|
|
7
|
+
createAssignmentStatement,
|
|
8
|
+
createBinaryExpression as createBinaryExpression2,
|
|
9
|
+
createBlock as createBlock2,
|
|
10
|
+
createCallExpression as createCallExpression2,
|
|
11
|
+
createExpressionStatement,
|
|
12
|
+
createForInStatement,
|
|
13
|
+
createFunctionExpression as createFunctionExpression2,
|
|
14
|
+
createIdentifier as createIdentifier2,
|
|
15
|
+
createIfStatement as createIfStatement2,
|
|
16
|
+
createNilLiteral,
|
|
17
|
+
createReturnStatement,
|
|
18
|
+
createStringLiteral as createStringLiteral2,
|
|
19
|
+
createTableIndexExpression,
|
|
20
|
+
createVariableDeclarationStatement as createVariableDeclarationStatement2,
|
|
21
|
+
NodeFlags as NodeFlags2,
|
|
22
|
+
SyntaxKind as SyntaxKind4
|
|
23
|
+
} from "typescript-to-lua";
|
|
24
|
+
|
|
25
|
+
// src/message-dispatch-lowering.ts
|
|
26
|
+
import * as ts from "typescript";
|
|
27
|
+
import {
|
|
28
|
+
createBinaryExpression,
|
|
29
|
+
createBlock,
|
|
30
|
+
createCallExpression,
|
|
31
|
+
createFunctionExpression,
|
|
32
|
+
createIdentifier,
|
|
33
|
+
createIfStatement,
|
|
34
|
+
createStringLiteral,
|
|
35
|
+
createVariableDeclarationStatement,
|
|
36
|
+
NodeFlags,
|
|
37
|
+
SyntaxKind as SyntaxKind2
|
|
38
|
+
} from "typescript-to-lua";
|
|
39
|
+
var DISPATCH_MODULE = "@defold-typescript/types";
|
|
40
|
+
var DISPATCH_NAME = "onMessage";
|
|
41
|
+
var HANDLER_PARAM_TARGETS = ["self", "message", "sender"];
|
|
42
|
+
function resolvesToDispatchExport(callee, checker) {
|
|
43
|
+
let symbol = checker.getSymbolAtLocation(callee);
|
|
44
|
+
if (symbol === undefined) {
|
|
45
|
+
return false;
|
|
8
46
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function append(target, key, value) {
|
|
12
|
-
const existing = target.get(key);
|
|
13
|
-
if (existing === undefined) {
|
|
14
|
-
target.set(key, [value]);
|
|
15
|
-
return;
|
|
47
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
48
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
16
49
|
}
|
|
17
|
-
|
|
50
|
+
if (symbol.getName() !== DISPATCH_NAME) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
54
|
+
if (declaration === undefined) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return declaration.getSourceFile().fileName.includes(DISPATCH_MODULE);
|
|
18
58
|
}
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
throw new SceneTextFormatError(message, at);
|
|
59
|
+
function handlerName(property) {
|
|
60
|
+
const name = property.name;
|
|
61
|
+
if (name === undefined) {
|
|
62
|
+
return;
|
|
24
63
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
pos += 1;
|
|
28
|
-
if (ch === `
|
|
29
|
-
`)
|
|
30
|
-
line += 1;
|
|
31
|
-
return ch;
|
|
64
|
+
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
65
|
+
return name.text;
|
|
32
66
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return;
|
|
39
|
-
advance();
|
|
40
|
-
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
function handlerFunction(property) {
|
|
70
|
+
if (ts.isMethodDeclaration(property) && property.body !== undefined) {
|
|
71
|
+
return property;
|
|
41
72
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return;
|
|
47
|
-
pos += 1;
|
|
73
|
+
if (ts.isPropertyAssignment(property)) {
|
|
74
|
+
const initializer = property.initializer;
|
|
75
|
+
if (ts.isFunctionExpression(initializer) || ts.isArrowFunction(initializer)) {
|
|
76
|
+
return initializer;
|
|
48
77
|
}
|
|
49
78
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
function isThisParameter(param) {
|
|
82
|
+
return ts.isIdentifier(param.name) && ts.identifierToKeywordKind(param.name) === ts.SyntaxKind.ThisKeyword;
|
|
83
|
+
}
|
|
84
|
+
function aliasStatements(fn) {
|
|
85
|
+
const params = fn.parameters.filter((param) => !isThisParameter(param));
|
|
86
|
+
const aliases = [];
|
|
87
|
+
params.forEach((param, index) => {
|
|
88
|
+
const engineName = HANDLER_PARAM_TARGETS[index];
|
|
89
|
+
if (engineName === undefined || !ts.isIdentifier(param.name)) {
|
|
90
|
+
return;
|
|
54
91
|
}
|
|
55
|
-
if (
|
|
56
|
-
|
|
92
|
+
if (param.name.text !== engineName) {
|
|
93
|
+
aliases.push(createVariableDeclarationStatement(createIdentifier(param.name.text), createIdentifier(engineName)));
|
|
57
94
|
}
|
|
58
|
-
|
|
95
|
+
});
|
|
96
|
+
return aliases;
|
|
97
|
+
}
|
|
98
|
+
function handlerBody(fn, context) {
|
|
99
|
+
if (ts.isBlock(fn.body)) {
|
|
100
|
+
return context.transformStatements(fn.body.statements);
|
|
59
101
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
value += "\t";
|
|
83
|
-
else
|
|
84
|
-
value += `\\${escaped}`;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (ch === '"') {
|
|
88
|
-
closed = true;
|
|
89
|
-
break;
|
|
102
|
+
return context.transformStatements([ts.factory.createExpressionStatement(fn.body)]);
|
|
103
|
+
}
|
|
104
|
+
var messageDispatchLoweringPlugin = {
|
|
105
|
+
visitors: {
|
|
106
|
+
[ts.SyntaxKind.CallExpression]: (node, context) => {
|
|
107
|
+
const [handlersArg] = node.arguments;
|
|
108
|
+
if (node.arguments.length === 1 && handlersArg !== undefined && ts.isObjectLiteralExpression(handlersArg) && resolvesToDispatchExport(node.expression, context.checker)) {
|
|
109
|
+
let chain;
|
|
110
|
+
const properties = [...handlersArg.properties];
|
|
111
|
+
for (let i = properties.length - 1;i >= 0; i--) {
|
|
112
|
+
const property = properties[i];
|
|
113
|
+
if (property === undefined) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const name = handlerName(property);
|
|
117
|
+
const fn = handlerFunction(property);
|
|
118
|
+
if (name === undefined || fn === undefined) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const condition = createBinaryExpression(createIdentifier("message_id"), createCallExpression(createIdentifier("hash"), [createStringLiteral(name)]), SyntaxKind2.EqualityOperator);
|
|
122
|
+
const body = [...aliasStatements(fn), ...handlerBody(fn, context)];
|
|
123
|
+
chain = createIfStatement(condition, createBlock(body), chain);
|
|
90
124
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
const resumePos = pos;
|
|
100
|
-
const resumeLine = line;
|
|
101
|
-
skipWhitespace();
|
|
102
|
-
if (text.charAt(pos) === '"') {
|
|
103
|
-
continue;
|
|
125
|
+
const params = [
|
|
126
|
+
createIdentifier("self"),
|
|
127
|
+
createIdentifier("message_id"),
|
|
128
|
+
createIdentifier("message"),
|
|
129
|
+
createIdentifier("sender")
|
|
130
|
+
];
|
|
131
|
+
return createFunctionExpression(createBlock(chain === undefined ? [] : [chain]), params, undefined, NodeFlags.Declaration, node);
|
|
104
132
|
}
|
|
105
|
-
|
|
106
|
-
line = resumeLine;
|
|
107
|
-
return value;
|
|
133
|
+
return context.superTransformExpression(node);
|
|
108
134
|
}
|
|
109
135
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// src/lifecycle-erasure.ts
|
|
139
|
+
var FACTORY_MODULE = "@defold-typescript/types";
|
|
140
|
+
var FACTORY_NAMES = new Set(["defineScript", "defineGuiScript", "defineRenderScript"]);
|
|
141
|
+
var FACTORY_SPECIFIERS = new Set([
|
|
142
|
+
FACTORY_MODULE,
|
|
143
|
+
`${FACTORY_MODULE}/script`,
|
|
144
|
+
`${FACTORY_MODULE}/gui-script`,
|
|
145
|
+
`${FACTORY_MODULE}/render-script`
|
|
146
|
+
]);
|
|
147
|
+
function resolvesToFactoryExport(callee, checker) {
|
|
148
|
+
let symbol = checker.getSymbolAtLocation(callee);
|
|
149
|
+
if (symbol === undefined) {
|
|
150
|
+
return false;
|
|
117
151
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
fail(`expected \`:\` or \`{\` after \`${key}\``, keyLine);
|
|
152
|
+
if (symbol.flags & ts2.SymbolFlags.Alias) {
|
|
153
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
154
|
+
}
|
|
155
|
+
if (!FACTORY_NAMES.has(symbol.getName())) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
159
|
+
if (declaration === undefined) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE);
|
|
163
|
+
}
|
|
164
|
+
function isThisParameter2(param) {
|
|
165
|
+
return ts2.isIdentifier(param.name) && ts2.identifierToKeywordKind(param.name) === ts2.SyntaxKind.ThisKeyword;
|
|
166
|
+
}
|
|
167
|
+
function hookName(property) {
|
|
168
|
+
const name = property.name;
|
|
169
|
+
if (name === undefined) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) {
|
|
173
|
+
return name.text;
|
|
174
|
+
}
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
function hookFunction(property) {
|
|
178
|
+
if (ts2.isMethodDeclaration(property) && property.body !== undefined) {
|
|
179
|
+
return property;
|
|
180
|
+
}
|
|
181
|
+
if (ts2.isPropertyAssignment(property)) {
|
|
182
|
+
const initializer = property.initializer;
|
|
183
|
+
if (ts2.isFunctionExpression(initializer) || ts2.isArrowFunction(initializer)) {
|
|
184
|
+
return initializer;
|
|
153
185
|
}
|
|
154
|
-
return { fields, messages };
|
|
155
186
|
}
|
|
156
|
-
return
|
|
187
|
+
return;
|
|
157
188
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
189
|
+
function dispatcherInitializer(property, checker) {
|
|
190
|
+
if (!ts2.isPropertyAssignment(property)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const initializer = property.initializer;
|
|
194
|
+
if (!ts2.isCallExpression(initializer)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
return resolvesToDispatchExport(initializer.expression, checker) ? initializer : undefined;
|
|
162
198
|
}
|
|
163
|
-
function
|
|
164
|
-
|
|
199
|
+
function transformHookBody(fn, context) {
|
|
200
|
+
if (ts2.isBlock(fn.body)) {
|
|
201
|
+
return context.transformStatements(fn.body.statements);
|
|
202
|
+
}
|
|
203
|
+
return [createExpressionStatement(context.transformExpression(fn.body))];
|
|
165
204
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
var ANIMATION_SET_SUFFIX = ".animationset";
|
|
169
|
-
var HOP_ONLY_SUFFIXES = [SPRITE_SUFFIX, MODEL_SUFFIX, ANIMATION_SET_SUFFIX];
|
|
170
|
-
function childrenOf(message, name) {
|
|
171
|
-
return message.messages.get(name) ?? [];
|
|
205
|
+
function crossesFunctionBoundary(node) {
|
|
206
|
+
return ts2.isFunctionDeclaration(node) || ts2.isFunctionExpression(node) || ts2.isArrowFunction(node) || ts2.isMethodDeclaration(node) || ts2.isGetAccessorDeclaration(node) || ts2.isSetAccessorDeclaration(node);
|
|
172
207
|
}
|
|
173
|
-
function
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
208
|
+
function initReturnsValue(fn) {
|
|
209
|
+
if (!ts2.isBlock(fn.body)) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
let found = false;
|
|
213
|
+
const visit = (node) => {
|
|
214
|
+
if (found || crossesFunctionBoundary(node)) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (ts2.isReturnStatement(node) && node.expression !== undefined) {
|
|
218
|
+
found = true;
|
|
219
|
+
return;
|
|
179
220
|
}
|
|
221
|
+
ts2.forEachChild(node, visit);
|
|
222
|
+
};
|
|
223
|
+
ts2.forEachChild(fn.body, visit);
|
|
224
|
+
return found;
|
|
225
|
+
}
|
|
226
|
+
function initBuilderBody(fn, context) {
|
|
227
|
+
if (ts2.isBlock(fn.body)) {
|
|
228
|
+
return context.transformStatements(fn.body.statements);
|
|
180
229
|
}
|
|
181
|
-
return
|
|
230
|
+
return [createReturnStatement([context.transformExpression(fn.body)])];
|
|
182
231
|
}
|
|
183
|
-
function
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
232
|
+
function emitInitMerge(fn, context, property) {
|
|
233
|
+
const authorParam = fn.parameters.find((param) => !isThisParameter2(param) && ts2.isIdentifier(param.name));
|
|
234
|
+
const builderParams = authorParam === undefined ? [] : [context.transformExpression(authorParam.name)];
|
|
235
|
+
const builder = createFunctionExpression2(createBlock2(initBuilderBody(fn, context)), builderParams, undefined, NodeFlags2.Declaration, fn);
|
|
236
|
+
const builderDecl = createVariableDeclarationStatement2(createIdentifier2("____init"), builder);
|
|
237
|
+
const builderArgs = authorParam === undefined ? [] : [createIdentifier2("self")];
|
|
238
|
+
const stateDecl = createVariableDeclarationStatement2(createIdentifier2("____s"), createCallExpression2(createIdentifier2("____init"), builderArgs));
|
|
239
|
+
const mergeAssignment = createAssignmentStatement(createTableIndexExpression(createIdentifier2("self"), createIdentifier2("____k")), createIdentifier2("____v"));
|
|
240
|
+
const forIn = createForInStatement(createBlock2([mergeAssignment]), [createIdentifier2("____k"), createIdentifier2("____v")], [createCallExpression2(createIdentifier2("pairs"), [createIdentifier2("____s")])]);
|
|
241
|
+
const guard = createIfStatement2(createBinaryExpression2(createIdentifier2("____s"), createNilLiteral(), SyntaxKind4.InequalityOperator), createBlock2([forIn]));
|
|
242
|
+
const initFn = createFunctionExpression2(createBlock2([stateDecl, guard]), [createIdentifier2("self")], undefined, NodeFlags2.Declaration, fn);
|
|
243
|
+
return [builderDecl, createAssignmentStatement(createIdentifier2("init"), initFn, property)];
|
|
244
|
+
}
|
|
245
|
+
function emitPropertyRegistrations(property, context) {
|
|
246
|
+
if (!ts2.isPropertyAssignment(property) || !ts2.isObjectLiteralExpression(property.initializer)) {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
const registrations = [];
|
|
250
|
+
for (const member of property.initializer.properties) {
|
|
251
|
+
if (!ts2.isPropertyAssignment(member)) {
|
|
188
252
|
continue;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
} catch (error) {
|
|
193
|
-
if (!(error instanceof SceneTextFormatError))
|
|
194
|
-
throw error;
|
|
195
|
-
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
253
|
+
}
|
|
254
|
+
const key = member.name;
|
|
255
|
+
if (!ts2.isIdentifier(key) && !ts2.isStringLiteral(key)) {
|
|
196
256
|
continue;
|
|
197
257
|
}
|
|
198
|
-
|
|
258
|
+
registrations.push(createExpressionStatement(createCallExpression2(createTableIndexExpression(createIdentifier2("go"), createStringLiteral2("property")), [createStringLiteral2(key.text), context.transformExpression(member.initializer)])));
|
|
199
259
|
}
|
|
200
|
-
return
|
|
260
|
+
return registrations;
|
|
201
261
|
}
|
|
202
|
-
function
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for (const animation of entry.fields.get("animation") ?? []) {
|
|
206
|
-
if (animation !== "")
|
|
207
|
-
entries.push(animation);
|
|
208
|
-
}
|
|
262
|
+
function eraseFactoryCall(expression, context) {
|
|
263
|
+
if (!ts2.isCallExpression(expression)) {
|
|
264
|
+
return;
|
|
209
265
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
function childrenOf2(message, name) {
|
|
223
|
-
return message.messages.get(name) ?? [];
|
|
224
|
-
}
|
|
225
|
-
function basename(resource) {
|
|
226
|
-
const file = resource.slice(resource.lastIndexOf("/") + 1);
|
|
227
|
-
const dot = file.lastIndexOf(".");
|
|
228
|
-
return dot === -1 ? file : file.slice(0, dot);
|
|
229
|
-
}
|
|
230
|
-
function readAssets(assets, unresolved) {
|
|
231
|
-
const animationsByTileSet = readAnimationSources(assets, unresolved);
|
|
232
|
-
const tileSetBySprite = new Map;
|
|
233
|
-
const modelDocuments = new Set;
|
|
234
|
-
const animationSourceByModel = new Map;
|
|
235
|
-
const entriesByAnimationSet = new Map;
|
|
236
|
-
for (const [path, text] of assets) {
|
|
237
|
-
const displayPath = normalizeDocumentKey(path);
|
|
238
|
-
const isSprite = displayPath.endsWith(SPRITE_SUFFIX2);
|
|
239
|
-
const isModel = displayPath.endsWith(MODEL_SUFFIX2);
|
|
240
|
-
const isAnimationSet = displayPath.endsWith(ANIMATION_SET_SUFFIX2);
|
|
241
|
-
if (!isSprite && !isModel && !isAnimationSet)
|
|
266
|
+
if (!resolvesToFactoryExport(expression.expression, context.checker)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const hooks = expression.arguments[0];
|
|
270
|
+
if (hooks === undefined || !ts2.isObjectLiteralExpression(hooks)) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const registrations = [];
|
|
274
|
+
const statements = [];
|
|
275
|
+
for (const property of hooks.properties) {
|
|
276
|
+
const name = hookName(property);
|
|
277
|
+
if (name === undefined) {
|
|
242
278
|
continue;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
} catch (error) {
|
|
247
|
-
if (!(error instanceof SceneTextFormatError))
|
|
248
|
-
throw error;
|
|
249
|
-
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
279
|
+
}
|
|
280
|
+
if (name === "properties") {
|
|
281
|
+
registrations.push(...emitPropertyRegistrations(property, context));
|
|
250
282
|
continue;
|
|
251
283
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
284
|
+
const fn = hookFunction(property);
|
|
285
|
+
if (fn === undefined) {
|
|
286
|
+
const dispatch = dispatcherInitializer(property, context.checker);
|
|
287
|
+
if (dispatch !== undefined) {
|
|
288
|
+
statements.push(createAssignmentStatement(createIdentifier2(name), context.transformExpression(dispatch), property));
|
|
289
|
+
}
|
|
256
290
|
continue;
|
|
257
291
|
}
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
const animations = firstField(document, "animations");
|
|
261
|
-
if (animations !== undefined)
|
|
262
|
-
animationSourceByModel.set(displayPath, animations);
|
|
292
|
+
if (name === "init" && initReturnsValue(fn)) {
|
|
293
|
+
statements.push(...emitInitMerge(fn, context, property));
|
|
263
294
|
continue;
|
|
264
295
|
}
|
|
265
|
-
|
|
296
|
+
const params = fn.parameters.filter((param) => !isThisParameter2(param) && ts2.isIdentifier(param.name)).map((param) => context.transformExpression(param.name));
|
|
297
|
+
const fnExpression = createFunctionExpression2(createBlock2(transformHookBody(fn, context)), params, undefined, NodeFlags2.Declaration, fn);
|
|
298
|
+
statements.push(createAssignmentStatement(createIdentifier2(name), fnExpression, property));
|
|
266
299
|
}
|
|
267
|
-
return
|
|
268
|
-
animationsByTileSet,
|
|
269
|
-
tileSetBySprite,
|
|
270
|
-
modelDocuments,
|
|
271
|
-
animationSourceByModel,
|
|
272
|
-
entriesByAnimationSet
|
|
273
|
-
};
|
|
300
|
+
return [...registrations, ...statements];
|
|
274
301
|
}
|
|
275
|
-
function
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
302
|
+
function isFactoryOnlyImport(node) {
|
|
303
|
+
if (!ts2.isStringLiteral(node.moduleSpecifier) || !FACTORY_SPECIFIERS.has(node.moduleSpecifier.text)) {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
const clause = node.importClause;
|
|
307
|
+
if (clause === undefined || clause.name !== undefined) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
if (clause.isTypeOnly) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
const bindings = clause.namedBindings;
|
|
314
|
+
if (bindings === undefined || !ts2.isNamedImports(bindings)) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const runtime = bindings.elements.filter((element) => !element.isTypeOnly);
|
|
318
|
+
if (runtime.length === 0) {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
return runtime.every((element) => FACTORY_NAMES.has((element.propertyName ?? element.name).text));
|
|
322
|
+
}
|
|
323
|
+
var lifecycleErasurePlugin = {
|
|
324
|
+
visitors: {
|
|
325
|
+
[ts2.SyntaxKind.ExpressionStatement]: (node, context) => eraseFactoryCall(node.expression, context) ?? context.superTransformStatements(node),
|
|
326
|
+
[ts2.SyntaxKind.ExportAssignment]: (node, context) => {
|
|
327
|
+
if (!node.isExportEquals) {
|
|
328
|
+
const erased = eraseFactoryCall(node.expression, context);
|
|
329
|
+
if (erased !== undefined) {
|
|
330
|
+
return erased;
|
|
331
|
+
}
|
|
300
332
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
stack,
|
|
305
|
-
assets,
|
|
306
|
-
unresolved
|
|
307
|
-
});
|
|
308
|
-
if (nested === undefined)
|
|
309
|
-
return;
|
|
310
|
-
for (const [id, declaring] of nested)
|
|
311
|
-
if (!ids.has(id))
|
|
312
|
-
ids.set(id, declaring);
|
|
313
|
-
}
|
|
314
|
-
return ids;
|
|
315
|
-
} finally {
|
|
316
|
-
stack.delete(path);
|
|
333
|
+
return context.superTransformStatements(node);
|
|
334
|
+
},
|
|
335
|
+
[ts2.SyntaxKind.ImportDeclaration]: (node, context) => isFactoryOnlyImport(node) ? [] : context.superTransformStatements(node)
|
|
317
336
|
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// src/companion-closure.ts
|
|
340
|
+
var COMPANION_INTERNAL_FIELD = "____closure";
|
|
341
|
+
function isAssignmentOperator(kind) {
|
|
342
|
+
return kind >= ts3.SyntaxKind.FirstAssignment && kind <= ts3.SyntaxKind.LastAssignment;
|
|
318
343
|
}
|
|
319
|
-
function
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (
|
|
323
|
-
|
|
324
|
-
return;
|
|
344
|
+
function isTypePosition(node) {
|
|
345
|
+
let current = node.parent;
|
|
346
|
+
while (current !== undefined && !ts3.isSourceFile(current)) {
|
|
347
|
+
if (ts3.isTypeNode(current)) {
|
|
348
|
+
return true;
|
|
325
349
|
}
|
|
326
|
-
|
|
350
|
+
current = current.parent;
|
|
327
351
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (id === undefined || payload === undefined)
|
|
335
|
-
continue;
|
|
336
|
-
let document;
|
|
337
|
-
try {
|
|
338
|
-
document = parseSceneTextFormat(payload);
|
|
339
|
-
} catch (error) {
|
|
340
|
-
if (!(error instanceof SceneTextFormatError))
|
|
341
|
-
throw error;
|
|
342
|
-
unresolved.push(`${displayPath}: the embedded ${type} "${id}" could not be read (${error.message})`);
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
if (type === "sprite") {
|
|
346
|
-
const tileSet = firstField(document, "tile_set");
|
|
347
|
-
if (tileSet !== undefined)
|
|
348
|
-
sources.set(id, { kind: "sprite", path: resourceKey(tileSet) });
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
const animations = firstField(document, "animations");
|
|
352
|
-
if (animations !== undefined)
|
|
353
|
-
claimModel(id, animations);
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
function isDeclarationName(node) {
|
|
355
|
+
const parent = node.parent;
|
|
356
|
+
if (parent === undefined) {
|
|
357
|
+
return false;
|
|
354
358
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
359
|
+
if (ts3.isPropertyAccessExpression(parent)) {
|
|
360
|
+
return parent.name === node;
|
|
361
|
+
}
|
|
362
|
+
if (ts3.isQualifiedName(parent)) {
|
|
363
|
+
return parent.right === node;
|
|
364
|
+
}
|
|
365
|
+
if ((ts3.isBindingElement(parent) || ts3.isImportSpecifier(parent) || ts3.isExportSpecifier(parent)) && parent.propertyName === node) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
const named = parent;
|
|
369
|
+
if (named.name !== node) {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
return ts3.isVariableDeclaration(parent) || ts3.isFunctionDeclaration(parent) || ts3.isClassDeclaration(parent) || ts3.isEnumDeclaration(parent) || ts3.isEnumMember(parent) || ts3.isParameter(parent) || ts3.isBindingElement(parent) || ts3.isImportClause(parent) || ts3.isImportSpecifier(parent) || ts3.isNamespaceImport(parent) || ts3.isPropertyAssignment(parent) || ts3.isPropertyDeclaration(parent) || ts3.isPropertySignature(parent) || ts3.isMethodDeclaration(parent) || ts3.isMethodSignature(parent) || ts3.isTypeAliasDeclaration(parent) || ts3.isInterfaceDeclaration(parent) || ts3.isGetAccessor(parent) || ts3.isSetAccessor(parent);
|
|
373
|
+
}
|
|
374
|
+
function forEachReference(root, checker, visit) {
|
|
375
|
+
const walk = (node) => {
|
|
376
|
+
if (ts3.isIdentifier(node) && !isDeclarationName(node) && !isTypePosition(node)) {
|
|
377
|
+
const symbol = resolveReferencedSymbol(node, checker);
|
|
378
|
+
if (symbol !== undefined) {
|
|
379
|
+
visit(node, symbol);
|
|
365
380
|
}
|
|
366
|
-
sources.set(id, { kind: "sprite", path: tileSet });
|
|
367
|
-
continue;
|
|
368
381
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (!assets.modelDocuments.has(resource)) {
|
|
373
|
-
unresolved.push(`${displayPath}: the model component "${id}" names ${component}, which is not among the project's model documents`);
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
const animations = assets.animationSourceByModel.get(resource);
|
|
377
|
-
if (animations !== undefined)
|
|
378
|
-
claimModel(id, animations);
|
|
379
|
-
}
|
|
380
|
-
return sources;
|
|
382
|
+
ts3.forEachChild(node, walk);
|
|
383
|
+
};
|
|
384
|
+
walk(root);
|
|
381
385
|
}
|
|
382
|
-
function
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (resource === undefined || !resource.endsWith(SCRIPT_SUFFIX))
|
|
387
|
-
continue;
|
|
388
|
-
const key = resourceKey(resource);
|
|
389
|
-
if (key !== SCRIPT_SUFFIX.slice(1))
|
|
390
|
-
resources.push(key);
|
|
386
|
+
function resolveReferencedSymbol(node, checker) {
|
|
387
|
+
const parent = node.parent;
|
|
388
|
+
if (parent !== undefined && ts3.isShorthandPropertyAssignment(parent) && parent.name === node) {
|
|
389
|
+
return checker.getShorthandAssignmentValueSymbol(parent) ?? checker.getSymbolAtLocation(node);
|
|
391
390
|
}
|
|
392
|
-
return
|
|
393
|
-
}
|
|
394
|
-
function isGameObject(message) {
|
|
395
|
-
return message.messages.has("components") || message.messages.has("embedded_components");
|
|
391
|
+
return checker.getSymbolAtLocation(node);
|
|
396
392
|
}
|
|
397
|
-
function
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const claimedBy = new Map;
|
|
403
|
-
function walk(message, blockName, displayPath) {
|
|
404
|
-
if (isGameObject(message)) {
|
|
405
|
-
claim(message, displayPath);
|
|
393
|
+
function forEachAssignmentTarget(root, checker, visit) {
|
|
394
|
+
const classify = (target) => {
|
|
395
|
+
if (ts3.isParenthesizedExpression(target)) {
|
|
396
|
+
classify(target.expression);
|
|
397
|
+
return;
|
|
406
398
|
}
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
399
|
+
if (ts3.isPropertyAccessExpression(target) || ts3.isElementAccessExpression(target)) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (ts3.isArrayLiteralExpression(target)) {
|
|
403
|
+
for (const element of target.elements) {
|
|
404
|
+
if (ts3.isOmittedExpression(element)) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
if (ts3.isSpreadElement(element)) {
|
|
408
|
+
classify(element.expression);
|
|
409
|
+
} else if (ts3.isBinaryExpression(element) && element.operatorToken.kind === ts3.SyntaxKind.EqualsToken) {
|
|
410
|
+
classify(element.left);
|
|
411
|
+
} else {
|
|
412
|
+
classify(element);
|
|
415
413
|
}
|
|
416
414
|
}
|
|
415
|
+
return;
|
|
417
416
|
}
|
|
418
|
-
|
|
419
|
-
for (const
|
|
420
|
-
|
|
417
|
+
if (ts3.isObjectLiteralExpression(target)) {
|
|
418
|
+
for (const property of target.properties) {
|
|
419
|
+
if (ts3.isPropertyAssignment(property)) {
|
|
420
|
+
classify(property.initializer);
|
|
421
|
+
} else if (ts3.isSpreadAssignment(property)) {
|
|
422
|
+
classify(property.expression);
|
|
423
|
+
} else if (ts3.isShorthandPropertyAssignment(property)) {
|
|
424
|
+
const symbol = checker.getShorthandAssignmentValueSymbol(property);
|
|
425
|
+
if (symbol !== undefined) {
|
|
426
|
+
visit(property.name, symbol);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
421
429
|
}
|
|
430
|
+
return;
|
|
422
431
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
432
|
+
if (ts3.isIdentifier(target)) {
|
|
433
|
+
const symbol = checker.getSymbolAtLocation(target);
|
|
434
|
+
if (symbol !== undefined) {
|
|
435
|
+
visit(target, symbol);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
const walk = (node) => {
|
|
440
|
+
if (ts3.isBinaryExpression(node) && isAssignmentOperator(node.operatorToken.kind)) {
|
|
441
|
+
classify(node.left);
|
|
442
|
+
} else if ((ts3.isPrefixUnaryExpression(node) || ts3.isPostfixUnaryExpression(node)) && (node.operator === ts3.SyntaxKind.PlusPlusToken || node.operator === ts3.SyntaxKind.MinusMinusToken)) {
|
|
443
|
+
classify(node.operand);
|
|
444
|
+
} else if ((ts3.isForInStatement(node) || ts3.isForOfStatement(node)) && !ts3.isVariableDeclarationList(node.initializer)) {
|
|
445
|
+
classify(node.initializer);
|
|
446
|
+
}
|
|
447
|
+
ts3.forEachChild(node, walk);
|
|
448
|
+
};
|
|
449
|
+
walk(root);
|
|
450
|
+
}
|
|
451
|
+
function collectTopLevel(sourceFile, checker) {
|
|
452
|
+
const declarations = new Map;
|
|
453
|
+
let order = 0;
|
|
454
|
+
const add = (name, statement, node) => {
|
|
455
|
+
if (name === undefined || !ts3.isIdentifier(name)) {
|
|
430
456
|
return;
|
|
431
457
|
}
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
stack: new Set,
|
|
436
|
-
assets,
|
|
437
|
-
unresolved
|
|
438
|
-
});
|
|
439
|
-
if (resolved !== undefined)
|
|
440
|
-
return resolved;
|
|
441
|
-
if (!assets.entriesByAnimationSet.has(source.path)) {
|
|
442
|
-
unresolved.push(`${displayPath}: the model component "${id}" names the animation set /${source.path}, which is not among the project's asset documents`);
|
|
458
|
+
const symbol = checker.getSymbolAtLocation(name);
|
|
459
|
+
if (symbol === undefined || declarations.has(symbol)) {
|
|
460
|
+
return;
|
|
443
461
|
}
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
462
|
+
declarations.set(symbol, { name: name.text, statement, node, order: order++ });
|
|
463
|
+
};
|
|
464
|
+
const addBinding = (name, statement, node) => {
|
|
465
|
+
if (ts3.isIdentifier(name)) {
|
|
466
|
+
add(name, statement, node);
|
|
449
467
|
return;
|
|
450
|
-
const sources = componentAnimationSources(object, displayPath, assets, unresolved);
|
|
451
|
-
const animations = new Map;
|
|
452
|
-
const declaringSources = new Map;
|
|
453
|
-
for (const [id, source] of sources) {
|
|
454
|
-
const resolved = idsOf(id, source, displayPath);
|
|
455
|
-
if (resolved === undefined)
|
|
456
|
-
continue;
|
|
457
|
-
animations.set(id, new Set(resolved.keys()));
|
|
458
|
-
declaringSources.set(id, resolved);
|
|
459
468
|
}
|
|
460
|
-
for (const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
byScriptResource.delete(key);
|
|
464
|
-
sourceByScriptResource.delete(key);
|
|
465
|
-
unresolved.push(`${key}: claimed by both ${owner} and ${displayPath}, so its component animations are ambiguous`);
|
|
466
|
-
continue;
|
|
469
|
+
for (const element of name.elements) {
|
|
470
|
+
if (ts3.isBindingElement(element)) {
|
|
471
|
+
addBinding(element.name, statement, node);
|
|
467
472
|
}
|
|
468
|
-
claimedBy.set(key, displayPath);
|
|
469
|
-
byScriptResource.set(key, animations);
|
|
470
|
-
sourceByScriptResource.set(key, declaringSources);
|
|
471
473
|
}
|
|
472
|
-
}
|
|
473
|
-
for (const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
474
|
+
};
|
|
475
|
+
for (const statement of sourceFile.statements) {
|
|
476
|
+
if (ts3.isVariableStatement(statement)) {
|
|
477
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
478
|
+
addBinding(declaration.name, statement, declaration);
|
|
479
|
+
}
|
|
480
|
+
} else if (ts3.isFunctionDeclaration(statement) || ts3.isClassDeclaration(statement) || ts3.isEnumDeclaration(statement)) {
|
|
481
|
+
add(statement.name, statement, statement);
|
|
482
|
+
} else if (ts3.isImportDeclaration(statement)) {
|
|
483
|
+
const clause = statement.importClause;
|
|
484
|
+
if (clause === undefined) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
add(clause.name, statement, statement);
|
|
488
|
+
const bindings = clause.namedBindings;
|
|
489
|
+
if (bindings === undefined) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
if (ts3.isNamespaceImport(bindings)) {
|
|
493
|
+
add(bindings.name, statement, statement);
|
|
494
|
+
} else {
|
|
495
|
+
for (const element of bindings.elements) {
|
|
496
|
+
add(element.name, statement, statement);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
481
499
|
}
|
|
482
500
|
}
|
|
483
|
-
return
|
|
501
|
+
return declarations;
|
|
484
502
|
}
|
|
485
|
-
function
|
|
486
|
-
|
|
487
|
-
return;
|
|
488
|
-
const id = address.slice(1);
|
|
489
|
-
if (id === "" || id.includes("/") || id.includes("#"))
|
|
490
|
-
return;
|
|
491
|
-
return id;
|
|
503
|
+
function hasExportModifier(statement) {
|
|
504
|
+
return ts3.canHaveModifiers(statement) && (ts3.getModifiers(statement) ?? []).some((modifier) => modifier.kind === ts3.SyntaxKind.ExportKeyword);
|
|
492
505
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
506
|
+
function isValueSymbol(symbol, checker) {
|
|
507
|
+
if (symbol === undefined) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
const resolved = symbol.flags & ts3.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
511
|
+
return (resolved.flags & ts3.SymbolFlags.Value) !== 0;
|
|
497
512
|
}
|
|
498
|
-
function
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
section = header;
|
|
506
|
-
continue;
|
|
513
|
+
function collectExports(sourceFile, checker, topLevel) {
|
|
514
|
+
const exported = [];
|
|
515
|
+
const seen = new Set;
|
|
516
|
+
const take = (symbol, name, nameNode) => {
|
|
517
|
+
const declaration = symbol && topLevel.get(symbol);
|
|
518
|
+
if (symbol === undefined || declaration === undefined) {
|
|
519
|
+
return;
|
|
507
520
|
}
|
|
508
|
-
if (
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
521
|
+
if (!isValueSymbol(symbol, checker)) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const key = `${declaration.order}\x00${name}`;
|
|
525
|
+
if (seen.has(key)) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
seen.add(key);
|
|
529
|
+
exported.push({ symbol, name, nameNode });
|
|
530
|
+
};
|
|
531
|
+
const takeLocal = (symbol, name) => {
|
|
532
|
+
const declaration = symbol && topLevel.get(symbol);
|
|
533
|
+
if (declaration === undefined) {
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
take(symbol, name.text, declaration.node);
|
|
537
|
+
};
|
|
538
|
+
for (const statement of sourceFile.statements) {
|
|
539
|
+
if (ts3.isExportDeclaration(statement)) {
|
|
540
|
+
if (statement.moduleSpecifier !== undefined || statement.isTypeOnly) {
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
const clause = statement.exportClause;
|
|
544
|
+
if (clause === undefined || !ts3.isNamedExports(clause)) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
for (const element of clause.elements) {
|
|
548
|
+
if (element.isTypeOnly) {
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
take(checker.getExportSpecifierLocalTargetSymbol(element), element.name.text, element.name);
|
|
552
|
+
}
|
|
512
553
|
continue;
|
|
513
|
-
|
|
514
|
-
if (
|
|
554
|
+
}
|
|
555
|
+
if (!hasExportModifier(statement)) {
|
|
515
556
|
continue;
|
|
516
|
-
|
|
557
|
+
}
|
|
558
|
+
if (ts3.isVariableStatement(statement)) {
|
|
559
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
560
|
+
forEachDeclaredName(declaration.name, (name) => takeLocal(checker.getSymbolAtLocation(name), name));
|
|
561
|
+
}
|
|
562
|
+
} else if (ts3.isFunctionDeclaration(statement) || ts3.isClassDeclaration(statement) || ts3.isEnumDeclaration(statement)) {
|
|
563
|
+
if (statement.name !== undefined) {
|
|
564
|
+
takeLocal(checker.getSymbolAtLocation(statement.name), statement.name);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
517
567
|
}
|
|
518
|
-
return
|
|
568
|
+
return exported;
|
|
519
569
|
}
|
|
520
|
-
function
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
570
|
+
function forEachDeclaredName(name, visit) {
|
|
571
|
+
if (ts3.isIdentifier(name)) {
|
|
572
|
+
visit(name);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
for (const element of name.elements) {
|
|
576
|
+
if (ts3.isBindingElement(element)) {
|
|
577
|
+
forEachDeclaredName(element.name, visit);
|
|
528
578
|
}
|
|
529
|
-
if (current !== section)
|
|
530
|
-
continue;
|
|
531
|
-
const separator = line.indexOf("=");
|
|
532
|
-
if (separator === -1)
|
|
533
|
-
continue;
|
|
534
|
-
if (line.slice(0, separator).trim() !== key)
|
|
535
|
-
continue;
|
|
536
|
-
const value = line.slice(separator + 1).trim();
|
|
537
|
-
if (value !== "")
|
|
538
|
-
return value;
|
|
539
579
|
}
|
|
540
|
-
return;
|
|
541
580
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
function scriptKeyOf(script) {
|
|
545
|
-
if (!script.endsWith(SCRIPT_SUFFIX2))
|
|
546
|
-
return;
|
|
547
|
-
const key = resourceKey(script);
|
|
548
|
-
return key === SCRIPT_SUFFIX2 ? undefined : key;
|
|
581
|
+
function isLifecycleFactoryCall(expression, checker) {
|
|
582
|
+
return ts3.isCallExpression(expression) && resolvesToFactoryExport(expression.expression, checker);
|
|
549
583
|
}
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
584
|
+
function isEffectFreeExpression(expression) {
|
|
585
|
+
if (expression === undefined) {
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
if (ts3.isParenthesizedExpression(expression) || ts3.isAsExpression(expression) || ts3.isTypeAssertionExpression(expression) || ts3.isNonNullExpression(expression)) {
|
|
589
|
+
return isEffectFreeExpression(expression.expression);
|
|
590
|
+
}
|
|
591
|
+
if (ts3.isIdentifier(expression) || ts3.isLiteralExpression(expression)) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
switch (expression.kind) {
|
|
595
|
+
case ts3.SyntaxKind.TrueKeyword:
|
|
596
|
+
case ts3.SyntaxKind.FalseKeyword:
|
|
597
|
+
case ts3.SyntaxKind.NullKeyword:
|
|
598
|
+
case ts3.SyntaxKind.ThisKeyword:
|
|
599
|
+
return true;
|
|
600
|
+
default:
|
|
601
|
+
break;
|
|
602
|
+
}
|
|
603
|
+
if (ts3.isFunctionExpression(expression) || ts3.isArrowFunction(expression)) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
if (ts3.isPrefixUnaryExpression(expression)) {
|
|
607
|
+
return expression.operator !== ts3.SyntaxKind.PlusPlusToken && expression.operator !== ts3.SyntaxKind.MinusMinusToken && isEffectFreeExpression(expression.operand);
|
|
608
|
+
}
|
|
609
|
+
if (ts3.isBinaryExpression(expression)) {
|
|
610
|
+
return !isAssignmentOperator(expression.operatorToken.kind) && isEffectFreeExpression(expression.left) && isEffectFreeExpression(expression.right);
|
|
611
|
+
}
|
|
612
|
+
if (ts3.isConditionalExpression(expression)) {
|
|
613
|
+
return isEffectFreeExpression(expression.condition) && isEffectFreeExpression(expression.whenTrue) && isEffectFreeExpression(expression.whenFalse);
|
|
614
|
+
}
|
|
615
|
+
if (ts3.isArrayLiteralExpression(expression)) {
|
|
616
|
+
return expression.elements.every(isEffectFreeExpression);
|
|
617
|
+
}
|
|
618
|
+
if (ts3.isObjectLiteralExpression(expression)) {
|
|
619
|
+
return expression.properties.every((property) => {
|
|
620
|
+
if (ts3.isPropertyAssignment(property)) {
|
|
621
|
+
return isEffectFreeExpression(property.initializer);
|
|
622
|
+
}
|
|
623
|
+
return ts3.isShorthandPropertyAssignment(property) || ts3.isMethodDeclaration(property);
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
function isEffectFreeStatement(statement, checker) {
|
|
629
|
+
if (ts3.isImportDeclaration(statement) || ts3.isInterfaceDeclaration(statement) || ts3.isTypeAliasDeclaration(statement) || ts3.isFunctionDeclaration(statement) || ts3.isExportDeclaration(statement)) {
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
if (ts3.isVariableStatement(statement)) {
|
|
633
|
+
return statement.declarationList.declarations.every((declaration) => isEffectFreeExpression(declaration.initializer));
|
|
634
|
+
}
|
|
635
|
+
if (ts3.isExpressionStatement(statement)) {
|
|
636
|
+
return isLifecycleFactoryCall(statement.expression, checker) || isEffectFreeExpression(statement.expression);
|
|
637
|
+
}
|
|
638
|
+
if (ts3.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
639
|
+
return isLifecycleFactoryCall(statement.expression, checker) || isEffectFreeExpression(statement.expression);
|
|
640
|
+
}
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
function siteOf(node, role) {
|
|
644
|
+
const sourceFile = node.getSourceFile();
|
|
645
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
646
|
+
return { role, line: line + 1, column: character + 1 };
|
|
647
|
+
}
|
|
648
|
+
function formatSites(sites) {
|
|
649
|
+
return sites.map((site) => `${site.role} at ${site.line}:${site.column}`).join(", ");
|
|
650
|
+
}
|
|
651
|
+
function bySourcePosition(a, b) {
|
|
652
|
+
return a.line === b.line ? a.column - b.column : a.line - b.line;
|
|
653
|
+
}
|
|
654
|
+
function computeCompanionClosure(sourceFile, checker) {
|
|
655
|
+
const topLevel = collectTopLevel(sourceFile, checker);
|
|
656
|
+
const exportEntries = collectExports(sourceFile, checker, topLevel);
|
|
657
|
+
const siblingsOf = new Map;
|
|
658
|
+
for (const [symbol, declaration] of topLevel) {
|
|
659
|
+
siblingsOf.set(declaration.statement, [
|
|
660
|
+
...siblingsOf.get(declaration.statement) ?? [],
|
|
661
|
+
symbol
|
|
662
|
+
]);
|
|
663
|
+
}
|
|
664
|
+
const memberSymbols = new Set;
|
|
665
|
+
const importBindingSymbols = new Set;
|
|
666
|
+
const closureStatements = new Set;
|
|
667
|
+
const queue = exportEntries.map((entry) => entry.symbol);
|
|
668
|
+
while (queue.length > 0) {
|
|
669
|
+
const symbol = queue.pop();
|
|
670
|
+
if (symbol === undefined || memberSymbols.has(symbol)) {
|
|
564
671
|
continue;
|
|
565
672
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
const key = scriptKeyOf(script);
|
|
570
|
-
if (key === undefined)
|
|
673
|
+
memberSymbols.add(symbol);
|
|
674
|
+
const declaration = topLevel.get(symbol);
|
|
675
|
+
if (declaration === undefined) {
|
|
571
676
|
continue;
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
|
|
575
|
-
unresolved.push(`${key}: claimed by both ${owner} and ${displayPath}, so its flipbook animations are ambiguous`);
|
|
677
|
+
}
|
|
678
|
+
if (ts3.isImportDeclaration(declaration.statement)) {
|
|
679
|
+
importBindingSymbols.add(symbol);
|
|
576
680
|
continue;
|
|
577
681
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
continue;
|
|
584
|
-
const source = resourceKey(texture);
|
|
585
|
-
const ids = animationsBySource.get(source);
|
|
586
|
-
if (ids === undefined) {
|
|
587
|
-
unresolved.push(`${displayPath}: the texture ${texture} is not among the project's asset documents`);
|
|
588
|
-
continue;
|
|
589
|
-
}
|
|
590
|
-
for (const id of ids) {
|
|
591
|
-
const declarers = declaredBy.get(id);
|
|
592
|
-
if (declarers) {
|
|
593
|
-
declarers.add(source);
|
|
594
|
-
} else {
|
|
595
|
-
declaredBy.set(id, new Set([source]));
|
|
596
|
-
}
|
|
682
|
+
if (!closureStatements.has(declaration.statement)) {
|
|
683
|
+
closureStatements.add(declaration.statement);
|
|
684
|
+
for (const sibling of siblingsOf.get(declaration.statement) ?? []) {
|
|
685
|
+
if (!memberSymbols.has(sibling)) {
|
|
686
|
+
queue.push(sibling);
|
|
597
687
|
}
|
|
598
688
|
}
|
|
599
689
|
}
|
|
600
|
-
|
|
690
|
+
forEachReference(declaration.node, checker, (_node, referenced) => {
|
|
691
|
+
if (topLevel.has(referenced) && !memberSymbols.has(referenced)) {
|
|
692
|
+
queue.push(referenced);
|
|
693
|
+
}
|
|
694
|
+
});
|
|
601
695
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
var SCRIPT_SUFFIX3 = ".gui_script";
|
|
606
|
-
function scriptKeyOf2(script) {
|
|
607
|
-
if (!script.endsWith(SCRIPT_SUFFIX3))
|
|
608
|
-
return;
|
|
609
|
-
const key = script.startsWith("/") ? script.slice(1) : script;
|
|
610
|
-
return key === SCRIPT_SUFFIX3 ? undefined : key;
|
|
611
|
-
}
|
|
612
|
-
function guiScriptResourceOf(document) {
|
|
613
|
-
const [script] = document.fields.get("script") ?? [];
|
|
614
|
-
return script === undefined ? undefined : scriptKeyOf2(script);
|
|
615
|
-
}
|
|
616
|
-
function guiScriptResourcesOf(documents) {
|
|
617
|
-
const scripts = new Map;
|
|
618
|
-
for (const [displayPath, text] of documents) {
|
|
619
|
-
let resource;
|
|
620
|
-
try {
|
|
621
|
-
resource = guiScriptResourceOf(parseSceneTextFormat(text));
|
|
622
|
-
} catch (error) {
|
|
623
|
-
if (!(error instanceof SceneTextFormatError))
|
|
624
|
-
throw error;
|
|
696
|
+
const splits = closureStatements.size > 0;
|
|
697
|
+
for (const statement of sourceFile.statements) {
|
|
698
|
+
if (!ts3.isExportDeclaration(statement) || statement.isTypeOnly) {
|
|
625
699
|
continue;
|
|
626
700
|
}
|
|
627
|
-
if (
|
|
628
|
-
|
|
701
|
+
if (statement.moduleSpecifier !== undefined) {
|
|
702
|
+
if (splits) {
|
|
703
|
+
closureStatements.add(statement);
|
|
704
|
+
}
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
const clause = statement.exportClause;
|
|
708
|
+
if (clause === undefined || !ts3.isNamedExports(clause)) {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
const readsMember = clause.elements.some((element) => {
|
|
712
|
+
if (element.isTypeOnly) {
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
const local = checker.getExportSpecifierLocalTargetSymbol(element);
|
|
716
|
+
return local !== undefined && memberSymbols.has(local);
|
|
717
|
+
});
|
|
718
|
+
if (readsMember) {
|
|
719
|
+
closureStatements.add(statement);
|
|
720
|
+
}
|
|
629
721
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
} catch (error) {
|
|
641
|
-
if (!(error instanceof SceneTextFormatError))
|
|
642
|
-
throw error;
|
|
643
|
-
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
722
|
+
const mutations = new Map;
|
|
723
|
+
forEachAssignmentTarget(sourceFile, checker, (node, symbol) => {
|
|
724
|
+
if (!memberSymbols.has(symbol)) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
mutations.set(symbol, [...mutations.get(symbol) ?? [], node]);
|
|
728
|
+
});
|
|
729
|
+
const scriptReferences = new Map;
|
|
730
|
+
for (const statement of sourceFile.statements) {
|
|
731
|
+
if (closureStatements.has(statement) || ts3.isExportDeclaration(statement)) {
|
|
644
732
|
continue;
|
|
645
733
|
}
|
|
646
|
-
|
|
647
|
-
|
|
734
|
+
forEachReference(statement, checker, (node, symbol) => {
|
|
735
|
+
if (memberSymbols.has(symbol)) {
|
|
736
|
+
scriptReferences.set(symbol, [...scriptReferences.get(symbol) ?? [], node]);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
const ordered = [...memberSymbols].flatMap((symbol) => {
|
|
741
|
+
const declaration = topLevel.get(symbol);
|
|
742
|
+
return declaration === undefined ? [] : [{ symbol, declaration }];
|
|
743
|
+
}).sort((a, b) => a.declaration.order - b.declaration.order);
|
|
744
|
+
const exportSet = new Set(exportEntries.map((entry) => entry.symbol));
|
|
745
|
+
const violations = [];
|
|
746
|
+
for (const { symbol, declaration } of ordered) {
|
|
747
|
+
const mutated = mutations.get(symbol);
|
|
748
|
+
const referenced = scriptReferences.get(symbol);
|
|
749
|
+
if (mutated === undefined || referenced === undefined) {
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
const sites = [
|
|
753
|
+
...mutated.map((node) => siteOf(node, "reassigned")),
|
|
754
|
+
...referenced.map((node) => siteOf(node, "read by the script"))
|
|
755
|
+
].filter((site, index, all) => all.findIndex((other) => other.line === site.line && other.column === site.column) === index).sort(bySourcePosition);
|
|
756
|
+
violations.push({
|
|
757
|
+
kind: "shared-mutable",
|
|
758
|
+
member: declaration.name,
|
|
759
|
+
sites,
|
|
760
|
+
message: `"${declaration.name}" is reassigned and is also used outside the companion, ` + `so the script's copy would never see the update (${formatSites(sites)}). ` + "Move that state into a source with no lifecycle factory."
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
for (const entry of exportEntries) {
|
|
764
|
+
if (entry.name !== COMPANION_INTERNAL_FIELD) {
|
|
648
765
|
continue;
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
766
|
+
}
|
|
767
|
+
const sites = [siteOf(entry.nameNode, "exported")];
|
|
768
|
+
violations.push({
|
|
769
|
+
kind: "reserved-internal-name",
|
|
770
|
+
member: entry.name,
|
|
771
|
+
sites,
|
|
772
|
+
message: `"${COMPANION_INTERNAL_FIELD}" is reserved for the companion's own internals ` + `and cannot be exported (${formatSites(sites)}). Rename the export.`
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
for (const statement of sourceFile.statements) {
|
|
776
|
+
if (closureStatements.has(statement) || isEffectFreeStatement(statement, checker)) {
|
|
653
777
|
continue;
|
|
654
778
|
}
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
779
|
+
const start = statement.getStart(sourceFile);
|
|
780
|
+
const hoisted = ordered.find((entry) => entry.declaration.statement.getStart(sourceFile) > start);
|
|
781
|
+
if (hoisted === undefined) {
|
|
782
|
+
continue;
|
|
783
|
+
}
|
|
784
|
+
const sites = [
|
|
785
|
+
siteOf(statement, "runs in the script"),
|
|
786
|
+
siteOf(hoisted.declaration.node, "moves into the companion")
|
|
787
|
+
];
|
|
788
|
+
violations.push({
|
|
789
|
+
kind: "initialization-order",
|
|
790
|
+
member: hoisted.declaration.name,
|
|
791
|
+
sites,
|
|
792
|
+
message: `top-level work precedes "${hoisted.declaration.name}", which the companion would run first, ` + `reversing their order (${formatSites(sites)}). ` + "Move that work below the companion's declarations, or into a lifecycle hook."
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
return {
|
|
796
|
+
members: ordered.map(({ declaration }) => declaration.name),
|
|
797
|
+
exports: exportEntries.map((entry) => entry.name),
|
|
798
|
+
statements: sourceFile.statements.filter((statement) => closureStatements.has(statement)),
|
|
799
|
+
importBindings: ordered.filter(({ symbol }) => importBindingSymbols.has(symbol)).map(({ declaration }) => declaration.name),
|
|
800
|
+
internals: ordered.filter(({ symbol }) => !exportSet.has(symbol) && scriptReferences.has(symbol)).map(({ declaration }) => declaration.name),
|
|
801
|
+
violations
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
// src/scene-text-format.ts
|
|
805
|
+
class SceneTextFormatError extends Error {
|
|
806
|
+
line;
|
|
807
|
+
constructor(message, line) {
|
|
808
|
+
super(`${message} (line ${line})`);
|
|
809
|
+
this.name = "SceneTextFormatError";
|
|
810
|
+
this.line = line;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
var IDENTIFIER_PART = /[A-Za-z0-9_]/;
|
|
814
|
+
function append(target, key, value) {
|
|
815
|
+
const existing = target.get(key);
|
|
816
|
+
if (existing === undefined) {
|
|
817
|
+
target.set(key, [value]);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
existing.push(value);
|
|
821
|
+
}
|
|
822
|
+
function parseSceneTextFormat(text) {
|
|
823
|
+
let pos = 0;
|
|
824
|
+
let line = 1;
|
|
825
|
+
function fail(message, at) {
|
|
826
|
+
throw new SceneTextFormatError(message, at);
|
|
827
|
+
}
|
|
828
|
+
function advance() {
|
|
829
|
+
const ch = text.charAt(pos);
|
|
830
|
+
pos += 1;
|
|
831
|
+
if (ch === `
|
|
832
|
+
`)
|
|
833
|
+
line += 1;
|
|
834
|
+
return ch;
|
|
835
|
+
}
|
|
836
|
+
function skipWhitespace() {
|
|
837
|
+
while (pos < text.length) {
|
|
838
|
+
const ch = text.charAt(pos);
|
|
839
|
+
if (ch !== " " && ch !== "\t" && ch !== "\r" && ch !== `
|
|
840
|
+
`)
|
|
841
|
+
return;
|
|
842
|
+
advance();
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
function skipInlineWhitespace() {
|
|
846
|
+
while (pos < text.length) {
|
|
847
|
+
const ch = text.charAt(pos);
|
|
848
|
+
if (ch !== " " && ch !== "\t")
|
|
849
|
+
return;
|
|
850
|
+
pos += 1;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function readIdentifier(at) {
|
|
854
|
+
const start = pos;
|
|
855
|
+
while (pos < text.length && IDENTIFIER_PART.test(text.charAt(pos))) {
|
|
856
|
+
pos += 1;
|
|
857
|
+
}
|
|
858
|
+
if (pos === start) {
|
|
859
|
+
fail(`unexpected \`${text.charAt(start)}\``, at);
|
|
860
|
+
}
|
|
861
|
+
return text.slice(start, pos);
|
|
862
|
+
}
|
|
863
|
+
function readQuotedScalar() {
|
|
864
|
+
let value = "";
|
|
865
|
+
for (;; ) {
|
|
866
|
+
const openedAt = line;
|
|
867
|
+
advance();
|
|
868
|
+
let closed = false;
|
|
869
|
+
while (pos < text.length) {
|
|
870
|
+
const ch = advance();
|
|
871
|
+
if (ch === "\\") {
|
|
872
|
+
if (pos >= text.length)
|
|
873
|
+
break;
|
|
874
|
+
const escaped = advance();
|
|
875
|
+
if (escaped === '"')
|
|
876
|
+
value += '"';
|
|
877
|
+
else if (escaped === "\\")
|
|
878
|
+
value += "\\";
|
|
879
|
+
else if (escaped === "n")
|
|
880
|
+
value += `
|
|
881
|
+
`;
|
|
882
|
+
else if (escaped === "r")
|
|
883
|
+
value += "\r";
|
|
884
|
+
else if (escaped === "t")
|
|
885
|
+
value += "\t";
|
|
886
|
+
else
|
|
887
|
+
value += `\\${escaped}`;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
if (ch === '"') {
|
|
891
|
+
closed = true;
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
if (ch === `
|
|
895
|
+
`)
|
|
896
|
+
break;
|
|
897
|
+
value += ch;
|
|
898
|
+
}
|
|
899
|
+
if (!closed) {
|
|
900
|
+
fail("unterminated string literal", openedAt);
|
|
901
|
+
}
|
|
902
|
+
const resumePos = pos;
|
|
903
|
+
const resumeLine = line;
|
|
904
|
+
skipWhitespace();
|
|
905
|
+
if (text.charAt(pos) === '"') {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
pos = resumePos;
|
|
909
|
+
line = resumeLine;
|
|
910
|
+
return value;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
function readUnquotedScalar() {
|
|
914
|
+
const newline = text.indexOf(`
|
|
915
|
+
`, pos);
|
|
916
|
+
const end = newline === -1 ? text.length : newline;
|
|
917
|
+
const raw = text.slice(pos, end);
|
|
918
|
+
pos = end;
|
|
919
|
+
return raw.trim();
|
|
920
|
+
}
|
|
921
|
+
function parseBody(nested, openedAt) {
|
|
922
|
+
const fields = new Map;
|
|
923
|
+
const messages = new Map;
|
|
924
|
+
for (;; ) {
|
|
925
|
+
skipWhitespace();
|
|
926
|
+
if (pos >= text.length) {
|
|
927
|
+
if (nested) {
|
|
928
|
+
fail("unclosed `{`", openedAt);
|
|
929
|
+
}
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
if (text.charAt(pos) === "}") {
|
|
933
|
+
if (!nested) {
|
|
934
|
+
fail("unexpected `}`", line);
|
|
935
|
+
}
|
|
936
|
+
advance();
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
const keyLine = line;
|
|
940
|
+
const key = readIdentifier(keyLine);
|
|
941
|
+
skipInlineWhitespace();
|
|
942
|
+
const delimiter = text.charAt(pos);
|
|
943
|
+
if (delimiter === "{") {
|
|
944
|
+
const braceLine = line;
|
|
945
|
+
advance();
|
|
946
|
+
append(messages, key, parseBody(true, braceLine));
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
if (delimiter === ":") {
|
|
950
|
+
advance();
|
|
951
|
+
skipInlineWhitespace();
|
|
952
|
+
append(fields, key, text.charAt(pos) === '"' ? readQuotedScalar() : readUnquotedScalar());
|
|
953
|
+
continue;
|
|
661
954
|
}
|
|
955
|
+
fail(`expected \`:\` or \`{\` after \`${key}\``, keyLine);
|
|
956
|
+
}
|
|
957
|
+
return { fields, messages };
|
|
958
|
+
}
|
|
959
|
+
return parseBody(false, 1);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/animation-sources.ts
|
|
963
|
+
function resourceKey(resource) {
|
|
964
|
+
return resource.startsWith("/") ? resource.slice(1) : resource;
|
|
965
|
+
}
|
|
966
|
+
function normalizeDocumentKey(path) {
|
|
967
|
+
return path.replaceAll("\\", "/");
|
|
968
|
+
}
|
|
969
|
+
var SPRITE_SUFFIX = ".sprite";
|
|
970
|
+
var MODEL_SUFFIX = ".model";
|
|
971
|
+
var ANIMATION_SET_SUFFIX = ".animationset";
|
|
972
|
+
var HOP_ONLY_SUFFIXES = [SPRITE_SUFFIX, MODEL_SUFFIX, ANIMATION_SET_SUFFIX];
|
|
973
|
+
function childrenOf(message, name) {
|
|
974
|
+
return message.messages.get(name) ?? [];
|
|
975
|
+
}
|
|
976
|
+
function declaredAnimations(document) {
|
|
977
|
+
const ids = new Set;
|
|
978
|
+
for (const animation of childrenOf(document, "animations")) {
|
|
979
|
+
for (const id of animation.fields.get("id") ?? []) {
|
|
980
|
+
if (id !== "")
|
|
981
|
+
ids.add(id);
|
|
662
982
|
}
|
|
663
|
-
byScriptResource.set(key, ids);
|
|
664
983
|
}
|
|
665
|
-
return
|
|
984
|
+
return ids;
|
|
666
985
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
const
|
|
670
|
-
|
|
986
|
+
function readAnimationSources(assets, unresolved) {
|
|
987
|
+
const animationsByTileSet = new Map;
|
|
988
|
+
for (const [path, text] of assets) {
|
|
989
|
+
const displayPath = normalizeDocumentKey(path);
|
|
990
|
+
if (HOP_ONLY_SUFFIXES.some((suffix) => displayPath.endsWith(suffix)))
|
|
991
|
+
continue;
|
|
671
992
|
let document;
|
|
672
993
|
try {
|
|
673
994
|
document = parseSceneTextFormat(text);
|
|
674
995
|
} catch (error) {
|
|
675
996
|
if (!(error instanceof SceneTextFormatError))
|
|
676
997
|
throw error;
|
|
998
|
+
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
677
999
|
continue;
|
|
678
1000
|
}
|
|
679
|
-
|
|
680
|
-
for (const trigger of triggers) {
|
|
681
|
-
for (const action of trigger.fields.get("action") ?? []) {
|
|
682
|
-
if (action !== "")
|
|
683
|
-
actions.add(action);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
1001
|
+
animationsByTileSet.set(displayPath, declaredAnimations(document));
|
|
687
1002
|
}
|
|
688
|
-
return
|
|
1003
|
+
return animationsByTileSet;
|
|
689
1004
|
}
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
1005
|
+
function animationSetEntries(document) {
|
|
1006
|
+
const entries = [];
|
|
1007
|
+
for (const entry of childrenOf(document, "animations")) {
|
|
1008
|
+
for (const animation of entry.fields.get("animation") ?? []) {
|
|
1009
|
+
if (animation !== "")
|
|
1010
|
+
entries.push(animation);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return entries;
|
|
695
1014
|
}
|
|
696
1015
|
|
|
697
|
-
// src/
|
|
698
|
-
var
|
|
699
|
-
var
|
|
700
|
-
var
|
|
701
|
-
var
|
|
702
|
-
var
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
".sprite",
|
|
706
|
-
".model",
|
|
707
|
-
".animationset"
|
|
708
|
-
];
|
|
709
|
-
var LIBRARY_SCENE_EXTENSIONS = [
|
|
710
|
-
...SCENE_EXTENSIONS,
|
|
711
|
-
...GUI_EXTENSIONS,
|
|
712
|
-
...ANIMATION_ASSET_EXTENSIONS,
|
|
713
|
-
...COLLECTION_REFERENCE_EXTENSIONS
|
|
714
|
-
];
|
|
715
|
-
var PROJECT_EXTENSIONS = [".project"];
|
|
716
|
-
var GAME_PROJECT_DOCUMENT = "game.project";
|
|
717
|
-
function displayPathOf(projectRoot, filePath) {
|
|
718
|
-
const path = filePath.replace(/\\/g, "/");
|
|
719
|
-
const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
720
|
-
return path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
|
|
1016
|
+
// src/component-animation-index.ts
|
|
1017
|
+
var SCRIPT_SUFFIX = ".script";
|
|
1018
|
+
var SPRITE_SUFFIX2 = ".sprite";
|
|
1019
|
+
var MODEL_SUFFIX2 = ".model";
|
|
1020
|
+
var ANIMATION_SET_SUFFIX2 = ".animationset";
|
|
1021
|
+
var MESH_SUFFIXES = [".gltf", ".glb"];
|
|
1022
|
+
function firstField(message, name) {
|
|
1023
|
+
return (message.fields.get(name) ?? [])[0];
|
|
721
1024
|
}
|
|
722
|
-
function
|
|
723
|
-
return
|
|
1025
|
+
function childrenOf2(message, name) {
|
|
1026
|
+
return message.messages.get(name) ?? [];
|
|
724
1027
|
}
|
|
725
|
-
function
|
|
726
|
-
|
|
1028
|
+
function basename(resource) {
|
|
1029
|
+
const file = resource.slice(resource.lastIndexOf("/") + 1);
|
|
1030
|
+
const dot = file.lastIndexOf(".");
|
|
1031
|
+
return dot === -1 ? file : file.slice(0, dot);
|
|
727
1032
|
}
|
|
728
|
-
function
|
|
729
|
-
const
|
|
730
|
-
const
|
|
731
|
-
const
|
|
732
|
-
const
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const
|
|
739
|
-
if (
|
|
1033
|
+
function readAssets(assets, unresolved) {
|
|
1034
|
+
const animationsByTileSet = readAnimationSources(assets, unresolved);
|
|
1035
|
+
const tileSetBySprite = new Map;
|
|
1036
|
+
const modelDocuments = new Set;
|
|
1037
|
+
const animationSourceByModel = new Map;
|
|
1038
|
+
const entriesByAnimationSet = new Map;
|
|
1039
|
+
for (const [path, text] of assets) {
|
|
1040
|
+
const displayPath = normalizeDocumentKey(path);
|
|
1041
|
+
const isSprite = displayPath.endsWith(SPRITE_SUFFIX2);
|
|
1042
|
+
const isModel = displayPath.endsWith(MODEL_SUFFIX2);
|
|
1043
|
+
const isAnimationSet = displayPath.endsWith(ANIMATION_SET_SUFFIX2);
|
|
1044
|
+
if (!isSprite && !isModel && !isAnimationSet)
|
|
740
1045
|
continue;
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1046
|
+
let document;
|
|
1047
|
+
try {
|
|
1048
|
+
document = parseSceneTextFormat(text);
|
|
1049
|
+
} catch (error) {
|
|
1050
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1051
|
+
throw error;
|
|
1052
|
+
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
744
1053
|
continue;
|
|
745
1054
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
unreadable.push(...library.unreadable);
|
|
751
|
-
for (const { displayPath, hostPath, url, text } of library.documents) {
|
|
752
|
-
if (documents.has(displayPath)) {
|
|
753
|
-
unreadable.push(`${displayPath}: also declared by ${url}; the project's own file is used`);
|
|
1055
|
+
if (isSprite) {
|
|
1056
|
+
const tileSet = firstField(document, "tile_set");
|
|
1057
|
+
if (tileSet !== undefined)
|
|
1058
|
+
tileSetBySprite.set(displayPath, resourceKey(tileSet));
|
|
754
1059
|
continue;
|
|
755
1060
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
}
|
|
762
|
-
function listProjectResourcePaths(host, projectRoot, extensions) {
|
|
763
|
-
if (!host.readDirectory)
|
|
764
|
-
return new Set;
|
|
765
|
-
const paths = [];
|
|
766
|
-
for (const filePath of host.readDirectory(projectRoot, extensions)) {
|
|
767
|
-
const displayPath = displayPathOf(projectRoot, filePath);
|
|
768
|
-
if (isExcludedProjectPath(displayPath))
|
|
769
|
-
continue;
|
|
770
|
-
if (!extensions.some((extension) => displayPath.endsWith(extension)))
|
|
1061
|
+
if (isModel) {
|
|
1062
|
+
modelDocuments.add(displayPath);
|
|
1063
|
+
const animations = firstField(document, "animations");
|
|
1064
|
+
if (animations !== undefined)
|
|
1065
|
+
animationSourceByModel.set(displayPath, animations);
|
|
771
1066
|
continue;
|
|
772
|
-
|
|
1067
|
+
}
|
|
1068
|
+
entriesByAnimationSet.set(displayPath, animationSetEntries(document));
|
|
773
1069
|
}
|
|
774
|
-
return
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
}
|
|
781
|
-
function isSectionHeader(line) {
|
|
782
|
-
return /^\[.+\]\s*$/.test(line.trim());
|
|
1070
|
+
return {
|
|
1071
|
+
animationsByTileSet,
|
|
1072
|
+
tileSetBySprite,
|
|
1073
|
+
modelDocuments,
|
|
1074
|
+
animationSourceByModel,
|
|
1075
|
+
entriesByAnimationSet
|
|
1076
|
+
};
|
|
783
1077
|
}
|
|
784
|
-
function
|
|
785
|
-
const
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1078
|
+
function resolveAnimationSet(input) {
|
|
1079
|
+
const { path, prefix, stack, assets, unresolved } = input;
|
|
1080
|
+
const entries = assets.entriesByAnimationSet.get(path);
|
|
1081
|
+
if (entries === undefined)
|
|
1082
|
+
return;
|
|
1083
|
+
stack.add(path);
|
|
1084
|
+
try {
|
|
1085
|
+
const ids = new Map;
|
|
1086
|
+
for (const entry of entries) {
|
|
1087
|
+
const key = resourceKey(entry);
|
|
1088
|
+
if (MESH_SUFFIXES.some((suffix) => key.endsWith(suffix))) {
|
|
1089
|
+
ids.set(prefix + basename(key), path);
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
if (!key.endsWith(ANIMATION_SET_SUFFIX2)) {
|
|
1093
|
+
unresolved.push(`${path}: the entry ${entry} is not a .gltf, .glb or .animationset, so it declares no animation id`);
|
|
1094
|
+
continue;
|
|
1095
|
+
}
|
|
1096
|
+
if (!assets.entriesByAnimationSet.has(key)) {
|
|
1097
|
+
unresolved.push(`${path}: the entry ${entry} is not among the project's animation set documents`);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
if (stack.has(key)) {
|
|
1101
|
+
unresolved.push(`${path}: the entry ${entry} re-enters an animation set already being read, so the chain is cyclic`);
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
const nested = resolveAnimationSet({
|
|
1105
|
+
path: key,
|
|
1106
|
+
prefix: `${prefix + basename(key)}/`,
|
|
1107
|
+
stack,
|
|
1108
|
+
assets,
|
|
1109
|
+
unresolved
|
|
1110
|
+
});
|
|
1111
|
+
if (nested === undefined)
|
|
1112
|
+
return;
|
|
1113
|
+
for (const [id, declaring] of nested)
|
|
1114
|
+
if (!ids.has(id))
|
|
1115
|
+
ids.set(id, declaring);
|
|
800
1116
|
}
|
|
1117
|
+
return ids;
|
|
1118
|
+
} finally {
|
|
1119
|
+
stack.delete(path);
|
|
801
1120
|
}
|
|
802
|
-
return deps;
|
|
803
1121
|
}
|
|
804
|
-
function
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
1122
|
+
function componentAnimationSources(object, displayPath, assets, unresolved) {
|
|
1123
|
+
const sources = new Map;
|
|
1124
|
+
function claimModel(id, animations) {
|
|
1125
|
+
if (!animations.endsWith(ANIMATION_SET_SUFFIX2)) {
|
|
1126
|
+
unresolved.push(`${displayPath}: the model component "${id}" names ${animations} rather than an animation set, so none of its animation ids are established`);
|
|
809
1127
|
return;
|
|
810
1128
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
1129
|
+
sources.set(id, { kind: "model", path: resourceKey(animations) });
|
|
1130
|
+
}
|
|
1131
|
+
for (const embedded of childrenOf2(object, "embedded_components")) {
|
|
1132
|
+
const type = firstField(embedded, "type");
|
|
1133
|
+
if (type !== "sprite" && type !== "model")
|
|
1134
|
+
continue;
|
|
1135
|
+
const id = firstField(embedded, "id");
|
|
1136
|
+
const payload = firstField(embedded, "data");
|
|
1137
|
+
if (id === undefined || payload === undefined)
|
|
1138
|
+
continue;
|
|
1139
|
+
let document;
|
|
1140
|
+
try {
|
|
1141
|
+
document = parseSceneTextFormat(payload);
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1144
|
+
throw error;
|
|
1145
|
+
unresolved.push(`${displayPath}: the embedded ${type} "${id}" could not be read (${error.message})`);
|
|
1146
|
+
continue;
|
|
1147
|
+
}
|
|
1148
|
+
if (type === "sprite") {
|
|
1149
|
+
const tileSet = firstField(document, "tile_set");
|
|
1150
|
+
if (tileSet !== undefined)
|
|
1151
|
+
sources.set(id, { kind: "sprite", path: resourceKey(tileSet) });
|
|
1152
|
+
continue;
|
|
816
1153
|
}
|
|
1154
|
+
const animations = firstField(document, "animations");
|
|
1155
|
+
if (animations !== undefined)
|
|
1156
|
+
claimModel(id, animations);
|
|
817
1157
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
for (const line of gameProjectText.split(`
|
|
823
|
-
`)) {
|
|
824
|
-
if (isSectionHeader(line)) {
|
|
825
|
-
inLibrary = line.trim() === "[library]";
|
|
1158
|
+
for (const referenced of childrenOf2(object, "components")) {
|
|
1159
|
+
const component = firstField(referenced, "component");
|
|
1160
|
+
const id = firstField(referenced, "id");
|
|
1161
|
+
if (id === undefined || component === undefined)
|
|
826
1162
|
continue;
|
|
827
|
-
|
|
828
|
-
|
|
1163
|
+
if (component.endsWith(SPRITE_SUFFIX2)) {
|
|
1164
|
+
const tileSet = assets.tileSetBySprite.get(resourceKey(component));
|
|
1165
|
+
if (tileSet === undefined) {
|
|
1166
|
+
unresolved.push(`${displayPath}: the sprite component "${id}" names ${component}, which is not among the project's sprite documents`);
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
sources.set(id, { kind: "sprite", path: tileSet });
|
|
829
1170
|
continue;
|
|
830
1171
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1172
|
+
if (!component.endsWith(MODEL_SUFFIX2))
|
|
1173
|
+
continue;
|
|
1174
|
+
const resource = resourceKey(component);
|
|
1175
|
+
if (!assets.modelDocuments.has(resource)) {
|
|
1176
|
+
unresolved.push(`${displayPath}: the model component "${id}" names ${component}, which is not among the project's model documents`);
|
|
1177
|
+
continue;
|
|
834
1178
|
}
|
|
1179
|
+
const animations = assets.animationSourceByModel.get(resource);
|
|
1180
|
+
if (animations !== undefined)
|
|
1181
|
+
claimModel(id, animations);
|
|
835
1182
|
}
|
|
836
|
-
return
|
|
1183
|
+
return sources;
|
|
837
1184
|
}
|
|
838
|
-
function
|
|
839
|
-
|
|
840
|
-
|
|
1185
|
+
function scriptResourcesOf(object) {
|
|
1186
|
+
const resources = [];
|
|
1187
|
+
for (const component of childrenOf2(object, "components")) {
|
|
1188
|
+
const resource = firstField(component, "component");
|
|
1189
|
+
if (resource === undefined || !resource.endsWith(SCRIPT_SUFFIX))
|
|
1190
|
+
continue;
|
|
1191
|
+
const key = resourceKey(resource);
|
|
1192
|
+
if (key !== SCRIPT_SUFFIX.slice(1))
|
|
1193
|
+
resources.push(key);
|
|
841
1194
|
}
|
|
842
|
-
return
|
|
1195
|
+
return resources;
|
|
843
1196
|
}
|
|
844
|
-
function
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1197
|
+
function isGameObject(message) {
|
|
1198
|
+
return message.messages.has("components") || message.messages.has("embedded_components");
|
|
1199
|
+
}
|
|
1200
|
+
function buildComponentAnimationIndex(input) {
|
|
1201
|
+
const unresolved = [];
|
|
1202
|
+
const assets = readAssets(input.assets, unresolved);
|
|
1203
|
+
const byScriptResource = new Map;
|
|
1204
|
+
const sourceByScriptResource = new Map;
|
|
1205
|
+
const claimedBy = new Map;
|
|
1206
|
+
function walk(message, blockName, displayPath) {
|
|
1207
|
+
if (isGameObject(message)) {
|
|
1208
|
+
claim(message, displayPath);
|
|
1209
|
+
}
|
|
1210
|
+
if (blockName === "embedded_instances") {
|
|
1211
|
+
for (const payload of message.fields.get("data") ?? []) {
|
|
1212
|
+
try {
|
|
1213
|
+
walk(parseSceneTextFormat(payload), "", displayPath);
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1216
|
+
throw error;
|
|
1217
|
+
unresolved.push(`${displayPath}: an embedded game object could not be read (${error.message})`);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
for (const [name, nested] of message.messages) {
|
|
1222
|
+
for (const child of nested) {
|
|
1223
|
+
walk(child, name, displayPath);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
851
1226
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1227
|
+
function idsOf(id, source, displayPath) {
|
|
1228
|
+
if (source.kind === "sprite") {
|
|
1229
|
+
const declared = assets.animationsByTileSet.get(source.path);
|
|
1230
|
+
if (declared !== undefined)
|
|
1231
|
+
return new Map([...declared].map((name) => [name, source.path]));
|
|
1232
|
+
unresolved.push(`${displayPath}: the sprite component "${id}" names the tile source /${source.path}, which is not among the project's asset documents`);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const resolved = resolveAnimationSet({
|
|
1236
|
+
path: source.path,
|
|
1237
|
+
prefix: "",
|
|
1238
|
+
stack: new Set,
|
|
1239
|
+
assets,
|
|
1240
|
+
unresolved
|
|
1241
|
+
});
|
|
1242
|
+
if (resolved !== undefined)
|
|
1243
|
+
return resolved;
|
|
1244
|
+
if (!assets.entriesByAnimationSet.has(source.path)) {
|
|
1245
|
+
unresolved.push(`${displayPath}: the model component "${id}" names the animation set /${source.path}, which is not among the project's asset documents`);
|
|
1246
|
+
}
|
|
1247
|
+
return;
|
|
859
1248
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
const
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
1249
|
+
function claim(object, displayPath) {
|
|
1250
|
+
const scripts = scriptResourcesOf(object);
|
|
1251
|
+
if (scripts.length === 0)
|
|
1252
|
+
return;
|
|
1253
|
+
const sources = componentAnimationSources(object, displayPath, assets, unresolved);
|
|
1254
|
+
const animations = new Map;
|
|
1255
|
+
const declaringSources = new Map;
|
|
1256
|
+
for (const [id, source] of sources) {
|
|
1257
|
+
const resolved = idsOf(id, source, displayPath);
|
|
1258
|
+
if (resolved === undefined)
|
|
1259
|
+
continue;
|
|
1260
|
+
animations.set(id, new Set(resolved.keys()));
|
|
1261
|
+
declaringSources.set(id, resolved);
|
|
868
1262
|
}
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
1263
|
+
for (const key of scripts) {
|
|
1264
|
+
const owner = claimedBy.get(key);
|
|
1265
|
+
if (owner !== undefined) {
|
|
1266
|
+
byScriptResource.delete(key);
|
|
1267
|
+
sourceByScriptResource.delete(key);
|
|
1268
|
+
unresolved.push(`${key}: claimed by both ${owner} and ${displayPath}, so its component animations are ambiguous`);
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
claimedBy.set(key, displayPath);
|
|
1272
|
+
byScriptResource.set(key, animations);
|
|
1273
|
+
sourceByScriptResource.set(key, declaringSources);
|
|
872
1274
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1275
|
+
}
|
|
1276
|
+
for (const [path, text] of input.scenes) {
|
|
1277
|
+
const displayPath = normalizeDocumentKey(path);
|
|
1278
|
+
try {
|
|
1279
|
+
walk(parseSceneTextFormat(text), "", displayPath);
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1282
|
+
throw error;
|
|
1283
|
+
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
876
1284
|
}
|
|
877
|
-
shared.push({ entry, path });
|
|
878
1285
|
}
|
|
879
|
-
|
|
880
|
-
return { shared, reasons: [], refused };
|
|
881
|
-
}
|
|
882
|
-
var LIBRARY_DEPENDENCY_ROOT = ".defold-types/dependencies";
|
|
883
|
-
var LIBRARY_DEPENDENCY_MANIFEST = `${LIBRARY_DEPENDENCY_ROOT}/dependencies.json`;
|
|
884
|
-
function joinProject(projectRoot, relative) {
|
|
885
|
-
return `${projectRoot.replace(/\\/g, "/").replace(/\/+$/, "")}/${relative}`;
|
|
1286
|
+
return { byScriptResource, sourceByScriptResource, unresolved };
|
|
886
1287
|
}
|
|
887
|
-
function
|
|
888
|
-
|
|
889
|
-
try {
|
|
890
|
-
parsed = JSON.parse(manifestText);
|
|
891
|
-
} catch {
|
|
1288
|
+
function componentIdOfSameObjectAddress(address) {
|
|
1289
|
+
if (!address.startsWith("#"))
|
|
892
1290
|
return;
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
if (!Array.isArray(entries))
|
|
1291
|
+
const id = address.slice(1);
|
|
1292
|
+
if (id === "" || id.includes("/") || id.includes("#"))
|
|
896
1293
|
return;
|
|
897
|
-
|
|
898
|
-
for (const entry of entries) {
|
|
899
|
-
const { key, url } = entry ?? {};
|
|
900
|
-
if (typeof key === "string" && typeof url === "string")
|
|
901
|
-
keyByUrl.set(url, key);
|
|
902
|
-
}
|
|
903
|
-
return keyByUrl;
|
|
1294
|
+
return id;
|
|
904
1295
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
unreadable.push(`${url}: is declared by game.project but ${LIBRARY_DEPENDENCY_MANIFEST} is absent`);
|
|
920
|
-
}
|
|
921
|
-
return { documents, unreadable };
|
|
922
|
-
}
|
|
923
|
-
const keyByUrl = readMaterializedKeys(manifestText);
|
|
924
|
-
if (keyByUrl === undefined) {
|
|
925
|
-
for (const { url } of declared) {
|
|
926
|
-
unreadable.push(`${url}: is declared by game.project but ${LIBRARY_DEPENDENCY_MANIFEST} is not a readable dependency manifest`);
|
|
1296
|
+
// src/config-key-index.ts
|
|
1297
|
+
function sectionNameOf(line) {
|
|
1298
|
+
const match = line.trim().match(/^\[(.+)\]$/);
|
|
1299
|
+
return match?.[1];
|
|
1300
|
+
}
|
|
1301
|
+
function buildConfigKeyIndex(gameProjectText) {
|
|
1302
|
+
const keys = new Set;
|
|
1303
|
+
let section;
|
|
1304
|
+
for (const line of gameProjectText.split(`
|
|
1305
|
+
`)) {
|
|
1306
|
+
const header = sectionNameOf(line);
|
|
1307
|
+
if (header !== undefined) {
|
|
1308
|
+
section = header;
|
|
1309
|
+
continue;
|
|
927
1310
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
const key =
|
|
934
|
-
if (key ===
|
|
935
|
-
unreadable.push(`${url}: is declared by game.project but was not materialized by the last resolve`);
|
|
1311
|
+
if (section === undefined)
|
|
1312
|
+
continue;
|
|
1313
|
+
const separator = line.indexOf("=");
|
|
1314
|
+
if (separator === -1)
|
|
1315
|
+
continue;
|
|
1316
|
+
const key = line.slice(0, separator).trim();
|
|
1317
|
+
if (key === "")
|
|
936
1318
|
continue;
|
|
937
|
-
}
|
|
938
|
-
resolved.push({ key, url });
|
|
939
|
-
urlByKey.set(key, url);
|
|
1319
|
+
keys.add(`${section}.${key}`);
|
|
940
1320
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1321
|
+
return keys;
|
|
1322
|
+
}
|
|
1323
|
+
function readGameProjectSetting(gameProjectText, section, key) {
|
|
1324
|
+
let current;
|
|
1325
|
+
for (const line of gameProjectText.split(`
|
|
1326
|
+
`)) {
|
|
1327
|
+
const header = sectionNameOf(line);
|
|
1328
|
+
if (header !== undefined) {
|
|
1329
|
+
current = header;
|
|
947
1330
|
continue;
|
|
948
|
-
|
|
949
|
-
if (
|
|
1331
|
+
}
|
|
1332
|
+
if (current !== section)
|
|
950
1333
|
continue;
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
if (url === undefined) {
|
|
954
|
-
stray.add(key);
|
|
1334
|
+
const separator = line.indexOf("=");
|
|
1335
|
+
if (separator === -1)
|
|
955
1336
|
continue;
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
bucket.push(filePath);
|
|
1337
|
+
if (line.slice(0, separator).trim() !== key)
|
|
1338
|
+
continue;
|
|
1339
|
+
const value = line.slice(separator + 1).trim();
|
|
1340
|
+
if (value !== "")
|
|
1341
|
+
return value;
|
|
962
1342
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
// src/lua-require-scan.ts
|
|
1346
|
+
var PLACEHOLDER = "\x00";
|
|
1347
|
+
function longBracketLevel(src, open) {
|
|
1348
|
+
let i = open + 1;
|
|
1349
|
+
let level = 0;
|
|
1350
|
+
while (src[i] === "=") {
|
|
1351
|
+
level++;
|
|
1352
|
+
i++;
|
|
1353
|
+
}
|
|
1354
|
+
return src[i] === "[" ? level : undefined;
|
|
1355
|
+
}
|
|
1356
|
+
function skipLongBracket(src, open, level) {
|
|
1357
|
+
const close = `]${"=".repeat(level)}]`;
|
|
1358
|
+
const end = src.indexOf(close, open + level + 2);
|
|
1359
|
+
return end === -1 ? src.length : end + close.length;
|
|
1360
|
+
}
|
|
1361
|
+
function mask(lua) {
|
|
1362
|
+
const literals = [];
|
|
1363
|
+
let text = "";
|
|
1364
|
+
let i = 0;
|
|
1365
|
+
while (i < lua.length) {
|
|
1366
|
+
const c = lua[i];
|
|
1367
|
+
if (c === "-" && lua[i + 1] === "-") {
|
|
1368
|
+
const level = lua[i + 2] === "[" ? longBracketLevel(lua, i + 2) : undefined;
|
|
1369
|
+
if (level !== undefined) {
|
|
1370
|
+
i = skipLongBracket(lua, i + 2, level);
|
|
1371
|
+
} else {
|
|
1372
|
+
const newline = lua.indexOf(`
|
|
1373
|
+
`, i);
|
|
1374
|
+
i = newline === -1 ? lua.length : newline;
|
|
973
1375
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1376
|
+
text += " ";
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
if (c === '"' || c === "'") {
|
|
1380
|
+
let j = i + 1;
|
|
1381
|
+
let value = "";
|
|
1382
|
+
while (j < lua.length) {
|
|
1383
|
+
const ch = lua[j];
|
|
1384
|
+
if (ch === "\\") {
|
|
1385
|
+
const next = lua[j + 1] ?? "";
|
|
1386
|
+
value += next === "n" ? `
|
|
1387
|
+
` : next === "t" ? "\t" : next;
|
|
1388
|
+
j += 2;
|
|
1389
|
+
continue;
|
|
1390
|
+
}
|
|
1391
|
+
if (ch === c) {
|
|
1392
|
+
j++;
|
|
1393
|
+
break;
|
|
1394
|
+
}
|
|
1395
|
+
if (ch === `
|
|
1396
|
+
`) {
|
|
1397
|
+
break;
|
|
1398
|
+
}
|
|
1399
|
+
value += ch;
|
|
1400
|
+
j++;
|
|
1401
|
+
}
|
|
1402
|
+
text += `${PLACEHOLDER}${literals.length}${PLACEHOLDER}`;
|
|
1403
|
+
literals.push({ value, start: i, end: j });
|
|
1404
|
+
i = j;
|
|
1405
|
+
continue;
|
|
1406
|
+
}
|
|
1407
|
+
if (c === "[") {
|
|
1408
|
+
const level = longBracketLevel(lua, i);
|
|
1409
|
+
if (level !== undefined) {
|
|
1410
|
+
const end = skipLongBracket(lua, i, level);
|
|
1411
|
+
const close = `]${"=".repeat(level)}]`;
|
|
1412
|
+
const inner = lua.slice(i + level + 2, Math.max(i + level + 2, end - close.length));
|
|
1413
|
+
text += `${PLACEHOLDER}${literals.length}${PLACEHOLDER}`;
|
|
1414
|
+
literals.push({ value: inner, start: i, end });
|
|
1415
|
+
i = end;
|
|
977
1416
|
continue;
|
|
978
1417
|
}
|
|
979
|
-
claimed.set(displayPath, url);
|
|
980
|
-
documents.push({ displayPath, hostPath, url, text });
|
|
981
1418
|
}
|
|
1419
|
+
text += c;
|
|
1420
|
+
i++;
|
|
982
1421
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1422
|
+
return { text, literals };
|
|
1423
|
+
}
|
|
1424
|
+
var REQUIRE_RE = new RegExp(String.raw`(?<![A-Za-z0-9_.])require\s*\(\s*${PLACEHOLDER}(\d+)${PLACEHOLDER}\s*\)`, "g");
|
|
1425
|
+
function scanEmittedRequires(lua) {
|
|
1426
|
+
const { text, literals } = mask(lua);
|
|
1427
|
+
const sites = [];
|
|
1428
|
+
for (const match of text.matchAll(REQUIRE_RE)) {
|
|
1429
|
+
const literal = literals[Number(match[1])];
|
|
1430
|
+
if (literal === undefined) {
|
|
1431
|
+
continue;
|
|
1432
|
+
}
|
|
1433
|
+
sites.push({ path: literal.value, start: literal.start, end: literal.end });
|
|
985
1434
|
}
|
|
986
|
-
return
|
|
1435
|
+
return sites;
|
|
987
1436
|
}
|
|
988
|
-
// src/main-entry-factory-imports.ts
|
|
989
|
-
import * as ts3 from "typescript";
|
|
990
1437
|
|
|
991
|
-
// src/
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
createCallExpression as createCallExpression2,
|
|
998
|
-
createExpressionStatement,
|
|
999
|
-
createForInStatement,
|
|
1000
|
-
createFunctionExpression as createFunctionExpression2,
|
|
1001
|
-
createIdentifier as createIdentifier2,
|
|
1002
|
-
createIfStatement as createIfStatement2,
|
|
1003
|
-
createNilLiteral,
|
|
1004
|
-
createReturnStatement,
|
|
1005
|
-
createStringLiteral as createStringLiteral2,
|
|
1006
|
-
createTableIndexExpression,
|
|
1007
|
-
createVariableDeclarationStatement as createVariableDeclarationStatement2,
|
|
1008
|
-
NodeFlags as NodeFlags2,
|
|
1009
|
-
SyntaxKind as SyntaxKind4
|
|
1010
|
-
} from "typescript-to-lua";
|
|
1438
|
+
// src/timers-runtime.ts
|
|
1439
|
+
var TIMERS_MODULE_SPECIFIER = "@defold-typescript/types/timers";
|
|
1440
|
+
var TIMERS_REQUIRE_NAME = "defold_typescript_timers";
|
|
1441
|
+
var TIMERS_RUNTIME = `local ____lualib = require("lualib_bundle")
|
|
1442
|
+
local __TS__Promise = ____lualib.__TS__Promise
|
|
1443
|
+
local __TS__New = ____lualib.__TS__New
|
|
1011
1444
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1445
|
+
local function setTimeout(callback, delayMs)
|
|
1446
|
+
return timer.delay(delayMs / 1000, false, function()
|
|
1447
|
+
callback()
|
|
1448
|
+
end)
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
local function setInterval(callback, delayMs)
|
|
1452
|
+
return timer.delay(delayMs / 1000, true, function()
|
|
1453
|
+
callback()
|
|
1454
|
+
end)
|
|
1455
|
+
end
|
|
1456
|
+
|
|
1457
|
+
local function clearTimeout(handle)
|
|
1458
|
+
timer.cancel(handle)
|
|
1459
|
+
end
|
|
1460
|
+
|
|
1461
|
+
local function clearInterval(handle)
|
|
1462
|
+
timer.cancel(handle)
|
|
1463
|
+
end
|
|
1464
|
+
|
|
1465
|
+
local function wait(seconds)
|
|
1466
|
+
return __TS__New(__TS__Promise, function(_, resolve)
|
|
1467
|
+
timer.delay(seconds, false, function()
|
|
1468
|
+
resolve()
|
|
1469
|
+
end)
|
|
1470
|
+
end)
|
|
1471
|
+
end
|
|
1472
|
+
|
|
1473
|
+
return {
|
|
1474
|
+
setTimeout = setTimeout,
|
|
1475
|
+
setInterval = setInterval,
|
|
1476
|
+
clearTimeout = clearTimeout,
|
|
1477
|
+
clearInterval = clearInterval,
|
|
1478
|
+
wait = wait,
|
|
1479
|
+
}
|
|
1480
|
+
`;
|
|
1481
|
+
|
|
1482
|
+
// src/emitted-requires.ts
|
|
1483
|
+
var LUALIB_REQUIRE_NAME = "lualib_bundle";
|
|
1484
|
+
var GENERATED_RUNTIME_REQUIRES = new Set([
|
|
1485
|
+
LUALIB_REQUIRE_NAME,
|
|
1486
|
+
TIMERS_REQUIRE_NAME
|
|
1487
|
+
]);
|
|
1488
|
+
function findEmittedRequires(lua) {
|
|
1489
|
+
const found = [];
|
|
1490
|
+
const seen = new Set;
|
|
1491
|
+
for (const { path } of scanEmittedRequires(lua)) {
|
|
1492
|
+
if (GENERATED_RUNTIME_REQUIRES.has(path) || seen.has(path)) {
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
seen.add(path);
|
|
1496
|
+
found.push(path);
|
|
1043
1497
|
}
|
|
1044
|
-
return
|
|
1498
|
+
return found;
|
|
1045
1499
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1500
|
+
// src/gui-flipbook-index.ts
|
|
1501
|
+
var SCRIPT_SUFFIX2 = ".gui_script";
|
|
1502
|
+
function scriptKeyOf(script) {
|
|
1503
|
+
if (!script.endsWith(SCRIPT_SUFFIX2))
|
|
1049
1504
|
return;
|
|
1505
|
+
const key = resourceKey(script);
|
|
1506
|
+
return key === SCRIPT_SUFFIX2 ? undefined : key;
|
|
1507
|
+
}
|
|
1508
|
+
function buildGuiFlipbookIndex(input) {
|
|
1509
|
+
const unresolved = [];
|
|
1510
|
+
const animationsBySource = readAnimationSources(input.assets, unresolved);
|
|
1511
|
+
const byScriptResource = new Map;
|
|
1512
|
+
const claimedBy = new Map;
|
|
1513
|
+
for (const [path, text] of input.scenes) {
|
|
1514
|
+
const displayPath = normalizeDocumentKey(path);
|
|
1515
|
+
let document;
|
|
1516
|
+
try {
|
|
1517
|
+
document = parseSceneTextFormat(text);
|
|
1518
|
+
} catch (error) {
|
|
1519
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1520
|
+
throw error;
|
|
1521
|
+
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
1522
|
+
continue;
|
|
1523
|
+
}
|
|
1524
|
+
const [script] = document.fields.get("script") ?? [];
|
|
1525
|
+
if (script === undefined)
|
|
1526
|
+
continue;
|
|
1527
|
+
const key = scriptKeyOf(script);
|
|
1528
|
+
if (key === undefined)
|
|
1529
|
+
continue;
|
|
1530
|
+
const owner = claimedBy.get(key);
|
|
1531
|
+
if (owner !== undefined) {
|
|
1532
|
+
byScriptResource.delete(key);
|
|
1533
|
+
unresolved.push(`${key}: claimed by both ${owner} and ${displayPath}, so its flipbook animations are ambiguous`);
|
|
1534
|
+
continue;
|
|
1535
|
+
}
|
|
1536
|
+
claimedBy.set(key, displayPath);
|
|
1537
|
+
const declaredBy = new Map;
|
|
1538
|
+
for (const message of document.messages.get("textures") ?? []) {
|
|
1539
|
+
for (const texture of message.fields.get("texture") ?? []) {
|
|
1540
|
+
if (texture === "")
|
|
1541
|
+
continue;
|
|
1542
|
+
const source = resourceKey(texture);
|
|
1543
|
+
const ids = animationsBySource.get(source);
|
|
1544
|
+
if (ids === undefined) {
|
|
1545
|
+
unresolved.push(`${displayPath}: the texture ${texture} is not among the project's asset documents`);
|
|
1546
|
+
continue;
|
|
1547
|
+
}
|
|
1548
|
+
for (const id of ids) {
|
|
1549
|
+
const declarers = declaredBy.get(id);
|
|
1550
|
+
if (declarers) {
|
|
1551
|
+
declarers.add(source);
|
|
1552
|
+
} else {
|
|
1553
|
+
declaredBy.set(id, new Set([source]));
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
byScriptResource.set(key, declaredBy);
|
|
1050
1559
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1560
|
+
return { byScriptResource, unresolved };
|
|
1561
|
+
}
|
|
1562
|
+
// src/gui-node-index.ts
|
|
1563
|
+
var SCRIPT_SUFFIX3 = ".gui_script";
|
|
1564
|
+
function scriptKeyOf2(script) {
|
|
1565
|
+
if (!script.endsWith(SCRIPT_SUFFIX3))
|
|
1566
|
+
return;
|
|
1567
|
+
const key = script.startsWith("/") ? script.slice(1) : script;
|
|
1568
|
+
return key === SCRIPT_SUFFIX3 ? undefined : key;
|
|
1569
|
+
}
|
|
1570
|
+
function guiScriptResourceOf(document) {
|
|
1571
|
+
const [script] = document.fields.get("script") ?? [];
|
|
1572
|
+
return script === undefined ? undefined : scriptKeyOf2(script);
|
|
1055
1573
|
}
|
|
1056
|
-
function
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1574
|
+
function guiScriptResourcesOf(documents) {
|
|
1575
|
+
const scripts = new Map;
|
|
1576
|
+
for (const [displayPath, text] of documents) {
|
|
1577
|
+
let resource;
|
|
1578
|
+
try {
|
|
1579
|
+
resource = guiScriptResourceOf(parseSceneTextFormat(text));
|
|
1580
|
+
} catch (error) {
|
|
1581
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1582
|
+
throw error;
|
|
1583
|
+
continue;
|
|
1064
1584
|
}
|
|
1585
|
+
if (resource !== undefined)
|
|
1586
|
+
scripts.set(displayPath, resource);
|
|
1065
1587
|
}
|
|
1066
|
-
return;
|
|
1067
|
-
}
|
|
1068
|
-
function isThisParameter(param) {
|
|
1069
|
-
return ts.isIdentifier(param.name) && ts.identifierToKeywordKind(param.name) === ts.SyntaxKind.ThisKeyword;
|
|
1588
|
+
return scripts;
|
|
1070
1589
|
}
|
|
1071
|
-
function
|
|
1072
|
-
const
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1590
|
+
function buildGuiNodeIndex(documents) {
|
|
1591
|
+
const byScriptResource = new Map;
|
|
1592
|
+
const claimedBy = new Map;
|
|
1593
|
+
const unresolved = [];
|
|
1594
|
+
for (const [displayPath, text] of documents) {
|
|
1595
|
+
let document;
|
|
1596
|
+
try {
|
|
1597
|
+
document = parseSceneTextFormat(text);
|
|
1598
|
+
} catch (error) {
|
|
1599
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1600
|
+
throw error;
|
|
1601
|
+
unresolved.push(`${displayPath}: could not be parsed (${error.message})`);
|
|
1602
|
+
continue;
|
|
1078
1603
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1604
|
+
const key = guiScriptResourceOf(document);
|
|
1605
|
+
if (key === undefined)
|
|
1606
|
+
continue;
|
|
1607
|
+
const owner = claimedBy.get(key);
|
|
1608
|
+
if (owner !== undefined) {
|
|
1609
|
+
byScriptResource.delete(key);
|
|
1610
|
+
unresolved.push(`${key}: claimed by both ${owner} and ${displayPath}, so its node ids are ambiguous`);
|
|
1611
|
+
continue;
|
|
1081
1612
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1613
|
+
claimedBy.set(key, displayPath);
|
|
1614
|
+
const ids = new Set;
|
|
1615
|
+
for (const message of document.messages.get("nodes") ?? []) {
|
|
1616
|
+
for (const id of message.fields.get("id") ?? []) {
|
|
1617
|
+
if (id !== "")
|
|
1618
|
+
ids.add(id);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
byScriptResource.set(key, ids);
|
|
1088
1622
|
}
|
|
1089
|
-
return
|
|
1623
|
+
return { byScriptResource, unresolved };
|
|
1090
1624
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
const condition = createBinaryExpression(createIdentifier("message_id"), createCallExpression(createIdentifier("hash"), [createStringLiteral(name)]), SyntaxKind2.EqualityOperator);
|
|
1109
|
-
const body = [...aliasStatements(fn), ...handlerBody(fn, context)];
|
|
1110
|
-
chain = createIfStatement(condition, createBlock(body), chain);
|
|
1625
|
+
// src/input-action-index.ts
|
|
1626
|
+
function buildInputActionIndex(documents) {
|
|
1627
|
+
const actions = new Set;
|
|
1628
|
+
for (const text of documents.values()) {
|
|
1629
|
+
let document;
|
|
1630
|
+
try {
|
|
1631
|
+
document = parseSceneTextFormat(text);
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
if (!(error instanceof SceneTextFormatError))
|
|
1634
|
+
throw error;
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
for (const triggers of document.messages.values()) {
|
|
1638
|
+
for (const trigger of triggers) {
|
|
1639
|
+
for (const action of trigger.fields.get("action") ?? []) {
|
|
1640
|
+
if (action !== "")
|
|
1641
|
+
actions.add(action);
|
|
1111
1642
|
}
|
|
1112
|
-
const params = [
|
|
1113
|
-
createIdentifier("self"),
|
|
1114
|
-
createIdentifier("message_id"),
|
|
1115
|
-
createIdentifier("message"),
|
|
1116
|
-
createIdentifier("sender")
|
|
1117
|
-
];
|
|
1118
|
-
return createFunctionExpression(createBlock(chain === undefined ? [] : [chain]), params, undefined, NodeFlags.Declaration, node);
|
|
1119
1643
|
}
|
|
1120
|
-
return context.superTransformExpression(node);
|
|
1121
1644
|
}
|
|
1122
1645
|
}
|
|
1123
|
-
|
|
1646
|
+
return actions;
|
|
1647
|
+
}
|
|
1648
|
+
// src/project-resources.ts
|
|
1649
|
+
var SCAFFOLDED_DEFIGNORE_LINES = ["/node_modules", "/.defold-types", "/.vscode"];
|
|
1650
|
+
function isDefignoredPath(displayPath) {
|
|
1651
|
+
const rooted = `/${displayPath.replace(/^\/+/, "")}`;
|
|
1652
|
+
return SCAFFOLDED_DEFIGNORE_LINES.some((line) => rooted === line || rooted.startsWith(`${line}/`));
|
|
1653
|
+
}
|
|
1124
1654
|
|
|
1125
|
-
// src/
|
|
1126
|
-
var
|
|
1127
|
-
var
|
|
1128
|
-
var
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1149
|
-
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE);
|
|
1655
|
+
// src/scene-documents.ts
|
|
1656
|
+
var SCENE_EXTENSIONS = [".go", ".collection"];
|
|
1657
|
+
var GUI_EXTENSIONS = [".gui"];
|
|
1658
|
+
var INPUT_BINDING_EXTENSIONS = [".input_binding"];
|
|
1659
|
+
var COLLECTION_REFERENCE_EXTENSIONS = [".collectionproxy", ".collectionfactory"];
|
|
1660
|
+
var ANIMATION_ASSET_EXTENSIONS = [
|
|
1661
|
+
".atlas",
|
|
1662
|
+
".tilesource",
|
|
1663
|
+
".sprite",
|
|
1664
|
+
".model",
|
|
1665
|
+
".animationset"
|
|
1666
|
+
];
|
|
1667
|
+
var LIBRARY_SCENE_EXTENSIONS = [
|
|
1668
|
+
...SCENE_EXTENSIONS,
|
|
1669
|
+
...GUI_EXTENSIONS,
|
|
1670
|
+
...ANIMATION_ASSET_EXTENSIONS,
|
|
1671
|
+
...COLLECTION_REFERENCE_EXTENSIONS
|
|
1672
|
+
];
|
|
1673
|
+
var PROJECT_EXTENSIONS = [".project"];
|
|
1674
|
+
var GAME_PROJECT_DOCUMENT = "game.project";
|
|
1675
|
+
function displayPathOf(projectRoot, filePath) {
|
|
1676
|
+
const path = filePath.replace(/\\/g, "/");
|
|
1677
|
+
const root = projectRoot.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
1678
|
+
return path.startsWith(`${root}/`) ? path.slice(root.length + 1) : path;
|
|
1150
1679
|
}
|
|
1151
|
-
function
|
|
1152
|
-
return
|
|
1680
|
+
function isBuildOutput(displayPath) {
|
|
1681
|
+
return displayPath.split("/").includes("build");
|
|
1153
1682
|
}
|
|
1154
|
-
function
|
|
1155
|
-
|
|
1156
|
-
if (name === undefined) {
|
|
1157
|
-
return;
|
|
1158
|
-
}
|
|
1159
|
-
if (ts2.isIdentifier(name) || ts2.isStringLiteral(name)) {
|
|
1160
|
-
return name.text;
|
|
1161
|
-
}
|
|
1162
|
-
return;
|
|
1683
|
+
function isExcludedProjectPath(displayPath) {
|
|
1684
|
+
return isBuildOutput(displayPath) || isDefignoredPath(displayPath);
|
|
1163
1685
|
}
|
|
1164
|
-
function
|
|
1165
|
-
|
|
1166
|
-
|
|
1686
|
+
function readSceneDocuments(host, projectRoot, extensions = SCENE_EXTENSIONS) {
|
|
1687
|
+
const documents = new Map;
|
|
1688
|
+
const origins = new Map;
|
|
1689
|
+
const unreadable = [];
|
|
1690
|
+
const paths = [];
|
|
1691
|
+
if (!host.readDirectory) {
|
|
1692
|
+
unreadable.push("the editor host cannot enumerate project files, so no scene source was read");
|
|
1693
|
+
return { documents, origins, unreadable, paths };
|
|
1167
1694
|
}
|
|
1168
|
-
|
|
1169
|
-
const
|
|
1170
|
-
if (
|
|
1171
|
-
|
|
1695
|
+
for (const filePath of host.readDirectory(projectRoot, extensions)) {
|
|
1696
|
+
const displayPath = displayPathOf(projectRoot, filePath);
|
|
1697
|
+
if (isExcludedProjectPath(displayPath))
|
|
1698
|
+
continue;
|
|
1699
|
+
const text = host.readFile(filePath);
|
|
1700
|
+
if (text === undefined) {
|
|
1701
|
+
unreadable.push(`${displayPath}: could not be read`);
|
|
1702
|
+
continue;
|
|
1172
1703
|
}
|
|
1704
|
+
documents.set(displayPath, text);
|
|
1705
|
+
paths.push(filePath);
|
|
1173
1706
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1707
|
+
const library = readLibrarySceneDocuments(host, projectRoot, extensions);
|
|
1708
|
+
unreadable.push(...library.unreadable);
|
|
1709
|
+
for (const { displayPath, hostPath, url, text } of library.documents) {
|
|
1710
|
+
if (documents.has(displayPath)) {
|
|
1711
|
+
unreadable.push(`${displayPath}: also declared by ${url}; the project's own file is used`);
|
|
1712
|
+
continue;
|
|
1713
|
+
}
|
|
1714
|
+
documents.set(displayPath, text);
|
|
1715
|
+
origins.set(displayPath, url);
|
|
1716
|
+
paths.push(hostPath);
|
|
1183
1717
|
}
|
|
1184
|
-
return
|
|
1718
|
+
return { documents, origins, unreadable, paths };
|
|
1185
1719
|
}
|
|
1186
|
-
function
|
|
1187
|
-
if (
|
|
1188
|
-
return
|
|
1720
|
+
function listProjectResourcePaths(host, projectRoot, extensions) {
|
|
1721
|
+
if (!host.readDirectory)
|
|
1722
|
+
return new Set;
|
|
1723
|
+
const paths = [];
|
|
1724
|
+
for (const filePath of host.readDirectory(projectRoot, extensions)) {
|
|
1725
|
+
const displayPath = displayPathOf(projectRoot, filePath);
|
|
1726
|
+
if (isExcludedProjectPath(displayPath))
|
|
1727
|
+
continue;
|
|
1728
|
+
if (!extensions.some((extension) => displayPath.endsWith(extension)))
|
|
1729
|
+
continue;
|
|
1730
|
+
paths.push(`/${displayPath}`);
|
|
1189
1731
|
}
|
|
1190
|
-
return
|
|
1732
|
+
return new Set(paths.sort());
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// src/library-dependencies.ts
|
|
1736
|
+
function isProjectHeader(line) {
|
|
1737
|
+
return line.trim() === "[project]";
|
|
1191
1738
|
}
|
|
1192
|
-
function
|
|
1193
|
-
return
|
|
1739
|
+
function isSectionHeader(line) {
|
|
1740
|
+
return /^\[.+\]\s*$/.test(line.trim());
|
|
1194
1741
|
}
|
|
1195
|
-
function
|
|
1196
|
-
|
|
1197
|
-
|
|
1742
|
+
function readGameProjectDependencies(gameProjectText) {
|
|
1743
|
+
const lines = gameProjectText.split(`
|
|
1744
|
+
`);
|
|
1745
|
+
const deps = [];
|
|
1746
|
+
let inProject = false;
|
|
1747
|
+
for (const line of lines) {
|
|
1748
|
+
if (isSectionHeader(line)) {
|
|
1749
|
+
inProject = isProjectHeader(line);
|
|
1750
|
+
continue;
|
|
1751
|
+
}
|
|
1752
|
+
if (!inProject) {
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
const match = line.match(/^dependencies#(\d+)\s*=\s*(.+)$/);
|
|
1756
|
+
if (match?.[1] !== undefined && match[2] !== undefined) {
|
|
1757
|
+
deps.push({ index: Number(match[1]), url: match[2] });
|
|
1758
|
+
}
|
|
1198
1759
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1760
|
+
return deps;
|
|
1761
|
+
}
|
|
1762
|
+
function archiveWrapperOf(entries) {
|
|
1763
|
+
let wrapper;
|
|
1764
|
+
for (const entry of entries) {
|
|
1765
|
+
const separator = entry.indexOf("/");
|
|
1766
|
+
if (separator <= 0) {
|
|
1202
1767
|
return;
|
|
1203
1768
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1769
|
+
const segment = entry.slice(0, separator);
|
|
1770
|
+
if (wrapper === undefined) {
|
|
1771
|
+
wrapper = segment;
|
|
1772
|
+
} else if (wrapper !== segment) {
|
|
1206
1773
|
return;
|
|
1207
1774
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
ts2.forEachChild(fn.body, visit);
|
|
1211
|
-
return found;
|
|
1775
|
+
}
|
|
1776
|
+
return wrapper;
|
|
1212
1777
|
}
|
|
1213
|
-
function
|
|
1214
|
-
|
|
1215
|
-
|
|
1778
|
+
function readLibraryIncludeDirs(gameProjectText) {
|
|
1779
|
+
let inLibrary = false;
|
|
1780
|
+
for (const line of gameProjectText.split(`
|
|
1781
|
+
`)) {
|
|
1782
|
+
if (isSectionHeader(line)) {
|
|
1783
|
+
inLibrary = line.trim() === "[library]";
|
|
1784
|
+
continue;
|
|
1785
|
+
}
|
|
1786
|
+
if (!inLibrary) {
|
|
1787
|
+
continue;
|
|
1788
|
+
}
|
|
1789
|
+
const match = line.match(/^include_dirs\s*=\s*(.*)$/);
|
|
1790
|
+
if (match?.[1] !== undefined) {
|
|
1791
|
+
return match[1].split(",").map((dir) => dir.trim()).filter((dir) => dir.length > 0);
|
|
1792
|
+
}
|
|
1216
1793
|
}
|
|
1217
|
-
return [
|
|
1794
|
+
return [];
|
|
1218
1795
|
}
|
|
1219
|
-
function
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
const builderArgs = authorParam === undefined ? [] : [createIdentifier2("self")];
|
|
1225
|
-
const stateDecl = createVariableDeclarationStatement2(createIdentifier2("____s"), createCallExpression2(createIdentifier2("____init"), builderArgs));
|
|
1226
|
-
const mergeAssignment = createAssignmentStatement(createTableIndexExpression(createIdentifier2("self"), createIdentifier2("____k")), createIdentifier2("____v"));
|
|
1227
|
-
const forIn = createForInStatement(createBlock2([mergeAssignment]), [createIdentifier2("____k"), createIdentifier2("____v")], [createCallExpression2(createIdentifier2("pairs"), [createIdentifier2("____s")])]);
|
|
1228
|
-
const guard = createIfStatement2(createBinaryExpression2(createIdentifier2("____s"), createNilLiteral(), SyntaxKind4.InequalityOperator), createBlock2([forIn]));
|
|
1229
|
-
const initFn = createFunctionExpression2(createBlock2([stateDecl, guard]), [createIdentifier2("self")], undefined, NodeFlags2.Declaration, fn);
|
|
1230
|
-
return [builderDecl, createAssignmentStatement(createIdentifier2("init"), initFn, property)];
|
|
1796
|
+
function isContainedResourcePath(path) {
|
|
1797
|
+
if (path.length === 0 || path.includes("\\")) {
|
|
1798
|
+
return false;
|
|
1799
|
+
}
|
|
1800
|
+
return path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
1231
1801
|
}
|
|
1232
|
-
function
|
|
1233
|
-
if (
|
|
1234
|
-
return
|
|
1802
|
+
function libraryIncludedEntries(entries, gameProjectText) {
|
|
1803
|
+
if (gameProjectText === undefined) {
|
|
1804
|
+
return {
|
|
1805
|
+
shared: [],
|
|
1806
|
+
reasons: ["ships no game.project, so it declares no [library] include_dirs"],
|
|
1807
|
+
refused: []
|
|
1808
|
+
};
|
|
1235
1809
|
}
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1810
|
+
const includeDirs = new Set(readLibraryIncludeDirs(gameProjectText));
|
|
1811
|
+
if (includeDirs.size === 0) {
|
|
1812
|
+
return {
|
|
1813
|
+
shared: [],
|
|
1814
|
+
reasons: ["its game.project declares no [library] include_dirs"],
|
|
1815
|
+
refused: []
|
|
1816
|
+
};
|
|
1817
|
+
}
|
|
1818
|
+
const wrapper = archiveWrapperOf(entries);
|
|
1819
|
+
const shared = [];
|
|
1820
|
+
const refused = [];
|
|
1821
|
+
for (const entry of entries) {
|
|
1822
|
+
const path = wrapper === undefined ? entry : entry.slice(wrapper.length + 1);
|
|
1823
|
+
const [head] = path.split("/");
|
|
1824
|
+
if (head === undefined || !includeDirs.has(head)) {
|
|
1239
1825
|
continue;
|
|
1240
1826
|
}
|
|
1241
|
-
const
|
|
1242
|
-
if (!
|
|
1827
|
+
const dot = path.lastIndexOf(".");
|
|
1828
|
+
if (dot === -1 || !LIBRARY_SCENE_EXTENSIONS.includes(path.slice(dot).toLowerCase())) {
|
|
1243
1829
|
continue;
|
|
1244
1830
|
}
|
|
1245
|
-
|
|
1831
|
+
if (!isContainedResourcePath(path)) {
|
|
1832
|
+
refused.push(entry);
|
|
1833
|
+
continue;
|
|
1834
|
+
}
|
|
1835
|
+
shared.push({ entry, path });
|
|
1246
1836
|
}
|
|
1247
|
-
|
|
1837
|
+
shared.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1838
|
+
return { shared, reasons: [], refused };
|
|
1248
1839
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1840
|
+
var LIBRARY_DEPENDENCY_ROOT = ".defold-types/dependencies";
|
|
1841
|
+
var LIBRARY_DEPENDENCY_MANIFEST = `${LIBRARY_DEPENDENCY_ROOT}/dependencies.json`;
|
|
1842
|
+
function joinProject(projectRoot, relative) {
|
|
1843
|
+
return `${projectRoot.replace(/\\/g, "/").replace(/\/+$/, "")}/${relative}`;
|
|
1844
|
+
}
|
|
1845
|
+
function readMaterializedKeys(manifestText) {
|
|
1846
|
+
let parsed;
|
|
1847
|
+
try {
|
|
1848
|
+
parsed = JSON.parse(manifestText);
|
|
1849
|
+
} catch {
|
|
1251
1850
|
return;
|
|
1252
1851
|
}
|
|
1253
|
-
|
|
1852
|
+
const entries = parsed?.dependencies;
|
|
1853
|
+
if (!Array.isArray(entries))
|
|
1254
1854
|
return;
|
|
1855
|
+
const keyByUrl = new Map;
|
|
1856
|
+
for (const entry of entries) {
|
|
1857
|
+
const { key, url } = entry ?? {};
|
|
1858
|
+
if (typeof key === "string" && typeof url === "string")
|
|
1859
|
+
keyByUrl.set(url, key);
|
|
1255
1860
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1861
|
+
return keyByUrl;
|
|
1862
|
+
}
|
|
1863
|
+
function readLibrarySceneDocuments(host, projectRoot, extensions = LIBRARY_SCENE_EXTENSIONS) {
|
|
1864
|
+
const documents = [];
|
|
1865
|
+
const unreadable = [];
|
|
1866
|
+
if (!host.readDirectory)
|
|
1867
|
+
return { documents, unreadable };
|
|
1868
|
+
const gameProjectText = host.readFile(joinProject(projectRoot, GAME_PROJECT_DOCUMENT));
|
|
1869
|
+
if (gameProjectText === undefined)
|
|
1870
|
+
return { documents, unreadable };
|
|
1871
|
+
const declared = [...readGameProjectDependencies(gameProjectText)].sort((a, b) => a.index - b.index);
|
|
1872
|
+
if (declared.length === 0)
|
|
1873
|
+
return { documents, unreadable };
|
|
1874
|
+
const manifestText = host.readFile(joinProject(projectRoot, LIBRARY_DEPENDENCY_MANIFEST));
|
|
1875
|
+
if (manifestText === undefined) {
|
|
1876
|
+
for (const { url } of declared) {
|
|
1877
|
+
unreadable.push(`${url}: is declared by game.project but ${LIBRARY_DEPENDENCY_MANIFEST} is absent`);
|
|
1878
|
+
}
|
|
1879
|
+
return { documents, unreadable };
|
|
1259
1880
|
}
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
if (name === undefined) {
|
|
1265
|
-
continue;
|
|
1881
|
+
const keyByUrl = readMaterializedKeys(manifestText);
|
|
1882
|
+
if (keyByUrl === undefined) {
|
|
1883
|
+
for (const { url } of declared) {
|
|
1884
|
+
unreadable.push(`${url}: is declared by game.project but ${LIBRARY_DEPENDENCY_MANIFEST} is not a readable dependency manifest`);
|
|
1266
1885
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1886
|
+
return { documents, unreadable };
|
|
1887
|
+
}
|
|
1888
|
+
const resolved = [];
|
|
1889
|
+
const urlByKey = new Map;
|
|
1890
|
+
for (const { url } of declared) {
|
|
1891
|
+
const key = keyByUrl.get(url);
|
|
1892
|
+
if (key === undefined) {
|
|
1893
|
+
unreadable.push(`${url}: is declared by game.project but was not materialized by the last resolve`);
|
|
1269
1894
|
continue;
|
|
1270
1895
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1896
|
+
resolved.push({ key, url });
|
|
1897
|
+
urlByKey.set(key, url);
|
|
1898
|
+
}
|
|
1899
|
+
const root = joinProject(projectRoot, LIBRARY_DEPENDENCY_ROOT);
|
|
1900
|
+
const filesByKey = new Map;
|
|
1901
|
+
const stray = new Set;
|
|
1902
|
+
for (const filePath of host.readDirectory(root, extensions)) {
|
|
1903
|
+
const relative = displayPathOf(root, filePath);
|
|
1904
|
+
if (relative === filePath.replace(/\\/g, "/"))
|
|
1277
1905
|
continue;
|
|
1278
|
-
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1906
|
+
const separator = relative.indexOf("/");
|
|
1907
|
+
if (separator <= 0)
|
|
1908
|
+
continue;
|
|
1909
|
+
const key = relative.slice(0, separator);
|
|
1910
|
+
const url = urlByKey.get(key);
|
|
1911
|
+
if (url === undefined) {
|
|
1912
|
+
stray.add(key);
|
|
1281
1913
|
continue;
|
|
1282
1914
|
}
|
|
1283
|
-
const
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1289
|
-
function isFactoryOnlyImport(node) {
|
|
1290
|
-
if (!ts2.isStringLiteral(node.moduleSpecifier) || !FACTORY_SPECIFIERS.has(node.moduleSpecifier.text)) {
|
|
1291
|
-
return false;
|
|
1292
|
-
}
|
|
1293
|
-
const clause = node.importClause;
|
|
1294
|
-
if (clause === undefined || clause.name !== undefined) {
|
|
1295
|
-
return false;
|
|
1296
|
-
}
|
|
1297
|
-
if (clause.isTypeOnly) {
|
|
1298
|
-
return false;
|
|
1915
|
+
const bucket = filesByKey.get(key);
|
|
1916
|
+
if (bucket === undefined)
|
|
1917
|
+
filesByKey.set(key, [filePath]);
|
|
1918
|
+
else
|
|
1919
|
+
bucket.push(filePath);
|
|
1299
1920
|
}
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1921
|
+
const claimed = new Map;
|
|
1922
|
+
for (const { key, url } of resolved) {
|
|
1923
|
+
for (const hostPath of (filesByKey.get(key) ?? []).sort()) {
|
|
1924
|
+
const displayPath = displayPathOf(root, hostPath).slice(key.length + 1);
|
|
1925
|
+
if (displayPath === "")
|
|
1926
|
+
continue;
|
|
1927
|
+
const owner = claimed.get(displayPath);
|
|
1928
|
+
if (owner !== undefined) {
|
|
1929
|
+
unreadable.push(`${displayPath}: also declared by ${url}; ${owner}'s file is used`);
|
|
1930
|
+
continue;
|
|
1931
|
+
}
|
|
1932
|
+
const text = host.readFile(hostPath);
|
|
1933
|
+
if (text === undefined) {
|
|
1934
|
+
unreadable.push(`${displayPath}: could not be read from ${url}`);
|
|
1935
|
+
continue;
|
|
1936
|
+
}
|
|
1937
|
+
claimed.set(displayPath, url);
|
|
1938
|
+
documents.push({ displayPath, hostPath, url, text });
|
|
1939
|
+
}
|
|
1303
1940
|
}
|
|
1304
|
-
const
|
|
1305
|
-
|
|
1306
|
-
return false;
|
|
1941
|
+
for (const key of [...stray].sort()) {
|
|
1942
|
+
unreadable.push(`${LIBRARY_DEPENDENCY_ROOT}/${key}: is materialized but no longer declared by game.project, so its scenes are left out`);
|
|
1307
1943
|
}
|
|
1308
|
-
return
|
|
1944
|
+
return { documents, unreadable };
|
|
1309
1945
|
}
|
|
1310
|
-
var lifecycleErasurePlugin = {
|
|
1311
|
-
visitors: {
|
|
1312
|
-
[ts2.SyntaxKind.ExpressionStatement]: (node, context) => eraseFactoryCall(node.expression, context) ?? context.superTransformStatements(node),
|
|
1313
|
-
[ts2.SyntaxKind.ExportAssignment]: (node, context) => {
|
|
1314
|
-
if (!node.isExportEquals) {
|
|
1315
|
-
const erased = eraseFactoryCall(node.expression, context);
|
|
1316
|
-
if (erased !== undefined) {
|
|
1317
|
-
return erased;
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
return context.superTransformStatements(node);
|
|
1321
|
-
},
|
|
1322
|
-
[ts2.SyntaxKind.ImportDeclaration]: (node, context) => isFactoryOnlyImport(node) ? [] : context.superTransformStatements(node)
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
1946
|
// src/main-entry-factory-imports.ts
|
|
1947
|
+
import * as ts4 from "typescript";
|
|
1327
1948
|
function findMainEntryFactoryImports(fileName, source) {
|
|
1328
|
-
const sourceFile =
|
|
1949
|
+
const sourceFile = ts4.createSourceFile(fileName, source, ts4.ScriptTarget.Latest, true);
|
|
1329
1950
|
const factories = [];
|
|
1330
1951
|
for (const statement of sourceFile.statements) {
|
|
1331
|
-
if (!
|
|
1952
|
+
if (!ts4.isImportDeclaration(statement)) {
|
|
1332
1953
|
continue;
|
|
1333
1954
|
}
|
|
1334
1955
|
const specifier = statement.moduleSpecifier;
|
|
1335
|
-
if (!
|
|
1956
|
+
if (!ts4.isStringLiteral(specifier) || specifier.text !== FACTORY_MODULE) {
|
|
1336
1957
|
continue;
|
|
1337
1958
|
}
|
|
1338
1959
|
const bindings = statement.importClause?.namedBindings;
|
|
1339
|
-
if (bindings === undefined || !
|
|
1960
|
+
if (bindings === undefined || !ts4.isNamedImports(bindings)) {
|
|
1340
1961
|
continue;
|
|
1341
1962
|
}
|
|
1342
1963
|
for (const element of bindings.elements) {
|
|
@@ -1381,6 +2002,15 @@ function relUnderOutDir(rel, config) {
|
|
|
1381
2002
|
const relUnderBase = rel.slice(includeBase.length);
|
|
1382
2003
|
return path.posix.join(outDir, relUnderBase);
|
|
1383
2004
|
}
|
|
2005
|
+
function requirePathForRel(rel) {
|
|
2006
|
+
const segments = rel.split("/").filter((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
2007
|
+
const last = segments.length - 1;
|
|
2008
|
+
const lastSegment = segments[last];
|
|
2009
|
+
if (lastSegment !== undefined) {
|
|
2010
|
+
segments[last] = lastSegment.replace(/\.[^.]*$/, "");
|
|
2011
|
+
}
|
|
2012
|
+
return segments.map((segment) => segment.replace(/\./g, "_")).join(".");
|
|
2013
|
+
}
|
|
1384
2014
|
function computeOutputRel(rel, config, kind) {
|
|
1385
2015
|
const baseRel = relUnderOutDir(rel, config);
|
|
1386
2016
|
if (kind === "module") {
|
|
@@ -1389,16 +2019,16 @@ function computeOutputRel(rel, config, kind) {
|
|
|
1389
2019
|
return baseRel.replace(/\.ts$/, SCRIPT_SUFFIX_BY_KIND[kind]);
|
|
1390
2020
|
}
|
|
1391
2021
|
// src/program-diagnostics.ts
|
|
1392
|
-
import * as
|
|
2022
|
+
import * as ts8 from "typescript";
|
|
1393
2023
|
import * as tstl from "typescript-to-lua";
|
|
1394
2024
|
|
|
1395
2025
|
// src/message-guard-lowering.ts
|
|
1396
|
-
import * as
|
|
2026
|
+
import * as ts5 from "typescript";
|
|
1397
2027
|
import {
|
|
1398
2028
|
createBinaryExpression as createBinaryExpression3,
|
|
1399
2029
|
createCallExpression as createCallExpression3,
|
|
1400
2030
|
createIdentifier as createIdentifier3,
|
|
1401
|
-
SyntaxKind as
|
|
2031
|
+
SyntaxKind as SyntaxKind7
|
|
1402
2032
|
} from "typescript-to-lua";
|
|
1403
2033
|
var GUARD_MODULE = "@defold-typescript/types";
|
|
1404
2034
|
var GUARD_NAME = "isMessage";
|
|
@@ -1407,7 +2037,7 @@ function resolvesToGuardExport(callee, checker) {
|
|
|
1407
2037
|
if (symbol === undefined) {
|
|
1408
2038
|
return false;
|
|
1409
2039
|
}
|
|
1410
|
-
if (symbol.flags &
|
|
2040
|
+
if (symbol.flags & ts5.SymbolFlags.Alias) {
|
|
1411
2041
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1412
2042
|
}
|
|
1413
2043
|
if (symbol.getName() !== GUARD_NAME) {
|
|
@@ -1421,12 +2051,12 @@ function resolvesToGuardExport(callee, checker) {
|
|
|
1421
2051
|
}
|
|
1422
2052
|
var messageGuardLoweringPlugin = {
|
|
1423
2053
|
visitors: {
|
|
1424
|
-
[
|
|
2054
|
+
[ts5.SyntaxKind.CallExpression]: (node, context) => {
|
|
1425
2055
|
const [messageIdArg, , expectedArg] = node.arguments;
|
|
1426
2056
|
if (node.arguments.length === 3 && messageIdArg !== undefined && expectedArg !== undefined && resolvesToGuardExport(node.expression, context.checker)) {
|
|
1427
2057
|
const messageId = context.transformExpression(messageIdArg);
|
|
1428
2058
|
const expected = context.transformExpression(expectedArg);
|
|
1429
|
-
return createBinaryExpression3(messageId, createCallExpression3(createIdentifier3("hash"), [expected]),
|
|
2059
|
+
return createBinaryExpression3(messageId, createCallExpression3(createIdentifier3("hash"), [expected]), SyntaxKind7.EqualityOperator, node);
|
|
1430
2060
|
}
|
|
1431
2061
|
return context.superTransformExpression(node);
|
|
1432
2062
|
}
|
|
@@ -1434,77 +2064,34 @@ var messageGuardLoweringPlugin = {
|
|
|
1434
2064
|
};
|
|
1435
2065
|
|
|
1436
2066
|
// src/timers-lowering.ts
|
|
1437
|
-
import * as
|
|
1438
|
-
|
|
1439
|
-
// src/timers-runtime.ts
|
|
1440
|
-
var TIMERS_MODULE_SPECIFIER = "@defold-typescript/types/timers";
|
|
1441
|
-
var TIMERS_REQUIRE_NAME = "defold_typescript_timers";
|
|
1442
|
-
var TIMERS_RUNTIME = `local ____lualib = require("lualib_bundle")
|
|
1443
|
-
local __TS__Promise = ____lualib.__TS__Promise
|
|
1444
|
-
local __TS__New = ____lualib.__TS__New
|
|
1445
|
-
|
|
1446
|
-
local function setTimeout(callback, delayMs)
|
|
1447
|
-
return timer.delay(delayMs / 1000, false, function()
|
|
1448
|
-
callback()
|
|
1449
|
-
end)
|
|
1450
|
-
end
|
|
1451
|
-
|
|
1452
|
-
local function setInterval(callback, delayMs)
|
|
1453
|
-
return timer.delay(delayMs / 1000, true, function()
|
|
1454
|
-
callback()
|
|
1455
|
-
end)
|
|
1456
|
-
end
|
|
1457
|
-
|
|
1458
|
-
local function clearTimeout(handle)
|
|
1459
|
-
timer.cancel(handle)
|
|
1460
|
-
end
|
|
1461
|
-
|
|
1462
|
-
local function clearInterval(handle)
|
|
1463
|
-
timer.cancel(handle)
|
|
1464
|
-
end
|
|
1465
|
-
|
|
1466
|
-
local function wait(seconds)
|
|
1467
|
-
return __TS__New(__TS__Promise, function(_, resolve)
|
|
1468
|
-
timer.delay(seconds, false, function()
|
|
1469
|
-
resolve()
|
|
1470
|
-
end)
|
|
1471
|
-
end)
|
|
1472
|
-
end
|
|
1473
|
-
|
|
1474
|
-
return {
|
|
1475
|
-
setTimeout = setTimeout,
|
|
1476
|
-
setInterval = setInterval,
|
|
1477
|
-
clearTimeout = clearTimeout,
|
|
1478
|
-
clearInterval = clearInterval,
|
|
1479
|
-
wait = wait,
|
|
1480
|
-
}
|
|
1481
|
-
`;
|
|
1482
|
-
|
|
1483
|
-
// src/timers-lowering.ts
|
|
2067
|
+
import * as ts6 from "typescript";
|
|
2068
|
+
import { LuaLibFeature } from "typescript-to-lua";
|
|
1484
2069
|
function isTimersSpecifier(node) {
|
|
1485
|
-
return
|
|
2070
|
+
return ts6.isStringLiteral(node) && node.text === TIMERS_MODULE_SPECIFIER;
|
|
1486
2071
|
}
|
|
1487
2072
|
function importsTimersModule(sourceFile) {
|
|
1488
|
-
return sourceFile.statements.some((statement) =>
|
|
2073
|
+
return sourceFile.statements.some((statement) => ts6.isImportDeclaration(statement) && isTimersSpecifier(statement.moduleSpecifier));
|
|
1489
2074
|
}
|
|
1490
2075
|
var TIMERS_REQUIRE_PATH = `@NoResolution:${TIMERS_REQUIRE_NAME}`;
|
|
1491
2076
|
var timersLoweringPlugin = {
|
|
1492
2077
|
visitors: {
|
|
1493
|
-
[
|
|
2078
|
+
[ts6.SyntaxKind.ImportDeclaration]: (node, context) => {
|
|
1494
2079
|
if (!isTimersSpecifier(node.moduleSpecifier)) {
|
|
1495
2080
|
return context.superTransformStatements(node);
|
|
1496
2081
|
}
|
|
1497
|
-
|
|
2082
|
+
context.usedLuaLibFeatures.add(LuaLibFeature.Promise);
|
|
2083
|
+
context.usedLuaLibFeatures.add(LuaLibFeature.New);
|
|
2084
|
+
const rewritten = ts6.factory.updateImportDeclaration(node, node.modifiers, node.importClause, ts6.factory.createStringLiteral(TIMERS_REQUIRE_PATH), node.attributes);
|
|
1498
2085
|
return context.superTransformStatements(rewritten);
|
|
1499
2086
|
}
|
|
1500
2087
|
}
|
|
1501
2088
|
};
|
|
1502
2089
|
|
|
1503
2090
|
// src/window-event-guard-lowering.ts
|
|
1504
|
-
import * as
|
|
2091
|
+
import * as ts7 from "typescript";
|
|
1505
2092
|
import {
|
|
1506
2093
|
createBinaryExpression as createBinaryExpression4,
|
|
1507
|
-
SyntaxKind as
|
|
2094
|
+
SyntaxKind as SyntaxKind10
|
|
1508
2095
|
} from "typescript-to-lua";
|
|
1509
2096
|
var GUARD_MODULE2 = "@defold-typescript/types";
|
|
1510
2097
|
var GUARD_NAME2 = "isWindowEvent";
|
|
@@ -1513,7 +2100,7 @@ function resolvesToGuardExport2(callee, checker) {
|
|
|
1513
2100
|
if (symbol === undefined) {
|
|
1514
2101
|
return false;
|
|
1515
2102
|
}
|
|
1516
|
-
if (symbol.flags &
|
|
2103
|
+
if (symbol.flags & ts7.SymbolFlags.Alias) {
|
|
1517
2104
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1518
2105
|
}
|
|
1519
2106
|
if (symbol.getName() !== GUARD_NAME2) {
|
|
@@ -1527,12 +2114,12 @@ function resolvesToGuardExport2(callee, checker) {
|
|
|
1527
2114
|
}
|
|
1528
2115
|
var windowEventGuardLoweringPlugin = {
|
|
1529
2116
|
visitors: {
|
|
1530
|
-
[
|
|
2117
|
+
[ts7.SyntaxKind.CallExpression]: (node, context) => {
|
|
1531
2118
|
const [eventArg, , expectedArg] = node.arguments;
|
|
1532
2119
|
if (node.arguments.length === 3 && eventArg !== undefined && expectedArg !== undefined && resolvesToGuardExport2(node.expression, context.checker)) {
|
|
1533
2120
|
const event = context.transformExpression(eventArg);
|
|
1534
2121
|
const expected = context.transformExpression(expectedArg);
|
|
1535
|
-
return createBinaryExpression4(event, expected,
|
|
2122
|
+
return createBinaryExpression4(event, expected, SyntaxKind10.EqualityOperator, node);
|
|
1536
2123
|
}
|
|
1537
2124
|
return context.superTransformExpression(node);
|
|
1538
2125
|
}
|
|
@@ -1552,13 +2139,33 @@ function isAmbient(fileName) {
|
|
|
1552
2139
|
return /[\\/]node_modules[\\/]/.test(fileName) || /(^|[\\/])lib\.[^\\/]*\.d\.ts$/.test(fileName);
|
|
1553
2140
|
}
|
|
1554
2141
|
function getProgramDiagnostics(program, sourceFile) {
|
|
1555
|
-
const { diagnostics } = tstl.getProgramTranspileResult(
|
|
2142
|
+
const { diagnostics } = tstl.getProgramTranspileResult(ts8.sys, noopWriteFile, {
|
|
1556
2143
|
program,
|
|
1557
2144
|
plugins: LUA_PLUGINS,
|
|
1558
2145
|
...sourceFile ? { sourceFiles: [sourceFile] } : {}
|
|
1559
2146
|
});
|
|
1560
2147
|
return diagnostics.filter((d) => d.file !== undefined && !isAmbient(d.file.fileName));
|
|
1561
2148
|
}
|
|
2149
|
+
// src/require-rewrite.ts
|
|
2150
|
+
function quote(value) {
|
|
2151
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
2152
|
+
}
|
|
2153
|
+
function rewriteEmittedRequires(lua, rewrites) {
|
|
2154
|
+
if (rewrites.size === 0) {
|
|
2155
|
+
return lua;
|
|
2156
|
+
}
|
|
2157
|
+
let out = "";
|
|
2158
|
+
let cursor = 0;
|
|
2159
|
+
for (const { path, start, end } of scanEmittedRequires(lua)) {
|
|
2160
|
+
const mapped = rewrites.get(path);
|
|
2161
|
+
if (mapped === undefined) {
|
|
2162
|
+
continue;
|
|
2163
|
+
}
|
|
2164
|
+
out += lua.slice(cursor, start) + quote(mapped);
|
|
2165
|
+
cursor = end;
|
|
2166
|
+
}
|
|
2167
|
+
return cursor === 0 ? lua : out + lua.slice(cursor);
|
|
2168
|
+
}
|
|
1562
2169
|
// src/scene-component-index.ts
|
|
1563
2170
|
var COMPONENT_BLOCKS = new Set(["components", "embedded_components"]);
|
|
1564
2171
|
var EMBEDDING_BLOCKS = new Set(["embedded_instances", "embedded_components"]);
|
|
@@ -2052,13 +2659,441 @@ function relativeAddressesFrom(index, context) {
|
|
|
2052
2659
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
2053
2660
|
import { createRequire as createRequire2 } from "node:module";
|
|
2054
2661
|
import * as path3 from "node:path";
|
|
2055
|
-
import * as
|
|
2662
|
+
import * as ts12 from "typescript";
|
|
2056
2663
|
import * as tstl3 from "typescript-to-lua";
|
|
2057
2664
|
|
|
2665
|
+
// src/companion-emit.ts
|
|
2666
|
+
import * as ts9 from "typescript";
|
|
2667
|
+
import {
|
|
2668
|
+
createAssignmentStatement as createAssignmentStatement2,
|
|
2669
|
+
createCallExpression as createCallExpression4,
|
|
2670
|
+
createFile,
|
|
2671
|
+
createIdentifier as createIdentifier4,
|
|
2672
|
+
createReturnStatement as createReturnStatement2,
|
|
2673
|
+
createStringLiteral as createStringLiteral3,
|
|
2674
|
+
createTableExpression,
|
|
2675
|
+
createTableFieldExpression,
|
|
2676
|
+
createTableIndexExpression as createTableIndexExpression2,
|
|
2677
|
+
createVariableDeclarationStatement as createVariableDeclarationStatement3,
|
|
2678
|
+
isBlock as isBlock3,
|
|
2679
|
+
isCallExpression as isCallExpression4,
|
|
2680
|
+
isDoStatement,
|
|
2681
|
+
isForInStatement as isForInStatement2,
|
|
2682
|
+
isForStatement,
|
|
2683
|
+
isFunctionDefinition,
|
|
2684
|
+
isFunctionExpression as isFunctionExpression4,
|
|
2685
|
+
isIdentifier as isIdentifier4,
|
|
2686
|
+
isMethodCallExpression,
|
|
2687
|
+
isRepeatStatement,
|
|
2688
|
+
isReturnStatement as isReturnStatement2,
|
|
2689
|
+
isStringLiteral as isStringLiteral6,
|
|
2690
|
+
isTableExpression,
|
|
2691
|
+
isVariableDeclarationStatement,
|
|
2692
|
+
LuaPrinter
|
|
2693
|
+
} from "typescript-to-lua";
|
|
2694
|
+
var EXPORTS_NAME = "____exports";
|
|
2695
|
+
function exportsIdentifier() {
|
|
2696
|
+
return createIdentifier4(EXPORTS_NAME);
|
|
2697
|
+
}
|
|
2698
|
+
function isRuntimeScriptSource(sourceFile, checker) {
|
|
2699
|
+
return sourceFile.statements.some((statement) => {
|
|
2700
|
+
const expression = ts9.isExpressionStatement(statement) ? statement.expression : ts9.isExportAssignment(statement) && !statement.isExportEquals ? statement.expression : undefined;
|
|
2701
|
+
return expression !== undefined && ts9.isCallExpression(expression) && resolvesToFactoryExport(expression.expression, checker);
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
function planFor(sourceFile, checker) {
|
|
2705
|
+
if (sourceFile.isDeclarationFile || !isRuntimeScriptSource(sourceFile, checker)) {
|
|
2706
|
+
return;
|
|
2707
|
+
}
|
|
2708
|
+
const closure = computeCompanionClosure(sourceFile, checker);
|
|
2709
|
+
if (closure.statements.length === 0 || closure.violations.length > 0) {
|
|
2710
|
+
return;
|
|
2711
|
+
}
|
|
2712
|
+
return {
|
|
2713
|
+
closureStarts: new Set(closure.statements.map((statement) => statement.pos)),
|
|
2714
|
+
internals: closure.internals,
|
|
2715
|
+
importBindings: closure.importBindings,
|
|
2716
|
+
requirePath: requirePathForRel(sourceFile.fileName)
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
function isLuaNode(value) {
|
|
2720
|
+
return typeof value === "object" && value !== null && typeof value.kind === "number";
|
|
2721
|
+
}
|
|
2722
|
+
function forEachLuaNode(root, visit) {
|
|
2723
|
+
visit(root);
|
|
2724
|
+
for (const value of Object.values(root)) {
|
|
2725
|
+
if (Array.isArray(value)) {
|
|
2726
|
+
for (const element of value) {
|
|
2727
|
+
if (isLuaNode(element)) {
|
|
2728
|
+
forEachLuaNode(element, visit);
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
} else if (isLuaNode(value)) {
|
|
2732
|
+
forEachLuaNode(value, visit);
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
function declaredNames(statement) {
|
|
2737
|
+
return isVariableDeclarationStatement(statement) ? statement.left.map((name) => name.text) : [];
|
|
2738
|
+
}
|
|
2739
|
+
function freeNames(statements) {
|
|
2740
|
+
const free = new Set;
|
|
2741
|
+
const scopes = [new Set];
|
|
2742
|
+
function declare(name) {
|
|
2743
|
+
scopes[scopes.length - 1]?.add(name);
|
|
2744
|
+
}
|
|
2745
|
+
function isBound(name) {
|
|
2746
|
+
return scopes.some((scope) => scope.has(name));
|
|
2747
|
+
}
|
|
2748
|
+
function inScope(run) {
|
|
2749
|
+
scopes.push(new Set);
|
|
2750
|
+
run();
|
|
2751
|
+
scopes.pop();
|
|
2752
|
+
}
|
|
2753
|
+
function visitEach(nodes) {
|
|
2754
|
+
for (const node of nodes ?? []) {
|
|
2755
|
+
visit(node);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
function visit(node) {
|
|
2759
|
+
if (node === undefined) {
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2762
|
+
if (isIdentifier4(node)) {
|
|
2763
|
+
if (!isBound(node.text)) {
|
|
2764
|
+
free.add(node.text);
|
|
2765
|
+
}
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2768
|
+
if (isVariableDeclarationStatement(node)) {
|
|
2769
|
+
if (isFunctionDefinition(node)) {
|
|
2770
|
+
const [name] = node.left;
|
|
2771
|
+
if (name !== undefined) {
|
|
2772
|
+
declare(name.text);
|
|
2773
|
+
}
|
|
2774
|
+
visit(node.right[0]);
|
|
2775
|
+
return;
|
|
2776
|
+
}
|
|
2777
|
+
visitEach(node.right);
|
|
2778
|
+
for (const name of node.left) {
|
|
2779
|
+
declare(name.text);
|
|
2780
|
+
}
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
if (isFunctionExpression4(node)) {
|
|
2784
|
+
inScope(() => {
|
|
2785
|
+
for (const param of node.params ?? []) {
|
|
2786
|
+
declare(param.text);
|
|
2787
|
+
}
|
|
2788
|
+
visit(node.body);
|
|
2789
|
+
});
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
if (isForStatement(node)) {
|
|
2793
|
+
visit(node.controlVariableInitializer);
|
|
2794
|
+
visit(node.limitExpression);
|
|
2795
|
+
visit(node.stepExpression);
|
|
2796
|
+
inScope(() => {
|
|
2797
|
+
declare(node.controlVariable.text);
|
|
2798
|
+
visit(node.body);
|
|
2799
|
+
});
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
if (isForInStatement2(node)) {
|
|
2803
|
+
visitEach(node.expressions);
|
|
2804
|
+
inScope(() => {
|
|
2805
|
+
for (const name of node.names) {
|
|
2806
|
+
declare(name.text);
|
|
2807
|
+
}
|
|
2808
|
+
visit(node.body);
|
|
2809
|
+
});
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
if (isRepeatStatement(node)) {
|
|
2813
|
+
inScope(() => {
|
|
2814
|
+
visitEach(node.body.statements);
|
|
2815
|
+
visit(node.condition);
|
|
2816
|
+
});
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
if (isBlock3(node) || isDoStatement(node)) {
|
|
2820
|
+
inScope(() => visitEach(node.statements));
|
|
2821
|
+
return;
|
|
2822
|
+
}
|
|
2823
|
+
if (isMethodCallExpression(node)) {
|
|
2824
|
+
visit(node.prefixExpression);
|
|
2825
|
+
visitEach(node.params);
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
for (const value of Object.values(node)) {
|
|
2829
|
+
if (Array.isArray(value)) {
|
|
2830
|
+
for (const element of value) {
|
|
2831
|
+
if (isLuaNode(element)) {
|
|
2832
|
+
visit(element);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
} else if (isLuaNode(value)) {
|
|
2836
|
+
visit(value);
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
for (const statement of statements) {
|
|
2841
|
+
for (const name of declaredNames(statement)) {
|
|
2842
|
+
declare(name);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
for (const statement of statements) {
|
|
2846
|
+
visit(statement);
|
|
2847
|
+
}
|
|
2848
|
+
return free;
|
|
2849
|
+
}
|
|
2850
|
+
function resolvedRequirePaths(sourceFile, checker) {
|
|
2851
|
+
const paths = new Map;
|
|
2852
|
+
for (const statement of sourceFile.statements) {
|
|
2853
|
+
const specifier = ts9.isImportDeclaration(statement) || ts9.isExportDeclaration(statement) ? statement.moduleSpecifier : undefined;
|
|
2854
|
+
if (specifier === undefined || !ts9.isStringLiteral(specifier)) {
|
|
2855
|
+
continue;
|
|
2856
|
+
}
|
|
2857
|
+
const target = checker.getSymbolAtLocation(specifier)?.declarations?.find((declaration) => ts9.isSourceFile(declaration));
|
|
2858
|
+
if (target === undefined || target.isDeclarationFile) {
|
|
2859
|
+
continue;
|
|
2860
|
+
}
|
|
2861
|
+
paths.set(specifier.text, requirePathForRel(target.fileName));
|
|
2862
|
+
}
|
|
2863
|
+
return paths;
|
|
2864
|
+
}
|
|
2865
|
+
function resolveMovedRequires(statements, paths) {
|
|
2866
|
+
for (const statement of statements) {
|
|
2867
|
+
forEachLuaNode(statement, (node) => {
|
|
2868
|
+
if (!isCallExpression4(node) || !isIdentifier4(node.expression)) {
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
if (node.expression.text !== "require" || node.params.length !== 1) {
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
const [argument] = node.params;
|
|
2875
|
+
if (argument === undefined || !isStringLiteral6(argument)) {
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
const resolved = paths.get(argument.value);
|
|
2879
|
+
if (resolved !== undefined) {
|
|
2880
|
+
argument.value = resolved;
|
|
2881
|
+
}
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
function withResolvedRequire(statement, paths) {
|
|
2886
|
+
if (!isVariableDeclarationStatement(statement) || statement.left.length !== 1) {
|
|
2887
|
+
return statement;
|
|
2888
|
+
}
|
|
2889
|
+
const name = statement.left[0];
|
|
2890
|
+
const [value] = statement.right ?? [];
|
|
2891
|
+
if (name === undefined || value === undefined || !isCallExpression4(value)) {
|
|
2892
|
+
return statement;
|
|
2893
|
+
}
|
|
2894
|
+
if (!isIdentifier4(value.expression) || value.expression.text !== "require") {
|
|
2895
|
+
return statement;
|
|
2896
|
+
}
|
|
2897
|
+
const [argument] = value.params;
|
|
2898
|
+
if (argument === undefined || !isStringLiteral6(argument)) {
|
|
2899
|
+
return statement;
|
|
2900
|
+
}
|
|
2901
|
+
const resolved = paths.get(argument.value);
|
|
2902
|
+
if (resolved === undefined) {
|
|
2903
|
+
return statement;
|
|
2904
|
+
}
|
|
2905
|
+
return createVariableDeclarationStatement3(createIdentifier4(name.text), createCallExpression4(createIdentifier4("require"), [createStringLiteral3(resolved)]));
|
|
2906
|
+
}
|
|
2907
|
+
function copiedPrelude(halves, importBindings) {
|
|
2908
|
+
const needed = new Set(importBindings);
|
|
2909
|
+
for (const name of freeNames(halves.companion)) {
|
|
2910
|
+
needed.add(name);
|
|
2911
|
+
}
|
|
2912
|
+
const alreadyCarried = new Set(halves.companion);
|
|
2913
|
+
const candidates = halves.script.filter((statement) => isVariableDeclarationStatement(statement) && !alreadyCarried.has(statement));
|
|
2914
|
+
const copied = new Set;
|
|
2915
|
+
let grew = true;
|
|
2916
|
+
while (grew) {
|
|
2917
|
+
grew = false;
|
|
2918
|
+
for (const statement of candidates) {
|
|
2919
|
+
if (copied.has(statement) || !declaredNames(statement).some((name) => needed.has(name))) {
|
|
2920
|
+
continue;
|
|
2921
|
+
}
|
|
2922
|
+
copied.add(statement);
|
|
2923
|
+
for (const name of freeNames([statement])) {
|
|
2924
|
+
needed.add(name);
|
|
2925
|
+
}
|
|
2926
|
+
grew = true;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
return halves.script.filter((statement) => copied.has(statement));
|
|
2930
|
+
}
|
|
2931
|
+
function namesIdentifier(statement, names) {
|
|
2932
|
+
let found = false;
|
|
2933
|
+
forEachLuaNode(statement, (node) => {
|
|
2934
|
+
if (isIdentifier4(node) && names.has(node.text)) {
|
|
2935
|
+
found = true;
|
|
2936
|
+
}
|
|
2937
|
+
});
|
|
2938
|
+
return found;
|
|
2939
|
+
}
|
|
2940
|
+
function isExportsTableInit(statement) {
|
|
2941
|
+
if (!isVariableDeclarationStatement(statement) || statement.left.length !== 1) {
|
|
2942
|
+
return false;
|
|
2943
|
+
}
|
|
2944
|
+
const [single] = statement.right ?? [];
|
|
2945
|
+
return statement.left[0]?.text === EXPORTS_NAME && single !== undefined && isTableExpression(single);
|
|
2946
|
+
}
|
|
2947
|
+
function isExportsReturn(statement) {
|
|
2948
|
+
if (!isReturnStatement2(statement) || statement.expressions.length !== 1) {
|
|
2949
|
+
return false;
|
|
2950
|
+
}
|
|
2951
|
+
const [single] = statement.expressions;
|
|
2952
|
+
return single !== undefined && isIdentifier4(single) && single.text === EXPORTS_NAME;
|
|
2953
|
+
}
|
|
2954
|
+
function isHoistedNameDeclaration(statement) {
|
|
2955
|
+
return isVariableDeclarationStatement(statement) && statement.right === undefined;
|
|
2956
|
+
}
|
|
2957
|
+
function internalsField(name) {
|
|
2958
|
+
return createTableIndexExpression2(createTableIndexExpression2(exportsIdentifier(), createStringLiteral3(COMPANION_INTERNAL_FIELD)), createStringLiteral3(name));
|
|
2959
|
+
}
|
|
2960
|
+
function requireInsertionPoint(script, reads) {
|
|
2961
|
+
let index = 0;
|
|
2962
|
+
while (index < script.length) {
|
|
2963
|
+
const statement = script[index];
|
|
2964
|
+
if (statement === undefined || !isVariableDeclarationStatement(statement)) {
|
|
2965
|
+
break;
|
|
2966
|
+
}
|
|
2967
|
+
if (namesIdentifier(statement, reads)) {
|
|
2968
|
+
break;
|
|
2969
|
+
}
|
|
2970
|
+
index++;
|
|
2971
|
+
}
|
|
2972
|
+
return index;
|
|
2973
|
+
}
|
|
2974
|
+
function split(statements, owned) {
|
|
2975
|
+
const script = [];
|
|
2976
|
+
const companion = [];
|
|
2977
|
+
for (const statement of statements) {
|
|
2978
|
+
if (isExportsTableInit(statement) || isExportsReturn(statement)) {
|
|
2979
|
+
continue;
|
|
2980
|
+
}
|
|
2981
|
+
if (owned.has(statement)) {
|
|
2982
|
+
companion.push(statement);
|
|
2983
|
+
continue;
|
|
2984
|
+
}
|
|
2985
|
+
if (isHoistedNameDeclaration(statement)) {
|
|
2986
|
+
companion.push(statement);
|
|
2987
|
+
}
|
|
2988
|
+
script.push(statement);
|
|
2989
|
+
}
|
|
2990
|
+
return { script, companion };
|
|
2991
|
+
}
|
|
2992
|
+
function createCompanionEmitPlugin() {
|
|
2993
|
+
const plans = new Map;
|
|
2994
|
+
const owned = new Map;
|
|
2995
|
+
const companions = new Map;
|
|
2996
|
+
function planOf(sourceFile, checker) {
|
|
2997
|
+
const key = sourceFile.fileName;
|
|
2998
|
+
if (!plans.has(key)) {
|
|
2999
|
+
plans.set(key, planFor(sourceFile, checker));
|
|
3000
|
+
}
|
|
3001
|
+
return plans.get(key);
|
|
3002
|
+
}
|
|
3003
|
+
function capture(node, context) {
|
|
3004
|
+
const statements = context.superTransformStatements(node);
|
|
3005
|
+
const sourceFile = context.sourceFile;
|
|
3006
|
+
const plan = planOf(sourceFile, context.checker);
|
|
3007
|
+
if (plan === undefined || !plan.closureStarts.has(node.pos)) {
|
|
3008
|
+
return statements;
|
|
3009
|
+
}
|
|
3010
|
+
let bucket = owned.get(sourceFile.fileName);
|
|
3011
|
+
if (bucket === undefined) {
|
|
3012
|
+
bucket = new Set;
|
|
3013
|
+
owned.set(sourceFile.fileName, bucket);
|
|
3014
|
+
}
|
|
3015
|
+
for (const statement of statements) {
|
|
3016
|
+
bucket.add(statement);
|
|
3017
|
+
}
|
|
3018
|
+
return statements;
|
|
3019
|
+
}
|
|
3020
|
+
const visitors = {
|
|
3021
|
+
[ts9.SyntaxKind.VariableStatement]: capture,
|
|
3022
|
+
[ts9.SyntaxKind.FunctionDeclaration]: capture,
|
|
3023
|
+
[ts9.SyntaxKind.ClassDeclaration]: capture,
|
|
3024
|
+
[ts9.SyntaxKind.EnumDeclaration]: capture,
|
|
3025
|
+
[ts9.SyntaxKind.ExportDeclaration]: capture
|
|
3026
|
+
};
|
|
3027
|
+
let configuredNoResolvePaths = [];
|
|
3028
|
+
const plugin = {
|
|
3029
|
+
visitors,
|
|
3030
|
+
beforeTransform(_program, options) {
|
|
3031
|
+
configuredNoResolvePaths = options.noResolvePaths ?? [];
|
|
3032
|
+
},
|
|
3033
|
+
afterPrint(program, options, emitHost, result) {
|
|
3034
|
+
const emitted = [];
|
|
3035
|
+
for (const file of result) {
|
|
3036
|
+
const sourceFile = file.sourceFiles?.[0];
|
|
3037
|
+
if (sourceFile === undefined || file.luaAst === undefined) {
|
|
3038
|
+
continue;
|
|
3039
|
+
}
|
|
3040
|
+
const plan = plans.get(sourceFile.fileName);
|
|
3041
|
+
const bucket = owned.get(sourceFile.fileName);
|
|
3042
|
+
if (plan === undefined || bucket === undefined || bucket.size === 0) {
|
|
3043
|
+
continue;
|
|
3044
|
+
}
|
|
3045
|
+
emitCompanion(program, emitHost, file, sourceFile, plan, bucket, companions);
|
|
3046
|
+
emitted.push(plan.requirePath);
|
|
3047
|
+
}
|
|
3048
|
+
if (emitted.length > 0) {
|
|
3049
|
+
options.noResolvePaths = [...configuredNoResolvePaths, ...emitted];
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
};
|
|
3053
|
+
return { plugin, companions };
|
|
3054
|
+
}
|
|
3055
|
+
function emitCompanion(program, emitHost, file, sourceFile, plan, owned, companions) {
|
|
3056
|
+
const luaAst = file.luaAst;
|
|
3057
|
+
if (luaAst === undefined) {
|
|
3058
|
+
return;
|
|
3059
|
+
}
|
|
3060
|
+
const halves = split(luaAst.statements, owned);
|
|
3061
|
+
const requirePaths = resolvedRequirePaths(sourceFile, program.getTypeChecker());
|
|
3062
|
+
resolveMovedRequires(halves.companion, requirePaths);
|
|
3063
|
+
const closureTable = createTableExpression(plan.internals.map((name) => createTableFieldExpression(createIdentifier4(name), createStringLiteral3(name))));
|
|
3064
|
+
const companionStatements = [
|
|
3065
|
+
createVariableDeclarationStatement3(exportsIdentifier(), createTableExpression()),
|
|
3066
|
+
...copiedPrelude(halves, plan.importBindings).map((statement) => withResolvedRequire(statement, requirePaths)),
|
|
3067
|
+
...halves.companion,
|
|
3068
|
+
...plan.internals.length > 0 ? [
|
|
3069
|
+
createAssignmentStatement2(createTableIndexExpression2(exportsIdentifier(), createStringLiteral3(COMPANION_INTERNAL_FIELD)), closureTable)
|
|
3070
|
+
] : [],
|
|
3071
|
+
createReturnStatement2([exportsIdentifier()])
|
|
3072
|
+
];
|
|
3073
|
+
const reads = new Set([EXPORTS_NAME, ...plan.internals]);
|
|
3074
|
+
const insertAt = requireInsertionPoint(halves.script, reads);
|
|
3075
|
+
const scriptStatements = [
|
|
3076
|
+
...halves.script.slice(0, insertAt),
|
|
3077
|
+
createVariableDeclarationStatement3(exportsIdentifier(), createCallExpression4(createIdentifier4("require"), [createStringLiteral3(plan.requirePath)])),
|
|
3078
|
+
...plan.internals.map((name) => createVariableDeclarationStatement3(createIdentifier4(name), internalsField(name))),
|
|
3079
|
+
...halves.script.slice(insertAt),
|
|
3080
|
+
createReturnStatement2([exportsIdentifier()])
|
|
3081
|
+
];
|
|
3082
|
+
const features = new Set(luaAst.luaLibFeatures);
|
|
3083
|
+
const printer = new LuaPrinter(emitHost, program, sourceFile.fileName);
|
|
3084
|
+
companions.set(sourceFile.fileName, printer.print(createFile(companionStatements, new Set(features), luaAst.trivia, sourceFile)).code);
|
|
3085
|
+
const scriptFile = createFile(scriptStatements, features, luaAst.trivia, sourceFile);
|
|
3086
|
+
const printed = new LuaPrinter(emitHost, program, sourceFile.fileName).print(scriptFile);
|
|
3087
|
+
file.luaAst = scriptFile;
|
|
3088
|
+
file.code = printed.code;
|
|
3089
|
+
file.sourceMap = printed.sourceMap;
|
|
3090
|
+
file.sourceMapNode = printed.sourceMapNode;
|
|
3091
|
+
}
|
|
3092
|
+
|
|
2058
3093
|
// src/editor-script-erasure.ts
|
|
2059
|
-
import * as
|
|
3094
|
+
import * as ts10 from "typescript";
|
|
2060
3095
|
import {
|
|
2061
|
-
createReturnStatement as
|
|
3096
|
+
createReturnStatement as createReturnStatement3
|
|
2062
3097
|
} from "typescript-to-lua";
|
|
2063
3098
|
var EDITOR_FACTORY_MODULE = "@defold-typescript/types";
|
|
2064
3099
|
var EDITOR_SCRIPT_FACTORY_NAME = "defineEditorScript";
|
|
@@ -2076,7 +3111,7 @@ function resolveEditorFactoryExport(callee, checker) {
|
|
|
2076
3111
|
if (symbol === undefined) {
|
|
2077
3112
|
return;
|
|
2078
3113
|
}
|
|
2079
|
-
if (symbol.flags &
|
|
3114
|
+
if (symbol.flags & ts10.SymbolFlags.Alias) {
|
|
2080
3115
|
symbol = checker.getAliasedSymbol(symbol);
|
|
2081
3116
|
}
|
|
2082
3117
|
const name = symbol.getName();
|
|
@@ -2090,7 +3125,7 @@ function resolveEditorFactoryExport(callee, checker) {
|
|
|
2090
3125
|
return declaration.getSourceFile().fileName.includes(EDITOR_FACTORY_MODULE) ? name : undefined;
|
|
2091
3126
|
}
|
|
2092
3127
|
function lowerEditorFactoryCall(expression, context) {
|
|
2093
|
-
if (!
|
|
3128
|
+
if (!ts10.isCallExpression(expression)) {
|
|
2094
3129
|
return;
|
|
2095
3130
|
}
|
|
2096
3131
|
if (resolveEditorFactoryExport(expression.expression, context.checker) !== EDITOR_SCRIPT_FACTORY_NAME) {
|
|
@@ -2100,10 +3135,10 @@ function lowerEditorFactoryCall(expression, context) {
|
|
|
2100
3135
|
if (module === undefined) {
|
|
2101
3136
|
return;
|
|
2102
3137
|
}
|
|
2103
|
-
return [
|
|
3138
|
+
return [createReturnStatement3([context.transformExpression(module)])];
|
|
2104
3139
|
}
|
|
2105
3140
|
function isEditorFactoryOnlyImport(node) {
|
|
2106
|
-
if (!
|
|
3141
|
+
if (!ts10.isStringLiteral(node.moduleSpecifier) || !EDITOR_FACTORY_SPECIFIERS.has(node.moduleSpecifier.text)) {
|
|
2107
3142
|
return false;
|
|
2108
3143
|
}
|
|
2109
3144
|
const clause = node.importClause;
|
|
@@ -2114,7 +3149,7 @@ function isEditorFactoryOnlyImport(node) {
|
|
|
2114
3149
|
return false;
|
|
2115
3150
|
}
|
|
2116
3151
|
const bindings = clause.namedBindings;
|
|
2117
|
-
if (bindings === undefined || !
|
|
3152
|
+
if (bindings === undefined || !ts10.isNamedImports(bindings)) {
|
|
2118
3153
|
return false;
|
|
2119
3154
|
}
|
|
2120
3155
|
const runtime = bindings.elements.filter((element) => !element.isTypeOnly);
|
|
@@ -2125,7 +3160,7 @@ function isEditorFactoryOnlyImport(node) {
|
|
|
2125
3160
|
}
|
|
2126
3161
|
var editorScriptErasurePlugin = {
|
|
2127
3162
|
visitors: {
|
|
2128
|
-
[
|
|
3163
|
+
[ts10.SyntaxKind.ExportAssignment]: (node, context) => {
|
|
2129
3164
|
if (!node.isExportEquals) {
|
|
2130
3165
|
const lowered = lowerEditorFactoryCall(node.expression, context);
|
|
2131
3166
|
if (lowered !== undefined) {
|
|
@@ -2134,14 +3169,14 @@ var editorScriptErasurePlugin = {
|
|
|
2134
3169
|
}
|
|
2135
3170
|
return context.superTransformStatements(node);
|
|
2136
3171
|
},
|
|
2137
|
-
[
|
|
3172
|
+
[ts10.SyntaxKind.CallExpression]: (node, context) => {
|
|
2138
3173
|
const command = node.arguments[0];
|
|
2139
3174
|
if (command !== undefined && resolveEditorFactoryExport(node.expression, context.checker) === EDITOR_COMMAND_FACTORY_NAME) {
|
|
2140
3175
|
return context.transformExpression(command);
|
|
2141
3176
|
}
|
|
2142
3177
|
return context.superTransformExpression(node);
|
|
2143
3178
|
},
|
|
2144
|
-
[
|
|
3179
|
+
[ts10.SyntaxKind.ImportDeclaration]: (node, context) => isEditorFactoryOnlyImport(node) ? [] : context.superTransformStatements(node)
|
|
2145
3180
|
}
|
|
2146
3181
|
};
|
|
2147
3182
|
|
|
@@ -2152,17 +3187,17 @@ import * as path2 from "node:path";
|
|
|
2152
3187
|
import * as tstl2 from "typescript-to-lua";
|
|
2153
3188
|
|
|
2154
3189
|
// src/go-property-direct-call.ts
|
|
2155
|
-
import * as
|
|
3190
|
+
import * as ts11 from "typescript";
|
|
2156
3191
|
var GO_PROPERTY_DIRECT_CALL_MESSAGE = "`go.property` called directly is deprecated; declare the property in `defineScript({ properties })` so it types onto `self` (the transpiler emits the registration for you).";
|
|
2157
3192
|
function findDirectGoPropertyCalls(sourceFile) {
|
|
2158
3193
|
const calls = [];
|
|
2159
3194
|
const visit = (node) => {
|
|
2160
|
-
if (
|
|
3195
|
+
if (ts11.isCallExpression(node) && ts11.isPropertyAccessExpression(node.expression) && node.expression.name.text === "property" && ts11.isIdentifier(node.expression.expression) && node.expression.expression.text === "go") {
|
|
2161
3196
|
calls.push(node);
|
|
2162
3197
|
}
|
|
2163
|
-
|
|
3198
|
+
ts11.forEachChild(node, visit);
|
|
2164
3199
|
};
|
|
2165
|
-
|
|
3200
|
+
ts11.forEachChild(sourceFile, visit);
|
|
2166
3201
|
return calls;
|
|
2167
3202
|
}
|
|
2168
3203
|
|
|
@@ -2261,9 +3296,10 @@ var LUALIB_BUNDLE_NAME = "lualib_bundle.lua";
|
|
|
2261
3296
|
function isLualibBundle(file) {
|
|
2262
3297
|
return file.sourceFiles.length === 0 && file.outPath.endsWith(LUALIB_BUNDLE_NAME);
|
|
2263
3298
|
}
|
|
2264
|
-
function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
3299
|
+
function collectOutputs(transpiledFiles, diagnostics, userKeys, emittedCompanions = new Map) {
|
|
2265
3300
|
const lua = {};
|
|
2266
3301
|
const sourceMaps = {};
|
|
3302
|
+
const companions = {};
|
|
2267
3303
|
let lualib;
|
|
2268
3304
|
for (const file of transpiledFiles) {
|
|
2269
3305
|
if (isLualibBundle(file) && typeof file.lua === "string") {
|
|
@@ -2278,6 +3314,10 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2278
3314
|
if (typeof file.luaSourceMap === "string") {
|
|
2279
3315
|
sourceMaps[userSource.fileName] = file.luaSourceMap;
|
|
2280
3316
|
}
|
|
3317
|
+
const companion = emittedCompanions.get(userSource.fileName);
|
|
3318
|
+
if (companion !== undefined) {
|
|
3319
|
+
companions[userSource.fileName] = companion;
|
|
3320
|
+
}
|
|
2281
3321
|
}
|
|
2282
3322
|
const collectedDiagnostics = diagnostics.map((d) => {
|
|
2283
3323
|
const fileName = d.file?.fileName;
|
|
@@ -2315,6 +3355,7 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2315
3355
|
lua,
|
|
2316
3356
|
sourceMaps,
|
|
2317
3357
|
diagnostics: collectedDiagnostics,
|
|
3358
|
+
...Object.keys(companions).length > 0 ? { companions } : {},
|
|
2318
3359
|
...lualib !== undefined ? { lualib } : {},
|
|
2319
3360
|
...timersImported ? { timersRuntime: TIMERS_RUNTIME } : {}
|
|
2320
3361
|
};
|
|
@@ -2322,6 +3363,7 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2322
3363
|
function transpileProject(input) {
|
|
2323
3364
|
const userKeys = new Set(Object.keys(input.files));
|
|
2324
3365
|
const merged = { ...AMBIENT_FILES, ...input.files };
|
|
3366
|
+
const companionEmit = createCompanionEmitPlugin();
|
|
2325
3367
|
const result = tstl2.transpileVirtualProject(merged, {
|
|
2326
3368
|
luaTarget: tstl2.LuaTarget.Lua51,
|
|
2327
3369
|
sourceMap: true,
|
|
@@ -2334,10 +3376,11 @@ function transpileProject(input) {
|
|
|
2334
3376
|
{ plugin: messageGuardLoweringPlugin },
|
|
2335
3377
|
{ plugin: windowEventGuardLoweringPlugin },
|
|
2336
3378
|
{ plugin: messageDispatchLoweringPlugin },
|
|
2337
|
-
{ plugin: timersLoweringPlugin }
|
|
3379
|
+
{ plugin: timersLoweringPlugin },
|
|
3380
|
+
{ plugin: companionEmit.plugin }
|
|
2338
3381
|
]
|
|
2339
3382
|
});
|
|
2340
|
-
return collectOutputs(result.transpiledFiles, result.diagnostics, userKeys);
|
|
3383
|
+
return collectOutputs(result.transpiledFiles, result.diagnostics, userKeys, companionEmit.companions);
|
|
2341
3384
|
}
|
|
2342
3385
|
function transpile(source) {
|
|
2343
3386
|
const project = transpileProject({ files: { "main.ts": source } });
|
|
@@ -2350,21 +3393,24 @@ function transpile(source) {
|
|
|
2350
3393
|
|
|
2351
3394
|
// src/session.ts
|
|
2352
3395
|
var requireFromHere2 = createRequire2(import.meta.url);
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
}
|
|
3396
|
+
function compilerOptions(companionEmit) {
|
|
3397
|
+
return {
|
|
3398
|
+
luaTarget: tstl3.LuaTarget.Lua51,
|
|
3399
|
+
sourceMap: true,
|
|
3400
|
+
lib: ["lib.es2022.d.ts"],
|
|
3401
|
+
skipLibCheck: true,
|
|
3402
|
+
noImplicitSelf: true,
|
|
3403
|
+
luaPlugins: [
|
|
3404
|
+
{ plugin: lifecycleErasurePlugin },
|
|
3405
|
+
{ plugin: editorScriptErasurePlugin },
|
|
3406
|
+
{ plugin: messageGuardLoweringPlugin },
|
|
3407
|
+
{ plugin: windowEventGuardLoweringPlugin },
|
|
3408
|
+
{ plugin: messageDispatchLoweringPlugin },
|
|
3409
|
+
{ plugin: timersLoweringPlugin },
|
|
3410
|
+
{ plugin: companionEmit.plugin }
|
|
3411
|
+
]
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
2368
3414
|
function normalizeSlashes(p) {
|
|
2369
3415
|
return p.replace(/\\/g, "/");
|
|
2370
3416
|
}
|
|
@@ -2403,7 +3449,7 @@ function createTranspileSession() {
|
|
|
2403
3449
|
if (cached) {
|
|
2404
3450
|
return cached;
|
|
2405
3451
|
}
|
|
2406
|
-
const created =
|
|
3452
|
+
const created = ts12.createSourceFile(fileName, content, ts12.ScriptTarget.Latest, false);
|
|
2407
3453
|
sourceFileCache.set(normalized, created);
|
|
2408
3454
|
return created;
|
|
2409
3455
|
}
|
|
@@ -2422,7 +3468,7 @@ function createTranspileSession() {
|
|
|
2422
3468
|
return cached;
|
|
2423
3469
|
}
|
|
2424
3470
|
const fileContent = readFileSync2(filePath, "utf8");
|
|
2425
|
-
const created =
|
|
3471
|
+
const created = ts12.createSourceFile(filePath, fileContent, ts12.ScriptTarget.Latest, false);
|
|
2426
3472
|
libCache.set(fileName, created);
|
|
2427
3473
|
return created;
|
|
2428
3474
|
}
|
|
@@ -2435,10 +3481,10 @@ function createTranspileSession() {
|
|
|
2435
3481
|
return AMBIENT_FILES[normalized];
|
|
2436
3482
|
}
|
|
2437
3483
|
const host = {
|
|
2438
|
-
fileExists: (fileName) => mergedContent(normalizeSlashes(fileName)) !== undefined ||
|
|
3484
|
+
fileExists: (fileName) => mergedContent(normalizeSlashes(fileName)) !== undefined || ts12.sys.fileExists(fileName),
|
|
2439
3485
|
getCanonicalFileName: (fileName) => fileName,
|
|
2440
3486
|
getCurrentDirectory: () => "",
|
|
2441
|
-
getDefaultLibFileName:
|
|
3487
|
+
getDefaultLibFileName: ts12.getDefaultLibFileName,
|
|
2442
3488
|
readFile: () => "",
|
|
2443
3489
|
getNewLine: () => `
|
|
2444
3490
|
`,
|
|
@@ -2459,17 +3505,18 @@ function createTranspileSession() {
|
|
|
2459
3505
|
}
|
|
2460
3506
|
const userKeys = new Set(userFiles.keys());
|
|
2461
3507
|
const rootNames = [...Object.keys(AMBIENT_FILES).map(normalizeSlashes), ...userKeys];
|
|
2462
|
-
|
|
2463
|
-
|
|
3508
|
+
const companionEmit = createCompanionEmitPlugin();
|
|
3509
|
+
program = ts12.createProgram(rootNames, compilerOptions(companionEmit), host, program);
|
|
3510
|
+
const preEmitDiagnostics = ts12.getPreEmitDiagnostics(program);
|
|
2464
3511
|
const collector = createOutputCollector();
|
|
2465
3512
|
const { diagnostics: transpileDiagnostics } = new tstl3.Transpiler().emit({
|
|
2466
3513
|
program,
|
|
2467
3514
|
writeFile: collector.writeFile
|
|
2468
3515
|
});
|
|
2469
3516
|
const diagnostics = [
|
|
2470
|
-
...
|
|
3517
|
+
...ts12.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics])
|
|
2471
3518
|
];
|
|
2472
|
-
return collectOutputs(collector.files, diagnostics, userKeys);
|
|
3519
|
+
return collectOutputs(collector.files, diagnostics, userKeys, companionEmit.companions);
|
|
2473
3520
|
}
|
|
2474
3521
|
return {
|
|
2475
3522
|
update,
|
|
@@ -2477,7 +3524,7 @@ function createTranspileSession() {
|
|
|
2477
3524
|
};
|
|
2478
3525
|
}
|
|
2479
3526
|
// src/url-address-slots.ts
|
|
2480
|
-
import * as
|
|
3527
|
+
import * as ts13 from "typescript";
|
|
2481
3528
|
var ADDRESS_CLASSES = {
|
|
2482
3529
|
"game-object": true,
|
|
2483
3530
|
component: true,
|
|
@@ -2496,7 +3543,7 @@ function isFragmentCaret(slot, position) {
|
|
|
2496
3543
|
return slot.fragmentStart !== -1 && position >= slot.fragmentStart;
|
|
2497
3544
|
}
|
|
2498
3545
|
function tableKey(checker, callee) {
|
|
2499
|
-
const symbol = checker.getSymbolAtLocation(
|
|
3546
|
+
const symbol = checker.getSymbolAtLocation(ts13.isIdentifier(callee) ? callee : callee.name);
|
|
2500
3547
|
if (!symbol)
|
|
2501
3548
|
return;
|
|
2502
3549
|
const fqn = checker.getFullyQualifiedName(symbol);
|
|
@@ -2504,43 +3551,43 @@ function tableKey(checker, callee) {
|
|
|
2504
3551
|
}
|
|
2505
3552
|
function parameterName(checker, call, index) {
|
|
2506
3553
|
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
2507
|
-
if (!declaration || !
|
|
3554
|
+
if (!declaration || !ts13.isFunctionLike(declaration))
|
|
2508
3555
|
return;
|
|
2509
3556
|
const parameter = declaration.parameters[index];
|
|
2510
|
-
if (!parameter || parameter.dotDotDotToken || !
|
|
3557
|
+
if (!parameter || parameter.dotDotDotToken || !ts13.isIdentifier(parameter.name))
|
|
2511
3558
|
return;
|
|
2512
3559
|
return parameter.name.text;
|
|
2513
3560
|
}
|
|
2514
3561
|
var EQUALITY_OPERATORS = new Set([
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
3562
|
+
ts13.SyntaxKind.EqualsEqualsEqualsToken,
|
|
3563
|
+
ts13.SyntaxKind.ExclamationEqualsEqualsToken,
|
|
3564
|
+
ts13.SyntaxKind.EqualsEqualsToken,
|
|
3565
|
+
ts13.SyntaxKind.ExclamationEqualsToken
|
|
2519
3566
|
]);
|
|
2520
3567
|
function comparisonSatisfied(checker, entry, call) {
|
|
2521
3568
|
if (entry.comparedParameter === undefined)
|
|
2522
3569
|
return true;
|
|
2523
3570
|
let node = call;
|
|
2524
|
-
while (
|
|
3571
|
+
while (ts13.isParenthesizedExpression(node.parent))
|
|
2525
3572
|
node = node.parent;
|
|
2526
3573
|
const comparison = node.parent;
|
|
2527
|
-
if (!
|
|
3574
|
+
if (!ts13.isBinaryExpression(comparison))
|
|
2528
3575
|
return false;
|
|
2529
3576
|
if (!EQUALITY_OPERATORS.has(comparison.operatorToken.kind))
|
|
2530
3577
|
return false;
|
|
2531
3578
|
const other = comparison.left === node ? comparison.right : comparison.left;
|
|
2532
3579
|
const symbol = checker.getSymbolAtLocation(other);
|
|
2533
|
-
return (symbol?.declarations ?? []).some((declaration) =>
|
|
3580
|
+
return (symbol?.declarations ?? []).some((declaration) => ts13.isParameter(declaration) && ts13.isIdentifier(declaration.name) && declaration.name.text === entry.comparedParameter);
|
|
2534
3581
|
}
|
|
2535
3582
|
function classifiedEntryOfArgument(checker, table, argument) {
|
|
2536
3583
|
const call = argument.parent;
|
|
2537
|
-
if (!
|
|
3584
|
+
if (!ts13.isCallExpression(call))
|
|
2538
3585
|
return;
|
|
2539
3586
|
const argumentIndex = call.arguments.indexOf(argument);
|
|
2540
3587
|
if (argumentIndex === -1)
|
|
2541
3588
|
return;
|
|
2542
3589
|
const callee = call.expression;
|
|
2543
|
-
if (!
|
|
3590
|
+
if (!ts13.isPropertyAccessExpression(callee) && !ts13.isIdentifier(callee))
|
|
2544
3591
|
return;
|
|
2545
3592
|
const fqn = tableKey(checker, callee);
|
|
2546
3593
|
if (fqn === undefined)
|
|
@@ -2557,10 +3604,10 @@ function classifiedEntryOfArgument(checker, table, argument) {
|
|
|
2557
3604
|
}
|
|
2558
3605
|
function slotThroughHashedCall(checker, table, literal) {
|
|
2559
3606
|
const call = literal.parent;
|
|
2560
|
-
if (!
|
|
3607
|
+
if (!ts13.isCallExpression(call))
|
|
2561
3608
|
return;
|
|
2562
3609
|
const callee = call.expression;
|
|
2563
|
-
if (!
|
|
3610
|
+
if (!ts13.isPropertyAccessExpression(callee) && !ts13.isIdentifier(callee))
|
|
2564
3611
|
return;
|
|
2565
3612
|
if (tableKey(checker, callee) !== "hash")
|
|
2566
3613
|
return;
|
|
@@ -2578,24 +3625,24 @@ function addressTextOf(checker, entry, call) {
|
|
|
2578
3625
|
if (entry.addressParameter === undefined)
|
|
2579
3626
|
return;
|
|
2580
3627
|
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
2581
|
-
if (!declaration || !
|
|
3628
|
+
if (!declaration || !ts13.isFunctionLike(declaration))
|
|
2582
3629
|
return;
|
|
2583
|
-
const index = declaration.parameters.findIndex((parameter) => !parameter.dotDotDotToken &&
|
|
3630
|
+
const index = declaration.parameters.findIndex((parameter) => !parameter.dotDotDotToken && ts13.isIdentifier(parameter.name) && parameter.name.text === entry.addressParameter);
|
|
2584
3631
|
if (index === -1)
|
|
2585
3632
|
return;
|
|
2586
3633
|
const argument = call.arguments[index];
|
|
2587
|
-
return argument &&
|
|
3634
|
+
return argument && ts13.isStringLiteralLike(argument) ? argument.text : undefined;
|
|
2588
3635
|
}
|
|
2589
3636
|
function innermostLiteralAt(sourceFile, position) {
|
|
2590
3637
|
let found;
|
|
2591
3638
|
const visit = (node) => {
|
|
2592
3639
|
if (position < node.getStart(sourceFile) || position > node.getEnd())
|
|
2593
3640
|
return;
|
|
2594
|
-
if (
|
|
3641
|
+
if (ts13.isStringLiteralLike(node))
|
|
2595
3642
|
found = node;
|
|
2596
|
-
|
|
3643
|
+
ts13.forEachChild(node, visit);
|
|
2597
3644
|
};
|
|
2598
|
-
|
|
3645
|
+
ts13.forEachChild(sourceFile, visit);
|
|
2599
3646
|
return found;
|
|
2600
3647
|
}
|
|
2601
3648
|
function resolveClassifiedSlotAtPosition(input) {
|
|
@@ -2629,23 +3676,23 @@ function resolveClassifiedSlotAtPosition(input) {
|
|
|
2629
3676
|
};
|
|
2630
3677
|
}
|
|
2631
3678
|
// src/url-cross-world-address.ts
|
|
2632
|
-
import * as
|
|
3679
|
+
import * as ts15 from "typescript";
|
|
2633
3680
|
|
|
2634
3681
|
// src/url-address-literals.ts
|
|
2635
|
-
import * as
|
|
3682
|
+
import * as ts14 from "typescript";
|
|
2636
3683
|
function isAmbient2(fileName) {
|
|
2637
3684
|
return /[\\/]node_modules[\\/]/.test(fileName) || /(^|[\\/])lib\.[^\\/]*\.d\.ts$/.test(fileName);
|
|
2638
3685
|
}
|
|
2639
3686
|
function referenceTargetSymbol(type) {
|
|
2640
|
-
if ((type.flags &
|
|
3687
|
+
if ((type.flags & ts14.TypeFlags.Object) === 0)
|
|
2641
3688
|
return;
|
|
2642
|
-
if ((type.objectFlags &
|
|
3689
|
+
if ((type.objectFlags & ts14.ObjectFlags.Reference) === 0)
|
|
2643
3690
|
return;
|
|
2644
3691
|
return type.target.symbol;
|
|
2645
3692
|
}
|
|
2646
3693
|
function ambientHashAliasTargets(checker, anchor) {
|
|
2647
3694
|
const targets = new Set;
|
|
2648
|
-
for (const symbol of checker.getSymbolsInScope(anchor,
|
|
3695
|
+
for (const symbol of checker.getSymbolsInScope(anchor, ts14.SymbolFlags.Type)) {
|
|
2649
3696
|
if (symbol.name !== "Hash")
|
|
2650
3697
|
continue;
|
|
2651
3698
|
const target = referenceTargetSymbol(checker.getDeclaredTypeOfSymbol(symbol));
|
|
@@ -2661,7 +3708,7 @@ function canonicalHashSymbols(checker, program) {
|
|
|
2661
3708
|
if (!anchor)
|
|
2662
3709
|
return canonical;
|
|
2663
3710
|
const aliased = ambientHashAliasTargets(checker, anchor);
|
|
2664
|
-
for (const symbol of checker.getSymbolsInScope(anchor,
|
|
3711
|
+
for (const symbol of checker.getSymbolsInScope(anchor, ts14.SymbolFlags.Function)) {
|
|
2665
3712
|
if (symbol.name !== "hash")
|
|
2666
3713
|
continue;
|
|
2667
3714
|
const declaration = symbol.declarations?.[0];
|
|
@@ -2683,7 +3730,7 @@ function hashedSourceOfType(checker, type, canonical) {
|
|
|
2683
3730
|
return source?.isStringLiteral() ? source.value : undefined;
|
|
2684
3731
|
}
|
|
2685
3732
|
function staticAddressTextOf(checker, node, canonical) {
|
|
2686
|
-
return
|
|
3733
|
+
return ts14.isStringLiteralLike(node) ? node.text : hashedSourceOfType(checker, checker.getTypeAtLocation(node), canonical);
|
|
2687
3734
|
}
|
|
2688
3735
|
|
|
2689
3736
|
// src/url-cross-world-address.ts
|
|
@@ -2707,7 +3754,7 @@ function checkCrossWorldAddresses(input) {
|
|
|
2707
3754
|
if (worlds.length === 0)
|
|
2708
3755
|
continue;
|
|
2709
3756
|
const visit = (node) => {
|
|
2710
|
-
if (
|
|
3757
|
+
if (ts15.isExpression(node)) {
|
|
2711
3758
|
const entry = addressEntryOfArgument(checker, table, node);
|
|
2712
3759
|
if (entry !== undefined && slotRejectsForeignSocket(entry)) {
|
|
2713
3760
|
const address = staticAddressTextOf(checker, node, canonical);
|
|
@@ -2724,14 +3771,14 @@ function checkCrossWorldAddresses(input) {
|
|
|
2724
3771
|
}
|
|
2725
3772
|
}
|
|
2726
3773
|
}
|
|
2727
|
-
|
|
3774
|
+
ts15.forEachChild(node, visit);
|
|
2728
3775
|
};
|
|
2729
|
-
|
|
3776
|
+
ts15.forEachChild(sourceFile, visit);
|
|
2730
3777
|
}
|
|
2731
3778
|
return findings;
|
|
2732
3779
|
}
|
|
2733
3780
|
// src/url-fragment-reachability.ts
|
|
2734
|
-
import * as
|
|
3781
|
+
import * as ts16 from "typescript";
|
|
2735
3782
|
function pathOfKey(key) {
|
|
2736
3783
|
const socket = socketOfAddress(key);
|
|
2737
3784
|
return socket === undefined ? key : key.slice(socket.length + 1);
|
|
@@ -2776,7 +3823,7 @@ function checkUrlFragmentReachability(input) {
|
|
|
2776
3823
|
if (isAmbient2(sourceFile.fileName))
|
|
2777
3824
|
continue;
|
|
2778
3825
|
const visit = (node) => {
|
|
2779
|
-
if (
|
|
3826
|
+
if (ts16.isExpression(node) && isAddressClass(addressClassOfArgument(checker, table, node))) {
|
|
2780
3827
|
const text = staticAddressTextOf(checker, node, canonical);
|
|
2781
3828
|
if (text !== undefined) {
|
|
2782
3829
|
const hash = text.indexOf("#");
|
|
@@ -2795,26 +3842,29 @@ function checkUrlFragmentReachability(input) {
|
|
|
2795
3842
|
}
|
|
2796
3843
|
}
|
|
2797
3844
|
}
|
|
2798
|
-
|
|
3845
|
+
ts16.forEachChild(node, visit);
|
|
2799
3846
|
};
|
|
2800
|
-
|
|
3847
|
+
ts16.forEachChild(sourceFile, visit);
|
|
2801
3848
|
}
|
|
2802
3849
|
return { kind: "checked", findings };
|
|
2803
3850
|
}
|
|
2804
3851
|
export {
|
|
2805
3852
|
ANIMATION_ASSET_EXTENSIONS,
|
|
2806
3853
|
COLLECTION_REFERENCE_EXTENSIONS,
|
|
3854
|
+
COMPANION_INTERNAL_FIELD,
|
|
2807
3855
|
DEFAULT_INCLUDE,
|
|
2808
3856
|
GAME_PROJECT_DOCUMENT,
|
|
2809
3857
|
GUI_EXTENSIONS,
|
|
2810
3858
|
INPUT_BINDING_EXTENSIONS,
|
|
2811
3859
|
LIBRARY_DEPENDENCY_ROOT,
|
|
2812
3860
|
LIBRARY_SCENE_EXTENSIONS,
|
|
3861
|
+
LUALIB_REQUIRE_NAME,
|
|
2813
3862
|
PROJECT_EXTENSIONS,
|
|
2814
3863
|
SCAFFOLDED_DEFIGNORE_LINES,
|
|
2815
3864
|
SCENE_EXTENSIONS,
|
|
2816
3865
|
SCRIPT_SUFFIX_BY_KIND,
|
|
2817
3866
|
SceneTextFormatError,
|
|
3867
|
+
TIMERS_REQUIRE_NAME,
|
|
2818
3868
|
addressClassOfArgument,
|
|
2819
3869
|
addressEntryOfArgument,
|
|
2820
3870
|
archiveWrapperOf,
|
|
@@ -2833,9 +3883,11 @@ export {
|
|
|
2833
3883
|
collectComponentDeclarations,
|
|
2834
3884
|
collectComponentIds,
|
|
2835
3885
|
componentIdOfSameObjectAddress,
|
|
3886
|
+
computeCompanionClosure,
|
|
2836
3887
|
computeOutputRel,
|
|
2837
3888
|
createTranspileSession,
|
|
2838
3889
|
displayPathOf,
|
|
3890
|
+
findEmittedRequires,
|
|
2839
3891
|
findMainEntryFactoryImports,
|
|
2840
3892
|
getProgramDiagnostics,
|
|
2841
3893
|
guiScriptResourceOf,
|
|
@@ -2854,7 +3906,9 @@ export {
|
|
|
2854
3906
|
readLibrarySceneDocuments,
|
|
2855
3907
|
readSceneDocuments,
|
|
2856
3908
|
relativeAddressesFrom,
|
|
3909
|
+
requirePathForRel,
|
|
2857
3910
|
resolveClassifiedSlotAtPosition,
|
|
3911
|
+
rewriteEmittedRequires,
|
|
2858
3912
|
slotRejectsForeignSocket,
|
|
2859
3913
|
socketOfAddress,
|
|
2860
3914
|
stripIncludeBase,
|