@adobe/ecs 0.2.1 → 0.2.4
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 +2 -2
- package/dist/implementation/compiler/body-access.d.ts +18 -1
- package/dist/implementation/compiler/body-access.js +104 -15
- package/dist/implementation/compiler/body-access.js.map +1 -1
- package/dist/implementation/compiler/describe.d.ts +1 -1
- package/dist/implementation/compiler/describe.js +3 -3
- package/dist/implementation/compiler/describe.js.map +1 -1
- package/dist/implementation/compiler/estree.d.ts +5 -2
- package/dist/implementation/compiler/estree.js +8 -5
- package/dist/implementation/compiler/estree.js.map +1 -1
- package/dist/implementation/compiler/inferred.js +4 -2
- package/dist/implementation/compiler/inferred.js.map +1 -1
- package/dist/implementation/compiler/signature.js +1 -1
- package/dist/implementation/compiler/transform.js +6 -5
- package/dist/implementation/compiler/transform.js.map +1 -1
- package/dist/implementation/world/activate.js +14 -2
- package/dist/implementation/world/activate.js.map +1 -1
- package/dist/implementation/world/buffer.d.ts +7 -0
- package/dist/implementation/world/buffer.js +7 -0
- package/dist/implementation/world/buffer.js.map +1 -1
- package/dist/implementation/world/cascade.d.ts +10 -3
- package/dist/implementation/world/cascade.js +48 -23
- package/dist/implementation/world/cascade.js.map +1 -1
- package/dist/implementation/world/commands.js +86 -2
- package/dist/implementation/world/commands.js.map +1 -1
- package/dist/implementation/world/create.js +53 -2
- package/dist/implementation/world/create.js.map +1 -1
- package/dist/implementation/world/entities.d.ts +2 -0
- package/dist/implementation/world/entities.js +6 -0
- package/dist/implementation/world/entities.js.map +1 -1
- package/dist/implementation/world/execute.d.ts +4 -4
- package/dist/implementation/world/execute.js +132 -83
- package/dist/implementation/world/execute.js.map +1 -1
- package/dist/implementation/world/finalizers.d.ts +2 -0
- package/dist/implementation/world/finalizers.js +24 -3
- package/dist/implementation/world/finalizers.js.map +1 -1
- package/dist/implementation/world/join.js +22 -4
- package/dist/implementation/world/join.js.map +1 -1
- package/dist/implementation/world/register.js +2 -2
- package/dist/implementation/world/resource-changes.d.ts +18 -0
- package/dist/implementation/world/resource-changes.js +66 -0
- package/dist/implementation/world/resource-changes.js.map +1 -0
- package/dist/implementation/world/rows.d.ts +1 -1
- package/dist/implementation/world/rows.js +23 -13
- package/dist/implementation/world/rows.js.map +1 -1
- package/dist/implementation/world/run-changes.d.ts +38 -0
- package/dist/implementation/world/run-changes.js +138 -0
- package/dist/implementation/world/run-changes.js.map +1 -0
- package/dist/implementation/world/runner.js +19 -15
- package/dist/implementation/world/runner.js.map +1 -1
- package/dist/implementation/world/sharing.js +1 -1
- package/dist/implementation/world/staging.d.ts +4 -0
- package/dist/implementation/world/staging.js +15 -3
- package/dist/implementation/world/staging.js.map +1 -1
- package/dist/implementation/world/state.d.ts +13 -0
- package/dist/implementation/world/state.js +13 -1
- package/dist/implementation/world/state.js.map +1 -1
- package/dist/implementation/world/synchronize.js +72 -22
- package/dist/implementation/world/synchronize.js.map +1 -1
- package/dist/implementation/world/tables-read.d.ts +9 -0
- package/dist/implementation/world/tables-read.js +72 -0
- package/dist/implementation/world/tables-read.js.map +1 -0
- package/dist/implementation/world/tables.d.ts +10 -0
- package/dist/implementation/world/tables.js +401 -0
- package/dist/implementation/world/tables.js.map +1 -0
- package/dist/implementation/world/thread-observer.js +1 -1
- package/dist/implementation/world/thread-observer.js.map +1 -1
- package/dist/implementation/world/thread-systems.js +11 -6
- package/dist/implementation/world/thread-systems.js.map +1 -1
- package/dist/implementation/world/up.js +7 -1
- package/dist/implementation/world/up.js.map +1 -1
- package/dist/implementation/world/where.d.ts +8 -0
- package/dist/implementation/world/where.js +40 -11
- package/dist/implementation/world/where.js.map +1 -1
- package/dist/index.d.ts +8 -28
- package/dist/index.js +4 -9
- package/dist/index.js.map +1 -1
- package/dist/interface/component/declarations.d.ts +4 -0
- package/dist/interface/component/declarations.js +8 -0
- package/dist/interface/component/declarations.js.map +1 -0
- package/dist/interface/component/declared.d.ts +12 -0
- package/dist/interface/component/declared.js +2 -0
- package/dist/interface/component/declared.js.map +1 -0
- package/dist/interface/component/index.d.ts +2 -0
- package/dist/interface/component/index.js +1 -1
- package/dist/interface/component/index.js.map +1 -1
- package/dist/interface/finalizer/body.d.ts +18 -3
- package/dist/interface/finalizer/create.d.ts +7 -5
- package/dist/interface/finalizer/create.js +8 -5
- package/dist/interface/finalizer/create.js.map +1 -1
- package/dist/interface/finalizer/declaration.d.ts +4 -2
- package/dist/interface/indexes/declaration-of.d.ts +17 -0
- package/dist/interface/indexes/declaration-of.js +20 -0
- package/dist/interface/indexes/declaration-of.js.map +1 -0
- package/dist/interface/indexes/index.d.ts +1 -0
- package/dist/interface/indexes/index.js +1 -0
- package/dist/interface/indexes/index.js.map +1 -1
- package/dist/interface/registry/names.d.ts +2 -0
- package/dist/interface/registry/names.js +9 -0
- package/dist/interface/registry/names.js.map +1 -1
- package/dist/interface/registry/schedule.d.ts +31 -4
- package/dist/interface/registry/schedule.js +185 -24
- package/dist/interface/registry/schedule.js.map +1 -1
- package/dist/interface/resource/declarations.d.ts +4 -0
- package/dist/interface/resource/declarations.js +8 -0
- package/dist/interface/resource/declarations.js.map +1 -0
- package/dist/interface/resource/index.d.ts +2 -0
- package/dist/interface/resource/index.js +1 -1
- package/dist/interface/resource/index.js.map +1 -1
- package/dist/interface/system/access.d.ts +15 -0
- package/dist/interface/system/body.d.ts +11 -6
- package/dist/interface/system/check.d.ts +8 -1
- package/dist/interface/system/check.js +42 -12
- package/dist/interface/system/check.js.map +1 -1
- package/dist/interface/system/commands.d.ts +37 -0
- package/dist/interface/system/create-resolved.js +1 -1
- package/dist/interface/system/create-resolved.js.map +1 -1
- package/dist/interface/system/create.d.ts +31 -15
- package/dist/interface/system/create.js +8 -7
- package/dist/interface/system/create.js.map +1 -1
- package/dist/interface/system/declaration.d.ts +9 -2
- package/dist/interface/system/describe.d.ts +120 -0
- package/dist/interface/system/describe.js +116 -0
- package/dist/interface/system/describe.js.map +1 -0
- package/dist/interface/system/index.d.ts +1 -0
- package/dist/interface/system/index.js +1 -0
- package/dist/interface/system/index.js.map +1 -1
- package/dist/interface/system/leaf.d.ts +6 -0
- package/dist/interface/system/render.js +1 -0
- package/dist/interface/system/render.js.map +1 -1
- package/dist/interface/system/resolve.d.ts +5 -1
- package/dist/interface/system/resolve.js +19 -1
- package/dist/interface/system/resolve.js.map +1 -1
- package/dist/interface/system/shared-only.d.ts +7 -0
- package/dist/interface/system/shared-only.js +2 -0
- package/dist/interface/system/shared-only.js.map +1 -0
- package/dist/interface/system/tables.d.ts +28 -0
- package/dist/interface/system/tables.js +2 -0
- package/dist/interface/system/tables.js.map +1 -0
- package/dist/interface/world/index.d.ts +1 -1
- package/dist/interface/world/table/index.d.ts +27 -0
- package/dist/interface/world/table/index.js +3 -0
- package/dist/interface/world/table/index.js.map +1 -0
- package/dist/interface/world/table/table.d.ts +11 -0
- package/dist/interface/world/table/table.js +2 -0
- package/dist/interface/world/table/table.js.map +1 -0
- package/dist/interface/world/world.d.ts +25 -10
- package/dist/world.d.ts +27 -0
- package/dist/world.js +27 -0
- package/dist/world.js.map +1 -0
- package/package.json +11 -2
- package/src/exports.test.ts +1 -1
- package/src/guide/00-keys.ts +1 -1
- package/src/guide/01-resources.md +1 -1
- package/src/guide/01-resources.ts +1 -1
- package/src/guide/02-entities.ts +2 -2
- package/src/guide/03-systems.md +2 -2
- package/src/guide/03-systems.out +1 -1
- package/src/guide/03-systems.ts +3 -3
- package/src/guide/04-ticks.md +1 -1
- package/src/guide/04-ticks.ts +3 -3
- package/src/guide/05-scheduling.ts +1 -1
- package/src/guide/06-sync-points.md +18 -7
- package/src/guide/06-sync-points.out +1 -2
- package/src/guide/06-sync-points.ts +10 -6
- package/src/guide/07-change-filters.ts +2 -2
- package/src/guide/08-input.ts +1 -1
- package/src/guide/09-rules.ts +1 -1
- package/src/guide/11-traits.ts +3 -3
- package/src/guide/12-lookups.ts +2 -2
- package/src/guide/13-indexes.ts +4 -4
- package/src/guide/14-kernels.ts +1 -1
- package/src/guide/15-reductions.ts +1 -1
- package/src/guide/16-gpu.ts +1 -1
- package/src/guide/17-hierarchies.ts +1 -1
- package/src/guide/18-identity.out +1 -1
- package/src/guide/19-threads.md +4 -2
- package/src/guide/19-threads.ts +2 -2
- package/src/guide/20-shared.ts +3 -3
- package/src/guide/21-dom.md +2 -2
- package/src/guide/21-dom.ts +1 -1
- package/src/guide/22-canvas.md +1 -1
- package/src/guide/22-canvas.ts +1 -1
- package/src/guide/CLAUDE.md +1 -1
- package/src/guide/guide.test.ts +9 -154
- package/src/implementation/compiler/body-access.ts +102 -12
- package/src/implementation/compiler/describe.test-helper.ts +1 -1
- package/src/implementation/compiler/describe.test.ts +1 -1
- package/src/implementation/compiler/describe.ts +3 -3
- package/src/implementation/compiler/estree.ts +9 -6
- package/src/implementation/compiler/hygiene.test.ts +1 -1
- package/src/implementation/compiler/inferred.test.ts +1 -1
- package/src/implementation/compiler/inferred.ts +4 -2
- package/src/implementation/compiler/plugin.test.ts +2 -2
- package/src/implementation/compiler/signature.ts +1 -1
- package/src/implementation/compiler/transform.test.ts +43 -23
- package/src/implementation/compiler/transform.ts +6 -4
- package/src/implementation/world/activate.ts +11 -2
- package/src/implementation/world/batches.test.ts +3 -3
- package/src/implementation/world/buffer.ts +7 -0
- package/src/implementation/world/cascade.ts +46 -22
- package/src/implementation/world/change-blocks.test.ts +1 -1
- package/src/implementation/world/commands.ts +76 -2
- package/src/implementation/world/create.test.ts +8 -8
- package/src/implementation/world/create.ts +57 -2
- package/src/implementation/world/defaults.test.ts +1 -1
- package/src/implementation/world/despawn-where.test.ts +287 -0
- package/src/implementation/world/entities.ts +6 -0
- package/src/implementation/world/execute.ts +125 -78
- package/src/implementation/world/finalizers.test.ts +1 -1
- package/src/implementation/world/finalizers.ts +27 -4
- package/src/implementation/world/ids.test.ts +1 -1
- package/src/implementation/world/index-changed.test.ts +2 -2
- package/src/implementation/world/index-joined.test.ts +5 -5
- package/src/implementation/world/index-order.test.ts +1 -1
- package/src/implementation/world/indexes.test.ts +2 -1
- package/src/implementation/world/join.test.ts +23 -4
- package/src/implementation/world/join.ts +26 -4
- package/src/implementation/world/joined-observer.test.ts +1 -1
- package/src/implementation/world/joining-worker.fixture.ts +1 -1
- package/src/implementation/world/joining.fixture.ts +1 -1
- package/src/implementation/world/joining.test-helper.ts +1 -1
- package/src/implementation/world/kernel-spawns.test.ts +1 -1
- package/src/implementation/world/names.test.ts +1 -2
- package/src/implementation/world/observe-factories.test.ts +2 -2
- package/src/implementation/world/observe-ticks-cases.test.ts +1 -1
- package/src/implementation/world/observe.test-helper.ts +1 -1
- package/src/implementation/world/observer-contained-worker.fixture.ts +1 -1
- package/src/implementation/world/observer-contained.test-helper.ts +1 -1
- package/src/implementation/world/observer-contained.test.ts +2 -2
- package/src/implementation/world/observer-joined.test-helper.ts +4 -4
- package/src/implementation/world/observer-joined.test.ts +23 -15
- package/src/implementation/world/observer.browser.test.ts +2 -2
- package/src/implementation/world/observer.test.ts +8 -8
- package/src/implementation/world/optional-workers.fixture.ts +1 -1
- package/src/implementation/world/optional.test.ts +7 -7
- package/src/implementation/world/perf.md +3 -1
- package/src/implementation/world/reclaim.test.ts +3 -3
- package/src/implementation/world/register.ts +2 -2
- package/src/implementation/world/remote-objects.test-helper.ts +1 -1
- package/src/implementation/world/resource-changes.test.ts +61 -0
- package/src/implementation/world/resource-changes.ts +67 -0
- package/src/implementation/world/rows.ts +24 -13
- package/src/implementation/world/rules.test.ts +37 -0
- package/src/implementation/world/run-changes.test.ts +88 -0
- package/src/implementation/world/run-changes.ts +160 -0
- package/src/implementation/world/run-results.test.ts +10 -10
- package/src/implementation/world/runner.ts +20 -16
- package/src/implementation/world/shared-gpu.browser.test.ts +2 -2
- package/src/implementation/world/shared-kernels.test.ts +2 -2
- package/src/implementation/world/shared-workers.fixture.ts +2 -2
- package/src/implementation/world/shared.test.ts +10 -10
- package/src/implementation/world/sharing.ts +1 -1
- package/src/implementation/world/staging.ts +16 -3
- package/src/implementation/world/state.ts +19 -0
- package/src/implementation/world/sync-points.test.ts +135 -0
- package/src/implementation/world/synchronize.ts +65 -18
- package/src/implementation/world/tables-read.ts +70 -0
- package/src/implementation/world/tables.test.ts +369 -0
- package/src/implementation/world/tables.ts +368 -0
- package/src/implementation/world/tails.test.ts +1 -1
- package/src/implementation/world/target.test.ts +2 -2
- package/src/implementation/world/thread-observer.ts +1 -1
- package/src/implementation/world/thread-systems.test-helper.ts +3 -3
- package/src/implementation/world/thread-systems.ts +11 -6
- package/src/implementation/world/up.test.ts +13 -1
- package/src/implementation/world/up.ts +6 -1
- package/src/implementation/world/where.test.ts +4 -4
- package/src/implementation/world/where.ts +38 -10
- package/src/implementation/world/workers.fixture.ts +2 -2
- package/src/index.ts +4 -29
- package/src/interface/component/declarations.ts +11 -0
- package/src/interface/component/declared.ts +9 -0
- package/src/interface/component/index.ts +2 -0
- package/src/interface/finalizer/body.ts +13 -3
- package/src/interface/finalizer/create.test.ts +3 -1
- package/src/interface/finalizer/create.ts +12 -7
- package/src/interface/finalizer/declaration.ts +4 -2
- package/src/interface/index.type-test.ts +2 -2
- package/src/interface/indexes/create.test.ts +10 -0
- package/src/interface/indexes/declaration-of.ts +34 -0
- package/src/interface/indexes/index.ts +1 -0
- package/src/interface/indexes/index.type-test.ts +1 -1
- package/src/interface/registry/names.ts +8 -0
- package/src/interface/registry/schedule.ts +200 -27
- package/src/interface/resource/declarations.ts +11 -0
- package/src/interface/resource/index.ts +2 -0
- package/src/interface/system/access.ts +16 -0
- package/src/interface/system/body.ts +7 -5
- package/src/interface/system/check.ts +37 -10
- package/src/interface/system/commands.ts +33 -0
- package/src/interface/system/commands.type-test.ts +31 -0
- package/src/interface/system/create-resolved.ts +1 -1
- package/src/interface/system/create.test.ts +21 -13
- package/src/interface/system/create.ts +24 -15
- package/src/interface/system/declaration.ts +9 -2
- package/src/interface/system/describe.test.ts +79 -0
- package/src/interface/system/describe.ts +122 -0
- package/src/interface/system/index.ts +1 -0
- package/src/interface/system/leaf.ts +6 -0
- package/src/interface/system/lists.type-test.ts +1 -1
- package/src/interface/system/optional.type-test.ts +1 -1
- package/src/interface/system/render.ts +1 -0
- package/src/interface/system/resolve.ts +25 -2
- package/src/interface/system/shared-only.ts +5 -0
- package/src/interface/system/shared.type-test.ts +1 -1
- package/src/interface/system/system.type-test.ts +26 -20
- package/src/interface/system/tables.ts +27 -0
- package/src/interface/system/up.type-test.ts +3 -3
- package/src/interface/world/index.ts +2 -2
- package/src/interface/world/run.type-test.ts +14 -4
- package/src/interface/world/table/index.ts +20 -0
- package/src/interface/world/table/table.ts +12 -0
- package/src/interface/world/world.ts +23 -10
- package/src/observe/entity.ts +2 -2
- package/src/observe/resource.ts +2 -2
- package/src/observe/select.ts +4 -4
- package/src/observe/world-state.ts +3 -3
- package/src/perftest/benchmarks.ts +19 -1
- package/src/perftest/indexes.ts +3 -3
- package/src/perftest/loop.ts +1 -1
- package/src/perftest/observer.ts +4 -4
- package/src/perftest/reads.ts +2 -2
- package/src/perftest/remote.ts +5 -5
- package/src/perftest/strings.ts +1 -1
- package/src/perftest/structural.ts +20 -0
- package/src/perftest/suite.ts +1 -1
- package/src/perftest/tables.ts +107 -0
- package/src/world.test.ts +2 -2
- package/src/world.ts +32 -0
package/src/guide/08-input.ts
CHANGED
|
@@ -30,7 +30,7 @@ const heal = System.create({
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
const healths: number[] = [];
|
|
33
|
-
const read = System.create({
|
|
33
|
+
const read = System.create({ readonly: true, components: { with: [health] } }, row => {
|
|
34
34
|
healths.push(row[health]);
|
|
35
35
|
});
|
|
36
36
|
|
package/src/guide/09-rules.ts
CHANGED
|
@@ -31,7 +31,7 @@ const hide = System.create({ components: { with: [sprite] } }, (row, { commands
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
const drawing: string[] = [];
|
|
34
|
-
const read = System.create({
|
|
34
|
+
const read = System.create({ readonly: true, components: { with: [layer, drawn], optional: [mesh, sprite] } }, row => {
|
|
35
35
|
drawing.push(`${row[mesh] === undefined ? `sprite ${row[sprite]}` : `mesh ${row[mesh]}`} on layer ${row[layer]}`);
|
|
36
36
|
});
|
|
37
37
|
/** Logs what's drawn, in order. */
|
package/src/guide/11-traits.ts
CHANGED
|
@@ -33,9 +33,9 @@ const destroy = System.create({ components: { with: [ship] } }, (row, { commands
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
const counts = { outlined: 0, targeting: 0, entities: 0 };
|
|
36
|
-
const countOutlined = System.create({
|
|
37
|
-
const countTargeting = System.create({
|
|
38
|
-
const countAll = System.create({
|
|
36
|
+
const countOutlined = System.create({ readonly: true, components: { with: [outline] } }, () => { counts.outlined += 1; });
|
|
37
|
+
const countTargeting = System.create({ readonly: true, components: { with: [target] } }, () => { counts.targeting += 1; });
|
|
38
|
+
const countAll = System.create({ readonly: true, components: {} }, () => { counts.entities += 1; });
|
|
39
39
|
const count = System.create([countOutlined, countTargeting, countAll]);
|
|
40
40
|
|
|
41
41
|
export const main = async (): Promise<void> => {
|
package/src/guide/12-lookups.ts
CHANGED
|
@@ -25,7 +25,7 @@ const track = System.create({
|
|
|
25
25
|
|
|
26
26
|
const refreshed: boolean[] = [];
|
|
27
27
|
const watch = System.create({
|
|
28
|
-
|
|
28
|
+
readonly: true,
|
|
29
29
|
components: { with: [target] },
|
|
30
30
|
lookup: { enemy: { with: [health], changed: [health] } },
|
|
31
31
|
}, (row, { lookup }) => {
|
|
@@ -34,7 +34,7 @@ const watch = System.create({
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
const aims: number[] = [];
|
|
37
|
-
const readAims = System.create({
|
|
37
|
+
const readAims = System.create({ readonly: true, components: { with: [aim] } }, row => {
|
|
38
38
|
aims.push(row[aim]);
|
|
39
39
|
});
|
|
40
40
|
|
package/src/guide/13-indexes.ts
CHANGED
|
@@ -26,14 +26,14 @@ const count = System.create({ components: { with: [cell, crowded] }, lookup: { a
|
|
|
26
26
|
|
|
27
27
|
const byScore = Index.create({ key: [score], sorted: true, components: { with: [player] } });
|
|
28
28
|
|
|
29
|
-
const leaders = System.create({
|
|
29
|
+
const leaders = System.create({ readonly: true, lookup: { scores: { index: byScore } } }, ({ lookup }) => {
|
|
30
30
|
const winners: string[] = [];
|
|
31
31
|
const high = lookup.scores({ ">=": 90 });
|
|
32
32
|
for (let i = 0; i < high.length; i++) winners.push(high.at(i)[player]);
|
|
33
33
|
return winners;
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const list = System.create({
|
|
36
|
+
const list = System.create({ readonly: true, components: { with: [player, score] }, order: byScore }, row => {
|
|
37
37
|
console.log(row[player], row[score]);
|
|
38
38
|
});
|
|
39
39
|
|
|
@@ -42,12 +42,12 @@ const find = System.create({ lookup: { byId: { index: byServerId } } }, ({ looku
|
|
|
42
42
|
lookup.byId(input.id)?.[player] ?? null);
|
|
43
43
|
|
|
44
44
|
const players = Index.create({ key: [], components: { with: [player] } });
|
|
45
|
-
const countPlayers = System.create({
|
|
45
|
+
const countPlayers = System.create({ readonly: true, lookup: { players: { index: players, changed: true } } }, ({ lookup }) => {
|
|
46
46
|
console.log("players", lookup.players().length);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
const crowds: number[] = [];
|
|
50
|
-
const readCrowds = System.create({
|
|
50
|
+
const readCrowds = System.create({ readonly: true, components: { with: [crowded] } }, row => {
|
|
51
51
|
crowds.push(row[crowded]);
|
|
52
52
|
});
|
|
53
53
|
|
package/src/guide/14-kernels.ts
CHANGED
|
@@ -29,7 +29,7 @@ const slow = System.create({ kernel: false, components: { with: [velocity] } },
|
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
const moved: string[] = [];
|
|
32
|
-
const read = System.create({
|
|
32
|
+
const read = System.create({ readonly: true, components: { with: [position, velocity] } }, row => {
|
|
33
33
|
moved.push(`at ${row[position][0]}, moving at ${row[velocity][0]}`);
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -23,7 +23,7 @@ const weigh = System.create({ components: { with: [mass] } }, (row, { reduce })
|
|
|
23
23
|
reduce[count](1);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
const report = System.create({
|
|
26
|
+
const report = System.create({ readonly: true }, ({ resources }) =>
|
|
27
27
|
`${resources[count]} weigh ${resources[total]}, at most ${resources[heaviest]}`);
|
|
28
28
|
|
|
29
29
|
const spawn = System.create(({ commands }) => {
|
package/src/guide/16-gpu.ts
CHANGED
|
@@ -32,7 +32,7 @@ const draw = System.render({ shader: { accessors: { dotPosition: position, dotSi
|
|
|
32
32
|
});
|
|
33
33
|
const shaderCode = Gpu.wgsl(draw);
|
|
34
34
|
|
|
35
|
-
const read = System.create({
|
|
35
|
+
const read = System.create({ readonly: true, components: { with: [position] } }, row => {
|
|
36
36
|
console.log("at", row[position]);
|
|
37
37
|
});
|
|
38
38
|
|
|
@@ -21,7 +21,7 @@ const place = System.create({ components: { with: [offset, placed] }, up: { thro
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
const where: string[] = [];
|
|
24
|
-
const read = System.create({
|
|
24
|
+
const read = System.create({ readonly: true, components: { with: [label, placed] } }, row => {
|
|
25
25
|
where.push(`${row[label]} at ${row[placed]}`);
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Error: System "explode" (@adobe/ecs@0.2.
|
|
1
|
+
Error: System "explode" (@adobe/ecs@0.2.4/src/guide/18-identity.ts#explode) failed: boom
|
package/src/guide/19-threads.md
CHANGED
|
@@ -11,6 +11,8 @@ A *logical thread* is where objects live and the code touching them runs: the pa
|
|
|
11
11
|
`World.join(port, { threads: ["audio"] })`, claiming the threads it fills. Usually the other end of the channel goes
|
|
12
12
|
to a worker; [here both ends](19-threads.ts#L44-L54) are on one thread.
|
|
13
13
|
|
|
14
|
-
- `share` resolves once the thread joined, with the
|
|
15
|
-
anything else. Those
|
|
14
|
+
- `share` resolves once the thread joined, with the readonly systems it added as `join` resolved, before awaiting
|
|
15
|
+
anything else. Those readonly systems run there after the world's sync points: `listen` hears what `mix` wrote.
|
|
16
|
+
- A joined thread adds only [readonly systems](03-systems.md), which run on it; a system that writes is added on the
|
|
17
|
+
world's thread.
|
|
16
18
|
- A joined world runs systems as the world does: [`audio.run`](19-threads.ts#L60-L61) spawns and mixes too.
|
package/src/guide/19-threads.ts
CHANGED
|
@@ -22,7 +22,7 @@ const mix = System.create({ components: { with: [volume] } }, (row, { resources
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
let heard = 0;
|
|
25
|
-
const listen = System.create({
|
|
25
|
+
const listen = System.create({ readonly: true }, ({ resources }) => {
|
|
26
26
|
heard = resources[levels].size;
|
|
27
27
|
});
|
|
28
28
|
|
|
@@ -31,7 +31,7 @@ const spawn = System.create(({ commands }) => {
|
|
|
31
31
|
commands.spawn([volume])({ [volume]: 0.3 });
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
const countVoices = System.create({
|
|
34
|
+
const countVoices = System.create({ readonly: true }, ({ resources }) => resources[levels].size);
|
|
35
35
|
|
|
36
36
|
/** Waits a turn of the event loop at a time until `done`, for two seconds at most. */
|
|
37
37
|
const until = async (done: () => boolean): Promise<void> => {
|
package/src/guide/20-shared.ts
CHANGED
|
@@ -56,7 +56,7 @@ let drawn = 0;
|
|
|
56
56
|
let left = Infinity;
|
|
57
57
|
let right = -Infinity;
|
|
58
58
|
const draw = System.create({
|
|
59
|
-
|
|
59
|
+
readonly: true,
|
|
60
60
|
components: { with: [position], where: { [cell]: (at, { resources }) => resources[camera]?.sees(at) === true } },
|
|
61
61
|
}, row => {
|
|
62
62
|
drawn += 1;
|
|
@@ -66,7 +66,7 @@ const draw = System.create({
|
|
|
66
66
|
|
|
67
67
|
let refreshed = 0;
|
|
68
68
|
const refresh = System.create({
|
|
69
|
-
|
|
69
|
+
readonly: true,
|
|
70
70
|
components: { with: [position], changed: [position], where: { [cell]: (at, { resources }) => resources[camera]?.sees(at) === true } },
|
|
71
71
|
}, () => {
|
|
72
72
|
refreshed += 1;
|
|
@@ -74,7 +74,7 @@ const refresh = System.create({
|
|
|
74
74
|
|
|
75
75
|
// Only chunk [4, 0], which no unit is in until one crosses into it.
|
|
76
76
|
let east = 0;
|
|
77
|
-
const countEast = System.create({
|
|
77
|
+
const countEast = System.create({ readonly: true, components: { with: [position], where: { [cell]: [4, 0] } } }, () => {
|
|
78
78
|
east += 1;
|
|
79
79
|
});
|
|
80
80
|
|
package/src/guide/21-dom.md
CHANGED
|
@@ -13,9 +13,9 @@ same.
|
|
|
13
13
|
Each tick runs one composite:
|
|
14
14
|
|
|
15
15
|
1. [`move`](21-dom.ts#L38-L44) moves every particle and turns it back from the walls.
|
|
16
|
-
2. [`create`](21-dom.ts#L46-L51) gives each particle without a dot an element, with `commands.add`.
|
|
16
|
+
2. [`create`](21-dom.ts#L46-L51) gives each particle without a dot an element, with `commands.add`. Readonly systems can't
|
|
17
17
|
issue commands, so it ticks, and its condition `is: [stage]` waits for a stage.
|
|
18
|
-
3. [`draw`](21-dom.ts#L52-L60),
|
|
18
|
+
3. [`draw`](21-dom.ts#L52-L60), a readonly system, sets each moved dot's `style.translate`, a transform, which the page
|
|
19
19
|
doesn't lay out again. `changed: [position]` skips the dots that didn't move.
|
|
20
20
|
|
|
21
21
|
[A finalizer](21-dom.ts#L61-L63) removes a particle's element when the particle goes, and every element when the
|
package/src/guide/21-dom.ts
CHANGED
|
@@ -51,7 +51,7 @@ const create = System.create({ components: { with: [position], not: [dot] }, res
|
|
|
51
51
|
});
|
|
52
52
|
// Moves each dot whose particle moved, by a transform, which the page doesn't lay out again.
|
|
53
53
|
const draw = System.create({
|
|
54
|
-
|
|
54
|
+
readonly: true,
|
|
55
55
|
components: { with: [position, dot], optional: [traced], changed: [position] },
|
|
56
56
|
}, (row, { resources }) => {
|
|
57
57
|
const [x, y] = row[position];
|
package/src/guide/22-canvas.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The same particles, drawn in immediate mode: each frame, the canvas is cleared and drawn again whole.
|
|
4
4
|
|
|
5
|
-
[`draw`](22-canvas.ts#L52-L80) is one
|
|
5
|
+
[`draw`](22-canvas.ts#L52-L80) is one readonly system without components, so it runs once per tick, not per particle.
|
|
6
6
|
|
|
7
7
|
- `changed: [clock]` runs it after every tick, and `is: [pen]` waits for a 2D context.
|
|
8
8
|
- It reads every particle through [an index without a key](22-canvas.ts#L50-L51), `key: []`, and the traced one
|
package/src/guide/22-canvas.ts
CHANGED
|
@@ -51,7 +51,7 @@ const particles = Index.create({ key: [], components: { with: [position] } });
|
|
|
51
51
|
const tracedOnes = Index.create({ key: [], components: { with: [position, traced] } });
|
|
52
52
|
// Clears the canvas and draws every particle, after each tick.
|
|
53
53
|
const draw = System.create({
|
|
54
|
-
|
|
54
|
+
readonly: true,
|
|
55
55
|
resources: { is: [pen], changed: [clock] },
|
|
56
56
|
lookup: { particles: { index: particles }, traced: { index: tracedOnes } },
|
|
57
57
|
}, ({ resources, lookup }) => {
|
package/src/guide/CLAUDE.md
CHANGED
|
@@ -45,5 +45,5 @@ it in `NN-name.type-test.ts`, under a `// @ts-expect-error` that the package's b
|
|
|
45
45
|
before they're printed.
|
|
46
46
|
- Keys are `Symbol()` with no description: the build's id names each by its binding.
|
|
47
47
|
- Archetypes are types, so their names are PascalCase: `const Particle = [position, velocity] as const`.
|
|
48
|
-
- Use the public API only, as a consumer imports it, not internal modules. Read a world through
|
|
48
|
+
- Use the public API only, as a consumer imports it, not internal modules. Read a world through readonly systems.
|
|
49
49
|
- Lines change as code does: the test of links fails on any that no longer covers whole code, so move them with it.
|
package/src/guide/guide.test.ts
CHANGED
|
@@ -1,80 +1,15 @@
|
|
|
1
1
|
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
-
import {
|
|
3
|
-
import { formatWithOptions } from "node:util";
|
|
4
|
-
import ts from "typescript";
|
|
5
|
-
import { afterAll, expect, it, vi } from "vitest";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Each chapter here is its prose, `NN-name.md`, and a program, which its `main` runs. Run, it prints what the `.out`
|
|
9
|
-
* file beside it says: a line per console call, as node writes its values, on one line each. Ids name the package's
|
|
10
|
-
* version, which is left out of the comparison, so a new version changes no example. The folder is read as the test
|
|
11
|
-
* runs, not through `import.meta.glob`, which vitest's cache of transformed modules would keep as of the test's first
|
|
12
|
-
* run, missing a chapter added since.
|
|
13
|
-
*/
|
|
14
|
-
const folder = new URL(".", import.meta.url);
|
|
15
|
-
const files = readdirSync(folder);
|
|
16
|
-
const read = (file: string): string => readFileSync(new URL(file, folder), "utf8");
|
|
17
|
-
const names = files.filter(file => /^\d+-[\w-]+\.ts$/.test(file) && !file.endsWith(".type-test.ts")).map(file => file.slice(0, -".ts".length)).sort();
|
|
18
|
-
const proseFiles = files.filter(file => /^\d+-[\w-]+\.md$/.test(file)).sort();
|
|
19
|
-
/** Where the mutation tests write each program changed: `.mutants` in the package. */
|
|
20
|
-
const mutants = new URL("../../.mutants/", import.meta.url);
|
|
21
|
-
afterAll(() => rmSync(mutants, { recursive: true, force: true }));
|
|
22
|
-
|
|
23
|
-
const levels = ["log", "info", "warn", "error", "debug"] as const;
|
|
24
|
-
const unversioned = (text: string): string => text.replace(/@adobe\/ecs@[^/\s]+\//g, "@adobe/ecs/");
|
|
25
|
-
const chapterOf = (file: string): number => Number(/^(\d+)-/.exec(file)?.[1]);
|
|
26
|
-
|
|
27
|
-
/** What `main` prints, a line per console call, and how it failed, if it did. */
|
|
28
|
-
const printed = async (main: () => Promise<void>): Promise<string> => {
|
|
29
|
-
const lines: string[] = [];
|
|
30
|
-
const spies = levels.map(level => vi.spyOn(console, level).mockImplementation((...values: unknown[]) => {
|
|
31
|
-
lines.push(formatWithOptions({ breakLength: Infinity, compact: true }, ...values));
|
|
32
|
-
}));
|
|
33
|
-
try {
|
|
34
|
-
await main();
|
|
35
|
-
} catch (error) {
|
|
36
|
-
lines.push(`main failed: ${String(error)}`);
|
|
37
|
-
} finally {
|
|
38
|
-
for (const spy of spies) spy.mockRestore();
|
|
39
|
-
}
|
|
40
|
-
return lines.map(line => `${line}\n`).join("");
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/** What a program prints, run from its file, or how it failed, as a declaration the world rejects fails its import. */
|
|
44
|
-
const run = (file: URL): Promise<string> => printed(async () => {
|
|
45
|
-
const program: unknown = await import(/* @vite-ignore */ file.href);
|
|
46
|
-
const main: unknown = Reflect.get(Object(program), "main");
|
|
47
|
-
if (typeof main !== "function") throw new Error(`${file.pathname} exports no main`);
|
|
48
|
-
await Reflect.apply(main, undefined, []);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
/** Code without its comments, as TypeScript prints it. */
|
|
52
|
-
const withoutComments = (source: string): string =>
|
|
53
|
-
ts.createPrinter({ removeComments: true }).printFile(ts.createSourceFile("program.ts", source, ts.ScriptTarget.ESNext, false));
|
|
54
|
-
|
|
55
|
-
/** Each chapter's code: its files', without comments. */
|
|
56
|
-
const codeOf = (chapter: number): string =>
|
|
57
|
-
files.filter(file => file.endsWith(".ts") && !file.endsWith(".test.ts") && chapterOf(file) === chapter).map(file => withoutComments(read(file))).join("\n");
|
|
58
|
-
|
|
59
|
-
/** What prose shows as code: its inline code and its blocks. */
|
|
60
|
-
const shownIn = (prose: string): readonly string[] => [...prose.matchAll(/```\w*\n([\s\S]*?)```|`([^`\n]+)`/g)].map(([, block, inline]) => block ?? inline ?? "");
|
|
61
|
-
|
|
62
|
-
/** Each link of the prose to lines of a program, which the interactive guide shows in its editor: `NN-name.ts#L4-L9`. */
|
|
63
|
-
const editorLinks = proseFiles.flatMap(prose => [...read(prose).matchAll(/\]\(([^)#\s]*)#L(\d+)(?:-L(\d+))?\)/g)].map(([, file = "", from = "", to]) =>
|
|
64
|
-
({ prose, file, from: Number(from), to: Number(to ?? from) })));
|
|
65
|
-
|
|
66
|
-
/** The chapters the guide's index lists, in order: each its number, title and prose. */
|
|
67
|
-
const listed = [...read("README.md").matchAll(/^(?:- |(\d+)\. )\[([^\]]+)\]\(([^)]+)\)$/gm)].map(([, number = "0", title = "", file = ""]) => ({ number: Number(number), title, file }));
|
|
2
|
+
import { checkChapters } from "ecs-guide-checks";
|
|
68
3
|
|
|
69
4
|
/** What each chapter teaches, which its prose names as code and its program does; 0 is the unnumbered keys chapter's. */
|
|
70
5
|
const teaches: { readonly [chapter: number]: readonly string[] } = {
|
|
71
6
|
0: ["Symbol()", "declare module \"@adobe/ecs\"", "Components", "Resources", "row[score]", "resources[bonus]", "default"],
|
|
72
|
-
1: ["Resources", "default", "World.create", "
|
|
7
|
+
1: ["Resources", "default", "World.create", "readonly: true", "run", "ReadonlyMap", "Entity"],
|
|
73
8
|
2: ["Components", "type: true", "as const", "commands.spawn", "commands.remove", "with: [...Particle]"],
|
|
74
|
-
3: ["System.create", "with", "not", "
|
|
9
|
+
3: ["System.create", "with", "not", "readonly: true", "optional: [velocity]"],
|
|
75
10
|
4: ["clock", "delta", "cadence", "always", "resources: { changed: [elapsed] }", "wake", "reduce[wake]", "world.add", "world.remove"],
|
|
76
11
|
5: ["after", "during", "System.create([heal, hit])", "during: [update]"],
|
|
77
|
-
6: ["commands.spawn", "commands.add", "commands.despawn", "after: [spawn]"],
|
|
12
|
+
6: ["commands.spawn", "commands.add", "commands.despawn", "after: [spawn]", "readonly: true"],
|
|
78
13
|
7: ["resources: { changed: [level] }", "changed: [score]", "resources: { is: [map], not: [paused] }", "resources[map]"],
|
|
79
14
|
8: ["world.run(hit, { amount: 3 })", "target: \"entity\""],
|
|
80
15
|
9: ["Rule.create", "derived: true"],
|
|
@@ -106,10 +41,12 @@ const mutations: { readonly [chapter: number]: readonly (readonly [string, strin
|
|
|
106
41
|
],
|
|
107
42
|
1: [["World.create({ [gravity]: -1.6 })", "World.create()"], ["default: -9.8 ", ""], ["{ default: -Infinity }", "{}"]],
|
|
108
43
|
2: [["commands.remove(row.entity, enemy);", ""], ["{ [position]: [0, 10, 0] }", "{}"]],
|
|
109
|
-
3: [
|
|
44
|
+
3: [
|
|
45
|
+
["not: [frozen]", "not: []"], ["System.create([count, fail])", "System.create([fail])"],
|
|
46
|
+
],
|
|
110
47
|
4: [["world.remove(advance);", ""]],
|
|
111
48
|
5: [["after: [hit] ", ""], ["during: [update] ", ""]],
|
|
112
|
-
6: [["commands.add(hero, health, 5);", ""], ["commands.despawn(commands.spawn([health])({ [health]: 1 }));", "commands.spawn([health])({ [health]: 1 });"], ["watched.add(watch);", ""]],
|
|
49
|
+
6: [["commands.add(hero, health, 5);", ""], ["after: [spawn] ", ""], ["commands.despawn(commands.spawn([health])({ [health]: 1 }));", "commands.spawn([health])({ [health]: 1 });"], ["watched.add(watch);", ""], ["const watch = System.create({ readonly: true, ", "const watch = System.create({ "]],
|
|
113
50
|
7: [["resources: { changed: [level] } ", ""], [", changed: [score]", ""], [", not: [paused]", ""], ["is: [map], ", ""]],
|
|
114
51
|
8: [["target: \"entity\",", ""]],
|
|
115
52
|
9: [["with: [mesh], not: [hidden]", "with: [mesh]"], ["Rule.create({ components: { with: [sprite], not: [hidden] }, derive: [drawn] });", ""], ["Rule.create({ components: { with: [drawn] }, derive: [layer] });", ""]],
|
|
@@ -130,86 +67,4 @@ const mutations: { readonly [chapter: number]: readonly (readonly [string, strin
|
|
|
130
67
|
22: [["context.fill();", ""]],
|
|
131
68
|
};
|
|
132
69
|
|
|
133
|
-
|
|
134
|
-
expect(files.filter(file => file.endsWith(".out")).map(file => file.slice(0, -".out".length)).sort()).toEqual(names);
|
|
135
|
-
expect(proseFiles).toEqual(["00-setup.md", ...names.map(name => `${name}.md`)].sort());
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("lists every chapter in its index, the unnumbered first, numbered as its files are and by the title its prose gives", () => {
|
|
139
|
-
expect(listed.map(chapter => chapter.file).sort()).toEqual(proseFiles);
|
|
140
|
-
expect(listed.map(chapter => chapter.number)).toEqual(listed.map(chapter => chapter.number).sort((a, b) => a - b));
|
|
141
|
-
for (const { number, title, file } of listed) {
|
|
142
|
-
expect(number).toBe(chapterOf(file));
|
|
143
|
-
const [heading, ...rest] = read(file).split("\n");
|
|
144
|
-
expect(heading).toBe(`# ${title}`);
|
|
145
|
-
expect(rest.join("\n").trim()).not.toBe("");
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it.each(names)("%s prints what its .out says", async name => {
|
|
150
|
-
const expected = read(`${name}.out`);
|
|
151
|
-
expect(expected.trim()).not.toBe("");
|
|
152
|
-
expect(unversioned(await run(new URL(`${name}.ts`, folder)))).toBe(unversioned(expected));
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it.each(Object.entries(teaches))("chapter %s's prose names what it teaches, as code, and its program does it", (chapter, taught) => {
|
|
156
|
-
const prose = `${names.find(name => chapterOf(name) === Number(chapter)) ?? ""}.md`;
|
|
157
|
-
const shown = shownIn(read(prose)).join("\n");
|
|
158
|
-
const code = codeOf(Number(chapter));
|
|
159
|
-
expect(taught.filter(name => !shown.includes(name))).toEqual([]);
|
|
160
|
-
expect(taught.filter(name => !code.includes(name))).toEqual([]);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it("teaches something in every chapter", () => {
|
|
164
|
-
expect(Object.keys(teaches).map(Number)).toEqual(names.map(chapterOf));
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it("keeps code in the prose to a line or two, the program in the editor showing the rest", () => {
|
|
168
|
-
const long = proseFiles.flatMap(file => [...read(file).matchAll(/```\w*\n([\s\S]*?)```/g)].filter(([, block = ""]) => block.split("\n").length > 3).map(() => file));
|
|
169
|
-
expect(long).toEqual([]);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("links chapters only to chapters there are", () => {
|
|
173
|
-
const chapterLinks = proseFiles.flatMap(file => [...read(file).matchAll(/\]\(([^)#\s]+\.md)\)/g)].map(([, target = ""]) => target));
|
|
174
|
-
expect(chapterLinks.length).toBeGreaterThan(0);
|
|
175
|
-
expect(chapterLinks.filter(target => !proseFiles.includes(target))).toEqual([]);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
/** The messages of TypeScript's syntax errors in code. */
|
|
179
|
-
const syntaxErrors = (code: string): readonly string[] => {
|
|
180
|
-
const { diagnostics = [] } = ts.transpileModule(code, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext } });
|
|
181
|
-
return diagnostics.map(diagnostic => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"));
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
it.each(editorLinks.map(link => [`${link.prose} to ${link.file}#L${link.from}-L${link.to}`, link] as const))("links %s, lines of its own program that are whole code", (_place, { prose, file, from, to }) => {
|
|
185
|
-
expect(file.startsWith(prose.replace(/\.md$/, "."))).toBe(true);
|
|
186
|
-
const lines = read(file).split("\n");
|
|
187
|
-
expect(from).toBeGreaterThanOrEqual(1);
|
|
188
|
-
expect(to).toBeGreaterThanOrEqual(from);
|
|
189
|
-
expect(to).toBeLessThanOrEqual(lines.length);
|
|
190
|
-
const code = lines.slice(from - 1, to).join("\n");
|
|
191
|
-
expect(withoutComments(code).trim()).not.toBe("");
|
|
192
|
-
expect(lines[from - 1]?.trim()).not.toBe("");
|
|
193
|
-
expect(lines[to - 1]?.trim()).not.toBe("");
|
|
194
|
-
// Lines cut short leave a brace or a call open, which parses neither as statements nor as a declaration's members.
|
|
195
|
-
expect(syntaxErrors(code).length === 0 || syntaxErrors(`interface Members {\n${code}\n}`).length === 0 ? [] : syntaxErrors(code)).toEqual([]);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it.each(Object.entries(mutations).flatMap(([chapter, changes]) => changes.map(([from, to, failure], index) => [Number(chapter), from, to, failure, index] as const)))(
|
|
199
|
-
"catches chapter %s's point taken away, %j, in its output", async (chapter, from, to, failure, index) => {
|
|
200
|
-
const name = names.find(item => chapterOf(item) === chapter) ?? "";
|
|
201
|
-
const source = read(`${name}.ts`);
|
|
202
|
-
expect(source.split(from).length).toBe(2);
|
|
203
|
-
// A file of the package's own, compiled as the program is, outside its sources, which other tests read.
|
|
204
|
-
const mutant = `${name}-${index}.ts`;
|
|
205
|
-
mkdirSync(mutants, { recursive: true });
|
|
206
|
-
const file = new URL(mutant, mutants);
|
|
207
|
-
writeFileSync(file, source.replace(from, to).replace(` from "../index.js";`, ` from "../src/index.js";`));
|
|
208
|
-
try {
|
|
209
|
-
const output = (await run(file)).replaceAll(`.mutants/${mutant}`, `src/guide/${name}.ts`);
|
|
210
|
-
expect(unversioned(output)).not.toBe(unversioned(read(`${name}.out`)));
|
|
211
|
-
if (failure !== undefined) expect(output).toContain(failure);
|
|
212
|
-
} finally {
|
|
213
|
-
rmSync(file, { force: true });
|
|
214
|
-
}
|
|
215
|
-
});
|
|
70
|
+
checkChapters({ folder: new URL(".", import.meta.url), teaches, mutations });
|