@axi-engine/fields 0.3.6 → 0.3.8

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _axi_engine_utils from '@axi-engine/utils';
2
- import { Subscribable, ConstructorRegistry, Emitter, Constructor, PathType } from '@axi-engine/utils';
2
+ import { Subscribable, Registry, Constructor, Emitter, PathType, DataStorage } from '@axi-engine/utils';
3
3
 
4
4
  interface Policy<T> {
5
5
  readonly id: string;
@@ -107,7 +107,7 @@ interface StringField extends Field<string> {
107
107
  clear(): void;
108
108
  }
109
109
 
110
- declare class FieldRegistry extends ConstructorRegistry<Field<any>> {
110
+ declare class FieldRegistry extends Registry<string, Constructor<Field<any>>> {
111
111
  }
112
112
 
113
113
  /**
@@ -583,9 +583,8 @@ interface PolicySerializerHandler<T extends Policy<any>, S extends object> {
583
583
  hydrate(snapshotData: S): T;
584
584
  }
585
585
  declare class PolicySerializer {
586
- private readonly handlers;
587
- register(policyId: string, handler: PolicySerializerHandler<any, any>): this;
588
- clearHandlers(): void;
586
+ handlers: Registry<string, PolicySerializerHandler<any, any>>;
587
+ register(policyId: string, handler: PolicySerializerHandler<any, any>): void;
589
588
  /**
590
589
  * Creates a serializable snapshot of a policy instance.
591
590
  * The snapshot includes the policy's state and a `__type` identifier.
@@ -648,6 +647,7 @@ interface FieldSnapshot {
648
647
  value: any;
649
648
  policies?: object[];
650
649
  }
650
+
651
651
  /**
652
652
  * Orchestrates the serialization and deserialization of Field instances.
653
653
  *
@@ -695,6 +695,7 @@ interface FieldsSnapshot {
695
695
  __type: string;
696
696
  [fieldName: string]: FieldSnapshot | string;
697
697
  }
698
+
698
699
  /**
699
700
  * Orchestrates the serialization and deserialization of `Fields` container instances.
700
701
  *
@@ -747,6 +748,7 @@ interface FieldTreeSnapshot {
747
748
  __type: string;
748
749
  [fieldName: string]: FieldsSnapshot | FieldTreeSnapshot | string;
749
750
  }
751
+
750
752
  /**
751
753
  * Orchestrates the recursive serialization and deserialization of `FieldTree` instances.
752
754
  *
@@ -789,7 +791,7 @@ interface StoreCreateFieldOptions {
789
791
  * It acts as a facade, simplifying access to the underlying FieldTree and providing
790
792
  * both type-safe and dynamic methods for manipulating data.
791
793
  */
792
- interface Store {
794
+ interface Store extends DataStorage {
793
795
  /**
794
796
  * Retrieves the raw value of a Field at a specific path.
795
797
  * @template T The expected type of the value.
@@ -955,8 +957,55 @@ declare class DataStore implements Store {
955
957
  remove(path: PathType): void;
956
958
  private isPathToRootFields;
957
959
  private getDestinationFields;
960
+ has(path: PathType): boolean;
961
+ /** implementation of the DataStore from utils */
962
+ get(path: PathType): unknown;
963
+ set(path: PathType, value: unknown): void;
964
+ create(path: PathType, value: unknown): void;
965
+ upset(path: PathType, value: unknown): void;
966
+ delete(path: PathType): void;
958
967
  }
959
968
 
969
+ /**
970
+ * Type guard that checks if a value is an instance of the `Fields` class.
971
+ * It verifies this by checking the static `typeName` property on the instance.
972
+ *
973
+ * @param value The value to check.
974
+ * @returns {boolean} `true` if the value is a `Fields` instance, otherwise `false`.
975
+ */
976
+ declare function isFields(value: unknown): value is Fields;
977
+ /**
978
+ * Type guard that checks if a value is an instance of the `FieldTree` class.
979
+ * It verifies this by checking the static `typeName` property on the instance.
980
+ *
981
+ * @param value The value to check.
982
+ * @returns {boolean} `true` if the value is a `FieldTree` instance, otherwise `false`.
983
+ */
984
+ declare function isFieldTree(value: unknown): value is FieldTree<any>;
985
+ /**
986
+ * Type guard that checks if an unknown value conforms to the `Store` interface.
987
+ *
988
+ * It performs a structural check (duck typing) by verifying the presence of methods
989
+ * that are unique to the `Store` interface and are not part of the simpler `DataSource`
990
+ * or `DataStorage` contracts, such as `createFields` and `createTree`.
991
+ *
992
+ * @param value The `unknown` value to check.
993
+ * @returns {boolean} `true` if the value is a `Store`-like object, `false` otherwise.
994
+ *
995
+ * @example
996
+ * function processData(source: DataSource) {
997
+ * if (isStore(source)) {
998
+ * // Inside this block, TypeScript now knows `source` is a full `Store`.
999
+ * // We can safely call Store-specific methods like `createFields`.
1000
+ * source.createFields('new.data.group');
1001
+ * } else {
1002
+ * // Fallback logic for simpler data sources that are not a `Store`.
1003
+ * console.warn('Cannot create new groups with a simple data source.');
1004
+ * }
1005
+ * }
1006
+ */
1007
+ declare function isStore(value: unknown): value is Store;
1008
+
960
1009
  /**
961
1010
  * Creates and configures a FieldRegistry with all the core field types.
962
1011
  * @returns {FieldRegistry} A pre-configured FieldRegistry instance.
@@ -994,4 +1043,4 @@ declare function createCoreFieldSystem(config?: CoreFieldSystemConfig): {
994
1043
  serializer: FieldTreeSerializer<CoreFields>;
995
1044
  };
996
1045
 
997
- export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, CoreBooleanField, type CoreBooleanFieldOptions, CoreField, type CoreFieldSystemConfig, CoreFieldTree, CoreFields, CoreFieldsFactory, CoreNumericField, type CoreNumericFieldOptions, CoreStringField, type CoreStringFieldOptions, CoreTreeNodeFactory, DataStore, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, type FieldTreeFactory, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type Store, type StoreCreateFieldOptions, type StringField, type TreeNode, clampMaxPolicy, clampMinPolicy, clampPolicy, createCoreFieldRegistry, createCoreFieldSystem, createCorePolicySerializer, createCoreTreeNodeFactory, createCoreTreeSerializer, createTypedMethodsMixin };
1046
+ export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, CoreBooleanField, type CoreBooleanFieldOptions, CoreField, type CoreFieldSystemConfig, CoreFieldTree, CoreFields, CoreFieldsFactory, CoreNumericField, type CoreNumericFieldOptions, CoreStringField, type CoreStringFieldOptions, CoreTreeNodeFactory, DataStore, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, type FieldTreeFactory, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type Store, type StoreCreateFieldOptions, type StringField, type TreeNode, clampMaxPolicy, clampMinPolicy, clampPolicy, createCoreFieldRegistry, createCoreFieldSystem, createCorePolicySerializer, createCoreTreeNodeFactory, createCoreTreeSerializer, createTypedMethodsMixin, isFieldTree, isFields, isStore };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _axi_engine_utils from '@axi-engine/utils';
2
- import { Subscribable, ConstructorRegistry, Emitter, Constructor, PathType } from '@axi-engine/utils';
2
+ import { Subscribable, Registry, Constructor, Emitter, PathType, DataStorage } from '@axi-engine/utils';
3
3
 
4
4
  interface Policy<T> {
5
5
  readonly id: string;
@@ -107,7 +107,7 @@ interface StringField extends Field<string> {
107
107
  clear(): void;
108
108
  }
109
109
 
110
- declare class FieldRegistry extends ConstructorRegistry<Field<any>> {
110
+ declare class FieldRegistry extends Registry<string, Constructor<Field<any>>> {
111
111
  }
112
112
 
113
113
  /**
@@ -583,9 +583,8 @@ interface PolicySerializerHandler<T extends Policy<any>, S extends object> {
583
583
  hydrate(snapshotData: S): T;
584
584
  }
585
585
  declare class PolicySerializer {
586
- private readonly handlers;
587
- register(policyId: string, handler: PolicySerializerHandler<any, any>): this;
588
- clearHandlers(): void;
586
+ handlers: Registry<string, PolicySerializerHandler<any, any>>;
587
+ register(policyId: string, handler: PolicySerializerHandler<any, any>): void;
589
588
  /**
590
589
  * Creates a serializable snapshot of a policy instance.
591
590
  * The snapshot includes the policy's state and a `__type` identifier.
@@ -648,6 +647,7 @@ interface FieldSnapshot {
648
647
  value: any;
649
648
  policies?: object[];
650
649
  }
650
+
651
651
  /**
652
652
  * Orchestrates the serialization and deserialization of Field instances.
653
653
  *
@@ -695,6 +695,7 @@ interface FieldsSnapshot {
695
695
  __type: string;
696
696
  [fieldName: string]: FieldSnapshot | string;
697
697
  }
698
+
698
699
  /**
699
700
  * Orchestrates the serialization and deserialization of `Fields` container instances.
700
701
  *
@@ -747,6 +748,7 @@ interface FieldTreeSnapshot {
747
748
  __type: string;
748
749
  [fieldName: string]: FieldsSnapshot | FieldTreeSnapshot | string;
749
750
  }
751
+
750
752
  /**
751
753
  * Orchestrates the recursive serialization and deserialization of `FieldTree` instances.
752
754
  *
@@ -789,7 +791,7 @@ interface StoreCreateFieldOptions {
789
791
  * It acts as a facade, simplifying access to the underlying FieldTree and providing
790
792
  * both type-safe and dynamic methods for manipulating data.
791
793
  */
792
- interface Store {
794
+ interface Store extends DataStorage {
793
795
  /**
794
796
  * Retrieves the raw value of a Field at a specific path.
795
797
  * @template T The expected type of the value.
@@ -955,8 +957,55 @@ declare class DataStore implements Store {
955
957
  remove(path: PathType): void;
956
958
  private isPathToRootFields;
957
959
  private getDestinationFields;
960
+ has(path: PathType): boolean;
961
+ /** implementation of the DataStore from utils */
962
+ get(path: PathType): unknown;
963
+ set(path: PathType, value: unknown): void;
964
+ create(path: PathType, value: unknown): void;
965
+ upset(path: PathType, value: unknown): void;
966
+ delete(path: PathType): void;
958
967
  }
959
968
 
969
+ /**
970
+ * Type guard that checks if a value is an instance of the `Fields` class.
971
+ * It verifies this by checking the static `typeName` property on the instance.
972
+ *
973
+ * @param value The value to check.
974
+ * @returns {boolean} `true` if the value is a `Fields` instance, otherwise `false`.
975
+ */
976
+ declare function isFields(value: unknown): value is Fields;
977
+ /**
978
+ * Type guard that checks if a value is an instance of the `FieldTree` class.
979
+ * It verifies this by checking the static `typeName` property on the instance.
980
+ *
981
+ * @param value The value to check.
982
+ * @returns {boolean} `true` if the value is a `FieldTree` instance, otherwise `false`.
983
+ */
984
+ declare function isFieldTree(value: unknown): value is FieldTree<any>;
985
+ /**
986
+ * Type guard that checks if an unknown value conforms to the `Store` interface.
987
+ *
988
+ * It performs a structural check (duck typing) by verifying the presence of methods
989
+ * that are unique to the `Store` interface and are not part of the simpler `DataSource`
990
+ * or `DataStorage` contracts, such as `createFields` and `createTree`.
991
+ *
992
+ * @param value The `unknown` value to check.
993
+ * @returns {boolean} `true` if the value is a `Store`-like object, `false` otherwise.
994
+ *
995
+ * @example
996
+ * function processData(source: DataSource) {
997
+ * if (isStore(source)) {
998
+ * // Inside this block, TypeScript now knows `source` is a full `Store`.
999
+ * // We can safely call Store-specific methods like `createFields`.
1000
+ * source.createFields('new.data.group');
1001
+ * } else {
1002
+ * // Fallback logic for simpler data sources that are not a `Store`.
1003
+ * console.warn('Cannot create new groups with a simple data source.');
1004
+ * }
1005
+ * }
1006
+ */
1007
+ declare function isStore(value: unknown): value is Store;
1008
+
960
1009
  /**
961
1010
  * Creates and configures a FieldRegistry with all the core field types.
962
1011
  * @returns {FieldRegistry} A pre-configured FieldRegistry instance.
@@ -994,4 +1043,4 @@ declare function createCoreFieldSystem(config?: CoreFieldSystemConfig): {
994
1043
  serializer: FieldTreeSerializer<CoreFields>;
995
1044
  };
996
1045
 
997
- export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, CoreBooleanField, type CoreBooleanFieldOptions, CoreField, type CoreFieldSystemConfig, CoreFieldTree, CoreFields, CoreFieldsFactory, CoreNumericField, type CoreNumericFieldOptions, CoreStringField, type CoreStringFieldOptions, CoreTreeNodeFactory, DataStore, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, type FieldTreeFactory, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type Store, type StoreCreateFieldOptions, type StringField, type TreeNode, clampMaxPolicy, clampMinPolicy, clampPolicy, createCoreFieldRegistry, createCoreFieldSystem, createCorePolicySerializer, createCoreTreeNodeFactory, createCoreTreeSerializer, createTypedMethodsMixin };
1046
+ export { type BooleanField, ClampMaxPolicy, ClampMaxPolicySerializerHandler, ClampMinPolicy, ClampMinPolicySerializerHandler, ClampPolicy, ClampPolicySerializerHandler, CoreBooleanField, type CoreBooleanFieldOptions, CoreField, type CoreFieldSystemConfig, CoreFieldTree, CoreFields, CoreFieldsFactory, CoreNumericField, type CoreNumericFieldOptions, CoreStringField, type CoreStringFieldOptions, CoreTreeNodeFactory, DataStore, type Field, type FieldOptions, FieldRegistry, FieldSerializer, type FieldSnapshot, FieldTree, type FieldTreeFactory, FieldTreeSerializer, type FieldTreeSnapshot, Fields, type FieldsFactory, FieldsSerializer, type FieldsSnapshot, type NumericField, Policies, type Policy, PolicySerializer, type PolicySerializerHandler, type Store, type StoreCreateFieldOptions, type StringField, type TreeNode, clampMaxPolicy, clampMinPolicy, clampPolicy, createCoreFieldRegistry, createCoreFieldSystem, createCorePolicySerializer, createCoreTreeNodeFactory, createCoreTreeSerializer, createTypedMethodsMixin, isFieldTree, isFields, isStore };
package/dist/index.js CHANGED
@@ -51,7 +51,10 @@ __export(index_exports, {
51
51
  createCorePolicySerializer: () => createCorePolicySerializer,
52
52
  createCoreTreeNodeFactory: () => createCoreTreeNodeFactory,
53
53
  createCoreTreeSerializer: () => createCoreTreeSerializer,
54
- createTypedMethodsMixin: () => createTypedMethodsMixin
54
+ createTypedMethodsMixin: () => createTypedMethodsMixin,
55
+ isFieldTree: () => isFieldTree,
56
+ isFields: () => isFields,
57
+ isStore: () => isStore
55
58
  });
56
59
  module.exports = __toCommonJS(index_exports);
57
60
 
@@ -348,7 +351,7 @@ var CoreNumericField = class _CoreNumericField extends CoreField {
348
351
 
349
352
  // src/field-registry.ts
350
353
  var import_utils3 = require("@axi-engine/utils");
351
- var FieldRegistry = class extends import_utils3.ConstructorRegistry {
354
+ var FieldRegistry = class extends import_utils3.Registry {
352
355
  };
353
356
 
354
357
  // src/fields.ts
@@ -422,7 +425,7 @@ var Fields = class _Fields {
422
425
  * @returns {T} The newly created `Field` instance.
423
426
  */
424
427
  create(typeName, name, initialValue, options) {
425
- const Ctor = this._fieldRegistry.get(typeName);
428
+ const Ctor = this._fieldRegistry.getOrThrow(typeName);
426
429
  const field = new Ctor(name, initialValue, options);
427
430
  this.add(field);
428
431
  return field;
@@ -817,14 +820,9 @@ var ClampMinPolicySerializerHandler = class {
817
820
  // src/serializer/policy-serializer.ts
818
821
  var import_utils6 = require("@axi-engine/utils");
819
822
  var PolicySerializer = class {
820
- handlers = /* @__PURE__ */ new Map();
823
+ handlers = new import_utils6.Registry();
821
824
  register(policyId, handler) {
822
- (0, import_utils6.throwIf)(this.handlers.has(policyId), `A handler for policy ID '${policyId}' is already registered.`);
823
- this.handlers.set(policyId, handler);
824
- return this;
825
- }
826
- clearHandlers() {
827
- this.handlers.clear();
825
+ this.handlers.register(policyId, handler);
828
826
  }
829
827
  /**
830
828
  * Creates a serializable snapshot of a policy instance.
@@ -834,8 +832,7 @@ var PolicySerializer = class {
834
832
  * @throws If no handler is registered for the policy's ID.
835
833
  */
836
834
  snapshot(policy) {
837
- const handler = this.handlers.get(policy.id);
838
- (0, import_utils6.throwIfEmpty)(handler, `No serializer handler registered for policy ID: '${policy.id}'`);
835
+ const handler = this.handlers.getOrThrow(policy.id);
839
836
  const data = handler.snapshot(policy);
840
837
  return {
841
838
  __type: policy.id,
@@ -851,8 +848,7 @@ var PolicySerializer = class {
851
848
  hydrate(snapshot) {
852
849
  const typeId = snapshot?.__type;
853
850
  (0, import_utils6.throwIfEmpty)(typeId, 'Invalid policy snapshot: missing "__type" identifier.');
854
- const handler = this.handlers.get(typeId);
855
- (0, import_utils6.throwIfEmpty)(handler, `No serializer handler registered for policy ID: '${typeId}'`);
851
+ const handler = this.handlers.getOrThrow(typeId);
856
852
  const { __type, ...data } = snapshot;
857
853
  return handler.hydrate(data);
858
854
  }
@@ -900,7 +896,7 @@ var FieldSerializer = class {
900
896
  hydrate(snapshot) {
901
897
  const fieldType = snapshot.__type;
902
898
  (0, import_utils7.throwIfEmpty)(fieldType, 'Invalid field snapshot: missing "__type" identifier.');
903
- const Ctor = this.fieldRegistry.get(fieldType);
899
+ const Ctor = this.fieldRegistry.getOrThrow(fieldType);
904
900
  let policies;
905
901
  if (!(0, import_utils7.isNullOrUndefined)(snapshot.policies)) {
906
902
  policies = [];
@@ -1002,6 +998,9 @@ var FieldTreeSerializer = class {
1002
998
  }
1003
999
  };
1004
1000
 
1001
+ // src/data-store.ts
1002
+ var import_utils10 = require("@axi-engine/utils");
1003
+
1005
1004
  // src/data-store-field-resolver.ts
1006
1005
  var import_utils9 = require("@axi-engine/utils");
1007
1006
  var NumericFieldResolver = class {
@@ -1024,7 +1023,6 @@ var StringFieldResolver = class {
1024
1023
  };
1025
1024
 
1026
1025
  // src/data-store.ts
1027
- var import_utils10 = require("@axi-engine/utils");
1028
1026
  var DataStore = class {
1029
1027
  constructor(tree) {
1030
1028
  this.tree = tree;
@@ -1155,8 +1153,43 @@ var DataStore = class {
1155
1153
  const leafName = pathArr.pop();
1156
1154
  return { fields: this.tree.getOrCreateFields(path), leafName };
1157
1155
  }
1156
+ has(path) {
1157
+ const pathArr = (0, import_utils10.ensurePathArray)(path);
1158
+ if (this.isPathToRootFields(pathArr)) {
1159
+ return this.rootFields.has(pathArr[0]);
1160
+ }
1161
+ return this.tree.hasPath(pathArr);
1162
+ }
1163
+ /** implementation of the DataStore from utils */
1164
+ get(path) {
1165
+ return this.getField(path).value;
1166
+ }
1167
+ set(path, value) {
1168
+ this.setValue(path, value);
1169
+ }
1170
+ create(path, value) {
1171
+ this.createValue(path, value);
1172
+ }
1173
+ upset(path, value) {
1174
+ this.upsetValue(path, value);
1175
+ }
1176
+ delete(path) {
1177
+ this.remove(path);
1178
+ }
1158
1179
  };
1159
1180
 
1181
+ // src/guards.ts
1182
+ var import_utils11 = require("@axi-engine/utils");
1183
+ function isFields(value) {
1184
+ return value != null && value.typeName === Fields.typeName;
1185
+ }
1186
+ function isFieldTree(value) {
1187
+ return value != null && value.typeName === FieldTree.typeName;
1188
+ }
1189
+ function isStore(value) {
1190
+ return !(0, import_utils11.isNullOrUndefined)(value) && typeof value.createFields === "function" && typeof value.createTree === "function";
1191
+ }
1192
+
1160
1193
  // src/setup.ts
1161
1194
  function createCoreFieldRegistry() {
1162
1195
  const fieldRegistry = new FieldRegistry();
@@ -1224,5 +1257,8 @@ function createCoreFieldSystem(config) {
1224
1257
  createCorePolicySerializer,
1225
1258
  createCoreTreeNodeFactory,
1226
1259
  createCoreTreeSerializer,
1227
- createTypedMethodsMixin
1260
+ createTypedMethodsMixin,
1261
+ isFieldTree,
1262
+ isFields,
1263
+ isStore
1228
1264
  });
package/dist/index.mjs CHANGED
@@ -290,8 +290,8 @@ var CoreNumericField = class _CoreNumericField extends CoreField {
290
290
  };
291
291
 
292
292
  // src/field-registry.ts
293
- import { ConstructorRegistry } from "@axi-engine/utils";
294
- var FieldRegistry = class extends ConstructorRegistry {
293
+ import { Registry } from "@axi-engine/utils";
294
+ var FieldRegistry = class extends Registry {
295
295
  };
296
296
 
297
297
  // src/fields.ts
@@ -365,7 +365,7 @@ var Fields = class _Fields {
365
365
  * @returns {T} The newly created `Field` instance.
366
366
  */
367
367
  create(typeName, name, initialValue, options) {
368
- const Ctor = this._fieldRegistry.get(typeName);
368
+ const Ctor = this._fieldRegistry.getOrThrow(typeName);
369
369
  const field = new Ctor(name, initialValue, options);
370
370
  this.add(field);
371
371
  return field;
@@ -758,16 +758,11 @@ var ClampMinPolicySerializerHandler = class {
758
758
  };
759
759
 
760
760
  // src/serializer/policy-serializer.ts
761
- import { throwIf as throwIf3, throwIfEmpty as throwIfEmpty2 } from "@axi-engine/utils";
761
+ import { Registry as Registry2, throwIfEmpty as throwIfEmpty2 } from "@axi-engine/utils";
762
762
  var PolicySerializer = class {
763
- handlers = /* @__PURE__ */ new Map();
763
+ handlers = new Registry2();
764
764
  register(policyId, handler) {
765
- throwIf3(this.handlers.has(policyId), `A handler for policy ID '${policyId}' is already registered.`);
766
- this.handlers.set(policyId, handler);
767
- return this;
768
- }
769
- clearHandlers() {
770
- this.handlers.clear();
765
+ this.handlers.register(policyId, handler);
771
766
  }
772
767
  /**
773
768
  * Creates a serializable snapshot of a policy instance.
@@ -777,8 +772,7 @@ var PolicySerializer = class {
777
772
  * @throws If no handler is registered for the policy's ID.
778
773
  */
779
774
  snapshot(policy) {
780
- const handler = this.handlers.get(policy.id);
781
- throwIfEmpty2(handler, `No serializer handler registered for policy ID: '${policy.id}'`);
775
+ const handler = this.handlers.getOrThrow(policy.id);
782
776
  const data = handler.snapshot(policy);
783
777
  return {
784
778
  __type: policy.id,
@@ -794,8 +788,7 @@ var PolicySerializer = class {
794
788
  hydrate(snapshot) {
795
789
  const typeId = snapshot?.__type;
796
790
  throwIfEmpty2(typeId, 'Invalid policy snapshot: missing "__type" identifier.');
797
- const handler = this.handlers.get(typeId);
798
- throwIfEmpty2(handler, `No serializer handler registered for policy ID: '${typeId}'`);
791
+ const handler = this.handlers.getOrThrow(typeId);
799
792
  const { __type, ...data } = snapshot;
800
793
  return handler.hydrate(data);
801
794
  }
@@ -843,7 +836,7 @@ var FieldSerializer = class {
843
836
  hydrate(snapshot) {
844
837
  const fieldType = snapshot.__type;
845
838
  throwIfEmpty3(fieldType, 'Invalid field snapshot: missing "__type" identifier.');
846
- const Ctor = this.fieldRegistry.get(fieldType);
839
+ const Ctor = this.fieldRegistry.getOrThrow(fieldType);
847
840
  let policies;
848
841
  if (!isNullOrUndefined2(snapshot.policies)) {
849
842
  policies = [];
@@ -945,6 +938,9 @@ var FieldTreeSerializer = class {
945
938
  }
946
939
  };
947
940
 
941
+ // src/data-store.ts
942
+ import { ensurePathArray as ensurePathArray2, ensurePathString as ensurePathString2, throwIfEmpty as throwIfEmpty4 } from "@axi-engine/utils";
943
+
948
944
  // src/data-store-field-resolver.ts
949
945
  import { isBoolean, isNumber, isString as isString2 } from "@axi-engine/utils";
950
946
  var NumericFieldResolver = class {
@@ -967,7 +963,6 @@ var StringFieldResolver = class {
967
963
  };
968
964
 
969
965
  // src/data-store.ts
970
- import { ensurePathArray as ensurePathArray2, ensurePathString as ensurePathString2, throwIfEmpty as throwIfEmpty4 } from "@axi-engine/utils";
971
966
  var DataStore = class {
972
967
  constructor(tree) {
973
968
  this.tree = tree;
@@ -1098,8 +1093,43 @@ var DataStore = class {
1098
1093
  const leafName = pathArr.pop();
1099
1094
  return { fields: this.tree.getOrCreateFields(path), leafName };
1100
1095
  }
1096
+ has(path) {
1097
+ const pathArr = ensurePathArray2(path);
1098
+ if (this.isPathToRootFields(pathArr)) {
1099
+ return this.rootFields.has(pathArr[0]);
1100
+ }
1101
+ return this.tree.hasPath(pathArr);
1102
+ }
1103
+ /** implementation of the DataStore from utils */
1104
+ get(path) {
1105
+ return this.getField(path).value;
1106
+ }
1107
+ set(path, value) {
1108
+ this.setValue(path, value);
1109
+ }
1110
+ create(path, value) {
1111
+ this.createValue(path, value);
1112
+ }
1113
+ upset(path, value) {
1114
+ this.upsetValue(path, value);
1115
+ }
1116
+ delete(path) {
1117
+ this.remove(path);
1118
+ }
1101
1119
  };
1102
1120
 
1121
+ // src/guards.ts
1122
+ import { isNullOrUndefined as isNullOrUndefined3 } from "@axi-engine/utils";
1123
+ function isFields(value) {
1124
+ return value != null && value.typeName === Fields.typeName;
1125
+ }
1126
+ function isFieldTree(value) {
1127
+ return value != null && value.typeName === FieldTree.typeName;
1128
+ }
1129
+ function isStore(value) {
1130
+ return !isNullOrUndefined3(value) && typeof value.createFields === "function" && typeof value.createTree === "function";
1131
+ }
1132
+
1103
1133
  // src/setup.ts
1104
1134
  function createCoreFieldRegistry() {
1105
1135
  const fieldRegistry = new FieldRegistry();
@@ -1166,5 +1196,8 @@ export {
1166
1196
  createCorePolicySerializer,
1167
1197
  createCoreTreeNodeFactory,
1168
1198
  createCoreTreeSerializer,
1169
- createTypedMethodsMixin
1199
+ createTypedMethodsMixin,
1200
+ isFieldTree,
1201
+ isFields,
1202
+ isStore
1170
1203
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axi-engine/fields",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "A compact, reactive state management library based on a tree of observable fields.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "dequal": "^2.0.3"
37
37
  },
38
38
  "devDependencies": {
39
- "@axi-engine/utils": "^0.2.0"
39
+ "@axi-engine/utils": "^0.2.6"
40
40
  },
41
41
  "peerDependencies": {
42
- "@axi-engine/utils": "^0.2.0"
42
+ "@axi-engine/utils": "^0.2.6"
43
43
  }
44
44
  }