@defold-typescript/transpiler 0.46.0 → 0.48.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/hsm/index.ts +249 -25
- package/dist/index.js +2 -0
- package/package.json +2 -2
- package/src/session.ts +7 -0
- package/src/transpile.ts +7 -0
package/dist/hsm/index.ts
CHANGED
|
@@ -168,6 +168,22 @@ export type AlwaysSpec<Ctx, To extends string = string> =
|
|
|
168
168
|
| AlwaysConfig<Ctx, To>
|
|
169
169
|
| RuleList<AlwaysConfig<Ctx, To>>;
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* One entry of the list form of `after`: a `delay` and the `to` its timer leads to.
|
|
173
|
+
* @noSelf
|
|
174
|
+
*/
|
|
175
|
+
export interface AfterConfig<Ctx, To extends string = string> {
|
|
176
|
+
/**
|
|
177
|
+
* The delay in seconds of game time: a number, or a function of the context that returns one.
|
|
178
|
+
* A function is read once each time the state is entered, after its `enter` hook, and again on
|
|
179
|
+
* a hot reload, so the delay is fixed for that stay. A result that is not a non-negative number
|
|
180
|
+
* throws, naming the state.
|
|
181
|
+
*/
|
|
182
|
+
readonly delay: number | ((ctx: Ctx) => number);
|
|
183
|
+
/** The full path of the state to move to when the delay has passed. */
|
|
184
|
+
readonly to: To;
|
|
185
|
+
}
|
|
186
|
+
|
|
171
187
|
/**
|
|
172
188
|
* A state's rules by event `type`. Only the machine's event types are keys, and each rule's
|
|
173
189
|
* `when` and `run` see the event variant its key names.
|
|
@@ -304,11 +320,15 @@ interface StateBase<Ctx, E extends EventObject, T, Self extends string, To exten
|
|
|
304
320
|
*/
|
|
305
321
|
readonly on?: NoInfer<OnConfig<Ctx, E, To>>;
|
|
306
322
|
/**
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
323
|
+
* Timers, in one of two forms: targets by delay in seconds of game time, such as
|
|
324
|
+
* `{ 2: "/idle" }`, or a list of `AfterConfig` entries, such as
|
|
325
|
+
* `[{ delay: (ctx) => ctx.patrolFor, to: "/rest" }]`, whose `delay` is a number or a function
|
|
326
|
+
* of the context. A delay function is read once each time the state is entered, after its
|
|
327
|
+
* `enter` hook, and again on a hot reload. The delay is counted by `update(dt)` while the state
|
|
328
|
+
* is active, from zero on each entry. One `update` call fires at most one timer, and none when
|
|
329
|
+
* an `update` hook moved the machine.
|
|
310
330
|
*/
|
|
311
|
-
readonly after?: NoInfer<{ readonly [seconds: number]: To }>;
|
|
331
|
+
readonly after?: NoInfer<{ readonly [seconds: number]: To } | readonly AfterConfig<Ctx, To>[]>;
|
|
312
332
|
/**
|
|
313
333
|
* Targets taken right after any move that leaves this state active; the first whose `when` is
|
|
314
334
|
* missing or passes wins. It is checked after a move only: not after a rule with no `to`, and
|
|
@@ -415,6 +435,8 @@ interface Transition<Ctx, E extends EventObject> {
|
|
|
415
435
|
readonly run: readonly MoveAction<Ctx, E>[];
|
|
416
436
|
}
|
|
417
437
|
|
|
438
|
+
type Delay<Ctx> = number | ((ctx: Ctx) => number);
|
|
439
|
+
|
|
418
440
|
interface Compiled<Ctx, E extends EventObject> {
|
|
419
441
|
count: number;
|
|
420
442
|
readonly configs: StateConfig<Ctx, E>[];
|
|
@@ -431,6 +453,10 @@ interface Compiled<Ctx, E extends EventObject> {
|
|
|
431
453
|
readonly transitions: Transition<Ctx, E>[][];
|
|
432
454
|
readonly afterDelays: number[][];
|
|
433
455
|
readonly afterTargets: number[][];
|
|
456
|
+
// Set only for a state whose after list holds a delay function: its entries in list order,
|
|
457
|
+
// for each instance to sort once the function is read.
|
|
458
|
+
readonly afterListDelays: (Delay<Ctx>[] | undefined)[];
|
|
459
|
+
readonly afterListTargets: (number[] | undefined)[];
|
|
434
460
|
readonly always: Transition<Ctx, E>[][];
|
|
435
461
|
readonly pathIndex: { [path: string]: number };
|
|
436
462
|
}
|
|
@@ -763,6 +789,25 @@ function parseDelay(key: string | number): number {
|
|
|
763
789
|
return delay;
|
|
764
790
|
}
|
|
765
791
|
|
|
792
|
+
// NaN fails the comparison, so it is rejected with the negative numbers.
|
|
793
|
+
function checkDelay(path: string, delay: unknown, written: unknown): void {
|
|
794
|
+
if (typeof delay !== "number" || !(delay >= 0)) {
|
|
795
|
+
throw `hsm: state "${describePath(path)}" has an after delay "${written}" that is not a non-negative number`;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Keeps the delays ascending; timers with one delay stay in the order they were added.
|
|
800
|
+
function insertTimer(delays: number[], targets: number[], delay: number, target: number): void {
|
|
801
|
+
let slot = delays.length;
|
|
802
|
+
while (slot > 0 && (delays[slot - 1] as number) > delay) {
|
|
803
|
+
delays[slot] = delays[slot - 1] as number;
|
|
804
|
+
targets[slot] = targets[slot - 1] as number;
|
|
805
|
+
slot--;
|
|
806
|
+
}
|
|
807
|
+
delays[slot] = delay;
|
|
808
|
+
targets[slot] = target;
|
|
809
|
+
}
|
|
810
|
+
|
|
766
811
|
function compileAfter<Ctx, E extends EventObject>(compiled: Compiled<Ctx, E>, index: number): void {
|
|
767
812
|
const delays: number[] = [];
|
|
768
813
|
const targets: number[] = [];
|
|
@@ -773,20 +818,39 @@ function compileAfter<Ctx, E extends EventObject>(compiled: Compiled<Ctx, E>, in
|
|
|
773
818
|
return;
|
|
774
819
|
}
|
|
775
820
|
const path = compiled.paths[index] as string;
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
821
|
+
// Read as an array type: the transpiler shifts an index to Lua's base 1 only on an array.
|
|
822
|
+
const list = after as readonly AfterConfig<Ctx>[];
|
|
823
|
+
if (typeof list[0] !== "object") {
|
|
824
|
+
const byDelay = after as { readonly [seconds: number]: string };
|
|
825
|
+
for (const key in byDelay) {
|
|
826
|
+
const delay = parseDelay(key);
|
|
827
|
+
checkDelay(path, delay, key);
|
|
828
|
+
const target = resolveTarget(compiled, index, byDelay[key as unknown as number] as string);
|
|
829
|
+
insertTimer(delays, targets, delay, target);
|
|
780
830
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const listDelays: Delay<Ctx>[] = [];
|
|
834
|
+
const listTargets: number[] = [];
|
|
835
|
+
let perInstance = false;
|
|
836
|
+
for (let i = 0; i < list.length; i++) {
|
|
837
|
+
const entry = list[i] as AfterConfig<Ctx>;
|
|
838
|
+
const delay = entry.delay;
|
|
839
|
+
if (typeof delay === "function") {
|
|
840
|
+
perInstance = true;
|
|
841
|
+
} else {
|
|
842
|
+
checkDelay(path, delay, delay);
|
|
787
843
|
}
|
|
788
|
-
|
|
789
|
-
|
|
844
|
+
listDelays[i] = delay;
|
|
845
|
+
listTargets[i] = resolveTarget(compiled, index, entry.to);
|
|
846
|
+
}
|
|
847
|
+
if (perInstance) {
|
|
848
|
+
compiled.afterListDelays[index] = listDelays;
|
|
849
|
+
compiled.afterListTargets[index] = listTargets;
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
for (let i = 0; i < listDelays.length; i++) {
|
|
853
|
+
insertTimer(delays, targets, listDelays[i] as number, listTargets[i] as number);
|
|
790
854
|
}
|
|
791
855
|
}
|
|
792
856
|
|
|
@@ -807,6 +871,8 @@ function compile<Ctx, E extends EventObject>(config: MachineConfig<Ctx, E>): Com
|
|
|
807
871
|
transitions: [],
|
|
808
872
|
afterDelays: [],
|
|
809
873
|
afterTargets: [],
|
|
874
|
+
afterListDelays: [],
|
|
875
|
+
afterListTargets: [],
|
|
810
876
|
always: [],
|
|
811
877
|
pathIndex: {},
|
|
812
878
|
};
|
|
@@ -865,6 +931,23 @@ interface Registered<Ctx, E extends EventObject> {
|
|
|
865
931
|
|
|
866
932
|
const registered: { [key: string]: Registered<unknown, EventObject> } = {};
|
|
867
933
|
|
|
934
|
+
// Adds the fields the root's privateCtx returns to ctx; the factory receives target. With
|
|
935
|
+
// onlyMissing, a field ctx already has keeps its value: a hot reload adds new private fields and
|
|
936
|
+
// leaves the old ones alone.
|
|
937
|
+
function fillPrivate(
|
|
938
|
+
target: { [name: string]: unknown },
|
|
939
|
+
root: unknown,
|
|
940
|
+
onlyMissing: boolean,
|
|
941
|
+
): void {
|
|
942
|
+
const factory = (root as PrivateCtxConfig<unknown, object>).privateCtx;
|
|
943
|
+
const fields = (factory?.(target) || {}) as { [name: string]: unknown };
|
|
944
|
+
for (const name in fields) {
|
|
945
|
+
if (!onlyMissing || target[name] === undefined) {
|
|
946
|
+
target[name] = fields[name];
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
868
951
|
function createMachine<Ctx, E extends EventObject>(
|
|
869
952
|
definition: Definition<Ctx, E>,
|
|
870
953
|
): Machine<Ctx, E> {
|
|
@@ -883,11 +966,16 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
883
966
|
let transitions = compiled.transitions;
|
|
884
967
|
let afterDelays = compiled.afterDelays;
|
|
885
968
|
let afterTargets = compiled.afterTargets;
|
|
969
|
+
let afterListDelays = compiled.afterListDelays;
|
|
970
|
+
let afterListTargets = compiled.afterListTargets;
|
|
886
971
|
let always = compiled.always;
|
|
887
972
|
const activeChild: number[] = [];
|
|
888
973
|
const isActive: boolean[] = [];
|
|
889
974
|
const elapsed: number[] = [];
|
|
890
975
|
const fired: number[] = [];
|
|
976
|
+
// The sorted timers of a state whose after list holds a delay function, read on each entry.
|
|
977
|
+
const ownDelays: (number[] | undefined)[] = [];
|
|
978
|
+
const ownTargets: (number[] | undefined)[] = [];
|
|
891
979
|
const entryId: number[] = [];
|
|
892
980
|
const cleanup: ((() => void) | undefined)[] = [];
|
|
893
981
|
// Keyed by path, not index, so a remembered child outlives a rebind's recompilation.
|
|
@@ -921,10 +1009,32 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
921
1009
|
isActive[state] = false;
|
|
922
1010
|
elapsed[state] = 0;
|
|
923
1011
|
fired[state] = 0;
|
|
1012
|
+
ownDelays[state] = undefined;
|
|
1013
|
+
ownTargets[state] = undefined;
|
|
924
1014
|
entryId[state] = 0;
|
|
925
1015
|
cleanup[state] = undefined;
|
|
926
1016
|
}
|
|
927
1017
|
|
|
1018
|
+
function readDelays(state: number): void {
|
|
1019
|
+
const list = afterListDelays[state];
|
|
1020
|
+
if (list === undefined) {
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
const listTargets = afterListTargets[state] as number[];
|
|
1024
|
+
const delays: number[] = [];
|
|
1025
|
+
const targets: number[] = [];
|
|
1026
|
+
for (let i = 0; i < list.length; i++) {
|
|
1027
|
+
let delay = list[i] as Delay<Ctx>;
|
|
1028
|
+
if (typeof delay === "function") {
|
|
1029
|
+
delay = delay(ctx);
|
|
1030
|
+
checkDelay(paths[state] as string, delay, delay);
|
|
1031
|
+
}
|
|
1032
|
+
insertTimer(delays, targets, delay, listTargets[i] as number);
|
|
1033
|
+
}
|
|
1034
|
+
ownDelays[state] = delays;
|
|
1035
|
+
ownTargets[state] = targets;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
928
1038
|
function growSlots(): void {
|
|
929
1039
|
while (slotCount < compiled.count) {
|
|
930
1040
|
clearSlot(slotCount);
|
|
@@ -979,7 +1089,10 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
979
1089
|
transitions = compiled.transitions;
|
|
980
1090
|
afterDelays = compiled.afterDelays;
|
|
981
1091
|
afterTargets = compiled.afterTargets;
|
|
1092
|
+
afterListDelays = compiled.afterListDelays;
|
|
1093
|
+
afterListTargets = compiled.afterListTargets;
|
|
982
1094
|
always = compiled.always;
|
|
1095
|
+
fillPrivate(ctx as never, configs[ROOT], true);
|
|
983
1096
|
growSlots();
|
|
984
1097
|
const dropped: number[] = [];
|
|
985
1098
|
for (let i = 0; i < order.length; i++) {
|
|
@@ -1002,6 +1115,7 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
1002
1115
|
fired[state] = keptFired[i] as number;
|
|
1003
1116
|
entryId[state] = keptEntryId[i] as number;
|
|
1004
1117
|
cleanup[state] = keptCleanup[i];
|
|
1118
|
+
readDelays(state);
|
|
1005
1119
|
}
|
|
1006
1120
|
for (let i = dropped.length - 1; i >= 0; i--) {
|
|
1007
1121
|
const run = keptCleanup[dropped[i] as number];
|
|
@@ -1104,6 +1218,7 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
1104
1218
|
if (hook !== undefined) {
|
|
1105
1219
|
hook(ctx, instance);
|
|
1106
1220
|
}
|
|
1221
|
+
readDelays(state);
|
|
1107
1222
|
const task = config.task;
|
|
1108
1223
|
if (task !== undefined) {
|
|
1109
1224
|
// A path, not an index, so a finish held across a rebind still finds its entry.
|
|
@@ -1501,17 +1616,12 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
1501
1616
|
if (child !== NO_STATE && fireTimers(child)) {
|
|
1502
1617
|
return true;
|
|
1503
1618
|
}
|
|
1504
|
-
const delays = afterDelays[state] as number[];
|
|
1619
|
+
const delays = ownDelays[state] || (afterDelays[state] as number[]);
|
|
1505
1620
|
const next = fired[state] as number;
|
|
1506
1621
|
if (next < delays.length && (delays[next] as number) <= (elapsed[state] as number)) {
|
|
1507
1622
|
fired[state] = next + 1;
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
(afterTargets[state] as number[])[next] as number,
|
|
1511
|
-
undefined,
|
|
1512
|
-
undefined,
|
|
1513
|
-
"after",
|
|
1514
|
-
);
|
|
1623
|
+
const targets = ownTargets[state] || (afterTargets[state] as number[]);
|
|
1624
|
+
transition(state, targets[next] as number, undefined, undefined, "after");
|
|
1515
1625
|
return true;
|
|
1516
1626
|
}
|
|
1517
1627
|
return false;
|
|
@@ -1553,6 +1663,7 @@ function createMachine<Ctx, E extends EventObject>(
|
|
|
1553
1663
|
}
|
|
1554
1664
|
|
|
1555
1665
|
busy = true;
|
|
1666
|
+
fillPrivate(ctx as never, configs[ROOT], false);
|
|
1556
1667
|
enterState(ROOT);
|
|
1557
1668
|
enterDefaults(ROOT, 0);
|
|
1558
1669
|
refreshLeaves();
|
|
@@ -1585,6 +1696,11 @@ function define<Ctx, E extends EventObject>(
|
|
|
1585
1696
|
return machine;
|
|
1586
1697
|
}
|
|
1587
1698
|
|
|
1699
|
+
// Ctx for a config without privateCtx, Ctx & Priv for one with it. The tuple test keeps the
|
|
1700
|
+
// context whole while Priv has no inference yet, so a generic helper in a slot, such as
|
|
1701
|
+
// `sequence`, still takes its ctx from the slot.
|
|
1702
|
+
type WithPrivate<Ctx, Priv> = [Priv] extends [never] ? Ctx : Ctx & Priv;
|
|
1703
|
+
|
|
1588
1704
|
// Ctx and E are given explicitly and the config is inferred, so the config takes a second call.
|
|
1589
1705
|
// A key makes a later definition under it (a hot-reloaded module re-running) rebind live instances.
|
|
1590
1706
|
/**
|
|
@@ -1593,9 +1709,117 @@ function define<Ctx, E extends EventObject>(
|
|
|
1593
1709
|
* when that call runs, and a mistake throws, naming the state path. With a key, a later
|
|
1594
1710
|
* definition under it puts its states into the machine already built, so every running instance
|
|
1595
1711
|
* sees the edit; without one, each call builds a separate machine.
|
|
1712
|
+
*
|
|
1713
|
+
* The root config may hold `privateCtx`, for a machine that keeps fields of its own, such as a
|
|
1714
|
+
* counter, a heat level or a list it builds up. Every hook, `when`, `run`, `task` and `update`
|
|
1715
|
+
* then sees those fields beside `Ctx`, while `start` takes only `Ctx` and the instance it returns
|
|
1716
|
+
* shows only `Ctx` in its `ctx`. A machine without fields of its own leaves `privateCtx` out.
|
|
1596
1717
|
*/
|
|
1597
1718
|
export function defineMachine<Ctx, E extends EventObject>(
|
|
1598
1719
|
key?: string,
|
|
1599
|
-
): <T
|
|
1720
|
+
): <T, Priv extends object = never>(
|
|
1721
|
+
config: RootState<WithPrivate<Ctx, Priv>, E, T> & PrivateCtxConfig<Ctx, Priv>,
|
|
1722
|
+
) => Machine<Ctx, E, TreePath<T>> {
|
|
1600
1723
|
return ((config: MachineConfig<Ctx, E>) => define(key, config)) as never;
|
|
1601
1724
|
}
|
|
1725
|
+
|
|
1726
|
+
/**
|
|
1727
|
+
* The optional key a `defineMachine` root config takes beside `initial` and `states`.
|
|
1728
|
+
* @noSelf
|
|
1729
|
+
*/
|
|
1730
|
+
export interface PrivateCtxConfig<Ctx, Priv> {
|
|
1731
|
+
/**
|
|
1732
|
+
* Builds the fields only the machine uses. It runs once per `start`, before the root's `enter`
|
|
1733
|
+
* hook, so every instance gets fresh fields of its own; a value written straight into the
|
|
1734
|
+
* config would be one array or table shared by every instance. It receives the object passed
|
|
1735
|
+
* to `start`, typed `Ctx`, so a private field can start from a field of `Ctx`:
|
|
1736
|
+
* `privateCtx: (ctx: TurretOptions) => ({ heat: ctx.startHeat })`. Give `ctx` its type; without
|
|
1737
|
+
* one TypeScript can type a hook before it knows the private fields, and that hook reports the
|
|
1738
|
+
* field as missing.
|
|
1739
|
+
*
|
|
1740
|
+
* The fields are added to the object passed to `start`, which stays the instance's `ctx`, so
|
|
1741
|
+
* restarting with `start(old.ctx)` keeps the public fields and builds the private ones fresh.
|
|
1742
|
+
* A hot reload under the machine's key adds the fields a new factory introduces and leaves
|
|
1743
|
+
* every field that already holds a value alone. A private field may not share a name with a
|
|
1744
|
+
* field of `Ctx`.
|
|
1745
|
+
*
|
|
1746
|
+
* The fields are hidden from callers by type only. At run time `ctx` is one table, and hooks,
|
|
1747
|
+
* `hsm-view` and a debugger see every field.
|
|
1748
|
+
*
|
|
1749
|
+
* There are two ways to type the fields.
|
|
1750
|
+
*
|
|
1751
|
+
* @example
|
|
1752
|
+
* **Inferred.** For a few fields, write them inline and let TypeScript infer their types. Add
|
|
1753
|
+
* `as` where the inferred type is wrong: an empty array is `never[]` until it reads
|
|
1754
|
+
* `[] as Hash[]`, and a field holding one of several strings is any `string` until it reads
|
|
1755
|
+
* `"cool" as "cool" | "hot"`.
|
|
1756
|
+
*
|
|
1757
|
+
* ```ts
|
|
1758
|
+
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
1759
|
+
*
|
|
1760
|
+
* export const turret = defineMachine<{ readonly fireRate: number }, TurretEvent>("turret")({
|
|
1761
|
+
* privateCtx: () => ({ heat: 0, targets: [] as Hash[] }),
|
|
1762
|
+
* initial: "/idle",
|
|
1763
|
+
* states: {
|
|
1764
|
+
* idle: { on: { SPOTTED: "/firing" } },
|
|
1765
|
+
* firing: {
|
|
1766
|
+
* enter: (ctx) => {
|
|
1767
|
+
* ctx.heat += 1 / ctx.fireRate;
|
|
1768
|
+
* },
|
|
1769
|
+
* on: { LOST: "/idle" },
|
|
1770
|
+
* },
|
|
1771
|
+
* },
|
|
1772
|
+
* });
|
|
1773
|
+
*
|
|
1774
|
+
* const gun = turret.start({ fireRate: 2 }); // gun.ctx shows fireRate only
|
|
1775
|
+
* ```
|
|
1776
|
+
*
|
|
1777
|
+
* @example
|
|
1778
|
+
* **A named type.** For more fields, or when a helper outside the config needs the whole
|
|
1779
|
+
* context, declare the fields as an interface and make it the factory's return type. The
|
|
1780
|
+
* fields need no `as`, a misspelled or unknown field is a compile error, and the whole context
|
|
1781
|
+
* is `TurretOptions & TurretPrivate`. `satisfies TurretPrivate` does not do this: it checks the
|
|
1782
|
+
* object but keeps its narrow types, so an empty array stays `never[]`.
|
|
1783
|
+
*
|
|
1784
|
+
* ```ts
|
|
1785
|
+
* interface TurretOptions {
|
|
1786
|
+
* readonly fireRate: number;
|
|
1787
|
+
* }
|
|
1788
|
+
*
|
|
1789
|
+
* interface TurretPrivate {
|
|
1790
|
+
* heat: number;
|
|
1791
|
+
* mode: "cool" | "hot";
|
|
1792
|
+
* }
|
|
1793
|
+
*
|
|
1794
|
+
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
1795
|
+
*
|
|
1796
|
+
* const overheated = (ctx: TurretOptions & TurretPrivate) => ctx.heat > ctx.fireRate;
|
|
1797
|
+
*
|
|
1798
|
+
* export const turret = defineMachine<TurretOptions, TurretEvent>("turret")({
|
|
1799
|
+
* privateCtx: (): TurretPrivate => ({ heat: 0, mode: "cool" }),
|
|
1800
|
+
* initial: "/idle",
|
|
1801
|
+
* states: {
|
|
1802
|
+
* idle: { on: { SPOTTED: "/firing" } },
|
|
1803
|
+
* firing: {
|
|
1804
|
+
* enter: (ctx) => {
|
|
1805
|
+
* ctx.heat += 1 / ctx.fireRate;
|
|
1806
|
+
* },
|
|
1807
|
+
* always: { to: "/cooling", when: overheated },
|
|
1808
|
+
* on: { LOST: "/idle" },
|
|
1809
|
+
* },
|
|
1810
|
+
* cooling: {
|
|
1811
|
+
* enter: (ctx) => {
|
|
1812
|
+
* ctx.mode = "hot";
|
|
1813
|
+
* },
|
|
1814
|
+
* exit: (ctx) => {
|
|
1815
|
+
* ctx.heat = 0;
|
|
1816
|
+
* ctx.mode = "cool";
|
|
1817
|
+
* },
|
|
1818
|
+
* after: { 2: "/idle" },
|
|
1819
|
+
* },
|
|
1820
|
+
* },
|
|
1821
|
+
* });
|
|
1822
|
+
* ```
|
|
1823
|
+
*/
|
|
1824
|
+
readonly privateCtx?: (ctx: Ctx) => Priv & { readonly [K in keyof Ctx & keyof Priv]: never };
|
|
1825
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -3666,6 +3666,7 @@ function transpileVirtual(files, companionEmit, overrides = {}) {
|
|
|
3666
3666
|
sourceMap: true,
|
|
3667
3667
|
lib: ["lib.es2022.d.ts"],
|
|
3668
3668
|
skipLibCheck: true,
|
|
3669
|
+
resolvePackageJsonImports: false,
|
|
3669
3670
|
noImplicitSelf: true,
|
|
3670
3671
|
luaPlugins: [
|
|
3671
3672
|
{ plugin: lifecycleErasurePlugin },
|
|
@@ -3745,6 +3746,7 @@ function compilerOptions(companionEmit) {
|
|
|
3745
3746
|
sourceMap: true,
|
|
3746
3747
|
lib: ["lib.es2022.d.ts"],
|
|
3747
3748
|
skipLibCheck: true,
|
|
3749
|
+
resolvePackageJsonImports: false,
|
|
3748
3750
|
noImplicitSelf: true,
|
|
3749
3751
|
luaPlugins: [
|
|
3750
3752
|
{ plugin: lifecycleErasurePlugin },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defold-typescript/transpiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.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.48.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/session.ts
CHANGED
|
@@ -35,6 +35,13 @@ function compilerOptions(companionEmit: CompanionEmitter): tstl.CompilerOptions
|
|
|
35
35
|
// Don't cross-check the seeded ambient .d.ts surface against itself; only user
|
|
36
36
|
// files matter (mirrors transpileProject and the editor's skipLibCheck).
|
|
37
37
|
skipLibCheck: true,
|
|
38
|
+
// TypeScript turns this on under its default `bundler` resolution. With it on,
|
|
39
|
+
// an error that has to name a module-declared type the file does not import
|
|
40
|
+
// (`Url`, `Hash`, `Vector3`) throws inside the checker, which builds a module
|
|
41
|
+
// specifier from an undefined base path and the virtual host's empty current
|
|
42
|
+
// directory. The virtual host reads every `package.json` as empty, so no `#`
|
|
43
|
+
// import resolves with the option on or off.
|
|
44
|
+
resolvePackageJsonImports: false,
|
|
38
45
|
// Defold scripts are not OO: free helper functions never receive a context,
|
|
39
46
|
// so suppress TSTL's implicit `self` parameter and the `_G` call-site filler.
|
|
40
47
|
noImplicitSelf: true,
|
package/src/transpile.ts
CHANGED
|
@@ -341,6 +341,13 @@ function transpileVirtual(
|
|
|
341
341
|
// Don't cross-check the seeded ambient .d.ts surface against itself; we only
|
|
342
342
|
// care about diagnostics on user files (mirrors the editor's skipLibCheck).
|
|
343
343
|
skipLibCheck: true,
|
|
344
|
+
// TypeScript turns this on under its default `bundler` resolution. With it on,
|
|
345
|
+
// an error that has to name a module-declared type the file does not import
|
|
346
|
+
// (`Url`, `Hash`, `Vector3`) throws inside the checker, which builds a module
|
|
347
|
+
// specifier from an undefined base path and the virtual host's empty current
|
|
348
|
+
// directory. The virtual host reads every `package.json` as empty, so no `#`
|
|
349
|
+
// import resolves with the option on or off.
|
|
350
|
+
resolvePackageJsonImports: false,
|
|
344
351
|
// Defold scripts are not OO: free helper functions never receive a context,
|
|
345
352
|
// so suppress TSTL's implicit `self` parameter and the `_G` call-site filler.
|
|
346
353
|
noImplicitSelf: true,
|