@axi-engine/fields 0.2.0 → 0.2.2
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/index.d.mts +100 -50
- package/dist/index.d.ts +100 -50
- package/dist/index.js +106 -27
- package/dist/index.mjs +106 -28
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -330,6 +330,7 @@ declare class Fields {
|
|
|
330
330
|
* Removes all fields from the collection, ensuring each is properly destroyed.
|
|
331
331
|
*/
|
|
332
332
|
clear(): void;
|
|
333
|
+
destroy(): void;
|
|
333
334
|
}
|
|
334
335
|
|
|
335
336
|
declare const DefaultFields_base: {
|
|
@@ -355,6 +356,7 @@ declare const DefaultFields_base: {
|
|
|
355
356
|
get<T extends Field<any>>(name: string): T;
|
|
356
357
|
remove(names: string | string[]): void;
|
|
357
358
|
clear(): void;
|
|
359
|
+
destroy(): void;
|
|
358
360
|
};
|
|
359
361
|
} & {
|
|
360
362
|
new (...args: any[]): {
|
|
@@ -379,6 +381,7 @@ declare const DefaultFields_base: {
|
|
|
379
381
|
get<T extends Field<any>>(name: string): T;
|
|
380
382
|
remove(names: string | string[]): void;
|
|
381
383
|
clear(): void;
|
|
384
|
+
destroy(): void;
|
|
382
385
|
};
|
|
383
386
|
} & {
|
|
384
387
|
new (...args: any[]): {
|
|
@@ -403,11 +406,13 @@ declare const DefaultFields_base: {
|
|
|
403
406
|
get<T extends Field<any>>(name: string): T;
|
|
404
407
|
remove(names: string | string[]): void;
|
|
405
408
|
clear(): void;
|
|
409
|
+
destroy(): void;
|
|
406
410
|
};
|
|
407
411
|
} & {
|
|
408
412
|
new (...args: any[]): {
|
|
409
|
-
|
|
410
|
-
|
|
413
|
+
createGeneric<T>(name: string, initialValue: T, options?: FieldOptions<T> | undefined): DefaultField<T>;
|
|
414
|
+
upsetGeneric<T>(name: string, value: T, options?: FieldOptions<T> | undefined): DefaultField<T>;
|
|
415
|
+
getGeneric<T>(name: string): DefaultField<T>;
|
|
411
416
|
readonly typeName: "fields";
|
|
412
417
|
readonly _fields: Map<string, Field<any>>;
|
|
413
418
|
readonly _fieldRegistry: FieldRegistry;
|
|
@@ -426,31 +431,38 @@ declare const DefaultFields_base: {
|
|
|
426
431
|
get<T extends Field<any>>(name: string): T;
|
|
427
432
|
remove(names: string | string[]): void;
|
|
428
433
|
clear(): void;
|
|
434
|
+
destroy(): void;
|
|
429
435
|
};
|
|
430
436
|
} & typeof Fields;
|
|
431
437
|
declare class DefaultFields extends DefaultFields_base {
|
|
432
438
|
}
|
|
433
439
|
|
|
440
|
+
interface FieldsFactory<TFields extends Fields> {
|
|
441
|
+
fields(): TFields;
|
|
442
|
+
}
|
|
443
|
+
declare class DefaultFieldsFactory implements FieldsFactory<DefaultFields> {
|
|
444
|
+
private readonly fieldRegistry;
|
|
445
|
+
constructor(fieldRegistry: FieldRegistry);
|
|
446
|
+
fields(): DefaultFields;
|
|
447
|
+
}
|
|
434
448
|
/**
|
|
435
449
|
* Defines the contract for a factory that creates nodes for a FieldTree.
|
|
436
450
|
* This allows for custom implementations of Fields and FieldTree to be used.
|
|
437
451
|
*/
|
|
438
|
-
interface TreeNodeFactory {
|
|
439
|
-
fields
|
|
440
|
-
tree
|
|
452
|
+
interface TreeNodeFactory<TFields extends Fields> extends FieldsFactory<TFields> {
|
|
453
|
+
fields(): TFields;
|
|
454
|
+
tree(): FieldTree<TFields>;
|
|
441
455
|
}
|
|
442
456
|
/**
|
|
443
457
|
* The default factory implementation that creates standard DefaultFields and FieldTree instances.
|
|
444
458
|
*/
|
|
445
|
-
declare class DefaultTreeNodeFactory implements TreeNodeFactory {
|
|
446
|
-
private readonly fieldRegistry;
|
|
459
|
+
declare class DefaultTreeNodeFactory extends DefaultFieldsFactory implements TreeNodeFactory<DefaultFields> {
|
|
447
460
|
constructor(fieldRegistry: FieldRegistry);
|
|
448
|
-
|
|
449
|
-
tree: () => any;
|
|
461
|
+
tree(): FieldTree<DefaultFields>;
|
|
450
462
|
}
|
|
451
463
|
|
|
452
464
|
/** A type alias for any container that can be a child node in a FieldTree */
|
|
453
|
-
type
|
|
465
|
+
type TreeNode<F extends Fields> = FieldTree<F> | F;
|
|
454
466
|
/**
|
|
455
467
|
* Represents a hierarchical data structure for managing the global state of the system.
|
|
456
468
|
*
|
|
@@ -459,26 +471,51 @@ type TreeOrFieldsNode = FieldTree | Fields;
|
|
|
459
471
|
* and overall game progress. It uses a path-based system for accessing and
|
|
460
472
|
* manipulating nested data, similar to a file system.
|
|
461
473
|
*
|
|
462
|
-
* @todo
|
|
463
|
-
* - Add node removal functionality.
|
|
464
|
-
* - Implement an event system for node creation/removal.
|
|
465
474
|
*/
|
|
466
|
-
declare class FieldTree {
|
|
475
|
+
declare class FieldTree<TFields extends Fields> {
|
|
467
476
|
static readonly typeName = "fieldTree";
|
|
468
477
|
readonly typeName = "fieldTree";
|
|
469
478
|
/** @private The internal map storing child nodes (branches or leaves). */
|
|
470
479
|
private readonly _nodes;
|
|
471
480
|
/** @private The factory used to create new child nodes. */
|
|
472
481
|
private readonly _factory;
|
|
482
|
+
/**
|
|
483
|
+
* An event emitter that fires immediately after a new node is added to this tree branch.
|
|
484
|
+
* @event
|
|
485
|
+
* @param {object} event - The event payload.
|
|
486
|
+
* @param {string} event.name - The name (key) of the added node.
|
|
487
|
+
* @param event.node - The node instance that was added.
|
|
488
|
+
* @example
|
|
489
|
+
* myTree.onAdd.subscribe(({ name, node }) => {
|
|
490
|
+
* console.log(`Node '${name}' was added.`, node);
|
|
491
|
+
* });
|
|
492
|
+
*/
|
|
493
|
+
onAdd: Emitter<[event: {
|
|
494
|
+
name: string;
|
|
495
|
+
node: TreeNode<TFields>;
|
|
496
|
+
}]>;
|
|
497
|
+
/**
|
|
498
|
+
* An event emitter that fires once after one or more nodes have been successfully removed.
|
|
499
|
+
* @event
|
|
500
|
+
* @param {object} event - The event payload.
|
|
501
|
+
* @param {string[]} event.names - An array of names of the nodes that were removed.
|
|
502
|
+
* @example
|
|
503
|
+
* myTree.onRemove.subscribe(({ names }) => {
|
|
504
|
+
* console.log(`Nodes removed: ${names.join(', ')}`);
|
|
505
|
+
* });
|
|
506
|
+
*/
|
|
507
|
+
onRemove: Emitter<[event: {
|
|
508
|
+
names: string[];
|
|
509
|
+
}]>;
|
|
473
510
|
/**
|
|
474
511
|
* Gets the collection of direct child nodes of this tree branch.
|
|
475
512
|
*/
|
|
476
|
-
get nodes(): Map<string,
|
|
513
|
+
get nodes(): Map<string, TreeNode<TFields>>;
|
|
477
514
|
/**
|
|
478
515
|
* Creates an instance of FieldTree.
|
|
479
516
|
* @param {TreeNodeFactory} factory - A factory responsible for creating new nodes within the tree.
|
|
480
517
|
*/
|
|
481
|
-
constructor(factory: TreeNodeFactory);
|
|
518
|
+
constructor(factory: TreeNodeFactory<TFields>);
|
|
482
519
|
/**
|
|
483
520
|
* Checks if a direct child node with the given name exists.
|
|
484
521
|
* @param {string} name - The name of the direct child node.
|
|
@@ -494,18 +531,29 @@ declare class FieldTree {
|
|
|
494
531
|
/**
|
|
495
532
|
* Adds a pre-existing node as a direct child of this tree branch.
|
|
496
533
|
* @param {string} name - The name to assign to the new child node.
|
|
497
|
-
* @param {
|
|
498
|
-
* @returns {
|
|
534
|
+
* @param {TreeNode} node - The node instance to add.
|
|
535
|
+
* @returns {TreeNode} The added node.
|
|
499
536
|
* @throws If a node with the same name already exists.
|
|
500
537
|
*/
|
|
501
|
-
addNode(name: string, node:
|
|
538
|
+
addNode(name: string, node: TreeNode<TFields>): TreeNode<TFields>;
|
|
502
539
|
/**
|
|
503
540
|
* Retrieves a direct child node by its name.
|
|
504
541
|
* @param {string} name - The name of the child node.
|
|
505
|
-
* @returns {
|
|
542
|
+
* @returns {TreeNode} The retrieved node.
|
|
506
543
|
* @throws If a node with the given name cannot be found.
|
|
507
544
|
*/
|
|
508
|
-
getNode(name: string):
|
|
545
|
+
getNode(name: string): TreeNode<TFields>;
|
|
546
|
+
/**
|
|
547
|
+
* Removes one or more nodes from this tree branch.
|
|
548
|
+
*
|
|
549
|
+
* This method first validates that all specified nodes exist. If validation passes,
|
|
550
|
+
* it recursively calls `destroy()` on each node to ensure proper cleanup of the entire subtree.
|
|
551
|
+
* Finally, it emits a single `onRemove` event with the names of all successfully removed nodes.
|
|
552
|
+
*
|
|
553
|
+
* @param {string | string[]} names - A single name or an array of names of the nodes to remove.
|
|
554
|
+
* @throws If any of the specified names do not correspond to an existing node.
|
|
555
|
+
*/
|
|
556
|
+
removeNode(names: string | string[]): void;
|
|
509
557
|
/**
|
|
510
558
|
* Creates a new `FieldTree` (branch) node at the specified path.
|
|
511
559
|
* @param {PathType} path - The path where the new `FieldTree` should be created.
|
|
@@ -513,7 +561,7 @@ declare class FieldTree {
|
|
|
513
561
|
* @returns {FieldTree} The newly created `FieldTree` instance.
|
|
514
562
|
* @throws If the path is invalid or a node already exists at the target location.
|
|
515
563
|
*/
|
|
516
|
-
createFieldTree<T extends FieldTree
|
|
564
|
+
createFieldTree<T extends FieldTree<TFields>>(path: PathType, createPath?: boolean): T;
|
|
517
565
|
/**
|
|
518
566
|
* Creates a new `Fields` (leaf) container at the specified path.
|
|
519
567
|
* @param {PathType} path - The path where the new `Fields` container should be created.
|
|
@@ -521,33 +569,47 @@ declare class FieldTree {
|
|
|
521
569
|
* @returns {Fields} The newly created `Fields` instance.
|
|
522
570
|
* @throws If the path is invalid or a node already exists at the target location.
|
|
523
571
|
*/
|
|
524
|
-
createFields
|
|
572
|
+
createFields(path: PathType, createPath?: boolean): TFields;
|
|
525
573
|
/**
|
|
526
574
|
* Retrieves a `FieldTree` (branch) node from a specified path.
|
|
527
575
|
* @param {PathType} path - The path to the `FieldTree` node.
|
|
528
576
|
* @returns {FieldTree} The `FieldTree` instance at the specified path.
|
|
529
577
|
* @throws If the path is invalid or the node at the path is not a `FieldTree`.
|
|
530
578
|
*/
|
|
531
|
-
getFieldTree(path: PathType): FieldTree
|
|
579
|
+
getFieldTree(path: PathType): FieldTree<TFields>;
|
|
532
580
|
/**
|
|
533
581
|
* Retrieves a `Fields` (leaf) container from a specified path.
|
|
534
582
|
* @param {PathType} path - The path to the `Fields` container.
|
|
535
583
|
* @returns {Fields} The `Fields` instance at the specified path.
|
|
536
584
|
* @throws If the path is invalid or the node at the path is not a `Fields` container.
|
|
537
585
|
*/
|
|
538
|
-
getFields(path: PathType):
|
|
586
|
+
getFields(path: PathType): TFields;
|
|
539
587
|
/**
|
|
540
588
|
* Retrieves a `FieldTree` at the specified path. If it or any part of the path doesn't exist, it will be created.
|
|
541
589
|
* @param {PathType} path - The path to the `FieldTree` node.
|
|
542
590
|
* @returns {FieldTree} The existing or newly created `FieldTree` instance.
|
|
543
591
|
*/
|
|
544
|
-
getOrCreateFieldTree(path: PathType): FieldTree
|
|
592
|
+
getOrCreateFieldTree(path: PathType): FieldTree<TFields>;
|
|
545
593
|
/**
|
|
546
594
|
* Retrieves a `Fields` container at the specified path. If it or any part of the path doesn't exist, it will be created.
|
|
547
595
|
* @param {PathType} path - The path to the `Fields` container.
|
|
548
596
|
* @returns {Fields} The existing or newly created `Fields` instance.
|
|
549
597
|
*/
|
|
550
598
|
getOrCreateFields(path: PathType): Fields;
|
|
599
|
+
/**
|
|
600
|
+
* Removes all child nodes from this tree branch.
|
|
601
|
+
* This method ensures that `destroy()` is called on each child node, allowing for
|
|
602
|
+
* a full, recursive cleanup of the entire subtree.
|
|
603
|
+
*/
|
|
604
|
+
clear(): void;
|
|
605
|
+
/**
|
|
606
|
+
* Performs a complete cleanup of this node and its entire subtree.
|
|
607
|
+
*
|
|
608
|
+
* It recursively destroys all child nodes by calling `clear()` and then
|
|
609
|
+
* unsubscribes all listeners from its own event emitters.
|
|
610
|
+
* This method should be called when a node is no longer needed.
|
|
611
|
+
*/
|
|
612
|
+
destroy(): void;
|
|
551
613
|
/**
|
|
552
614
|
* @private
|
|
553
615
|
* Navigates the tree to the parent of a target node.
|
|
@@ -699,30 +761,19 @@ interface FieldsSnapshot {
|
|
|
699
761
|
* into a storable snapshot and back.
|
|
700
762
|
* It delegates the actual serialization of each `Field` and `Policy` to their respective serializers.
|
|
701
763
|
*
|
|
702
|
-
* @todo This implementation is coupled to creating `DefaultFields` instances during hydration.
|
|
703
|
-
* To make the system fully extensible, this class should be refactored to use a
|
|
704
|
-
* `FieldsRegistry` (a `ConstructorRegistry<Fields>`). This would allow it to
|
|
705
|
-
* hydrate any custom `Fields` class (e.g., `ReactiveFields`) based on the `__type`
|
|
706
|
-
* property in the snapshot, mirroring the pattern used by `FieldSerializer`.
|
|
707
|
-
*
|
|
708
764
|
* @todo Implement a `patch(fields, snapshot)` method. It should perform a non-destructive
|
|
709
765
|
* update, creating new fields, removing missing ones, and patching existing ones
|
|
710
766
|
* in place, preserving the container instance itself.
|
|
711
767
|
*/
|
|
712
|
-
declare class FieldsSerializer {
|
|
713
|
-
private readonly
|
|
714
|
-
private readonly policySerializer;
|
|
715
|
-
/**
|
|
716
|
-
* An internal instance of FieldSerializer to handle individual fields.
|
|
717
|
-
* @private
|
|
718
|
-
*/
|
|
768
|
+
declare class FieldsSerializer<TFields extends Fields> {
|
|
769
|
+
private readonly fieldsFactory;
|
|
719
770
|
private readonly fieldSerializer;
|
|
720
771
|
/**
|
|
721
772
|
* Creates an instance of FieldsSerializer.
|
|
722
|
-
* @param {
|
|
723
|
-
* @param {
|
|
773
|
+
* @param {FieldsFactory} fieldsFactory - A registry that maps string type names to Field constructors.
|
|
774
|
+
* @param {FieldSerializer} fieldSerializer - A serializer of field instances.
|
|
724
775
|
*/
|
|
725
|
-
constructor(
|
|
776
|
+
constructor(fieldsFactory: FieldsFactory<TFields>, fieldSerializer: FieldSerializer);
|
|
726
777
|
/**
|
|
727
778
|
* Creates a serializable snapshot of a `Fields` container.
|
|
728
779
|
*
|
|
@@ -735,12 +786,11 @@ declare class FieldsSerializer {
|
|
|
735
786
|
/**
|
|
736
787
|
* Restores a `Fields` container instance from its snapshot representation.
|
|
737
788
|
*
|
|
738
|
-
* **Limitation:** This method is currently hardcoded to always create an instance of `DefaultFields`.
|
|
739
789
|
* It iterates through the field snapshots and hydrates them individually, adding them to the new container.
|
|
740
790
|
* @param {FieldsSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
741
|
-
* @returns {
|
|
791
|
+
* @returns {Fields} A new `DefaultFields` instance populated with the restored fields.
|
|
742
792
|
*/
|
|
743
|
-
hydrate(snapshot: FieldsSnapshot):
|
|
793
|
+
hydrate(snapshot: FieldsSnapshot): TFields;
|
|
744
794
|
}
|
|
745
795
|
|
|
746
796
|
/**
|
|
@@ -772,21 +822,21 @@ interface FieldTreeSnapshot {
|
|
|
772
822
|
* updates. This method should traverse the existing tree and the snapshot,
|
|
773
823
|
* patching nodes in place to maintain object references.
|
|
774
824
|
*/
|
|
775
|
-
declare class FieldTreeSerializer {
|
|
825
|
+
declare class FieldTreeSerializer<TFields extends Fields> {
|
|
776
826
|
private readonly fieldTreeNodeFactory;
|
|
777
827
|
private readonly fieldsSerializer;
|
|
778
|
-
constructor(fieldTreeNodeFactory: TreeNodeFactory
|
|
828
|
+
constructor(fieldTreeNodeFactory: TreeNodeFactory<TFields>, fieldsSerializer: FieldsSerializer<TFields>);
|
|
779
829
|
/**
|
|
780
830
|
* Creates a serializable snapshot of the entire tree and its contained fields.
|
|
781
831
|
* @returns A plain JavaScript object representing the complete state managed by this tree.
|
|
782
832
|
*/
|
|
783
|
-
snapshot(tree: FieldTree): FieldTreeSnapshot;
|
|
833
|
+
snapshot(tree: FieldTree<TFields>): FieldTreeSnapshot;
|
|
784
834
|
/**
|
|
785
835
|
* Restores the state of the tree from a snapshot.
|
|
786
836
|
* It intelligently creates missing nodes based on `__type` metadata and delegates hydration to child nodes.
|
|
787
837
|
* @param snapshot The snapshot object to load.
|
|
788
838
|
*/
|
|
789
|
-
hydrate(snapshot: FieldTreeSnapshot): FieldTree
|
|
839
|
+
hydrate(snapshot: FieldTreeSnapshot): FieldTree<TFields>;
|
|
790
840
|
}
|
|
791
841
|
|
|
792
|
-
export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, DefaultBooleanField, type DefaultBooleanFieldOptions, DefaultField, DefaultFields, DefaultNumericField, type DefaultNumericFieldOptions, DefaultStringField, type DefaultStringFieldOptions, DefaultTreeNodeFactory, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, FieldTreeSerializer, type FieldTreeSnapshot, Fields, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type StringField, type
|
|
842
|
+
export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, DefaultBooleanField, type DefaultBooleanFieldOptions, DefaultField, DefaultFields, DefaultFieldsFactory, DefaultNumericField, type DefaultNumericFieldOptions, DefaultStringField, type DefaultStringFieldOptions, DefaultTreeNodeFactory, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type StringField, type TreeNode, type TreeNodeFactory, clampMaxPolicy, clampMinPolicy, clampPolicy };
|
package/dist/index.d.ts
CHANGED
|
@@ -330,6 +330,7 @@ declare class Fields {
|
|
|
330
330
|
* Removes all fields from the collection, ensuring each is properly destroyed.
|
|
331
331
|
*/
|
|
332
332
|
clear(): void;
|
|
333
|
+
destroy(): void;
|
|
333
334
|
}
|
|
334
335
|
|
|
335
336
|
declare const DefaultFields_base: {
|
|
@@ -355,6 +356,7 @@ declare const DefaultFields_base: {
|
|
|
355
356
|
get<T extends Field<any>>(name: string): T;
|
|
356
357
|
remove(names: string | string[]): void;
|
|
357
358
|
clear(): void;
|
|
359
|
+
destroy(): void;
|
|
358
360
|
};
|
|
359
361
|
} & {
|
|
360
362
|
new (...args: any[]): {
|
|
@@ -379,6 +381,7 @@ declare const DefaultFields_base: {
|
|
|
379
381
|
get<T extends Field<any>>(name: string): T;
|
|
380
382
|
remove(names: string | string[]): void;
|
|
381
383
|
clear(): void;
|
|
384
|
+
destroy(): void;
|
|
382
385
|
};
|
|
383
386
|
} & {
|
|
384
387
|
new (...args: any[]): {
|
|
@@ -403,11 +406,13 @@ declare const DefaultFields_base: {
|
|
|
403
406
|
get<T extends Field<any>>(name: string): T;
|
|
404
407
|
remove(names: string | string[]): void;
|
|
405
408
|
clear(): void;
|
|
409
|
+
destroy(): void;
|
|
406
410
|
};
|
|
407
411
|
} & {
|
|
408
412
|
new (...args: any[]): {
|
|
409
|
-
|
|
410
|
-
|
|
413
|
+
createGeneric<T>(name: string, initialValue: T, options?: FieldOptions<T> | undefined): DefaultField<T>;
|
|
414
|
+
upsetGeneric<T>(name: string, value: T, options?: FieldOptions<T> | undefined): DefaultField<T>;
|
|
415
|
+
getGeneric<T>(name: string): DefaultField<T>;
|
|
411
416
|
readonly typeName: "fields";
|
|
412
417
|
readonly _fields: Map<string, Field<any>>;
|
|
413
418
|
readonly _fieldRegistry: FieldRegistry;
|
|
@@ -426,31 +431,38 @@ declare const DefaultFields_base: {
|
|
|
426
431
|
get<T extends Field<any>>(name: string): T;
|
|
427
432
|
remove(names: string | string[]): void;
|
|
428
433
|
clear(): void;
|
|
434
|
+
destroy(): void;
|
|
429
435
|
};
|
|
430
436
|
} & typeof Fields;
|
|
431
437
|
declare class DefaultFields extends DefaultFields_base {
|
|
432
438
|
}
|
|
433
439
|
|
|
440
|
+
interface FieldsFactory<TFields extends Fields> {
|
|
441
|
+
fields(): TFields;
|
|
442
|
+
}
|
|
443
|
+
declare class DefaultFieldsFactory implements FieldsFactory<DefaultFields> {
|
|
444
|
+
private readonly fieldRegistry;
|
|
445
|
+
constructor(fieldRegistry: FieldRegistry);
|
|
446
|
+
fields(): DefaultFields;
|
|
447
|
+
}
|
|
434
448
|
/**
|
|
435
449
|
* Defines the contract for a factory that creates nodes for a FieldTree.
|
|
436
450
|
* This allows for custom implementations of Fields and FieldTree to be used.
|
|
437
451
|
*/
|
|
438
|
-
interface TreeNodeFactory {
|
|
439
|
-
fields
|
|
440
|
-
tree
|
|
452
|
+
interface TreeNodeFactory<TFields extends Fields> extends FieldsFactory<TFields> {
|
|
453
|
+
fields(): TFields;
|
|
454
|
+
tree(): FieldTree<TFields>;
|
|
441
455
|
}
|
|
442
456
|
/**
|
|
443
457
|
* The default factory implementation that creates standard DefaultFields and FieldTree instances.
|
|
444
458
|
*/
|
|
445
|
-
declare class DefaultTreeNodeFactory implements TreeNodeFactory {
|
|
446
|
-
private readonly fieldRegistry;
|
|
459
|
+
declare class DefaultTreeNodeFactory extends DefaultFieldsFactory implements TreeNodeFactory<DefaultFields> {
|
|
447
460
|
constructor(fieldRegistry: FieldRegistry);
|
|
448
|
-
|
|
449
|
-
tree: () => any;
|
|
461
|
+
tree(): FieldTree<DefaultFields>;
|
|
450
462
|
}
|
|
451
463
|
|
|
452
464
|
/** A type alias for any container that can be a child node in a FieldTree */
|
|
453
|
-
type
|
|
465
|
+
type TreeNode<F extends Fields> = FieldTree<F> | F;
|
|
454
466
|
/**
|
|
455
467
|
* Represents a hierarchical data structure for managing the global state of the system.
|
|
456
468
|
*
|
|
@@ -459,26 +471,51 @@ type TreeOrFieldsNode = FieldTree | Fields;
|
|
|
459
471
|
* and overall game progress. It uses a path-based system for accessing and
|
|
460
472
|
* manipulating nested data, similar to a file system.
|
|
461
473
|
*
|
|
462
|
-
* @todo
|
|
463
|
-
* - Add node removal functionality.
|
|
464
|
-
* - Implement an event system for node creation/removal.
|
|
465
474
|
*/
|
|
466
|
-
declare class FieldTree {
|
|
475
|
+
declare class FieldTree<TFields extends Fields> {
|
|
467
476
|
static readonly typeName = "fieldTree";
|
|
468
477
|
readonly typeName = "fieldTree";
|
|
469
478
|
/** @private The internal map storing child nodes (branches or leaves). */
|
|
470
479
|
private readonly _nodes;
|
|
471
480
|
/** @private The factory used to create new child nodes. */
|
|
472
481
|
private readonly _factory;
|
|
482
|
+
/**
|
|
483
|
+
* An event emitter that fires immediately after a new node is added to this tree branch.
|
|
484
|
+
* @event
|
|
485
|
+
* @param {object} event - The event payload.
|
|
486
|
+
* @param {string} event.name - The name (key) of the added node.
|
|
487
|
+
* @param event.node - The node instance that was added.
|
|
488
|
+
* @example
|
|
489
|
+
* myTree.onAdd.subscribe(({ name, node }) => {
|
|
490
|
+
* console.log(`Node '${name}' was added.`, node);
|
|
491
|
+
* });
|
|
492
|
+
*/
|
|
493
|
+
onAdd: Emitter<[event: {
|
|
494
|
+
name: string;
|
|
495
|
+
node: TreeNode<TFields>;
|
|
496
|
+
}]>;
|
|
497
|
+
/**
|
|
498
|
+
* An event emitter that fires once after one or more nodes have been successfully removed.
|
|
499
|
+
* @event
|
|
500
|
+
* @param {object} event - The event payload.
|
|
501
|
+
* @param {string[]} event.names - An array of names of the nodes that were removed.
|
|
502
|
+
* @example
|
|
503
|
+
* myTree.onRemove.subscribe(({ names }) => {
|
|
504
|
+
* console.log(`Nodes removed: ${names.join(', ')}`);
|
|
505
|
+
* });
|
|
506
|
+
*/
|
|
507
|
+
onRemove: Emitter<[event: {
|
|
508
|
+
names: string[];
|
|
509
|
+
}]>;
|
|
473
510
|
/**
|
|
474
511
|
* Gets the collection of direct child nodes of this tree branch.
|
|
475
512
|
*/
|
|
476
|
-
get nodes(): Map<string,
|
|
513
|
+
get nodes(): Map<string, TreeNode<TFields>>;
|
|
477
514
|
/**
|
|
478
515
|
* Creates an instance of FieldTree.
|
|
479
516
|
* @param {TreeNodeFactory} factory - A factory responsible for creating new nodes within the tree.
|
|
480
517
|
*/
|
|
481
|
-
constructor(factory: TreeNodeFactory);
|
|
518
|
+
constructor(factory: TreeNodeFactory<TFields>);
|
|
482
519
|
/**
|
|
483
520
|
* Checks if a direct child node with the given name exists.
|
|
484
521
|
* @param {string} name - The name of the direct child node.
|
|
@@ -494,18 +531,29 @@ declare class FieldTree {
|
|
|
494
531
|
/**
|
|
495
532
|
* Adds a pre-existing node as a direct child of this tree branch.
|
|
496
533
|
* @param {string} name - The name to assign to the new child node.
|
|
497
|
-
* @param {
|
|
498
|
-
* @returns {
|
|
534
|
+
* @param {TreeNode} node - The node instance to add.
|
|
535
|
+
* @returns {TreeNode} The added node.
|
|
499
536
|
* @throws If a node with the same name already exists.
|
|
500
537
|
*/
|
|
501
|
-
addNode(name: string, node:
|
|
538
|
+
addNode(name: string, node: TreeNode<TFields>): TreeNode<TFields>;
|
|
502
539
|
/**
|
|
503
540
|
* Retrieves a direct child node by its name.
|
|
504
541
|
* @param {string} name - The name of the child node.
|
|
505
|
-
* @returns {
|
|
542
|
+
* @returns {TreeNode} The retrieved node.
|
|
506
543
|
* @throws If a node with the given name cannot be found.
|
|
507
544
|
*/
|
|
508
|
-
getNode(name: string):
|
|
545
|
+
getNode(name: string): TreeNode<TFields>;
|
|
546
|
+
/**
|
|
547
|
+
* Removes one or more nodes from this tree branch.
|
|
548
|
+
*
|
|
549
|
+
* This method first validates that all specified nodes exist. If validation passes,
|
|
550
|
+
* it recursively calls `destroy()` on each node to ensure proper cleanup of the entire subtree.
|
|
551
|
+
* Finally, it emits a single `onRemove` event with the names of all successfully removed nodes.
|
|
552
|
+
*
|
|
553
|
+
* @param {string | string[]} names - A single name or an array of names of the nodes to remove.
|
|
554
|
+
* @throws If any of the specified names do not correspond to an existing node.
|
|
555
|
+
*/
|
|
556
|
+
removeNode(names: string | string[]): void;
|
|
509
557
|
/**
|
|
510
558
|
* Creates a new `FieldTree` (branch) node at the specified path.
|
|
511
559
|
* @param {PathType} path - The path where the new `FieldTree` should be created.
|
|
@@ -513,7 +561,7 @@ declare class FieldTree {
|
|
|
513
561
|
* @returns {FieldTree} The newly created `FieldTree` instance.
|
|
514
562
|
* @throws If the path is invalid or a node already exists at the target location.
|
|
515
563
|
*/
|
|
516
|
-
createFieldTree<T extends FieldTree
|
|
564
|
+
createFieldTree<T extends FieldTree<TFields>>(path: PathType, createPath?: boolean): T;
|
|
517
565
|
/**
|
|
518
566
|
* Creates a new `Fields` (leaf) container at the specified path.
|
|
519
567
|
* @param {PathType} path - The path where the new `Fields` container should be created.
|
|
@@ -521,33 +569,47 @@ declare class FieldTree {
|
|
|
521
569
|
* @returns {Fields} The newly created `Fields` instance.
|
|
522
570
|
* @throws If the path is invalid or a node already exists at the target location.
|
|
523
571
|
*/
|
|
524
|
-
createFields
|
|
572
|
+
createFields(path: PathType, createPath?: boolean): TFields;
|
|
525
573
|
/**
|
|
526
574
|
* Retrieves a `FieldTree` (branch) node from a specified path.
|
|
527
575
|
* @param {PathType} path - The path to the `FieldTree` node.
|
|
528
576
|
* @returns {FieldTree} The `FieldTree` instance at the specified path.
|
|
529
577
|
* @throws If the path is invalid or the node at the path is not a `FieldTree`.
|
|
530
578
|
*/
|
|
531
|
-
getFieldTree(path: PathType): FieldTree
|
|
579
|
+
getFieldTree(path: PathType): FieldTree<TFields>;
|
|
532
580
|
/**
|
|
533
581
|
* Retrieves a `Fields` (leaf) container from a specified path.
|
|
534
582
|
* @param {PathType} path - The path to the `Fields` container.
|
|
535
583
|
* @returns {Fields} The `Fields` instance at the specified path.
|
|
536
584
|
* @throws If the path is invalid or the node at the path is not a `Fields` container.
|
|
537
585
|
*/
|
|
538
|
-
getFields(path: PathType):
|
|
586
|
+
getFields(path: PathType): TFields;
|
|
539
587
|
/**
|
|
540
588
|
* Retrieves a `FieldTree` at the specified path. If it or any part of the path doesn't exist, it will be created.
|
|
541
589
|
* @param {PathType} path - The path to the `FieldTree` node.
|
|
542
590
|
* @returns {FieldTree} The existing or newly created `FieldTree` instance.
|
|
543
591
|
*/
|
|
544
|
-
getOrCreateFieldTree(path: PathType): FieldTree
|
|
592
|
+
getOrCreateFieldTree(path: PathType): FieldTree<TFields>;
|
|
545
593
|
/**
|
|
546
594
|
* Retrieves a `Fields` container at the specified path. If it or any part of the path doesn't exist, it will be created.
|
|
547
595
|
* @param {PathType} path - The path to the `Fields` container.
|
|
548
596
|
* @returns {Fields} The existing or newly created `Fields` instance.
|
|
549
597
|
*/
|
|
550
598
|
getOrCreateFields(path: PathType): Fields;
|
|
599
|
+
/**
|
|
600
|
+
* Removes all child nodes from this tree branch.
|
|
601
|
+
* This method ensures that `destroy()` is called on each child node, allowing for
|
|
602
|
+
* a full, recursive cleanup of the entire subtree.
|
|
603
|
+
*/
|
|
604
|
+
clear(): void;
|
|
605
|
+
/**
|
|
606
|
+
* Performs a complete cleanup of this node and its entire subtree.
|
|
607
|
+
*
|
|
608
|
+
* It recursively destroys all child nodes by calling `clear()` and then
|
|
609
|
+
* unsubscribes all listeners from its own event emitters.
|
|
610
|
+
* This method should be called when a node is no longer needed.
|
|
611
|
+
*/
|
|
612
|
+
destroy(): void;
|
|
551
613
|
/**
|
|
552
614
|
* @private
|
|
553
615
|
* Navigates the tree to the parent of a target node.
|
|
@@ -699,30 +761,19 @@ interface FieldsSnapshot {
|
|
|
699
761
|
* into a storable snapshot and back.
|
|
700
762
|
* It delegates the actual serialization of each `Field` and `Policy` to their respective serializers.
|
|
701
763
|
*
|
|
702
|
-
* @todo This implementation is coupled to creating `DefaultFields` instances during hydration.
|
|
703
|
-
* To make the system fully extensible, this class should be refactored to use a
|
|
704
|
-
* `FieldsRegistry` (a `ConstructorRegistry<Fields>`). This would allow it to
|
|
705
|
-
* hydrate any custom `Fields` class (e.g., `ReactiveFields`) based on the `__type`
|
|
706
|
-
* property in the snapshot, mirroring the pattern used by `FieldSerializer`.
|
|
707
|
-
*
|
|
708
764
|
* @todo Implement a `patch(fields, snapshot)` method. It should perform a non-destructive
|
|
709
765
|
* update, creating new fields, removing missing ones, and patching existing ones
|
|
710
766
|
* in place, preserving the container instance itself.
|
|
711
767
|
*/
|
|
712
|
-
declare class FieldsSerializer {
|
|
713
|
-
private readonly
|
|
714
|
-
private readonly policySerializer;
|
|
715
|
-
/**
|
|
716
|
-
* An internal instance of FieldSerializer to handle individual fields.
|
|
717
|
-
* @private
|
|
718
|
-
*/
|
|
768
|
+
declare class FieldsSerializer<TFields extends Fields> {
|
|
769
|
+
private readonly fieldsFactory;
|
|
719
770
|
private readonly fieldSerializer;
|
|
720
771
|
/**
|
|
721
772
|
* Creates an instance of FieldsSerializer.
|
|
722
|
-
* @param {
|
|
723
|
-
* @param {
|
|
773
|
+
* @param {FieldsFactory} fieldsFactory - A registry that maps string type names to Field constructors.
|
|
774
|
+
* @param {FieldSerializer} fieldSerializer - A serializer of field instances.
|
|
724
775
|
*/
|
|
725
|
-
constructor(
|
|
776
|
+
constructor(fieldsFactory: FieldsFactory<TFields>, fieldSerializer: FieldSerializer);
|
|
726
777
|
/**
|
|
727
778
|
* Creates a serializable snapshot of a `Fields` container.
|
|
728
779
|
*
|
|
@@ -735,12 +786,11 @@ declare class FieldsSerializer {
|
|
|
735
786
|
/**
|
|
736
787
|
* Restores a `Fields` container instance from its snapshot representation.
|
|
737
788
|
*
|
|
738
|
-
* **Limitation:** This method is currently hardcoded to always create an instance of `DefaultFields`.
|
|
739
789
|
* It iterates through the field snapshots and hydrates them individually, adding them to the new container.
|
|
740
790
|
* @param {FieldsSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
741
|
-
* @returns {
|
|
791
|
+
* @returns {Fields} A new `DefaultFields` instance populated with the restored fields.
|
|
742
792
|
*/
|
|
743
|
-
hydrate(snapshot: FieldsSnapshot):
|
|
793
|
+
hydrate(snapshot: FieldsSnapshot): TFields;
|
|
744
794
|
}
|
|
745
795
|
|
|
746
796
|
/**
|
|
@@ -772,21 +822,21 @@ interface FieldTreeSnapshot {
|
|
|
772
822
|
* updates. This method should traverse the existing tree and the snapshot,
|
|
773
823
|
* patching nodes in place to maintain object references.
|
|
774
824
|
*/
|
|
775
|
-
declare class FieldTreeSerializer {
|
|
825
|
+
declare class FieldTreeSerializer<TFields extends Fields> {
|
|
776
826
|
private readonly fieldTreeNodeFactory;
|
|
777
827
|
private readonly fieldsSerializer;
|
|
778
|
-
constructor(fieldTreeNodeFactory: TreeNodeFactory
|
|
828
|
+
constructor(fieldTreeNodeFactory: TreeNodeFactory<TFields>, fieldsSerializer: FieldsSerializer<TFields>);
|
|
779
829
|
/**
|
|
780
830
|
* Creates a serializable snapshot of the entire tree and its contained fields.
|
|
781
831
|
* @returns A plain JavaScript object representing the complete state managed by this tree.
|
|
782
832
|
*/
|
|
783
|
-
snapshot(tree: FieldTree): FieldTreeSnapshot;
|
|
833
|
+
snapshot(tree: FieldTree<TFields>): FieldTreeSnapshot;
|
|
784
834
|
/**
|
|
785
835
|
* Restores the state of the tree from a snapshot.
|
|
786
836
|
* It intelligently creates missing nodes based on `__type` metadata and delegates hydration to child nodes.
|
|
787
837
|
* @param snapshot The snapshot object to load.
|
|
788
838
|
*/
|
|
789
|
-
hydrate(snapshot: FieldTreeSnapshot): FieldTree
|
|
839
|
+
hydrate(snapshot: FieldTreeSnapshot): FieldTree<TFields>;
|
|
790
840
|
}
|
|
791
841
|
|
|
792
|
-
export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, DefaultBooleanField, type DefaultBooleanFieldOptions, DefaultField, DefaultFields, DefaultNumericField, type DefaultNumericFieldOptions, DefaultStringField, type DefaultStringFieldOptions, DefaultTreeNodeFactory, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, FieldTreeSerializer, type FieldTreeSnapshot, Fields, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type StringField, type
|
|
842
|
+
export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, DefaultBooleanField, type DefaultBooleanFieldOptions, DefaultField, DefaultFields, DefaultFieldsFactory, DefaultNumericField, type DefaultNumericFieldOptions, DefaultStringField, type DefaultStringFieldOptions, DefaultTreeNodeFactory, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type StringField, type TreeNode, type TreeNodeFactory, clampMaxPolicy, clampMinPolicy, clampPolicy };
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ __export(index_exports, {
|
|
|
29
29
|
DefaultBooleanField: () => DefaultBooleanField,
|
|
30
30
|
DefaultField: () => DefaultField,
|
|
31
31
|
DefaultFields: () => DefaultFields,
|
|
32
|
+
DefaultFieldsFactory: () => DefaultFieldsFactory,
|
|
32
33
|
DefaultNumericField: () => DefaultNumericField,
|
|
33
34
|
DefaultStringField: () => DefaultStringField,
|
|
34
35
|
DefaultTreeNodeFactory: () => DefaultTreeNodeFactory,
|
|
@@ -491,6 +492,11 @@ var Fields = class _Fields {
|
|
|
491
492
|
clear() {
|
|
492
493
|
this.remove(Array.from(this._fields.keys()));
|
|
493
494
|
}
|
|
495
|
+
destroy() {
|
|
496
|
+
this.clear();
|
|
497
|
+
this.onAdd.clear();
|
|
498
|
+
this.onRemove.clear();
|
|
499
|
+
}
|
|
494
500
|
};
|
|
495
501
|
|
|
496
502
|
// src/mixins/with-boolean-fields.mixin.ts
|
|
@@ -538,20 +544,23 @@ function WithNumericFields(Base) {
|
|
|
538
544
|
};
|
|
539
545
|
}
|
|
540
546
|
|
|
541
|
-
// src/mixins/with-default-fields.mixin.ts
|
|
542
|
-
function
|
|
543
|
-
return class
|
|
544
|
-
|
|
547
|
+
// src/mixins/with-default-generic-fields.mixin.ts
|
|
548
|
+
function WithDefaultGenericFields(Base) {
|
|
549
|
+
return class FieldsWithDefaultGeneric extends Base {
|
|
550
|
+
createGeneric(name, initialValue, options) {
|
|
545
551
|
return this.create(DefaultField.typeName, name, initialValue, options);
|
|
546
552
|
}
|
|
547
|
-
|
|
553
|
+
upsetGeneric(name, value, options) {
|
|
548
554
|
return this.upset(DefaultField.typeName, name, value, options);
|
|
549
555
|
}
|
|
556
|
+
getGeneric(name) {
|
|
557
|
+
return this.get(name);
|
|
558
|
+
}
|
|
550
559
|
};
|
|
551
560
|
}
|
|
552
561
|
|
|
553
562
|
// src/default-fields.ts
|
|
554
|
-
var DefaultFields = class extends WithBooleanFields(WithStringFields(WithNumericFields(
|
|
563
|
+
var DefaultFields = class extends WithBooleanFields(WithStringFields(WithNumericFields(WithDefaultGenericFields(Fields)))) {
|
|
555
564
|
};
|
|
556
565
|
|
|
557
566
|
// src/field-tree.ts
|
|
@@ -563,6 +572,29 @@ var FieldTree = class _FieldTree {
|
|
|
563
572
|
_nodes = /* @__PURE__ */ new Map();
|
|
564
573
|
/** @private The factory used to create new child nodes. */
|
|
565
574
|
_factory;
|
|
575
|
+
/**
|
|
576
|
+
* An event emitter that fires immediately after a new node is added to this tree branch.
|
|
577
|
+
* @event
|
|
578
|
+
* @param {object} event - The event payload.
|
|
579
|
+
* @param {string} event.name - The name (key) of the added node.
|
|
580
|
+
* @param event.node - The node instance that was added.
|
|
581
|
+
* @example
|
|
582
|
+
* myTree.onAdd.subscribe(({ name, node }) => {
|
|
583
|
+
* console.log(`Node '${name}' was added.`, node);
|
|
584
|
+
* });
|
|
585
|
+
*/
|
|
586
|
+
onAdd = new import_utils5.Emitter();
|
|
587
|
+
/**
|
|
588
|
+
* An event emitter that fires once after one or more nodes have been successfully removed.
|
|
589
|
+
* @event
|
|
590
|
+
* @param {object} event - The event payload.
|
|
591
|
+
* @param {string[]} event.names - An array of names of the nodes that were removed.
|
|
592
|
+
* @example
|
|
593
|
+
* myTree.onRemove.subscribe(({ names }) => {
|
|
594
|
+
* console.log(`Nodes removed: ${names.join(', ')}`);
|
|
595
|
+
* });
|
|
596
|
+
*/
|
|
597
|
+
onRemove = new import_utils5.Emitter();
|
|
566
598
|
/**
|
|
567
599
|
* Gets the collection of direct child nodes of this tree branch.
|
|
568
600
|
*/
|
|
@@ -596,19 +628,20 @@ var FieldTree = class _FieldTree {
|
|
|
596
628
|
/**
|
|
597
629
|
* Adds a pre-existing node as a direct child of this tree branch.
|
|
598
630
|
* @param {string} name - The name to assign to the new child node.
|
|
599
|
-
* @param {
|
|
600
|
-
* @returns {
|
|
631
|
+
* @param {TreeNode} node - The node instance to add.
|
|
632
|
+
* @returns {TreeNode} The added node.
|
|
601
633
|
* @throws If a node with the same name already exists.
|
|
602
634
|
*/
|
|
603
635
|
addNode(name, node) {
|
|
604
636
|
(0, import_utils5.throwIf)(this.has(name), `Can't add node with name: '${name}', node already exists`);
|
|
605
637
|
this._nodes.set(name, node);
|
|
638
|
+
this.onAdd.emit({ name, node });
|
|
606
639
|
return node;
|
|
607
640
|
}
|
|
608
641
|
/**
|
|
609
642
|
* Retrieves a direct child node by its name.
|
|
610
643
|
* @param {string} name - The name of the child node.
|
|
611
|
-
* @returns {
|
|
644
|
+
* @returns {TreeNode} The retrieved node.
|
|
612
645
|
* @throws If a node with the given name cannot be found.
|
|
613
646
|
*/
|
|
614
647
|
getNode(name) {
|
|
@@ -616,6 +649,29 @@ var FieldTree = class _FieldTree {
|
|
|
616
649
|
(0, import_utils5.throwIfEmpty)(node, `Can't find node with name '${name}'`);
|
|
617
650
|
return node;
|
|
618
651
|
}
|
|
652
|
+
/**
|
|
653
|
+
* Removes one or more nodes from this tree branch.
|
|
654
|
+
*
|
|
655
|
+
* This method first validates that all specified nodes exist. If validation passes,
|
|
656
|
+
* it recursively calls `destroy()` on each node to ensure proper cleanup of the entire subtree.
|
|
657
|
+
* Finally, it emits a single `onRemove` event with the names of all successfully removed nodes.
|
|
658
|
+
*
|
|
659
|
+
* @param {string | string[]} names - A single name or an array of names of the nodes to remove.
|
|
660
|
+
* @throws If any of the specified names do not correspond to an existing node.
|
|
661
|
+
*/
|
|
662
|
+
removeNode(names) {
|
|
663
|
+
const toRemoveNames = Array.isArray(names) ? names : [names];
|
|
664
|
+
toRemoveNames.forEach((name) => {
|
|
665
|
+
(0, import_utils5.throwIf)(!this.has(name), `Can't remove node with name: '${name}', node doesn't exists`);
|
|
666
|
+
});
|
|
667
|
+
toRemoveNames.forEach((name) => {
|
|
668
|
+
this._nodes.get(name).destroy();
|
|
669
|
+
this._nodes.delete(name);
|
|
670
|
+
});
|
|
671
|
+
if (toRemoveNames.length) {
|
|
672
|
+
this.onRemove.emit({ names: toRemoveNames });
|
|
673
|
+
}
|
|
674
|
+
}
|
|
619
675
|
/**
|
|
620
676
|
* Creates a new `FieldTree` (branch) node at the specified path.
|
|
621
677
|
* @param {PathType} path - The path where the new `FieldTree` should be created.
|
|
@@ -686,6 +742,26 @@ var FieldTree = class _FieldTree {
|
|
|
686
742
|
const traversedPath = this.traversePath(path, true);
|
|
687
743
|
return traversedPath.branch.has(traversedPath.leafName) ? traversedPath.branch.getFields(traversedPath.leafName) : traversedPath.branch.createFields(traversedPath.leafName);
|
|
688
744
|
}
|
|
745
|
+
/**
|
|
746
|
+
* Removes all child nodes from this tree branch.
|
|
747
|
+
* This method ensures that `destroy()` is called on each child node, allowing for
|
|
748
|
+
* a full, recursive cleanup of the entire subtree.
|
|
749
|
+
*/
|
|
750
|
+
clear() {
|
|
751
|
+
this.removeNode(Array.from(this._nodes.keys()));
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Performs a complete cleanup of this node and its entire subtree.
|
|
755
|
+
*
|
|
756
|
+
* It recursively destroys all child nodes by calling `clear()` and then
|
|
757
|
+
* unsubscribes all listeners from its own event emitters.
|
|
758
|
+
* This method should be called when a node is no longer needed.
|
|
759
|
+
*/
|
|
760
|
+
destroy() {
|
|
761
|
+
this.clear();
|
|
762
|
+
this.onAdd.clear();
|
|
763
|
+
this.onRemove.clear();
|
|
764
|
+
}
|
|
689
765
|
/**
|
|
690
766
|
* @private
|
|
691
767
|
* Navigates the tree to the parent of a target node.
|
|
@@ -718,12 +794,21 @@ var FieldTree = class _FieldTree {
|
|
|
718
794
|
};
|
|
719
795
|
|
|
720
796
|
// src/field-tree-node-factory.ts
|
|
721
|
-
var
|
|
797
|
+
var DefaultFieldsFactory = class {
|
|
722
798
|
constructor(fieldRegistry) {
|
|
723
799
|
this.fieldRegistry = fieldRegistry;
|
|
724
800
|
}
|
|
725
|
-
fields
|
|
726
|
-
|
|
801
|
+
fields() {
|
|
802
|
+
return new DefaultFields(this.fieldRegistry);
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
var DefaultTreeNodeFactory = class extends DefaultFieldsFactory {
|
|
806
|
+
constructor(fieldRegistry) {
|
|
807
|
+
super(fieldRegistry);
|
|
808
|
+
}
|
|
809
|
+
tree() {
|
|
810
|
+
return new FieldTree(this);
|
|
811
|
+
}
|
|
727
812
|
};
|
|
728
813
|
|
|
729
814
|
// src/serializer/policies/clamp-policy-serializer-handler.ts
|
|
@@ -856,19 +941,13 @@ var FieldSerializer = class {
|
|
|
856
941
|
var FieldsSerializer = class {
|
|
857
942
|
/**
|
|
858
943
|
* Creates an instance of FieldsSerializer.
|
|
859
|
-
* @param {
|
|
860
|
-
* @param {
|
|
944
|
+
* @param {FieldsFactory} fieldsFactory - A registry that maps string type names to Field constructors.
|
|
945
|
+
* @param {FieldSerializer} fieldSerializer - A serializer of field instances.
|
|
861
946
|
*/
|
|
862
|
-
constructor(
|
|
863
|
-
this.
|
|
864
|
-
this.
|
|
865
|
-
this.fieldSerializer = new FieldSerializer(this.fieldRegistry, this.policySerializer);
|
|
947
|
+
constructor(fieldsFactory, fieldSerializer) {
|
|
948
|
+
this.fieldsFactory = fieldsFactory;
|
|
949
|
+
this.fieldSerializer = fieldSerializer;
|
|
866
950
|
}
|
|
867
|
-
/**
|
|
868
|
-
* An internal instance of FieldSerializer to handle individual fields.
|
|
869
|
-
* @private
|
|
870
|
-
*/
|
|
871
|
-
fieldSerializer;
|
|
872
951
|
/**
|
|
873
952
|
* Creates a serializable snapshot of a `Fields` container.
|
|
874
953
|
*
|
|
@@ -887,14 +966,13 @@ var FieldsSerializer = class {
|
|
|
887
966
|
/**
|
|
888
967
|
* Restores a `Fields` container instance from its snapshot representation.
|
|
889
968
|
*
|
|
890
|
-
* **Limitation:** This method is currently hardcoded to always create an instance of `DefaultFields`.
|
|
891
969
|
* It iterates through the field snapshots and hydrates them individually, adding them to the new container.
|
|
892
970
|
* @param {FieldsSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
893
|
-
* @returns {
|
|
971
|
+
* @returns {Fields} A new `DefaultFields` instance populated with the restored fields.
|
|
894
972
|
*/
|
|
895
973
|
hydrate(snapshot) {
|
|
896
974
|
const { __type, ...fieldsData } = snapshot;
|
|
897
|
-
const fields =
|
|
975
|
+
const fields = this.fieldsFactory.fields();
|
|
898
976
|
for (const fieldName in fieldsData) {
|
|
899
977
|
const fieldSnapshot = fieldsData[fieldName];
|
|
900
978
|
const restoredField = this.fieldSerializer.hydrate(fieldSnapshot);
|
|
@@ -943,7 +1021,7 @@ var FieldTreeSerializer = class {
|
|
|
943
1021
|
}
|
|
944
1022
|
if (nodeData.__type === FieldTree.typeName) {
|
|
945
1023
|
tree.addNode(key, this.hydrate(nodeData));
|
|
946
|
-
} else {
|
|
1024
|
+
} else if (nodeData.__type === Fields.typeName) {
|
|
947
1025
|
tree.addNode(key, this.fieldsSerializer.hydrate(nodeData));
|
|
948
1026
|
}
|
|
949
1027
|
}
|
|
@@ -961,6 +1039,7 @@ var FieldTreeSerializer = class {
|
|
|
961
1039
|
DefaultBooleanField,
|
|
962
1040
|
DefaultField,
|
|
963
1041
|
DefaultFields,
|
|
1042
|
+
DefaultFieldsFactory,
|
|
964
1043
|
DefaultNumericField,
|
|
965
1044
|
DefaultStringField,
|
|
966
1045
|
DefaultTreeNodeFactory,
|
package/dist/index.mjs
CHANGED
|
@@ -443,6 +443,11 @@ var Fields = class _Fields {
|
|
|
443
443
|
clear() {
|
|
444
444
|
this.remove(Array.from(this._fields.keys()));
|
|
445
445
|
}
|
|
446
|
+
destroy() {
|
|
447
|
+
this.clear();
|
|
448
|
+
this.onAdd.clear();
|
|
449
|
+
this.onRemove.clear();
|
|
450
|
+
}
|
|
446
451
|
};
|
|
447
452
|
|
|
448
453
|
// src/mixins/with-boolean-fields.mixin.ts
|
|
@@ -490,24 +495,27 @@ function WithNumericFields(Base) {
|
|
|
490
495
|
};
|
|
491
496
|
}
|
|
492
497
|
|
|
493
|
-
// src/mixins/with-default-fields.mixin.ts
|
|
494
|
-
function
|
|
495
|
-
return class
|
|
496
|
-
|
|
498
|
+
// src/mixins/with-default-generic-fields.mixin.ts
|
|
499
|
+
function WithDefaultGenericFields(Base) {
|
|
500
|
+
return class FieldsWithDefaultGeneric extends Base {
|
|
501
|
+
createGeneric(name, initialValue, options) {
|
|
497
502
|
return this.create(DefaultField.typeName, name, initialValue, options);
|
|
498
503
|
}
|
|
499
|
-
|
|
504
|
+
upsetGeneric(name, value, options) {
|
|
500
505
|
return this.upset(DefaultField.typeName, name, value, options);
|
|
501
506
|
}
|
|
507
|
+
getGeneric(name) {
|
|
508
|
+
return this.get(name);
|
|
509
|
+
}
|
|
502
510
|
};
|
|
503
511
|
}
|
|
504
512
|
|
|
505
513
|
// src/default-fields.ts
|
|
506
|
-
var DefaultFields = class extends WithBooleanFields(WithStringFields(WithNumericFields(
|
|
514
|
+
var DefaultFields = class extends WithBooleanFields(WithStringFields(WithNumericFields(WithDefaultGenericFields(Fields)))) {
|
|
507
515
|
};
|
|
508
516
|
|
|
509
517
|
// src/field-tree.ts
|
|
510
|
-
import { ensurePathArray, ensurePathString, throwIf as throwIf3, throwIfEmpty as throwIfEmpty2 } from "@axi-engine/utils";
|
|
518
|
+
import { Emitter as Emitter3, ensurePathArray, ensurePathString, throwIf as throwIf3, throwIfEmpty as throwIfEmpty2 } from "@axi-engine/utils";
|
|
511
519
|
var FieldTree = class _FieldTree {
|
|
512
520
|
static typeName = "fieldTree";
|
|
513
521
|
typeName = _FieldTree.typeName;
|
|
@@ -515,6 +523,29 @@ var FieldTree = class _FieldTree {
|
|
|
515
523
|
_nodes = /* @__PURE__ */ new Map();
|
|
516
524
|
/** @private The factory used to create new child nodes. */
|
|
517
525
|
_factory;
|
|
526
|
+
/**
|
|
527
|
+
* An event emitter that fires immediately after a new node is added to this tree branch.
|
|
528
|
+
* @event
|
|
529
|
+
* @param {object} event - The event payload.
|
|
530
|
+
* @param {string} event.name - The name (key) of the added node.
|
|
531
|
+
* @param event.node - The node instance that was added.
|
|
532
|
+
* @example
|
|
533
|
+
* myTree.onAdd.subscribe(({ name, node }) => {
|
|
534
|
+
* console.log(`Node '${name}' was added.`, node);
|
|
535
|
+
* });
|
|
536
|
+
*/
|
|
537
|
+
onAdd = new Emitter3();
|
|
538
|
+
/**
|
|
539
|
+
* An event emitter that fires once after one or more nodes have been successfully removed.
|
|
540
|
+
* @event
|
|
541
|
+
* @param {object} event - The event payload.
|
|
542
|
+
* @param {string[]} event.names - An array of names of the nodes that were removed.
|
|
543
|
+
* @example
|
|
544
|
+
* myTree.onRemove.subscribe(({ names }) => {
|
|
545
|
+
* console.log(`Nodes removed: ${names.join(', ')}`);
|
|
546
|
+
* });
|
|
547
|
+
*/
|
|
548
|
+
onRemove = new Emitter3();
|
|
518
549
|
/**
|
|
519
550
|
* Gets the collection of direct child nodes of this tree branch.
|
|
520
551
|
*/
|
|
@@ -548,19 +579,20 @@ var FieldTree = class _FieldTree {
|
|
|
548
579
|
/**
|
|
549
580
|
* Adds a pre-existing node as a direct child of this tree branch.
|
|
550
581
|
* @param {string} name - The name to assign to the new child node.
|
|
551
|
-
* @param {
|
|
552
|
-
* @returns {
|
|
582
|
+
* @param {TreeNode} node - The node instance to add.
|
|
583
|
+
* @returns {TreeNode} The added node.
|
|
553
584
|
* @throws If a node with the same name already exists.
|
|
554
585
|
*/
|
|
555
586
|
addNode(name, node) {
|
|
556
587
|
throwIf3(this.has(name), `Can't add node with name: '${name}', node already exists`);
|
|
557
588
|
this._nodes.set(name, node);
|
|
589
|
+
this.onAdd.emit({ name, node });
|
|
558
590
|
return node;
|
|
559
591
|
}
|
|
560
592
|
/**
|
|
561
593
|
* Retrieves a direct child node by its name.
|
|
562
594
|
* @param {string} name - The name of the child node.
|
|
563
|
-
* @returns {
|
|
595
|
+
* @returns {TreeNode} The retrieved node.
|
|
564
596
|
* @throws If a node with the given name cannot be found.
|
|
565
597
|
*/
|
|
566
598
|
getNode(name) {
|
|
@@ -568,6 +600,29 @@ var FieldTree = class _FieldTree {
|
|
|
568
600
|
throwIfEmpty2(node, `Can't find node with name '${name}'`);
|
|
569
601
|
return node;
|
|
570
602
|
}
|
|
603
|
+
/**
|
|
604
|
+
* Removes one or more nodes from this tree branch.
|
|
605
|
+
*
|
|
606
|
+
* This method first validates that all specified nodes exist. If validation passes,
|
|
607
|
+
* it recursively calls `destroy()` on each node to ensure proper cleanup of the entire subtree.
|
|
608
|
+
* Finally, it emits a single `onRemove` event with the names of all successfully removed nodes.
|
|
609
|
+
*
|
|
610
|
+
* @param {string | string[]} names - A single name or an array of names of the nodes to remove.
|
|
611
|
+
* @throws If any of the specified names do not correspond to an existing node.
|
|
612
|
+
*/
|
|
613
|
+
removeNode(names) {
|
|
614
|
+
const toRemoveNames = Array.isArray(names) ? names : [names];
|
|
615
|
+
toRemoveNames.forEach((name) => {
|
|
616
|
+
throwIf3(!this.has(name), `Can't remove node with name: '${name}', node doesn't exists`);
|
|
617
|
+
});
|
|
618
|
+
toRemoveNames.forEach((name) => {
|
|
619
|
+
this._nodes.get(name).destroy();
|
|
620
|
+
this._nodes.delete(name);
|
|
621
|
+
});
|
|
622
|
+
if (toRemoveNames.length) {
|
|
623
|
+
this.onRemove.emit({ names: toRemoveNames });
|
|
624
|
+
}
|
|
625
|
+
}
|
|
571
626
|
/**
|
|
572
627
|
* Creates a new `FieldTree` (branch) node at the specified path.
|
|
573
628
|
* @param {PathType} path - The path where the new `FieldTree` should be created.
|
|
@@ -638,6 +693,26 @@ var FieldTree = class _FieldTree {
|
|
|
638
693
|
const traversedPath = this.traversePath(path, true);
|
|
639
694
|
return traversedPath.branch.has(traversedPath.leafName) ? traversedPath.branch.getFields(traversedPath.leafName) : traversedPath.branch.createFields(traversedPath.leafName);
|
|
640
695
|
}
|
|
696
|
+
/**
|
|
697
|
+
* Removes all child nodes from this tree branch.
|
|
698
|
+
* This method ensures that `destroy()` is called on each child node, allowing for
|
|
699
|
+
* a full, recursive cleanup of the entire subtree.
|
|
700
|
+
*/
|
|
701
|
+
clear() {
|
|
702
|
+
this.removeNode(Array.from(this._nodes.keys()));
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Performs a complete cleanup of this node and its entire subtree.
|
|
706
|
+
*
|
|
707
|
+
* It recursively destroys all child nodes by calling `clear()` and then
|
|
708
|
+
* unsubscribes all listeners from its own event emitters.
|
|
709
|
+
* This method should be called when a node is no longer needed.
|
|
710
|
+
*/
|
|
711
|
+
destroy() {
|
|
712
|
+
this.clear();
|
|
713
|
+
this.onAdd.clear();
|
|
714
|
+
this.onRemove.clear();
|
|
715
|
+
}
|
|
641
716
|
/**
|
|
642
717
|
* @private
|
|
643
718
|
* Navigates the tree to the parent of a target node.
|
|
@@ -670,12 +745,21 @@ var FieldTree = class _FieldTree {
|
|
|
670
745
|
};
|
|
671
746
|
|
|
672
747
|
// src/field-tree-node-factory.ts
|
|
673
|
-
var
|
|
748
|
+
var DefaultFieldsFactory = class {
|
|
674
749
|
constructor(fieldRegistry) {
|
|
675
750
|
this.fieldRegistry = fieldRegistry;
|
|
676
751
|
}
|
|
677
|
-
fields
|
|
678
|
-
|
|
752
|
+
fields() {
|
|
753
|
+
return new DefaultFields(this.fieldRegistry);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
var DefaultTreeNodeFactory = class extends DefaultFieldsFactory {
|
|
757
|
+
constructor(fieldRegistry) {
|
|
758
|
+
super(fieldRegistry);
|
|
759
|
+
}
|
|
760
|
+
tree() {
|
|
761
|
+
return new FieldTree(this);
|
|
762
|
+
}
|
|
679
763
|
};
|
|
680
764
|
|
|
681
765
|
// src/serializer/policies/clamp-policy-serializer-handler.ts
|
|
@@ -808,19 +892,13 @@ var FieldSerializer = class {
|
|
|
808
892
|
var FieldsSerializer = class {
|
|
809
893
|
/**
|
|
810
894
|
* Creates an instance of FieldsSerializer.
|
|
811
|
-
* @param {
|
|
812
|
-
* @param {
|
|
895
|
+
* @param {FieldsFactory} fieldsFactory - A registry that maps string type names to Field constructors.
|
|
896
|
+
* @param {FieldSerializer} fieldSerializer - A serializer of field instances.
|
|
813
897
|
*/
|
|
814
|
-
constructor(
|
|
815
|
-
this.
|
|
816
|
-
this.
|
|
817
|
-
this.fieldSerializer = new FieldSerializer(this.fieldRegistry, this.policySerializer);
|
|
898
|
+
constructor(fieldsFactory, fieldSerializer) {
|
|
899
|
+
this.fieldsFactory = fieldsFactory;
|
|
900
|
+
this.fieldSerializer = fieldSerializer;
|
|
818
901
|
}
|
|
819
|
-
/**
|
|
820
|
-
* An internal instance of FieldSerializer to handle individual fields.
|
|
821
|
-
* @private
|
|
822
|
-
*/
|
|
823
|
-
fieldSerializer;
|
|
824
902
|
/**
|
|
825
903
|
* Creates a serializable snapshot of a `Fields` container.
|
|
826
904
|
*
|
|
@@ -839,14 +917,13 @@ var FieldsSerializer = class {
|
|
|
839
917
|
/**
|
|
840
918
|
* Restores a `Fields` container instance from its snapshot representation.
|
|
841
919
|
*
|
|
842
|
-
* **Limitation:** This method is currently hardcoded to always create an instance of `DefaultFields`.
|
|
843
920
|
* It iterates through the field snapshots and hydrates them individually, adding them to the new container.
|
|
844
921
|
* @param {FieldsSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
845
|
-
* @returns {
|
|
922
|
+
* @returns {Fields} A new `DefaultFields` instance populated with the restored fields.
|
|
846
923
|
*/
|
|
847
924
|
hydrate(snapshot) {
|
|
848
925
|
const { __type, ...fieldsData } = snapshot;
|
|
849
|
-
const fields =
|
|
926
|
+
const fields = this.fieldsFactory.fields();
|
|
850
927
|
for (const fieldName in fieldsData) {
|
|
851
928
|
const fieldSnapshot = fieldsData[fieldName];
|
|
852
929
|
const restoredField = this.fieldSerializer.hydrate(fieldSnapshot);
|
|
@@ -895,7 +972,7 @@ var FieldTreeSerializer = class {
|
|
|
895
972
|
}
|
|
896
973
|
if (nodeData.__type === FieldTree.typeName) {
|
|
897
974
|
tree.addNode(key, this.hydrate(nodeData));
|
|
898
|
-
} else {
|
|
975
|
+
} else if (nodeData.__type === Fields.typeName) {
|
|
899
976
|
tree.addNode(key, this.fieldsSerializer.hydrate(nodeData));
|
|
900
977
|
}
|
|
901
978
|
}
|
|
@@ -912,6 +989,7 @@ export {
|
|
|
912
989
|
DefaultBooleanField,
|
|
913
990
|
DefaultField,
|
|
914
991
|
DefaultFields,
|
|
992
|
+
DefaultFieldsFactory,
|
|
915
993
|
DefaultNumericField,
|
|
916
994
|
DefaultStringField,
|
|
917
995
|
DefaultTreeNodeFactory,
|