@moku-labs/game 0.14.11 → 0.14.13
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/README.md +13 -12
- package/dist/app/page.d.mts +8 -3
- package/dist/app/page.mjs +57 -12
- package/dist/app/system.d.mts +5 -3
- package/dist/app/system.mjs +2 -0
- package/dist/app.d.mts +15 -7
- package/dist/app.mjs +131 -27
- package/dist/{assets-BrKSg1O6.mjs → assets-CEMfBogh.mjs} +471 -120
- package/dist/assets.d.mts +30 -13
- package/dist/assets.mjs +1 -1
- package/dist/cli.d.mts +105 -8
- package/dist/cli.mjs +1036 -128
- package/dist/{commands-d5Zlh9hf.d.mts → commands-DAETmK86.d.mts} +43 -7
- package/dist/{config-CdARrrhU.mjs → config-B87aFTW-.mjs} +25 -4
- package/dist/control.d.mts +130 -17
- package/dist/control.mjs +4 -4
- package/dist/{define-BN15lAWb.d.mts → define-BASd9ZUh.d.mts} +32 -4
- package/dist/dev-DbHgx-R-.mjs +89 -0
- package/dist/{fake-MpzwZhIZ.mjs → fake-6mazmHK3.mjs} +20 -2
- package/dist/features-DowEilZm.mjs +266 -0
- package/dist/{headless-CrhefcLu.d.mts → headless-cFveciuY.d.mts} +1 -1
- package/dist/hot.d.mts +4 -2
- package/dist/hot.mjs +7 -4
- package/dist/{index-0GIP3tgm.d.mts → index-DedbED3T.d.mts} +317 -69
- package/dist/index.d.mts +5 -6
- package/dist/index.mjs +3 -3
- package/dist/inspect.d.mts +12 -7
- package/dist/inspect.mjs +2 -2
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/lint.d.mts +8 -3
- package/dist/lint.mjs +432 -20
- package/dist/project.d.mts +15 -1
- package/dist/project.mjs +1 -1
- package/dist/{run-Bf2hKyjZ.mjs → run-BbipFRc6.mjs} +250 -51
- package/dist/{runtime-aLkoeoGj.d.mts → runtime-DoSlRx8X.d.mts} +1 -1
- package/dist/{session-DgukhR_7.mjs → session-CeKgO2hy.mjs} +30 -2
- package/dist/{sources-Duzj6lhV.mjs → sources-Cdvb0rOS.mjs} +33 -6
- package/dist/{src-Do697seR.mjs → src-BEbJ_sSx.mjs} +29154 -11121
- package/dist/testing.d.mts +119 -14
- package/dist/testing.mjs +97 -7
- package/dist/{types-BZa187kz.d.mts → types-7GXcXxxv.d.mts} +196 -242
- package/dist/{types-BT9S_Lo2.d.mts → types-BGcda5Le.d.mts} +4464 -735
- package/dist/{types-yiHtzg1Y.d.mts → types-C73hbmxi.d.mts} +129 -17
- package/dist/{types-Bc9AvZVO.d.mts → types-DngFQJro.d.mts} +43 -5
- package/dist/{types-kNiV7iFj.d.mts → types-GHE4J5Uf.d.mts} +1027 -192
- package/dist/{visual-dMW8iqAE.mjs → visual-2m4wJL_z.mjs} +111 -7
- package/dist/visual-_XhoGeIC.d.mts +345 -0
- package/dist/visual.d.mts +1 -332
- package/dist/visual.mjs +130 -20
- package/dist/{watch-CWI_on4T.mjs → watch-BEdrp80i.mjs} +149 -30
- package/llms.txt +103 -51
- package/package.json +8 -6
- package/dist/dev-Cc50Dk7H.mjs +0 -47
- package/dist/memory-DR1ibF_s.d.mts +0 -50
- package/dist/types-DMoi447V.d.mts +0 -656
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/project/features.ts
|
|
4
|
+
/** The folders that hold one kind of code or resource of a feature: never a sub-feature, whatever they hold. */
|
|
5
|
+
const KIND_FOLDER = /^(?:flow|views|rules|styles|motion|world|effects|nodes|assets|strings|content|__tests__)$/;
|
|
6
|
+
/** The file names of a door, in the order a door is looked for. */
|
|
7
|
+
const DOORS = ["index.ts", "index.tsx"];
|
|
8
|
+
/** A `//` comment to the end of the line or a block comment, whichever starts first. */
|
|
9
|
+
const COMMENT = /\/\*[\s\S]*?\*\/|\/\/[^\n]*/g;
|
|
10
|
+
/** An import declaration: the text up to its source (the clause and `from`), and the source. */
|
|
11
|
+
const IMPORT = /\bimport\b([^;"']*)["']([^"']+)["']/g;
|
|
12
|
+
/** A `features: [ … ]` property, key bare or quoted, up to the first `]`. */
|
|
13
|
+
const LISTING = /(?:\bfeatures|"features"|'features')\s*:\s*\[([^\]]*)\]/g;
|
|
14
|
+
/** An identifier. */
|
|
15
|
+
const IDENTIFIER = /[$A-Z_a-z][\w$]*/g;
|
|
16
|
+
/** A source naming a folder beside the door: `./<folder>`, `./<folder>/index`, either with `.ts`, `.tsx` or `.js`. */
|
|
17
|
+
const FOLDER_SOURCE = /^\.\/([^/]+?)(?:\/index)?(?:\.(?:tsx?|js))?$/;
|
|
18
|
+
/**
|
|
19
|
+
* Finds every feature owner of a game: each folder of the features folder, and inside an owner each folder (not a kind
|
|
20
|
+
* folder such as `flow/` or `assets/`) with a door `index.ts` and resources of its own, at any depth. Depth first, a
|
|
21
|
+
* parent before its children, siblings sorted as the asset scanner sorts features. Reads folders only, never a door.
|
|
22
|
+
*
|
|
23
|
+
* @param root - The game folder.
|
|
24
|
+
* @param features - The name of the folder that holds the features. Default `"features"`.
|
|
25
|
+
* @returns The owners; none when the features folder is missing.
|
|
26
|
+
* @throws {Error} When one feature name belongs to two folders; the message names both.
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // tests/fixtures/episodes-game
|
|
30
|
+
* findFeatureOwners("tests/fixtures/episodes-game").map(owner => owner.dir);
|
|
31
|
+
* // ["features/episodes", "features/episodes/ep01", "features/episodes/ep02",
|
|
32
|
+
* // "features/episodes/episodes-kit", "features/home"]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function findFeatureOwners(root, features = "features") {
|
|
36
|
+
return walk(root, features, false);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Finds every feature folder lint and the project index treat as a unit: the owners of `findFeatureOwners`, and
|
|
40
|
+
* inside an owner each code-only folder with a door that the owner's door imports from `./<folder>` and lists in
|
|
41
|
+
* `features: [...]`. Reads the owners' doors as text, never with TypeScript. Same order and the same name check as
|
|
42
|
+
* `findFeatureOwners`. A code-only sub-feature declares no sub-features: its own folders are never searched.
|
|
43
|
+
*
|
|
44
|
+
* @param root - The game folder.
|
|
45
|
+
* @param features - The name of the folder that holds the features. Default `"features"`.
|
|
46
|
+
* @returns The owners and the code-only sub-features; none when the features folder is missing.
|
|
47
|
+
* @throws {Error} When one feature name belongs to two folders; the message names both.
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* // features/episodes/index.ts imports { toolsFeature } from "./tools" and lists it in features: [...];
|
|
51
|
+
* // features/episodes/tools/ has an index.ts and code only.
|
|
52
|
+
* findFeatureUnits("game").find(unit => unit.name === "tools");
|
|
53
|
+
* // { name: "tools", dir: "features/episodes/tools", parent: "episodes", depth: 1, resources: { assets: false, strings: false } }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
function findFeatureUnits(root, features = "features") {
|
|
57
|
+
return walk(root, features, true);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The owner a root-relative path belongs to: the one with the longest `dir` that is the path or a folder above it.
|
|
61
|
+
*
|
|
62
|
+
* @param owners - The owners of `findFeatureOwners`, or the units of `findFeatureUnits`.
|
|
63
|
+
* @param file - A root-relative POSIX path, a file or a folder, with or without an extension.
|
|
64
|
+
* @returns The deepest owner holding it; `undefined` outside every owner.
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* ownerOf([{ dir: "features/episodes" }, { dir: "features/episodes/ep01" }], "features/episodes/ep01/flow/story.ts")?.dir; // "features/episodes/ep01"
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
function ownerOf(owners, file) {
|
|
71
|
+
let deepest;
|
|
72
|
+
for (const owner of owners) if ((file === owner.dir || file.startsWith(`${owner.dir}/`)) && (deepest === void 0 || owner.dir.length > deepest.dir.length)) deepest = owner;
|
|
73
|
+
return deepest;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Walks the features folder: each of its folders is an owner, and below each owner its sub-features.
|
|
77
|
+
*
|
|
78
|
+
* @param root - The game folder.
|
|
79
|
+
* @param features - The features folder, relative to the root.
|
|
80
|
+
* @param units - True to add the code-only sub-features the owners' doors list.
|
|
81
|
+
* @returns The owners (and units), depth first, siblings sorted.
|
|
82
|
+
* @throws {Error} When one feature name belongs to two folders.
|
|
83
|
+
*/
|
|
84
|
+
function walk(root, features, units) {
|
|
85
|
+
const top = path.join(root, features);
|
|
86
|
+
const base = features.replaceAll("\\", "/");
|
|
87
|
+
const found = [];
|
|
88
|
+
for (const entry of sorted(list(top).filter((item) => item.isDirectory()))) {
|
|
89
|
+
const folder = path.join(top, entry.name);
|
|
90
|
+
const entries = list(folder);
|
|
91
|
+
collect(found, {
|
|
92
|
+
name: entry.name,
|
|
93
|
+
dir: path.posix.join(base, entry.name),
|
|
94
|
+
depth: 0,
|
|
95
|
+
resources: resourcesOf(entries)
|
|
96
|
+
}, folder, entries, units);
|
|
97
|
+
}
|
|
98
|
+
checkNames(found);
|
|
99
|
+
return found;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Adds an owner, then its sub-features in sibling order: an owner sub-feature with its own sub-features, a code-only
|
|
103
|
+
* one its door lists as a leaf.
|
|
104
|
+
*
|
|
105
|
+
* @param found - The list to add to, in walk order.
|
|
106
|
+
* @param owner - The owner to add.
|
|
107
|
+
* @param folder - The owner's folder on disk.
|
|
108
|
+
* @param entries - The entries of that folder.
|
|
109
|
+
* @param units - True to add the code-only sub-features the door lists.
|
|
110
|
+
*/
|
|
111
|
+
function collect(found, owner, folder, entries, units) {
|
|
112
|
+
found.push(owner);
|
|
113
|
+
const listed = units ? listedIn(folder, entries) : [];
|
|
114
|
+
for (const child of sorted(entries.filter((entry) => isCandidate(entry)))) {
|
|
115
|
+
const childFolder = path.join(folder, child.name);
|
|
116
|
+
const childEntries = list(childFolder);
|
|
117
|
+
if (doorOf(childEntries) === void 0) continue;
|
|
118
|
+
const resources = resourcesOf(childEntries);
|
|
119
|
+
const sub = {
|
|
120
|
+
name: child.name,
|
|
121
|
+
dir: `${owner.dir}/${child.name}`,
|
|
122
|
+
parent: owner.name,
|
|
123
|
+
depth: owner.depth + 1
|
|
124
|
+
};
|
|
125
|
+
if (resources.assets || resources.strings) collect(found, {
|
|
126
|
+
...sub,
|
|
127
|
+
resources
|
|
128
|
+
}, childFolder, childEntries, units);
|
|
129
|
+
else if (listed.includes(child.name)) found.push({
|
|
130
|
+
...sub,
|
|
131
|
+
resources
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Tells whether a folder entry may be a sub-feature: a folder, not a kind folder, not a dot folder.
|
|
137
|
+
*
|
|
138
|
+
* @param entry - An entry of an owner's folder.
|
|
139
|
+
* @returns True when the entry is worth a look.
|
|
140
|
+
*/
|
|
141
|
+
function isCandidate(entry) {
|
|
142
|
+
return entry.isDirectory() && !KIND_FOLDER.test(entry.name) && !entry.name.startsWith(".");
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Lists a folder; a folder that is missing, a file or unreadable counts as empty.
|
|
146
|
+
*
|
|
147
|
+
* @param folder - The folder on disk.
|
|
148
|
+
* @returns Its entries.
|
|
149
|
+
*/
|
|
150
|
+
function list(folder) {
|
|
151
|
+
try {
|
|
152
|
+
return readdirSync(folder, { withFileTypes: true });
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Sorts folder entries by name, with the comparator the asset scanner sorts features with.
|
|
159
|
+
*
|
|
160
|
+
* @param entries - The entries.
|
|
161
|
+
* @returns A sorted copy.
|
|
162
|
+
*/
|
|
163
|
+
function sorted(entries) {
|
|
164
|
+
return entries.toSorted((left, right) => left.name.localeCompare(right.name));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The door of a folder: `index.ts`, else `index.tsx`.
|
|
168
|
+
*
|
|
169
|
+
* @param entries - The entries of the folder.
|
|
170
|
+
* @returns The door's file name; `undefined` without one.
|
|
171
|
+
*/
|
|
172
|
+
function doorOf(entries) {
|
|
173
|
+
return DOORS.find((door) => entries.some((entry) => entry.isFile() && entry.name === door));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* What a folder brings of its own.
|
|
177
|
+
*
|
|
178
|
+
* @param entries - The entries of the folder.
|
|
179
|
+
* @returns Whether it has `assets/` or `assets.ts`, and whether it has `strings/`.
|
|
180
|
+
*/
|
|
181
|
+
function resourcesOf(entries) {
|
|
182
|
+
const has = (name, folder) => entries.some((entry) => entry.name === name && (folder ? entry.isDirectory() : entry.isFile()));
|
|
183
|
+
return {
|
|
184
|
+
assets: has("assets", true) || has("assets.ts", false),
|
|
185
|
+
strings: has("strings", true)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* The folders an owner's door imports and lists in `features: [...]`. A door that cannot be read lists nothing.
|
|
190
|
+
*
|
|
191
|
+
* @param folder - The owner's folder on disk.
|
|
192
|
+
* @param entries - The entries of that folder.
|
|
193
|
+
* @returns The listed folder names.
|
|
194
|
+
*/
|
|
195
|
+
function listedIn(folder, entries) {
|
|
196
|
+
const door = doorOf(entries);
|
|
197
|
+
if (door === void 0) return [];
|
|
198
|
+
try {
|
|
199
|
+
return listedFolders(readFileSync(path.join(folder, door), "utf8"));
|
|
200
|
+
} catch {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The folders a door imports from `./<folder>` (not `import type`) and names in a `features: [...]` array, comments
|
|
206
|
+
* removed first. A text scan, not a parse.
|
|
207
|
+
*
|
|
208
|
+
* @param doorText - The text of the door.
|
|
209
|
+
* @returns The folder names, in import order.
|
|
210
|
+
* @example listedFolders('import { kitFeature } from "./kit";\nexport const f = defineFeature("a", { features: [kitFeature] });'); // ["kit"]
|
|
211
|
+
*/
|
|
212
|
+
function listedFolders(doorText) {
|
|
213
|
+
const text = doorText.replaceAll(COMMENT, "");
|
|
214
|
+
const listed = /* @__PURE__ */ new Set();
|
|
215
|
+
for (const [, items = ""] of text.matchAll(LISTING)) for (const [identifier] of items.matchAll(IDENTIFIER)) listed.add(identifier);
|
|
216
|
+
const folders = /* @__PURE__ */ new Set();
|
|
217
|
+
for (const [, head = "", source = ""] of text.matchAll(IMPORT)) {
|
|
218
|
+
const folder = FOLDER_SOURCE.exec(source)?.[1];
|
|
219
|
+
const clause = head.trim().replace(/from$/, "");
|
|
220
|
+
if (folder === void 0 || /^type\s/.test(clause)) continue;
|
|
221
|
+
if (localNames(clause).some((name) => listed.has(name))) folders.add(folder);
|
|
222
|
+
}
|
|
223
|
+
return [...folders];
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The local names an import clause binds at runtime: the default import, the namespace import and each named
|
|
227
|
+
* specifier that is not `type`-only (`a as b` gives `b`).
|
|
228
|
+
*
|
|
229
|
+
* @param clause - The text between `import` and `from`.
|
|
230
|
+
* @returns The local names.
|
|
231
|
+
* @example localNames("main, { a as b, type c, d }"); // ["b", "d", "main"]
|
|
232
|
+
*/
|
|
233
|
+
function localNames(clause) {
|
|
234
|
+
const open = clause.indexOf("{");
|
|
235
|
+
const close = clause.indexOf("}");
|
|
236
|
+
const named = open === -1 ? [] : clause.slice(open + 1, close).split(",");
|
|
237
|
+
const outside = open === -1 ? clause : clause.slice(0, open) + clause.slice(close + 1);
|
|
238
|
+
const names = [];
|
|
239
|
+
for (const part of [...named, ...outside.split(",")]) {
|
|
240
|
+
const words = part.trim().split(/\s+/);
|
|
241
|
+
if (words[0] === "type" && words.length > 1) continue;
|
|
242
|
+
const name = words.at(-1);
|
|
243
|
+
if (name) names.push(name);
|
|
244
|
+
}
|
|
245
|
+
return names;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Refuses a feature name used by two folders, before anything is returned. The first folder is the earlier one in
|
|
249
|
+
* walk order.
|
|
250
|
+
*
|
|
251
|
+
* @param found - The owners (and units), in walk order.
|
|
252
|
+
* @throws {Error} For the first name met twice; the message names both folders and a free name.
|
|
253
|
+
*/
|
|
254
|
+
function checkNames(found) {
|
|
255
|
+
const seen = /* @__PURE__ */ new Map();
|
|
256
|
+
for (const owner of found) {
|
|
257
|
+
const first = seen.get(owner.name);
|
|
258
|
+
if (first !== void 0) {
|
|
259
|
+
const parent = owner.parent ?? first.parent;
|
|
260
|
+
throw new Error(`[game] features: the feature name "${owner.name}" is taken by two folders: ${first.dir} and ${owner.dir}.\n A feature is named like its folder, once in the game. Name a shared sub-feature after its parent: ${parent}-${owner.name}.`);
|
|
261
|
+
}
|
|
262
|
+
seen.set(owner.name, owner);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
export { findFeatureUnits as n, ownerOf as r, findFeatureOwners as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as Api, Cr as RngState, Gn as RouteStep, Hn as FlowState, Un as JournalEntry, bn as Api$1, er as Answer, ur as Json } from "./types-BGcda5Le.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/plugins/flow/headless.d.ts
|
|
4
4
|
/**
|
package/dist/hot.d.mts
CHANGED
|
@@ -16,7 +16,8 @@ type HotOptions = {
|
|
|
16
16
|
* The files that get the footer. Default: `.tsx` files, `styles.ts`, `view.ts`,
|
|
17
17
|
* `animations.ts`, `effects.ts`, any `.ts` directly in a `styles/`, `motion/`, `effects/` or
|
|
18
18
|
* `views/` folder, and in `world/projections/` or `world/layout/`,
|
|
19
|
-
* `generated/strings.<locale>.ts
|
|
19
|
+
* `generated/strings.<locale>.ts` and `generated/strings.<feature>.<locale>.ts`, and the stamp
|
|
20
|
+
* module `.moku/assets-stamp.ts`. Bun runs it as
|
|
20
21
|
* the load filter on the absolute path, so it should not anchor at the start.
|
|
21
22
|
*/
|
|
22
23
|
include?: RegExp;
|
|
@@ -25,7 +26,8 @@ type HotOptions = {
|
|
|
25
26
|
* `node_modules/`, `web/`, `generated/`, `__tests__/` or `tests/`, and `.test`/`.spec` files.
|
|
26
27
|
* Tested on the path relative to the game root with a leading `/` and `/` separators, also on
|
|
27
28
|
* Windows: `/features/home/view.tsx`. A folder above the game root never excludes a file. A
|
|
28
|
-
* `generated/strings.<locale>.ts`
|
|
29
|
+
* `generated/strings.<locale>.ts` and a `generated/strings.<feature>.<locale>.ts` file are never
|
|
30
|
+
* excluded: the generated strings swap.
|
|
29
31
|
*/
|
|
30
32
|
exclude?: RegExp;
|
|
31
33
|
};
|
package/dist/hot.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { readFile } from "node:fs/promises";
|
|
|
10
10
|
* the keys watch names. A view module is a `.tsx` file, a `styles.ts`, a `view.ts`, an
|
|
11
11
|
* `animations.ts`, an `effects.ts`, any `.ts` directly in a `styles/`, `motion/`, `effects/` or
|
|
12
12
|
* `views/` folder, any `.ts` directly in `world/projections/` or `world/layout/`, or a generated
|
|
13
|
-
* `generated/strings.<locale>.ts`. The stamp module `.moku/assets-stamp.ts` gets the footer too:
|
|
13
|
+
* `generated/strings.<locale>.ts` or `generated/strings.<feature>.<locale>.ts`. The stamp module `.moku/assets-stamp.ts` gets the footer too:
|
|
14
14
|
* its new exports say which asset files changed. A logic module never gets the footer
|
|
15
15
|
* (`world/components/` and `world/systems/` included: they are registered at start, and
|
|
16
16
|
* `.moku/main.ts` too), so its save reaches the root and the page reloads and restores its state. `moku-game dev` lists the
|
|
@@ -21,9 +21,12 @@ import { readFile } from "node:fs/promises";
|
|
|
21
21
|
* The default modules that swap: the view files by name or by kind folder, and the stamp module.
|
|
22
22
|
* Three literals joined, so each stays readable.
|
|
23
23
|
*/
|
|
24
|
-
const DEFAULT_INCLUDE = new RegExp(`(${/\.tsx|\/styles\.ts|\/view\.ts|\/animations\.ts|\/effects\.ts|\/generated\/strings\.[\w-]+\.ts/.source}|${/\/(?:styles|motion|effects|views)\/[^/]+\.ts|\/world\/(?:projections|layout)\/[^/]+\.ts/.source}|${/\/\.moku\/assets-stamp\.ts/.source})$`);
|
|
25
|
-
/**
|
|
26
|
-
|
|
24
|
+
const DEFAULT_INCLUDE = new RegExp(`(${/\.tsx|\/styles\.ts|\/view\.ts|\/animations\.ts|\/effects\.ts|\/generated\/strings\.(?:[\w-]+\.)?[\w-]+\.ts/.source}|${/\/(?:styles|motion|effects|views)\/[^/]+\.ts|\/world\/(?:projections|layout)\/[^/]+\.ts/.source}|${/\/\.moku\/assets-stamp\.ts/.source})$`);
|
|
25
|
+
/**
|
|
26
|
+
* The generated strings of one locale, whole-game or of one sub-feature: the files under
|
|
27
|
+
* `generated/` that swap.
|
|
28
|
+
*/
|
|
29
|
+
const STRINGS = /\/generated\/strings\.(?:[\w-]+\.)?[\w-]+\.ts$/;
|
|
27
30
|
/** The default folders and test files that never hot swap. The outer group only scopes the `$`. */
|
|
28
31
|
const DEFAULT_EXCLUDE = /(\/(node_modules|web|generated|__tests__|tests)\/|\.(test|spec)\.tsx?$)/;
|
|
29
32
|
/**
|