@defold-typescript/transpiler 0.51.0 → 0.52.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/index.d.ts +1 -0
- package/dist/index.js +180 -12
- package/dist/lifecycle-erasure.d.ts +1 -0
- package/dist/transpile.d.ts +3 -0
- package/package.json +2 -2
- package/src/hsm-builtin.ts +2 -2
- package/src/index.ts +1 -0
- package/src/lifecycle-erasure.ts +233 -8
- package/src/timers-runtime.ts +2 -2
- package/src/transpile.ts +48 -12
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { HSM_MODULE_SPECIFIER, HSM_REQUIRE_ROOT, hsmModules, hsmRequireName, hsm
|
|
|
13
13
|
export { buildInputActionIndex } from "./input-action-index";
|
|
14
14
|
export type { ExtensionDependency, LibraryIncludedEntries, LibrarySceneDocument, LibrarySceneDocuments, LibrarySharedEntry, } from "./library-dependencies";
|
|
15
15
|
export { archiveWrapperOf, isContainedResourcePath, LIBRARY_DEPENDENCY_ROOT, libraryIncludedEntries, readGameProjectDependencies, readLibrarySceneDocuments, } from "./library-dependencies";
|
|
16
|
+
export { scanEmittedRequires } from "./lua-require-scan";
|
|
16
17
|
export { findMainEntryFactoryImports } from "./main-entry-factory-imports";
|
|
17
18
|
export type { BuildConfig, ScriptKind, SourceOutputKind } from "./output-paths";
|
|
18
19
|
export { computeOutputRel, DEFAULT_INCLUDE, parseBuildConfig, projectRelativeBase, requirePathForRel, SCRIPT_SUFFIX_BY_KIND, stripIncludeBase, } from "./output-paths";
|
package/dist/index.js
CHANGED
|
@@ -172,22 +172,26 @@ var FACTORY_SPECIFIERS = new Set([
|
|
|
172
172
|
`${FACTORY_MODULE}/gui-script`,
|
|
173
173
|
`${FACTORY_MODULE}/render-script`
|
|
174
174
|
]);
|
|
175
|
-
function
|
|
175
|
+
function factoryExportName(callee, checker) {
|
|
176
176
|
let symbol = checker.getSymbolAtLocation(callee);
|
|
177
177
|
if (symbol === undefined) {
|
|
178
|
-
return
|
|
178
|
+
return;
|
|
179
179
|
}
|
|
180
180
|
if (symbol.flags & ts2.SymbolFlags.Alias) {
|
|
181
181
|
symbol = checker.getAliasedSymbol(symbol);
|
|
182
182
|
}
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
const name = symbol.getName();
|
|
184
|
+
if (!FACTORY_NAMES.has(name)) {
|
|
185
|
+
return;
|
|
185
186
|
}
|
|
186
187
|
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
187
188
|
if (declaration === undefined) {
|
|
188
|
-
return
|
|
189
|
+
return;
|
|
189
190
|
}
|
|
190
|
-
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE);
|
|
191
|
+
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE) ? name : undefined;
|
|
192
|
+
}
|
|
193
|
+
function resolvesToFactoryExport(callee, checker) {
|
|
194
|
+
return factoryExportName(callee, checker) !== undefined;
|
|
191
195
|
}
|
|
192
196
|
function isThisParameter2(param) {
|
|
193
197
|
return ts2.isIdentifier(param.name) && ts2.identifierToKeywordKind(param.name) === ts2.SyntaxKind.ThisKeyword;
|
|
@@ -270,6 +274,15 @@ function emitInitMerge(fn, context, property) {
|
|
|
270
274
|
const initFn = createFunctionExpression2(createBlock2([stateDecl, guard]), [createIdentifier2("self")], undefined, NodeFlags2.Declaration, fn);
|
|
271
275
|
return [builderDecl, createAssignmentStatement(createIdentifier2("init"), initFn, property)];
|
|
272
276
|
}
|
|
277
|
+
var RESOURCE_PROPERTY_MARKERS = new Set([
|
|
278
|
+
"resource.atlas",
|
|
279
|
+
"resource.buffer",
|
|
280
|
+
"resource.font",
|
|
281
|
+
"resource.material",
|
|
282
|
+
"resource.render_target",
|
|
283
|
+
"resource.texture",
|
|
284
|
+
"resource.tile_source"
|
|
285
|
+
]);
|
|
273
286
|
function propertyMembers(property) {
|
|
274
287
|
if (!ts2.isPropertyAssignment(property) || !ts2.isObjectLiteralExpression(property.initializer)) {
|
|
275
288
|
return [];
|
|
@@ -306,11 +319,108 @@ function isPropertiesHook(property) {
|
|
|
306
319
|
function emitPropertyRegistrations(property, context) {
|
|
307
320
|
return propertyMembers(property).map(({ name, initializer }) => createExpressionStatement(createCallExpression2(createTableIndexExpression(createIdentifier2("go"), createStringLiteral2("property")), [createStringLiteral2(name), context.transformExpression(initializer)])));
|
|
308
321
|
}
|
|
322
|
+
function scriptOnlyProperties(property, factory) {
|
|
323
|
+
const file = property.getSourceFile();
|
|
324
|
+
const start = property.getStart(file);
|
|
325
|
+
return {
|
|
326
|
+
file,
|
|
327
|
+
start,
|
|
328
|
+
length: property.getEnd() - start,
|
|
329
|
+
category: ts2.DiagnosticCategory.Error,
|
|
330
|
+
code: 0,
|
|
331
|
+
messageText: `\`${factory}\` cannot declare \`properties\`: Defold builds \`go.property\` only in \`.script\` files. Declare the property in a \`defineScript\` and send its value with \`msg.post\`.`
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function outermostWrapper(node) {
|
|
335
|
+
let current = node;
|
|
336
|
+
while (ts2.isParenthesizedExpression(current.parent) || ts2.isAsExpression(current.parent) || ts2.isSatisfiesExpression(current.parent) || ts2.isNonNullExpression(current.parent) || ts2.isTypeAssertionExpression(current.parent)) {
|
|
337
|
+
current = current.parent;
|
|
338
|
+
}
|
|
339
|
+
return current;
|
|
340
|
+
}
|
|
341
|
+
function innermostExpression(node) {
|
|
342
|
+
let current = node;
|
|
343
|
+
while (ts2.isParenthesizedExpression(current) || ts2.isAsExpression(current) || ts2.isSatisfiesExpression(current) || ts2.isNonNullExpression(current) || ts2.isTypeAssertionExpression(current)) {
|
|
344
|
+
current = current.expression;
|
|
345
|
+
}
|
|
346
|
+
return current;
|
|
347
|
+
}
|
|
348
|
+
function globalName(symbol, checker) {
|
|
349
|
+
if (symbol === undefined) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const fqn = checker.getFullyQualifiedName(symbol);
|
|
353
|
+
return fqn.startsWith("global.") ? fqn.slice("global.".length) : undefined;
|
|
354
|
+
}
|
|
355
|
+
function calledGlobal(call, checker) {
|
|
356
|
+
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
357
|
+
if (declaration === undefined || !ts2.isFunctionDeclaration(declaration) || declaration.name === undefined) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
return globalName(checker.getSymbolAtLocation(declaration.name), checker);
|
|
361
|
+
}
|
|
362
|
+
function isPropertyDefault(call, checker) {
|
|
363
|
+
const value = outermostWrapper(call);
|
|
364
|
+
const parent = value.parent;
|
|
365
|
+
if (ts2.isCallExpression(parent)) {
|
|
366
|
+
return parent.arguments[1] === value && calledGlobal(parent, checker) === "go.property";
|
|
367
|
+
}
|
|
368
|
+
const properties = parent?.parent?.parent;
|
|
369
|
+
if (properties === undefined || !ts2.isPropertyAssignment(properties) || !isPropertiesHook(properties)) {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
const hooks = properties.parent;
|
|
373
|
+
return ts2.isObjectLiteralExpression(hooks) && factoryHooks(hooks.parent, checker) === hooks && propertyMembers(properties).some((member) => member.initializer === value);
|
|
374
|
+
}
|
|
375
|
+
function misplacedMarker(node, marker) {
|
|
376
|
+
const file = node.getSourceFile();
|
|
377
|
+
const start = node.getStart(file);
|
|
378
|
+
return {
|
|
379
|
+
file,
|
|
380
|
+
start,
|
|
381
|
+
length: node.getEnd() - start,
|
|
382
|
+
category: ts2.DiagnosticCategory.Error,
|
|
383
|
+
code: 0,
|
|
384
|
+
messageText: `\`${marker}\` is a build-time marker: Defold's build reads it only in a \`go.property\` default, and the engine binds no such function. Use it as a \`defineScript\` \`properties\` default.`
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function readsAsMarker(call) {
|
|
388
|
+
const callee = innermostExpression(call.expression);
|
|
389
|
+
if (ts2.isOptionalChain(call) || ts2.isOptionalChain(callee)) {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
if (!ts2.isPropertyAccessExpression(callee) && !(ts2.isElementAccessExpression(callee) && ts2.isStringLiteralLike(innermostExpression(callee.argumentExpression)))) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
const receiver = innermostExpression(callee.expression);
|
|
396
|
+
if (!ts2.isIdentifier(receiver) || receiver.text !== "resource") {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
const [path] = call.arguments;
|
|
400
|
+
return path === undefined || ts2.isStringLiteralLike(innermostExpression(path));
|
|
401
|
+
}
|
|
402
|
+
function unreadableMarker(node, marker) {
|
|
403
|
+
const file = node.getSourceFile();
|
|
404
|
+
const start = node.getStart(file);
|
|
405
|
+
return {
|
|
406
|
+
file,
|
|
407
|
+
start,
|
|
408
|
+
length: node.getEnd() - start,
|
|
409
|
+
category: ts2.DiagnosticCategory.Error,
|
|
410
|
+
code: 0,
|
|
411
|
+
messageText: `\`${marker}\` in a property default must be written \`${marker}("<path>")\`, with a string literal path: Defold's build reads no other form.`
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function isCallee(node) {
|
|
415
|
+
const callee = outermostWrapper(node);
|
|
416
|
+
return ts2.isCallExpression(callee.parent) && callee.parent.expression === callee;
|
|
417
|
+
}
|
|
309
418
|
function eraseFactoryCall(expression, context) {
|
|
310
419
|
const hooks = factoryHooks(expression, context.checker);
|
|
311
|
-
if (hooks === undefined) {
|
|
420
|
+
if (hooks === undefined || !ts2.isCallExpression(expression)) {
|
|
312
421
|
return;
|
|
313
422
|
}
|
|
423
|
+
const factory = factoryExportName(expression.expression, context.checker);
|
|
314
424
|
const registrations = [];
|
|
315
425
|
const statements = [];
|
|
316
426
|
for (const property of hooks.properties) {
|
|
@@ -319,7 +429,11 @@ function eraseFactoryCall(expression, context) {
|
|
|
319
429
|
continue;
|
|
320
430
|
}
|
|
321
431
|
if (name === "properties") {
|
|
322
|
-
|
|
432
|
+
if (factory === "defineScript") {
|
|
433
|
+
registrations.push(...emitPropertyRegistrations(property, context));
|
|
434
|
+
} else if (factory !== undefined && propertyMembers(property).length > 0) {
|
|
435
|
+
context.diagnostics.push(scriptOnlyProperties(property, factory));
|
|
436
|
+
}
|
|
323
437
|
continue;
|
|
324
438
|
}
|
|
325
439
|
const fn = hookFunction(property);
|
|
@@ -373,7 +487,37 @@ var lifecycleErasurePlugin = {
|
|
|
373
487
|
}
|
|
374
488
|
return context.superTransformStatements(node);
|
|
375
489
|
},
|
|
376
|
-
[ts2.SyntaxKind.ImportDeclaration]: (node, context) => isFactoryOnlyImport(node) ? [] : context.superTransformStatements(node)
|
|
490
|
+
[ts2.SyntaxKind.ImportDeclaration]: (node, context) => isFactoryOnlyImport(node) ? [] : context.superTransformStatements(node),
|
|
491
|
+
[ts2.SyntaxKind.CallExpression]: (node, context) => {
|
|
492
|
+
const marker = node.parent === undefined ? undefined : calledGlobal(node, context.checker);
|
|
493
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
494
|
+
if (!isPropertyDefault(node, context.checker)) {
|
|
495
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
496
|
+
} else if (!readsAsMarker(node)) {
|
|
497
|
+
context.diagnostics.push(unreadableMarker(node, marker));
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return context.superTransformExpression(node);
|
|
501
|
+
},
|
|
502
|
+
[ts2.SyntaxKind.PropertyAccessExpression]: (node, context) => {
|
|
503
|
+
if (node.parent !== undefined && !isCallee(node)) {
|
|
504
|
+
const marker = globalName(context.checker.getSymbolAtLocation(node.name), context.checker);
|
|
505
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
506
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return context.superTransformExpression(node);
|
|
510
|
+
},
|
|
511
|
+
[ts2.SyntaxKind.ElementAccessExpression]: (node, context) => {
|
|
512
|
+
if (node.parent !== undefined && !isCallee(node)) {
|
|
513
|
+
const key = innermostExpression(node.argumentExpression);
|
|
514
|
+
const marker = ts2.isStringLiteralLike(key) ? globalName(context.checker.getPropertyOfType(context.checker.getTypeAtLocation(node.expression), key.text), context.checker) : undefined;
|
|
515
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
516
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return context.superTransformExpression(node);
|
|
520
|
+
}
|
|
377
521
|
}
|
|
378
522
|
};
|
|
379
523
|
|
|
@@ -3694,6 +3838,7 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys, emittedCompanion
|
|
|
3694
3838
|
}
|
|
3695
3839
|
}
|
|
3696
3840
|
const hsm = hsmClosure([...Object.values(lua), ...Object.values(companions)], compileHsmModules);
|
|
3841
|
+
const hsmSourceMaps = hsm === undefined ? undefined : selectHsmSourceMaps(Object.keys(hsm));
|
|
3697
3842
|
return {
|
|
3698
3843
|
lua,
|
|
3699
3844
|
sourceMaps,
|
|
@@ -3701,9 +3846,21 @@ function collectOutputs(transpiledFiles, diagnostics, userKeys, emittedCompanion
|
|
|
3701
3846
|
...Object.keys(companions).length > 0 ? { companions } : {},
|
|
3702
3847
|
...lualib !== undefined ? { lualib } : {},
|
|
3703
3848
|
...timersImported ? { timersRuntime: TIMERS_RUNTIME } : {},
|
|
3704
|
-
...hsm !== undefined ? { hsmModules: hsm } : {}
|
|
3849
|
+
...hsm !== undefined ? { hsmModules: hsm } : {},
|
|
3850
|
+
...hsmSourceMaps !== undefined ? { hsmSourceMaps } : {}
|
|
3705
3851
|
};
|
|
3706
3852
|
}
|
|
3853
|
+
function selectHsmSourceMaps(names) {
|
|
3854
|
+
const maps = compileHsmSourceMaps();
|
|
3855
|
+
const selected = {};
|
|
3856
|
+
for (const name of names) {
|
|
3857
|
+
const map = maps[name];
|
|
3858
|
+
if (map !== undefined) {
|
|
3859
|
+
selected[name] = map;
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
return selected;
|
|
3863
|
+
}
|
|
3707
3864
|
function transpileVirtual(files, companionEmit, overrides = {}) {
|
|
3708
3865
|
return tstl2.transpileVirtualProject({ ...AMBIENT_FILES, ...files }, {
|
|
3709
3866
|
luaTarget: tstl2.LuaTarget.Lua51,
|
|
@@ -3738,6 +3895,12 @@ function requiresLualib(lua) {
|
|
|
3738
3895
|
return scanEmittedRequires(lua).some(({ path: requirePath }) => requirePath === "lualib_bundle");
|
|
3739
3896
|
}
|
|
3740
3897
|
function compileHsmModules() {
|
|
3898
|
+
return compileHsm().lua;
|
|
3899
|
+
}
|
|
3900
|
+
function compileHsmSourceMaps() {
|
|
3901
|
+
return compileHsm().sourceMaps;
|
|
3902
|
+
}
|
|
3903
|
+
function compileHsm() {
|
|
3741
3904
|
if (compiledHsm !== undefined) {
|
|
3742
3905
|
return compiledHsm;
|
|
3743
3906
|
}
|
|
@@ -3752,6 +3915,7 @@ function compileHsmModules() {
|
|
|
3752
3915
|
const result = transpileVirtual(files, createCompanionEmitPlugin(), { removeComments: true });
|
|
3753
3916
|
const problems = result.diagnostics.map((d) => `${d.file?.fileName ?? "(project)"}: ${flattenDiagnosticMessage(d.messageText)}`);
|
|
3754
3917
|
const lua = {};
|
|
3918
|
+
const sourceMaps = {};
|
|
3755
3919
|
for (const file of result.transpiledFiles) {
|
|
3756
3920
|
if (isLualibBundle(file)) {
|
|
3757
3921
|
continue;
|
|
@@ -3765,14 +3929,17 @@ function compileHsmModules() {
|
|
|
3765
3929
|
problems.push(`the compiled ${name} module requires lualib_bundle`);
|
|
3766
3930
|
}
|
|
3767
3931
|
lua[name] = file.lua;
|
|
3932
|
+
if (typeof file.luaSourceMap === "string") {
|
|
3933
|
+
sourceMaps[name] = file.luaSourceMap;
|
|
3934
|
+
}
|
|
3768
3935
|
}
|
|
3769
3936
|
if (problems.length > 0) {
|
|
3770
3937
|
throw new Error(`@defold-typescript/transpiler: the hsm library does not compile:
|
|
3771
3938
|
${problems.join(`
|
|
3772
3939
|
`)}`);
|
|
3773
3940
|
}
|
|
3774
|
-
compiledHsm = lua;
|
|
3775
|
-
return
|
|
3941
|
+
compiledHsm = { lua, sourceMaps };
|
|
3942
|
+
return compiledHsm;
|
|
3776
3943
|
}
|
|
3777
3944
|
function transpile(source) {
|
|
3778
3945
|
const project = transpileProject({ files: { "main.ts": source } });
|
|
@@ -4379,6 +4546,7 @@ export {
|
|
|
4379
4546
|
resolveClassifiedSlotAtPosition,
|
|
4380
4547
|
resolveHsmSourceDir,
|
|
4381
4548
|
rewriteEmittedRequires,
|
|
4549
|
+
scanEmittedRequires,
|
|
4382
4550
|
slotRejectsForeignSocket,
|
|
4383
4551
|
socketOfAddress,
|
|
4384
4552
|
stripIncludeBase,
|
|
@@ -3,6 +3,7 @@ import { type Plugin } from "typescript-to-lua";
|
|
|
3
3
|
export declare const FACTORY_MODULE = "@defold-typescript/types";
|
|
4
4
|
export declare const FACTORY_NAMES: Set<string>;
|
|
5
5
|
export declare function resolvesToFactoryExport(callee: ts.Expression, checker: ts.TypeChecker): boolean;
|
|
6
|
+
export declare const RESOURCE_PROPERTY_MARKERS: ReadonlySet<string>;
|
|
6
7
|
export interface PropertyMember {
|
|
7
8
|
readonly name: string;
|
|
8
9
|
readonly initializer: ts.Expression;
|
package/dist/transpile.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface TranspileProjectResult {
|
|
|
22
22
|
readonly lualib?: string;
|
|
23
23
|
readonly timersRuntime?: string;
|
|
24
24
|
readonly hsmModules?: Readonly<Record<string, string>>;
|
|
25
|
+
readonly hsmSourceMaps?: Readonly<Record<string, string>>;
|
|
25
26
|
}
|
|
26
27
|
export declare const AMBIENT_FILES: Readonly<Record<string, string>>;
|
|
27
28
|
interface CollectableFile {
|
|
@@ -42,5 +43,7 @@ export declare function transpileProject(input: TranspileProjectInput): Transpil
|
|
|
42
43
|
* lualib bundle.
|
|
43
44
|
*/
|
|
44
45
|
export declare function compileHsmModules(): Readonly<Record<string, string>>;
|
|
46
|
+
/** The source map of every module `compileHsmModules` returns, under the same keys. */
|
|
47
|
+
export declare function compileHsmSourceMaps(): Readonly<Record<string, string>>;
|
|
45
48
|
export declare function transpile(source: string): TranspileResult;
|
|
46
49
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defold-typescript/transpiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0",
|
|
4
4
|
"description": "TypeScript-to-Lua build pipeline tuned for Defold's runtime.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"test": "bun test"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@defold-typescript/types": "0.
|
|
38
|
+
"@defold-typescript/types": "0.52.0",
|
|
39
39
|
"@typescript-to-lua/language-extensions": "1.19.0",
|
|
40
40
|
"typescript": "6.0.2",
|
|
41
41
|
"typescript-to-lua": "^1.36.0"
|
package/src/hsm-builtin.ts
CHANGED
|
@@ -7,8 +7,8 @@ import { scanEmittedRequires } from "./lua-require-scan";
|
|
|
7
7
|
|
|
8
8
|
// `@defold-typescript/types/hsm` is the `index` module; every other module is a
|
|
9
9
|
// subpath of it. Each lowers to a require of `defold_typescript_hsm.<module>`,
|
|
10
|
-
// which the CLI
|
|
11
|
-
// runtime.
|
|
10
|
+
// which the CLI respells to the module's place in its runtime folder, the way it
|
|
11
|
+
// handles the timers runtime.
|
|
12
12
|
export const HSM_MODULE_SPECIFIER = "@defold-typescript/types/hsm";
|
|
13
13
|
export const HSM_REQUIRE_ROOT = "defold_typescript_hsm";
|
|
14
14
|
|
package/src/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ export {
|
|
|
46
46
|
readGameProjectDependencies,
|
|
47
47
|
readLibrarySceneDocuments,
|
|
48
48
|
} from "./library-dependencies";
|
|
49
|
+
export { scanEmittedRequires } from "./lua-require-scan";
|
|
49
50
|
export { findMainEntryFactoryImports } from "./main-entry-factory-imports";
|
|
50
51
|
export type { BuildConfig, ScriptKind, SourceOutputKind } from "./output-paths";
|
|
51
52
|
export {
|
package/src/lifecycle-erasure.ts
CHANGED
|
@@ -35,22 +35,29 @@ const FACTORY_SPECIFIERS = new Set([
|
|
|
35
35
|
`${FACTORY_MODULE}/render-script`,
|
|
36
36
|
]);
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
// The lifecycle factory a callee resolves to, aliases followed, or `undefined`
|
|
39
|
+
// when it is not one of this package's factory exports.
|
|
40
|
+
function factoryExportName(callee: ts.Expression, checker: ts.TypeChecker): string | undefined {
|
|
39
41
|
let symbol = checker.getSymbolAtLocation(callee);
|
|
40
42
|
if (symbol === undefined) {
|
|
41
|
-
return
|
|
43
|
+
return undefined;
|
|
42
44
|
}
|
|
43
45
|
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
44
46
|
symbol = checker.getAliasedSymbol(symbol);
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
const name = symbol.getName();
|
|
49
|
+
if (!FACTORY_NAMES.has(name)) {
|
|
50
|
+
return undefined;
|
|
48
51
|
}
|
|
49
52
|
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
50
53
|
if (declaration === undefined) {
|
|
51
|
-
return
|
|
54
|
+
return undefined;
|
|
52
55
|
}
|
|
53
|
-
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE);
|
|
56
|
+
return declaration.getSourceFile().fileName.includes(FACTORY_MODULE) ? name : undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function resolvesToFactoryExport(callee: ts.Expression, checker: ts.TypeChecker): boolean {
|
|
60
|
+
return factoryExportName(callee, checker) !== undefined;
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
function isThisParameter(param: ts.ParameterDeclaration): boolean {
|
|
@@ -208,6 +215,20 @@ function emitInitMerge(
|
|
|
208
215
|
return [builderDecl, createAssignmentStatement(createIdentifier("init"), initFn, property)];
|
|
209
216
|
}
|
|
210
217
|
|
|
218
|
+
// Build-time markers, never engine functions: bob reads `resource.<kind>("path")`
|
|
219
|
+
// only as a `go.property` default (`LuaScanner.java:923-933` at defold
|
|
220
|
+
// `a81dbb04`), and the engine's `resource` table registers none of them
|
|
221
|
+
// (`script_resource.cpp:3447-3463` in 1.14.0). Called anywhere else, each is nil.
|
|
222
|
+
export const RESOURCE_PROPERTY_MARKERS: ReadonlySet<string> = new Set([
|
|
223
|
+
"resource.atlas",
|
|
224
|
+
"resource.buffer",
|
|
225
|
+
"resource.font",
|
|
226
|
+
"resource.material",
|
|
227
|
+
"resource.render_target",
|
|
228
|
+
"resource.texture",
|
|
229
|
+
"resource.tile_source",
|
|
230
|
+
]);
|
|
231
|
+
|
|
211
232
|
export interface PropertyMember {
|
|
212
233
|
readonly name: string;
|
|
213
234
|
readonly initializer: ts.Expression;
|
|
@@ -275,14 +296,171 @@ function emitPropertyRegistrations(
|
|
|
275
296
|
);
|
|
276
297
|
}
|
|
277
298
|
|
|
299
|
+
// Defold builds `go.property` only in `.script` files, so a GUI or render
|
|
300
|
+
// script's `properties` block has nothing it could lower to.
|
|
301
|
+
function scriptOnlyProperties(
|
|
302
|
+
property: ts.ObjectLiteralElementLike,
|
|
303
|
+
factory: string,
|
|
304
|
+
): ts.Diagnostic {
|
|
305
|
+
const file = property.getSourceFile();
|
|
306
|
+
const start = property.getStart(file);
|
|
307
|
+
return {
|
|
308
|
+
file,
|
|
309
|
+
start,
|
|
310
|
+
length: property.getEnd() - start,
|
|
311
|
+
category: ts.DiagnosticCategory.Error,
|
|
312
|
+
code: 0,
|
|
313
|
+
messageText: `\`${factory}\` cannot declare \`properties\`: Defold builds \`go.property\` only in \`.script\` files. Declare the property in a \`defineScript\` and send its value with \`msg.post\`.`,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// The outermost expression that only wraps `node` in parentheses or a type-only
|
|
318
|
+
// form, so `(resource.atlas("/a.atlas") as Hash)` sits where the bare call would.
|
|
319
|
+
function outermostWrapper(node: ts.Expression): ts.Expression {
|
|
320
|
+
let current = node;
|
|
321
|
+
while (
|
|
322
|
+
ts.isParenthesizedExpression(current.parent) ||
|
|
323
|
+
ts.isAsExpression(current.parent) ||
|
|
324
|
+
ts.isSatisfiesExpression(current.parent) ||
|
|
325
|
+
ts.isNonNullExpression(current.parent) ||
|
|
326
|
+
ts.isTypeAssertionExpression(current.parent)
|
|
327
|
+
) {
|
|
328
|
+
current = current.parent;
|
|
329
|
+
}
|
|
330
|
+
return current;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// The inverse of `outermostWrapper`: the expression a run of parentheses and
|
|
334
|
+
// type-only forms wraps, which TSTL emits in place of the whole run.
|
|
335
|
+
function innermostExpression(node: ts.Expression): ts.Expression {
|
|
336
|
+
let current = node;
|
|
337
|
+
while (
|
|
338
|
+
ts.isParenthesizedExpression(current) ||
|
|
339
|
+
ts.isAsExpression(current) ||
|
|
340
|
+
ts.isSatisfiesExpression(current) ||
|
|
341
|
+
ts.isNonNullExpression(current) ||
|
|
342
|
+
ts.isTypeAssertionExpression(current)
|
|
343
|
+
) {
|
|
344
|
+
current = current.expression;
|
|
345
|
+
}
|
|
346
|
+
return current;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Keyed by the declaration's fully qualified name: only a symbol declared in an
|
|
350
|
+
// ambient `declare global` block carries the `global.` prefix, so a project's
|
|
351
|
+
// own `resource` never matches.
|
|
352
|
+
function globalName(symbol: ts.Symbol | undefined, checker: ts.TypeChecker): string | undefined {
|
|
353
|
+
if (symbol === undefined) {
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
const fqn = checker.getFullyQualifiedName(symbol);
|
|
357
|
+
return fqn.startsWith("global.") ? fqn.slice("global.".length) : undefined;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function calledGlobal(call: ts.CallExpression, checker: ts.TypeChecker): string | undefined {
|
|
361
|
+
const declaration = checker.getResolvedSignature(call)?.declaration;
|
|
362
|
+
if (
|
|
363
|
+
declaration === undefined ||
|
|
364
|
+
!ts.isFunctionDeclaration(declaration) ||
|
|
365
|
+
declaration.name === undefined
|
|
366
|
+
) {
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
return globalName(checker.getSymbolAtLocation(declaration.name), checker);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// A `properties` default of a factory call, or the default argument of a
|
|
373
|
+
// direct `go.property` call: the two places bob reads a marker.
|
|
374
|
+
function isPropertyDefault(call: ts.CallExpression, checker: ts.TypeChecker): boolean {
|
|
375
|
+
const value = outermostWrapper(call);
|
|
376
|
+
const parent = value.parent;
|
|
377
|
+
if (ts.isCallExpression(parent)) {
|
|
378
|
+
return parent.arguments[1] === value && calledGlobal(parent, checker) === "go.property";
|
|
379
|
+
}
|
|
380
|
+
const properties = parent?.parent?.parent;
|
|
381
|
+
if (
|
|
382
|
+
properties === undefined ||
|
|
383
|
+
!ts.isPropertyAssignment(properties) ||
|
|
384
|
+
!isPropertiesHook(properties)
|
|
385
|
+
) {
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
const hooks = properties.parent;
|
|
389
|
+
return (
|
|
390
|
+
ts.isObjectLiteralExpression(hooks) &&
|
|
391
|
+
factoryHooks(hooks.parent as ts.Expression, checker) === hooks &&
|
|
392
|
+
propertyMembers(properties).some((member) => member.initializer === value)
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function misplacedMarker(node: ts.Expression, marker: string): ts.Diagnostic {
|
|
397
|
+
const file = node.getSourceFile();
|
|
398
|
+
const start = node.getStart(file);
|
|
399
|
+
return {
|
|
400
|
+
file,
|
|
401
|
+
start,
|
|
402
|
+
length: node.getEnd() - start,
|
|
403
|
+
category: ts.DiagnosticCategory.Error,
|
|
404
|
+
code: 0,
|
|
405
|
+
messageText: `\`${marker}\` is a build-time marker: Defold's build reads it only in a \`go.property\` default, and the engine binds no such function. Use it as a \`defineScript\` \`properties\` default.`,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Bob reads a default as a marker only when the emitted text is
|
|
410
|
+
// `resource.<kind>("<path>")` or `resource.<kind>()`: the object token must be
|
|
411
|
+
// `resource` with a dot `NAME` key, and the first argument a string literal or
|
|
412
|
+
// absent (`LuaScanner.java:801-822`, `:923-933` and `:493-510` at defold
|
|
413
|
+
// `a81dbb04`). The receiver test is textual like bob's; the marker resolution
|
|
414
|
+
// has already excluded a project's own `resource`.
|
|
415
|
+
function readsAsMarker(call: ts.CallExpression): boolean {
|
|
416
|
+
const callee = innermostExpression(call.expression);
|
|
417
|
+
if (ts.isOptionalChain(call) || ts.isOptionalChain(callee)) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
if (
|
|
421
|
+
!ts.isPropertyAccessExpression(callee) &&
|
|
422
|
+
!(
|
|
423
|
+
ts.isElementAccessExpression(callee) &&
|
|
424
|
+
ts.isStringLiteralLike(innermostExpression(callee.argumentExpression))
|
|
425
|
+
)
|
|
426
|
+
) {
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
const receiver = innermostExpression(callee.expression);
|
|
430
|
+
if (!ts.isIdentifier(receiver) || receiver.text !== "resource") {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
const [path] = call.arguments;
|
|
434
|
+
return path === undefined || ts.isStringLiteralLike(innermostExpression(path));
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function unreadableMarker(node: ts.CallExpression, marker: string): ts.Diagnostic {
|
|
438
|
+
const file = node.getSourceFile();
|
|
439
|
+
const start = node.getStart(file);
|
|
440
|
+
return {
|
|
441
|
+
file,
|
|
442
|
+
start,
|
|
443
|
+
length: node.getEnd() - start,
|
|
444
|
+
category: ts.DiagnosticCategory.Error,
|
|
445
|
+
code: 0,
|
|
446
|
+
messageText: `\`${marker}\` in a property default must be written \`${marker}("<path>")\`, with a string literal path: Defold's build reads no other form.`,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function isCallee(node: ts.Expression): boolean {
|
|
451
|
+
const callee = outermostWrapper(node);
|
|
452
|
+
return ts.isCallExpression(callee.parent) && callee.parent.expression === callee;
|
|
453
|
+
}
|
|
454
|
+
|
|
278
455
|
function eraseFactoryCall(
|
|
279
456
|
expression: ts.Expression,
|
|
280
457
|
context: TransformationContext,
|
|
281
458
|
): Statement[] | undefined {
|
|
282
459
|
const hooks = factoryHooks(expression, context.checker);
|
|
283
|
-
if (hooks === undefined) {
|
|
460
|
+
if (hooks === undefined || !ts.isCallExpression(expression)) {
|
|
284
461
|
return undefined;
|
|
285
462
|
}
|
|
463
|
+
const factory = factoryExportName(expression.expression, context.checker);
|
|
286
464
|
const registrations: Statement[] = [];
|
|
287
465
|
const statements: Statement[] = [];
|
|
288
466
|
for (const property of hooks.properties) {
|
|
@@ -291,7 +469,11 @@ function eraseFactoryCall(
|
|
|
291
469
|
continue;
|
|
292
470
|
}
|
|
293
471
|
if (name === "properties") {
|
|
294
|
-
|
|
472
|
+
if (factory === "defineScript") {
|
|
473
|
+
registrations.push(...emitPropertyRegistrations(property, context));
|
|
474
|
+
} else if (factory !== undefined && propertyMembers(property).length > 0) {
|
|
475
|
+
context.diagnostics.push(scriptOnlyProperties(property, factory));
|
|
476
|
+
}
|
|
295
477
|
continue;
|
|
296
478
|
}
|
|
297
479
|
const fn = hookFunction(property);
|
|
@@ -374,5 +556,48 @@ export const lifecycleErasurePlugin: Plugin = {
|
|
|
374
556
|
},
|
|
375
557
|
[ts.SyntaxKind.ImportDeclaration]: (node, context) =>
|
|
376
558
|
isFactoryOnlyImport(node) ? [] : context.superTransformStatements(node),
|
|
559
|
+
// TSTL's optional-chain lowering also visits nodes it synthesizes, which have
|
|
560
|
+
// no parent and no source span; only parsed nodes are checked.
|
|
561
|
+
[ts.SyntaxKind.CallExpression]: (node, context) => {
|
|
562
|
+
const marker = node.parent === undefined ? undefined : calledGlobal(node, context.checker);
|
|
563
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
564
|
+
if (!isPropertyDefault(node, context.checker)) {
|
|
565
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
566
|
+
} else if (!readsAsMarker(node)) {
|
|
567
|
+
context.diagnostics.push(unreadableMarker(node, marker));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return context.superTransformExpression(node);
|
|
571
|
+
},
|
|
572
|
+
[ts.SyntaxKind.PropertyAccessExpression]: (node, context) => {
|
|
573
|
+
if (node.parent !== undefined && !isCallee(node)) {
|
|
574
|
+
const marker = globalName(context.checker.getSymbolAtLocation(node.name), context.checker);
|
|
575
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
576
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return context.superTransformExpression(node);
|
|
580
|
+
},
|
|
581
|
+
[ts.SyntaxKind.ElementAccessExpression]: (node, context) => {
|
|
582
|
+
if (node.parent !== undefined && !isCallee(node)) {
|
|
583
|
+
// The checker resolves a string key only when it is the direct argument,
|
|
584
|
+
// so a wrapped key is looked up by name on the receiver's type, as the
|
|
585
|
+
// checker does for a direct one.
|
|
586
|
+
const key = innermostExpression(node.argumentExpression);
|
|
587
|
+
const marker = ts.isStringLiteralLike(key)
|
|
588
|
+
? globalName(
|
|
589
|
+
context.checker.getPropertyOfType(
|
|
590
|
+
context.checker.getTypeAtLocation(node.expression),
|
|
591
|
+
key.text,
|
|
592
|
+
),
|
|
593
|
+
context.checker,
|
|
594
|
+
)
|
|
595
|
+
: undefined;
|
|
596
|
+
if (marker !== undefined && RESOURCE_PROPERTY_MARKERS.has(marker)) {
|
|
597
|
+
context.diagnostics.push(misplacedMarker(node, marker));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return context.superTransformExpression(node);
|
|
601
|
+
},
|
|
377
602
|
},
|
|
378
603
|
};
|
package/src/timers-runtime.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The importable polyfill specifier (matched by the type checker and the
|
|
2
2
|
// lowering pass) and the flat Lua require name the import is rewritten to. The
|
|
3
|
-
// CLI writes the runtime
|
|
4
|
-
//
|
|
3
|
+
// CLI writes the runtime into its runtime folder beside `lualib_bundle` and
|
|
4
|
+
// respells every `require("defold_typescript_timers")` to that path.
|
|
5
5
|
export const TIMERS_MODULE_SPECIFIER = "@defold-typescript/types/timers";
|
|
6
6
|
export const TIMERS_REQUIRE_NAME = "defold_typescript_timers";
|
|
7
7
|
|
package/src/transpile.ts
CHANGED
|
@@ -63,23 +63,27 @@ export interface TranspileProjectResult {
|
|
|
63
63
|
// TSTL synthesizes this bundle (no user source) whenever a lualib feature is
|
|
64
64
|
// registered — either by a user source using one (`Object.keys`, spread,
|
|
65
65
|
// `__TS__TypeOf`, ...) or by the timers import lowering, whose generated
|
|
66
|
-
// runtime requires the bundle. The emitted `require("lualib_bundle")`
|
|
67
|
-
//
|
|
66
|
+
// runtime requires the bundle. The emitted `require("lualib_bundle")` is an
|
|
67
|
+
// internal name the CLI respells to where it writes the bundle. Absent when
|
|
68
68
|
// neither trigger fires.
|
|
69
69
|
readonly lualib?: string;
|
|
70
70
|
// Hand-authored runtime Lua for the `@defold-typescript/types/timers`
|
|
71
71
|
// polyfills (`setTimeout`/`wait`/...). Unlike `defineScript`, the import is
|
|
72
|
-
// not erased — it lowers to `require("defold_typescript_timers")`,
|
|
73
|
-
//
|
|
74
|
-
// the module (pay-for-use).
|
|
72
|
+
// not erased — it lowers to `require("defold_typescript_timers")`, an
|
|
73
|
+
// internal name the CLI respells to where it writes this. Present only when
|
|
74
|
+
// a user file imports the module (pay-for-use).
|
|
75
75
|
readonly timersRuntime?: string;
|
|
76
76
|
// The compiled `hsm` modules the program requires, keyed by module name
|
|
77
77
|
// (`index`, `defold`, ...). An hsm import lowers to
|
|
78
|
-
// `require("defold_typescript_hsm.<module>")`,
|
|
79
|
-
//
|
|
80
|
-
// (pay-for-use)
|
|
81
|
-
// at is not in the user's project.
|
|
78
|
+
// `require("defold_typescript_hsm.<module>")`, an internal name the CLI
|
|
79
|
+
// respells to where it writes each one. Present only when some chunk requires one
|
|
80
|
+
// (pay-for-use).
|
|
82
81
|
readonly hsmModules?: Readonly<Record<string, string>>;
|
|
82
|
+
// The source map of each module in `hsmModules`, under the same keys. Its
|
|
83
|
+
// `sources` names `<module>.ts` with an empty `sourceRoot`: only the CLI knows
|
|
84
|
+
// where the module is written and where the hsm source sits, so it sets the
|
|
85
|
+
// root that joins them.
|
|
86
|
+
readonly hsmSourceMaps?: Readonly<Record<string, string>>;
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
function flattenDiagnosticMessage(
|
|
@@ -313,6 +317,7 @@ export function collectOutputs(
|
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
const hsm = hsmClosure([...Object.values(lua), ...Object.values(companions)], compileHsmModules);
|
|
320
|
+
const hsmSourceMaps = hsm === undefined ? undefined : selectHsmSourceMaps(Object.keys(hsm));
|
|
316
321
|
|
|
317
322
|
return {
|
|
318
323
|
lua,
|
|
@@ -322,9 +327,22 @@ export function collectOutputs(
|
|
|
322
327
|
...(lualib !== undefined ? { lualib } : {}),
|
|
323
328
|
...(timersImported ? { timersRuntime: TIMERS_RUNTIME } : {}),
|
|
324
329
|
...(hsm !== undefined ? { hsmModules: hsm } : {}),
|
|
330
|
+
...(hsmSourceMaps !== undefined ? { hsmSourceMaps } : {}),
|
|
325
331
|
};
|
|
326
332
|
}
|
|
327
333
|
|
|
334
|
+
function selectHsmSourceMaps(names: readonly string[]): Record<string, string> {
|
|
335
|
+
const maps = compileHsmSourceMaps();
|
|
336
|
+
const selected: Record<string, string> = {};
|
|
337
|
+
for (const name of names) {
|
|
338
|
+
const map = maps[name];
|
|
339
|
+
if (map !== undefined) {
|
|
340
|
+
selected[name] = map;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return selected;
|
|
344
|
+
}
|
|
345
|
+
|
|
328
346
|
function transpileVirtual(
|
|
329
347
|
files: Readonly<Record<string, string>>,
|
|
330
348
|
companionEmit: ReturnType<typeof createCompanionEmitPlugin>,
|
|
@@ -382,7 +400,12 @@ export function transpileProject(input: TranspileProjectInput): TranspileProject
|
|
|
382
400
|
);
|
|
383
401
|
}
|
|
384
402
|
|
|
385
|
-
|
|
403
|
+
interface CompiledHsm {
|
|
404
|
+
readonly lua: Readonly<Record<string, string>>;
|
|
405
|
+
readonly sourceMaps: Readonly<Record<string, string>>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
let compiledHsm: CompiledHsm | undefined;
|
|
386
409
|
|
|
387
410
|
function requiresLualib(lua: string): boolean {
|
|
388
411
|
return scanEmittedRequires(lua).some(({ path: requirePath }) => requirePath === "lualib_bundle");
|
|
@@ -398,6 +421,15 @@ function requiresLualib(lua: string): boolean {
|
|
|
398
421
|
* lualib bundle.
|
|
399
422
|
*/
|
|
400
423
|
export function compileHsmModules(): Readonly<Record<string, string>> {
|
|
424
|
+
return compileHsm().lua;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** The source map of every module `compileHsmModules` returns, under the same keys. */
|
|
428
|
+
export function compileHsmSourceMaps(): Readonly<Record<string, string>> {
|
|
429
|
+
return compileHsm().sourceMaps;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function compileHsm(): CompiledHsm {
|
|
401
433
|
if (compiledHsm !== undefined) {
|
|
402
434
|
return compiledHsm;
|
|
403
435
|
}
|
|
@@ -417,6 +449,7 @@ export function compileHsmModules(): Readonly<Record<string, string>> {
|
|
|
417
449
|
(d) => `${d.file?.fileName ?? "(project)"}: ${flattenDiagnosticMessage(d.messageText)}`,
|
|
418
450
|
);
|
|
419
451
|
const lua: Record<string, string> = {};
|
|
452
|
+
const sourceMaps: Record<string, string> = {};
|
|
420
453
|
for (const file of result.transpiledFiles) {
|
|
421
454
|
if (isLualibBundle(file)) {
|
|
422
455
|
continue;
|
|
@@ -430,14 +463,17 @@ export function compileHsmModules(): Readonly<Record<string, string>> {
|
|
|
430
463
|
problems.push(`the compiled ${name} module requires lualib_bundle`);
|
|
431
464
|
}
|
|
432
465
|
lua[name] = file.lua;
|
|
466
|
+
if (typeof file.luaSourceMap === "string") {
|
|
467
|
+
sourceMaps[name] = file.luaSourceMap;
|
|
468
|
+
}
|
|
433
469
|
}
|
|
434
470
|
if (problems.length > 0) {
|
|
435
471
|
throw new Error(
|
|
436
472
|
`@defold-typescript/transpiler: the hsm library does not compile:\n ${problems.join("\n ")}`,
|
|
437
473
|
);
|
|
438
474
|
}
|
|
439
|
-
compiledHsm = lua;
|
|
440
|
-
return
|
|
475
|
+
compiledHsm = { lua, sourceMaps };
|
|
476
|
+
return compiledHsm;
|
|
441
477
|
}
|
|
442
478
|
|
|
443
479
|
export function transpile(source: string): TranspileResult {
|