@moku-labs/game 0.7.1 → 0.9.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.
Files changed (40) hide show
  1. package/README.md +12 -8
  2. package/dist/assets.d.mts +97 -33
  3. package/dist/assets.mjs +350 -110
  4. package/dist/{commands-mzE9PX0H.d.mts → commands-DuwCxK5t.d.mts} +5 -4
  5. package/dist/control.d.mts +4 -3
  6. package/dist/control.mjs +2 -2
  7. package/dist/{define-BbgXv4cy.d.mts → define-B6pHpdBi.d.mts} +4 -3
  8. package/dist/headless-BsNdJs9W.mjs +186 -0
  9. package/dist/headless-SCQXJxQf.d.mts +181 -0
  10. package/dist/hot.d.mts +4 -2
  11. package/dist/hot.mjs +8 -6
  12. package/dist/index-BO9kZzY3.d.mts +1611 -0
  13. package/dist/index.d.mts +6 -1596
  14. package/dist/index.mjs +4 -34334
  15. package/dist/{input-CK4nxBO1.mjs → input-z_35Jwfn.mjs} +2 -2
  16. package/dist/inspect.d.mts +7 -6
  17. package/dist/inspect.mjs +2 -2
  18. package/dist/jsx-dev-runtime.d.mts +1 -1
  19. package/dist/jsx-runtime.d.mts +1 -1
  20. package/dist/lint.d.mts +55 -4
  21. package/dist/lint.mjs +993 -40
  22. package/dist/project.d.mts +57 -41
  23. package/dist/project.mjs +994 -505
  24. package/dist/{run-Bcyg32M5.mjs → run-CofJEdYx.mjs} +4 -187
  25. package/dist/{runtime-HTlmRb81.d.mts → runtime-CdNJ0UBm.d.mts} +1 -1
  26. package/dist/{sources-DVWJ8nfr.mjs → sources-DNnzyCYf.mjs} +2 -2
  27. package/dist/src-536arXjV.mjs +34644 -0
  28. package/dist/testing.d.mts +85 -283
  29. package/dist/testing.mjs +158 -2109
  30. package/dist/{types-BMEn0tSC.d.mts → types-B0v5VVa3.d.mts} +10 -9
  31. package/dist/{types-ClF8say0.d.mts → types-CQueODzo.d.mts} +2 -2
  32. package/dist/{types-CYYKjvLn.d.mts → types-DUMoYPYe.d.mts} +5 -182
  33. package/dist/{types-CXyipKhE.d.mts → types-VZVWwqCg.d.mts} +42 -4
  34. package/dist/{types-BaUUcIaN.d.mts → types-xXfyk56Q.d.mts} +1 -1
  35. package/dist/{visual-DUvvPPCt.mjs → visual-dMW8iqAE.mjs} +8 -4
  36. package/dist/visual.d.mts +330 -0
  37. package/dist/visual.mjs +2142 -0
  38. package/llms.txt +59 -21
  39. package/package.json +7 -8
  40. package/dist/memory-CvgdnsQO.mjs +0 -259
@@ -4,8 +4,9 @@
4
4
  * it holds, the anchors of a key, the fresh lines `find` answers and the handle itself. The index
5
5
  * maps every engine id of a game (flows, nodes, features, scenes, projections, emitters, text
6
6
  * styles, styles, components and JSX keys) to anchors: a path plus a binding, a key or a component. It never
7
- * holds a line number; `find` reads the line from the file as it is on disk at the call. No type
8
- * here names a `typescript` type, so the shipped declarations need no TypeScript.
7
+ * holds a line number; `find` reads the line from the file as it is on disk at the call. Names are
8
+ * followed through relative imports and the tsconfig `paths` of the game. No type here names a
9
+ * `typescript` type, so the shipped declarations need no TypeScript.
9
10
  */
10
11
  /**
11
12
  * What `openProject` reads. Paths are root-relative POSIX; the root itself is resolved against the
@@ -13,13 +14,20 @@
13
14
  *
14
15
  * @example
15
16
  * ```ts
16
- * // The editor opens the fixture game with the default manifest and a slower debounce.
17
- * const options: ProjectOptions = { root: "tests/integration/merge-game", debounceMs: 120 };
17
+ * // The editor opens the mini game with the default manifest and a slower debounce.
18
+ * const options: ProjectOptions = { root: "tests/fixtures/mini-game", debounceMs: 120 };
19
+ * // A v15 game whose aliases live in a second tsconfig.
20
+ * const game: ProjectOptions = { root: "games/orders", tsconfig: "tsconfig.game.json" };
18
21
  * ```
19
22
  */
20
23
  type ProjectOptions = {
21
24
  /** The folder of the game. A path that is not a directory rejects `openProject`. */root: string; /** The asset manifest, root-relative. Default `manifest.json`, the scanner's default. */
22
- manifest?: string; /** The quiet period, in milliseconds, that closes a batch of file events. Default 75. */
25
+ manifest?: string;
26
+ /**
27
+ * The tsconfig whose `paths` the index follows, root-relative. Default `tsconfig.json`. A path
28
+ * that leaves the root or a file that does not parse rejects `openProject`.
29
+ */
30
+ tsconfig?: string; /** The quiet period, in milliseconds, that closes a batch of file events. Default 75. */
23
31
  debounceMs?: number;
24
32
  };
25
33
  /**
@@ -29,7 +37,7 @@ type ProjectOptions = {
29
37
  *
30
38
  * @example
31
39
  * ```ts
32
- * const kind: JsxKind = "idProp"; // id="settingsBoard" on <Signboard>
40
+ * const kind: JsxKind = "idProp"; // id="infoPanel" on <Panel>
33
41
  * ```
34
42
  */
35
43
  type JsxKind = "literal" | "template" | "idProp" | "ident";
@@ -39,8 +47,8 @@ type JsxKind = "literal" | "template" | "idProp" | "ident";
39
47
  *
40
48
  * @example
41
49
  * ```ts
42
- * // node:board/merge, defined by the const `merge` of nodes/merge.ts.
43
- * const anchor: Anchor = { path: "nodes/merge.ts", binding: "merge" };
50
+ * // node:infoPopup/count, defined by the const `count` of nodes/count.ts.
51
+ * const anchor: Anchor = { path: "nodes/count.ts", binding: "count" };
44
52
  * ```
45
53
  */
46
54
  type Anchor = {
@@ -66,14 +74,17 @@ type Anchor = {
66
74
  *
67
75
  * @example
68
76
  * ```ts
69
- * index.symbols["flow:board"]; // { def: [{ path: "flows/board.ts", binding: "boardFlow" }] }
70
- * index.files["nodes/merge.ts"]?.state; // "ok"
77
+ * index.symbols["flow:infoPopup"]; // { def: [{ path: "flows/info.ts", binding: "infoFlow" }] }
78
+ * index.files["nodes/count.ts"]?.state; // "ok"
79
+ * // A game whose tsconfig.json holds paths, such as tests/fixtures/layout-game.
80
+ * index.tsconfig; // "tsconfig.json"
71
81
  * ```
72
82
  */
73
83
  type ProjectIndex = {
74
84
  /** The shape of this object. A change of shape bumps it. */schemaVersion: 1; /** sha1 hex over the sorted lines `${path}\0${hash}\n` of every indexed file. */
75
85
  revision: string; /** The asset manifest, root-relative, when that file exists. */
76
- manifest?: string;
86
+ manifest?: string; /** The tsconfig, root-relative, when that file exists and holds `paths` the index follows. */
87
+ tsconfig?: string;
77
88
  /**
78
89
  * Every key: where it is defined (`def`), where its binding is used (`uses`, nodes, styles and
79
90
  * components, one level), and `conflict` when a key other than `jsx:` is defined twice.
@@ -99,9 +110,9 @@ type ProjectIndex = {
99
110
  *
100
111
  * @example
101
112
  * ```ts
102
- * // An agent moved nodes/toast.ts to nodes/board/toast.ts and fixed the import of the board flow.
103
- * change.files; // ["flows/board.ts", "nodes/board/toast.ts", "nodes/toast.ts"]
104
- * change.moved; // [{ key: "node:board/toast", from: "nodes/toast.ts", to: "nodes/board/toast.ts" }]
113
+ * // An agent moved nodes/count.ts to nodes/info/count.ts and fixed the import of the info flow.
114
+ * change.files; // ["flows/info.ts", "nodes/count.ts", "nodes/info/count.ts"]
115
+ * change.moved; // [{ key: "node:infoPopup/count", from: "nodes/count.ts", to: "nodes/info/count.ts" }]
105
116
  * change.removed; // []
106
117
  * ```
107
118
  */
@@ -123,9 +134,9 @@ type ProjectChange = {
123
134
  *
124
135
  * @example
125
136
  * ```ts
126
- * // The editor opens the Home scene of the fixture game.
137
+ * // The editor opens the Home scene of the mini game.
127
138
  * const [found] = await project.find("scene:home");
128
- * [found?.path, found?.line, found?.range]; // ["features/home/scene.ts", 8, [8, 1, 13, 4]]
139
+ * [found?.path, found?.line, found?.range]; // ["features/home/scene.ts", 8, [8, 1, 12, 4]]
129
140
  * ```
130
141
  */
131
142
  type Found = Anchor & {
@@ -145,26 +156,27 @@ type ProjectApi = {
145
156
  * @example
146
157
  * ```ts
147
158
  * // The editor checks a node file before it opens it.
148
- * project.index.files["nodes/merge.ts"]?.state; // "ok"
159
+ * project.index.files["nodes/count.ts"]?.state; // "ok"
149
160
  * ```
150
161
  */
151
162
  readonly index: ProjectIndex;
152
163
  /**
153
- * Answers where a key is defined, with lines read from the file on disk now. A file whose bytes
154
- * changed since the index was built is parsed again for the answer; the index itself stays as
155
- * it is until the next watch batch. A JSX key the game reports at run time also finds the
156
- * patterns it was built from: exact keys first, then `{id}` and `{amountKey}` patterns filled
157
- * with a literal prop of the same name on their component (both the pattern and the prop come
158
- * back), then `*` patterns. An unknown key answers `[]`.
164
+ * Answers where a key is defined, with lines read from the file on disk now. A name is followed
165
+ * through relative imports and the tsconfig aliases, so `@features/home` reaches the file that
166
+ * declares the node. A file whose bytes changed since the index was built is parsed again for
167
+ * the answer; the index itself stays as it is until the next watch batch. A JSX key the game
168
+ * reports at run time also finds the patterns it was built from: exact keys first, then `{id}`
169
+ * and `{amountKey}` patterns filled with a literal prop of the same name on their component
170
+ * (both the pattern and the prop come back), then `*` patterns. An unknown key answers `[]`.
159
171
  *
160
- * @param key - An engine id: `node:board/merge`, `flow:board`, `textStyle:ui.title`, `jsx:card2Picture`.
172
+ * @param key - An engine id: `node:infoPopup/count`, `flow:main`, `textStyle:ui.counter`, `jsx:infoPanelSpark`.
161
173
  * @returns One entry per place, in the order above; `broken` when the file does not parse now.
162
174
  * @example
163
175
  * ```ts
164
- * // The editor jumps to the node the flow view clicked, and to the X of the settings board.
165
- * (await project.find("node:board/merge"))[0]?.line; // 17, in "nodes/merge.ts"
166
- * (await project.find("jsx:settingsBoardClose")).map(found => `${found.path}:${found.line}`);
167
- * // ["features/ui/kit.tsx:844", "features/settings/settings.tsx:290"]
176
+ * // The editor jumps to the node the flow view clicked, and to the spark of the info panel.
177
+ * (await project.find("node:infoPopup/count"))[0]?.line; // 7, in "nodes/count.ts"
178
+ * (await project.find("jsx:infoPanelSpark")).map(found => `${found.path}:${found.line}`);
179
+ * // ["features/info/popup.tsx:65", "features/info/popup.tsx:79"]
168
180
  * ```
169
181
  */
170
182
  find(key: string): Promise<Found[]>;
@@ -190,17 +202,20 @@ type ProjectApi = {
190
202
  watch(onIndex: (index: ProjectIndex, change: ProjectChange) => void): () => void;
191
203
  /**
192
204
  * Re-indexes one root-relative path now, for a caller that watches files itself. A deleted
193
- * file drops its entries; a path that is not a `.ts` or `.tsx` source of the index changes
194
- * nothing. The watch callers are not called.
205
+ * file drops its entries. The tsconfig, or a file it extends, reads the aliases again, and the
206
+ * index is rebuilt when names now follow them elsewhere. Any other path that is not a `.ts` or
207
+ * `.tsx` source of the index changes nothing. The watch callers are not called.
195
208
  *
196
209
  * @param path - The root-relative POSIX path of the file.
197
210
  * @returns The index after the file was read.
198
211
  * @throws {Error} When the path leaves the root, by `..` or by a symlink.
199
212
  * @example
200
213
  * ```ts
201
- * // The editor saved nodes/merge.ts through its own file layer.
202
- * const index = await project.changed("nodes/merge.ts");
203
- * index.files["nodes/merge.ts"]?.state; // "ok"
214
+ * // The editor saved nodes/count.ts through its own file layer.
215
+ * const index = await project.changed("nodes/count.ts");
216
+ * index.files["nodes/count.ts"]?.state; // "ok"
217
+ * // It added a paths block to tsconfig.json: the keys behind the aliases join the index.
218
+ * (await project.changed("tsconfig.json")).tsconfig; // "tsconfig.json"
204
219
  * ```
205
220
  */
206
221
  changed(path: string): Promise<ProjectIndex>;
@@ -247,9 +262,9 @@ type IndexUi = {
247
262
  * `--check` that found a broken file or a conflict; else `0`.
248
263
  * @example
249
264
  * ```ts
250
- * // An agent asks where a node of the fixture game lives.
251
- * await runCli(["--root", "tests/integration/merge-game", "where", "node:board/merge"]);
252
- * // 0, and the console printed "nodes/merge.ts:17"
265
+ * // An agent asks where a node of the mini game lives.
266
+ * await runCli(["--root", "tests/fixtures/mini-game", "where", "node:infoPopup/count"]);
267
+ * // 0, and the console printed "nodes/count.ts:7"
253
268
  * ```
254
269
  */
255
270
  declare function runCli(argv: readonly string[], ui?: IndexUi): Promise<number>;
@@ -260,16 +275,17 @@ declare function runCli(argv: readonly string[], ui?: IndexUi): Promise<number>;
260
275
  * path), loads TypeScript, parses every source file and builds the index. Nothing is written to
261
276
  * disk and nothing is inferred from the working directory but the root itself.
262
277
  *
263
- * @param options - The game root, the manifest path and the quiet period of `watch`.
278
+ * @param options - The game root, the manifest path, the tsconfig whose `paths` the index follows
279
+ * (`tsconfig`, root-relative, `tsconfig.json` by default) and the quiet period of `watch`.
264
280
  * @returns The handle; close it when the game closes.
265
281
  * @throws {Error} When the root is missing or not a directory, or the `typescript` package is not
266
282
  * installed: `[game] The project index needs the "typescript" package.`
267
283
  * @example
268
284
  * ```ts
269
- * // The editor opens the fixture game and answers where a node and a text style live.
270
- * const project = await openProject({ root: "tests/integration/merge-game" });
271
- * Object.keys(project.index.files).length; // 111
272
- * (await project.find("textStyle:ui.title"))[0]?.line; // 39, in "features/ui/styles.ts"
285
+ * // The editor opens the mini game and answers where a node and a text style live.
286
+ * const project = await openProject({ root: "tests/fixtures/mini-game" });
287
+ * Object.keys(project.index.files).length; // 21
288
+ * (await project.find("textStyle:ui.counter"))[0]?.line; // 16, in "features/home/styles.ts"
273
289
  * project.close();
274
290
  * ```
275
291
  */