@adobe/ecs 0.2.3 → 0.3.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/implementation/compiler/augmentations.js +8 -1
- package/dist/implementation/compiler/augmentations.js.map +1 -1
- 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/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 +5 -2
- package/dist/implementation/compiler/inferred.js.map +1 -1
- package/dist/implementation/compiler/transform.js +5 -4
- package/dist/implementation/compiler/transform.js.map +1 -1
- package/dist/implementation/compiler/type-schemas.d.ts +1 -0
- package/dist/implementation/compiler/type-schemas.js +35 -2
- package/dist/implementation/compiler/type-schemas.js.map +1 -1
- package/dist/implementation/world/activate.d.ts +14 -3
- package/dist/implementation/world/activate.js +28 -10
- 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 +41 -5
- package/dist/implementation/world/commands.js.map +1 -1
- package/dist/implementation/world/create.js +57 -6
- package/dist/implementation/world/create.js.map +1 -1
- package/dist/implementation/world/execute.d.ts +4 -4
- package/dist/implementation/world/execute.js +228 -93
- package/dist/implementation/world/execute.js.map +1 -1
- package/dist/implementation/world/finalizers.d.ts +10 -0
- package/dist/implementation/world/finalizers.js +60 -10
- package/dist/implementation/world/finalizers.js.map +1 -1
- package/dist/implementation/world/join.js +12 -2
- package/dist/implementation/world/join.js.map +1 -1
- package/dist/implementation/world/program.js +5 -1
- package/dist/implementation/world/program.js.map +1 -1
- 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.js +21 -16
- 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 +16 -12
- package/dist/implementation/world/runner.js.map +1 -1
- package/dist/implementation/world/state.d.ts +15 -0
- package/dist/implementation/world/state.js +22 -1
- package/dist/implementation/world/state.js.map +1 -1
- package/dist/implementation/world/synchronize.js +81 -24
- package/dist/implementation/world/synchronize.js.map +1 -1
- package/dist/implementation/world/tables-read.d.ts +5 -3
- package/dist/implementation/world/tables-read.js +16 -4
- package/dist/implementation/world/tables-read.js.map +1 -1
- package/dist/implementation/world/tables.d.ts +4 -2
- package/dist/implementation/world/tables.js +137 -38
- package/dist/implementation/world/tables.js.map +1 -1
- 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 +10 -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/interface/finalizer/body.d.ts +40 -4
- package/dist/interface/finalizer/create.d.ts +8 -6
- package/dist/interface/finalizer/create.js +45 -10
- package/dist/interface/finalizer/create.js.map +1 -1
- package/dist/interface/finalizer/declaration.d.ts +26 -4
- 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/index.d.ts +1 -1
- package/dist/interface/registry/index.js +1 -1
- package/dist/interface/registry/index.js.map +1 -1
- package/dist/interface/registry/names.d.ts +4 -0
- package/dist/interface/registry/names.js +20 -0
- package/dist/interface/registry/names.js.map +1 -1
- package/dist/interface/registry/schedule.d.ts +29 -1
- package/dist/interface/registry/schedule.js +261 -25
- package/dist/interface/registry/schedule.js.map +1 -1
- package/dist/interface/system/access.d.ts +15 -0
- package/dist/interface/system/check.d.ts +7 -0
- package/dist/interface/system/check.js +21 -3
- package/dist/interface/system/check.js.map +1 -1
- package/dist/interface/system/commands.d.ts +31 -5
- package/dist/interface/system/create-resolved.js +2 -1
- package/dist/interface/system/create-resolved.js.map +1 -1
- package/dist/interface/system/create.d.ts +10 -6
- package/dist/interface/system/create.js +5 -4
- package/dist/interface/system/create.js.map +1 -1
- package/dist/interface/system/declaration.d.ts +11 -4
- 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 +7 -0
- package/dist/interface/system/render.js +2 -1
- package/dist/interface/system/render.js.map +1 -1
- package/dist/interface/system/resolve.d.ts +14 -1
- package/dist/interface/system/resolve.js +50 -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 +9 -1
- package/dist/interface/world/table/index.d.ts +3 -2
- package/dist/interface/world/world.d.ts +15 -0
- package/package.json +11 -2
- package/src/guide/01-resources.md +4 -3
- package/src/guide/03-systems.out +1 -1
- package/src/guide/05-scheduling.md +12 -6
- package/src/guide/05-scheduling.out +1 -0
- package/src/guide/05-scheduling.ts +17 -0
- package/src/guide/06-sync-points.md +20 -8
- package/src/guide/06-sync-points.out +3 -2
- package/src/guide/06-sync-points.ts +24 -5
- package/src/guide/10-finalizers.md +5 -0
- package/src/guide/18-identity.out +1 -1
- package/src/guide/guide.test.ts +6 -153
- package/src/implementation/compiler/augmentations.test.ts +28 -1
- package/src/implementation/compiler/augmentations.ts +5 -1
- package/src/implementation/compiler/body-access.ts +102 -12
- package/src/implementation/compiler/estree.ts +9 -6
- package/src/implementation/compiler/inferred.test.ts +1 -1
- package/src/implementation/compiler/inferred.ts +5 -2
- package/src/implementation/compiler/transform.test.ts +41 -21
- package/src/implementation/compiler/transform.ts +5 -3
- package/src/implementation/compiler/type-schemas.ts +28 -2
- package/src/implementation/world/activate.ts +32 -10
- 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/commands.ts +37 -5
- package/src/implementation/world/create.test.ts +8 -8
- package/src/implementation/world/create.ts +61 -6
- package/src/implementation/world/defaults.test.ts +24 -1
- package/src/implementation/world/despawn-where.test.ts +310 -0
- package/src/implementation/world/execute.ts +222 -86
- package/src/implementation/world/finalizers.ts +63 -11
- package/src/implementation/world/ids.test.ts +1 -1
- package/src/implementation/world/indexes.test.ts +2 -1
- package/src/implementation/world/join.test.ts +19 -0
- package/src/implementation/world/join.ts +16 -2
- package/src/implementation/world/lifetime.test-helper.ts +1 -1
- package/src/implementation/world/names.test.ts +1 -2
- package/src/implementation/world/passes.test.ts +61 -0
- package/src/implementation/world/perf.md +12 -1
- package/src/implementation/world/program.ts +4 -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 +21 -14
- 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 +17 -0
- package/src/implementation/world/runner.ts +17 -13
- package/src/implementation/world/schedule.test.ts +42 -1
- package/src/implementation/world/shared.test.ts +2 -2
- package/src/implementation/world/state.ts +27 -0
- package/src/implementation/world/sync-points.test.ts +147 -0
- package/src/implementation/world/synchronize.ts +73 -20
- package/src/implementation/world/tables-read.ts +16 -5
- package/src/implementation/world/tables.test.ts +139 -4
- package/src/implementation/world/tables.ts +118 -35
- package/src/implementation/world/thread-observer.ts +1 -1
- package/src/implementation/world/thread-systems.ts +10 -6
- package/src/implementation/world/up.test.ts +13 -1
- package/src/implementation/world/up.ts +6 -1
- package/src/implementation/world/watch-traits-late.test-helper.ts +14 -0
- package/src/implementation/world/watch-traits.test-helper.ts +10 -0
- package/src/implementation/world/watch-traits.test.ts +62 -0
- package/src/implementation/world/where.ts +38 -10
- package/src/interface/finalizer/body.ts +33 -4
- package/src/interface/finalizer/create.test.ts +6 -1
- package/src/interface/finalizer/create.ts +45 -12
- package/src/interface/finalizer/declaration.ts +31 -4
- 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/registry/index.ts +1 -1
- package/src/interface/registry/names.ts +19 -0
- package/src/interface/registry/schedule.ts +275 -29
- package/src/interface/rule/rule.type-test.ts +23 -1
- package/src/interface/system/access.ts +16 -0
- package/src/interface/system/check.ts +17 -2
- package/src/interface/system/commands.ts +28 -4
- package/src/interface/system/commands.type-test.ts +31 -0
- package/src/interface/system/create-resolved.ts +2 -1
- package/src/interface/system/create.test.ts +10 -2
- package/src/interface/system/create.ts +9 -5
- package/src/interface/system/declaration.ts +10 -4
- package/src/interface/system/describe.test.ts +98 -0
- package/src/interface/system/describe.ts +122 -0
- package/src/interface/system/index.ts +1 -0
- package/src/interface/system/leaf.ts +7 -0
- package/src/interface/system/render.ts +2 -1
- package/src/interface/system/resolve.test.ts +17 -1
- package/src/interface/system/resolve.ts +60 -2
- package/src/interface/system/shared-only.ts +5 -0
- package/src/interface/system/system.type-test.ts +6 -0
- package/src/interface/system/tables.ts +7 -1
- package/src/interface/world/run.type-test.ts +11 -1
- package/src/interface/world/table/index.ts +3 -2
- package/src/interface/world/world.ts +13 -0
- package/src/perftest/benchmarks.ts +20 -0
- package/src/perftest/chained.ts +108 -0
- package/src/perftest/structural.ts +20 -0
- package/src/perftest/tables.ts +107 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/interface/system/resolve.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../../src/interface/system/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Shared } from '../component/value.js';
|
|
2
|
+
/** A `where`'s keys that aren't shared components, each an error: `where` names only shared components. */
|
|
3
|
+
export type SharedOnly<W> = {
|
|
4
|
+
readonly [K in Exclude<keyof W, Shared>]: {
|
|
5
|
+
readonly "error: where names only shared components, which each archetype holds one value of": K;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-only.js","sourceRoot":"","sources":["../../../src/interface/system/shared-only.ts"],"names":[],"mappings":""}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import type { Component } from '../component/component.js';
|
|
2
|
+
import type { Shared } from '../component/value.js';
|
|
2
3
|
import type { Resource } from '../resource/resource.js';
|
|
3
4
|
import type { Table } from '../world/table/table.js';
|
|
4
5
|
/**
|
|
5
|
-
* What a readonly system's `tables` reads: of every archetype matching `with` and `
|
|
6
|
+
* What a readonly system's `tables` reads: of every archetype matching `with`, `not` and `where` that holds any of
|
|
6
7
|
* `components`, a table of those it holds; and, with `resources`, each resource's value.
|
|
7
8
|
*/
|
|
8
9
|
export type TablesDeclaration = {
|
|
9
10
|
readonly components: readonly Component.Key[];
|
|
10
11
|
readonly with?: readonly Component.Key[];
|
|
11
12
|
readonly not?: readonly Component.Key[];
|
|
13
|
+
/**
|
|
14
|
+
* Keeps the tables to the archetypes holding these values of shared components, each one required as `with`
|
|
15
|
+
* requires it, as a system's `where` of values keeps its system to them.
|
|
16
|
+
*/
|
|
17
|
+
readonly where?: {
|
|
18
|
+
readonly [K in Shared]?: Component<K>;
|
|
19
|
+
};
|
|
12
20
|
readonly resources?: readonly Resource.Key[];
|
|
13
21
|
};
|
|
14
22
|
/** A readonly system's `tables`: a table of each archetype its declaration reads, and the values of the resources it reads. */
|
|
@@ -17,8 +17,9 @@ export type Column = {
|
|
|
17
17
|
readonly value: unknown;
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
|
-
* What `commands.spawnTables` spawned: each table's
|
|
21
|
-
*
|
|
20
|
+
* What `commands.spawnTables` spawned: each table's entities in its row order, the one spawned for each row, the one
|
|
21
|
+
* existing for a row its `existing` maps, and `Entity.none` for a row it didn't spawn; and how many rows it didn't,
|
|
22
|
+
* those owned by an entity outside the tables.
|
|
22
23
|
*/
|
|
23
24
|
export type Spawned = {
|
|
24
25
|
readonly entities: readonly Float64Array[];
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { Input } from '../system/input.js';
|
|
2
2
|
import type { System } from '../system/system.js';
|
|
3
|
+
import type { ChangeSet } from '../finalizer/body.js';
|
|
4
|
+
import type { Essential } from '../component/value.js';
|
|
5
|
+
import type { Resource } from '../resource/resource.js';
|
|
3
6
|
/**
|
|
4
7
|
* A world. Systems read and change it; readonly systems read it after each run's and tick's sync point. Every member's
|
|
5
8
|
* type is named from the package root, so declarations a consumer emits for its results name no internal module.
|
|
@@ -21,6 +24,18 @@ export type World = {
|
|
|
21
24
|
* added or GPU work, is reported out of band, as ticks' failures are (see `add`).
|
|
22
25
|
*/
|
|
23
26
|
run<I, R>(system: System<I, R>, ...input: Input<NoInfer<I>>): Promise<R>;
|
|
27
|
+
/**
|
|
28
|
+
* Runs as `run` does, and resolves to this run's own changes, in the shape `Finalizer.changes` gives, rather than its
|
|
29
|
+
* value: the structural changes its commands made, rules and cascades included, to every component that isn't
|
|
30
|
+
* derived or an object a joined thread fills, the values its adds gave components entities had before and after, and
|
|
31
|
+
* each resource its systems write or reduce into whose value changed, compared as `Finalizer.changes` compares them;
|
|
32
|
+
* `previous` and `next` give values before and after the run. Commands the finalizers of an earlier sync point
|
|
33
|
+
* queued apply first, at a sync point of their own. Values written to rows aren't structural changes, so they're in
|
|
34
|
+
* none. The run pays for this only when asked. Only on the world's thread: a joined thread's rejects.
|
|
35
|
+
*/
|
|
36
|
+
run<I, R>(system: System<I, R>, ...input: [...Input<NoInfer<I>>, options: {
|
|
37
|
+
readonly changes: true;
|
|
38
|
+
}]): Promise<ChangeSet<Essential, Resource.Key>>;
|
|
24
39
|
/**
|
|
25
40
|
* Adds a system to every tick, from the next one on, ordered with those already added by its constraints, as a
|
|
26
41
|
* composite's members are. A tick runs on a beat of the `cadence` resource where `always` is set, `wake` is due or
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/ecs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Adobe ECS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"typescript": "^5.8.3",
|
|
47
47
|
"vite": "^8.3.4",
|
|
48
48
|
"vitest": "^5.0.5",
|
|
49
|
-
"wabt": "1.0.39"
|
|
49
|
+
"wabt": "1.0.39",
|
|
50
|
+
"ecs-guide-checks": "0.0.0"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
52
53
|
"vite": "^8.0.0"
|
|
@@ -66,6 +67,14 @@
|
|
|
66
67
|
"types": "./dist/implementation/compiler/index.d.ts"
|
|
67
68
|
}
|
|
68
69
|
},
|
|
70
|
+
"guide": {
|
|
71
|
+
"files": [
|
|
72
|
+
"src/index.ts",
|
|
73
|
+
"src/interface/**/*.ts",
|
|
74
|
+
"dist/index.js",
|
|
75
|
+
"dist/interface/**/*.js"
|
|
76
|
+
]
|
|
77
|
+
},
|
|
69
78
|
"scripts": {
|
|
70
79
|
"build": "cp ../../LICENSE . && tsc -b",
|
|
71
80
|
"dev": "tsc -b -w --preserveWatchOutput",
|
|
@@ -10,11 +10,12 @@ A world starts each resource at the first of these that applies:
|
|
|
10
10
|
3. its type's namespace's `default`, as [`Height`](01-resources.ts#L11-L12) gives; every world shares that value, so
|
|
11
11
|
it's read-only;
|
|
12
12
|
4. a reduction's identity ([Reductions](15-reductions.md)), `null` for a nullable type, the zero value (`0`, `false`,
|
|
13
|
-
`""`, item by item), or an empty `ReadonlyMap` or `ReadonlySet` of each world's own
|
|
13
|
+
`""`, item by item), or an empty `ReadonlyMap` or `ReadonlySet` of each world's own, whatever it holds, which takes
|
|
14
|
+
no `default`.
|
|
14
15
|
|
|
15
16
|
Data, such as numbers, strings, tuples, structs, maps and sets, is held as a value: a system replaces it whole. A value
|
|
16
|
-
that isn't data, such as an `AudioContext`,
|
|
17
|
-
written back. An `Entity` resource with no entity holds `Entity.none`, which is `0` rather than `null`, so it stays data
|
|
17
|
+
that isn't data, such as an `AudioContext`, a symbol such as a `Resource.Key`, or a map or set holding one, is stored
|
|
18
|
+
as it is; a change inside it is seen only once the resource is written back. An `Entity` resource with no entity holds `Entity.none`, which is `0` rather than `null`, so it stays data
|
|
18
19
|
every thread can read.
|
|
19
20
|
|
|
20
21
|
A system reads resources by key. With `readonly: true` it only reads, and runs after the world's changes apply.
|
package/src/guide/03-systems.out
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# Scheduling and composites
|
|
2
2
|
|
|
3
3
|
`after`, `before` and `during` order a system against others, listing the systems themselves:
|
|
4
|
-
[`heal`](05-scheduling.ts#
|
|
4
|
+
[`heal`](05-scheduling.ts#L22-L24) runs `after: [hit]`.
|
|
5
5
|
|
|
6
6
|
A *composite* is a list of systems, `System.create([heal, hit])`, run as one system. Its members run in the order
|
|
7
|
-
their constraints give, not the order they're listed, so [`frame`](05-scheduling.ts#
|
|
7
|
+
their constraints give, not the order they're listed, so [`frame`](05-scheduling.ts#L25) hits before it heals.
|
|
8
8
|
Members with no order between them may run in parallel; two that write what the other reads or writes must be
|
|
9
|
-
ordered, or the composite is rejected
|
|
10
|
-
|
|
9
|
+
ordered, or the composite is rejected, unless their rows never match one entity, one's `not` naming a component the
|
|
10
|
+
other requires, and they use what they share only through their rows. `System.create({ systems, after, ... })`
|
|
11
|
+
declares a composite with constraints of its own.
|
|
11
12
|
|
|
12
|
-
A *phase* is a system that does nothing, such as [`update` and `render`](05-scheduling.ts#
|
|
13
|
+
A *phase* is a system that does nothing, such as [`update` and `render`](05-scheduling.ts#L32-L33). A system
|
|
13
14
|
`during: [update]` runs after what `update` follows and before what follows `update`. Phases let systems written apart
|
|
14
|
-
agree on an order without naming each other: in [`phased`](05-scheduling.ts#
|
|
15
|
+
agree on an order without naming each other: in [`phased`](05-scheduling.ts#L40), `poison` runs before `report`.
|
|
16
|
+
|
|
17
|
+
`before` and `after` also take a resource: a system listing one runs before, or after, every other system of the
|
|
18
|
+
composite that uses it, as [`harden`](05-scheduling.ts#L43) runs `before: [difficulty]`, so `scale` reads the
|
|
19
|
+
difficulty it set. One that must read the value before it's written says so of the writer itself, `before: [harden]`;
|
|
20
|
+
two systems listing the same resource aren't ordered with each other by it, so two writers still need an order.
|
|
@@ -3,12 +3,16 @@ import { System, World } from "../index.js";
|
|
|
3
3
|
|
|
4
4
|
const health = Symbol();
|
|
5
5
|
const damage = Symbol();
|
|
6
|
+
const difficulty = Symbol();
|
|
6
7
|
|
|
7
8
|
declare module "@adobe/ecs" {
|
|
8
9
|
interface Components {
|
|
9
10
|
[health]: { type: number };
|
|
10
11
|
[damage]: { type: number };
|
|
11
12
|
}
|
|
13
|
+
interface Resources {
|
|
14
|
+
[difficulty]: { type: number; default: 1 };
|
|
15
|
+
}
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
const spawn = System.create(({ commands }) => { commands.spawn([health, damage])({ [health]: 10, [damage]: 4 }); });
|
|
@@ -35,6 +39,16 @@ const report = System.create({ components: { with: [health] }, during: [render]
|
|
|
35
39
|
});
|
|
36
40
|
const phased = System.create([report, poison, update, render]);
|
|
37
41
|
|
|
42
|
+
// Ordering by a resource: before every other system that uses it.
|
|
43
|
+
const harden = System.create({ before: [difficulty] }, ({ resources }) => { resources[difficulty] = 2; });
|
|
44
|
+
const scale = System.create({ components: { with: [damage] } }, (row, { resources }) => {
|
|
45
|
+
row[damage] = 4 * resources[difficulty];
|
|
46
|
+
});
|
|
47
|
+
const tuned = System.create([scale, harden]);
|
|
48
|
+
const readDamage = System.create({ readonly: true, components: { with: [damage] } }, row => {
|
|
49
|
+
console.log("damage", row[damage]);
|
|
50
|
+
});
|
|
51
|
+
|
|
38
52
|
export const main = async (): Promise<void> => {
|
|
39
53
|
await using world = World.create();
|
|
40
54
|
await world.run(spawn);
|
|
@@ -43,4 +57,7 @@ export const main = async (): Promise<void> => {
|
|
|
43
57
|
await world.run(read);
|
|
44
58
|
// poison, then report.
|
|
45
59
|
await world.run(phased);
|
|
60
|
+
// harden, then scale, 4 * 2.
|
|
61
|
+
await world.run(tuned);
|
|
62
|
+
await world.run(readDamage);
|
|
46
63
|
};
|
|
@@ -1,18 +1,30 @@
|
|
|
1
1
|
# Sync points
|
|
2
2
|
|
|
3
|
-
A run
|
|
3
|
+
A run applies its commands at *sync points*.
|
|
4
4
|
|
|
5
5
|
- **Values** written to rows and resources apply at once.
|
|
6
|
-
- **Commands** wait for
|
|
7
|
-
once, so [later commands can name it](06-sync-points.ts#
|
|
6
|
+
- **Commands** wait for a sync point, then apply in the order issued. `commands.spawn` returns the new entity at
|
|
7
|
+
once, so [later commands can name it](06-sync-points.ts#L20-L25): `commands.add` sets the hero's health to 5. An
|
|
8
8
|
entity spawned and removed with `commands.despawn` before the sync point never exists.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
Every run ends at a sync point. Within it, the build tells which components each system's commands name, and a system
|
|
11
|
+
that follows one whose commands could change what it reads, matches, looks up or indexes gets a sync point before its
|
|
12
|
+
tier. In [`frame`](06-sync-points.ts#L32), `count` runs `after: [spawn]`, so the hero exists by then and it counts it;
|
|
13
|
+
[`early`](06-sync-points.ts#L29-L31), ordered with nothing, runs beside `spawn`, before that sync point, and counts
|
|
14
|
+
none. An ordering costs a little, a tier boundary, and a sync point where the earlier system's commands could change
|
|
15
|
+
what the later one reads, which costs more only when commands were issued: a run adds the fewest sync points that put
|
|
16
|
+
one between every such pair, and none where no system depends on another's commands.
|
|
12
17
|
|
|
13
|
-
**
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
**One-frame events.** An event, such as a key going down, is an entity that lives one frame. The system making
|
|
19
|
+
events clears those it made before and makes this frame's in one body, as
|
|
20
|
+
[`press`](06-sync-points.ts#L40-L43) does: `commands.despawnWhere({ with: [keyDown] })` despawns the entities with
|
|
21
|
+
`keyDown` that were alive before its sync point, never one the same sync point spawns, so `handle`, `after: [press]`,
|
|
22
|
+
reads this frame's key and no earlier one. Events many systems make are cleared instead by one system ordered `after`
|
|
23
|
+
a composite of everything else, which despawns them once every system has read them.
|
|
24
|
+
|
|
25
|
+
**Readonly systems.** `readonly: true` places a system after the last sync point, so it reads what the commands did.
|
|
26
|
+
Added to a world, [`watch`](06-sync-points.ts#L34-L36) runs after the last sync point of every run and tick, and logs
|
|
27
|
+
the hero after the run that spawned it; `count`, which isn't readonly, runs in its tier.
|
|
16
28
|
|
|
17
29
|
- **Where:** a readonly system runs on the thread that added or ran it, so a [joined thread](19-threads.md) adds only
|
|
18
30
|
readonly systems.
|
|
@@ -3,13 +3,17 @@ import { System, World } from "../index.js";
|
|
|
3
3
|
|
|
4
4
|
const health = Symbol();
|
|
5
5
|
const seen = Symbol();
|
|
6
|
+
const seenEarly = Symbol();
|
|
7
|
+
const keyDown = Symbol();
|
|
6
8
|
|
|
7
9
|
declare module "@adobe/ecs" {
|
|
8
10
|
interface Components {
|
|
9
11
|
[health]: { type: number };
|
|
12
|
+
[keyDown]: { type: string };
|
|
10
13
|
}
|
|
11
14
|
interface Resources {
|
|
12
15
|
[seen]: { type: number };
|
|
16
|
+
[seenEarly]: { type: number };
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -22,21 +26,36 @@ const spawn = System.create(({ commands }) => {
|
|
|
22
26
|
const count = System.create({ components: { with: [health] }, after: [spawn] }, (row, { resources }) => {
|
|
23
27
|
resources[seen] += 1;
|
|
24
28
|
});
|
|
25
|
-
const
|
|
29
|
+
const early = System.create({ components: { with: [health] } }, (row, { resources }) => {
|
|
30
|
+
resources[seenEarly] += 1;
|
|
31
|
+
});
|
|
32
|
+
const frame = System.create([spawn, count, early]);
|
|
26
33
|
|
|
27
34
|
const watch = System.create({ readonly: true, components: { with: [health] } }, row => {
|
|
28
35
|
console.log("health", row[health]);
|
|
29
36
|
});
|
|
30
|
-
const readSeen = System.create({ readonly: true }, ({ resources }) => resources[seen]);
|
|
37
|
+
const readSeen = System.create({ readonly: true }, ({ resources }) => [resources[seen], resources[seenEarly]]);
|
|
38
|
+
|
|
39
|
+
// One-frame events: the producer clears the events it made before, then makes this frame's.
|
|
40
|
+
const press = System.create({}, ({ commands }, input: { readonly key: string }) => {
|
|
41
|
+
commands.despawnWhere({ with: [keyDown] });
|
|
42
|
+
commands.spawn([keyDown])({ [keyDown]: input.key });
|
|
43
|
+
});
|
|
44
|
+
const handle = System.create({ components: { with: [keyDown] }, after: [press] }, row => {
|
|
45
|
+
console.log("pressed", row[keyDown]);
|
|
46
|
+
});
|
|
47
|
+
const keys = System.create([press, handle]);
|
|
31
48
|
|
|
32
49
|
export const main = async (): Promise<void> => {
|
|
33
50
|
await using world = World.create();
|
|
34
51
|
await world.run(frame);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log("counted", await world.run(readSeen));
|
|
52
|
+
const [counted, countedEarly] = await world.run(readSeen);
|
|
53
|
+
console.log("counted", counted, "early", countedEarly);
|
|
38
54
|
|
|
39
55
|
await using watched = World.create();
|
|
40
56
|
watched.add(watch);
|
|
41
57
|
await watched.run(spawn);
|
|
58
|
+
|
|
59
|
+
await world.run(keys, { key: "a" });
|
|
60
|
+
await world.run(keys, { key: "b" });
|
|
42
61
|
};
|
|
@@ -11,3 +11,8 @@ closes too.
|
|
|
11
11
|
A *change set* is each sync point's structural changes to the components a `Finalizer.changes` watches, grouped by how
|
|
12
12
|
entities changed. [`changes.previous` and `changes.next`](10-finalizers.ts#L32-L36) give a component's value before
|
|
13
13
|
and after, `null` where the entity didn't have it: what saving and undo need.
|
|
14
|
+
|
|
15
|
+
It watches what `watch` names: components, resources, whose writes it sees as `changes.resources`, and traits of your
|
|
16
|
+
own, every component and resource declaring one, as each registers, so a list kept by hand never misses a key. Without
|
|
17
|
+
`watch`, every component and no resource; `watch: { components: true, resources: [...] }` watches every component and
|
|
18
|
+
the resources listed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Error: System "explode" (@adobe/ecs@0.
|
|
1
|
+
Error: System "explode" (@adobe/ecs@0.3.0/src/guide/18-identity.ts#explode) failed: boom
|
package/src/guide/guide.test.ts
CHANGED
|
@@ -1,70 +1,5 @@
|
|
|
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[] } = {
|
|
@@ -73,8 +8,8 @@ const teaches: { readonly [chapter: number]: readonly string[] } = {
|
|
|
73
8
|
2: ["Components", "type: true", "as const", "commands.spawn", "commands.remove", "with: [...Particle]"],
|
|
74
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
|
-
5: ["after", "during", "System.create([heal, hit])", "during: [update]"],
|
|
77
|
-
6: ["commands.spawn", "commands.add", "commands.despawn", "after: [spawn]", "readonly: true"],
|
|
11
|
+
5: ["after", "during", "System.create([heal, hit])", "during: [update]", "before: [difficulty]"],
|
|
12
|
+
6: ["commands.spawn", "commands.add", "commands.despawn", "after: [spawn]", "readonly: true", "commands.despawnWhere({ with: [keyDown] })"],
|
|
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"],
|
|
@@ -110,8 +45,8 @@ const mutations: { readonly [chapter: number]: readonly (readonly [string, strin
|
|
|
110
45
|
["not: [frozen]", "not: []"], ["System.create([count, fail])", "System.create([fail])"],
|
|
111
46
|
],
|
|
112
47
|
4: [["world.remove(advance);", ""]],
|
|
113
|
-
5: [["after: [hit] ", ""], ["during: [update] ", ""]],
|
|
114
|
-
6: [["commands.add(hero, health, 5);", ""], ["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({ "]],
|
|
48
|
+
5: [["after: [hit] ", ""], ["during: [update] ", ""], ["{ before: [difficulty] }, ", ""]],
|
|
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({ "], ["commands.despawnWhere({ with: [keyDown] });", ""]],
|
|
115
50
|
7: [["resources: { changed: [level] } ", ""], [", changed: [score]", ""], [", not: [paused]", ""], ["is: [map], ", ""]],
|
|
116
51
|
8: [["target: \"entity\",", ""]],
|
|
117
52
|
9: [["with: [mesh], not: [hidden]", "with: [mesh]"], ["Rule.create({ components: { with: [sprite], not: [hidden] }, derive: [drawn] });", ""], ["Rule.create({ components: { with: [drawn] }, derive: [layer] });", ""]],
|
|
@@ -132,86 +67,4 @@ const mutations: { readonly [chapter: number]: readonly (readonly [string, strin
|
|
|
132
67
|
22: [["context.fill();", ""]],
|
|
133
68
|
};
|
|
134
69
|
|
|
135
|
-
|
|
136
|
-
expect(files.filter(file => file.endsWith(".out")).map(file => file.slice(0, -".out".length)).sort()).toEqual(names);
|
|
137
|
-
expect(proseFiles).toEqual(["00-setup.md", ...names.map(name => `${name}.md`)].sort());
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("lists every chapter in its index, the unnumbered first, numbered as its files are and by the title its prose gives", () => {
|
|
141
|
-
expect(listed.map(chapter => chapter.file).sort()).toEqual(proseFiles);
|
|
142
|
-
expect(listed.map(chapter => chapter.number)).toEqual(listed.map(chapter => chapter.number).sort((a, b) => a - b));
|
|
143
|
-
for (const { number, title, file } of listed) {
|
|
144
|
-
expect(number).toBe(chapterOf(file));
|
|
145
|
-
const [heading, ...rest] = read(file).split("\n");
|
|
146
|
-
expect(heading).toBe(`# ${title}`);
|
|
147
|
-
expect(rest.join("\n").trim()).not.toBe("");
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it.each(names)("%s prints what its .out says", async name => {
|
|
152
|
-
const expected = read(`${name}.out`);
|
|
153
|
-
expect(expected.trim()).not.toBe("");
|
|
154
|
-
expect(unversioned(await run(new URL(`${name}.ts`, folder)))).toBe(unversioned(expected));
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it.each(Object.entries(teaches))("chapter %s's prose names what it teaches, as code, and its program does it", (chapter, taught) => {
|
|
158
|
-
const prose = `${names.find(name => chapterOf(name) === Number(chapter)) ?? ""}.md`;
|
|
159
|
-
const shown = shownIn(read(prose)).join("\n");
|
|
160
|
-
const code = codeOf(Number(chapter));
|
|
161
|
-
expect(taught.filter(name => !shown.includes(name))).toEqual([]);
|
|
162
|
-
expect(taught.filter(name => !code.includes(name))).toEqual([]);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("teaches something in every chapter", () => {
|
|
166
|
-
expect(Object.keys(teaches).map(Number)).toEqual(names.map(chapterOf));
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it("keeps code in the prose to a line or two, the program in the editor showing the rest", () => {
|
|
170
|
-
const long = proseFiles.flatMap(file => [...read(file).matchAll(/```\w*\n([\s\S]*?)```/g)].filter(([, block = ""]) => block.split("\n").length > 3).map(() => file));
|
|
171
|
-
expect(long).toEqual([]);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it("links chapters only to chapters there are", () => {
|
|
175
|
-
const chapterLinks = proseFiles.flatMap(file => [...read(file).matchAll(/\]\(([^)#\s]+\.md)\)/g)].map(([, target = ""]) => target));
|
|
176
|
-
expect(chapterLinks.length).toBeGreaterThan(0);
|
|
177
|
-
expect(chapterLinks.filter(target => !proseFiles.includes(target))).toEqual([]);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
/** The messages of TypeScript's syntax errors in code. */
|
|
181
|
-
const syntaxErrors = (code: string): readonly string[] => {
|
|
182
|
-
const { diagnostics = [] } = ts.transpileModule(code, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext } });
|
|
183
|
-
return diagnostics.map(diagnostic => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"));
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
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 }) => {
|
|
187
|
-
expect(file.startsWith(prose.replace(/\.md$/, "."))).toBe(true);
|
|
188
|
-
const lines = read(file).split("\n");
|
|
189
|
-
expect(from).toBeGreaterThanOrEqual(1);
|
|
190
|
-
expect(to).toBeGreaterThanOrEqual(from);
|
|
191
|
-
expect(to).toBeLessThanOrEqual(lines.length);
|
|
192
|
-
const code = lines.slice(from - 1, to).join("\n");
|
|
193
|
-
expect(withoutComments(code).trim()).not.toBe("");
|
|
194
|
-
expect(lines[from - 1]?.trim()).not.toBe("");
|
|
195
|
-
expect(lines[to - 1]?.trim()).not.toBe("");
|
|
196
|
-
// Lines cut short leave a brace or a call open, which parses neither as statements nor as a declaration's members.
|
|
197
|
-
expect(syntaxErrors(code).length === 0 || syntaxErrors(`interface Members {\n${code}\n}`).length === 0 ? [] : syntaxErrors(code)).toEqual([]);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it.each(Object.entries(mutations).flatMap(([chapter, changes]) => changes.map(([from, to, failure], index) => [Number(chapter), from, to, failure, index] as const)))(
|
|
201
|
-
"catches chapter %s's point taken away, %j, in its output", async (chapter, from, to, failure, index) => {
|
|
202
|
-
const name = names.find(item => chapterOf(item) === chapter) ?? "";
|
|
203
|
-
const source = read(`${name}.ts`);
|
|
204
|
-
expect(source.split(from).length).toBe(2);
|
|
205
|
-
// A file of the package's own, compiled as the program is, outside its sources, which other tests read.
|
|
206
|
-
const mutant = `${name}-${index}.ts`;
|
|
207
|
-
mkdirSync(mutants, { recursive: true });
|
|
208
|
-
const file = new URL(mutant, mutants);
|
|
209
|
-
writeFileSync(file, source.replace(from, to).replace(` from "../index.js";`, ` from "../src/index.js";`));
|
|
210
|
-
try {
|
|
211
|
-
const output = (await run(file)).replaceAll(`.mutants/${mutant}`, `src/guide/${name}.ts`);
|
|
212
|
-
expect(unversioned(output)).not.toBe(unversioned(read(`${name}.out`)));
|
|
213
|
-
if (failure !== undefined) expect(output).toContain(failure);
|
|
214
|
-
} finally {
|
|
215
|
-
rmSync(file, { force: true });
|
|
216
|
-
}
|
|
217
|
-
});
|
|
70
|
+
checkChapters({ folder: new URL(".", import.meta.url), teaches, mutations });
|
|
@@ -213,7 +213,34 @@ const Height = { default: -1 } as const;`);
|
|
|
213
213
|
});
|
|
214
214
|
test("gives a mutable Map or Set no start of its own: null when its type allows it, else a failure", async () => {
|
|
215
215
|
expect(await registrations(`${keys("pool")}declare module "@adobe/ecs" { interface Resources { [pool]: { type: Pool | null } } }\ntype Pool = Map<string, number>;`)).toEqual([`declare$(pool, "resource", {});`]);
|
|
216
|
-
expect(await passed(`${keys("pool")}declare module "@adobe/ecs" { interface Resources { [pool]: { type: Pool } } }\ntype Pool = Map<string, number>;`)).toContain("a ReadonlyMap or ReadonlySet starts
|
|
216
|
+
expect(await passed(`${keys("pool")}declare module "@adobe/ecs" { interface Resources { [pool]: { type: Pool } } }\ntype Pool = Map<string, number>;`)).toContain("or declare it a ReadonlyMap or ReadonlySet, which starts empty in each world");
|
|
217
|
+
});
|
|
218
|
+
test("starts a ReadonlyMap or ReadonlySet of what isn't data fresh in each world, with no schema", async () => {
|
|
219
|
+
const files = { "/src/pool.ts": `export class Pool {}` };
|
|
220
|
+
expect(await registrations(`import { Pool } from "./pool.js";\nimport type { Resource, Component } from "@adobe/ecs";\n${keys("written", "pools", "marks", "seen", "named", "byKey")}declare module "@adobe/ecs" {
|
|
221
|
+
interface Resources {
|
|
222
|
+
[written]: { type: ReadonlyMap<Resource.Key, unknown> };
|
|
223
|
+
[pools]: { type: ReadonlyMap<string, Pool> };
|
|
224
|
+
[marks]: { type: ReadonlySet<symbol> };
|
|
225
|
+
[seen]: { type: ReadonlySet<unknown> };
|
|
226
|
+
[named]: { type: Named };
|
|
227
|
+
}
|
|
228
|
+
interface Components { [byKey]: { type: ReadonlySet<Component.Key> } }
|
|
229
|
+
}
|
|
230
|
+
type Named = ReadonlyMap<unique symbol, string>;`, files)).toEqual([
|
|
231
|
+
`declare$(written, "resource", { fresh: "Map" });`,
|
|
232
|
+
`declare$(pools, "resource", { fresh: "Map" });`,
|
|
233
|
+
`declare$(marks, "resource", { fresh: "Set" });`,
|
|
234
|
+
`declare$(seen, "resource", { fresh: "Set" });`,
|
|
235
|
+
`declare$(named, "resource", { fresh: "Map" });`,
|
|
236
|
+
`declare$(byKey, "component", {});`,
|
|
237
|
+
]);
|
|
238
|
+
});
|
|
239
|
+
test("fails for a default of a ReadonlyMap or ReadonlySet, which starts empty in each world", async () => {
|
|
240
|
+
for (const type of ["ReadonlySet<string>", "ReadonlyMap<string, number>", "ReadonlySet<unknown>"]) {
|
|
241
|
+
expect(await passed(`${keys("tags")}declare module "@adobe/ecs" { interface Resources { [tags]: { type: ${type}; default: [] } } }`))
|
|
242
|
+
.toContain(`tags is a ${type.slice(0, type.indexOf("<"))}, which starts empty in each world: leave its default out`);
|
|
243
|
+
}
|
|
217
244
|
});
|
|
218
245
|
test("gives a value that isn't data no schema, and its traits", async () => {
|
|
219
246
|
const files = { "/src/row.ts": `export class Row extends HTMLElement {}\nexport class Pool {}` };
|