@axi-engine/fields 0.3.8 → 0.3.10

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.js CHANGED
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  CoreStringField: () => CoreStringField,
36
36
  CoreTreeNodeFactory: () => CoreTreeNodeFactory,
37
37
  DataStore: () => DataStore,
38
+ DataStoreSerializer: () => DataStoreSerializer,
38
39
  FieldRegistry: () => FieldRegistry,
39
40
  FieldSerializer: () => FieldSerializer,
40
41
  FieldTree: () => FieldTree,
@@ -52,9 +53,9 @@ __export(index_exports, {
52
53
  createCoreTreeNodeFactory: () => createCoreTreeNodeFactory,
53
54
  createCoreTreeSerializer: () => createCoreTreeSerializer,
54
55
  createTypedMethodsMixin: () => createTypedMethodsMixin,
56
+ isDataStore: () => isDataStore,
55
57
  isFieldTree: () => isFieldTree,
56
- isFields: () => isFields,
57
- isStore: () => isStore
58
+ isFields: () => isFields
58
59
  });
59
60
  module.exports = __toCommonJS(index_exports);
60
61
 
@@ -378,6 +379,9 @@ var Fields = class _Fields {
378
379
  onRemove = new import_utils4.Emitter();
379
380
  /**
380
381
  * Gets the read-only map of all `Field` instances in this container.
382
+ *
383
+ * @internal
384
+ *
381
385
  * @returns {Map<string, Field<any>>} The collection of fields.
382
386
  */
383
387
  get fields() {
@@ -524,11 +528,28 @@ var FieldTree = class _FieldTree {
524
528
  */
525
529
  onRemove = new import_utils5.Emitter();
526
530
  /**
527
- * Gets the collection of direct child nodes of this tree branch.
531
+ * Provides direct access to the internal node storage.
532
+ *
533
+ * @remarks
534
+ * This is primarily intended for **serialization**, debugging, or low-level iteration.
535
+ * Avoid modifying this map directly to maintain internal consistency; use {@link addNode} or {@link removeNode} instead.
536
+ * @internal
528
537
  */
529
538
  get nodes() {
530
539
  return this._nodes;
531
540
  }
541
+ /**
542
+ * Exposes the internal factory instance used by this tree.
543
+ *
544
+ * @remarks
545
+ * Direct usage of this getter is generally unnecessary.
546
+ * Prefer using {@link createDetachedTree} or {@link createDetachedFields} to create isolated instances.
547
+ *
548
+ * @returns {FieldTreeFactory} The factory instance.
549
+ */
550
+ get factory() {
551
+ return this._factory;
552
+ }
532
553
  /**
533
554
  * Creates an instance of FieldTree.
534
555
  * @param {FieldTreeFactory} factory - A factory responsible for creating new nodes within the tree.
@@ -700,6 +721,23 @@ var FieldTree = class _FieldTree {
700
721
  this.onAdd.clear();
701
722
  this.onRemove.clear();
702
723
  }
724
+ /**
725
+ * Creates a new, detached FieldTree instance using the same factory as this tree.
726
+ * This new tree has no parent and is completely isolated.
727
+ *
728
+ * @returns A new instance of the same tree type.
729
+ */
730
+ createDetachedTree() {
731
+ return this._factory.tree();
732
+ }
733
+ /**
734
+ * Creates a new, detached Fields container using the same factory.
735
+ *
736
+ * @returns
737
+ */
738
+ createDetachedFields() {
739
+ return this._factory.fields();
740
+ }
703
741
  /**
704
742
  * @private
705
743
  * Navigates the tree to the parent of a target node.
@@ -897,13 +935,35 @@ var FieldSerializer = class {
897
935
  const fieldType = snapshot.__type;
898
936
  (0, import_utils7.throwIfEmpty)(fieldType, 'Invalid field snapshot: missing "__type" identifier.');
899
937
  const Ctor = this.fieldRegistry.getOrThrow(fieldType);
900
- let policies;
901
- if (!(0, import_utils7.isNullOrUndefined)(snapshot.policies)) {
902
- policies = [];
903
- snapshot.policies.forEach((p) => policies.push(this.policySerializer.hydrate(p)));
904
- }
938
+ let policies = this.hydratePolicies(snapshot);
905
939
  return new Ctor(snapshot.name, snapshot.value, { policies });
906
940
  }
941
+ /**
942
+ * Updates an existing Field instance with data from a snapshot.
943
+ *
944
+ * This method modifies the field in-place, preserving the object reference.
945
+ * It updates the field's value and completely replaces its current policies
946
+ * with the ones defined in the snapshot.
947
+ *
948
+ * @param {Field<any>} field - The existing Field instance to update.
949
+ * @param {FieldSnapshot} snapshot - The snapshot containing the new state.
950
+ */
951
+ patch(field, snapshot) {
952
+ let policies = this.hydratePolicies(snapshot);
953
+ field.policies.clear();
954
+ if (policies) {
955
+ policies.forEach((p) => field.policies.add(p));
956
+ }
957
+ field.value = snapshot.value;
958
+ }
959
+ hydratePolicies(snapshot) {
960
+ if ((0, import_utils7.isNullOrUndefined)(snapshot.policies)) {
961
+ return void 0;
962
+ }
963
+ const policies = [];
964
+ snapshot.policies.forEach((p) => policies.push(this.policySerializer.hydrate(p)));
965
+ return policies;
966
+ }
907
967
  };
908
968
 
909
969
  // src/serializer/fields-serializer.ts
@@ -954,9 +1014,17 @@ var FieldsSerializer = class {
954
1014
  // src/serializer/field-tree-serializer.ts
955
1015
  var import_utils8 = require("@axi-engine/utils");
956
1016
  var FieldTreeSerializer = class {
1017
+ _factory;
1018
+ _fieldsSerializer;
1019
+ get factory() {
1020
+ return this._factory;
1021
+ }
1022
+ get fieldsSerializer() {
1023
+ return this._fieldsSerializer;
1024
+ }
957
1025
  constructor(fieldTreeNodeFactory, fieldsSerializer) {
958
- this.fieldTreeNodeFactory = fieldTreeNodeFactory;
959
- this.fieldsSerializer = fieldsSerializer;
1026
+ this._factory = fieldTreeNodeFactory;
1027
+ this._fieldsSerializer = fieldsSerializer;
960
1028
  }
961
1029
  /**
962
1030
  * Creates a serializable snapshot of the entire tree and its contained fields.
@@ -982,7 +1050,7 @@ var FieldTreeSerializer = class {
982
1050
  */
983
1051
  hydrate(snapshot) {
984
1052
  const { __type, ...nodes } = snapshot;
985
- const tree = this.fieldTreeNodeFactory.tree();
1053
+ const tree = this._factory.tree();
986
1054
  for (const key in nodes) {
987
1055
  const nodeData = nodes[key];
988
1056
  if ((0, import_utils8.isString)(nodeData)) {
@@ -999,7 +1067,7 @@ var FieldTreeSerializer = class {
999
1067
  };
1000
1068
 
1001
1069
  // src/data-store.ts
1002
- var import_utils10 = require("@axi-engine/utils");
1070
+ var import_utils11 = require("@axi-engine/utils");
1003
1071
 
1004
1072
  // src/data-store-field-resolver.ts
1005
1073
  var import_utils9 = require("@axi-engine/utils");
@@ -1022,23 +1090,52 @@ var StringFieldResolver = class {
1022
1090
  }
1023
1091
  };
1024
1092
 
1093
+ // src/guards.ts
1094
+ var import_utils10 = require("@axi-engine/utils");
1095
+ function isFields(value) {
1096
+ return !(0, import_utils10.isNullOrUndefined)(value) && value.typeName === Fields.typeName;
1097
+ }
1098
+ function isFieldTree(value) {
1099
+ return !(0, import_utils10.isNullOrUndefined)(value) && value.typeName === FieldTree.typeName;
1100
+ }
1101
+ function isDataStore(value) {
1102
+ return !(0, import_utils10.isNullOrUndefined)(value) && value.typeName === DataStore.typeName;
1103
+ }
1104
+
1025
1105
  // src/data-store.ts
1026
- var DataStore = class {
1027
- constructor(tree) {
1028
- this.tree = tree;
1106
+ var DataStore = class _DataStore {
1107
+ static typeName = "dataStore";
1108
+ typeName = _DataStore.typeName;
1109
+ resolvers = [];
1110
+ _variables;
1111
+ _tree;
1112
+ _factory;
1113
+ get variables() {
1114
+ if (!this._variables) {
1115
+ this._variables = this._factory.fields();
1116
+ }
1117
+ return this._variables;
1118
+ }
1119
+ get tree() {
1120
+ if (!this._tree) {
1121
+ this._tree = this._factory.tree();
1122
+ }
1123
+ return this._tree;
1124
+ }
1125
+ constructor(treeOrFactory, variables) {
1126
+ if (!isFieldTree(treeOrFactory)) {
1127
+ this._factory = treeOrFactory;
1128
+ } else {
1129
+ this._tree = treeOrFactory;
1130
+ this._factory = this._tree.factory;
1131
+ }
1132
+ if (variables) {
1133
+ this._variables = variables;
1134
+ }
1029
1135
  this.registerResolver(new NumericFieldResolver());
1030
1136
  this.registerResolver(new BooleanFieldResolver());
1031
1137
  this.registerResolver(new StringFieldResolver());
1032
1138
  }
1033
- resolvers = [];
1034
- rootFieldsName = "__root_fields";
1035
- _rootFields;
1036
- get rootFields() {
1037
- if (!this._rootFields) {
1038
- this._rootFields = this.tree.getOrCreateFields(this.rootFieldsName);
1039
- }
1040
- return this._rootFields;
1041
- }
1042
1139
  registerResolver(resolver) {
1043
1140
  this.resolvers.unshift(resolver);
1044
1141
  }
@@ -1106,10 +1203,10 @@ var DataStore = class {
1106
1203
  return this.getField(path);
1107
1204
  }
1108
1205
  getField(path) {
1109
- const pathArr = (0, import_utils10.ensurePathArray)(path);
1110
- (0, import_utils10.throwIfEmpty)(pathArr, `Wrong path or path is empty: ${(0, import_utils10.ensurePathString)(path)}, should contain at least one path segment`);
1111
- if (this.isPathToRootFields(pathArr)) {
1112
- return this.rootFields.get(pathArr[0]);
1206
+ const pathArr = (0, import_utils11.ensurePathArray)(path);
1207
+ (0, import_utils11.throwIfEmpty)(pathArr, `Wrong path or path is empty: ${(0, import_utils11.ensurePathString)(path)}, should contain at least one path segment`);
1208
+ if (this.isPathToVariables(pathArr)) {
1209
+ return this.variables.get(pathArr[0]);
1113
1210
  }
1114
1211
  const fieldName = pathArr.pop();
1115
1212
  const fields = this.tree.getFields(pathArr);
@@ -1128,10 +1225,10 @@ var DataStore = class {
1128
1225
  return this.tree.getFieldTree(path);
1129
1226
  }
1130
1227
  remove(path) {
1131
- const pathArr = (0, import_utils10.ensurePathArray)(path);
1132
- (0, import_utils10.throwIfEmpty)(pathArr, `Wrong path or path is empty: ${(0, import_utils10.ensurePathString)(path)}, should contain at least one path segment`);
1133
- if (this.isPathToRootFields(pathArr)) {
1134
- this.rootFields.remove(pathArr);
1228
+ const pathArr = (0, import_utils11.ensurePathArray)(path);
1229
+ (0, import_utils11.throwIfEmpty)(pathArr, `Wrong path or path is empty: ${(0, import_utils11.ensurePathString)(path)}, should contain at least one path segment`);
1230
+ if (this.isPathToVariables(pathArr)) {
1231
+ this.variables.remove(pathArr);
1135
1232
  return;
1136
1233
  }
1137
1234
  const node = this.tree.findParentNode(pathArr);
@@ -1142,25 +1239,26 @@ var DataStore = class {
1142
1239
  node.removeNode(leafName);
1143
1240
  }
1144
1241
  }
1145
- isPathToRootFields(path) {
1146
- return (0, import_utils10.ensurePathArray)(path).length === 1;
1147
- }
1148
- getDestinationFields(path) {
1149
- const pathArr = (0, import_utils10.ensurePathArray)(path);
1150
- if (this.isPathToRootFields(pathArr)) {
1151
- return { fields: this.rootFields, leafName: pathArr[0] };
1152
- }
1153
- const leafName = pathArr.pop();
1154
- return { fields: this.tree.getOrCreateFields(path), leafName };
1242
+ /**
1243
+ * Creates a new, independent instance of the Store with a fresh, empty data state (FieldsTree).
1244
+ *
1245
+ * The new instance retains the same capabilities (e.g., factory configuration)
1246
+ * as the current one but is completely detached from the existing data hierarchy.
1247
+ * This is useful for creating local scopes, stack frames, or temporary data contexts.
1248
+ *
1249
+ * @returns {DataStore} A new, isolated DataStore instance.
1250
+ */
1251
+ createIsolated() {
1252
+ return new _DataStore(this._factory);
1155
1253
  }
1254
+ /** code below -> implementation of the DataStore from utils */
1156
1255
  has(path) {
1157
- const pathArr = (0, import_utils10.ensurePathArray)(path);
1158
- if (this.isPathToRootFields(pathArr)) {
1159
- return this.rootFields.has(pathArr[0]);
1256
+ const pathArr = (0, import_utils11.ensurePathArray)(path);
1257
+ if (this.isPathToVariables(pathArr)) {
1258
+ return this.variables.has(pathArr[0]);
1160
1259
  }
1161
1260
  return this.tree.hasPath(pathArr);
1162
1261
  }
1163
- /** implementation of the DataStore from utils */
1164
1262
  get(path) {
1165
1263
  return this.getField(path).value;
1166
1264
  }
@@ -1176,19 +1274,86 @@ var DataStore = class {
1176
1274
  delete(path) {
1177
1275
  this.remove(path);
1178
1276
  }
1277
+ /**
1278
+ * @internal Used for serialization
1279
+ */
1280
+ getInternalVariables() {
1281
+ return this._variables;
1282
+ }
1283
+ /**
1284
+ * @internal Used for serialization
1285
+ */
1286
+ getInternalTree() {
1287
+ return this._tree;
1288
+ }
1289
+ /**
1290
+ * @private
1291
+ */
1292
+ isPathToVariables(path) {
1293
+ return (0, import_utils11.ensurePathArray)(path).length === 1;
1294
+ }
1295
+ /**
1296
+ * @private
1297
+ */
1298
+ getDestinationFields(path) {
1299
+ const pathArr = (0, import_utils11.ensurePathArray)(path);
1300
+ if (this.isPathToVariables(pathArr)) {
1301
+ return { fields: this.variables, leafName: pathArr[0] };
1302
+ }
1303
+ const leafName = pathArr.pop();
1304
+ return { fields: this.tree.getOrCreateFields(path), leafName };
1305
+ }
1179
1306
  };
1180
1307
 
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
- }
1308
+ // src/serializer/data-store-serializer.ts
1309
+ var import_utils12 = require("@axi-engine/utils");
1310
+ var DataStoreSerializer = class {
1311
+ /**
1312
+ * Creates an instance of DataStoreSerializer.
1313
+ * @param {FieldTreeSerializer} fieldTreeSerializer - The serializer used for the underlying tree and fields.
1314
+ */
1315
+ constructor(fieldTreeSerializer) {
1316
+ this.fieldTreeSerializer = fieldTreeSerializer;
1317
+ }
1318
+ /**
1319
+ * Captures the current state of a DataStore into a serializable snapshot.
1320
+ *
1321
+ * It checks for the existence of internal variables and the internal tree,
1322
+ * serializing them only if they have been initialized (lazy serialization).
1323
+ *
1324
+ * @param {DataStore} store - The store instance to serialize.
1325
+ * @returns {DataStoreSnapshot} The snapshot object.
1326
+ */
1327
+ snapshot(store) {
1328
+ let snapshot = {
1329
+ __type: store.typeName
1330
+ };
1331
+ const variables = store.getInternalVariables();
1332
+ if (variables) {
1333
+ snapshot.variables = this.fieldTreeSerializer.fieldsSerializer.snapshot(variables);
1334
+ }
1335
+ const tree = store.getInternalTree();
1336
+ if (tree) {
1337
+ snapshot.tree = this.fieldTreeSerializer.snapshot(tree);
1338
+ }
1339
+ return snapshot;
1340
+ }
1341
+ /**
1342
+ * Reconstructs a DataStore instance from a snapshot.
1343
+ *
1344
+ * If the snapshot contains a tree, the store is initialized with it.
1345
+ * If not, the store is initialized with the factory (lazy mode), and the
1346
+ * detached variables are injected if present.
1347
+ *
1348
+ * @param {DataStoreSnapshot} snapshot - The snapshot to hydrate.
1349
+ * @returns {DataStore} A new, fully restored DataStore instance.
1350
+ */
1351
+ hydrate(snapshot) {
1352
+ const tree = (0, import_utils12.isNullOrUndefined)(snapshot.tree) ? void 0 : this.fieldTreeSerializer.hydrate(snapshot.tree);
1353
+ const variables = (0, import_utils12.isNullOrUndefined)(snapshot.variables) ? void 0 : this.fieldTreeSerializer.fieldsSerializer.hydrate(snapshot.variables);
1354
+ return new DataStore(tree ? tree : this.fieldTreeSerializer.factory, variables);
1355
+ }
1356
+ };
1192
1357
 
1193
1358
  // src/setup.ts
1194
1359
  function createCoreFieldRegistry() {
@@ -1241,6 +1406,7 @@ function createCoreFieldSystem(config) {
1241
1406
  CoreStringField,
1242
1407
  CoreTreeNodeFactory,
1243
1408
  DataStore,
1409
+ DataStoreSerializer,
1244
1410
  FieldRegistry,
1245
1411
  FieldSerializer,
1246
1412
  FieldTree,
@@ -1258,7 +1424,7 @@ function createCoreFieldSystem(config) {
1258
1424
  createCoreTreeNodeFactory,
1259
1425
  createCoreTreeSerializer,
1260
1426
  createTypedMethodsMixin,
1427
+ isDataStore,
1261
1428
  isFieldTree,
1262
- isFields,
1263
- isStore
1429
+ isFields
1264
1430
  });