@getodk/xforms-engine 0.15.0 → 0.16.0

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.
Files changed (94) hide show
  1. package/dist/client/AttributeNode.d.ts +2 -5
  2. package/dist/client/BaseNode.d.ts +5 -0
  3. package/dist/client/form/FormInstanceConfig.d.ts +15 -0
  4. package/dist/index.js +395 -231
  5. package/dist/index.js.map +1 -1
  6. package/dist/instance/Attribute.d.ts +17 -11
  7. package/dist/instance/Group.d.ts +0 -2
  8. package/dist/instance/InputControl.d.ts +2 -0
  9. package/dist/instance/PrimaryInstance.d.ts +0 -2
  10. package/dist/instance/Root.d.ts +0 -2
  11. package/dist/instance/UploadControl.d.ts +0 -2
  12. package/dist/instance/abstract/InstanceNode.d.ts +2 -2
  13. package/dist/instance/abstract/ValueNode.d.ts +2 -1
  14. package/dist/instance/attachments/buildAttributes.d.ts +6 -2
  15. package/dist/instance/hierarchy.d.ts +1 -2
  16. package/dist/instance/internal-api/AttributeContext.d.ts +6 -0
  17. package/dist/instance/internal-api/InstanceConfig.d.ts +2 -0
  18. package/dist/instance/internal-api/InstanceValueContext.d.ts +6 -0
  19. package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +0 -1
  20. package/dist/instance/internal-api/serialization/ClientReactiveSerializableValueNode.d.ts +4 -0
  21. package/dist/instance/repeat/RepeatInstance.d.ts +0 -2
  22. package/dist/lib/codecs/items/SingleValueItemCodec.d.ts +1 -1
  23. package/dist/lib/reactivity/createInstanceValueState.d.ts +4 -1
  24. package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +2 -2
  25. package/dist/lib/xml-serialization.d.ts +1 -1
  26. package/dist/parse/XFormDOM.d.ts +3 -0
  27. package/dist/parse/expression/ActionComputationExpression.d.ts +4 -0
  28. package/dist/parse/model/ActionDefinition.d.ts +15 -0
  29. package/dist/parse/model/AttributeDefinition.d.ts +3 -1
  30. package/dist/parse/model/BindPreloadDefinition.d.ts +6 -10
  31. package/dist/parse/model/Event.d.ts +8 -0
  32. package/dist/parse/model/LeafNodeDefinition.d.ts +5 -2
  33. package/dist/parse/model/ModelActionMap.d.ts +9 -0
  34. package/dist/parse/model/ModelDefinition.d.ts +8 -1
  35. package/dist/parse/model/NoteNodeDefinition.d.ts +3 -2
  36. package/dist/parse/model/RangeNodeDefinition.d.ts +2 -1
  37. package/dist/parse/model/RootDefinition.d.ts +1 -0
  38. package/dist/solid.js +395 -231
  39. package/dist/solid.js.map +1 -1
  40. package/package.json +21 -17
  41. package/src/client/AttributeNode.ts +2 -5
  42. package/src/client/BaseNode.ts +6 -0
  43. package/src/client/form/FormInstanceConfig.ts +17 -0
  44. package/src/client/validation.ts +1 -1
  45. package/src/entrypoints/FormInstance.ts +1 -0
  46. package/src/instance/Attribute.ts +45 -45
  47. package/src/instance/Group.ts +1 -10
  48. package/src/instance/InputControl.ts +8 -1
  49. package/src/instance/ModelValue.ts +7 -1
  50. package/src/instance/Note.ts +6 -1
  51. package/src/instance/PrimaryInstance.ts +1 -11
  52. package/src/instance/RangeControl.ts +6 -1
  53. package/src/instance/RankControl.ts +7 -1
  54. package/src/instance/Root.ts +1 -10
  55. package/src/instance/SelectControl.ts +6 -1
  56. package/src/instance/TriggerControl.ts +6 -1
  57. package/src/instance/UploadControl.ts +1 -10
  58. package/src/instance/abstract/DescendantNode.ts +0 -5
  59. package/src/instance/abstract/InstanceNode.ts +2 -2
  60. package/src/instance/abstract/ValueNode.ts +2 -1
  61. package/src/instance/attachments/buildAttributes.ts +11 -4
  62. package/src/instance/children/normalizeChildInitOptions.ts +1 -1
  63. package/src/instance/hierarchy.ts +1 -3
  64. package/src/instance/internal-api/AttributeContext.ts +6 -0
  65. package/src/instance/internal-api/InstanceConfig.ts +6 -1
  66. package/src/instance/internal-api/InstanceValueContext.ts +6 -0
  67. package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +0 -1
  68. package/src/instance/internal-api/serialization/ClientReactiveSerializableValueNode.ts +4 -0
  69. package/src/instance/repeat/RepeatInstance.ts +1 -10
  70. package/src/lib/client-reactivity/instance-state/createValueNodeInstanceState.ts +2 -1
  71. package/src/lib/client-reactivity/instance-state/prepareInstancePayload.ts +1 -0
  72. package/src/lib/codecs/NoteCodec.ts +1 -1
  73. package/src/lib/codecs/items/SingleValueItemCodec.ts +1 -3
  74. package/src/lib/reactivity/createInstanceValueState.ts +152 -53
  75. package/src/lib/reactivity/node-state/createSharedNodeState.ts +2 -2
  76. package/src/lib/xml-serialization.ts +9 -1
  77. package/src/parse/XFormDOM.ts +9 -0
  78. package/src/parse/body/GroupElementDefinition.ts +1 -1
  79. package/src/parse/body/control/InputControlDefinition.ts +1 -1
  80. package/src/parse/expression/ActionComputationExpression.ts +12 -0
  81. package/src/parse/model/ActionDefinition.ts +70 -0
  82. package/src/parse/model/AttributeDefinition.ts +3 -2
  83. package/src/parse/model/AttributeDefinitionMap.ts +1 -1
  84. package/src/parse/model/BindDefinition.ts +1 -6
  85. package/src/parse/model/BindPreloadDefinition.ts +44 -12
  86. package/src/parse/model/Event.ts +9 -0
  87. package/src/parse/model/LeafNodeDefinition.ts +5 -1
  88. package/src/parse/model/ModelActionMap.ts +37 -0
  89. package/src/parse/model/ModelDefinition.ts +18 -3
  90. package/src/parse/model/NoteNodeDefinition.ts +5 -2
  91. package/src/parse/model/RangeNodeDefinition.ts +5 -2
  92. package/src/parse/model/RootDefinition.ts +22 -4
  93. package/dist/lib/reactivity/createAttributeValueState.d.ts +0 -15
  94. package/src/lib/reactivity/createAttributeValueState.ts +0 -189
package/dist/index.js CHANGED
@@ -19644,6 +19644,12 @@ class XFormDOM {
19644
19644
  contextNode: model
19645
19645
  }
19646
19646
  );
19647
+ const setValues = evaluator.evaluateNodes(
19648
+ "./xf:setvalue[@event]",
19649
+ {
19650
+ contextNode: model
19651
+ }
19652
+ );
19647
19653
  const instances = evaluator.evaluateNodes("./xf:instance", {
19648
19654
  contextNode: model
19649
19655
  });
@@ -19679,6 +19685,7 @@ class XFormDOM {
19679
19685
  this.title = title;
19680
19686
  this.model = model;
19681
19687
  this.binds = binds;
19688
+ this.setValues = setValues;
19682
19689
  this.primaryInstance = primaryInstance;
19683
19690
  this.primaryInstanceRoot = primaryInstanceRoot;
19684
19691
  this.itextTranslationElements = itextTranslationElements;
@@ -19696,6 +19703,7 @@ class XFormDOM {
19696
19703
  title;
19697
19704
  model;
19698
19705
  binds;
19706
+ setValues;
19699
19707
  primaryInstance;
19700
19708
  primaryInstanceRoot;
19701
19709
  itextTranslationElements;
@@ -20536,6 +20544,27 @@ class ControlDefinition extends BodyElementDefinition {
20536
20544
  }
20537
20545
  }
20538
20546
 
20547
+ const parseToInteger = (value) => {
20548
+ if (value === null) {
20549
+ return null;
20550
+ }
20551
+ const parsed = Number(value);
20552
+ if (typeof value !== "string" || value.trim() === "" || !Number.isInteger(parsed)) {
20553
+ throw new Error(`Expected an integer, but got: ${value}`);
20554
+ }
20555
+ return parsed;
20556
+ };
20557
+ const parseToFloat = (value) => {
20558
+ if (value === null) {
20559
+ return null;
20560
+ }
20561
+ const parsed = Number(value);
20562
+ if (typeof value !== "string" || value.trim() === "" || Number.isNaN(parsed)) {
20563
+ throw new Error(`Expected a float, but got: ${value}`);
20564
+ }
20565
+ return parsed;
20566
+ };
20567
+
20539
20568
  const inputAppearanceParser = new TokenListParser([
20540
20569
  "multiline",
20541
20570
  "numbers",
@@ -20569,27 +20598,6 @@ const inputAppearanceParser = new TokenListParser([
20569
20598
  "masked"
20570
20599
  ]);
20571
20600
 
20572
- const parseToInteger = (value) => {
20573
- if (value === null) {
20574
- return null;
20575
- }
20576
- const parsed = Number(value);
20577
- if (typeof value !== "string" || value.trim() === "" || !Number.isInteger(parsed)) {
20578
- throw new Error(`Expected an integer, but got: ${value}`);
20579
- }
20580
- return parsed;
20581
- };
20582
- const parseToFloat = (value) => {
20583
- if (value === null) {
20584
- return null;
20585
- }
20586
- const parsed = Number(value);
20587
- if (typeof value !== "string" || value.trim() === "" || Number.isNaN(parsed)) {
20588
- throw new Error(`Expected a float, but got: ${value}`);
20589
- }
20590
- return parsed;
20591
- };
20592
-
20593
20601
  class InputControlDefinition extends ControlDefinition {
20594
20602
  static isCompatible(localName) {
20595
20603
  return localName === "input";
@@ -20966,8 +20974,8 @@ class GroupElementDefinition extends BodyElementDefinition {
20966
20974
  const childName = child.localName;
20967
20975
  return childName !== "label";
20968
20976
  });
20969
- this.children = this.body.getChildElementDefinitions(form, this, element, childElements);
20970
20977
  this.reference = parseNodesetReference(parent, element, "ref");
20978
+ this.children = this.body.getChildElementDefinitions(form, this, element, childElements);
20971
20979
  this.appearances = structureElementAppearanceParser.parseFrom(element, "appearance");
20972
20980
  this.label = LabelDefinition.forGroup(form, this);
20973
20981
  }
@@ -21573,6 +21581,105 @@ class ItextTranslationsDefinition extends Map {
21573
21581
  }
21574
21582
  }
21575
21583
 
21584
+ class ActionComputationExpression extends DependentExpression {
21585
+ constructor(resultType, expression) {
21586
+ super(resultType, expression);
21587
+ }
21588
+ }
21589
+
21590
+ const XFORM_EVENT = {
21591
+ odkInstanceLoad: "odk-instance-load",
21592
+ odkInstanceFirstLoad: "odk-instance-first-load",
21593
+ odkNewRepeat: "odk-new-repeat",
21594
+ xformsRevalidate: "xforms-revalidate",
21595
+ xformsValueChanged: "xforms-value-changed"
21596
+ };
21597
+
21598
+ class ActionDefinition {
21599
+ constructor(model, element, source) {
21600
+ this.element = element;
21601
+ const ref = ActionDefinition.getRef(model, element);
21602
+ if (!ref) {
21603
+ throw new Error(
21604
+ 'Invalid setvalue element - you must define either "ref" or "bind" attribute'
21605
+ );
21606
+ }
21607
+ this.ref = ref;
21608
+ this.events = ActionDefinition.getEvents(element);
21609
+ const value = ActionDefinition.getValue(element);
21610
+ this.computation = new ActionComputationExpression("string", value);
21611
+ this.source = source;
21612
+ }
21613
+ static getRef(model, setValueElement) {
21614
+ if (setValueElement.hasAttribute("ref")) {
21615
+ return setValueElement.getAttribute("ref") ?? null;
21616
+ }
21617
+ if (setValueElement.hasAttribute("bind")) {
21618
+ const bindId = setValueElement.getAttribute("bind");
21619
+ const bindDefinition = Array.from(model.binds.values()).find((definition) => {
21620
+ return definition.bindElement.getAttribute("id") === bindId;
21621
+ });
21622
+ return bindDefinition?.nodeset ?? null;
21623
+ }
21624
+ return null;
21625
+ }
21626
+ static getValue(element) {
21627
+ if (element.hasAttribute("value")) {
21628
+ return element.getAttribute("value") || "''";
21629
+ }
21630
+ if (element.firstChild && isTextNode(element.firstChild)) {
21631
+ return `'${element.firstChild.nodeValue}'`;
21632
+ }
21633
+ return "''";
21634
+ }
21635
+ static isKnownEvent = (event) => {
21636
+ return Object.values(XFORM_EVENT).includes(event);
21637
+ };
21638
+ static getEvents(element) {
21639
+ const events = element.getAttribute("event")?.split(" ") ?? [];
21640
+ const unknownEvents = events.filter((event) => !this.isKnownEvent(event));
21641
+ if (unknownEvents.length) {
21642
+ throw new Error(
21643
+ `An action was registered for unsupported events: ${unknownEvents.join(", ")}`
21644
+ );
21645
+ }
21646
+ return events;
21647
+ }
21648
+ ref;
21649
+ events;
21650
+ computation;
21651
+ source;
21652
+ }
21653
+
21654
+ const REPEAT_REGEX = /(\[[^\]]*\])/gm;
21655
+ class ModelActionMap extends Map {
21656
+ static fromModel(model) {
21657
+ return new this(model);
21658
+ }
21659
+ static getKey(ref) {
21660
+ return ref.replace(REPEAT_REGEX, "");
21661
+ }
21662
+ constructor(model) {
21663
+ super(
21664
+ model.form.xformDOM.setValues.map((setValueElement) => {
21665
+ const action = new ActionDefinition(model, setValueElement);
21666
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
21667
+ throw new Error('Model contains "setvalue" element with "odk-new-repeat" event');
21668
+ }
21669
+ const key = ModelActionMap.getKey(action.ref);
21670
+ return [key, action];
21671
+ })
21672
+ );
21673
+ }
21674
+ get(ref) {
21675
+ return super.get(ModelActionMap.getKey(ref));
21676
+ }
21677
+ add(action) {
21678
+ const key = ModelActionMap.getKey(action.ref);
21679
+ this.set(key, action);
21680
+ }
21681
+ }
21682
+
21576
21683
  const defaultBindComputationExpressions = {
21577
21684
  calculate: null,
21578
21685
  constraint: "true()",
@@ -21638,6 +21745,7 @@ class MessageDefinition extends TextRangeDefinition {
21638
21745
  chunks;
21639
21746
  }
21640
21747
 
21748
+ const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
21641
21749
  const getPreloadInput = (bindElement) => {
21642
21750
  const type = bindElement.getAttributeNS(JAVAROSA_NAMESPACE_URI$1, "preload");
21643
21751
  if (type == null) {
@@ -21662,9 +21770,38 @@ class BindPreloadDefinition {
21662
21770
  }
21663
21771
  type;
21664
21772
  parameter;
21773
+ event;
21774
+ getValue(context) {
21775
+ if (this.type === "uid") {
21776
+ return context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION);
21777
+ }
21778
+ if (this.type === "timestamp") {
21779
+ return context.evaluator.evaluateString("now()");
21780
+ }
21781
+ if (this.type === "date") {
21782
+ return context.evaluator.evaluateString("today()");
21783
+ }
21784
+ if (this.type === "property") {
21785
+ const properties = context.instanceConfig.preloadProperties;
21786
+ if (this.parameter === "deviceid") {
21787
+ return properties.deviceID;
21788
+ }
21789
+ if (this.parameter === "email") {
21790
+ return properties.email;
21791
+ }
21792
+ if (this.parameter === "phonenumber") {
21793
+ return properties.phoneNumber;
21794
+ }
21795
+ if (this.parameter === "username") {
21796
+ return properties.username;
21797
+ }
21798
+ }
21799
+ return;
21800
+ }
21665
21801
  constructor(input) {
21666
21802
  this.type = input.type;
21667
21803
  this.parameter = input.parameter;
21804
+ this.event = this.type === "timestamp" && this.parameter === "end" ? XFORM_EVENT.xformsRevalidate : XFORM_EVENT.odkInstanceFirstLoad;
21668
21805
  }
21669
21806
  }
21670
21807
 
@@ -21811,10 +21948,7 @@ class BindDefinition extends DependencyContext {
21811
21948
  // TODO: it is unclear whether this will need to be supported.
21812
21949
  // https://github.com/getodk/collect/issues/3758 mentions deprecation.
21813
21950
  saveIncomplete;
21814
- // TODO: these are deferred until prioritized
21815
- // readonly preload: string | null;
21816
- // readonly preloadParams: string | null;
21817
- // readonly 'max-pixels': string | null;
21951
+ // TODO: deferred until prioritized: readonly 'max-pixels': string | null;
21818
21952
  _parentBind;
21819
21953
  get parentBind() {
21820
21954
  let bind = this._parentBind;
@@ -21980,8 +22114,14 @@ const serializeParentElementXML = (qualifiedName, children, attributes, namespac
21980
22114
  namespaceDeclarations
21981
22115
  );
21982
22116
  };
21983
- const serializeLeafElementXML = (qualifiedName, xmlValue, namespaceDeclarations) => {
21984
- return serializeElementXML(qualifiedName, xmlValue.normalize(), "", namespaceDeclarations);
22117
+ const serializeLeafElementXML = (qualifiedName, xmlValue, attributes, namespaceDeclarations) => {
22118
+ const serializedAttributes = attributes?.map((attribute) => attribute.instanceState.instanceXML).join("") ?? "";
22119
+ return serializeElementXML(
22120
+ qualifiedName,
22121
+ xmlValue.normalize(),
22122
+ serializedAttributes,
22123
+ namespaceDeclarations
22124
+ );
21985
22125
  };
21986
22126
 
21987
22127
  class NamespaceDeclaration {
@@ -22211,11 +22351,12 @@ class NodeDefinition {
22211
22351
  }
22212
22352
 
22213
22353
  class AttributeDefinition extends NodeDefinition {
22214
- constructor(root, bind, template) {
22354
+ constructor(model, bind, template) {
22215
22355
  super(bind);
22356
+ this.model = model;
22216
22357
  this.template = template;
22217
22358
  const { value } = template;
22218
- this.root = root;
22359
+ this.root = model.root;
22219
22360
  this.value = value;
22220
22361
  this.qualifiedName = template.qualifiedName;
22221
22362
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
@@ -22250,7 +22391,7 @@ class AttributeDefinitionMap extends Map {
22250
22391
  const nonNamespaceAttributes = instanceNode.attributes.filter(isNonNamespaceAttribute);
22251
22392
  const definitions = nonNamespaceAttributes.map((attribute) => {
22252
22393
  const bind = model.binds.getOrCreateBindDefinition(attribute.nodeset);
22253
- return new AttributeDefinition(model.root, bind, attribute);
22394
+ return new AttributeDefinition(model, bind, attribute);
22254
22395
  });
22255
22396
  return new this(definitions);
22256
22397
  }
@@ -22302,22 +22443,24 @@ class GroupDefinition extends DescendentNodeDefinition {
22302
22443
  }
22303
22444
 
22304
22445
  class LeafNodeDefinition extends DescendentNodeDefinition {
22305
- constructor(parent, bind, bodyElement, template) {
22446
+ constructor(model, parent, bind, bodyElement, template) {
22306
22447
  if (bodyElement != null && bodyElement.category !== "control") {
22307
22448
  throw new Error(`Unexpected body element for nodeset ${bind.nodeset}`);
22308
22449
  }
22309
22450
  super(parent, bind, bodyElement);
22451
+ this.model = model;
22310
22452
  this.template = template;
22311
22453
  this.valueType = bind.type.resolved;
22312
22454
  this.qualifiedName = template.qualifiedName;
22313
22455
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
22456
+ this.attributes = AttributeDefinitionMap.from(model, template);
22314
22457
  }
22315
22458
  type = "leaf-node";
22316
22459
  valueType;
22317
22460
  namespaceDeclarations;
22318
22461
  qualifiedName;
22319
22462
  children = null;
22320
- attributes = null;
22463
+ attributes;
22321
22464
  toJSON() {
22322
22465
  const { bind, bodyElement, parent, root, ...rest } = this;
22323
22466
  return rest;
@@ -22328,13 +22471,13 @@ const isNoteBindDefinition = (bind) => {
22328
22471
  return bind.readonly.isConstantTruthyExpression();
22329
22472
  };
22330
22473
  class NoteNodeDefinition extends LeafNodeDefinition {
22331
- constructor(parent, bind, bodyElement, noteTextDefinition, template) {
22332
- super(parent, bind, bodyElement, template);
22474
+ constructor(model, parent, bind, bodyElement, noteTextDefinition, template) {
22475
+ super(model, parent, bind, bodyElement, template);
22333
22476
  this.bind = bind;
22334
22477
  this.bodyElement = bodyElement;
22335
22478
  this.noteTextDefinition = noteTextDefinition;
22336
22479
  }
22337
- static from(parent, bind, bodyElement, node) {
22480
+ static from(model, parent, bind, bodyElement, node) {
22338
22481
  if (!isNoteBindDefinition(bind) || bodyElement?.type !== "input") {
22339
22482
  return null;
22340
22483
  }
@@ -22343,7 +22486,7 @@ class NoteNodeDefinition extends LeafNodeDefinition {
22343
22486
  if (noteTextDefinition == null) {
22344
22487
  return null;
22345
22488
  }
22346
- return new this(parent, bind, bodyElement, noteTextDefinition, node);
22489
+ return new this(model, parent, bind, bodyElement, noteTextDefinition, node);
22347
22490
  }
22348
22491
  }
22349
22492
 
@@ -26554,15 +26697,15 @@ class RangeNodeBoundsDefinition {
26554
26697
  }
26555
26698
  }
26556
26699
  class RangeNodeDefinition extends LeafNodeDefinition {
26557
- constructor(parent, bind, bodyElement, node) {
26558
- super(parent, bind, bodyElement, node);
26700
+ constructor(model, parent, bind, bodyElement, node) {
26701
+ super(model, parent, bind, bodyElement, node);
26559
26702
  this.bind = bind;
26560
26703
  this.bodyElement = bodyElement;
26561
26704
  this.bounds = RangeNodeBoundsDefinition.from(bodyElement.bounds, bind);
26562
26705
  }
26563
- static from(parent, bind, bodyElement, node) {
26706
+ static from(model, parent, bind, bodyElement, node) {
26564
26707
  assertRangeBindDefinition(bind);
26565
- return new this(parent, bind, bodyElement, node);
26708
+ return new this(model, parent, bind, bodyElement, node);
26566
26709
  }
26567
26710
  bounds;
26568
26711
  }
@@ -26698,6 +26841,18 @@ class RootDefinition extends NodeDefinition {
26698
26841
  attributes;
26699
26842
  children;
26700
26843
  isTranslated = false;
26844
+ mapActions(bodyElement) {
26845
+ const source = bodyElement.reference;
26846
+ if (!source) {
26847
+ return;
26848
+ }
26849
+ for (const child of bodyElement.element.children) {
26850
+ if (child.nodeName === "setvalue") {
26851
+ const action = new ActionDefinition(this.model, child, source);
26852
+ this.model.actions.add(action);
26853
+ }
26854
+ }
26855
+ }
26701
26856
  buildSubtree(parent, node) {
26702
26857
  const { form, model } = this;
26703
26858
  const { body } = form;
@@ -26720,6 +26875,9 @@ class RootDefinition extends NodeDefinition {
26720
26875
  const bind = binds.getOrCreateBindDefinition(nodeset);
26721
26876
  const bodyElement = body.getBodyElement(nodeset);
26722
26877
  const [firstChild, ...restChildren] = children;
26878
+ if (bodyElement) {
26879
+ this.mapActions(bodyElement);
26880
+ }
26723
26881
  if (bodyElement?.type === "repeat") {
26724
26882
  return RepeatDefinition.from(model, parent, bind, bodyElement, children);
26725
26883
  }
@@ -26729,9 +26887,9 @@ class RootDefinition extends NodeDefinition {
26729
26887
  const element = firstChild;
26730
26888
  if (element.isLeafElement()) {
26731
26889
  if (bodyElement?.type === "range") {
26732
- return RangeNodeDefinition.from(parent, bind, bodyElement, element);
26890
+ return RangeNodeDefinition.from(model, parent, bind, bodyElement, element);
26733
26891
  }
26734
- return NoteNodeDefinition.from(parent, bind, bodyElement, element) ?? new LeafNodeDefinition(parent, bind, bodyElement, element);
26892
+ return NoteNodeDefinition.from(model, parent, bind, bodyElement, element) ?? new LeafNodeDefinition(model, parent, bind, bodyElement, element);
26735
26893
  }
26736
26894
  return new GroupDefinition(model, parent, bind, bodyElement, element);
26737
26895
  });
@@ -26779,6 +26937,7 @@ class ModelDefinition {
26779
26937
  this.form = form;
26780
26938
  const submission = new SubmissionDefinition(form.xformDOM);
26781
26939
  this.binds = ModelBindMap.fromModel(this);
26940
+ this.actions = ModelActionMap.fromModel(this);
26782
26941
  this.instance = parseStaticDocumentFromDOMSubtree(form.xformDOM.primaryInstanceRoot, {
26783
26942
  nodesetPrefix: "/"
26784
26943
  });
@@ -26786,13 +26945,16 @@ class ModelDefinition {
26786
26945
  this.nodes = nodeDefinitionMap(this.root);
26787
26946
  this.itextTranslations = ItextTranslationsDefinition.from(form.xformDOM);
26788
26947
  this.itextChunks = generateItextChunks(form.xformDOM.itextTranslationElements);
26948
+ this.xformsRevalidateListeners = /* @__PURE__ */ new Map();
26789
26949
  }
26790
26950
  binds;
26951
+ actions;
26791
26952
  root;
26792
26953
  nodes;
26793
26954
  instance;
26794
26955
  itextTranslations;
26795
26956
  itextChunks;
26957
+ xformsRevalidateListeners;
26796
26958
  getNodeDefinition(nodeset) {
26797
26959
  const definition = this.nodes.get(nodeset);
26798
26960
  if (definition == null) {
@@ -26807,14 +26969,20 @@ class ModelDefinition {
26807
26969
  }
26808
26970
  return definition;
26809
26971
  }
26810
- toJSON() {
26811
- const { form, ...rest } = this;
26812
- return rest;
26972
+ registerXformsRevalidateListener(ref, listener) {
26973
+ this.xformsRevalidateListeners.set(ref, listener);
26974
+ }
26975
+ triggerXformsRevalidateListeners() {
26976
+ this.xformsRevalidateListeners.forEach((listener) => listener());
26813
26977
  }
26814
26978
  getTranslationChunks(itextId, activeLanguage) {
26815
26979
  const languageMap = this.itextChunks.get(activeLanguage.language);
26816
26980
  return languageMap?.get(itextId) ?? [];
26817
26981
  }
26982
+ toJSON() {
26983
+ const { form, ...rest } = this;
26984
+ return rest;
26985
+ }
26818
26986
  }
26819
26987
 
26820
26988
  class XFormDefinition {
@@ -28878,6 +29046,7 @@ const chunkedInstancePayload = (validation, submissionMeta, instanceFile, attach
28878
29046
  };
28879
29047
  };
28880
29048
  const prepareInstancePayload = (instanceRoot, options) => {
29049
+ instanceRoot.root.parent.model.triggerXformsRevalidateListeners();
28881
29050
  const validation = validateInstance(instanceRoot);
28882
29051
  const submissionMeta = instanceRoot.definition.submission;
28883
29052
  const instanceFile = new InstanceFile(instanceRoot);
@@ -29306,17 +29475,21 @@ const createComputedExpression = (context, dependentExpression, options = {}) =>
29306
29475
  });
29307
29476
  };
29308
29477
 
29309
- const isInstanceFirstLoad$1 = (context) => {
29478
+ const REPEAT_INDEX_REGEX = /([^[]*)(\[[0-9]+\])/g;
29479
+ const isInstanceFirstLoad = (context) => {
29310
29480
  return context.rootDocument.initializationMode === "create";
29311
29481
  };
29312
- const isEditInitialLoad$1 = (context) => {
29482
+ const isAddingRepeatChild = (context) => {
29483
+ return context.rootDocument.isAttached();
29484
+ };
29485
+ const isEditInitialLoad = (context) => {
29313
29486
  return context.rootDocument.initializationMode === "edit";
29314
29487
  };
29315
- const getInitialValue$1 = (context) => {
29488
+ const getInitialValue = (context) => {
29316
29489
  const sourceNode = context.instanceNode ?? context.definition.template;
29317
29490
  return context.decodeInstanceValue(sourceNode.value);
29318
29491
  };
29319
- const createRelevantValueState$1 = (context, baseValueState) => {
29492
+ const createRelevantValueState = (context, baseValueState) => {
29320
29493
  return context.scope.runTask(() => {
29321
29494
  const [getRelevantValue, setValue] = baseValueState;
29322
29495
  const getValue = createMemo(() => {
@@ -29328,7 +29501,7 @@ const createRelevantValueState$1 = (context, baseValueState) => {
29328
29501
  return [getValue, setValue];
29329
29502
  });
29330
29503
  };
29331
- const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29504
+ const guardDownstreamReadonlyWrites = (context, baseState) => {
29332
29505
  const { readonly } = context.definition.bind;
29333
29506
  if (readonly.isDefaultExpression) {
29334
29507
  return baseState;
@@ -29343,88 +29516,161 @@ const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29343
29516
  };
29344
29517
  return [getValue, setValue];
29345
29518
  };
29346
- const PRELOAD_UID_EXPRESSION$1 = 'concat("uuid:", uuid())';
29347
- const shouldPreloadUID$1 = (context) => {
29348
- return isInstanceFirstLoad$1(context) || isEditInitialLoad$1(context);
29519
+ const isLoading = (context) => {
29520
+ return isInstanceFirstLoad(context) || isEditInitialLoad(context);
29521
+ };
29522
+ const setValueIfPreloadDefined = (context, setValue, preload) => {
29523
+ const value = preload.getValue(context);
29524
+ if (value) {
29525
+ setValue(value);
29526
+ }
29527
+ };
29528
+ const postloadValue = (context, setValue, preload) => {
29529
+ const ref = context.contextReference();
29530
+ context.definition.model.registerXformsRevalidateListener(ref, () => {
29531
+ setValueIfPreloadDefined(context, setValue, preload);
29532
+ });
29349
29533
  };
29350
- const setPreloadUIDValue$1 = (context, valueState) => {
29534
+ const preloadValue = (context, setValue) => {
29351
29535
  const { preload } = context.definition.bind;
29352
- if (preload?.type !== "uid" || !shouldPreloadUID$1(context)) {
29536
+ if (!preload) {
29353
29537
  return;
29354
29538
  }
29355
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION$1, {
29539
+ if (preload.event === XFORM_EVENT.xformsRevalidate) {
29540
+ postloadValue(context, setValue, preload);
29541
+ return;
29542
+ }
29543
+ if (isLoading(context)) {
29544
+ setValueIfPreloadDefined(context, setValue, preload);
29545
+ }
29546
+ };
29547
+ const referencesCurrentNode = (context, ref) => {
29548
+ const nodes = context.evaluator.evaluateNodes(ref, {
29356
29549
  contextNode: context.contextNode
29357
29550
  });
29358
- const [, setValue] = valueState;
29359
- setValue(preloadUIDValue);
29551
+ if (nodes.length > 1) {
29552
+ throw new Error(
29553
+ "You are trying to target a repeated field. Currently you may only target a field in a specific repeat instance. XPath nodeset has more than one node."
29554
+ );
29555
+ }
29556
+ return nodes.includes(context.contextNode);
29360
29557
  };
29361
- const createCalculation$1 = (context, setRelevantValue, calculateDefinition) => {
29362
- context.scope.runTask(() => {
29363
- const calculate = createComputedExpression(context, calculateDefinition, {
29364
- defaultValue: ""
29365
- });
29366
- createComputed(() => {
29367
- if (context.isAttached() && context.isRelevant()) {
29368
- const calculated = calculate();
29369
- const value = context.decodeInstanceValue(calculated);
29370
- setRelevantValue(value);
29558
+ const bindToRepeatInstance = (context, action) => {
29559
+ let source = action.source;
29560
+ let ref = action.ref;
29561
+ if (source) {
29562
+ const contextRef = context.contextReference();
29563
+ for (const part of contextRef.matchAll(REPEAT_INDEX_REGEX)) {
29564
+ const unbound = part[1] + "/";
29565
+ if (source.includes(unbound)) {
29566
+ const bound = part[0] + "/";
29567
+ source = source.replace(unbound, bound);
29568
+ ref = ref.replace(unbound, bound);
29371
29569
  }
29372
- });
29570
+ }
29571
+ }
29572
+ return { source, ref };
29573
+ };
29574
+ const createCalculation = (context, setRelevantValue, computation) => {
29575
+ const calculate = createComputedExpression(context, computation);
29576
+ createComputed(() => {
29577
+ if (context.isAttached() && context.isRelevant()) {
29578
+ const calculated = calculate();
29579
+ const value = context.decodeInstanceValue(calculated);
29580
+ setRelevantValue(value);
29581
+ }
29582
+ });
29583
+ };
29584
+ const createValueChangedCalculation = (context, setRelevantValue, action) => {
29585
+ const { source, ref } = bindToRepeatInstance(context, action);
29586
+ if (!source) {
29587
+ return;
29588
+ }
29589
+ let previous = "";
29590
+ const sourceElementExpression = new ActionComputationExpression("string", source);
29591
+ const calculateValueSource = createComputedExpression(context, sourceElementExpression);
29592
+ createComputed(() => {
29593
+ if (context.isAttached() && context.isRelevant()) {
29594
+ const valueSource = calculateValueSource();
29595
+ if (previous !== valueSource) {
29596
+ if (referencesCurrentNode(context, ref)) {
29597
+ const calc = context.evaluator.evaluateString(action.computation.expression, context);
29598
+ const value = context.decodeInstanceValue(calc);
29599
+ setRelevantValue(value);
29600
+ }
29601
+ }
29602
+ previous = valueSource;
29603
+ }
29373
29604
  });
29374
29605
  };
29375
- const createAttributeValueState = (context) => {
29606
+ const registerAction = (context, setValue, action) => {
29607
+ if (action.events.includes(XFORM_EVENT.odkInstanceFirstLoad)) {
29608
+ if (isInstanceFirstLoad(context)) {
29609
+ createCalculation(context, setValue, action.computation);
29610
+ }
29611
+ }
29612
+ if (action.events.includes(XFORM_EVENT.odkInstanceLoad)) {
29613
+ if (!isAddingRepeatChild(context)) {
29614
+ createCalculation(context, setValue, action.computation);
29615
+ }
29616
+ }
29617
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
29618
+ if (isAddingRepeatChild(context)) {
29619
+ createCalculation(context, setValue, action.computation);
29620
+ }
29621
+ }
29622
+ if (action.events.includes(XFORM_EVENT.xformsValueChanged)) {
29623
+ createValueChangedCalculation(context, setValue, action);
29624
+ }
29625
+ };
29626
+ const createInstanceValueState = (context) => {
29376
29627
  return context.scope.runTask(() => {
29377
- const initialValue = getInitialValue$1(context);
29628
+ const initialValue = getInitialValue(context);
29378
29629
  const baseValueState = createSignal(initialValue);
29379
- const relevantValueState = createRelevantValueState$1(context, baseValueState);
29380
- setPreloadUIDValue$1(context, relevantValueState);
29630
+ const relevantValueState = createRelevantValueState(context, baseValueState);
29631
+ const [, setValue] = relevantValueState;
29632
+ preloadValue(context, setValue);
29381
29633
  const { calculate } = context.definition.bind;
29382
29634
  if (calculate != null) {
29383
- const [, setValue] = relevantValueState;
29384
- createCalculation$1(context, setValue, calculate);
29635
+ createCalculation(context, setValue, calculate);
29385
29636
  }
29386
- return guardDownstreamReadonlyWrites$1(context, relevantValueState);
29637
+ const action = context.definition.model.actions.get(context.contextReference());
29638
+ if (action) {
29639
+ registerAction(context, setValue, action);
29640
+ }
29641
+ return guardDownstreamReadonlyWrites(context, relevantValueState);
29387
29642
  });
29388
29643
  };
29389
29644
 
29390
- class Attribute extends InstanceNode {
29391
- constructor(parent, definition, instanceNode) {
29392
- const codec = getSharedValueCodec("string");
29393
- super(parent.instanceConfig, parent, instanceNode, definition, {
29394
- scope: parent.scope,
29395
- computeReference: () => "@" + this.definition.qualifiedName.getPrefixedName()
29396
- });
29645
+ class Attribute {
29646
+ constructor(owner, definition, instanceNode) {
29647
+ this.owner = owner;
29648
+ this.definition = definition;
29397
29649
  this.instanceNode = instanceNode;
29398
- this.root = parent.root;
29399
- this.getActiveLanguage = parent.getActiveLanguage;
29650
+ const codec = getSharedValueCodec("string");
29651
+ this.contextNode = owner;
29652
+ this.scope = owner.scope;
29653
+ this.rootDocument = owner.rootDocument;
29654
+ this.root = owner.root;
29655
+ this.instanceConfig = owner.instanceConfig;
29656
+ this.getActiveLanguage = owner.getActiveLanguage;
29400
29657
  this.validationState = { violations: [] };
29401
29658
  this.valueType = "string";
29402
- this.evaluator = parent.evaluator;
29659
+ this.evaluator = owner.evaluator;
29403
29660
  this.decodeInstanceValue = codec.decodeInstanceValue;
29404
- const instanceValueState = createAttributeValueState(this);
29661
+ const instanceValueState = createInstanceValueState(this);
29405
29662
  const valueState = codec.createRuntimeValueState(instanceValueState);
29406
29663
  const [getInstanceValue] = instanceValueState;
29407
29664
  const [, setValueState] = valueState;
29408
29665
  this.getInstanceValue = getInstanceValue;
29409
29666
  this.setValueState = setValueState;
29410
- this.getXPathValue = () => {
29411
- return this.getInstanceValue();
29412
- };
29413
29667
  this.valueState = valueState;
29414
29668
  const state = createSharedNodeState(
29415
- this.scope,
29669
+ owner.scope,
29416
29670
  {
29417
- reference: this.contextReference,
29418
- readonly: this.isReadonly,
29419
- relevant: this.isRelevant,
29420
- required: () => false,
29421
- label: null,
29422
- hint: null,
29423
- children: null,
29424
- valueOptions: null,
29425
29671
  value: this.valueState,
29426
29672
  instanceValue: this.getInstanceValue,
29427
- attributes: null
29673
+ relevant: this.owner.isRelevant
29428
29674
  },
29429
29675
  this.instanceConfig
29430
29676
  );
@@ -29449,23 +29695,30 @@ class Attribute extends InstanceNode {
29449
29695
  setValueState;
29450
29696
  evaluator;
29451
29697
  getActiveLanguage;
29698
+ contextNode;
29699
+ scope;
29700
+ rootDocument;
29701
+ instanceConfig;
29452
29702
  root;
29453
29703
  isRelevant = () => {
29454
- return this.parent.isRelevant();
29704
+ return this.owner.isRelevant();
29455
29705
  };
29456
29706
  isAttached = () => {
29457
- return this.parent.isAttached();
29707
+ return this.owner.isAttached();
29458
29708
  };
29459
29709
  isReadonly = () => {
29460
29710
  return true;
29461
29711
  };
29462
29712
  hasReadonlyAncestor = () => {
29463
- const { parent } = this;
29464
- return parent.hasReadonlyAncestor() || parent.isReadonly();
29713
+ const { owner } = this;
29714
+ return owner.hasReadonlyAncestor() || owner.isReadonly();
29465
29715
  };
29466
29716
  hasNonRelevantAncestor = () => {
29467
- const { parent } = this;
29468
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29717
+ const { owner } = this;
29718
+ return owner.hasNonRelevantAncestor() || !owner.isRelevant();
29719
+ };
29720
+ contextReference = () => {
29721
+ return this.owner.contextReference() + "/@" + this.definition.qualifiedName.getPrefixedName();
29469
29722
  };
29470
29723
  setValue(value) {
29471
29724
  this.setValueState(value);
@@ -29474,11 +29727,17 @@ class Attribute extends InstanceNode {
29474
29727
  getChildren() {
29475
29728
  return [];
29476
29729
  }
29730
+ getXPathChildNodes() {
29731
+ return [];
29732
+ }
29733
+ getXPathValue() {
29734
+ return "";
29735
+ }
29477
29736
  }
29478
29737
 
29479
- function buildAttributes(parent) {
29480
- return Array.from(parent.definition.attributes.values()).map((attributeDefinition) => {
29481
- return new Attribute(parent, attributeDefinition, attributeDefinition.template);
29738
+ function buildAttributes(owner) {
29739
+ return Array.from(owner.definition.attributes.values()).map((attributeDefinition) => {
29740
+ return new Attribute(owner, attributeDefinition, attributeDefinition.template);
29482
29741
  });
29483
29742
  }
29484
29743
 
@@ -29582,11 +29841,6 @@ class DescendantNode extends InstanceNode {
29582
29841
  return true;
29583
29842
  }
29584
29843
  }
29585
- for (const attr of parent.getAttributes()) {
29586
- if (attr === self) {
29587
- return true;
29588
- }
29589
- }
29590
29844
  return false;
29591
29845
  });
29592
29846
  });
@@ -39976,7 +40230,6 @@ const createNodeLabel = (context, definition) => {
39976
40230
 
39977
40231
  class Group extends DescendantNode {
39978
40232
  childrenState;
39979
- attributeState;
39980
40233
  [XPathNodeKindKey] = "element";
39981
40234
  // InstanceNode
39982
40235
  state;
@@ -39994,7 +40247,6 @@ class Group extends DescendantNode {
39994
40247
  const childrenState = createChildrenState(this);
39995
40248
  const attributeState = createAttributeState(this.scope);
39996
40249
  this.childrenState = childrenState;
39997
- this.attributeState = attributeState;
39998
40250
  const state = createSharedNodeState(
39999
40251
  this.scope,
40000
40252
  {
@@ -40026,9 +40278,6 @@ class Group extends DescendantNode {
40026
40278
  getChildren() {
40027
40279
  return this.childrenState.getChildren();
40028
40280
  }
40029
- getAttributes() {
40030
- return this.attributeState.getAttributes();
40031
- }
40032
40281
  }
40033
40282
 
40034
40283
  const createFieldHint = (context, definition) => {
@@ -40047,92 +40296,12 @@ const createValueNodeInstanceState = (node) => {
40047
40296
  return "";
40048
40297
  }
40049
40298
  const xmlValue = escapeXMLText(node.currentState.instanceValue);
40050
- return serializeLeafElementXML(qualifiedName, xmlValue);
40299
+ const attributes = node.currentState.attributes;
40300
+ return serializeLeafElementXML(qualifiedName, xmlValue, attributes);
40051
40301
  }
40052
40302
  };
40053
40303
  };
40054
40304
 
40055
- const isInstanceFirstLoad = (context) => {
40056
- return context.rootDocument.initializationMode === "create";
40057
- };
40058
- const isEditInitialLoad = (context) => {
40059
- return context.rootDocument.initializationMode === "edit";
40060
- };
40061
- const getInitialValue = (context) => {
40062
- const sourceNode = context.instanceNode ?? context.definition.template;
40063
- return context.decodeInstanceValue(sourceNode.value);
40064
- };
40065
- const createRelevantValueState = (context, baseValueState) => {
40066
- return context.scope.runTask(() => {
40067
- const [getRelevantValue, setValue] = baseValueState;
40068
- const getValue = createMemo(() => {
40069
- if (context.isRelevant()) {
40070
- return getRelevantValue();
40071
- }
40072
- return "";
40073
- });
40074
- return [getValue, setValue];
40075
- });
40076
- };
40077
- const guardDownstreamReadonlyWrites = (context, baseState) => {
40078
- const { readonly } = context.definition.bind;
40079
- if (readonly.isDefaultExpression) {
40080
- return baseState;
40081
- }
40082
- const [getValue, baseSetValue] = baseState;
40083
- const setValue = (value) => {
40084
- if (context.isReadonly()) {
40085
- const reference = untrack(() => context.contextReference());
40086
- throw new Error(`Cannot write to readonly field: ${reference}`);
40087
- }
40088
- return baseSetValue(value);
40089
- };
40090
- return [getValue, setValue];
40091
- };
40092
- const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
40093
- const shouldPreloadUID = (context) => {
40094
- return isInstanceFirstLoad(context) || isEditInitialLoad(context);
40095
- };
40096
- const setPreloadUIDValue = (context, valueState) => {
40097
- const { preload } = context.definition.bind;
40098
- if (preload?.type !== "uid" || !shouldPreloadUID(context)) {
40099
- return;
40100
- }
40101
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION, {
40102
- contextNode: context.contextNode
40103
- });
40104
- const [, setValue] = valueState;
40105
- setValue(preloadUIDValue);
40106
- };
40107
- const createCalculation = (context, setRelevantValue, calculateDefinition) => {
40108
- context.scope.runTask(() => {
40109
- const calculate = createComputedExpression(context, calculateDefinition, {
40110
- defaultValue: ""
40111
- });
40112
- createComputed(() => {
40113
- if (context.isAttached() && context.isRelevant()) {
40114
- const calculated = calculate();
40115
- const value = context.decodeInstanceValue(calculated);
40116
- setRelevantValue(value);
40117
- }
40118
- });
40119
- });
40120
- };
40121
- const createInstanceValueState = (context) => {
40122
- return context.scope.runTask(() => {
40123
- const initialValue = getInitialValue(context);
40124
- const baseValueState = createSignal(initialValue);
40125
- const relevantValueState = createRelevantValueState(context, baseValueState);
40126
- setPreloadUIDValue(context, relevantValueState);
40127
- const { calculate } = context.definition.bind;
40128
- if (calculate != null) {
40129
- const [, setValue] = relevantValueState;
40130
- createCalculation(context, setValue, calculate);
40131
- }
40132
- return guardDownstreamReadonlyWrites(context, relevantValueState);
40133
- });
40134
- };
40135
-
40136
40305
  const engineViolationMessage = (context, role) => {
40137
40306
  const messageText = VALIDATION_TEXT[role];
40138
40307
  const chunk = new TextChunk(context, "literal", messageText);
@@ -40322,6 +40491,7 @@ class InputControl extends ValueNode {
40322
40491
  super(parent, instanceNode, definition, codec);
40323
40492
  this.appearances = definition.bodyElement.appearances;
40324
40493
  this.nodeOptions = nodeOptionsFactoryByType[definition.valueType](definition.bodyElement);
40494
+ const attributeState = createAttributeState(this.scope);
40325
40495
  const state = createSharedNodeState(
40326
40496
  this.scope,
40327
40497
  {
@@ -40332,13 +40502,14 @@ class InputControl extends ValueNode {
40332
40502
  label: createNodeLabel(this, definition),
40333
40503
  hint: createFieldHint(this, definition),
40334
40504
  children: null,
40335
- attributes: null,
40505
+ attributes: attributeState.getAttributes,
40336
40506
  valueOptions: null,
40337
40507
  value: this.valueState,
40338
40508
  instanceValue: this.getInstanceValue
40339
40509
  },
40340
40510
  this.instanceConfig
40341
40511
  );
40512
+ attributeState.setAttributes(buildAttributes(this));
40342
40513
  this.state = state;
40343
40514
  this.engineState = state.engineState;
40344
40515
  this.currentState = state.currentState;
@@ -40366,6 +40537,7 @@ class ModelValue extends ValueNode {
40366
40537
  constructor(parent, instanceNode, definition) {
40367
40538
  const codec = getSharedValueCodec(definition.valueType);
40368
40539
  super(parent, instanceNode, definition, codec);
40540
+ const attributeState = createAttributeState(this.scope);
40369
40541
  const state = createSharedNodeState(
40370
40542
  this.scope,
40371
40543
  {
@@ -40376,13 +40548,14 @@ class ModelValue extends ValueNode {
40376
40548
  label: null,
40377
40549
  hint: null,
40378
40550
  children: null,
40379
- attributes: null,
40551
+ attributes: attributeState.getAttributes,
40380
40552
  valueOptions: null,
40381
40553
  value: this.valueState,
40382
40554
  instanceValue: this.getInstanceValue
40383
40555
  },
40384
40556
  this.instanceConfig
40385
40557
  );
40558
+ attributeState.setAttributes(buildAttributes(this));
40386
40559
  this.state = state;
40387
40560
  this.engineState = state.engineState;
40388
40561
  this.currentState = state.currentState;
@@ -40474,6 +40647,7 @@ class Note extends ValueNode {
40474
40647
  this.appearances = definition.bodyElement.appearances;
40475
40648
  const isReadonly = createNoteReadonlyThunk(this, definition);
40476
40649
  const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
40650
+ const attributeState = createAttributeState(this.scope);
40477
40651
  let noteText;
40478
40652
  let label;
40479
40653
  let hint;
@@ -40504,13 +40678,14 @@ class Note extends ValueNode {
40504
40678
  hint,
40505
40679
  noteText,
40506
40680
  children: null,
40507
- attributes: null,
40681
+ attributes: attributeState.getAttributes,
40508
40682
  valueOptions: null,
40509
40683
  value: this.valueState,
40510
40684
  instanceValue: this.getInstanceValue
40511
40685
  },
40512
40686
  this.instanceConfig
40513
40687
  );
40688
+ attributeState.setAttributes(buildAttributes(this));
40514
40689
  this.state = state;
40515
40690
  this.engineState = state.engineState;
40516
40691
  this.currentState = state.currentState;
@@ -40574,6 +40749,7 @@ class RangeControl extends ValueNode {
40574
40749
  const codec = new RangeCodec(baseCodec, definition);
40575
40750
  super(parent, instanceNode, definition, codec);
40576
40751
  this.appearances = definition.bodyElement.appearances;
40752
+ const attributeState = createAttributeState(this.scope);
40577
40753
  const state = createSharedNodeState(
40578
40754
  this.scope,
40579
40755
  {
@@ -40584,13 +40760,14 @@ class RangeControl extends ValueNode {
40584
40760
  label: createNodeLabel(this, definition),
40585
40761
  hint: createFieldHint(this, definition),
40586
40762
  children: null,
40587
- attributes: null,
40763
+ attributes: attributeState.getAttributes,
40588
40764
  valueOptions: null,
40589
40765
  value: this.valueState,
40590
40766
  instanceValue: this.getInstanceValue
40591
40767
  },
40592
40768
  this.instanceConfig
40593
40769
  );
40770
+ attributeState.setAttributes(buildAttributes(this));
40594
40771
  this.state = state;
40595
40772
  this.engineState = state.engineState;
40596
40773
  this.currentState = state.currentState;
@@ -40808,6 +40985,7 @@ class RankControl extends ValueNode {
40808
40985
  this.mapOptionsByValue = mapOptionsByValue;
40809
40986
  const baseValueState = this.valueState;
40810
40987
  const [baseGetValue, setValue] = baseValueState;
40988
+ const attributeState = createAttributeState(this.scope);
40811
40989
  const getValue = this.scope.runTask(() => {
40812
40990
  return createMemo(() => {
40813
40991
  const options = valueOptions();
@@ -40842,13 +41020,14 @@ class RankControl extends ValueNode {
40842
41020
  label: createNodeLabel(this, definition),
40843
41021
  hint: createFieldHint(this, definition),
40844
41022
  children: null,
40845
- attributes: null,
41023
+ attributes: attributeState.getAttributes,
40846
41024
  valueOptions,
40847
41025
  value: valueState,
40848
41026
  instanceValue: this.getInstanceValue
40849
41027
  },
40850
41028
  this.instanceConfig
40851
41029
  );
41030
+ attributeState.setAttributes(buildAttributes(this));
40852
41031
  this.state = state;
40853
41032
  this.engineState = state.engineState;
40854
41033
  this.currentState = state.currentState;
@@ -40937,7 +41116,6 @@ class RepeatInstance extends DescendantNode {
40937
41116
  const childrenState = createChildrenState(this);
40938
41117
  const attributeState = createAttributeState(this.scope);
40939
41118
  this.childrenState = childrenState;
40940
- this.attributeState = attributeState;
40941
41119
  this.currentIndex = currentIndex;
40942
41120
  const state = createSharedNodeState(
40943
41121
  this.scope,
@@ -40972,7 +41150,6 @@ class RepeatInstance extends DescendantNode {
40972
41150
  this.instanceState = createTemplatedNodeInstanceState(this);
40973
41151
  }
40974
41152
  childrenState;
40975
- attributeState;
40976
41153
  currentIndex;
40977
41154
  [XPathNodeKindKey] = "element";
40978
41155
  // InstanceNode
@@ -41007,9 +41184,6 @@ class RepeatInstance extends DescendantNode {
41007
41184
  getChildren() {
41008
41185
  return this.childrenState.getChildren();
41009
41186
  }
41010
- getAttributes() {
41011
- return this.attributeState.getAttributes();
41012
- }
41013
41187
  }
41014
41188
 
41015
41189
  class BaseRepeatRange extends DescendantNode {
@@ -41345,6 +41519,7 @@ class SelectControl extends ValueNode {
41345
41519
  super(parent, instanceNode, definition, codec);
41346
41520
  this.appearances = definition.bodyElement.appearances;
41347
41521
  this.selectType = definition.bodyElement.type;
41522
+ const attributeState = createAttributeState(this.scope);
41348
41523
  const valueOptions = createItemCollection(this);
41349
41524
  const isSelectWithImages = this.scope.runTask(() => {
41350
41525
  return createMemo(() => valueOptions().some((item) => !!item.label.imageSource));
@@ -41381,7 +41556,7 @@ class SelectControl extends ValueNode {
41381
41556
  label: createNodeLabel(this, definition),
41382
41557
  hint: createFieldHint(this, definition),
41383
41558
  children: null,
41384
- attributes: null,
41559
+ attributes: attributeState.getAttributes,
41385
41560
  valueOptions,
41386
41561
  value: valueState,
41387
41562
  instanceValue: this.getInstanceValue,
@@ -41389,6 +41564,7 @@ class SelectControl extends ValueNode {
41389
41564
  },
41390
41565
  this.instanceConfig
41391
41566
  );
41567
+ attributeState.setAttributes(buildAttributes(this));
41392
41568
  this.state = state;
41393
41569
  this.engineState = state.engineState;
41394
41570
  this.currentState = state.currentState;
@@ -41507,6 +41683,7 @@ class TriggerControl extends ValueNode {
41507
41683
  constructor(parent, instanceNode, definition) {
41508
41684
  super(parent, instanceNode, definition, codec);
41509
41685
  this.appearances = definition.bodyElement.appearances;
41686
+ const attributeState = createAttributeState(this.scope);
41510
41687
  const state = createSharedNodeState(
41511
41688
  this.scope,
41512
41689
  {
@@ -41517,13 +41694,14 @@ class TriggerControl extends ValueNode {
41517
41694
  label: createNodeLabel(this, definition),
41518
41695
  hint: createFieldHint(this, definition),
41519
41696
  children: null,
41520
- attributes: null,
41697
+ attributes: attributeState.getAttributes,
41521
41698
  valueOptions: null,
41522
41699
  value: this.valueState,
41523
41700
  instanceValue: this.getInstanceValue
41524
41701
  },
41525
41702
  this.instanceConfig
41526
41703
  );
41704
+ attributeState.setAttributes(buildAttributes(this));
41527
41705
  this.state = state;
41528
41706
  this.engineState = state.engineState;
41529
41707
  this.currentState = state.currentState;
@@ -41717,7 +41895,6 @@ class UploadControl extends DescendantNode {
41717
41895
  const instanceAttachment = createInstanceAttachment(this);
41718
41896
  this.instanceAttachment = instanceAttachment;
41719
41897
  const attributeState = createAttributeState(this.scope);
41720
- this.attributeState = attributeState;
41721
41898
  this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
41722
41899
  this.getXPathValue = instanceAttachment.getInstanceValue;
41723
41900
  const state = createSharedNodeState(
@@ -41749,7 +41926,6 @@ class UploadControl extends DescendantNode {
41749
41926
  }
41750
41927
  validation;
41751
41928
  instanceAttachment;
41752
- attributeState;
41753
41929
  // XFormsXPathElement
41754
41930
  [XPathNodeKindKey] = "element";
41755
41931
  getXPathValue;
@@ -41784,9 +41960,6 @@ class UploadControl extends DescendantNode {
41784
41960
  this.instanceAttachment.setValue(value);
41785
41961
  return this.root;
41786
41962
  }
41787
- getAttributes() {
41788
- return this.attributeState.getAttributes();
41789
- }
41790
41963
  }
41791
41964
 
41792
41965
  const META_LOCAL_NAME = "meta";
@@ -41872,7 +42045,7 @@ const buildMetaValueElement = (group, localName, value) => {
41872
42045
  const buildDeprecatedIDDefinition = (group, instanceNode) => {
41873
42046
  const nodeset = instanceNode.nodeset;
41874
42047
  const bind = group.model.binds.getOrCreateBindDefinition(nodeset);
41875
- return new LeafNodeDefinition(group.parent.definition, bind, null, instanceNode);
42048
+ return new LeafNodeDefinition(group.model, group.parent.definition, bind, null, instanceNode);
41876
42049
  };
41877
42050
  const buildDeprecatedID = (group, value) => {
41878
42051
  const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
@@ -42068,7 +42241,6 @@ const buildChildren = (parent) => {
42068
42241
 
42069
42242
  class Root extends DescendantNode {
42070
42243
  childrenState;
42071
- attributeState;
42072
42244
  // XFormsXPathElement
42073
42245
  [XPathNodeKindKey] = "element";
42074
42246
  // DescendantNode
@@ -42102,7 +42274,6 @@ class Root extends DescendantNode {
42102
42274
  const childrenState = createChildrenState(this);
42103
42275
  const attributeState = createAttributeState(this.scope);
42104
42276
  this.childrenState = childrenState;
42105
- this.attributeState = attributeState;
42106
42277
  this.languages = parent.languages;
42107
42278
  const state = createSharedNodeState(
42108
42279
  this.scope,
@@ -42136,9 +42307,6 @@ class Root extends DescendantNode {
42136
42307
  getChildren() {
42137
42308
  return this.childrenState.getChildren();
42138
42309
  }
42139
- getAttributes() {
42140
- return this.attributeState.getAttributes();
42141
- }
42142
42310
  // RootNode
42143
42311
  setLanguage(language) {
42144
42312
  this.rootDocument.setLanguage(language);
@@ -42183,7 +42351,6 @@ class PrimaryInstance extends InstanceNode {
42183
42351
  isAttached;
42184
42352
  evaluator;
42185
42353
  contextNode = this;
42186
- attributeState;
42187
42354
  constructor(options) {
42188
42355
  const { mode, initialState, scope, model, secondaryInstances, config } = options;
42189
42356
  const { instance: modelInstance } = model;
@@ -42216,7 +42383,6 @@ class PrimaryInstance extends InstanceNode {
42216
42383
  const childrenState = createChildrenState(this);
42217
42384
  const attributeState = createAttributeState(this.scope);
42218
42385
  this.getChildren = childrenState.getChildren;
42219
- this.attributeState = attributeState;
42220
42386
  const stateSpec = {
42221
42387
  activeLanguage: getActiveLanguage,
42222
42388
  reference: PRIMARY_INSTANCE_REFERENCE,
@@ -42286,9 +42452,6 @@ class PrimaryInstance extends InstanceNode {
42286
42452
  });
42287
42453
  return Promise.resolve(result);
42288
42454
  }
42289
- getAttributes() {
42290
- return this.attributeState.getAttributes();
42291
- }
42292
42455
  }
42293
42456
 
42294
42457
  class FormInstance {
@@ -42297,7 +42460,8 @@ class FormInstance {
42297
42460
  const { mode, initialState, instanceConfig } = options;
42298
42461
  const config = {
42299
42462
  clientStateFactory: instanceConfig.stateFactory ?? identity,
42300
- computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null)
42463
+ computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null),
42464
+ preloadProperties: instanceConfig.preloadProperties ?? {}
42301
42465
  };
42302
42466
  const primaryInstanceOptions = {
42303
42467
  ...options.instanceOptions,