@defold-typescript/transpiler 0.35.0 → 0.37.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 +2311 -1245
- package/dist/lifecycle-erasure.d.ts +1 -0
- package/dist/lua-require-scan.d.ts +17 -0
- package/dist/output-paths.d.ts +10 -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 +12 -0
- package/src/lifecycle-erasure.ts +1 -1
- package/src/lua-require-scan.ts +0 -0
- package/src/output-paths.ts +44 -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;
|
|
661
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;
|
|
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
|
-
|
|
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 === "")
|
|
1318
|
+
continue;
|
|
1319
|
+
keys.add(`${section}.${key}`);
|
|
929
1320
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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;
|
|
936
1330
|
continue;
|
|
937
1331
|
}
|
|
938
|
-
|
|
939
|
-
urlByKey.set(key, url);
|
|
940
|
-
}
|
|
941
|
-
const root = joinProject(projectRoot, LIBRARY_DEPENDENCY_ROOT);
|
|
942
|
-
const filesByKey = new Map;
|
|
943
|
-
const stray = new Set;
|
|
944
|
-
for (const filePath of host.readDirectory(root, extensions)) {
|
|
945
|
-
const relative = displayPathOf(root, filePath);
|
|
946
|
-
if (relative === filePath.replace(/\\/g, "/"))
|
|
1332
|
+
if (current !== section)
|
|
947
1333
|
continue;
|
|
948
|
-
const separator =
|
|
949
|
-
if (separator
|
|
1334
|
+
const separator = line.indexOf("=");
|
|
1335
|
+
if (separator === -1)
|
|
950
1336
|
continue;
|
|
951
|
-
|
|
952
|
-
const url = urlByKey.get(key);
|
|
953
|
-
if (url === undefined) {
|
|
954
|
-
stray.add(key);
|
|
1337
|
+
if (line.slice(0, separator).trim() !== key)
|
|
955
1338
|
continue;
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
filesByKey.set(key, [filePath]);
|
|
960
|
-
else
|
|
961
|
-
bucket.push(filePath);
|
|
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;
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
return name.text;
|
|
1053
|
-
}
|
|
1054
|
-
return;
|
|
1505
|
+
const key = resourceKey(script);
|
|
1506
|
+
return key === SCRIPT_SUFFIX2 ? undefined : key;
|
|
1055
1507
|
}
|
|
1056
|
-
function
|
|
1057
|
-
|
|
1058
|
-
|
|
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);
|
|
1059
1559
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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);
|
|
1573
|
+
}
|
|
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());
|
|
1191
1733
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1734
|
+
|
|
1735
|
+
// src/library-dependencies.ts
|
|
1736
|
+
function isProjectHeader(line) {
|
|
1737
|
+
return line.trim() === "[project]";
|
|
1738
|
+
}
|
|
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
|
-
ts2.forEachChild(node, visit);
|
|
1209
|
-
};
|
|
1210
|
-
ts2.forEachChild(fn.body, visit);
|
|
1211
|
-
return found;
|
|
1212
|
-
}
|
|
1213
|
-
function initBuilderBody(fn, context) {
|
|
1214
|
-
if (ts2.isBlock(fn.body)) {
|
|
1215
|
-
return context.transformStatements(fn.body.statements);
|
|
1216
1775
|
}
|
|
1217
|
-
return
|
|
1218
|
-
}
|
|
1219
|
-
function emitInitMerge(fn, context, property) {
|
|
1220
|
-
const authorParam = fn.parameters.find((param) => !isThisParameter2(param) && ts2.isIdentifier(param.name));
|
|
1221
|
-
const builderParams = authorParam === undefined ? [] : [context.transformExpression(authorParam.name)];
|
|
1222
|
-
const builder = createFunctionExpression2(createBlock2(initBuilderBody(fn, context)), builderParams, undefined, NodeFlags2.Declaration, fn);
|
|
1223
|
-
const builderDecl = createVariableDeclarationStatement2(createIdentifier2("____init"), builder);
|
|
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)];
|
|
1776
|
+
return wrapper;
|
|
1231
1777
|
}
|
|
1232
|
-
function
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
if (!ts2.isPropertyAssignment(member)) {
|
|
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]";
|
|
1239
1784
|
continue;
|
|
1240
1785
|
}
|
|
1241
|
-
|
|
1242
|
-
if (!ts2.isIdentifier(key) && !ts2.isStringLiteral(key)) {
|
|
1786
|
+
if (!inLibrary) {
|
|
1243
1787
|
continue;
|
|
1244
1788
|
}
|
|
1245
|
-
|
|
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
|
+
}
|
|
1246
1793
|
}
|
|
1247
|
-
return
|
|
1794
|
+
return [];
|
|
1248
1795
|
}
|
|
1249
|
-
function
|
|
1250
|
-
if (
|
|
1251
|
-
return;
|
|
1796
|
+
function isContainedResourcePath(path) {
|
|
1797
|
+
if (path.length === 0 || path.includes("\\")) {
|
|
1798
|
+
return false;
|
|
1252
1799
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1800
|
+
return path.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
|
|
1801
|
+
}
|
|
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
|
+
};
|
|
1255
1809
|
}
|
|
1256
|
-
const
|
|
1257
|
-
if (
|
|
1258
|
-
return
|
|
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
|
+
};
|
|
1259
1817
|
}
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
if (name === "properties") {
|
|
1268
|
-
registrations.push(...emitPropertyRegistrations(property, context));
|
|
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)) {
|
|
1269
1825
|
continue;
|
|
1270
1826
|
}
|
|
1271
|
-
const
|
|
1272
|
-
if (
|
|
1273
|
-
const dispatch = dispatcherInitializer(property, context.checker);
|
|
1274
|
-
if (dispatch !== undefined) {
|
|
1275
|
-
statements.push(createAssignmentStatement(createIdentifier2(name), context.transformExpression(dispatch), property));
|
|
1276
|
-
}
|
|
1827
|
+
const dot = path.lastIndexOf(".");
|
|
1828
|
+
if (dot === -1 || !LIBRARY_SCENE_EXTENSIONS.includes(path.slice(dot).toLowerCase())) {
|
|
1277
1829
|
continue;
|
|
1278
1830
|
}
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1831
|
+
if (!isContainedResourcePath(path)) {
|
|
1832
|
+
refused.push(entry);
|
|
1281
1833
|
continue;
|
|
1282
1834
|
}
|
|
1283
|
-
|
|
1284
|
-
const fnExpression = createFunctionExpression2(createBlock2(transformHookBody(fn, context)), params, undefined, NodeFlags2.Declaration, fn);
|
|
1285
|
-
statements.push(createAssignmentStatement(createIdentifier2(name), fnExpression, property));
|
|
1835
|
+
shared.push({ entry, path });
|
|
1286
1836
|
}
|
|
1287
|
-
|
|
1837
|
+
shared.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
1838
|
+
return { shared, reasons: [], refused };
|
|
1288
1839
|
}
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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 {
|
|
1850
|
+
return;
|
|
1292
1851
|
}
|
|
1293
|
-
const
|
|
1294
|
-
if (
|
|
1295
|
-
return
|
|
1852
|
+
const entries = parsed?.dependencies;
|
|
1853
|
+
if (!Array.isArray(entries))
|
|
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);
|
|
1296
1860
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
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 };
|
|
1299
1880
|
}
|
|
1300
|
-
const
|
|
1301
|
-
if (
|
|
1302
|
-
|
|
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`);
|
|
1885
|
+
}
|
|
1886
|
+
return { documents, unreadable };
|
|
1303
1887
|
}
|
|
1304
|
-
const
|
|
1305
|
-
|
|
1306
|
-
|
|
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`);
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1896
|
+
resolved.push({ key, url });
|
|
1897
|
+
urlByKey.set(key, url);
|
|
1307
1898
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
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, "/"))
|
|
1905
|
+
continue;
|
|
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);
|
|
1913
|
+
continue;
|
|
1914
|
+
}
|
|
1915
|
+
const bucket = filesByKey.get(key);
|
|
1916
|
+
if (bucket === undefined)
|
|
1917
|
+
filesByKey.set(key, [filePath]);
|
|
1918
|
+
else
|
|
1919
|
+
bucket.push(filePath);
|
|
1920
|
+
}
|
|
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;
|
|
1319
1931
|
}
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
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
|
+
}
|
|
1323
1940
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
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`);
|
|
1943
|
+
}
|
|
1944
|
+
return { documents, unreadable };
|
|
1945
|
+
}
|
|
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) {
|
|
@@ -1372,6 +1993,17 @@ function stripIncludeBase(pattern) {
|
|
|
1372
1993
|
const lastSlash = upToWildcard.lastIndexOf("/");
|
|
1373
1994
|
return lastSlash === -1 ? "" : upToWildcard.slice(0, lastSlash + 1);
|
|
1374
1995
|
}
|
|
1996
|
+
var ABSOLUTE_SPELLING_RE = /^(\/|\\\\|[A-Za-z]:[\\/])/;
|
|
1997
|
+
function projectRelativeBase(pattern) {
|
|
1998
|
+
if (ABSOLUTE_SPELLING_RE.test(pattern)) {
|
|
1999
|
+
return;
|
|
2000
|
+
}
|
|
2001
|
+
const base = path.posix.normalize(stripIncludeBase(pattern.split("\\").join("/")));
|
|
2002
|
+
if (base === ".." || base.startsWith("../")) {
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
return base === "." || base === "./" ? "" : base;
|
|
2006
|
+
}
|
|
1375
2007
|
function relUnderOutDir(rel, config) {
|
|
1376
2008
|
const { outDir, include } = config;
|
|
1377
2009
|
if (outDir === undefined || outDir === "" || outDir === ".") {
|
|
@@ -1381,6 +2013,15 @@ function relUnderOutDir(rel, config) {
|
|
|
1381
2013
|
const relUnderBase = rel.slice(includeBase.length);
|
|
1382
2014
|
return path.posix.join(outDir, relUnderBase);
|
|
1383
2015
|
}
|
|
2016
|
+
function requirePathForRel(rel) {
|
|
2017
|
+
const segments = rel.split("/").filter((segment) => segment !== "" && segment !== "." && segment !== "..");
|
|
2018
|
+
const last = segments.length - 1;
|
|
2019
|
+
const lastSegment = segments[last];
|
|
2020
|
+
if (lastSegment !== undefined) {
|
|
2021
|
+
segments[last] = lastSegment.replace(/\.[^.]*$/, "");
|
|
2022
|
+
}
|
|
2023
|
+
return segments.map((segment) => segment.replace(/\./g, "_")).join(".");
|
|
2024
|
+
}
|
|
1384
2025
|
function computeOutputRel(rel, config, kind) {
|
|
1385
2026
|
const baseRel = relUnderOutDir(rel, config);
|
|
1386
2027
|
if (kind === "module") {
|
|
@@ -1389,16 +2030,16 @@ function computeOutputRel(rel, config, kind) {
|
|
|
1389
2030
|
return baseRel.replace(/\.ts$/, SCRIPT_SUFFIX_BY_KIND[kind]);
|
|
1390
2031
|
}
|
|
1391
2032
|
// src/program-diagnostics.ts
|
|
1392
|
-
import * as
|
|
2033
|
+
import * as ts8 from "typescript";
|
|
1393
2034
|
import * as tstl from "typescript-to-lua";
|
|
1394
2035
|
|
|
1395
2036
|
// src/message-guard-lowering.ts
|
|
1396
|
-
import * as
|
|
2037
|
+
import * as ts5 from "typescript";
|
|
1397
2038
|
import {
|
|
1398
2039
|
createBinaryExpression as createBinaryExpression3,
|
|
1399
2040
|
createCallExpression as createCallExpression3,
|
|
1400
2041
|
createIdentifier as createIdentifier3,
|
|
1401
|
-
SyntaxKind as
|
|
2042
|
+
SyntaxKind as SyntaxKind7
|
|
1402
2043
|
} from "typescript-to-lua";
|
|
1403
2044
|
var GUARD_MODULE = "@defold-typescript/types";
|
|
1404
2045
|
var GUARD_NAME = "isMessage";
|
|
@@ -1407,7 +2048,7 @@ function resolvesToGuardExport(callee, checker) {
|
|
|
1407
2048
|
if (symbol === undefined) {
|
|
1408
2049
|
return false;
|
|
1409
2050
|
}
|
|
1410
|
-
if (symbol.flags &
|
|
2051
|
+
if (symbol.flags & ts5.SymbolFlags.Alias) {
|
|
1411
2052
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1412
2053
|
}
|
|
1413
2054
|
if (symbol.getName() !== GUARD_NAME) {
|
|
@@ -1421,12 +2062,12 @@ function resolvesToGuardExport(callee, checker) {
|
|
|
1421
2062
|
}
|
|
1422
2063
|
var messageGuardLoweringPlugin = {
|
|
1423
2064
|
visitors: {
|
|
1424
|
-
[
|
|
2065
|
+
[ts5.SyntaxKind.CallExpression]: (node, context) => {
|
|
1425
2066
|
const [messageIdArg, , expectedArg] = node.arguments;
|
|
1426
2067
|
if (node.arguments.length === 3 && messageIdArg !== undefined && expectedArg !== undefined && resolvesToGuardExport(node.expression, context.checker)) {
|
|
1427
2068
|
const messageId = context.transformExpression(messageIdArg);
|
|
1428
2069
|
const expected = context.transformExpression(expectedArg);
|
|
1429
|
-
return createBinaryExpression3(messageId, createCallExpression3(createIdentifier3("hash"), [expected]),
|
|
2070
|
+
return createBinaryExpression3(messageId, createCallExpression3(createIdentifier3("hash"), [expected]), SyntaxKind7.EqualityOperator, node);
|
|
1430
2071
|
}
|
|
1431
2072
|
return context.superTransformExpression(node);
|
|
1432
2073
|
}
|
|
@@ -1434,77 +2075,34 @@ var messageGuardLoweringPlugin = {
|
|
|
1434
2075
|
};
|
|
1435
2076
|
|
|
1436
2077
|
// 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
|
|
2078
|
+
import * as ts6 from "typescript";
|
|
2079
|
+
import { LuaLibFeature } from "typescript-to-lua";
|
|
1484
2080
|
function isTimersSpecifier(node) {
|
|
1485
|
-
return
|
|
2081
|
+
return ts6.isStringLiteral(node) && node.text === TIMERS_MODULE_SPECIFIER;
|
|
1486
2082
|
}
|
|
1487
2083
|
function importsTimersModule(sourceFile) {
|
|
1488
|
-
return sourceFile.statements.some((statement) =>
|
|
2084
|
+
return sourceFile.statements.some((statement) => ts6.isImportDeclaration(statement) && isTimersSpecifier(statement.moduleSpecifier));
|
|
1489
2085
|
}
|
|
1490
2086
|
var TIMERS_REQUIRE_PATH = `@NoResolution:${TIMERS_REQUIRE_NAME}`;
|
|
1491
2087
|
var timersLoweringPlugin = {
|
|
1492
2088
|
visitors: {
|
|
1493
|
-
[
|
|
2089
|
+
[ts6.SyntaxKind.ImportDeclaration]: (node, context) => {
|
|
1494
2090
|
if (!isTimersSpecifier(node.moduleSpecifier)) {
|
|
1495
2091
|
return context.superTransformStatements(node);
|
|
1496
2092
|
}
|
|
1497
|
-
|
|
2093
|
+
context.usedLuaLibFeatures.add(LuaLibFeature.Promise);
|
|
2094
|
+
context.usedLuaLibFeatures.add(LuaLibFeature.New);
|
|
2095
|
+
const rewritten = ts6.factory.updateImportDeclaration(node, node.modifiers, node.importClause, ts6.factory.createStringLiteral(TIMERS_REQUIRE_PATH), node.attributes);
|
|
1498
2096
|
return context.superTransformStatements(rewritten);
|
|
1499
2097
|
}
|
|
1500
2098
|
}
|
|
1501
2099
|
};
|
|
1502
2100
|
|
|
1503
2101
|
// src/window-event-guard-lowering.ts
|
|
1504
|
-
import * as
|
|
2102
|
+
import * as ts7 from "typescript";
|
|
1505
2103
|
import {
|
|
1506
2104
|
createBinaryExpression as createBinaryExpression4,
|
|
1507
|
-
SyntaxKind as
|
|
2105
|
+
SyntaxKind as SyntaxKind10
|
|
1508
2106
|
} from "typescript-to-lua";
|
|
1509
2107
|
var GUARD_MODULE2 = "@defold-typescript/types";
|
|
1510
2108
|
var GUARD_NAME2 = "isWindowEvent";
|
|
@@ -1513,7 +2111,7 @@ function resolvesToGuardExport2(callee, checker) {
|
|
|
1513
2111
|
if (symbol === undefined) {
|
|
1514
2112
|
return false;
|
|
1515
2113
|
}
|
|
1516
|
-
if (symbol.flags &
|
|
2114
|
+
if (symbol.flags & ts7.SymbolFlags.Alias) {
|
|
1517
2115
|
symbol = checker.getAliasedSymbol(symbol);
|
|
1518
2116
|
}
|
|
1519
2117
|
if (symbol.getName() !== GUARD_NAME2) {
|
|
@@ -1527,12 +2125,12 @@ function resolvesToGuardExport2(callee, checker) {
|
|
|
1527
2125
|
}
|
|
1528
2126
|
var windowEventGuardLoweringPlugin = {
|
|
1529
2127
|
visitors: {
|
|
1530
|
-
[
|
|
2128
|
+
[ts7.SyntaxKind.CallExpression]: (node, context) => {
|
|
1531
2129
|
const [eventArg, , expectedArg] = node.arguments;
|
|
1532
2130
|
if (node.arguments.length === 3 && eventArg !== undefined && expectedArg !== undefined && resolvesToGuardExport2(node.expression, context.checker)) {
|
|
1533
2131
|
const event = context.transformExpression(eventArg);
|
|
1534
2132
|
const expected = context.transformExpression(expectedArg);
|
|
1535
|
-
return createBinaryExpression4(event, expected,
|
|
2133
|
+
return createBinaryExpression4(event, expected, SyntaxKind10.EqualityOperator, node);
|
|
1536
2134
|
}
|
|
1537
2135
|
return context.superTransformExpression(node);
|
|
1538
2136
|
}
|
|
@@ -1552,13 +2150,33 @@ function isAmbient(fileName) {
|
|
|
1552
2150
|
return /[\\/]node_modules[\\/]/.test(fileName) || /(^|[\\/])lib\.[^\\/]*\.d\.ts$/.test(fileName);
|
|
1553
2151
|
}
|
|
1554
2152
|
function getProgramDiagnostics(program, sourceFile) {
|
|
1555
|
-
const { diagnostics } = tstl.getProgramTranspileResult(
|
|
2153
|
+
const { diagnostics } = tstl.getProgramTranspileResult(ts8.sys, noopWriteFile, {
|
|
1556
2154
|
program,
|
|
1557
2155
|
plugins: LUA_PLUGINS,
|
|
1558
2156
|
...sourceFile ? { sourceFiles: [sourceFile] } : {}
|
|
1559
2157
|
});
|
|
1560
2158
|
return diagnostics.filter((d) => d.file !== undefined && !isAmbient(d.file.fileName));
|
|
1561
2159
|
}
|
|
2160
|
+
// src/require-rewrite.ts
|
|
2161
|
+
function quote(value) {
|
|
2162
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
2163
|
+
}
|
|
2164
|
+
function rewriteEmittedRequires(lua, rewrites) {
|
|
2165
|
+
if (rewrites.size === 0) {
|
|
2166
|
+
return lua;
|
|
2167
|
+
}
|
|
2168
|
+
let out = "";
|
|
2169
|
+
let cursor = 0;
|
|
2170
|
+
for (const { path, start, end } of scanEmittedRequires(lua)) {
|
|
2171
|
+
const mapped = rewrites.get(path);
|
|
2172
|
+
if (mapped === undefined) {
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
out += lua.slice(cursor, start) + quote(mapped);
|
|
2176
|
+
cursor = end;
|
|
2177
|
+
}
|
|
2178
|
+
return cursor === 0 ? lua : out + lua.slice(cursor);
|
|
2179
|
+
}
|
|
1562
2180
|
// src/scene-component-index.ts
|
|
1563
2181
|
var COMPONENT_BLOCKS = new Set(["components", "embedded_components"]);
|
|
1564
2182
|
var EMBEDDING_BLOCKS = new Set(["embedded_instances", "embedded_components"]);
|
|
@@ -2052,13 +2670,441 @@ function relativeAddressesFrom(index, context) {
|
|
|
2052
2670
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
2053
2671
|
import { createRequire as createRequire2 } from "node:module";
|
|
2054
2672
|
import * as path3 from "node:path";
|
|
2055
|
-
import * as
|
|
2673
|
+
import * as ts12 from "typescript";
|
|
2056
2674
|
import * as tstl3 from "typescript-to-lua";
|
|
2057
2675
|
|
|
2676
|
+
// src/companion-emit.ts
|
|
2677
|
+
import * as ts9 from "typescript";
|
|
2678
|
+
import {
|
|
2679
|
+
createAssignmentStatement as createAssignmentStatement2,
|
|
2680
|
+
createCallExpression as createCallExpression4,
|
|
2681
|
+
createFile,
|
|
2682
|
+
createIdentifier as createIdentifier4,
|
|
2683
|
+
createReturnStatement as createReturnStatement2,
|
|
2684
|
+
createStringLiteral as createStringLiteral3,
|
|
2685
|
+
createTableExpression,
|
|
2686
|
+
createTableFieldExpression,
|
|
2687
|
+
createTableIndexExpression as createTableIndexExpression2,
|
|
2688
|
+
createVariableDeclarationStatement as createVariableDeclarationStatement3,
|
|
2689
|
+
isBlock as isBlock3,
|
|
2690
|
+
isCallExpression as isCallExpression4,
|
|
2691
|
+
isDoStatement,
|
|
2692
|
+
isForInStatement as isForInStatement2,
|
|
2693
|
+
isForStatement,
|
|
2694
|
+
isFunctionDefinition,
|
|
2695
|
+
isFunctionExpression as isFunctionExpression4,
|
|
2696
|
+
isIdentifier as isIdentifier4,
|
|
2697
|
+
isMethodCallExpression,
|
|
2698
|
+
isRepeatStatement,
|
|
2699
|
+
isReturnStatement as isReturnStatement2,
|
|
2700
|
+
isStringLiteral as isStringLiteral6,
|
|
2701
|
+
isTableExpression,
|
|
2702
|
+
isVariableDeclarationStatement,
|
|
2703
|
+
LuaPrinter
|
|
2704
|
+
} from "typescript-to-lua";
|
|
2705
|
+
var EXPORTS_NAME = "____exports";
|
|
2706
|
+
function exportsIdentifier() {
|
|
2707
|
+
return createIdentifier4(EXPORTS_NAME);
|
|
2708
|
+
}
|
|
2709
|
+
function isRuntimeScriptSource(sourceFile, checker) {
|
|
2710
|
+
return sourceFile.statements.some((statement) => {
|
|
2711
|
+
const expression = ts9.isExpressionStatement(statement) ? statement.expression : ts9.isExportAssignment(statement) && !statement.isExportEquals ? statement.expression : undefined;
|
|
2712
|
+
return expression !== undefined && ts9.isCallExpression(expression) && resolvesToFactoryExport(expression.expression, checker);
|
|
2713
|
+
});
|
|
2714
|
+
}
|
|
2715
|
+
function planFor(sourceFile, checker) {
|
|
2716
|
+
if (sourceFile.isDeclarationFile || !isRuntimeScriptSource(sourceFile, checker)) {
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
const closure = computeCompanionClosure(sourceFile, checker);
|
|
2720
|
+
if (closure.statements.length === 0 || closure.violations.length > 0) {
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
return {
|
|
2724
|
+
closureStarts: new Set(closure.statements.map((statement) => statement.pos)),
|
|
2725
|
+
internals: closure.internals,
|
|
2726
|
+
importBindings: closure.importBindings,
|
|
2727
|
+
requirePath: requirePathForRel(sourceFile.fileName)
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
function isLuaNode(value) {
|
|
2731
|
+
return typeof value === "object" && value !== null && typeof value.kind === "number";
|
|
2732
|
+
}
|
|
2733
|
+
function forEachLuaNode(root, visit) {
|
|
2734
|
+
visit(root);
|
|
2735
|
+
for (const value of Object.values(root)) {
|
|
2736
|
+
if (Array.isArray(value)) {
|
|
2737
|
+
for (const element of value) {
|
|
2738
|
+
if (isLuaNode(element)) {
|
|
2739
|
+
forEachLuaNode(element, visit);
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
} else if (isLuaNode(value)) {
|
|
2743
|
+
forEachLuaNode(value, visit);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
function declaredNames(statement) {
|
|
2748
|
+
return isVariableDeclarationStatement(statement) ? statement.left.map((name) => name.text) : [];
|
|
2749
|
+
}
|
|
2750
|
+
function freeNames(statements) {
|
|
2751
|
+
const free = new Set;
|
|
2752
|
+
const scopes = [new Set];
|
|
2753
|
+
function declare(name) {
|
|
2754
|
+
scopes[scopes.length - 1]?.add(name);
|
|
2755
|
+
}
|
|
2756
|
+
function isBound(name) {
|
|
2757
|
+
return scopes.some((scope) => scope.has(name));
|
|
2758
|
+
}
|
|
2759
|
+
function inScope(run) {
|
|
2760
|
+
scopes.push(new Set);
|
|
2761
|
+
run();
|
|
2762
|
+
scopes.pop();
|
|
2763
|
+
}
|
|
2764
|
+
function visitEach(nodes) {
|
|
2765
|
+
for (const node of nodes ?? []) {
|
|
2766
|
+
visit(node);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
function visit(node) {
|
|
2770
|
+
if (node === undefined) {
|
|
2771
|
+
return;
|
|
2772
|
+
}
|
|
2773
|
+
if (isIdentifier4(node)) {
|
|
2774
|
+
if (!isBound(node.text)) {
|
|
2775
|
+
free.add(node.text);
|
|
2776
|
+
}
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
if (isVariableDeclarationStatement(node)) {
|
|
2780
|
+
if (isFunctionDefinition(node)) {
|
|
2781
|
+
const [name] = node.left;
|
|
2782
|
+
if (name !== undefined) {
|
|
2783
|
+
declare(name.text);
|
|
2784
|
+
}
|
|
2785
|
+
visit(node.right[0]);
|
|
2786
|
+
return;
|
|
2787
|
+
}
|
|
2788
|
+
visitEach(node.right);
|
|
2789
|
+
for (const name of node.left) {
|
|
2790
|
+
declare(name.text);
|
|
2791
|
+
}
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
if (isFunctionExpression4(node)) {
|
|
2795
|
+
inScope(() => {
|
|
2796
|
+
for (const param of node.params ?? []) {
|
|
2797
|
+
declare(param.text);
|
|
2798
|
+
}
|
|
2799
|
+
visit(node.body);
|
|
2800
|
+
});
|
|
2801
|
+
return;
|
|
2802
|
+
}
|
|
2803
|
+
if (isForStatement(node)) {
|
|
2804
|
+
visit(node.controlVariableInitializer);
|
|
2805
|
+
visit(node.limitExpression);
|
|
2806
|
+
visit(node.stepExpression);
|
|
2807
|
+
inScope(() => {
|
|
2808
|
+
declare(node.controlVariable.text);
|
|
2809
|
+
visit(node.body);
|
|
2810
|
+
});
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
if (isForInStatement2(node)) {
|
|
2814
|
+
visitEach(node.expressions);
|
|
2815
|
+
inScope(() => {
|
|
2816
|
+
for (const name of node.names) {
|
|
2817
|
+
declare(name.text);
|
|
2818
|
+
}
|
|
2819
|
+
visit(node.body);
|
|
2820
|
+
});
|
|
2821
|
+
return;
|
|
2822
|
+
}
|
|
2823
|
+
if (isRepeatStatement(node)) {
|
|
2824
|
+
inScope(() => {
|
|
2825
|
+
visitEach(node.body.statements);
|
|
2826
|
+
visit(node.condition);
|
|
2827
|
+
});
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
if (isBlock3(node) || isDoStatement(node)) {
|
|
2831
|
+
inScope(() => visitEach(node.statements));
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
if (isMethodCallExpression(node)) {
|
|
2835
|
+
visit(node.prefixExpression);
|
|
2836
|
+
visitEach(node.params);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
for (const value of Object.values(node)) {
|
|
2840
|
+
if (Array.isArray(value)) {
|
|
2841
|
+
for (const element of value) {
|
|
2842
|
+
if (isLuaNode(element)) {
|
|
2843
|
+
visit(element);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
} else if (isLuaNode(value)) {
|
|
2847
|
+
visit(value);
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
for (const statement of statements) {
|
|
2852
|
+
for (const name of declaredNames(statement)) {
|
|
2853
|
+
declare(name);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
for (const statement of statements) {
|
|
2857
|
+
visit(statement);
|
|
2858
|
+
}
|
|
2859
|
+
return free;
|
|
2860
|
+
}
|
|
2861
|
+
function resolvedRequirePaths(sourceFile, checker) {
|
|
2862
|
+
const paths = new Map;
|
|
2863
|
+
for (const statement of sourceFile.statements) {
|
|
2864
|
+
const specifier = ts9.isImportDeclaration(statement) || ts9.isExportDeclaration(statement) ? statement.moduleSpecifier : undefined;
|
|
2865
|
+
if (specifier === undefined || !ts9.isStringLiteral(specifier)) {
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2868
|
+
const target = checker.getSymbolAtLocation(specifier)?.declarations?.find((declaration) => ts9.isSourceFile(declaration));
|
|
2869
|
+
if (target === undefined || target.isDeclarationFile) {
|
|
2870
|
+
continue;
|
|
2871
|
+
}
|
|
2872
|
+
paths.set(specifier.text, requirePathForRel(target.fileName));
|
|
2873
|
+
}
|
|
2874
|
+
return paths;
|
|
2875
|
+
}
|
|
2876
|
+
function resolveMovedRequires(statements, paths) {
|
|
2877
|
+
for (const statement of statements) {
|
|
2878
|
+
forEachLuaNode(statement, (node) => {
|
|
2879
|
+
if (!isCallExpression4(node) || !isIdentifier4(node.expression)) {
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
if (node.expression.text !== "require" || node.params.length !== 1) {
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
const [argument] = node.params;
|
|
2886
|
+
if (argument === undefined || !isStringLiteral6(argument)) {
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
const resolved = paths.get(argument.value);
|
|
2890
|
+
if (resolved !== undefined) {
|
|
2891
|
+
argument.value = resolved;
|
|
2892
|
+
}
|
|
2893
|
+
});
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function withResolvedRequire(statement, paths) {
|
|
2897
|
+
if (!isVariableDeclarationStatement(statement) || statement.left.length !== 1) {
|
|
2898
|
+
return statement;
|
|
2899
|
+
}
|
|
2900
|
+
const name = statement.left[0];
|
|
2901
|
+
const [value] = statement.right ?? [];
|
|
2902
|
+
if (name === undefined || value === undefined || !isCallExpression4(value)) {
|
|
2903
|
+
return statement;
|
|
2904
|
+
}
|
|
2905
|
+
if (!isIdentifier4(value.expression) || value.expression.text !== "require") {
|
|
2906
|
+
return statement;
|
|
2907
|
+
}
|
|
2908
|
+
const [argument] = value.params;
|
|
2909
|
+
if (argument === undefined || !isStringLiteral6(argument)) {
|
|
2910
|
+
return statement;
|
|
2911
|
+
}
|
|
2912
|
+
const resolved = paths.get(argument.value);
|
|
2913
|
+
if (resolved === undefined) {
|
|
2914
|
+
return statement;
|
|
2915
|
+
}
|
|
2916
|
+
return createVariableDeclarationStatement3(createIdentifier4(name.text), createCallExpression4(createIdentifier4("require"), [createStringLiteral3(resolved)]));
|
|
2917
|
+
}
|
|
2918
|
+
function copiedPrelude(halves, importBindings) {
|
|
2919
|
+
const needed = new Set(importBindings);
|
|
2920
|
+
for (const name of freeNames(halves.companion)) {
|
|
2921
|
+
needed.add(name);
|
|
2922
|
+
}
|
|
2923
|
+
const alreadyCarried = new Set(halves.companion);
|
|
2924
|
+
const candidates = halves.script.filter((statement) => isVariableDeclarationStatement(statement) && !alreadyCarried.has(statement));
|
|
2925
|
+
const copied = new Set;
|
|
2926
|
+
let grew = true;
|
|
2927
|
+
while (grew) {
|
|
2928
|
+
grew = false;
|
|
2929
|
+
for (const statement of candidates) {
|
|
2930
|
+
if (copied.has(statement) || !declaredNames(statement).some((name) => needed.has(name))) {
|
|
2931
|
+
continue;
|
|
2932
|
+
}
|
|
2933
|
+
copied.add(statement);
|
|
2934
|
+
for (const name of freeNames([statement])) {
|
|
2935
|
+
needed.add(name);
|
|
2936
|
+
}
|
|
2937
|
+
grew = true;
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
return halves.script.filter((statement) => copied.has(statement));
|
|
2941
|
+
}
|
|
2942
|
+
function namesIdentifier(statement, names) {
|
|
2943
|
+
let found = false;
|
|
2944
|
+
forEachLuaNode(statement, (node) => {
|
|
2945
|
+
if (isIdentifier4(node) && names.has(node.text)) {
|
|
2946
|
+
found = true;
|
|
2947
|
+
}
|
|
2948
|
+
});
|
|
2949
|
+
return found;
|
|
2950
|
+
}
|
|
2951
|
+
function isExportsTableInit(statement) {
|
|
2952
|
+
if (!isVariableDeclarationStatement(statement) || statement.left.length !== 1) {
|
|
2953
|
+
return false;
|
|
2954
|
+
}
|
|
2955
|
+
const [single] = statement.right ?? [];
|
|
2956
|
+
return statement.left[0]?.text === EXPORTS_NAME && single !== undefined && isTableExpression(single);
|
|
2957
|
+
}
|
|
2958
|
+
function isExportsReturn(statement) {
|
|
2959
|
+
if (!isReturnStatement2(statement) || statement.expressions.length !== 1) {
|
|
2960
|
+
return false;
|
|
2961
|
+
}
|
|
2962
|
+
const [single] = statement.expressions;
|
|
2963
|
+
return single !== undefined && isIdentifier4(single) && single.text === EXPORTS_NAME;
|
|
2964
|
+
}
|
|
2965
|
+
function isHoistedNameDeclaration(statement) {
|
|
2966
|
+
return isVariableDeclarationStatement(statement) && statement.right === undefined;
|
|
2967
|
+
}
|
|
2968
|
+
function internalsField(name) {
|
|
2969
|
+
return createTableIndexExpression2(createTableIndexExpression2(exportsIdentifier(), createStringLiteral3(COMPANION_INTERNAL_FIELD)), createStringLiteral3(name));
|
|
2970
|
+
}
|
|
2971
|
+
function requireInsertionPoint(script, reads) {
|
|
2972
|
+
let index = 0;
|
|
2973
|
+
while (index < script.length) {
|
|
2974
|
+
const statement = script[index];
|
|
2975
|
+
if (statement === undefined || !isVariableDeclarationStatement(statement)) {
|
|
2976
|
+
break;
|
|
2977
|
+
}
|
|
2978
|
+
if (namesIdentifier(statement, reads)) {
|
|
2979
|
+
break;
|
|
2980
|
+
}
|
|
2981
|
+
index++;
|
|
2982
|
+
}
|
|
2983
|
+
return index;
|
|
2984
|
+
}
|
|
2985
|
+
function split(statements, owned) {
|
|
2986
|
+
const script = [];
|
|
2987
|
+
const companion = [];
|
|
2988
|
+
for (const statement of statements) {
|
|
2989
|
+
if (isExportsTableInit(statement) || isExportsReturn(statement)) {
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
if (owned.has(statement)) {
|
|
2993
|
+
companion.push(statement);
|
|
2994
|
+
continue;
|
|
2995
|
+
}
|
|
2996
|
+
if (isHoistedNameDeclaration(statement)) {
|
|
2997
|
+
companion.push(statement);
|
|
2998
|
+
}
|
|
2999
|
+
script.push(statement);
|
|
3000
|
+
}
|
|
3001
|
+
return { script, companion };
|
|
3002
|
+
}
|
|
3003
|
+
function createCompanionEmitPlugin() {
|
|
3004
|
+
const plans = new Map;
|
|
3005
|
+
const owned = new Map;
|
|
3006
|
+
const companions = new Map;
|
|
3007
|
+
function planOf(sourceFile, checker) {
|
|
3008
|
+
const key = sourceFile.fileName;
|
|
3009
|
+
if (!plans.has(key)) {
|
|
3010
|
+
plans.set(key, planFor(sourceFile, checker));
|
|
3011
|
+
}
|
|
3012
|
+
return plans.get(key);
|
|
3013
|
+
}
|
|
3014
|
+
function capture(node, context) {
|
|
3015
|
+
const statements = context.superTransformStatements(node);
|
|
3016
|
+
const sourceFile = context.sourceFile;
|
|
3017
|
+
const plan = planOf(sourceFile, context.checker);
|
|
3018
|
+
if (plan === undefined || !plan.closureStarts.has(node.pos)) {
|
|
3019
|
+
return statements;
|
|
3020
|
+
}
|
|
3021
|
+
let bucket = owned.get(sourceFile.fileName);
|
|
3022
|
+
if (bucket === undefined) {
|
|
3023
|
+
bucket = new Set;
|
|
3024
|
+
owned.set(sourceFile.fileName, bucket);
|
|
3025
|
+
}
|
|
3026
|
+
for (const statement of statements) {
|
|
3027
|
+
bucket.add(statement);
|
|
3028
|
+
}
|
|
3029
|
+
return statements;
|
|
3030
|
+
}
|
|
3031
|
+
const visitors = {
|
|
3032
|
+
[ts9.SyntaxKind.VariableStatement]: capture,
|
|
3033
|
+
[ts9.SyntaxKind.FunctionDeclaration]: capture,
|
|
3034
|
+
[ts9.SyntaxKind.ClassDeclaration]: capture,
|
|
3035
|
+
[ts9.SyntaxKind.EnumDeclaration]: capture,
|
|
3036
|
+
[ts9.SyntaxKind.ExportDeclaration]: capture
|
|
3037
|
+
};
|
|
3038
|
+
let configuredNoResolvePaths = [];
|
|
3039
|
+
const plugin = {
|
|
3040
|
+
visitors,
|
|
3041
|
+
beforeTransform(_program, options) {
|
|
3042
|
+
configuredNoResolvePaths = options.noResolvePaths ?? [];
|
|
3043
|
+
},
|
|
3044
|
+
afterPrint(program, options, emitHost, result) {
|
|
3045
|
+
const emitted = [];
|
|
3046
|
+
for (const file of result) {
|
|
3047
|
+
const sourceFile = file.sourceFiles?.[0];
|
|
3048
|
+
if (sourceFile === undefined || file.luaAst === undefined) {
|
|
3049
|
+
continue;
|
|
3050
|
+
}
|
|
3051
|
+
const plan = plans.get(sourceFile.fileName);
|
|
3052
|
+
const bucket = owned.get(sourceFile.fileName);
|
|
3053
|
+
if (plan === undefined || bucket === undefined || bucket.size === 0) {
|
|
3054
|
+
continue;
|
|
3055
|
+
}
|
|
3056
|
+
emitCompanion(program, emitHost, file, sourceFile, plan, bucket, companions);
|
|
3057
|
+
emitted.push(plan.requirePath);
|
|
3058
|
+
}
|
|
3059
|
+
if (emitted.length > 0) {
|
|
3060
|
+
options.noResolvePaths = [...configuredNoResolvePaths, ...emitted];
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
};
|
|
3064
|
+
return { plugin, companions };
|
|
3065
|
+
}
|
|
3066
|
+
function emitCompanion(program, emitHost, file, sourceFile, plan, owned, companions) {
|
|
3067
|
+
const luaAst = file.luaAst;
|
|
3068
|
+
if (luaAst === undefined) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
const halves = split(luaAst.statements, owned);
|
|
3072
|
+
const requirePaths = resolvedRequirePaths(sourceFile, program.getTypeChecker());
|
|
3073
|
+
resolveMovedRequires(halves.companion, requirePaths);
|
|
3074
|
+
const closureTable = createTableExpression(plan.internals.map((name) => createTableFieldExpression(createIdentifier4(name), createStringLiteral3(name))));
|
|
3075
|
+
const companionStatements = [
|
|
3076
|
+
createVariableDeclarationStatement3(exportsIdentifier(), createTableExpression()),
|
|
3077
|
+
...copiedPrelude(halves, plan.importBindings).map((statement) => withResolvedRequire(statement, requirePaths)),
|
|
3078
|
+
...halves.companion,
|
|
3079
|
+
...plan.internals.length > 0 ? [
|
|
3080
|
+
createAssignmentStatement2(createTableIndexExpression2(exportsIdentifier(), createStringLiteral3(COMPANION_INTERNAL_FIELD)), closureTable)
|
|
3081
|
+
] : [],
|
|
3082
|
+
createReturnStatement2([exportsIdentifier()])
|
|
3083
|
+
];
|
|
3084
|
+
const reads = new Set([EXPORTS_NAME, ...plan.internals]);
|
|
3085
|
+
const insertAt = requireInsertionPoint(halves.script, reads);
|
|
3086
|
+
const scriptStatements = [
|
|
3087
|
+
...halves.script.slice(0, insertAt),
|
|
3088
|
+
createVariableDeclarationStatement3(exportsIdentifier(), createCallExpression4(createIdentifier4("require"), [createStringLiteral3(plan.requirePath)])),
|
|
3089
|
+
...plan.internals.map((name) => createVariableDeclarationStatement3(createIdentifier4(name), internalsField(name))),
|
|
3090
|
+
...halves.script.slice(insertAt),
|
|
3091
|
+
createReturnStatement2([exportsIdentifier()])
|
|
3092
|
+
];
|
|
3093
|
+
const features = new Set(luaAst.luaLibFeatures);
|
|
3094
|
+
const printer = new LuaPrinter(emitHost, program, sourceFile.fileName);
|
|
3095
|
+
companions.set(sourceFile.fileName, printer.print(createFile(companionStatements, new Set(features), luaAst.trivia, sourceFile)).code);
|
|
3096
|
+
const scriptFile = createFile(scriptStatements, features, luaAst.trivia, sourceFile);
|
|
3097
|
+
const printed = new LuaPrinter(emitHost, program, sourceFile.fileName).print(scriptFile);
|
|
3098
|
+
file.luaAst = scriptFile;
|
|
3099
|
+
file.code = printed.code;
|
|
3100
|
+
file.sourceMap = printed.sourceMap;
|
|
3101
|
+
file.sourceMapNode = printed.sourceMapNode;
|
|
3102
|
+
}
|
|
3103
|
+
|
|
2058
3104
|
// src/editor-script-erasure.ts
|
|
2059
|
-
import * as
|
|
3105
|
+
import * as ts10 from "typescript";
|
|
2060
3106
|
import {
|
|
2061
|
-
createReturnStatement as
|
|
3107
|
+
createReturnStatement as createReturnStatement3
|
|
2062
3108
|
} from "typescript-to-lua";
|
|
2063
3109
|
var EDITOR_FACTORY_MODULE = "@defold-typescript/types";
|
|
2064
3110
|
var EDITOR_SCRIPT_FACTORY_NAME = "defineEditorScript";
|
|
@@ -2076,7 +3122,7 @@ function resolveEditorFactoryExport(callee, checker) {
|
|
|
2076
3122
|
if (symbol === undefined) {
|
|
2077
3123
|
return;
|
|
2078
3124
|
}
|
|
2079
|
-
if (symbol.flags &
|
|
3125
|
+
if (symbol.flags & ts10.SymbolFlags.Alias) {
|
|
2080
3126
|
symbol = checker.getAliasedSymbol(symbol);
|
|
2081
3127
|
}
|
|
2082
3128
|
const name = symbol.getName();
|
|
@@ -2090,7 +3136,7 @@ function resolveEditorFactoryExport(callee, checker) {
|
|
|
2090
3136
|
return declaration.getSourceFile().fileName.includes(EDITOR_FACTORY_MODULE) ? name : undefined;
|
|
2091
3137
|
}
|
|
2092
3138
|
function lowerEditorFactoryCall(expression, context) {
|
|
2093
|
-
if (!
|
|
3139
|
+
if (!ts10.isCallExpression(expression)) {
|
|
2094
3140
|
return;
|
|
2095
3141
|
}
|
|
2096
3142
|
if (resolveEditorFactoryExport(expression.expression, context.checker) !== EDITOR_SCRIPT_FACTORY_NAME) {
|
|
@@ -2100,10 +3146,10 @@ function lowerEditorFactoryCall(expression, context) {
|
|
|
2100
3146
|
if (module === undefined) {
|
|
2101
3147
|
return;
|
|
2102
3148
|
}
|
|
2103
|
-
return [
|
|
3149
|
+
return [createReturnStatement3([context.transformExpression(module)])];
|
|
2104
3150
|
}
|
|
2105
3151
|
function isEditorFactoryOnlyImport(node) {
|
|
2106
|
-
if (!
|
|
3152
|
+
if (!ts10.isStringLiteral(node.moduleSpecifier) || !EDITOR_FACTORY_SPECIFIERS.has(node.moduleSpecifier.text)) {
|
|
2107
3153
|
return false;
|
|
2108
3154
|
}
|
|
2109
3155
|
const clause = node.importClause;
|
|
@@ -2114,7 +3160,7 @@ function isEditorFactoryOnlyImport(node) {
|
|
|
2114
3160
|
return false;
|
|
2115
3161
|
}
|
|
2116
3162
|
const bindings = clause.namedBindings;
|
|
2117
|
-
if (bindings === undefined || !
|
|
3163
|
+
if (bindings === undefined || !ts10.isNamedImports(bindings)) {
|
|
2118
3164
|
return false;
|
|
2119
3165
|
}
|
|
2120
3166
|
const runtime = bindings.elements.filter((element) => !element.isTypeOnly);
|
|
@@ -2125,7 +3171,7 @@ function isEditorFactoryOnlyImport(node) {
|
|
|
2125
3171
|
}
|
|
2126
3172
|
var editorScriptErasurePlugin = {
|
|
2127
3173
|
visitors: {
|
|
2128
|
-
[
|
|
3174
|
+
[ts10.SyntaxKind.ExportAssignment]: (node, context) => {
|
|
2129
3175
|
if (!node.isExportEquals) {
|
|
2130
3176
|
const lowered = lowerEditorFactoryCall(node.expression, context);
|
|
2131
3177
|
if (lowered !== undefined) {
|
|
@@ -2134,14 +3180,14 @@ var editorScriptErasurePlugin = {
|
|
|
2134
3180
|
}
|
|
2135
3181
|
return context.superTransformStatements(node);
|
|
2136
3182
|
},
|
|
2137
|
-
[
|
|
3183
|
+
[ts10.SyntaxKind.CallExpression]: (node, context) => {
|
|
2138
3184
|
const command = node.arguments[0];
|
|
2139
3185
|
if (command !== undefined && resolveEditorFactoryExport(node.expression, context.checker) === EDITOR_COMMAND_FACTORY_NAME) {
|
|
2140
3186
|
return context.transformExpression(command);
|
|
2141
3187
|
}
|
|
2142
3188
|
return context.superTransformExpression(node);
|
|
2143
3189
|
},
|
|
2144
|
-
[
|
|
3190
|
+
[ts10.SyntaxKind.ImportDeclaration]: (node, context) => isEditorFactoryOnlyImport(node) ? [] : context.superTransformStatements(node)
|
|
2145
3191
|
}
|
|
2146
3192
|
};
|
|
2147
3193
|
|
|
@@ -2152,17 +3198,17 @@ import * as path2 from "node:path";
|
|
|
2152
3198
|
import * as tstl2 from "typescript-to-lua";
|
|
2153
3199
|
|
|
2154
3200
|
// src/go-property-direct-call.ts
|
|
2155
|
-
import * as
|
|
3201
|
+
import * as ts11 from "typescript";
|
|
2156
3202
|
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
3203
|
function findDirectGoPropertyCalls(sourceFile) {
|
|
2158
3204
|
const calls = [];
|
|
2159
3205
|
const visit = (node) => {
|
|
2160
|
-
if (
|
|
3206
|
+
if (ts11.isCallExpression(node) && ts11.isPropertyAccessExpression(node.expression) && node.expression.name.text === "property" && ts11.isIdentifier(node.expression.expression) && node.expression.expression.text === "go") {
|
|
2161
3207
|
calls.push(node);
|
|
2162
3208
|
}
|
|
2163
|
-
|
|
3209
|
+
ts11.forEachChild(node, visit);
|
|
2164
3210
|
};
|
|
2165
|
-
|
|
3211
|
+
ts11.forEachChild(sourceFile, visit);
|
|
2166
3212
|
return calls;
|
|
2167
3213
|
}
|
|
2168
3214
|
|
|
@@ -2261,9 +3307,10 @@ var LUALIB_BUNDLE_NAME = "lualib_bundle.lua";
|
|
|
2261
3307
|
function isLualibBundle(file) {
|
|
2262
3308
|
return file.sourceFiles.length === 0 && file.outPath.endsWith(LUALIB_BUNDLE_NAME);
|
|
2263
3309
|
}
|
|
2264
|
-
function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
3310
|
+
function collectOutputs(transpiledFiles, diagnostics, userKeys, emittedCompanions = new Map) {
|
|
2265
3311
|
const lua = {};
|
|
2266
3312
|
const sourceMaps = {};
|
|
3313
|
+
const companions = {};
|
|
2267
3314
|
let lualib;
|
|
2268
3315
|
for (const file of transpiledFiles) {
|
|
2269
3316
|
if (isLualibBundle(file) && typeof file.lua === "string") {
|
|
@@ -2278,6 +3325,10 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2278
3325
|
if (typeof file.luaSourceMap === "string") {
|
|
2279
3326
|
sourceMaps[userSource.fileName] = file.luaSourceMap;
|
|
2280
3327
|
}
|
|
3328
|
+
const companion = emittedCompanions.get(userSource.fileName);
|
|
3329
|
+
if (companion !== undefined) {
|
|
3330
|
+
companions[userSource.fileName] = companion;
|
|
3331
|
+
}
|
|
2281
3332
|
}
|
|
2282
3333
|
const collectedDiagnostics = diagnostics.map((d) => {
|
|
2283
3334
|
const fileName = d.file?.fileName;
|
|
@@ -2315,6 +3366,7 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2315
3366
|
lua,
|
|
2316
3367
|
sourceMaps,
|
|
2317
3368
|
diagnostics: collectedDiagnostics,
|
|
3369
|
+
...Object.keys(companions).length > 0 ? { companions } : {},
|
|
2318
3370
|
...lualib !== undefined ? { lualib } : {},
|
|
2319
3371
|
...timersImported ? { timersRuntime: TIMERS_RUNTIME } : {}
|
|
2320
3372
|
};
|
|
@@ -2322,6 +3374,7 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys) {
|
|
|
2322
3374
|
function transpileProject(input) {
|
|
2323
3375
|
const userKeys = new Set(Object.keys(input.files));
|
|
2324
3376
|
const merged = { ...AMBIENT_FILES, ...input.files };
|
|
3377
|
+
const companionEmit = createCompanionEmitPlugin();
|
|
2325
3378
|
const result = tstl2.transpileVirtualProject(merged, {
|
|
2326
3379
|
luaTarget: tstl2.LuaTarget.Lua51,
|
|
2327
3380
|
sourceMap: true,
|
|
@@ -2334,10 +3387,11 @@ function transpileProject(input) {
|
|
|
2334
3387
|
{ plugin: messageGuardLoweringPlugin },
|
|
2335
3388
|
{ plugin: windowEventGuardLoweringPlugin },
|
|
2336
3389
|
{ plugin: messageDispatchLoweringPlugin },
|
|
2337
|
-
{ plugin: timersLoweringPlugin }
|
|
3390
|
+
{ plugin: timersLoweringPlugin },
|
|
3391
|
+
{ plugin: companionEmit.plugin }
|
|
2338
3392
|
]
|
|
2339
3393
|
});
|
|
2340
|
-
return collectOutputs(result.transpiledFiles, result.diagnostics, userKeys);
|
|
3394
|
+
return collectOutputs(result.transpiledFiles, result.diagnostics, userKeys, companionEmit.companions);
|
|
2341
3395
|
}
|
|
2342
3396
|
function transpile(source) {
|
|
2343
3397
|
const project = transpileProject({ files: { "main.ts": source } });
|
|
@@ -2350,21 +3404,24 @@ function transpile(source) {
|
|
|
2350
3404
|
|
|
2351
3405
|
// src/session.ts
|
|
2352
3406
|
var requireFromHere2 = createRequire2(import.meta.url);
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
}
|
|
3407
|
+
function compilerOptions(companionEmit) {
|
|
3408
|
+
return {
|
|
3409
|
+
luaTarget: tstl3.LuaTarget.Lua51,
|
|
3410
|
+
sourceMap: true,
|
|
3411
|
+
lib: ["lib.es2022.d.ts"],
|
|
3412
|
+
skipLibCheck: true,
|
|
3413
|
+
noImplicitSelf: true,
|
|
3414
|
+
luaPlugins: [
|
|
3415
|
+
{ plugin: lifecycleErasurePlugin },
|
|
3416
|
+
{ plugin: editorScriptErasurePlugin },
|
|
3417
|
+
{ plugin: messageGuardLoweringPlugin },
|
|
3418
|
+
{ plugin: windowEventGuardLoweringPlugin },
|
|
3419
|
+
{ plugin: messageDispatchLoweringPlugin },
|
|
3420
|
+
{ plugin: timersLoweringPlugin },
|
|
3421
|
+
{ plugin: companionEmit.plugin }
|
|
3422
|
+
]
|
|
3423
|
+
};
|
|
3424
|
+
}
|
|
2368
3425
|
function normalizeSlashes(p) {
|
|
2369
3426
|
return p.replace(/\\/g, "/");
|
|
2370
3427
|
}
|
|
@@ -2403,7 +3460,7 @@ function createTranspileSession() {
|
|
|
2403
3460
|
if (cached) {
|
|
2404
3461
|
return cached;
|
|
2405
3462
|
}
|
|
2406
|
-
const created =
|
|
3463
|
+
const created = ts12.createSourceFile(fileName, content, ts12.ScriptTarget.Latest, false);
|
|
2407
3464
|
sourceFileCache.set(normalized, created);
|
|
2408
3465
|
return created;
|
|
2409
3466
|
}
|
|
@@ -2422,7 +3479,7 @@ function createTranspileSession() {
|
|
|
2422
3479
|
return cached;
|
|
2423
3480
|
}
|
|
2424
3481
|
const fileContent = readFileSync2(filePath, "utf8");
|
|
2425
|
-
const created =
|
|
3482
|
+
const created = ts12.createSourceFile(filePath, fileContent, ts12.ScriptTarget.Latest, false);
|
|
2426
3483
|
libCache.set(fileName, created);
|
|
2427
3484
|
return created;
|
|
2428
3485
|
}
|
|
@@ -2435,10 +3492,10 @@ function createTranspileSession() {
|
|
|
2435
3492
|
return AMBIENT_FILES[normalized];
|
|
2436
3493
|
}
|
|
2437
3494
|
const host = {
|
|
2438
|
-
fileExists: (fileName) => mergedContent(normalizeSlashes(fileName)) !== undefined ||
|
|
3495
|
+
fileExists: (fileName) => mergedContent(normalizeSlashes(fileName)) !== undefined || ts12.sys.fileExists(fileName),
|
|
2439
3496
|
getCanonicalFileName: (fileName) => fileName,
|
|
2440
3497
|
getCurrentDirectory: () => "",
|
|
2441
|
-
getDefaultLibFileName:
|
|
3498
|
+
getDefaultLibFileName: ts12.getDefaultLibFileName,
|
|
2442
3499
|
readFile: () => "",
|
|
2443
3500
|
getNewLine: () => `
|
|
2444
3501
|
`,
|
|
@@ -2459,17 +3516,18 @@ function createTranspileSession() {
|
|
|
2459
3516
|
}
|
|
2460
3517
|
const userKeys = new Set(userFiles.keys());
|
|
2461
3518
|
const rootNames = [...Object.keys(AMBIENT_FILES).map(normalizeSlashes), ...userKeys];
|
|
2462
|
-
|
|
2463
|
-
|
|
3519
|
+
const companionEmit = createCompanionEmitPlugin();
|
|
3520
|
+
program = ts12.createProgram(rootNames, compilerOptions(companionEmit), host, program);
|
|
3521
|
+
const preEmitDiagnostics = ts12.getPreEmitDiagnostics(program);
|
|
2464
3522
|
const collector = createOutputCollector();
|
|
2465
3523
|
const { diagnostics: transpileDiagnostics } = new tstl3.Transpiler().emit({
|
|
2466
3524
|
program,
|
|
2467
3525
|
writeFile: collector.writeFile
|
|
2468
3526
|
});
|
|
2469
3527
|
const diagnostics = [
|
|
2470
|
-
...
|
|
3528
|
+
...ts12.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics])
|
|
2471
3529
|
];
|
|
2472
|
-
return collectOutputs(collector.files, diagnostics, userKeys);
|
|
3530
|
+
return collectOutputs(collector.files, diagnostics, userKeys, companionEmit.companions);
|
|
2473
3531
|
}
|
|
2474
3532
|
return {
|
|
2475
3533
|
update,
|
|
@@ -2477,7 +3535,7 @@ function createTranspileSession() {
|
|
|
2477
3535
|
};
|
|
2478
3536
|
}
|
|
2479
3537
|
// src/url-address-slots.ts
|
|
2480
|
-
import * as
|
|
3538
|
+
import * as ts13 from "typescript";
|
|
2481
3539
|
var ADDRESS_CLASSES = {
|
|
2482
3540
|
"game-object": true,
|
|
2483
3541
|
component: true,
|
|
@@ -2496,7 +3554,7 @@ function isFragmentCaret(slot, position) {
|
|
|
2496
3554
|
return slot.fragmentStart !== -1 && position >= slot.fragmentStart;
|
|
2497
3555
|
}
|
|
2498
3556
|
function tableKey(checker, callee) {
|
|
2499
|
-
const symbol = checker.getSymbolAtLocation(
|
|
3557
|
+
const symbol = checker.getSymbolAtLocation(ts13.isIdentifier(callee) ? callee : callee.name);
|
|
2500
3558
|
if (!symbol)
|
|
2501
3559
|
return;
|
|
2502
3560
|
const fqn = checker.getFullyQualifiedName(symbol);
|
|
@@ -2504,43 +3562,43 @@ function tableKey(checker, callee) {
|
|
|
2504
3562
|
}
|
|
2505
3563
|
function parameterName(checker, call, index) {
|
|
2506
3564
|
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
2507
|
-
if (!declaration || !
|
|
3565
|
+
if (!declaration || !ts13.isFunctionLike(declaration))
|
|
2508
3566
|
return;
|
|
2509
3567
|
const parameter = declaration.parameters[index];
|
|
2510
|
-
if (!parameter || parameter.dotDotDotToken || !
|
|
3568
|
+
if (!parameter || parameter.dotDotDotToken || !ts13.isIdentifier(parameter.name))
|
|
2511
3569
|
return;
|
|
2512
3570
|
return parameter.name.text;
|
|
2513
3571
|
}
|
|
2514
3572
|
var EQUALITY_OPERATORS = new Set([
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
3573
|
+
ts13.SyntaxKind.EqualsEqualsEqualsToken,
|
|
3574
|
+
ts13.SyntaxKind.ExclamationEqualsEqualsToken,
|
|
3575
|
+
ts13.SyntaxKind.EqualsEqualsToken,
|
|
3576
|
+
ts13.SyntaxKind.ExclamationEqualsToken
|
|
2519
3577
|
]);
|
|
2520
3578
|
function comparisonSatisfied(checker, entry, call) {
|
|
2521
3579
|
if (entry.comparedParameter === undefined)
|
|
2522
3580
|
return true;
|
|
2523
3581
|
let node = call;
|
|
2524
|
-
while (
|
|
3582
|
+
while (ts13.isParenthesizedExpression(node.parent))
|
|
2525
3583
|
node = node.parent;
|
|
2526
3584
|
const comparison = node.parent;
|
|
2527
|
-
if (!
|
|
3585
|
+
if (!ts13.isBinaryExpression(comparison))
|
|
2528
3586
|
return false;
|
|
2529
3587
|
if (!EQUALITY_OPERATORS.has(comparison.operatorToken.kind))
|
|
2530
3588
|
return false;
|
|
2531
3589
|
const other = comparison.left === node ? comparison.right : comparison.left;
|
|
2532
3590
|
const symbol = checker.getSymbolAtLocation(other);
|
|
2533
|
-
return (symbol?.declarations ?? []).some((declaration) =>
|
|
3591
|
+
return (symbol?.declarations ?? []).some((declaration) => ts13.isParameter(declaration) && ts13.isIdentifier(declaration.name) && declaration.name.text === entry.comparedParameter);
|
|
2534
3592
|
}
|
|
2535
3593
|
function classifiedEntryOfArgument(checker, table, argument) {
|
|
2536
3594
|
const call = argument.parent;
|
|
2537
|
-
if (!
|
|
3595
|
+
if (!ts13.isCallExpression(call))
|
|
2538
3596
|
return;
|
|
2539
3597
|
const argumentIndex = call.arguments.indexOf(argument);
|
|
2540
3598
|
if (argumentIndex === -1)
|
|
2541
3599
|
return;
|
|
2542
3600
|
const callee = call.expression;
|
|
2543
|
-
if (!
|
|
3601
|
+
if (!ts13.isPropertyAccessExpression(callee) && !ts13.isIdentifier(callee))
|
|
2544
3602
|
return;
|
|
2545
3603
|
const fqn = tableKey(checker, callee);
|
|
2546
3604
|
if (fqn === undefined)
|
|
@@ -2557,10 +3615,10 @@ function classifiedEntryOfArgument(checker, table, argument) {
|
|
|
2557
3615
|
}
|
|
2558
3616
|
function slotThroughHashedCall(checker, table, literal) {
|
|
2559
3617
|
const call = literal.parent;
|
|
2560
|
-
if (!
|
|
3618
|
+
if (!ts13.isCallExpression(call))
|
|
2561
3619
|
return;
|
|
2562
3620
|
const callee = call.expression;
|
|
2563
|
-
if (!
|
|
3621
|
+
if (!ts13.isPropertyAccessExpression(callee) && !ts13.isIdentifier(callee))
|
|
2564
3622
|
return;
|
|
2565
3623
|
if (tableKey(checker, callee) !== "hash")
|
|
2566
3624
|
return;
|
|
@@ -2578,24 +3636,24 @@ function addressTextOf(checker, entry, call) {
|
|
|
2578
3636
|
if (entry.addressParameter === undefined)
|
|
2579
3637
|
return;
|
|
2580
3638
|
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
2581
|
-
if (!declaration || !
|
|
3639
|
+
if (!declaration || !ts13.isFunctionLike(declaration))
|
|
2582
3640
|
return;
|
|
2583
|
-
const index = declaration.parameters.findIndex((parameter) => !parameter.dotDotDotToken &&
|
|
3641
|
+
const index = declaration.parameters.findIndex((parameter) => !parameter.dotDotDotToken && ts13.isIdentifier(parameter.name) && parameter.name.text === entry.addressParameter);
|
|
2584
3642
|
if (index === -1)
|
|
2585
3643
|
return;
|
|
2586
3644
|
const argument = call.arguments[index];
|
|
2587
|
-
return argument &&
|
|
3645
|
+
return argument && ts13.isStringLiteralLike(argument) ? argument.text : undefined;
|
|
2588
3646
|
}
|
|
2589
3647
|
function innermostLiteralAt(sourceFile, position) {
|
|
2590
3648
|
let found;
|
|
2591
3649
|
const visit = (node) => {
|
|
2592
3650
|
if (position < node.getStart(sourceFile) || position > node.getEnd())
|
|
2593
3651
|
return;
|
|
2594
|
-
if (
|
|
3652
|
+
if (ts13.isStringLiteralLike(node))
|
|
2595
3653
|
found = node;
|
|
2596
|
-
|
|
3654
|
+
ts13.forEachChild(node, visit);
|
|
2597
3655
|
};
|
|
2598
|
-
|
|
3656
|
+
ts13.forEachChild(sourceFile, visit);
|
|
2599
3657
|
return found;
|
|
2600
3658
|
}
|
|
2601
3659
|
function resolveClassifiedSlotAtPosition(input) {
|
|
@@ -2629,23 +3687,23 @@ function resolveClassifiedSlotAtPosition(input) {
|
|
|
2629
3687
|
};
|
|
2630
3688
|
}
|
|
2631
3689
|
// src/url-cross-world-address.ts
|
|
2632
|
-
import * as
|
|
3690
|
+
import * as ts15 from "typescript";
|
|
2633
3691
|
|
|
2634
3692
|
// src/url-address-literals.ts
|
|
2635
|
-
import * as
|
|
3693
|
+
import * as ts14 from "typescript";
|
|
2636
3694
|
function isAmbient2(fileName) {
|
|
2637
3695
|
return /[\\/]node_modules[\\/]/.test(fileName) || /(^|[\\/])lib\.[^\\/]*\.d\.ts$/.test(fileName);
|
|
2638
3696
|
}
|
|
2639
3697
|
function referenceTargetSymbol(type) {
|
|
2640
|
-
if ((type.flags &
|
|
3698
|
+
if ((type.flags & ts14.TypeFlags.Object) === 0)
|
|
2641
3699
|
return;
|
|
2642
|
-
if ((type.objectFlags &
|
|
3700
|
+
if ((type.objectFlags & ts14.ObjectFlags.Reference) === 0)
|
|
2643
3701
|
return;
|
|
2644
3702
|
return type.target.symbol;
|
|
2645
3703
|
}
|
|
2646
3704
|
function ambientHashAliasTargets(checker, anchor) {
|
|
2647
3705
|
const targets = new Set;
|
|
2648
|
-
for (const symbol of checker.getSymbolsInScope(anchor,
|
|
3706
|
+
for (const symbol of checker.getSymbolsInScope(anchor, ts14.SymbolFlags.Type)) {
|
|
2649
3707
|
if (symbol.name !== "Hash")
|
|
2650
3708
|
continue;
|
|
2651
3709
|
const target = referenceTargetSymbol(checker.getDeclaredTypeOfSymbol(symbol));
|
|
@@ -2661,7 +3719,7 @@ function canonicalHashSymbols(checker, program) {
|
|
|
2661
3719
|
if (!anchor)
|
|
2662
3720
|
return canonical;
|
|
2663
3721
|
const aliased = ambientHashAliasTargets(checker, anchor);
|
|
2664
|
-
for (const symbol of checker.getSymbolsInScope(anchor,
|
|
3722
|
+
for (const symbol of checker.getSymbolsInScope(anchor, ts14.SymbolFlags.Function)) {
|
|
2665
3723
|
if (symbol.name !== "hash")
|
|
2666
3724
|
continue;
|
|
2667
3725
|
const declaration = symbol.declarations?.[0];
|
|
@@ -2683,7 +3741,7 @@ function hashedSourceOfType(checker, type, canonical) {
|
|
|
2683
3741
|
return source?.isStringLiteral() ? source.value : undefined;
|
|
2684
3742
|
}
|
|
2685
3743
|
function staticAddressTextOf(checker, node, canonical) {
|
|
2686
|
-
return
|
|
3744
|
+
return ts14.isStringLiteralLike(node) ? node.text : hashedSourceOfType(checker, checker.getTypeAtLocation(node), canonical);
|
|
2687
3745
|
}
|
|
2688
3746
|
|
|
2689
3747
|
// src/url-cross-world-address.ts
|
|
@@ -2707,7 +3765,7 @@ function checkCrossWorldAddresses(input) {
|
|
|
2707
3765
|
if (worlds.length === 0)
|
|
2708
3766
|
continue;
|
|
2709
3767
|
const visit = (node) => {
|
|
2710
|
-
if (
|
|
3768
|
+
if (ts15.isExpression(node)) {
|
|
2711
3769
|
const entry = addressEntryOfArgument(checker, table, node);
|
|
2712
3770
|
if (entry !== undefined && slotRejectsForeignSocket(entry)) {
|
|
2713
3771
|
const address = staticAddressTextOf(checker, node, canonical);
|
|
@@ -2724,14 +3782,14 @@ function checkCrossWorldAddresses(input) {
|
|
|
2724
3782
|
}
|
|
2725
3783
|
}
|
|
2726
3784
|
}
|
|
2727
|
-
|
|
3785
|
+
ts15.forEachChild(node, visit);
|
|
2728
3786
|
};
|
|
2729
|
-
|
|
3787
|
+
ts15.forEachChild(sourceFile, visit);
|
|
2730
3788
|
}
|
|
2731
3789
|
return findings;
|
|
2732
3790
|
}
|
|
2733
3791
|
// src/url-fragment-reachability.ts
|
|
2734
|
-
import * as
|
|
3792
|
+
import * as ts16 from "typescript";
|
|
2735
3793
|
function pathOfKey(key) {
|
|
2736
3794
|
const socket = socketOfAddress(key);
|
|
2737
3795
|
return socket === undefined ? key : key.slice(socket.length + 1);
|
|
@@ -2776,7 +3834,7 @@ function checkUrlFragmentReachability(input) {
|
|
|
2776
3834
|
if (isAmbient2(sourceFile.fileName))
|
|
2777
3835
|
continue;
|
|
2778
3836
|
const visit = (node) => {
|
|
2779
|
-
if (
|
|
3837
|
+
if (ts16.isExpression(node) && isAddressClass(addressClassOfArgument(checker, table, node))) {
|
|
2780
3838
|
const text = staticAddressTextOf(checker, node, canonical);
|
|
2781
3839
|
if (text !== undefined) {
|
|
2782
3840
|
const hash = text.indexOf("#");
|
|
@@ -2795,26 +3853,29 @@ function checkUrlFragmentReachability(input) {
|
|
|
2795
3853
|
}
|
|
2796
3854
|
}
|
|
2797
3855
|
}
|
|
2798
|
-
|
|
3856
|
+
ts16.forEachChild(node, visit);
|
|
2799
3857
|
};
|
|
2800
|
-
|
|
3858
|
+
ts16.forEachChild(sourceFile, visit);
|
|
2801
3859
|
}
|
|
2802
3860
|
return { kind: "checked", findings };
|
|
2803
3861
|
}
|
|
2804
3862
|
export {
|
|
2805
3863
|
ANIMATION_ASSET_EXTENSIONS,
|
|
2806
3864
|
COLLECTION_REFERENCE_EXTENSIONS,
|
|
3865
|
+
COMPANION_INTERNAL_FIELD,
|
|
2807
3866
|
DEFAULT_INCLUDE,
|
|
2808
3867
|
GAME_PROJECT_DOCUMENT,
|
|
2809
3868
|
GUI_EXTENSIONS,
|
|
2810
3869
|
INPUT_BINDING_EXTENSIONS,
|
|
2811
3870
|
LIBRARY_DEPENDENCY_ROOT,
|
|
2812
3871
|
LIBRARY_SCENE_EXTENSIONS,
|
|
3872
|
+
LUALIB_REQUIRE_NAME,
|
|
2813
3873
|
PROJECT_EXTENSIONS,
|
|
2814
3874
|
SCAFFOLDED_DEFIGNORE_LINES,
|
|
2815
3875
|
SCENE_EXTENSIONS,
|
|
2816
3876
|
SCRIPT_SUFFIX_BY_KIND,
|
|
2817
3877
|
SceneTextFormatError,
|
|
3878
|
+
TIMERS_REQUIRE_NAME,
|
|
2818
3879
|
addressClassOfArgument,
|
|
2819
3880
|
addressEntryOfArgument,
|
|
2820
3881
|
archiveWrapperOf,
|
|
@@ -2833,9 +3894,11 @@ export {
|
|
|
2833
3894
|
collectComponentDeclarations,
|
|
2834
3895
|
collectComponentIds,
|
|
2835
3896
|
componentIdOfSameObjectAddress,
|
|
3897
|
+
computeCompanionClosure,
|
|
2836
3898
|
computeOutputRel,
|
|
2837
3899
|
createTranspileSession,
|
|
2838
3900
|
displayPathOf,
|
|
3901
|
+
findEmittedRequires,
|
|
2839
3902
|
findMainEntryFactoryImports,
|
|
2840
3903
|
getProgramDiagnostics,
|
|
2841
3904
|
guiScriptResourceOf,
|
|
@@ -2849,12 +3912,15 @@ export {
|
|
|
2849
3912
|
listProjectResourcePaths,
|
|
2850
3913
|
parseBuildConfig,
|
|
2851
3914
|
parseSceneTextFormat,
|
|
3915
|
+
projectRelativeBase,
|
|
2852
3916
|
readGameProjectDependencies,
|
|
2853
3917
|
readGameProjectSetting,
|
|
2854
3918
|
readLibrarySceneDocuments,
|
|
2855
3919
|
readSceneDocuments,
|
|
2856
3920
|
relativeAddressesFrom,
|
|
3921
|
+
requirePathForRel,
|
|
2857
3922
|
resolveClassifiedSlotAtPosition,
|
|
3923
|
+
rewriteEmittedRequires,
|
|
2858
3924
|
slotRejectsForeignSocket,
|
|
2859
3925
|
socketOfAddress,
|
|
2860
3926
|
stripIncludeBase,
|