koota 0.4.3 → 0.5.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/README.md +38 -4
- package/dist/{chunk-6HKEF2RH.js → chunk-KLYFWWYD.js} +19 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.cts +3 -5
- package/dist/index.d.ts +3 -5
- package/dist/index.js +1 -1
- package/dist/react.cjs +19 -0
- package/dist/react.d.cts +1 -2
- package/dist/react.d.ts +1 -2
- package/dist/react.js +1 -1
- package/dist/{world-CbC1N0VY.d.cts → world-DzIKt3Qf.d.cts} +11 -8
- package/dist/{world-CbC1N0VY.d.ts → world-DzIKt3Qf.d.ts} +11 -8
- package/package.json +4 -4
- package/react/index.cjs +19 -0
- package/react/index.d.cts +1 -2
- package/react/index.d.ts +1 -2
- package/react/index.js +1 -1
package/README.md
CHANGED
|
@@ -217,6 +217,35 @@ const containsAnything = world.query(Contains('*')) // Returns [inventory, chest
|
|
|
217
217
|
const relatesToGold = world.query(Wildcard(gold)) // Returns [inventory, chest, dwarf]
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
+
#### Removing relationships
|
|
221
|
+
|
|
222
|
+
A relationship targets a specific entity, so we need to likewise remove relationships with specific entities.
|
|
223
|
+
|
|
224
|
+
```js
|
|
225
|
+
// Add a specific relation
|
|
226
|
+
player.add(Likes(apple))
|
|
227
|
+
player.add(Likes(banana))
|
|
228
|
+
|
|
229
|
+
// Remove that same relation
|
|
230
|
+
player.remove(Likes(apple))
|
|
231
|
+
|
|
232
|
+
player.has(apple) // false
|
|
233
|
+
player.has(banana) // true
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
However, a wildcard can be used to remove all relationships of a kind — for all targets — from an entity.
|
|
237
|
+
|
|
238
|
+
```js
|
|
239
|
+
player.add(Likes(apple))
|
|
240
|
+
player.add(Likes(banana))
|
|
241
|
+
|
|
242
|
+
// Remove all Likes relations
|
|
243
|
+
player.remove(Likes('*'))
|
|
244
|
+
|
|
245
|
+
player.has(apple) // false
|
|
246
|
+
player.has(banana) // false
|
|
247
|
+
```
|
|
248
|
+
|
|
220
249
|
### Query modifiers
|
|
221
250
|
|
|
222
251
|
Modifiers are used to filter query results enabling powerful patterns. All modifiers can be mixed together.
|
|
@@ -550,7 +579,7 @@ const { entityId, generation, worldId } = unpackEntity(entity)
|
|
|
550
579
|
|
|
551
580
|
### Trait
|
|
552
581
|
|
|
553
|
-
|
|
582
|
+
Traits are self-contained slices of data you attach to an entity to define its state. They serve the same purpose as components in a traditional ECS. We call them traits to avoid confusion with React or web components.
|
|
554
583
|
|
|
555
584
|
A trait can be created with a schema that describes the kind of data it will hold.
|
|
556
585
|
|
|
@@ -558,22 +587,27 @@ A trait can be created with a schema that describes the kind of data it will hol
|
|
|
558
587
|
const Position = trait({ x: 0, y: 0, z: 0 })
|
|
559
588
|
```
|
|
560
589
|
|
|
561
|
-
In cases where the data needs to
|
|
590
|
+
A schema supports primitive values with **no** nested objects or arrays. In cases where the data needs to initialized for each instance of the trait, or complex structures are required, a callback initializer can be used.
|
|
562
591
|
|
|
563
592
|
```js
|
|
564
|
-
// ❌
|
|
593
|
+
// ❌ Arrays and objects are not allowed in trait schemas
|
|
565
594
|
const Inventory = trait({
|
|
566
595
|
items: [],
|
|
596
|
+
vec3: { x: 0, y: 0, z: 0}
|
|
567
597
|
max: 10,
|
|
568
598
|
})
|
|
569
599
|
|
|
570
|
-
// ✅
|
|
600
|
+
// ✅ Use a callback initializer for arrays and objects
|
|
571
601
|
const Inventory = trait({
|
|
572
602
|
items: () => [],
|
|
603
|
+
vec3: () => ({ x: 0, y: 0, z: 0})
|
|
573
604
|
max: 10,
|
|
574
605
|
})
|
|
575
606
|
```
|
|
576
607
|
|
|
608
|
+
> ℹ️ **Why not support nested schemas?**<br>
|
|
609
|
+
> It looks obvious to support nested stores, but doing so makes algorithms that work with the data exponentially more complex. If all data can be assumed scalar then any operation is guaranteed to be the simplest and fastest algorithm possible. This is called the First Normal Form in relational database theory. [You can read more here](https://www.dataorienteddesign.com/dodbook/node3.html#SECTION00340000000000000000).
|
|
610
|
+
|
|
577
611
|
Sometimes a trait only has one field that points to an object instance. In cases like this, it is useful to skip the schema and use a callback directly in the trait.
|
|
578
612
|
|
|
579
613
|
```js
|
|
@@ -298,11 +298,23 @@ function createStore(schema) {
|
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
+
// ../core/src/trait/utils/validate-schema.ts
|
|
302
|
+
function validateSchema(schema) {
|
|
303
|
+
for (const key in schema) {
|
|
304
|
+
const value = schema[key];
|
|
305
|
+
if (value !== null && typeof value === "object") {
|
|
306
|
+
const kind = Array.isArray(value) ? "array" : "object";
|
|
307
|
+
throw new Error(`Koota: ${key} is an ${kind}, which is not supported in traits.`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
301
312
|
// ../core/src/trait/trait.ts
|
|
302
313
|
var traitId = 0;
|
|
303
314
|
function defineTrait(schema = {}) {
|
|
304
315
|
const isAoS = typeof schema === "function";
|
|
305
316
|
const traitType = isAoS ? "aos" : "soa";
|
|
317
|
+
validateSchema(schema);
|
|
306
318
|
const Trait = Object.assign((params) => [Trait, params], {
|
|
307
319
|
schema,
|
|
308
320
|
[$internal]: {
|
|
@@ -468,6 +480,13 @@ function removeTrait(world, entity, ...traits) {
|
|
|
468
480
|
if (otherTargets.length === 0) {
|
|
469
481
|
removeTrait(world, entity, Pair(relation2, Wildcard));
|
|
470
482
|
}
|
|
483
|
+
if (traitCtx.isPairTrait && traitCtx.pairTarget === Wildcard && traitCtx.relation !== Wildcard) {
|
|
484
|
+
const relation3 = traitCtx.relation;
|
|
485
|
+
const targets = getRelationTargets(world, relation3, entity);
|
|
486
|
+
for (const target2 of targets) {
|
|
487
|
+
removeTrait(world, entity, relation3(target2));
|
|
488
|
+
}
|
|
489
|
+
}
|
|
471
490
|
}
|
|
472
491
|
}
|
|
473
492
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -343,11 +343,23 @@ function createStore(schema) {
|
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
// ../core/src/trait/utils/validate-schema.ts
|
|
347
|
+
function validateSchema(schema) {
|
|
348
|
+
for (const key in schema) {
|
|
349
|
+
const value = schema[key];
|
|
350
|
+
if (value !== null && typeof value === "object") {
|
|
351
|
+
const kind = Array.isArray(value) ? "array" : "object";
|
|
352
|
+
throw new Error(`Koota: ${key} is an ${kind}, which is not supported in traits.`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
346
357
|
// ../core/src/trait/trait.ts
|
|
347
358
|
var traitId = 0;
|
|
348
359
|
function defineTrait(schema = {}) {
|
|
349
360
|
const isAoS = typeof schema === "function";
|
|
350
361
|
const traitType = isAoS ? "aos" : "soa";
|
|
362
|
+
validateSchema(schema);
|
|
351
363
|
const Trait = Object.assign((params) => [Trait, params], {
|
|
352
364
|
schema,
|
|
353
365
|
[$internal]: {
|
|
@@ -513,6 +525,13 @@ function removeTrait(world, entity, ...traits) {
|
|
|
513
525
|
if (otherTargets.length === 0) {
|
|
514
526
|
removeTrait(world, entity, Pair(relation2, Wildcard));
|
|
515
527
|
}
|
|
528
|
+
if (traitCtx.isPairTrait && traitCtx.pairTarget === Wildcard && traitCtx.relation !== Wildcard) {
|
|
529
|
+
const relation3 = traitCtx.relation;
|
|
530
|
+
const targets = getRelationTargets(world, relation3, entity);
|
|
531
|
+
for (const target2 of targets) {
|
|
532
|
+
removeTrait(world, entity, relation3(target2));
|
|
533
|
+
}
|
|
534
|
+
}
|
|
516
535
|
}
|
|
517
536
|
}
|
|
518
537
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, E as Entity, T as Trait, M as ModifierData, Q as QueryParameter, a as QueryHash, R as Relation, b as RelationTarget, S as Schema, c as WildcardRelation, d as ExtractStore, N as Norm } from './world-
|
|
2
|
-
export { $ as $internal, A as AoSFactory, C as ConfigurableTrait,
|
|
3
|
-
import 'src';
|
|
1
|
+
import { W as World, E as Entity, T as Trait, M as ModifierData, Q as QueryParameter, a as QueryHash, R as Relation, b as RelationTarget, S as Schema, c as WildcardRelation, d as ExtractStore, N as Norm } from './world-DzIKt3Qf.cjs';
|
|
2
|
+
export { $ as $internal, A as AoSFactory, C as ConfigurableTrait, u as ExtractIsTag, t as ExtractSchema, l as InstancesFromParameters, I as IsExcluded, m as IsNotModifier, v as IsTag, f as QueryModifier, j as QueryResult, i as QueryResultOptions, g as QuerySubscriber, h as QueryUnsubscriber, q as SetTraitCallback, s as Store, k as StoresFromParameters, r as TraitInstance, p as TraitTuple, n as TraitType, o as TraitValue, e as createWorld } from './world-DzIKt3Qf.cjs';
|
|
4
3
|
|
|
5
4
|
type Actions = Record<string, (...args: any[]) => void>;
|
|
6
5
|
type ActionInitializer<T extends Actions> = (world: World) => T;
|
|
@@ -35,8 +34,7 @@ declare const relation: typeof defineRelation;
|
|
|
35
34
|
declare const Pair: <T extends Trait>(relation: Relation<T>, target: RelationTarget) => T;
|
|
36
35
|
declare const Wildcard: WildcardRelation;
|
|
37
36
|
|
|
38
|
-
declare function defineTrait(): Trait<
|
|
39
|
-
declare function defineTrait<S extends Schema>(schema: S): Trait<Norm<S>>;
|
|
37
|
+
declare function defineTrait<S extends Schema>(schema?: S): Trait<Norm<S>>;
|
|
40
38
|
declare const trait: typeof defineTrait;
|
|
41
39
|
declare function getStore<C extends Trait = Trait>(world: World, trait: C): ExtractStore<C>;
|
|
42
40
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, E as Entity, T as Trait, M as ModifierData, Q as QueryParameter, a as QueryHash, R as Relation, b as RelationTarget, S as Schema, c as WildcardRelation, d as ExtractStore, N as Norm } from './world-
|
|
2
|
-
export { $ as $internal, A as AoSFactory, C as ConfigurableTrait,
|
|
3
|
-
import 'src';
|
|
1
|
+
import { W as World, E as Entity, T as Trait, M as ModifierData, Q as QueryParameter, a as QueryHash, R as Relation, b as RelationTarget, S as Schema, c as WildcardRelation, d as ExtractStore, N as Norm } from './world-DzIKt3Qf.js';
|
|
2
|
+
export { $ as $internal, A as AoSFactory, C as ConfigurableTrait, u as ExtractIsTag, t as ExtractSchema, l as InstancesFromParameters, I as IsExcluded, m as IsNotModifier, v as IsTag, f as QueryModifier, j as QueryResult, i as QueryResultOptions, g as QuerySubscriber, h as QueryUnsubscriber, q as SetTraitCallback, s as Store, k as StoresFromParameters, r as TraitInstance, p as TraitTuple, n as TraitType, o as TraitValue, e as createWorld } from './world-DzIKt3Qf.js';
|
|
4
3
|
|
|
5
4
|
type Actions = Record<string, (...args: any[]) => void>;
|
|
6
5
|
type ActionInitializer<T extends Actions> = (world: World) => T;
|
|
@@ -35,8 +34,7 @@ declare const relation: typeof defineRelation;
|
|
|
35
34
|
declare const Pair: <T extends Trait>(relation: Relation<T>, target: RelationTarget) => T;
|
|
36
35
|
declare const Wildcard: WildcardRelation;
|
|
37
36
|
|
|
38
|
-
declare function defineTrait(): Trait<
|
|
39
|
-
declare function defineTrait<S extends Schema>(schema: S): Trait<Norm<S>>;
|
|
37
|
+
declare function defineTrait<S extends Schema>(schema?: S): Trait<Norm<S>>;
|
|
40
38
|
declare const trait: typeof defineTrait;
|
|
41
39
|
declare function getStore<C extends Trait = Trait>(world: World, trait: C): ExtractStore<C>;
|
|
42
40
|
|
package/dist/index.js
CHANGED
package/dist/react.cjs
CHANGED
|
@@ -316,11 +316,23 @@ function createStore(schema) {
|
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
// ../core/src/trait/utils/validate-schema.ts
|
|
320
|
+
function validateSchema(schema) {
|
|
321
|
+
for (const key in schema) {
|
|
322
|
+
const value = schema[key];
|
|
323
|
+
if (value !== null && typeof value === "object") {
|
|
324
|
+
const kind = Array.isArray(value) ? "array" : "object";
|
|
325
|
+
throw new Error(`Koota: ${key} is an ${kind}, which is not supported in traits.`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
319
330
|
// ../core/src/trait/trait.ts
|
|
320
331
|
var traitId = 0;
|
|
321
332
|
function defineTrait(schema = {}) {
|
|
322
333
|
const isAoS = typeof schema === "function";
|
|
323
334
|
const traitType = isAoS ? "aos" : "soa";
|
|
335
|
+
validateSchema(schema);
|
|
324
336
|
const Trait = Object.assign((params) => [Trait, params], {
|
|
325
337
|
schema,
|
|
326
338
|
[$internal]: {
|
|
@@ -486,6 +498,13 @@ function removeTrait(world, entity, ...traits) {
|
|
|
486
498
|
if (otherTargets.length === 0) {
|
|
487
499
|
removeTrait(world, entity, Pair(relation2, Wildcard));
|
|
488
500
|
}
|
|
501
|
+
if (traitCtx.isPairTrait && traitCtx.pairTarget === Wildcard && traitCtx.relation !== Wildcard) {
|
|
502
|
+
const relation3 = traitCtx.relation;
|
|
503
|
+
const targets = getRelationTargets(world, relation3, entity);
|
|
504
|
+
for (const target2 of targets) {
|
|
505
|
+
removeTrait(world, entity, relation3(target2));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
489
508
|
}
|
|
490
509
|
}
|
|
491
510
|
}
|
package/dist/react.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait,
|
|
1
|
+
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait, r as TraitInstance } from './world-DzIKt3Qf.cjs';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import 'src';
|
|
4
3
|
|
|
5
4
|
declare function useActions<T extends Record<string, (...args: any[]) => any>>(actions: (world: World) => T): T;
|
|
6
5
|
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait,
|
|
1
|
+
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait, r as TraitInstance } from './world-DzIKt3Qf.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import 'src';
|
|
4
3
|
|
|
5
4
|
declare function useActions<T extends Record<string, (...args: any[]) => any>>(actions: (world: World) => T): T;
|
|
6
5
|
|
package/dist/react.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as src from 'src';
|
|
2
|
-
|
|
3
1
|
declare const $internal: unique symbol;
|
|
4
2
|
|
|
5
3
|
type IsEmpty<T> = T extends Record<string, never> ? true : false;
|
|
@@ -31,18 +29,21 @@ type ConfigurableTrait<T extends Trait = Trait> = T | TraitTuple<T>;
|
|
|
31
29
|
type TraitInstanceFromTrait<T extends Trait> = T['schema'] extends AoSFactory ? ReturnType<T['schema']> : {
|
|
32
30
|
[P in keyof T['schema']]: T['schema'][P] extends (...args: any[]) => any ? ReturnType<T['schema'][P]> : T['schema'][P];
|
|
33
31
|
};
|
|
32
|
+
type SetTraitCallback<T extends Trait> = (prev: TraitInstance<ExtractSchema<T>>) => TraitValue<ExtractSchema<T>>;
|
|
34
33
|
type TraitInstanceFromSchema<T extends Schema> = T extends AoSFactory ? ReturnType<T> : {
|
|
35
34
|
[P in keyof T]: T[P] extends (...args: any[]) => any ? ReturnType<T[P]> : T[P];
|
|
36
35
|
};
|
|
37
36
|
type TraitInstance<T extends Trait | Schema> = T extends Trait ? TraitInstanceFromTrait<T> : TraitInstanceFromSchema<T>;
|
|
38
37
|
type Schema = {
|
|
39
|
-
[key: string]: number | string | boolean |
|
|
38
|
+
[key: string]: number | bigint | string | boolean | null | undefined | (() => unknown);
|
|
40
39
|
} | AoSFactory;
|
|
41
|
-
type AoSFactory = () =>
|
|
40
|
+
type AoSFactory = () => unknown;
|
|
42
41
|
type Store<T extends Schema = any> = T extends AoSFactory ? ReturnType<T>[] : {
|
|
43
42
|
[P in keyof T]: T[P] extends (...args: any[]) => any ? ReturnType<T[P]>[] : T[P][];
|
|
44
43
|
};
|
|
45
44
|
type Norm<T extends Schema> = T extends AoSFactory ? () => ReturnType<T> extends number ? number : ReturnType<T> extends boolean ? boolean : ReturnType<T> extends string ? string : ReturnType<T> : {
|
|
45
|
+
[K in keyof T]: T[K] extends object ? T[K] extends (...args: any[]) => any ? T[K] : never : T[K] extends boolean ? boolean : T[K];
|
|
46
|
+
}[keyof T] extends never ? never : {
|
|
46
47
|
[K in keyof T]: T[K] extends boolean ? boolean : T[K];
|
|
47
48
|
};
|
|
48
49
|
type ExtractSchema<T extends Trait | Relation<Trait>> = T extends Relation<infer R> ? ExtractSchema<R> : T extends Trait<infer S> ? S : never;
|
|
@@ -77,7 +78,7 @@ type Entity = number & {
|
|
|
77
78
|
has: (trait: Trait) => boolean;
|
|
78
79
|
destroy: () => void;
|
|
79
80
|
changed: (trait: Trait) => void;
|
|
80
|
-
set: <T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> |
|
|
81
|
+
set: <T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> | SetTraitCallback<T>, flagChanged?: boolean) => void;
|
|
81
82
|
get: <T extends Trait | Relation<Trait>>(trait: T) => TraitInstance<ExtractSchema<T>> | undefined;
|
|
82
83
|
targetFor: <T extends Trait>(relation: Relation<T>) => Entity | undefined;
|
|
83
84
|
targetsFor: <T extends Trait>(relation: Relation<T>) => Entity[];
|
|
@@ -164,7 +165,9 @@ type QueryHash<T extends QueryParameter[]> = string & {
|
|
|
164
165
|
readonly [$parameters]: T;
|
|
165
166
|
};
|
|
166
167
|
|
|
167
|
-
declare const IsExcluded: Trait<
|
|
168
|
+
declare const IsExcluded: Trait<{
|
|
169
|
+
[x: string]: string | number | bigint | boolean | (() => unknown) | null | undefined;
|
|
170
|
+
} | (() => unknown)>;
|
|
168
171
|
declare class Query {
|
|
169
172
|
version: number;
|
|
170
173
|
world: World;
|
|
@@ -243,7 +246,7 @@ declare class World {
|
|
|
243
246
|
add(...traits: ConfigurableTrait[]): void;
|
|
244
247
|
remove(...traits: Trait[]): void;
|
|
245
248
|
get<T extends Trait>(trait: T): TraitInstance<ExtractSchema<T>> | undefined;
|
|
246
|
-
set<T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>>): void;
|
|
249
|
+
set<T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> | SetTraitCallback<T>): void;
|
|
247
250
|
destroy(): void;
|
|
248
251
|
reset(): void;
|
|
249
252
|
query<T extends QueryParameter[]>(key: QueryHash<T>): QueryResult<T>;
|
|
@@ -260,4 +263,4 @@ declare class World {
|
|
|
260
263
|
}
|
|
261
264
|
declare function createWorld(...traits: ConfigurableTrait[]): World;
|
|
262
265
|
|
|
263
|
-
export { $internal as $, type AoSFactory as A, type ConfigurableTrait as C, type Entity as E, IsExcluded as I, ModifierData as M, type Norm as N, type QueryParameter as Q, type Relation as R, type Schema as S, type Trait as T, World as W, type QueryHash as a, type RelationTarget as b, type WildcardRelation as c, type ExtractStore as d, createWorld as e, type QueryModifier as f, type QuerySubscriber as g, type QueryUnsubscriber as h, type QueryResultOptions as i, type QueryResult as j, type StoresFromParameters as k, type InstancesFromParameters as l, type IsNotModifier as m, type TraitType as n, type TraitValue as o, type TraitTuple as p, type
|
|
266
|
+
export { $internal as $, type AoSFactory as A, type ConfigurableTrait as C, type Entity as E, IsExcluded as I, ModifierData as M, type Norm as N, type QueryParameter as Q, type Relation as R, type Schema as S, type Trait as T, World as W, type QueryHash as a, type RelationTarget as b, type WildcardRelation as c, type ExtractStore as d, createWorld as e, type QueryModifier as f, type QuerySubscriber as g, type QueryUnsubscriber as h, type QueryResultOptions as i, type QueryResult as j, type StoresFromParameters as k, type InstancesFromParameters as l, type IsNotModifier as m, type TraitType as n, type TraitValue as o, type TraitTuple as p, type SetTraitCallback as q, type TraitInstance as r, type Store as s, type ExtractSchema as t, type ExtractIsTag as u, type IsTag as v };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as src from 'src';
|
|
2
|
-
|
|
3
1
|
declare const $internal: unique symbol;
|
|
4
2
|
|
|
5
3
|
type IsEmpty<T> = T extends Record<string, never> ? true : false;
|
|
@@ -31,18 +29,21 @@ type ConfigurableTrait<T extends Trait = Trait> = T | TraitTuple<T>;
|
|
|
31
29
|
type TraitInstanceFromTrait<T extends Trait> = T['schema'] extends AoSFactory ? ReturnType<T['schema']> : {
|
|
32
30
|
[P in keyof T['schema']]: T['schema'][P] extends (...args: any[]) => any ? ReturnType<T['schema'][P]> : T['schema'][P];
|
|
33
31
|
};
|
|
32
|
+
type SetTraitCallback<T extends Trait> = (prev: TraitInstance<ExtractSchema<T>>) => TraitValue<ExtractSchema<T>>;
|
|
34
33
|
type TraitInstanceFromSchema<T extends Schema> = T extends AoSFactory ? ReturnType<T> : {
|
|
35
34
|
[P in keyof T]: T[P] extends (...args: any[]) => any ? ReturnType<T[P]> : T[P];
|
|
36
35
|
};
|
|
37
36
|
type TraitInstance<T extends Trait | Schema> = T extends Trait ? TraitInstanceFromTrait<T> : TraitInstanceFromSchema<T>;
|
|
38
37
|
type Schema = {
|
|
39
|
-
[key: string]: number | string | boolean |
|
|
38
|
+
[key: string]: number | bigint | string | boolean | null | undefined | (() => unknown);
|
|
40
39
|
} | AoSFactory;
|
|
41
|
-
type AoSFactory = () =>
|
|
40
|
+
type AoSFactory = () => unknown;
|
|
42
41
|
type Store<T extends Schema = any> = T extends AoSFactory ? ReturnType<T>[] : {
|
|
43
42
|
[P in keyof T]: T[P] extends (...args: any[]) => any ? ReturnType<T[P]>[] : T[P][];
|
|
44
43
|
};
|
|
45
44
|
type Norm<T extends Schema> = T extends AoSFactory ? () => ReturnType<T> extends number ? number : ReturnType<T> extends boolean ? boolean : ReturnType<T> extends string ? string : ReturnType<T> : {
|
|
45
|
+
[K in keyof T]: T[K] extends object ? T[K] extends (...args: any[]) => any ? T[K] : never : T[K] extends boolean ? boolean : T[K];
|
|
46
|
+
}[keyof T] extends never ? never : {
|
|
46
47
|
[K in keyof T]: T[K] extends boolean ? boolean : T[K];
|
|
47
48
|
};
|
|
48
49
|
type ExtractSchema<T extends Trait | Relation<Trait>> = T extends Relation<infer R> ? ExtractSchema<R> : T extends Trait<infer S> ? S : never;
|
|
@@ -77,7 +78,7 @@ type Entity = number & {
|
|
|
77
78
|
has: (trait: Trait) => boolean;
|
|
78
79
|
destroy: () => void;
|
|
79
80
|
changed: (trait: Trait) => void;
|
|
80
|
-
set: <T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> |
|
|
81
|
+
set: <T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> | SetTraitCallback<T>, flagChanged?: boolean) => void;
|
|
81
82
|
get: <T extends Trait | Relation<Trait>>(trait: T) => TraitInstance<ExtractSchema<T>> | undefined;
|
|
82
83
|
targetFor: <T extends Trait>(relation: Relation<T>) => Entity | undefined;
|
|
83
84
|
targetsFor: <T extends Trait>(relation: Relation<T>) => Entity[];
|
|
@@ -164,7 +165,9 @@ type QueryHash<T extends QueryParameter[]> = string & {
|
|
|
164
165
|
readonly [$parameters]: T;
|
|
165
166
|
};
|
|
166
167
|
|
|
167
|
-
declare const IsExcluded: Trait<
|
|
168
|
+
declare const IsExcluded: Trait<{
|
|
169
|
+
[x: string]: string | number | bigint | boolean | (() => unknown) | null | undefined;
|
|
170
|
+
} | (() => unknown)>;
|
|
168
171
|
declare class Query {
|
|
169
172
|
version: number;
|
|
170
173
|
world: World;
|
|
@@ -243,7 +246,7 @@ declare class World {
|
|
|
243
246
|
add(...traits: ConfigurableTrait[]): void;
|
|
244
247
|
remove(...traits: Trait[]): void;
|
|
245
248
|
get<T extends Trait>(trait: T): TraitInstance<ExtractSchema<T>> | undefined;
|
|
246
|
-
set<T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>>): void;
|
|
249
|
+
set<T extends Trait>(trait: T, value: TraitValue<ExtractSchema<T>> | SetTraitCallback<T>): void;
|
|
247
250
|
destroy(): void;
|
|
248
251
|
reset(): void;
|
|
249
252
|
query<T extends QueryParameter[]>(key: QueryHash<T>): QueryResult<T>;
|
|
@@ -260,4 +263,4 @@ declare class World {
|
|
|
260
263
|
}
|
|
261
264
|
declare function createWorld(...traits: ConfigurableTrait[]): World;
|
|
262
265
|
|
|
263
|
-
export { $internal as $, type AoSFactory as A, type ConfigurableTrait as C, type Entity as E, IsExcluded as I, ModifierData as M, type Norm as N, type QueryParameter as Q, type Relation as R, type Schema as S, type Trait as T, World as W, type QueryHash as a, type RelationTarget as b, type WildcardRelation as c, type ExtractStore as d, createWorld as e, type QueryModifier as f, type QuerySubscriber as g, type QueryUnsubscriber as h, type QueryResultOptions as i, type QueryResult as j, type StoresFromParameters as k, type InstancesFromParameters as l, type IsNotModifier as m, type TraitType as n, type TraitValue as o, type TraitTuple as p, type
|
|
266
|
+
export { $internal as $, type AoSFactory as A, type ConfigurableTrait as C, type Entity as E, IsExcluded as I, ModifierData as M, type Norm as N, type QueryParameter as Q, type Relation as R, type Schema as S, type Trait as T, World as W, type QueryHash as a, type RelationTarget as b, type WildcardRelation as c, type ExtractStore as d, createWorld as e, type QueryModifier as f, type QuerySubscriber as g, type QueryUnsubscriber as h, type QueryResultOptions as i, type QueryResult as j, type StoresFromParameters as k, type InstancesFromParameters as l, type IsNotModifier as m, type TraitType as n, type TraitValue as o, type TraitTuple as p, type SetTraitCallback as q, type TraitInstance as r, type Store as s, type ExtractSchema as t, type ExtractIsTag as u, type IsTag as v };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koota",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "🌎 Performant real-time state management for React and TypeScript",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@testing-library/react": "^16.2.0",
|
|
35
|
-
"esbuild-plugin-inline-functions": "^0.
|
|
35
|
+
"esbuild-plugin-inline-functions": "^0.2.0",
|
|
36
36
|
"react": ">=18.0.0",
|
|
37
37
|
"react-dom": ">=18.0.0",
|
|
38
38
|
"tsup": "^8.3.0",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
|
-
"build": "tsup &&
|
|
57
|
+
"build": "tsup && node --no-warnings scripts/copy-readme.ts && node --no-warnings scripts/copy-react-files.ts",
|
|
58
58
|
"test": "vitest --environment=jsdom",
|
|
59
|
-
"generate-tests": "
|
|
59
|
+
"generate-tests": "node scripts/generate-tests.ts"
|
|
60
60
|
},
|
|
61
61
|
"module": "./dist/index.js"
|
|
62
62
|
}
|
package/react/index.cjs
CHANGED
|
@@ -316,11 +316,23 @@ function createStore(schema) {
|
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
// ../core/src/trait/utils/validate-schema.ts
|
|
320
|
+
function validateSchema(schema) {
|
|
321
|
+
for (const key in schema) {
|
|
322
|
+
const value = schema[key];
|
|
323
|
+
if (value !== null && typeof value === "object") {
|
|
324
|
+
const kind = Array.isArray(value) ? "array" : "object";
|
|
325
|
+
throw new Error(`Koota: ${key} is an ${kind}, which is not supported in traits.`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
319
330
|
// ../core/src/trait/trait.ts
|
|
320
331
|
var traitId = 0;
|
|
321
332
|
function defineTrait(schema = {}) {
|
|
322
333
|
const isAoS = typeof schema === "function";
|
|
323
334
|
const traitType = isAoS ? "aos" : "soa";
|
|
335
|
+
validateSchema(schema);
|
|
324
336
|
const Trait = Object.assign((params) => [Trait, params], {
|
|
325
337
|
schema,
|
|
326
338
|
[$internal]: {
|
|
@@ -486,6 +498,13 @@ function removeTrait(world, entity, ...traits) {
|
|
|
486
498
|
if (otherTargets.length === 0) {
|
|
487
499
|
removeTrait(world, entity, Pair(relation2, Wildcard));
|
|
488
500
|
}
|
|
501
|
+
if (traitCtx.isPairTrait && traitCtx.pairTarget === Wildcard && traitCtx.relation !== Wildcard) {
|
|
502
|
+
const relation3 = traitCtx.relation;
|
|
503
|
+
const targets = getRelationTargets(world, relation3, entity);
|
|
504
|
+
for (const target2 of targets) {
|
|
505
|
+
removeTrait(world, entity, relation3(target2));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
489
508
|
}
|
|
490
509
|
}
|
|
491
510
|
}
|
package/react/index.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait,
|
|
1
|
+
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait, r as TraitInstance } from '../dist/world-DzIKt3Qf.cjs';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import 'src';
|
|
4
3
|
|
|
5
4
|
declare function useActions<T extends Record<string, (...args: any[]) => any>>(actions: (world: World) => T): T;
|
|
6
5
|
|
package/react/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait,
|
|
1
|
+
import { W as World, Q as QueryParameter, j as QueryResult, E as Entity, T as Trait, r as TraitInstance } from '../dist/world-DzIKt3Qf.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
-
import 'src';
|
|
4
3
|
|
|
5
4
|
declare function useActions<T extends Record<string, (...args: any[]) => any>>(actions: (world: World) => T): T;
|
|
6
5
|
|