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