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 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
- A trait is a specific block of data. They are added to entities to build up its overall data signature. If you are familiar with ECS, it is our version of a component. It is called a trait instead to not get confused with React or web components.
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 be initialized for each instance of the trait created, a callback can be passed in to be used a as a lazy initializer.
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
- // ❌ The items array will be shared between every instance of this trait
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
- // ✅ With a lazy initializer, each instance will now get its own array
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-CbC1N0VY.cjs';
2
- export { $ as $internal, A as AoSFactory, C as ConfigurableTrait, t as ExtractIsTag, s as ExtractSchema, l as InstancesFromParameters, I as IsExcluded, m as IsNotModifier, u as IsTag, f as QueryModifier, j as QueryResult, i as QueryResultOptions, g as QuerySubscriber, h as QueryUnsubscriber, r as Store, k as StoresFromParameters, q as TraitInstance, p as TraitTuple, n as TraitType, o as TraitValue, e as createWorld } from './world-CbC1N0VY.cjs';
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<Schema>;
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-CbC1N0VY.js';
2
- export { $ as $internal, A as AoSFactory, C as ConfigurableTrait, t as ExtractIsTag, s as ExtractSchema, l as InstancesFromParameters, I as IsExcluded, m as IsNotModifier, u as IsTag, f as QueryModifier, j as QueryResult, i as QueryResultOptions, g as QuerySubscriber, h as QueryUnsubscriber, r as Store, k as StoresFromParameters, q as TraitInstance, p as TraitTuple, n as TraitType, o as TraitValue, e as createWorld } from './world-CbC1N0VY.js';
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<Schema>;
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
@@ -17,7 +17,7 @@ import {
17
17
  trait,
18
18
  universe,
19
19
  unpackEntity
20
- } from "./chunk-6HKEF2RH.js";
20
+ } from "./chunk-KLYFWWYD.js";
21
21
  export {
22
22
  $internal,
23
23
  IsExcluded,
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, q as TraitInstance } from './world-CbC1N0VY.cjs';
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, q as TraitInstance } from './world-CbC1N0VY.js';
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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  $internal,
4
4
  cacheQuery
5
- } from "./chunk-6HKEF2RH.js";
5
+ } from "./chunk-KLYFWWYD.js";
6
6
 
7
7
  // ../react/src/world/use-world.ts
8
8
  import { useContext } from "react";
@@ -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 | any[] | object | null | undefined;
38
+ [key: string]: number | bigint | string | boolean | null | undefined | (() => unknown);
40
39
  } | AoSFactory;
41
- type AoSFactory = () => Record<string, any>;
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>> | ((prev: TraitInstance<ExtractSchema<T>>) => TraitValue<ExtractSchema<T>>), flagChanged?: boolean) => void;
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<src.Schema>;
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 TraitInstance as q, type Store as r, type ExtractSchema as s, type ExtractIsTag as t, type IsTag as u };
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 | any[] | object | null | undefined;
38
+ [key: string]: number | bigint | string | boolean | null | undefined | (() => unknown);
40
39
  } | AoSFactory;
41
- type AoSFactory = () => Record<string, any>;
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>> | ((prev: TraitInstance<ExtractSchema<T>>) => TraitValue<ExtractSchema<T>>), flagChanged?: boolean) => void;
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<src.Schema>;
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 TraitInstance as q, type Store as r, type ExtractSchema as s, type ExtractIsTag as t, type IsTag as u };
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.4.3",
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.1.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 && tsx scripts/copy-readme.ts && tsx scripts/copy-react-files.ts",
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": "tsx scripts/generate-tests.ts"
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, q as TraitInstance } from '../dist/world-CbC1N0VY.cjs';
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, q as TraitInstance } from '../dist/world-CbC1N0VY.js';
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
 
package/react/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  $internal,
4
4
  cacheQuery
5
- } from "../dist/chunk-6HKEF2RH.js";
5
+ } from "../dist/chunk-KLYFWWYD.js";
6
6
 
7
7
  // ../react/src/world/use-world.ts
8
8
  import { useContext } from "react";