@defold-typescript/transpiler 0.42.0 → 0.44.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/emitted-requires.d.ts +1 -1
- package/dist/hsm/async.ts +73 -0
- package/dist/hsm/debug.ts +119 -0
- package/dist/hsm/defold.ts +39 -0
- package/dist/hsm/index.ts +1418 -0
- package/dist/hsm-builtin.d.ts +26 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +340 -130
- package/dist/transpile.d.ts +11 -0
- package/package.json +4 -3
- package/src/emitted-requires.ts +6 -4
- package/src/hsm-builtin.ts +246 -0
- package/src/index.ts +11 -1
- package/src/session.ts +2 -0
- package/src/transpile.ts +118 -26
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const LUALIB_REQUIRE_NAME = "lualib_bundle";
|
|
2
2
|
/**
|
|
3
3
|
* The distinct string-literal module paths an emitted Lua chunk requires, in
|
|
4
|
-
* source order. The
|
|
4
|
+
* source order. The generated runtimes and hsm modules are skipped, as is any require whose
|
|
5
5
|
* argument is not a string literal — neither can name a source the build owns.
|
|
6
6
|
*/
|
|
7
7
|
export declare function findEmittedRequires(lua: string): string[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { EventObject, TaskStart } from "./index";
|
|
2
|
+
|
|
3
|
+
/** @noSelf */
|
|
4
|
+
export interface SequenceSignal {
|
|
5
|
+
readonly aborted: boolean;
|
|
6
|
+
readonly wait: (seconds: number) => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** @noSelf */
|
|
10
|
+
interface Signal {
|
|
11
|
+
aborted: boolean;
|
|
12
|
+
readonly wait: (seconds: number) => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function forget(handles: number[], handle: number): void {
|
|
16
|
+
for (let i = 0; i < handles.length; i++) {
|
|
17
|
+
if (handles[i] === handle) {
|
|
18
|
+
handles[i] = handles[handles.length - 1] as number;
|
|
19
|
+
handles.pop();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// A rejected sequence promise has no reader, so its error would vanish; a fresh
|
|
26
|
+
// timer callback raises it where the engine logs it.
|
|
27
|
+
function rethrow(reason: unknown): void {
|
|
28
|
+
timer.delay(0, false, () => {
|
|
29
|
+
throw reason;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The sequence plugs into the state's task, so its cleanup cancels the pending
|
|
34
|
+
// waits on every way out of the state; a wait left pending is never resolved.
|
|
35
|
+
export function sequence<Ctx, E extends EventObject>(
|
|
36
|
+
// biome-ignore lint/suspicious/noConfusingVoidType: `void` lets a sequence end without returning an event.
|
|
37
|
+
run: (ctx: Ctx, signal: SequenceSignal) => Promise<NoInfer<E> | void>,
|
|
38
|
+
): TaskStart<Ctx, E> {
|
|
39
|
+
return (ctx, finish) => {
|
|
40
|
+
const handles: number[] = [];
|
|
41
|
+
const signal: Signal = {
|
|
42
|
+
aborted: false,
|
|
43
|
+
wait: (seconds) =>
|
|
44
|
+
new Promise<void>((resolve) => {
|
|
45
|
+
if (signal.aborted) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
handles.push(
|
|
49
|
+
timer.delay(seconds, false, (_self, handle) => {
|
|
50
|
+
forget(handles, handle);
|
|
51
|
+
if (!signal.aborted) {
|
|
52
|
+
resolve();
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
run(ctx, signal).then(
|
|
59
|
+
(event) => {
|
|
60
|
+
if (event !== undefined) {
|
|
61
|
+
finish(event);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
(reason) => rethrow(reason),
|
|
65
|
+
);
|
|
66
|
+
return () => {
|
|
67
|
+
signal.aborted = true;
|
|
68
|
+
while (handles.length > 0) {
|
|
69
|
+
timer.cancel(handles.pop() as number);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { EventObject, MachineInstance } from "./index";
|
|
2
|
+
|
|
3
|
+
/** @noSelf */
|
|
4
|
+
export interface MachineInspector {
|
|
5
|
+
readonly draw: (target: Hash | Url | string) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const SILENT: MachineInspector = {
|
|
9
|
+
draw: () => {},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const TEXT_OFFSET_Y = 40;
|
|
13
|
+
|
|
14
|
+
const labelUses: Record<string, number> = {};
|
|
15
|
+
const issuedLabels: Record<string, boolean> = {};
|
|
16
|
+
|
|
17
|
+
function uniqueLabel(label: string): string {
|
|
18
|
+
let ordinal = labelUses[label] ?? 1;
|
|
19
|
+
let issued = label;
|
|
20
|
+
while (issuedLabels[issued] === true) {
|
|
21
|
+
ordinal++;
|
|
22
|
+
issued = `${label}#${ordinal}`;
|
|
23
|
+
}
|
|
24
|
+
labelUses[label] = ordinal;
|
|
25
|
+
issuedLabels[issued] = true;
|
|
26
|
+
return issued;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const FIELD_ESCAPES: Record<string, string> = {
|
|
30
|
+
"\\": "\\\\",
|
|
31
|
+
"[": "\\[",
|
|
32
|
+
"]": "\\]",
|
|
33
|
+
"(": "\\(",
|
|
34
|
+
")": "\\)",
|
|
35
|
+
",": "\\,",
|
|
36
|
+
">": "\\>",
|
|
37
|
+
":": "\\:",
|
|
38
|
+
"\n": "\\n",
|
|
39
|
+
"\r": "\\r",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// A structural cast keeps each read a plain method call: native in JavaScript, string.sub in Lua.
|
|
43
|
+
interface StringChars {
|
|
44
|
+
charAt(index: number): string;
|
|
45
|
+
sub(first: number, last: number): string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// JavaScript strings hold UTF-16 code units; Lua strings hold UTF-8 bytes. Every escaped
|
|
49
|
+
// character is ASCII, and ASCII never occurs inside a UTF-8 sequence, so both walks agree.
|
|
50
|
+
const UTF16_UNITS = "\u{E000}".length === 1;
|
|
51
|
+
|
|
52
|
+
function charAt(text: string, index: number): string {
|
|
53
|
+
const chars = text as unknown as StringChars;
|
|
54
|
+
return UTF16_UNITS ? chars.charAt(index) : chars.sub(index + 1, index + 1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function escapeField(text: string): string {
|
|
58
|
+
let escaped = "";
|
|
59
|
+
for (let i = 0; i < text.length; i++) {
|
|
60
|
+
const char = charAt(text, i);
|
|
61
|
+
escaped = `${escaped}${FIELD_ESCAPES[char] ?? char}`;
|
|
62
|
+
}
|
|
63
|
+
return escaped;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function raw(text: string): string {
|
|
67
|
+
return text;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function shown(path: string | undefined): string {
|
|
71
|
+
return path === undefined ? "(stopped)" : escapeField(path);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function shownList(leaves: readonly string[], show: (leaf: string) => string): string {
|
|
75
|
+
if (leaves.length === 0) {
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
let text = show(leaves[0] as string);
|
|
79
|
+
for (let i = 1; i < leaves.length; i++) {
|
|
80
|
+
text = `${text}, ${show(leaves[i] as string)}`;
|
|
81
|
+
}
|
|
82
|
+
return text;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function shownLeaves(leaves: readonly string[]): string {
|
|
86
|
+
return leaves.length === 0 ? "(stopped)" : shownList(leaves, raw);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function inspect<Ctx, E extends EventObject, P extends string>(
|
|
90
|
+
instance: MachineInstance<Ctx, E, P>,
|
|
91
|
+
label: string,
|
|
92
|
+
): MachineInspector {
|
|
93
|
+
if (!sys.get_engine_info().is_debug) {
|
|
94
|
+
return SILENT;
|
|
95
|
+
}
|
|
96
|
+
const shownLabel = uniqueLabel(label);
|
|
97
|
+
const loggedLabel = escapeField(shownLabel);
|
|
98
|
+
let frame = 0;
|
|
99
|
+
instance.onMove((from, to, cause, event) => {
|
|
100
|
+
const reason = event === undefined ? cause : event.type;
|
|
101
|
+
print(
|
|
102
|
+
`hsm ${loggedLabel} frame ${frame}: ${escapeField(from)} -> ${shown(to)} (${escapeField(reason)}) [${shownList(instance.leaves, escapeField)}]`,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
print(
|
|
106
|
+
`hsm ${loggedLabel} frame ${frame}: inspecting [${shownList(instance.leaves, escapeField)}]`,
|
|
107
|
+
);
|
|
108
|
+
return {
|
|
109
|
+
draw: (target) => {
|
|
110
|
+
frame++;
|
|
111
|
+
const p = go.get_world_position(target);
|
|
112
|
+
msg.post("@render:", "draw_debug_text", {
|
|
113
|
+
text: `${shownLabel} ${shownLeaves(instance.leaves)}`,
|
|
114
|
+
position: vmath.vector3(p.x, p.y + TEXT_OFFSET_Y, p.z),
|
|
115
|
+
color: vmath.vector4(1, 1, 1, 1),
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type MessageEvent<K extends MessageId> = K extends MessageId
|
|
2
|
+
? { readonly type: K; readonly sender: Url } & Omit<MessagePayload<K>, "type" | "sender">
|
|
3
|
+
: never;
|
|
4
|
+
|
|
5
|
+
/** @noSelf */
|
|
6
|
+
export interface MessageEventMapper<K extends MessageId> {
|
|
7
|
+
readonly toEvent: (
|
|
8
|
+
message_id: Hash,
|
|
9
|
+
message: Record<string | number, unknown>,
|
|
10
|
+
sender: Url,
|
|
11
|
+
) => MessageEvent<K> | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function messageEvents<const K extends MessageId>(ids: readonly K[]): MessageEventMapper<K> {
|
|
15
|
+
const hashes: Hash[] = [];
|
|
16
|
+
for (let i = 0; i < ids.length; i++) {
|
|
17
|
+
hashes[i] = hash(ids[i] as K);
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
toEvent: (message_id, message, sender) => {
|
|
21
|
+
for (let i = 0; i < hashes.length; i++) {
|
|
22
|
+
if (hashes[i] === message_id) {
|
|
23
|
+
return copyEvent(ids[i] as K, message, sender) as MessageEvent<K>;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function copyEvent(type: string, message: Record<string | number, unknown>, sender: Url): unknown {
|
|
32
|
+
const event: { [key: string]: unknown } = {};
|
|
33
|
+
for (const key in message) {
|
|
34
|
+
event[key] = message[key];
|
|
35
|
+
}
|
|
36
|
+
event.type = type;
|
|
37
|
+
event.sender = sender;
|
|
38
|
+
return event;
|
|
39
|
+
}
|