@axi-engine/fields 0.3.9 → 0.3.11
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 +230 -61
- package/dist/index.d.ts +230 -61
- package/dist/index.js +400 -128
- package/dist/index.mjs +386 -119
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -408,6 +408,9 @@ var Fields = class _Fields {
|
|
|
408
408
|
*/
|
|
409
409
|
remove(names) {
|
|
410
410
|
const namesToRemove = Array.isArray(names) ? names : [names];
|
|
411
|
+
if (!namesToRemove.length) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
411
414
|
const reallyRemoved = namesToRemove.filter((name) => {
|
|
412
415
|
const field = this._fields.get(name);
|
|
413
416
|
if (!field) {
|
|
@@ -764,7 +767,7 @@ var CoreTreeNodeFactory = class extends CoreFieldsFactory {
|
|
|
764
767
|
}
|
|
765
768
|
};
|
|
766
769
|
|
|
767
|
-
// src/
|
|
770
|
+
// src/serializers/policies/clamp-policy-serializer-handler.ts
|
|
768
771
|
var ClampPolicySerializerHandler = class {
|
|
769
772
|
snapshot(policy) {
|
|
770
773
|
return { min: policy.min, max: policy.max };
|
|
@@ -774,7 +777,7 @@ var ClampPolicySerializerHandler = class {
|
|
|
774
777
|
}
|
|
775
778
|
};
|
|
776
779
|
|
|
777
|
-
// src/
|
|
780
|
+
// src/serializers/policies/clamp-max-policy-serializer-handler.ts
|
|
778
781
|
var ClampMaxPolicySerializerHandler = class {
|
|
779
782
|
snapshot(policy) {
|
|
780
783
|
return { max: policy.max };
|
|
@@ -784,7 +787,7 @@ var ClampMaxPolicySerializerHandler = class {
|
|
|
784
787
|
}
|
|
785
788
|
};
|
|
786
789
|
|
|
787
|
-
// src/
|
|
790
|
+
// src/serializers/policies/clamp-min-policy-serializer-handler.ts
|
|
788
791
|
var ClampMinPolicySerializerHandler = class {
|
|
789
792
|
snapshot(policy) {
|
|
790
793
|
return { min: policy.min };
|
|
@@ -794,7 +797,7 @@ var ClampMinPolicySerializerHandler = class {
|
|
|
794
797
|
}
|
|
795
798
|
};
|
|
796
799
|
|
|
797
|
-
// src/
|
|
800
|
+
// src/serializers/policy-serializer.ts
|
|
798
801
|
import { Registry as Registry2, throwIfEmpty as throwIfEmpty2 } from "@axi-engine/utils";
|
|
799
802
|
var PolicySerializer = class {
|
|
800
803
|
handlers = new Registry2();
|
|
@@ -831,9 +834,9 @@ var PolicySerializer = class {
|
|
|
831
834
|
}
|
|
832
835
|
};
|
|
833
836
|
|
|
834
|
-
// src/
|
|
837
|
+
// src/serializers/field-hydrator.ts
|
|
835
838
|
import { isNullOrUndefined as isNullOrUndefined2, throwIfEmpty as throwIfEmpty3 } from "@axi-engine/utils";
|
|
836
|
-
var
|
|
839
|
+
var FieldHydrator = class {
|
|
837
840
|
/**
|
|
838
841
|
* Creates an instance of FieldSerializer.
|
|
839
842
|
* @param {FieldRegistry} fieldRegistry - A registry that maps string type names to Field constructors.
|
|
@@ -843,6 +846,47 @@ var FieldSerializer = class {
|
|
|
843
846
|
this.fieldRegistry = fieldRegistry;
|
|
844
847
|
this.policySerializer = policySerializer;
|
|
845
848
|
}
|
|
849
|
+
/**
|
|
850
|
+
* Restores a Field instance from its snapshot representation.
|
|
851
|
+
* It uses the `__type` property to find the correct constructor and hydrates
|
|
852
|
+
* the field with its value and all its policies.
|
|
853
|
+
* @param {FieldSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
854
|
+
* @returns {Field<any>} A new, fully functional Field instance.
|
|
855
|
+
* @throws If the snapshot is invalid, missing a `__type`, or if the type is not registered.
|
|
856
|
+
*/
|
|
857
|
+
hydrate(snapshot) {
|
|
858
|
+
const fieldType = snapshot.__type;
|
|
859
|
+
throwIfEmpty3(fieldType, 'Invalid field snapshot: missing "__type" identifier.');
|
|
860
|
+
const Ctor = this.fieldRegistry.getOrThrow(fieldType);
|
|
861
|
+
let policies = this.hydratePolicies(snapshot);
|
|
862
|
+
return new Ctor(snapshot.name, snapshot.value, { policies });
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Updates an existing Field instance with data from a snapshot.
|
|
866
|
+
*
|
|
867
|
+
* This method modifies the field in-place, preserving the object reference.
|
|
868
|
+
* It updates the field's value and completely replaces its current policies
|
|
869
|
+
* with the ones defined in the snapshot.
|
|
870
|
+
*
|
|
871
|
+
* @param {Field<any>} field - The existing Field instance to update.
|
|
872
|
+
* @param {FieldSnapshot} snapshot - The snapshot containing the new state.
|
|
873
|
+
*/
|
|
874
|
+
patch(field, snapshot) {
|
|
875
|
+
field.policies.clear();
|
|
876
|
+
const policies = this.hydratePolicies(snapshot);
|
|
877
|
+
policies?.forEach((p) => field.policies.add(p));
|
|
878
|
+
field.value = snapshot.value;
|
|
879
|
+
}
|
|
880
|
+
hydratePolicies(snapshot) {
|
|
881
|
+
return isNullOrUndefined2(snapshot.policies) ? void 0 : snapshot.policies.map((p) => this.policySerializer.hydrate(p));
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
// src/serializers/field-snapshotter.ts
|
|
886
|
+
var FieldSnapshotter = class {
|
|
887
|
+
constructor(policySerializer) {
|
|
888
|
+
this.policySerializer = policySerializer;
|
|
889
|
+
}
|
|
846
890
|
/**
|
|
847
891
|
* Creates a serializable snapshot of a Field instance.
|
|
848
892
|
* The snapshot includes the field's type, name, current value, and the state of all its policies.
|
|
@@ -856,58 +900,22 @@ var FieldSerializer = class {
|
|
|
856
900
|
value: field.value
|
|
857
901
|
};
|
|
858
902
|
if (!field.policies.isEmpty()) {
|
|
859
|
-
|
|
860
|
-
field.policies.items.forEach((policy) => serializedPolicies.push(this.policySerializer.snapshot(policy)));
|
|
861
|
-
snapshot.policies = serializedPolicies;
|
|
903
|
+
snapshot.policies = Array.from(field.policies.items.values()).map((policy) => this.policySerializer.snapshot(policy));
|
|
862
904
|
}
|
|
863
905
|
return snapshot;
|
|
864
906
|
}
|
|
865
|
-
/**
|
|
866
|
-
* Restores a Field instance from its snapshot representation.
|
|
867
|
-
* It uses the `__type` property to find the correct constructor and hydrates
|
|
868
|
-
* the field with its value and all its policies.
|
|
869
|
-
* @param {FieldSnapshot} snapshot - The plain object snapshot to deserialize.
|
|
870
|
-
* @returns {Field<any>} A new, fully functional Field instance.
|
|
871
|
-
* @throws If the snapshot is invalid, missing a `__type`, or if the type is not registered.
|
|
872
|
-
*/
|
|
873
|
-
hydrate(snapshot) {
|
|
874
|
-
const fieldType = snapshot.__type;
|
|
875
|
-
throwIfEmpty3(fieldType, 'Invalid field snapshot: missing "__type" identifier.');
|
|
876
|
-
const Ctor = this.fieldRegistry.getOrThrow(fieldType);
|
|
877
|
-
let policies;
|
|
878
|
-
if (!isNullOrUndefined2(snapshot.policies)) {
|
|
879
|
-
policies = [];
|
|
880
|
-
snapshot.policies.forEach((p) => policies.push(this.policySerializer.hydrate(p)));
|
|
881
|
-
}
|
|
882
|
-
return new Ctor(snapshot.name, snapshot.value, { policies });
|
|
883
|
-
}
|
|
884
907
|
};
|
|
885
908
|
|
|
886
|
-
// src/
|
|
887
|
-
var
|
|
909
|
+
// src/serializers/fields-hydrator.ts
|
|
910
|
+
var FieldsHydrator = class {
|
|
888
911
|
/**
|
|
889
912
|
* Creates an instance of FieldsSerializer.
|
|
890
913
|
* @param {FieldsFactory} fieldsFactory - A registry that maps string type names to Field constructors.
|
|
891
|
-
* @param {
|
|
914
|
+
* @param {FieldHydrator} fieldHydrator - A hydrator of field instances.
|
|
892
915
|
*/
|
|
893
|
-
constructor(fieldsFactory,
|
|
916
|
+
constructor(fieldsFactory, fieldHydrator) {
|
|
894
917
|
this.fieldsFactory = fieldsFactory;
|
|
895
|
-
this.
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Creates a serializable snapshot of a `Fields` container.
|
|
899
|
-
*
|
|
900
|
-
* The snapshot includes a `__type` identifier (currently hardcoded) and an array of snapshots
|
|
901
|
-
* for each `Field` within the container.
|
|
902
|
-
* @param {Fields} fields - The `Fields` instance to serialize.
|
|
903
|
-
* @returns {FieldsSnapshot} A plain object ready for JSON serialization.
|
|
904
|
-
*/
|
|
905
|
-
snapshot(fields) {
|
|
906
|
-
const res = {
|
|
907
|
-
__type: fields.typeName
|
|
908
|
-
};
|
|
909
|
-
fields.fields.forEach((field) => res[field.name] = this.fieldSerializer.snapshot(field));
|
|
910
|
-
return res;
|
|
918
|
+
this.fieldHydrator = fieldHydrator;
|
|
911
919
|
}
|
|
912
920
|
/**
|
|
913
921
|
* Restores a `Fields` container instance from its snapshot representation.
|
|
@@ -921,37 +929,81 @@ var FieldsSerializer = class {
|
|
|
921
929
|
const fields = this.fieldsFactory.fields();
|
|
922
930
|
for (const fieldName in fieldsData) {
|
|
923
931
|
const fieldSnapshot = fieldsData[fieldName];
|
|
924
|
-
const restoredField = this.
|
|
932
|
+
const restoredField = this.fieldHydrator.hydrate(fieldSnapshot);
|
|
925
933
|
fields.add(restoredField);
|
|
926
934
|
}
|
|
927
935
|
return fields;
|
|
928
936
|
}
|
|
937
|
+
/**
|
|
938
|
+
* Synchronizes an existing `Fields` container with a snapshot.
|
|
939
|
+
*
|
|
940
|
+
* This method performs a "smart update":
|
|
941
|
+
* 1. **Removes** fields from the container that are missing in the snapshot.
|
|
942
|
+
* 2. **Patches** existing fields in-place using {@link FieldHydrator.patch}, preserving object references.
|
|
943
|
+
* 3. **Creates** (hydrates) and adds new fields that exist in the snapshot but not in the container.
|
|
944
|
+
*
|
|
945
|
+
* @param {Fields} fields - The target `Fields` container to update.
|
|
946
|
+
* @param {FieldsSnapshot} snapshot - The source snapshot containing the desired state.
|
|
947
|
+
*/
|
|
948
|
+
patch(fields, snapshot) {
|
|
949
|
+
const { __type, ...fieldsData } = snapshot;
|
|
950
|
+
const snapshotKeys = new Set(Object.keys(fieldsData));
|
|
951
|
+
const fieldsToRemove = Array.from(fields.fields.values()).filter((f) => !snapshotKeys.has(f.name)).map((f) => f.name);
|
|
952
|
+
fields.remove(fieldsToRemove);
|
|
953
|
+
for (const fieldName in fieldsData) {
|
|
954
|
+
const fieldSnapshot = fieldsData[fieldName];
|
|
955
|
+
if (fields.has(fieldName)) {
|
|
956
|
+
const existingField = fields.get(fieldName);
|
|
957
|
+
this.fieldHydrator.patch(existingField, fieldSnapshot);
|
|
958
|
+
} else {
|
|
959
|
+
const newField = this.fieldHydrator.hydrate(fieldSnapshot);
|
|
960
|
+
fields.add(newField);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
929
964
|
};
|
|
930
965
|
|
|
931
|
-
// src/
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
966
|
+
// src/serializers/fields-snapshotter.ts
|
|
967
|
+
var FieldsSnapshotter = class {
|
|
968
|
+
/**
|
|
969
|
+
* Creates an instance of FieldsSnapshotter.
|
|
970
|
+
* @param {FieldSnapshotter} fieldSnapshotter - A serializer of field instances.
|
|
971
|
+
*/
|
|
972
|
+
constructor(fieldSnapshotter) {
|
|
973
|
+
this.fieldSnapshotter = fieldSnapshotter;
|
|
937
974
|
}
|
|
938
975
|
/**
|
|
939
|
-
* Creates a serializable snapshot of
|
|
940
|
-
*
|
|
976
|
+
* Creates a serializable snapshot of a `Fields` container.
|
|
977
|
+
*
|
|
978
|
+
* The snapshot includes a `__type` identifier (currently hardcoded) and an array of snapshots
|
|
979
|
+
* for each `Field` within the container.
|
|
980
|
+
* @param {Fields} fields - The `Fields` instance to serialize.
|
|
981
|
+
* @returns {FieldsSnapshot} A plain object ready for JSON serialization.
|
|
941
982
|
*/
|
|
942
|
-
snapshot(
|
|
983
|
+
snapshot(fields) {
|
|
943
984
|
const res = {
|
|
944
|
-
__type:
|
|
985
|
+
__type: fields.typeName
|
|
945
986
|
};
|
|
946
|
-
|
|
947
|
-
if (node.typeName === tree.typeName) {
|
|
948
|
-
res[key] = this.snapshot(node);
|
|
949
|
-
} else if (node.typeName === Fields.typeName) {
|
|
950
|
-
res[key] = this.fieldsSerializer.snapshot(node);
|
|
951
|
-
}
|
|
952
|
-
});
|
|
987
|
+
fields.fields.forEach((field) => res[field.name] = this.fieldSnapshotter.snapshot(field));
|
|
953
988
|
return res;
|
|
954
989
|
}
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// src/serializers/field-tree-hydrator.ts
|
|
993
|
+
import { isString, throwError } from "@axi-engine/utils";
|
|
994
|
+
var FieldTreeHydrator = class {
|
|
995
|
+
_factory;
|
|
996
|
+
_fieldsHydrator;
|
|
997
|
+
get factory() {
|
|
998
|
+
return this._factory;
|
|
999
|
+
}
|
|
1000
|
+
get fieldsHydrator() {
|
|
1001
|
+
return this._fieldsHydrator;
|
|
1002
|
+
}
|
|
1003
|
+
constructor(fieldTreeNodeFactory, fieldsHydrator) {
|
|
1004
|
+
this._factory = fieldTreeNodeFactory;
|
|
1005
|
+
this._fieldsHydrator = fieldsHydrator;
|
|
1006
|
+
}
|
|
955
1007
|
/**
|
|
956
1008
|
* Restores the state of the tree from a snapshot.
|
|
957
1009
|
* It intelligently creates missing nodes based on `__type` metadata and delegates hydration to child nodes.
|
|
@@ -959,20 +1011,99 @@ var FieldTreeSerializer = class {
|
|
|
959
1011
|
*/
|
|
960
1012
|
hydrate(snapshot) {
|
|
961
1013
|
const { __type, ...nodes } = snapshot;
|
|
962
|
-
const tree = this.
|
|
1014
|
+
const tree = this._factory.tree();
|
|
963
1015
|
for (const key in nodes) {
|
|
964
1016
|
const nodeData = nodes[key];
|
|
965
1017
|
if (isString(nodeData)) {
|
|
966
1018
|
continue;
|
|
967
1019
|
}
|
|
968
|
-
|
|
969
|
-
tree.addNode(key, this.hydrate(nodeData));
|
|
970
|
-
} else if (nodeData.__type === Fields.typeName) {
|
|
971
|
-
tree.addNode(key, this.fieldsSerializer.hydrate(nodeData));
|
|
972
|
-
}
|
|
1020
|
+
this.addNodeFromSnapshot(tree, key, nodeData);
|
|
973
1021
|
}
|
|
974
1022
|
return tree;
|
|
975
1023
|
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Synchronizes an existing `FieldTree` branch with a snapshot.
|
|
1026
|
+
*
|
|
1027
|
+
* This method performs a recursive update to match the tree state with the provided snapshot:
|
|
1028
|
+
* 1. **Removes** child nodes that are present in the tree but missing in the snapshot.
|
|
1029
|
+
* 2. **Creates** new nodes that are present in the snapshot but missing in the tree.
|
|
1030
|
+
* 3. **Replaces** nodes if their type has changed (e.g., replacing a `Fields` leaf with a `FieldTree` branch).
|
|
1031
|
+
* 4. **Patches** existing matching nodes in-place (recursively).
|
|
1032
|
+
*
|
|
1033
|
+
* @param {FieldTree} tree - The target tree instance to update.
|
|
1034
|
+
* @param {FieldTreeSnapshot} snapshot - The source snapshot containing the desired state.
|
|
1035
|
+
*/
|
|
1036
|
+
patch(tree, snapshot) {
|
|
1037
|
+
const { __type, ...nodes } = snapshot;
|
|
1038
|
+
const snapshotKeys = new Set(Object.keys(nodes));
|
|
1039
|
+
const nodesToRemove = Array.from(tree.nodes.keys()).filter((key) => !snapshotKeys.has(key));
|
|
1040
|
+
tree.removeNode(nodesToRemove);
|
|
1041
|
+
for (const key in nodes) {
|
|
1042
|
+
const nodeData = nodes[key];
|
|
1043
|
+
if (isString(nodeData)) {
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
if (!tree.has(key)) {
|
|
1047
|
+
this.addNodeFromSnapshot(tree, key, nodeData);
|
|
1048
|
+
} else {
|
|
1049
|
+
const treeNode = tree.getNode(key);
|
|
1050
|
+
if (treeNode.typeName !== nodeData.__type) {
|
|
1051
|
+
tree.removeNode(key);
|
|
1052
|
+
this.addNodeFromSnapshot(tree, key, nodeData);
|
|
1053
|
+
} else {
|
|
1054
|
+
if (nodeData.__type === FieldTree.typeName) {
|
|
1055
|
+
this.patch(treeNode, nodeData);
|
|
1056
|
+
} else if (nodeData.__type === Fields.typeName) {
|
|
1057
|
+
this.fieldsHydrator.patch(treeNode, nodeData);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Helper method to instantiate and add a new node to the tree based on the snapshot type.
|
|
1065
|
+
*
|
|
1066
|
+
* It determines whether to create a nested `FieldTree` or a `Fields` container
|
|
1067
|
+
* by inspecting the `__type` property of the snapshot, hydrates it, and attaches it to the parent tree.
|
|
1068
|
+
*
|
|
1069
|
+
* @param {FieldTree} tree - The parent tree instance where the new node will be added.
|
|
1070
|
+
* @param {string} key - The name (key) for the new node.
|
|
1071
|
+
* @param {FieldsSnapshot | FieldTreeSnapshot} snapshot - The source snapshot data.
|
|
1072
|
+
* @throws If the snapshot contains an unsupported or unknown `__type`.
|
|
1073
|
+
*/
|
|
1074
|
+
addNodeFromSnapshot(tree, key, snapshot) {
|
|
1075
|
+
if (snapshot.__type === FieldTree.typeName) {
|
|
1076
|
+
tree.addNode(key, this.hydrate(snapshot));
|
|
1077
|
+
} else if (snapshot.__type === Fields.typeName) {
|
|
1078
|
+
tree.addNode(key, this.fieldsHydrator.hydrate(snapshot));
|
|
1079
|
+
} else {
|
|
1080
|
+
throwError(`Can't hydrate node with unsupported type: ${snapshot.__type}`);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
|
|
1085
|
+
// src/serializers/field-tree-snapshotter.ts
|
|
1086
|
+
var FieldTreeSnapshotter = class {
|
|
1087
|
+
constructor(fieldsSnapshotter) {
|
|
1088
|
+
this.fieldsSnapshotter = fieldsSnapshotter;
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Creates a serializable snapshot of the entire tree and its contained fields.
|
|
1092
|
+
* @returns A plain JavaScript object representing the complete state managed by this tree.
|
|
1093
|
+
*/
|
|
1094
|
+
snapshot(tree) {
|
|
1095
|
+
const res = {
|
|
1096
|
+
__type: tree.typeName
|
|
1097
|
+
};
|
|
1098
|
+
tree.nodes.forEach((node, key) => {
|
|
1099
|
+
if (node.typeName === tree.typeName) {
|
|
1100
|
+
res[key] = this.snapshot(node);
|
|
1101
|
+
} else if (node.typeName === Fields.typeName) {
|
|
1102
|
+
res[key] = this.fieldsSnapshotter.snapshot(node);
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
return res;
|
|
1106
|
+
}
|
|
976
1107
|
};
|
|
977
1108
|
|
|
978
1109
|
// src/data-store.ts
|
|
@@ -999,24 +1130,51 @@ var StringFieldResolver = class {
|
|
|
999
1130
|
}
|
|
1000
1131
|
};
|
|
1001
1132
|
|
|
1133
|
+
// src/guards.ts
|
|
1134
|
+
import { isNullOrUndefined as isNullOrUndefined3 } from "@axi-engine/utils";
|
|
1135
|
+
function isFields(value) {
|
|
1136
|
+
return !isNullOrUndefined3(value) && value.typeName === Fields.typeName;
|
|
1137
|
+
}
|
|
1138
|
+
function isFieldTree(value) {
|
|
1139
|
+
return !isNullOrUndefined3(value) && value.typeName === FieldTree.typeName;
|
|
1140
|
+
}
|
|
1141
|
+
function isDataStore(value) {
|
|
1142
|
+
return !isNullOrUndefined3(value) && value.typeName === DataStore.typeName;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1002
1145
|
// src/data-store.ts
|
|
1003
1146
|
var DataStore = class _DataStore {
|
|
1004
|
-
constructor(tree) {
|
|
1005
|
-
this.tree = tree;
|
|
1006
|
-
this.registerResolver(new NumericFieldResolver());
|
|
1007
|
-
this.registerResolver(new BooleanFieldResolver());
|
|
1008
|
-
this.registerResolver(new StringFieldResolver());
|
|
1009
|
-
}
|
|
1010
1147
|
static typeName = "dataStore";
|
|
1011
1148
|
typeName = _DataStore.typeName;
|
|
1012
1149
|
resolvers = [];
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1150
|
+
_variables;
|
|
1151
|
+
_tree;
|
|
1152
|
+
_factory;
|
|
1153
|
+
get variables() {
|
|
1154
|
+
if (!this._variables) {
|
|
1155
|
+
this._variables = this._factory.fields();
|
|
1018
1156
|
}
|
|
1019
|
-
return this.
|
|
1157
|
+
return this._variables;
|
|
1158
|
+
}
|
|
1159
|
+
get tree() {
|
|
1160
|
+
if (!this._tree) {
|
|
1161
|
+
this._tree = this._factory.tree();
|
|
1162
|
+
}
|
|
1163
|
+
return this._tree;
|
|
1164
|
+
}
|
|
1165
|
+
constructor(treeOrFactory, variables) {
|
|
1166
|
+
if (!isFieldTree(treeOrFactory)) {
|
|
1167
|
+
this._factory = treeOrFactory;
|
|
1168
|
+
} else {
|
|
1169
|
+
this._tree = treeOrFactory;
|
|
1170
|
+
this._factory = this._tree.factory;
|
|
1171
|
+
}
|
|
1172
|
+
if (variables) {
|
|
1173
|
+
this._variables = variables;
|
|
1174
|
+
}
|
|
1175
|
+
this.registerResolver(new NumericFieldResolver());
|
|
1176
|
+
this.registerResolver(new BooleanFieldResolver());
|
|
1177
|
+
this.registerResolver(new StringFieldResolver());
|
|
1020
1178
|
}
|
|
1021
1179
|
registerResolver(resolver) {
|
|
1022
1180
|
this.resolvers.unshift(resolver);
|
|
@@ -1087,8 +1245,8 @@ var DataStore = class _DataStore {
|
|
|
1087
1245
|
getField(path) {
|
|
1088
1246
|
const pathArr = ensurePathArray2(path);
|
|
1089
1247
|
throwIfEmpty4(pathArr, `Wrong path or path is empty: ${ensurePathString2(path)}, should contain at least one path segment`);
|
|
1090
|
-
if (this.
|
|
1091
|
-
return this.
|
|
1248
|
+
if (this.isPathToVariables(pathArr)) {
|
|
1249
|
+
return this.variables.get(pathArr[0]);
|
|
1092
1250
|
}
|
|
1093
1251
|
const fieldName = pathArr.pop();
|
|
1094
1252
|
const fields = this.tree.getFields(pathArr);
|
|
@@ -1109,8 +1267,8 @@ var DataStore = class _DataStore {
|
|
|
1109
1267
|
remove(path) {
|
|
1110
1268
|
const pathArr = ensurePathArray2(path);
|
|
1111
1269
|
throwIfEmpty4(pathArr, `Wrong path or path is empty: ${ensurePathString2(path)}, should contain at least one path segment`);
|
|
1112
|
-
if (this.
|
|
1113
|
-
this.
|
|
1270
|
+
if (this.isPathToVariables(pathArr)) {
|
|
1271
|
+
this.variables.remove(pathArr);
|
|
1114
1272
|
return;
|
|
1115
1273
|
}
|
|
1116
1274
|
const node = this.tree.findParentNode(pathArr);
|
|
@@ -1121,17 +1279,6 @@ var DataStore = class _DataStore {
|
|
|
1121
1279
|
node.removeNode(leafName);
|
|
1122
1280
|
}
|
|
1123
1281
|
}
|
|
1124
|
-
isPathToRootFields(path) {
|
|
1125
|
-
return ensurePathArray2(path).length === 1;
|
|
1126
|
-
}
|
|
1127
|
-
getDestinationFields(path) {
|
|
1128
|
-
const pathArr = ensurePathArray2(path);
|
|
1129
|
-
if (this.isPathToRootFields(pathArr)) {
|
|
1130
|
-
return { fields: this.rootFields, leafName: pathArr[0] };
|
|
1131
|
-
}
|
|
1132
|
-
const leafName = pathArr.pop();
|
|
1133
|
-
return { fields: this.tree.getOrCreateFields(path), leafName };
|
|
1134
|
-
}
|
|
1135
1282
|
/**
|
|
1136
1283
|
* Creates a new, independent instance of the Store with a fresh, empty data state (FieldsTree).
|
|
1137
1284
|
*
|
|
@@ -1142,13 +1289,13 @@ var DataStore = class _DataStore {
|
|
|
1142
1289
|
* @returns {DataStore} A new, isolated DataStore instance.
|
|
1143
1290
|
*/
|
|
1144
1291
|
createIsolated() {
|
|
1145
|
-
return new _DataStore(this.
|
|
1292
|
+
return new _DataStore(this._factory);
|
|
1146
1293
|
}
|
|
1147
1294
|
/** code below -> implementation of the DataStore from utils */
|
|
1148
1295
|
has(path) {
|
|
1149
1296
|
const pathArr = ensurePathArray2(path);
|
|
1150
|
-
if (this.
|
|
1151
|
-
return this.
|
|
1297
|
+
if (this.isPathToVariables(pathArr)) {
|
|
1298
|
+
return this.variables.has(pathArr[0]);
|
|
1152
1299
|
}
|
|
1153
1300
|
return this.tree.hasPath(pathArr);
|
|
1154
1301
|
}
|
|
@@ -1167,19 +1314,134 @@ var DataStore = class _DataStore {
|
|
|
1167
1314
|
delete(path) {
|
|
1168
1315
|
this.remove(path);
|
|
1169
1316
|
}
|
|
1317
|
+
/**
|
|
1318
|
+
* @internal Used for serialization
|
|
1319
|
+
*/
|
|
1320
|
+
getInternalVariables() {
|
|
1321
|
+
return this._variables;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* @internal Used for serialization
|
|
1325
|
+
*/
|
|
1326
|
+
getInternalTree() {
|
|
1327
|
+
return this._tree;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* @internal Used for serialization
|
|
1331
|
+
*/
|
|
1332
|
+
getOrCreateInternalVariables() {
|
|
1333
|
+
return this.variables;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* @internal Used for serialization
|
|
1337
|
+
*/
|
|
1338
|
+
getOrCreateInternalTree() {
|
|
1339
|
+
return this.tree;
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* @private
|
|
1343
|
+
*/
|
|
1344
|
+
isPathToVariables(path) {
|
|
1345
|
+
return ensurePathArray2(path).length === 1;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* @private
|
|
1349
|
+
*/
|
|
1350
|
+
getDestinationFields(path) {
|
|
1351
|
+
const pathArr = ensurePathArray2(path);
|
|
1352
|
+
if (this.isPathToVariables(pathArr)) {
|
|
1353
|
+
return { fields: this.variables, leafName: pathArr[0] };
|
|
1354
|
+
}
|
|
1355
|
+
const leafName = pathArr.pop();
|
|
1356
|
+
return { fields: this.tree.getOrCreateFields(path), leafName };
|
|
1357
|
+
}
|
|
1170
1358
|
};
|
|
1171
1359
|
|
|
1172
|
-
// src/
|
|
1173
|
-
import { isNullOrUndefined as
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1360
|
+
// src/serializers/data-store-hydrator.ts
|
|
1361
|
+
import { isNullOrUndefined as isNullOrUndefined4 } from "@axi-engine/utils";
|
|
1362
|
+
var DataStoreHydrator = class {
|
|
1363
|
+
/**
|
|
1364
|
+
* Creates an instance of DataStoreSerializer.
|
|
1365
|
+
* @param {FieldTreeHydrator} fieldsFieldTreeHydrator - The serializer used for the underlying tree and fields.
|
|
1366
|
+
*/
|
|
1367
|
+
constructor(fieldsFieldTreeHydrator) {
|
|
1368
|
+
this.fieldsFieldTreeHydrator = fieldsFieldTreeHydrator;
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Reconstructs a DataStore instance from a snapshot.
|
|
1372
|
+
*
|
|
1373
|
+
* If the snapshot contains a tree, the store is initialized with it.
|
|
1374
|
+
* If not, the store is initialized with the factory (lazy mode), and the
|
|
1375
|
+
* detached variables are injected if present.
|
|
1376
|
+
*
|
|
1377
|
+
* @param {DataStoreSnapshot} snapshot - The snapshot to hydrate.
|
|
1378
|
+
* @returns {DataStore} A new, fully restored DataStore instance.
|
|
1379
|
+
*/
|
|
1380
|
+
hydrate(snapshot) {
|
|
1381
|
+
const tree = isNullOrUndefined4(snapshot.tree) ? void 0 : this.fieldsFieldTreeHydrator.hydrate(snapshot.tree);
|
|
1382
|
+
const variables = isNullOrUndefined4(snapshot.variables) ? void 0 : this.fieldsFieldTreeHydrator.fieldsHydrator.hydrate(snapshot.variables);
|
|
1383
|
+
return new DataStore(tree ? tree : this.fieldsFieldTreeHydrator.factory, variables);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Synchronizes a DataStore instance with a snapshot.
|
|
1387
|
+
*
|
|
1388
|
+
* This method ensures the DataStore's internal state matches the snapshot by:
|
|
1389
|
+
* 1. **Destroying** internal containers (variables/tree) if they are missing in the snapshot.
|
|
1390
|
+
* 2. **Patching** (updating/creating) contents if they exist in the snapshot.
|
|
1391
|
+
*
|
|
1392
|
+
* This allows for a granular update where only specific parts of the store (e.g., only variables)
|
|
1393
|
+
* are modified if the snapshot contains partial data, or a full reset if parts are missing.
|
|
1394
|
+
*
|
|
1395
|
+
* @param {DataStore} store - The target DataStore to update.
|
|
1396
|
+
* @param {DataStoreSnapshot} snapshot - The source snapshot.
|
|
1397
|
+
*/
|
|
1398
|
+
patch(store, snapshot) {
|
|
1399
|
+
if (!snapshot.variables) {
|
|
1400
|
+
store.getInternalVariables()?.destroy();
|
|
1401
|
+
} else {
|
|
1402
|
+
this.fieldsFieldTreeHydrator.fieldsHydrator.patch(store.getOrCreateInternalVariables(), snapshot.variables);
|
|
1403
|
+
}
|
|
1404
|
+
if (!snapshot.tree) {
|
|
1405
|
+
store.getInternalTree()?.destroy();
|
|
1406
|
+
} else {
|
|
1407
|
+
this.fieldsFieldTreeHydrator.patch(store.getOrCreateInternalTree(), snapshot.tree);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1412
|
+
// src/serializers/data-store-snapshotter.ts
|
|
1413
|
+
var DataStoreSnapshotter = class {
|
|
1414
|
+
/**
|
|
1415
|
+
* Creates an instance of DataStoreSnapshotter.
|
|
1416
|
+
* @param {FieldTreeSnapshotter} treeSnapshotter - The serializer used for the underlying tree and fields.
|
|
1417
|
+
*/
|
|
1418
|
+
constructor(treeSnapshotter) {
|
|
1419
|
+
this.treeSnapshotter = treeSnapshotter;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Captures the current state of a DataStore into a serializable snapshot.
|
|
1423
|
+
*
|
|
1424
|
+
* It checks for the existence of internal variables and the internal tree,
|
|
1425
|
+
* serializing them only if they have been initialized (lazy serialization).
|
|
1426
|
+
*
|
|
1427
|
+
* @param {DataStore} store - The store instance to serialize.
|
|
1428
|
+
* @returns {DataStoreSnapshot} The snapshot object.
|
|
1429
|
+
*/
|
|
1430
|
+
snapshot(store) {
|
|
1431
|
+
let snapshot = {
|
|
1432
|
+
__type: store.typeName
|
|
1433
|
+
};
|
|
1434
|
+
const variables = store.getInternalVariables();
|
|
1435
|
+
if (variables) {
|
|
1436
|
+
snapshot.variables = this.treeSnapshotter.fieldsSnapshotter.snapshot(variables);
|
|
1437
|
+
}
|
|
1438
|
+
const tree = store.getInternalTree();
|
|
1439
|
+
if (tree) {
|
|
1440
|
+
snapshot.tree = this.treeSnapshotter.snapshot(tree);
|
|
1441
|
+
}
|
|
1442
|
+
return snapshot;
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1183
1445
|
|
|
1184
1446
|
// src/setup.ts
|
|
1185
1447
|
function createCoreFieldRegistry() {
|
|
@@ -1201,11 +1463,11 @@ function createCoreTreeNodeFactory(fieldRegistry) {
|
|
|
1201
1463
|
return new CoreTreeNodeFactory(fieldRegistry);
|
|
1202
1464
|
}
|
|
1203
1465
|
function createCoreTreeSerializer(fieldTreeNodeFactory, policySerializer) {
|
|
1204
|
-
return new
|
|
1466
|
+
return new FieldTreeHydrator(
|
|
1205
1467
|
fieldTreeNodeFactory,
|
|
1206
|
-
new
|
|
1468
|
+
new FieldsHydrator(
|
|
1207
1469
|
fieldTreeNodeFactory,
|
|
1208
|
-
new
|
|
1470
|
+
new FieldHydrator(fieldTreeNodeFactory.fieldRegistry, policySerializer ?? createCorePolicySerializer())
|
|
1209
1471
|
)
|
|
1210
1472
|
);
|
|
1211
1473
|
}
|
|
@@ -1231,12 +1493,17 @@ export {
|
|
|
1231
1493
|
CoreStringField,
|
|
1232
1494
|
CoreTreeNodeFactory,
|
|
1233
1495
|
DataStore,
|
|
1496
|
+
DataStoreHydrator,
|
|
1497
|
+
DataStoreSnapshotter,
|
|
1498
|
+
FieldHydrator,
|
|
1234
1499
|
FieldRegistry,
|
|
1235
|
-
|
|
1500
|
+
FieldSnapshotter,
|
|
1236
1501
|
FieldTree,
|
|
1237
|
-
|
|
1502
|
+
FieldTreeHydrator,
|
|
1503
|
+
FieldTreeSnapshotter,
|
|
1238
1504
|
Fields,
|
|
1239
|
-
|
|
1505
|
+
FieldsHydrator,
|
|
1506
|
+
FieldsSnapshotter,
|
|
1240
1507
|
Policies,
|
|
1241
1508
|
PolicySerializer,
|
|
1242
1509
|
clampMaxPolicy,
|