@getodk/xforms-engine 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/dist/client/AttributeNode.d.ts +4 -6
  2. package/dist/client/BaseNode.d.ts +5 -0
  3. package/dist/client/form/FormInstanceConfig.d.ts +15 -0
  4. package/dist/index.js +654 -429
  5. package/dist/index.js.map +1 -1
  6. package/dist/instance/Attribute.d.ts +13 -19
  7. package/dist/instance/Group.d.ts +2 -1
  8. package/dist/instance/InputControl.d.ts +5 -0
  9. package/dist/instance/ModelValue.d.ts +4 -0
  10. package/dist/instance/Note.d.ts +4 -0
  11. package/dist/instance/PrimaryInstance.d.ts +3 -2
  12. package/dist/instance/RangeControl.d.ts +4 -0
  13. package/dist/instance/RankControl.d.ts +5 -1
  14. package/dist/instance/Root.d.ts +2 -1
  15. package/dist/instance/SelectControl.d.ts +5 -1
  16. package/dist/instance/TriggerControl.d.ts +4 -0
  17. package/dist/instance/UploadControl.d.ts +3 -2
  18. package/dist/instance/abstract/DescendantNode.d.ts +5 -4
  19. package/dist/instance/abstract/InstanceNode.d.ts +6 -5
  20. package/dist/instance/abstract/ValueNode.d.ts +2 -1
  21. package/dist/instance/attachments/buildAttributes.d.ts +6 -2
  22. package/dist/instance/hierarchy.d.ts +2 -2
  23. package/dist/instance/internal-api/AttributeContext.d.ts +6 -0
  24. package/dist/instance/internal-api/InstanceConfig.d.ts +2 -0
  25. package/dist/instance/internal-api/InstanceValueContext.d.ts +6 -0
  26. package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +0 -1
  27. package/dist/instance/internal-api/serialization/ClientReactiveSerializableValueNode.d.ts +4 -0
  28. package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +1 -1
  29. package/dist/integration/xpath/adapter/kind.d.ts +5 -3
  30. package/dist/integration/xpath/adapter/traversal.d.ts +3 -3
  31. package/dist/integration/xpath/static-dom/StaticAttribute.d.ts +1 -0
  32. package/dist/lib/codecs/items/SingleValueItemCodec.d.ts +1 -1
  33. package/dist/lib/reactivity/createInstanceValueState.d.ts +4 -1
  34. package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +2 -2
  35. package/dist/lib/xml-serialization.d.ts +1 -1
  36. package/dist/parse/XFormDOM.d.ts +3 -0
  37. package/dist/parse/expression/ActionComputationExpression.d.ts +4 -0
  38. package/dist/parse/model/ActionDefinition.d.ts +15 -0
  39. package/dist/parse/model/AttributeDefinition.d.ts +5 -1
  40. package/dist/parse/model/BindPreloadDefinition.d.ts +6 -10
  41. package/dist/parse/model/Event.d.ts +8 -0
  42. package/dist/parse/model/LeafNodeDefinition.d.ts +5 -2
  43. package/dist/parse/model/ModelActionMap.d.ts +9 -0
  44. package/dist/parse/model/ModelDefinition.d.ts +8 -1
  45. package/dist/parse/model/NoteNodeDefinition.d.ts +3 -2
  46. package/dist/parse/model/RangeNodeDefinition.d.ts +2 -1
  47. package/dist/parse/model/RootDefinition.d.ts +1 -0
  48. package/dist/solid.js +654 -429
  49. package/dist/solid.js.map +1 -1
  50. package/package.json +21 -17
  51. package/src/client/AttributeNode.ts +4 -6
  52. package/src/client/BaseNode.ts +6 -0
  53. package/src/client/form/FormInstanceConfig.ts +17 -0
  54. package/src/client/validation.ts +1 -1
  55. package/src/entrypoints/FormInstance.ts +1 -0
  56. package/src/instance/Attribute.ts +43 -59
  57. package/src/instance/Group.ts +5 -6
  58. package/src/instance/InputControl.ts +16 -1
  59. package/src/instance/ModelValue.ts +16 -1
  60. package/src/instance/Note.ts +15 -1
  61. package/src/instance/PrimaryInstance.ts +8 -10
  62. package/src/instance/RangeControl.ts +15 -1
  63. package/src/instance/RankControl.ts +17 -2
  64. package/src/instance/Root.ts +5 -6
  65. package/src/instance/SelectControl.ts +16 -2
  66. package/src/instance/TriggerControl.ts +15 -1
  67. package/src/instance/UploadControl.ts +9 -8
  68. package/src/instance/abstract/DescendantNode.ts +4 -8
  69. package/src/instance/abstract/InstanceNode.ts +7 -5
  70. package/src/instance/abstract/ValueNode.ts +2 -1
  71. package/src/instance/attachments/buildAttributes.ts +15 -4
  72. package/src/instance/children/childrenInitOptions.ts +2 -1
  73. package/src/instance/children/normalizeChildInitOptions.ts +1 -1
  74. package/src/instance/hierarchy.ts +2 -2
  75. package/src/instance/internal-api/AttributeContext.ts +6 -0
  76. package/src/instance/internal-api/InstanceConfig.ts +6 -1
  77. package/src/instance/internal-api/InstanceValueContext.ts +6 -0
  78. package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +0 -1
  79. package/src/instance/internal-api/serialization/ClientReactiveSerializableValueNode.ts +4 -0
  80. package/src/instance/repeat/RepeatInstance.ts +3 -4
  81. package/src/integration/xpath/adapter/XFormsXPathNode.ts +1 -0
  82. package/src/integration/xpath/adapter/engineDOMAdapter.ts +2 -2
  83. package/src/integration/xpath/adapter/kind.ts +6 -1
  84. package/src/integration/xpath/adapter/names.ts +1 -0
  85. package/src/integration/xpath/adapter/traversal.ts +5 -6
  86. package/src/integration/xpath/static-dom/StaticAttribute.ts +1 -0
  87. package/src/lib/client-reactivity/instance-state/createValueNodeInstanceState.ts +2 -1
  88. package/src/lib/client-reactivity/instance-state/prepareInstancePayload.ts +1 -0
  89. package/src/lib/codecs/NoteCodec.ts +1 -1
  90. package/src/lib/codecs/items/SingleValueItemCodec.ts +1 -3
  91. package/src/lib/reactivity/createInstanceValueState.ts +177 -52
  92. package/src/lib/reactivity/node-state/createSharedNodeState.ts +2 -2
  93. package/src/lib/xml-serialization.ts +9 -1
  94. package/src/parse/XFormDOM.ts +9 -0
  95. package/src/parse/body/GroupElementDefinition.ts +1 -1
  96. package/src/parse/body/control/InputControlDefinition.ts +1 -1
  97. package/src/parse/expression/ActionComputationExpression.ts +12 -0
  98. package/src/parse/model/ActionDefinition.ts +70 -0
  99. package/src/parse/model/AttributeDefinition.ts +10 -2
  100. package/src/parse/model/AttributeDefinitionMap.ts +1 -1
  101. package/src/parse/model/BindDefinition.ts +1 -6
  102. package/src/parse/model/BindPreloadDefinition.ts +44 -12
  103. package/src/parse/model/Event.ts +9 -0
  104. package/src/parse/model/LeafNodeDefinition.ts +5 -1
  105. package/src/parse/model/ModelActionMap.ts +37 -0
  106. package/src/parse/model/ModelDefinition.ts +18 -3
  107. package/src/parse/model/NoteNodeDefinition.ts +5 -2
  108. package/src/parse/model/RangeNodeDefinition.ts +5 -2
  109. package/src/parse/model/RootDefinition.ts +22 -4
  110. package/dist/lib/reactivity/createAttributeValueState.d.ts +0 -15
  111. 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
  }
@@ -21244,6 +21252,7 @@ class StaticAttribute extends StaticNode {
21244
21252
  nodeset;
21245
21253
  attributes = [];
21246
21254
  children = null;
21255
+ childElements = [];
21247
21256
  value;
21248
21257
  // XFormsXPathAttribute
21249
21258
  getXPathValue() {
@@ -21573,6 +21582,105 @@ class ItextTranslationsDefinition extends Map {
21573
21582
  }
21574
21583
  }
21575
21584
 
21585
+ class ActionComputationExpression extends DependentExpression {
21586
+ constructor(resultType, expression) {
21587
+ super(resultType, expression);
21588
+ }
21589
+ }
21590
+
21591
+ const XFORM_EVENT = {
21592
+ odkInstanceLoad: "odk-instance-load",
21593
+ odkInstanceFirstLoad: "odk-instance-first-load",
21594
+ odkNewRepeat: "odk-new-repeat",
21595
+ xformsRevalidate: "xforms-revalidate",
21596
+ xformsValueChanged: "xforms-value-changed"
21597
+ };
21598
+
21599
+ class ActionDefinition {
21600
+ constructor(model, element, source) {
21601
+ this.element = element;
21602
+ const ref = ActionDefinition.getRef(model, element);
21603
+ if (!ref) {
21604
+ throw new Error(
21605
+ 'Invalid setvalue element - you must define either "ref" or "bind" attribute'
21606
+ );
21607
+ }
21608
+ this.ref = ref;
21609
+ this.events = ActionDefinition.getEvents(element);
21610
+ const value = ActionDefinition.getValue(element);
21611
+ this.computation = new ActionComputationExpression("string", value);
21612
+ this.source = source;
21613
+ }
21614
+ static getRef(model, setValueElement) {
21615
+ if (setValueElement.hasAttribute("ref")) {
21616
+ return setValueElement.getAttribute("ref") ?? null;
21617
+ }
21618
+ if (setValueElement.hasAttribute("bind")) {
21619
+ const bindId = setValueElement.getAttribute("bind");
21620
+ const bindDefinition = Array.from(model.binds.values()).find((definition) => {
21621
+ return definition.bindElement.getAttribute("id") === bindId;
21622
+ });
21623
+ return bindDefinition?.nodeset ?? null;
21624
+ }
21625
+ return null;
21626
+ }
21627
+ static getValue(element) {
21628
+ if (element.hasAttribute("value")) {
21629
+ return element.getAttribute("value") || "''";
21630
+ }
21631
+ if (element.firstChild && isTextNode(element.firstChild)) {
21632
+ return `'${element.firstChild.nodeValue}'`;
21633
+ }
21634
+ return "''";
21635
+ }
21636
+ static isKnownEvent = (event) => {
21637
+ return Object.values(XFORM_EVENT).includes(event);
21638
+ };
21639
+ static getEvents(element) {
21640
+ const events = element.getAttribute("event")?.split(" ") ?? [];
21641
+ const unknownEvents = events.filter((event) => !this.isKnownEvent(event));
21642
+ if (unknownEvents.length) {
21643
+ throw new Error(
21644
+ `An action was registered for unsupported events: ${unknownEvents.join(", ")}`
21645
+ );
21646
+ }
21647
+ return events;
21648
+ }
21649
+ ref;
21650
+ events;
21651
+ computation;
21652
+ source;
21653
+ }
21654
+
21655
+ const REPEAT_REGEX = /(\[[^\]]*\])/gm;
21656
+ class ModelActionMap extends Map {
21657
+ static fromModel(model) {
21658
+ return new this(model);
21659
+ }
21660
+ static getKey(ref) {
21661
+ return ref.replace(REPEAT_REGEX, "");
21662
+ }
21663
+ constructor(model) {
21664
+ super(
21665
+ model.form.xformDOM.setValues.map((setValueElement) => {
21666
+ const action = new ActionDefinition(model, setValueElement);
21667
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
21668
+ throw new Error('Model contains "setvalue" element with "odk-new-repeat" event');
21669
+ }
21670
+ const key = ModelActionMap.getKey(action.ref);
21671
+ return [key, action];
21672
+ })
21673
+ );
21674
+ }
21675
+ get(ref) {
21676
+ return super.get(ModelActionMap.getKey(ref));
21677
+ }
21678
+ add(action) {
21679
+ const key = ModelActionMap.getKey(action.ref);
21680
+ this.set(key, action);
21681
+ }
21682
+ }
21683
+
21576
21684
  const defaultBindComputationExpressions = {
21577
21685
  calculate: null,
21578
21686
  constraint: "true()",
@@ -21638,6 +21746,7 @@ class MessageDefinition extends TextRangeDefinition {
21638
21746
  chunks;
21639
21747
  }
21640
21748
 
21749
+ const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
21641
21750
  const getPreloadInput = (bindElement) => {
21642
21751
  const type = bindElement.getAttributeNS(JAVAROSA_NAMESPACE_URI$1, "preload");
21643
21752
  if (type == null) {
@@ -21662,9 +21771,38 @@ class BindPreloadDefinition {
21662
21771
  }
21663
21772
  type;
21664
21773
  parameter;
21774
+ event;
21775
+ getValue(context) {
21776
+ if (this.type === "uid") {
21777
+ return context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION);
21778
+ }
21779
+ if (this.type === "timestamp") {
21780
+ return context.evaluator.evaluateString("now()");
21781
+ }
21782
+ if (this.type === "date") {
21783
+ return context.evaluator.evaluateString("today()");
21784
+ }
21785
+ if (this.type === "property") {
21786
+ const properties = context.instanceConfig.preloadProperties;
21787
+ if (this.parameter === "deviceid") {
21788
+ return properties.deviceID;
21789
+ }
21790
+ if (this.parameter === "email") {
21791
+ return properties.email;
21792
+ }
21793
+ if (this.parameter === "phonenumber") {
21794
+ return properties.phoneNumber;
21795
+ }
21796
+ if (this.parameter === "username") {
21797
+ return properties.username;
21798
+ }
21799
+ }
21800
+ return;
21801
+ }
21665
21802
  constructor(input) {
21666
21803
  this.type = input.type;
21667
21804
  this.parameter = input.parameter;
21805
+ this.event = this.type === "timestamp" && this.parameter === "end" ? XFORM_EVENT.xformsRevalidate : XFORM_EVENT.odkInstanceFirstLoad;
21668
21806
  }
21669
21807
  }
21670
21808
 
@@ -21811,10 +21949,7 @@ class BindDefinition extends DependencyContext {
21811
21949
  // TODO: it is unclear whether this will need to be supported.
21812
21950
  // https://github.com/getodk/collect/issues/3758 mentions deprecation.
21813
21951
  saveIncomplete;
21814
- // TODO: these are deferred until prioritized
21815
- // readonly preload: string | null;
21816
- // readonly preloadParams: string | null;
21817
- // readonly 'max-pixels': string | null;
21952
+ // TODO: deferred until prioritized: readonly 'max-pixels': string | null;
21818
21953
  _parentBind;
21819
21954
  get parentBind() {
21820
21955
  let bind = this._parentBind;
@@ -21980,8 +22115,14 @@ const serializeParentElementXML = (qualifiedName, children, attributes, namespac
21980
22115
  namespaceDeclarations
21981
22116
  );
21982
22117
  };
21983
- const serializeLeafElementXML = (qualifiedName, xmlValue, namespaceDeclarations) => {
21984
- return serializeElementXML(qualifiedName, xmlValue.normalize(), "", namespaceDeclarations);
22118
+ const serializeLeafElementXML = (qualifiedName, xmlValue, attributes, namespaceDeclarations) => {
22119
+ const serializedAttributes = attributes?.map((attribute) => attribute.instanceState.instanceXML).join("") ?? "";
22120
+ return serializeElementXML(
22121
+ qualifiedName,
22122
+ xmlValue.normalize(),
22123
+ serializedAttributes,
22124
+ namespaceDeclarations
22125
+ );
21985
22126
  };
21986
22127
 
21987
22128
  class NamespaceDeclaration {
@@ -22211,11 +22352,12 @@ class NodeDefinition {
22211
22352
  }
22212
22353
 
22213
22354
  class AttributeDefinition extends NodeDefinition {
22214
- constructor(root, bind, template) {
22355
+ constructor(model, bind, template) {
22215
22356
  super(bind);
22357
+ this.model = model;
22216
22358
  this.template = template;
22217
22359
  const { value } = template;
22218
- this.root = root;
22360
+ this.root = model.root;
22219
22361
  this.value = value;
22220
22362
  this.qualifiedName = template.qualifiedName;
22221
22363
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
@@ -22229,6 +22371,7 @@ class AttributeDefinition extends NodeDefinition {
22229
22371
  serializedXML;
22230
22372
  value;
22231
22373
  type = "attribute";
22374
+ valueType = "string";
22232
22375
  namespaceDeclarations;
22233
22376
  bodyElement = null;
22234
22377
  root;
@@ -22240,6 +22383,10 @@ class AttributeDefinition extends NodeDefinition {
22240
22383
  serializeAttributeXML() {
22241
22384
  return this.serializedXML;
22242
22385
  }
22386
+ toJSON() {
22387
+ const { bind, bodyElement, parent, root, ...rest } = this;
22388
+ return rest;
22389
+ }
22243
22390
  }
22244
22391
 
22245
22392
  const isNonNamespaceAttribute = (attribute) => {
@@ -22250,7 +22397,7 @@ class AttributeDefinitionMap extends Map {
22250
22397
  const nonNamespaceAttributes = instanceNode.attributes.filter(isNonNamespaceAttribute);
22251
22398
  const definitions = nonNamespaceAttributes.map((attribute) => {
22252
22399
  const bind = model.binds.getOrCreateBindDefinition(attribute.nodeset);
22253
- return new AttributeDefinition(model.root, bind, attribute);
22400
+ return new AttributeDefinition(model, bind, attribute);
22254
22401
  });
22255
22402
  return new this(definitions);
22256
22403
  }
@@ -22302,22 +22449,24 @@ class GroupDefinition extends DescendentNodeDefinition {
22302
22449
  }
22303
22450
 
22304
22451
  class LeafNodeDefinition extends DescendentNodeDefinition {
22305
- constructor(parent, bind, bodyElement, template) {
22452
+ constructor(model, parent, bind, bodyElement, template) {
22306
22453
  if (bodyElement != null && bodyElement.category !== "control") {
22307
22454
  throw new Error(`Unexpected body element for nodeset ${bind.nodeset}`);
22308
22455
  }
22309
22456
  super(parent, bind, bodyElement);
22457
+ this.model = model;
22310
22458
  this.template = template;
22311
22459
  this.valueType = bind.type.resolved;
22312
22460
  this.qualifiedName = template.qualifiedName;
22313
22461
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
22462
+ this.attributes = AttributeDefinitionMap.from(model, template);
22314
22463
  }
22315
22464
  type = "leaf-node";
22316
22465
  valueType;
22317
22466
  namespaceDeclarations;
22318
22467
  qualifiedName;
22319
22468
  children = null;
22320
- attributes = null;
22469
+ attributes;
22321
22470
  toJSON() {
22322
22471
  const { bind, bodyElement, parent, root, ...rest } = this;
22323
22472
  return rest;
@@ -22328,13 +22477,13 @@ const isNoteBindDefinition = (bind) => {
22328
22477
  return bind.readonly.isConstantTruthyExpression();
22329
22478
  };
22330
22479
  class NoteNodeDefinition extends LeafNodeDefinition {
22331
- constructor(parent, bind, bodyElement, noteTextDefinition, template) {
22332
- super(parent, bind, bodyElement, template);
22480
+ constructor(model, parent, bind, bodyElement, noteTextDefinition, template) {
22481
+ super(model, parent, bind, bodyElement, template);
22333
22482
  this.bind = bind;
22334
22483
  this.bodyElement = bodyElement;
22335
22484
  this.noteTextDefinition = noteTextDefinition;
22336
22485
  }
22337
- static from(parent, bind, bodyElement, node) {
22486
+ static from(model, parent, bind, bodyElement, node) {
22338
22487
  if (!isNoteBindDefinition(bind) || bodyElement?.type !== "input") {
22339
22488
  return null;
22340
22489
  }
@@ -22343,7 +22492,7 @@ class NoteNodeDefinition extends LeafNodeDefinition {
22343
22492
  if (noteTextDefinition == null) {
22344
22493
  return null;
22345
22494
  }
22346
- return new this(parent, bind, bodyElement, noteTextDefinition, node);
22495
+ return new this(model, parent, bind, bodyElement, noteTextDefinition, node);
22347
22496
  }
22348
22497
  }
22349
22498
 
@@ -26554,15 +26703,15 @@ class RangeNodeBoundsDefinition {
26554
26703
  }
26555
26704
  }
26556
26705
  class RangeNodeDefinition extends LeafNodeDefinition {
26557
- constructor(parent, bind, bodyElement, node) {
26558
- super(parent, bind, bodyElement, node);
26706
+ constructor(model, parent, bind, bodyElement, node) {
26707
+ super(model, parent, bind, bodyElement, node);
26559
26708
  this.bind = bind;
26560
26709
  this.bodyElement = bodyElement;
26561
26710
  this.bounds = RangeNodeBoundsDefinition.from(bodyElement.bounds, bind);
26562
26711
  }
26563
- static from(parent, bind, bodyElement, node) {
26712
+ static from(model, parent, bind, bodyElement, node) {
26564
26713
  assertRangeBindDefinition(bind);
26565
- return new this(parent, bind, bodyElement, node);
26714
+ return new this(model, parent, bind, bodyElement, node);
26566
26715
  }
26567
26716
  bounds;
26568
26717
  }
@@ -26698,6 +26847,18 @@ class RootDefinition extends NodeDefinition {
26698
26847
  attributes;
26699
26848
  children;
26700
26849
  isTranslated = false;
26850
+ mapActions(bodyElement) {
26851
+ const source = bodyElement.reference;
26852
+ if (!source) {
26853
+ return;
26854
+ }
26855
+ for (const child of bodyElement.element.children) {
26856
+ if (child.nodeName === "setvalue") {
26857
+ const action = new ActionDefinition(this.model, child, source);
26858
+ this.model.actions.add(action);
26859
+ }
26860
+ }
26861
+ }
26701
26862
  buildSubtree(parent, node) {
26702
26863
  const { form, model } = this;
26703
26864
  const { body } = form;
@@ -26720,6 +26881,9 @@ class RootDefinition extends NodeDefinition {
26720
26881
  const bind = binds.getOrCreateBindDefinition(nodeset);
26721
26882
  const bodyElement = body.getBodyElement(nodeset);
26722
26883
  const [firstChild, ...restChildren] = children;
26884
+ if (bodyElement) {
26885
+ this.mapActions(bodyElement);
26886
+ }
26723
26887
  if (bodyElement?.type === "repeat") {
26724
26888
  return RepeatDefinition.from(model, parent, bind, bodyElement, children);
26725
26889
  }
@@ -26729,9 +26893,9 @@ class RootDefinition extends NodeDefinition {
26729
26893
  const element = firstChild;
26730
26894
  if (element.isLeafElement()) {
26731
26895
  if (bodyElement?.type === "range") {
26732
- return RangeNodeDefinition.from(parent, bind, bodyElement, element);
26896
+ return RangeNodeDefinition.from(model, parent, bind, bodyElement, element);
26733
26897
  }
26734
- return NoteNodeDefinition.from(parent, bind, bodyElement, element) ?? new LeafNodeDefinition(parent, bind, bodyElement, element);
26898
+ return NoteNodeDefinition.from(model, parent, bind, bodyElement, element) ?? new LeafNodeDefinition(model, parent, bind, bodyElement, element);
26735
26899
  }
26736
26900
  return new GroupDefinition(model, parent, bind, bodyElement, element);
26737
26901
  });
@@ -26779,6 +26943,7 @@ class ModelDefinition {
26779
26943
  this.form = form;
26780
26944
  const submission = new SubmissionDefinition(form.xformDOM);
26781
26945
  this.binds = ModelBindMap.fromModel(this);
26946
+ this.actions = ModelActionMap.fromModel(this);
26782
26947
  this.instance = parseStaticDocumentFromDOMSubtree(form.xformDOM.primaryInstanceRoot, {
26783
26948
  nodesetPrefix: "/"
26784
26949
  });
@@ -26786,13 +26951,16 @@ class ModelDefinition {
26786
26951
  this.nodes = nodeDefinitionMap(this.root);
26787
26952
  this.itextTranslations = ItextTranslationsDefinition.from(form.xformDOM);
26788
26953
  this.itextChunks = generateItextChunks(form.xformDOM.itextTranslationElements);
26954
+ this.xformsRevalidateListeners = /* @__PURE__ */ new Map();
26789
26955
  }
26790
26956
  binds;
26957
+ actions;
26791
26958
  root;
26792
26959
  nodes;
26793
26960
  instance;
26794
26961
  itextTranslations;
26795
26962
  itextChunks;
26963
+ xformsRevalidateListeners;
26796
26964
  getNodeDefinition(nodeset) {
26797
26965
  const definition = this.nodes.get(nodeset);
26798
26966
  if (definition == null) {
@@ -26807,14 +26975,20 @@ class ModelDefinition {
26807
26975
  }
26808
26976
  return definition;
26809
26977
  }
26810
- toJSON() {
26811
- const { form, ...rest } = this;
26812
- return rest;
26978
+ registerXformsRevalidateListener(ref, listener) {
26979
+ this.xformsRevalidateListeners.set(ref, listener);
26980
+ }
26981
+ triggerXformsRevalidateListeners() {
26982
+ this.xformsRevalidateListeners.forEach((listener) => listener());
26813
26983
  }
26814
26984
  getTranslationChunks(itextId, activeLanguage) {
26815
26985
  const languageMap = this.itextChunks.get(activeLanguage.language);
26816
26986
  return languageMap?.get(itextId) ?? [];
26817
26987
  }
26988
+ toJSON() {
26989
+ const { form, ...rest } = this;
26990
+ return rest;
26991
+ }
26818
26992
  }
26819
26993
 
26820
26994
  class XFormDefinition {
@@ -27785,6 +27959,7 @@ const resolveEngineXPathNodeNamespaceURI = (node, prefix) => {
27785
27959
  case "static-element":
27786
27960
  case "static-text":
27787
27961
  return resolveNamespaceURIFromStaticNodeContext(node, prefix);
27962
+ case "attribute":
27788
27963
  case "group":
27789
27964
  case "input":
27790
27965
  case "model-value":
@@ -27817,10 +27992,13 @@ class XPathFunctionalityPendingError extends XPathFunctionalityError {
27817
27992
  const getContainingEngineXPathDocument = (node) => {
27818
27993
  return node.rootDocument;
27819
27994
  };
27820
- const getEngineXPathAttributes = (node) => {
27995
+ const getAttributes = (node) => {
27821
27996
  if (node.nodeType === "static-element") {
27822
27997
  return node.attributes;
27823
27998
  }
27999
+ if (isEngineXPathElement(node)) {
28000
+ return node.getAttributes();
28001
+ }
27824
28002
  return [];
27825
28003
  };
27826
28004
  const getNamespaceDeclarations = () => [];
@@ -27977,7 +28155,7 @@ const engineDOMAdapter = {
27977
28155
  getNodeValue: getEngineXPathNodeValue,
27978
28156
  // XPathTraversalAdapter
27979
28157
  compareDocumentOrder,
27980
- getAttributes: getEngineXPathAttributes,
28158
+ getAttributes,
27981
28159
  getChildElements,
27982
28160
  getChildNodes,
27983
28161
  getContainingDocument: getContainingEngineXPathDocument,
@@ -28878,6 +29056,7 @@ const chunkedInstancePayload = (validation, submissionMeta, instanceFile, attach
28878
29056
  };
28879
29057
  };
28880
29058
  const prepareInstancePayload = (instanceRoot, options) => {
29059
+ instanceRoot.root.parent.model.triggerXformsRevalidateListeners();
28881
29060
  const validation = validateInstance(instanceRoot);
28882
29061
  const submissionMeta = instanceRoot.definition.submission;
28883
29062
  const instanceFile = new InstanceFile(instanceRoot);
@@ -29306,17 +29485,21 @@ const createComputedExpression = (context, dependentExpression, options = {}) =>
29306
29485
  });
29307
29486
  };
29308
29487
 
29309
- const isInstanceFirstLoad$1 = (context) => {
29488
+ const REPEAT_INDEX_REGEX = /([^[]*)(\[[0-9]+\])/g;
29489
+ const isInstanceFirstLoad = (context) => {
29310
29490
  return context.rootDocument.initializationMode === "create";
29311
29491
  };
29312
- const isEditInitialLoad$1 = (context) => {
29492
+ const isAddingRepeatChild = (context) => {
29493
+ return context.rootDocument.isAttached();
29494
+ };
29495
+ const isEditInitialLoad = (context) => {
29313
29496
  return context.rootDocument.initializationMode === "edit";
29314
29497
  };
29315
- const getInitialValue$1 = (context) => {
29498
+ const getInitialValue = (context) => {
29316
29499
  const sourceNode = context.instanceNode ?? context.definition.template;
29317
29500
  return context.decodeInstanceValue(sourceNode.value);
29318
29501
  };
29319
- const createRelevantValueState$1 = (context, baseValueState) => {
29502
+ const createRelevantValueState = (context, baseValueState) => {
29320
29503
  return context.scope.runTask(() => {
29321
29504
  const [getRelevantValue, setValue] = baseValueState;
29322
29505
  const getValue = createMemo(() => {
@@ -29328,7 +29511,7 @@ const createRelevantValueState$1 = (context, baseValueState) => {
29328
29511
  return [getValue, setValue];
29329
29512
  });
29330
29513
  };
29331
- const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29514
+ const guardDownstreamReadonlyWrites = (context, baseState) => {
29332
29515
  const { readonly } = context.definition.bind;
29333
29516
  if (readonly.isDefaultExpression) {
29334
29517
  return baseState;
@@ -29343,215 +29526,144 @@ const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29343
29526
  };
29344
29527
  return [getValue, setValue];
29345
29528
  };
29346
- const PRELOAD_UID_EXPRESSION$1 = 'concat("uuid:", uuid())';
29347
- const shouldPreloadUID$1 = (context) => {
29348
- return isInstanceFirstLoad$1(context) || isEditInitialLoad$1(context);
29529
+ const isLoading = (context) => {
29530
+ return isInstanceFirstLoad(context) || isEditInitialLoad(context);
29349
29531
  };
29350
- const setPreloadUIDValue$1 = (context, valueState) => {
29532
+ const setValueIfPreloadDefined = (context, setValue, preload) => {
29533
+ const value = preload.getValue(context);
29534
+ if (value) {
29535
+ setValue(value);
29536
+ }
29537
+ };
29538
+ const postloadValue = (context, setValue, preload) => {
29539
+ const ref = context.contextReference();
29540
+ context.definition.model.registerXformsRevalidateListener(ref, () => {
29541
+ setValueIfPreloadDefined(context, setValue, preload);
29542
+ });
29543
+ };
29544
+ const preloadValue = (context, setValue) => {
29351
29545
  const { preload } = context.definition.bind;
29352
- if (preload?.type !== "uid" || !shouldPreloadUID$1(context)) {
29546
+ if (!preload) {
29353
29547
  return;
29354
29548
  }
29355
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION$1, {
29549
+ if (preload.event === XFORM_EVENT.xformsRevalidate) {
29550
+ postloadValue(context, setValue, preload);
29551
+ return;
29552
+ }
29553
+ if (isLoading(context)) {
29554
+ setValueIfPreloadDefined(context, setValue, preload);
29555
+ }
29556
+ };
29557
+ const referencesCurrentNode = (context, ref) => {
29558
+ const nodes = context.evaluator.evaluateNodes(ref, {
29356
29559
  contextNode: context.contextNode
29357
29560
  });
29358
- const [, setValue] = valueState;
29359
- setValue(preloadUIDValue);
29561
+ if (nodes.length > 1) {
29562
+ throw new Error(
29563
+ "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."
29564
+ );
29565
+ }
29566
+ return nodes.includes(context.contextNode);
29360
29567
  };
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);
29568
+ const bindToRepeatInstance = (context, action) => {
29569
+ let source = action.source;
29570
+ let ref = action.ref;
29571
+ if (source) {
29572
+ const contextRef = context.contextReference();
29573
+ for (const part of contextRef.matchAll(REPEAT_INDEX_REGEX)) {
29574
+ const unbound = part[1] + "/";
29575
+ if (source.includes(unbound)) {
29576
+ const bound = part[0] + "/";
29577
+ source = source.replace(unbound, bound);
29578
+ ref = ref.replace(unbound, bound);
29371
29579
  }
29372
- });
29580
+ }
29581
+ }
29582
+ return { source, ref };
29583
+ };
29584
+ const createCalculation = (context, setRelevantValue, computation) => {
29585
+ const calculate = createComputedExpression(context, computation);
29586
+ createComputed(() => {
29587
+ if (context.isAttached() && context.isRelevant()) {
29588
+ const calculated = calculate();
29589
+ const value = context.decodeInstanceValue(calculated);
29590
+ setRelevantValue(value);
29591
+ }
29373
29592
  });
29374
29593
  };
29375
- const createAttributeValueState = (context) => {
29376
- return context.scope.runTask(() => {
29377
- const initialValue = getInitialValue$1(context);
29378
- const baseValueState = createSignal(initialValue);
29379
- const relevantValueState = createRelevantValueState$1(context, baseValueState);
29380
- setPreloadUIDValue$1(context, relevantValueState);
29381
- const { calculate } = context.definition.bind;
29382
- if (calculate != null) {
29383
- const [, setValue] = relevantValueState;
29384
- createCalculation$1(context, setValue, calculate);
29594
+ const createActionCalculation = (context, setRelevantValue, computation) => {
29595
+ createComputed(() => {
29596
+ if (context.isAttached()) {
29597
+ const relevant = untrack(() => context.isRelevant());
29598
+ if (!relevant) {
29599
+ return;
29600
+ }
29601
+ const calculated = untrack(() => {
29602
+ return context.evaluator.evaluateString(computation.expression, context);
29603
+ });
29604
+ const value = context.decodeInstanceValue(calculated);
29605
+ setRelevantValue(value);
29385
29606
  }
29386
- return guardDownstreamReadonlyWrites$1(context, relevantValueState);
29387
29607
  });
29388
29608
  };
29389
-
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
- });
29397
- this.instanceNode = instanceNode;
29398
- this.root = parent.root;
29399
- this.getActiveLanguage = parent.getActiveLanguage;
29400
- this.validationState = { violations: [] };
29401
- this.valueType = "string";
29402
- this.evaluator = parent.evaluator;
29403
- this.decodeInstanceValue = codec.decodeInstanceValue;
29404
- const instanceValueState = createAttributeValueState(this);
29405
- const valueState = codec.createRuntimeValueState(instanceValueState);
29406
- const [getInstanceValue] = instanceValueState;
29407
- const [, setValueState] = valueState;
29408
- this.getInstanceValue = getInstanceValue;
29409
- this.setValueState = setValueState;
29410
- this.getXPathValue = () => {
29411
- return this.getInstanceValue();
29412
- };
29413
- this.valueState = valueState;
29414
- const state = createSharedNodeState(
29415
- this.scope,
29416
- {
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
- value: this.valueState,
29426
- instanceValue: this.getInstanceValue,
29427
- attributes: null
29428
- },
29429
- this.instanceConfig
29430
- );
29431
- this.state = state;
29432
- this.engineState = state.engineState;
29433
- this.currentState = state.currentState;
29434
- this.instanceState = createAttributeNodeInstanceState(this);
29435
- }
29436
- [XPathNodeKindKey] = "attribute";
29437
- state;
29438
- engineState;
29439
- validationState;
29440
- nodeType = "attribute";
29441
- currentState;
29442
- instanceState;
29443
- appearances = null;
29444
- nodeOptions = null;
29445
- valueType;
29446
- decodeInstanceValue;
29447
- getInstanceValue;
29448
- valueState;
29449
- setValueState;
29450
- evaluator;
29451
- getActiveLanguage;
29452
- root;
29453
- isRelevant = () => {
29454
- return this.parent.isRelevant();
29455
- };
29456
- isAttached = () => {
29457
- return this.parent.isAttached();
29458
- };
29459
- isReadonly = () => {
29460
- return true;
29461
- };
29462
- hasReadonlyAncestor = () => {
29463
- const { parent } = this;
29464
- return parent.hasReadonlyAncestor() || parent.isReadonly();
29465
- };
29466
- hasNonRelevantAncestor = () => {
29467
- const { parent } = this;
29468
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29469
- };
29470
- setValue(value) {
29471
- this.setValueState(value);
29472
- return this.root;
29473
- }
29474
- getChildren() {
29475
- return [];
29609
+ const createValueChangedCalculation = (context, setRelevantValue, action) => {
29610
+ const { source, ref } = bindToRepeatInstance(context, action);
29611
+ if (!source) {
29612
+ return;
29476
29613
  }
29477
- }
29478
-
29479
- function buildAttributes(parent) {
29480
- return Array.from(parent.definition.attributes.values()).map((attributeDefinition) => {
29481
- return new Attribute(parent, attributeDefinition, attributeDefinition.template);
29614
+ let previous = "";
29615
+ const sourceElementExpression = new ActionComputationExpression("string", source);
29616
+ const calculateValueSource = createComputedExpression(context, sourceElementExpression);
29617
+ createComputed(() => {
29618
+ if (context.isAttached() && context.isRelevant()) {
29619
+ const valueSource = calculateValueSource();
29620
+ if (previous !== valueSource) {
29621
+ if (referencesCurrentNode(context, ref)) {
29622
+ const calc = context.evaluator.evaluateString(action.computation.expression, context);
29623
+ const value = context.decodeInstanceValue(calc);
29624
+ setRelevantValue(value);
29625
+ }
29626
+ }
29627
+ previous = valueSource;
29628
+ }
29482
29629
  });
29483
- }
29484
-
29485
- class InstanceAttachmentsState extends Map {
29486
- constructor(sourceAttachments = null) {
29487
- super();
29488
- this.sourceAttachments = sourceAttachments;
29630
+ };
29631
+ const registerAction = (context, setValue, action) => {
29632
+ if (action.events.includes(XFORM_EVENT.odkInstanceFirstLoad)) {
29633
+ if (isInstanceFirstLoad(context)) {
29634
+ createActionCalculation(context, setValue, action.computation);
29635
+ }
29489
29636
  }
29490
- getInitialFileValue(instanceNode) {
29491
- if (instanceNode == null) {
29492
- return null;
29637
+ if (action.events.includes(XFORM_EVENT.odkInstanceLoad)) {
29638
+ if (!isAddingRepeatChild(context)) {
29639
+ createActionCalculation(context, setValue, action.computation);
29493
29640
  }
29494
- return this.sourceAttachments?.get(instanceNode.value) ?? null;
29495
29641
  }
29496
- }
29497
-
29498
- const createRootInstanceState = (node) => {
29499
- return {
29500
- get instanceXML() {
29501
- return serializeParentElementXML(
29502
- node.definition.qualifiedName,
29503
- node.currentState.children,
29504
- node.currentState.attributes,
29505
- node.definition.namespaceDeclarations
29506
- );
29642
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
29643
+ if (isAddingRepeatChild(context)) {
29644
+ createActionCalculation(context, setValue, action.computation);
29507
29645
  }
29508
- };
29509
- };
29510
-
29511
- const violationReference = (node) => {
29512
- const violation = node.getViolation();
29513
- if (violation == null) {
29514
- return null;
29515
29646
  }
29516
- const { nodeId } = node;
29517
- return {
29518
- nodeId,
29519
- get reference() {
29520
- return node.currentState.reference;
29521
- },
29522
- violation
29523
- };
29647
+ if (action.events.includes(XFORM_EVENT.xformsValueChanged)) {
29648
+ createValueChangedCalculation(context, setValue, action);
29649
+ }
29524
29650
  };
29525
- const collectViolationReferences = (context) => {
29526
- return context.getChildren().flatMap((child) => {
29527
- switch (child.nodeType) {
29528
- case "model-value":
29529
- case "input":
29530
- case "note":
29531
- case "select":
29532
- case "range":
29533
- case "rank":
29534
- case "trigger":
29535
- case "upload": {
29536
- const reference = violationReference(child);
29537
- if (reference == null) {
29538
- return [];
29539
- }
29540
- return [reference];
29541
- }
29542
- default:
29543
- return collectViolationReferences(child);
29651
+ const createInstanceValueState = (context) => {
29652
+ return context.scope.runTask(() => {
29653
+ const initialValue = getInitialValue(context);
29654
+ const baseValueState = createSignal(initialValue);
29655
+ const relevantValueState = createRelevantValueState(context, baseValueState);
29656
+ const [, setValue] = relevantValueState;
29657
+ preloadValue(context, setValue);
29658
+ const { calculate } = context.definition.bind;
29659
+ if (calculate != null) {
29660
+ createCalculation(context, setValue, calculate);
29544
29661
  }
29545
- });
29546
- };
29547
- const createAggregatedViolations = (context, options) => {
29548
- const { scope } = context;
29549
- return scope.runTask(() => {
29550
- const violations = createMemo(() => {
29551
- return collectViolationReferences(context);
29552
- });
29553
- const spec = { violations };
29554
- return createSharedNodeState(scope, spec, options).currentState;
29662
+ const action = context.definition.model.actions.get(context.contextReference());
29663
+ if (action) {
29664
+ registerAction(context, setValue, action);
29665
+ }
29666
+ return guardDownstreamReadonlyWrites(context, relevantValueState);
29555
29667
  });
29556
29668
  };
29557
29669
 
@@ -29582,11 +29694,6 @@ class DescendantNode extends InstanceNode {
29582
29694
  return true;
29583
29695
  }
29584
29696
  }
29585
- for (const attr of parent.getAttributes()) {
29586
- if (attr === self) {
29587
- return true;
29588
- }
29589
- }
29590
29697
  return false;
29591
29698
  });
29592
29699
  });
@@ -29622,75 +29729,234 @@ class DescendantNode extends InstanceNode {
29622
29729
  if (this.hasReadonlyAncestor()) {
29623
29730
  return true;
29624
29731
  }
29625
- return this.isSelfReadonly();
29732
+ return this.isSelfReadonly();
29733
+ };
29734
+ hasNonRelevantAncestor = () => {
29735
+ const { parent } = this;
29736
+ return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29737
+ };
29738
+ isSelfRelevant;
29739
+ isRelevant = () => {
29740
+ if (this.hasNonRelevantAncestor()) {
29741
+ return false;
29742
+ }
29743
+ return this.isSelfRelevant();
29744
+ };
29745
+ isRequired;
29746
+ // XFormsXPathPrimaryInstanceDescendantNode
29747
+ /**
29748
+ * WARNING! Ideally, this would be an abstract property, defined by each
29749
+ * concrete subclass (or other intermediate abstract classes, where
29750
+ * appropriate). Unfortunately it must be assigned here, so it will be present
29751
+ * for certain XPath DOM adapter functionality **during** each concrete node's
29752
+ * construction.
29753
+ *
29754
+ * Those subclasses nevertheless override this same property, assigning the
29755
+ * same value, for the purposes of narrowing the XPath node kind semantics
29756
+ * appropriate for each node type.
29757
+ */
29758
+ [XPathNodeKindKey];
29759
+ root;
29760
+ // EvaluationContext
29761
+ isAttached;
29762
+ evaluator;
29763
+ contextNode = this;
29764
+ getActiveLanguage;
29765
+ /**
29766
+ * @package
29767
+ *
29768
+ * Performs recursive removal, first of the node's descendants, then of the
29769
+ * node itself. For all {@link DescendantNode}s, removal involves **at least**
29770
+ * disposal of its {@link scope} ({@link ReactiveScope}).
29771
+ *
29772
+ * It is expected that the outermost node targeted for removal will always be
29773
+ * a {@link RepeatInstance}. @see {@link RepeatInstance.remove} for additional
29774
+ * details.
29775
+ *
29776
+ * It is also expected that upon that outermost node's removal, its parent
29777
+ * {@link RepeatRange} will perform a reactive update to its children state so
29778
+ * that:
29779
+ *
29780
+ * 1. Any downstream computations affected by the removal are updated.
29781
+ * 2. The client invoking removal is also reactively updated (where
29782
+ * applicable).
29783
+ *
29784
+ * @see {@link RepeatInstance.remove} and {@link RepeatRange.removeInstances}
29785
+ * for additional details about their respective node-specific removal
29786
+ * behaviors and ordering.
29787
+ *
29788
+ * @todo Possibly retain removed repeat instances in memory. This came up as a
29789
+ * behavior of Collect/JavaRosa, and we should investigate the details and
29790
+ * ramifications of that, and whether it's the desired behavior.
29791
+ */
29792
+ remove() {
29793
+ this.scope.runTask(() => {
29794
+ this.getChildren().forEach((child) => {
29795
+ child.remove();
29796
+ });
29797
+ });
29798
+ this.scope.dispose();
29799
+ }
29800
+ }
29801
+
29802
+ class Attribute extends DescendantNode {
29803
+ constructor(owner, definition, instanceNode) {
29804
+ const computeReference = () => {
29805
+ return `${this.owner.contextReference()}/@${this.definition.qualifiedName.getPrefixedName()}`;
29806
+ };
29807
+ super(owner, instanceNode, definition, { computeReference });
29808
+ this.owner = owner;
29809
+ this.instanceNode = instanceNode;
29810
+ const codec = getSharedValueCodec("string");
29811
+ this.validationState = { violations: [] };
29812
+ this.valueType = "string";
29813
+ this.decodeInstanceValue = codec.decodeInstanceValue;
29814
+ const instanceValueState = createInstanceValueState(this);
29815
+ const valueState = codec.createRuntimeValueState(instanceValueState);
29816
+ const [getInstanceValue] = instanceValueState;
29817
+ const [, setValueState] = valueState;
29818
+ this.getInstanceValue = getInstanceValue;
29819
+ this.setValueState = setValueState;
29820
+ this.valueState = valueState;
29821
+ const state = createSharedNodeState(
29822
+ owner.scope,
29823
+ {
29824
+ value: this.valueState,
29825
+ instanceValue: this.getInstanceValue,
29826
+ relevant: this.owner.isRelevant,
29827
+ readonly: () => true,
29828
+ reference: this.contextReference,
29829
+ required: () => false,
29830
+ children: null,
29831
+ label: () => null,
29832
+ hint: () => null,
29833
+ attributes: () => [],
29834
+ valueOptions: () => []
29835
+ },
29836
+ this.instanceConfig
29837
+ );
29838
+ this.state = state;
29839
+ this.engineState = state.engineState;
29840
+ this.currentState = state.currentState;
29841
+ this.instanceState = createAttributeNodeInstanceState(this);
29842
+ this.attributeState = createAttributeState(this.scope);
29843
+ this.getXPathValue = () => {
29844
+ return this.getInstanceValue();
29845
+ };
29846
+ }
29847
+ [XPathNodeKindKey] = "attribute";
29848
+ state;
29849
+ engineState;
29850
+ validationState;
29851
+ nodeType = "attribute";
29852
+ currentState;
29853
+ instanceState;
29854
+ appearances = null;
29855
+ nodeOptions = null;
29856
+ valueType;
29857
+ decodeInstanceValue;
29858
+ getInstanceValue;
29859
+ valueState;
29860
+ setValueState;
29861
+ attributeState;
29862
+ isAttached = () => {
29863
+ return this.owner.isAttached();
29864
+ };
29865
+ getXPathValue;
29866
+ setValue(value) {
29867
+ this.setValueState(value);
29868
+ return this.root;
29869
+ }
29870
+ getAttributes() {
29871
+ return [];
29872
+ }
29873
+ getChildren() {
29874
+ return [];
29875
+ }
29876
+ }
29877
+
29878
+ function buildAttributes(owner) {
29879
+ const attributes = owner.definition.attributes;
29880
+ if (!attributes) {
29881
+ return [];
29882
+ }
29883
+ return Array.from(attributes.values()).map((attributeDefinition) => {
29884
+ return new Attribute(owner, attributeDefinition, attributeDefinition.template);
29885
+ });
29886
+ }
29887
+
29888
+ class InstanceAttachmentsState extends Map {
29889
+ constructor(sourceAttachments = null) {
29890
+ super();
29891
+ this.sourceAttachments = sourceAttachments;
29892
+ }
29893
+ getInitialFileValue(instanceNode) {
29894
+ if (instanceNode == null) {
29895
+ return null;
29896
+ }
29897
+ return this.sourceAttachments?.get(instanceNode.value) ?? null;
29898
+ }
29899
+ }
29900
+
29901
+ const createRootInstanceState = (node) => {
29902
+ return {
29903
+ get instanceXML() {
29904
+ return serializeParentElementXML(
29905
+ node.definition.qualifiedName,
29906
+ node.currentState.children,
29907
+ node.currentState.attributes,
29908
+ node.definition.namespaceDeclarations
29909
+ );
29910
+ }
29626
29911
  };
29627
- hasNonRelevantAncestor = () => {
29628
- const { parent } = this;
29629
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29912
+ };
29913
+
29914
+ const violationReference = (node) => {
29915
+ const violation = node.getViolation();
29916
+ if (violation == null) {
29917
+ return null;
29918
+ }
29919
+ const { nodeId } = node;
29920
+ return {
29921
+ nodeId,
29922
+ get reference() {
29923
+ return node.currentState.reference;
29924
+ },
29925
+ violation
29630
29926
  };
29631
- isSelfRelevant;
29632
- isRelevant = () => {
29633
- if (this.hasNonRelevantAncestor()) {
29634
- return false;
29927
+ };
29928
+ const collectViolationReferences = (context) => {
29929
+ return context.getChildren().flatMap((child) => {
29930
+ switch (child.nodeType) {
29931
+ case "model-value":
29932
+ case "input":
29933
+ case "note":
29934
+ case "select":
29935
+ case "range":
29936
+ case "rank":
29937
+ case "trigger":
29938
+ case "upload": {
29939
+ const reference = violationReference(child);
29940
+ if (reference == null) {
29941
+ return [];
29942
+ }
29943
+ return [reference];
29944
+ }
29945
+ default:
29946
+ return collectViolationReferences(child);
29635
29947
  }
29636
- return this.isSelfRelevant();
29637
- };
29638
- isRequired;
29639
- // XFormsXPathPrimaryInstanceDescendantNode
29640
- /**
29641
- * WARNING! Ideally, this would be an abstract property, defined by each
29642
- * concrete subclass (or other intermediate abstract classes, where
29643
- * appropriate). Unfortunately it must be assigned here, so it will be present
29644
- * for certain XPath DOM adapter functionality **during** each concrete node's
29645
- * construction.
29646
- *
29647
- * Those subclasses nevertheless override this same property, assigning the
29648
- * same value, for the purposes of narrowing the XPath node kind semantics
29649
- * appropriate for each node type.
29650
- */
29651
- [XPathNodeKindKey];
29652
- root;
29653
- // EvaluationContext
29654
- isAttached;
29655
- evaluator;
29656
- contextNode = this;
29657
- getActiveLanguage;
29658
- /**
29659
- * @package
29660
- *
29661
- * Performs recursive removal, first of the node's descendants, then of the
29662
- * node itself. For all {@link DescendantNode}s, removal involves **at least**
29663
- * disposal of its {@link scope} ({@link ReactiveScope}).
29664
- *
29665
- * It is expected that the outermost node targeted for removal will always be
29666
- * a {@link RepeatInstance}. @see {@link RepeatInstance.remove} for additional
29667
- * details.
29668
- *
29669
- * It is also expected that upon that outermost node's removal, its parent
29670
- * {@link RepeatRange} will perform a reactive update to its children state so
29671
- * that:
29672
- *
29673
- * 1. Any downstream computations affected by the removal are updated.
29674
- * 2. The client invoking removal is also reactively updated (where
29675
- * applicable).
29676
- *
29677
- * @see {@link RepeatInstance.remove} and {@link RepeatRange.removeInstances}
29678
- * for additional details about their respective node-specific removal
29679
- * behaviors and ordering.
29680
- *
29681
- * @todo Possibly retain removed repeat instances in memory. This came up as a
29682
- * behavior of Collect/JavaRosa, and we should investigate the details and
29683
- * ramifications of that, and whether it's the desired behavior.
29684
- */
29685
- remove() {
29686
- this.scope.runTask(() => {
29687
- this.getChildren().forEach((child) => {
29688
- child.remove();
29689
- });
29948
+ });
29949
+ };
29950
+ const createAggregatedViolations = (context, options) => {
29951
+ const { scope } = context;
29952
+ return scope.runTask(() => {
29953
+ const violations = createMemo(() => {
29954
+ return collectViolationReferences(context);
29690
29955
  });
29691
- this.scope.dispose();
29692
- }
29693
- }
29956
+ const spec = { violations };
29957
+ return createSharedNodeState(scope, spec, options).currentState;
29958
+ });
29959
+ };
29694
29960
 
29695
29961
  const createParentNodeInstanceState = (node) => {
29696
29962
  return {
@@ -39976,11 +40242,11 @@ const createNodeLabel = (context, definition) => {
39976
40242
 
39977
40243
  class Group extends DescendantNode {
39978
40244
  childrenState;
39979
- attributeState;
39980
40245
  [XPathNodeKindKey] = "element";
39981
40246
  // InstanceNode
39982
40247
  state;
39983
40248
  engineState;
40249
+ attributeState;
39984
40250
  // GroupNode
39985
40251
  nodeType = "group";
39986
40252
  appearances;
@@ -39992,9 +40258,8 @@ class Group extends DescendantNode {
39992
40258
  super(parent, instanceNode, definition);
39993
40259
  this.appearances = definition.bodyElement?.appearances ?? null;
39994
40260
  const childrenState = createChildrenState(this);
39995
- const attributeState = createAttributeState(this.scope);
40261
+ this.attributeState = createAttributeState(this.scope);
39996
40262
  this.childrenState = childrenState;
39997
- this.attributeState = attributeState;
39998
40263
  const state = createSharedNodeState(
39999
40264
  this.scope,
40000
40265
  {
@@ -40005,7 +40270,7 @@ class Group extends DescendantNode {
40005
40270
  label: createNodeLabel(this, definition),
40006
40271
  hint: null,
40007
40272
  children: childrenState.childIds,
40008
- attributes: attributeState.getAttributes,
40273
+ attributes: this.attributeState.getAttributes,
40009
40274
  valueOptions: null,
40010
40275
  value: null
40011
40276
  },
@@ -40019,7 +40284,7 @@ class Group extends DescendantNode {
40019
40284
  childrenState
40020
40285
  );
40021
40286
  childrenState.setChildren(buildChildren(this));
40022
- attributeState.setAttributes(buildAttributes(this));
40287
+ this.attributeState.setAttributes(buildAttributes(this));
40023
40288
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
40024
40289
  this.instanceState = createParentNodeInstanceState(this);
40025
40290
  }
@@ -40047,90 +40312,10 @@ const createValueNodeInstanceState = (node) => {
40047
40312
  return "";
40048
40313
  }
40049
40314
  const xmlValue = escapeXMLText(node.currentState.instanceValue);
40050
- return serializeLeafElementXML(qualifiedName, xmlValue);
40051
- }
40052
- };
40053
- };
40054
-
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}`);
40315
+ const attributes = node.currentState.attributes;
40316
+ return serializeLeafElementXML(qualifiedName, xmlValue, attributes);
40087
40317
  }
40088
- return baseSetValue(value);
40089
40318
  };
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
40319
  };
40135
40320
 
40136
40321
  const engineViolationMessage = (context, role) => {
@@ -40312,6 +40497,7 @@ class InputControl extends ValueNode {
40312
40497
  // InstanceNode
40313
40498
  state;
40314
40499
  engineState;
40500
+ attributeState;
40315
40501
  // InputNode
40316
40502
  nodeType = "input";
40317
40503
  appearances;
@@ -40322,6 +40508,7 @@ class InputControl extends ValueNode {
40322
40508
  super(parent, instanceNode, definition, codec);
40323
40509
  this.appearances = definition.bodyElement.appearances;
40324
40510
  this.nodeOptions = nodeOptionsFactoryByType[definition.valueType](definition.bodyElement);
40511
+ this.attributeState = createAttributeState(this.scope);
40325
40512
  const state = createSharedNodeState(
40326
40513
  this.scope,
40327
40514
  {
@@ -40332,13 +40519,14 @@ class InputControl extends ValueNode {
40332
40519
  label: createNodeLabel(this, definition),
40333
40520
  hint: createFieldHint(this, definition),
40334
40521
  children: null,
40335
- attributes: null,
40522
+ attributes: this.attributeState.getAttributes,
40336
40523
  valueOptions: null,
40337
40524
  value: this.valueState,
40338
40525
  instanceValue: this.getInstanceValue
40339
40526
  },
40340
40527
  this.instanceConfig
40341
40528
  );
40529
+ this.attributeState.setAttributes(buildAttributes(this));
40342
40530
  this.state = state;
40343
40531
  this.engineState = state.engineState;
40344
40532
  this.currentState = state.currentState;
@@ -40347,6 +40535,9 @@ class InputControl extends ValueNode {
40347
40535
  this.setValueState(value);
40348
40536
  return this.root;
40349
40537
  }
40538
+ getAttributes() {
40539
+ return this.attributeState.getAttributes();
40540
+ }
40350
40541
  }
40351
40542
 
40352
40543
  class ModelValue extends ValueNode {
@@ -40358,6 +40549,7 @@ class ModelValue extends ValueNode {
40358
40549
  // InstanceNode
40359
40550
  state;
40360
40551
  engineState;
40552
+ attributeState;
40361
40553
  // ModelValueNode
40362
40554
  nodeType = "model-value";
40363
40555
  appearances = null;
@@ -40366,6 +40558,7 @@ class ModelValue extends ValueNode {
40366
40558
  constructor(parent, instanceNode, definition) {
40367
40559
  const codec = getSharedValueCodec(definition.valueType);
40368
40560
  super(parent, instanceNode, definition, codec);
40561
+ this.attributeState = createAttributeState(this.scope);
40369
40562
  const state = createSharedNodeState(
40370
40563
  this.scope,
40371
40564
  {
@@ -40376,17 +40569,21 @@ class ModelValue extends ValueNode {
40376
40569
  label: null,
40377
40570
  hint: null,
40378
40571
  children: null,
40379
- attributes: null,
40572
+ attributes: this.attributeState.getAttributes,
40380
40573
  valueOptions: null,
40381
40574
  value: this.valueState,
40382
40575
  instanceValue: this.getInstanceValue
40383
40576
  },
40384
40577
  this.instanceConfig
40385
40578
  );
40579
+ this.attributeState.setAttributes(buildAttributes(this));
40386
40580
  this.state = state;
40387
40581
  this.engineState = state.engineState;
40388
40582
  this.currentState = state.currentState;
40389
40583
  }
40584
+ getAttributes() {
40585
+ return this.attributeState.getAttributes();
40586
+ }
40390
40587
  }
40391
40588
 
40392
40589
  class NoteCodec extends ValueCodec {
@@ -40463,6 +40660,7 @@ class Note extends ValueNode {
40463
40660
  // InstanceNode
40464
40661
  state;
40465
40662
  engineState;
40663
+ attributeState;
40466
40664
  // NoteNode
40467
40665
  nodeType = "note";
40468
40666
  appearances;
@@ -40474,6 +40672,7 @@ class Note extends ValueNode {
40474
40672
  this.appearances = definition.bodyElement.appearances;
40475
40673
  const isReadonly = createNoteReadonlyThunk(this, definition);
40476
40674
  const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
40675
+ this.attributeState = createAttributeState(this.scope);
40477
40676
  let noteText;
40478
40677
  let label;
40479
40678
  let hint;
@@ -40504,17 +40703,21 @@ class Note extends ValueNode {
40504
40703
  hint,
40505
40704
  noteText,
40506
40705
  children: null,
40507
- attributes: null,
40706
+ attributes: this.attributeState.getAttributes,
40508
40707
  valueOptions: null,
40509
40708
  value: this.valueState,
40510
40709
  instanceValue: this.getInstanceValue
40511
40710
  },
40512
40711
  this.instanceConfig
40513
40712
  );
40713
+ this.attributeState.setAttributes(buildAttributes(this));
40514
40714
  this.state = state;
40515
40715
  this.engineState = state.engineState;
40516
40716
  this.currentState = state.currentState;
40517
40717
  }
40718
+ getAttributes() {
40719
+ return this.attributeState.getAttributes();
40720
+ }
40518
40721
  }
40519
40722
 
40520
40723
  class RangeCodec extends ValueCodec {
@@ -40564,6 +40767,7 @@ class RangeControl extends ValueNode {
40564
40767
  // InstanceNode
40565
40768
  state;
40566
40769
  engineState;
40770
+ attributeState;
40567
40771
  // RangeNode
40568
40772
  nodeType = "range";
40569
40773
  appearances;
@@ -40574,6 +40778,7 @@ class RangeControl extends ValueNode {
40574
40778
  const codec = new RangeCodec(baseCodec, definition);
40575
40779
  super(parent, instanceNode, definition, codec);
40576
40780
  this.appearances = definition.bodyElement.appearances;
40781
+ this.attributeState = createAttributeState(this.scope);
40577
40782
  const state = createSharedNodeState(
40578
40783
  this.scope,
40579
40784
  {
@@ -40584,13 +40789,14 @@ class RangeControl extends ValueNode {
40584
40789
  label: createNodeLabel(this, definition),
40585
40790
  hint: createFieldHint(this, definition),
40586
40791
  children: null,
40587
- attributes: null,
40792
+ attributes: this.attributeState.getAttributes,
40588
40793
  valueOptions: null,
40589
40794
  value: this.valueState,
40590
40795
  instanceValue: this.getInstanceValue
40591
40796
  },
40592
40797
  this.instanceConfig
40593
40798
  );
40799
+ this.attributeState.setAttributes(buildAttributes(this));
40594
40800
  this.state = state;
40595
40801
  this.engineState = state.engineState;
40596
40802
  this.currentState = state.currentState;
@@ -40599,6 +40805,9 @@ class RangeControl extends ValueNode {
40599
40805
  this.setValueState(value);
40600
40806
  return this.root;
40601
40807
  }
40808
+ getAttributes() {
40809
+ return this.attributeState.getAttributes();
40810
+ }
40602
40811
  }
40603
40812
 
40604
40813
  class RankMissingValueError extends Error {
@@ -40790,6 +40999,7 @@ class RankControl extends ValueNode {
40790
40999
  // InstanceNode
40791
41000
  state;
40792
41001
  engineState;
41002
+ attributeState;
40793
41003
  // RankNode
40794
41004
  nodeType = "rank";
40795
41005
  appearances;
@@ -40808,6 +41018,7 @@ class RankControl extends ValueNode {
40808
41018
  this.mapOptionsByValue = mapOptionsByValue;
40809
41019
  const baseValueState = this.valueState;
40810
41020
  const [baseGetValue, setValue] = baseValueState;
41021
+ this.attributeState = createAttributeState(this.scope);
40811
41022
  const getValue = this.scope.runTask(() => {
40812
41023
  return createMemo(() => {
40813
41024
  const options = valueOptions();
@@ -40842,17 +41053,21 @@ class RankControl extends ValueNode {
40842
41053
  label: createNodeLabel(this, definition),
40843
41054
  hint: createFieldHint(this, definition),
40844
41055
  children: null,
40845
- attributes: null,
41056
+ attributes: this.attributeState.getAttributes,
40846
41057
  valueOptions,
40847
41058
  value: valueState,
40848
41059
  instanceValue: this.getInstanceValue
40849
41060
  },
40850
41061
  this.instanceConfig
40851
41062
  );
41063
+ this.attributeState.setAttributes(buildAttributes(this));
40852
41064
  this.state = state;
40853
41065
  this.engineState = state.engineState;
40854
41066
  this.currentState = state.currentState;
40855
41067
  }
41068
+ getAttributes() {
41069
+ return this.attributeState.getAttributes();
41070
+ }
40856
41071
  getValueLabel(value) {
40857
41072
  const valueOption = this.currentState.valueOptions.find((item) => item.value === value);
40858
41073
  return valueOption?.label ?? null;
@@ -40935,9 +41150,8 @@ class RepeatInstance extends DescendantNode {
40935
41150
  this.parent = parent;
40936
41151
  this.appearances = definition.bodyElement.appearances;
40937
41152
  const childrenState = createChildrenState(this);
40938
- const attributeState = createAttributeState(this.scope);
41153
+ this.attributeState = createAttributeState(this.scope);
40939
41154
  this.childrenState = childrenState;
40940
- this.attributeState = attributeState;
40941
41155
  this.currentIndex = currentIndex;
40942
41156
  const state = createSharedNodeState(
40943
41157
  this.scope,
@@ -40949,7 +41163,7 @@ class RepeatInstance extends DescendantNode {
40949
41163
  // TODO: only-child <group><label>
40950
41164
  label: createNodeLabel(this, definition),
40951
41165
  hint: null,
40952
- attributes: attributeState.getAttributes,
41166
+ attributes: this.attributeState.getAttributes,
40953
41167
  children: childrenState.childIds,
40954
41168
  valueOptions: null,
40955
41169
  value: null
@@ -41334,6 +41548,7 @@ class SelectControl extends ValueNode {
41334
41548
  // InstanceNode
41335
41549
  state;
41336
41550
  engineState;
41551
+ attributeState;
41337
41552
  // SelectNode
41338
41553
  nodeType = "select";
41339
41554
  selectType;
@@ -41345,6 +41560,7 @@ class SelectControl extends ValueNode {
41345
41560
  super(parent, instanceNode, definition, codec);
41346
41561
  this.appearances = definition.bodyElement.appearances;
41347
41562
  this.selectType = definition.bodyElement.type;
41563
+ this.attributeState = createAttributeState(this.scope);
41348
41564
  const valueOptions = createItemCollection(this);
41349
41565
  const isSelectWithImages = this.scope.runTask(() => {
41350
41566
  return createMemo(() => valueOptions().some((item) => !!item.label.imageSource));
@@ -41381,7 +41597,7 @@ class SelectControl extends ValueNode {
41381
41597
  label: createNodeLabel(this, definition),
41382
41598
  hint: createFieldHint(this, definition),
41383
41599
  children: null,
41384
- attributes: null,
41600
+ attributes: this.attributeState.getAttributes,
41385
41601
  valueOptions,
41386
41602
  value: valueState,
41387
41603
  instanceValue: this.getInstanceValue,
@@ -41389,6 +41605,7 @@ class SelectControl extends ValueNode {
41389
41605
  },
41390
41606
  this.instanceConfig
41391
41607
  );
41608
+ this.attributeState.setAttributes(buildAttributes(this));
41392
41609
  this.state = state;
41393
41610
  this.engineState = state.engineState;
41394
41611
  this.currentState = state.currentState;
@@ -41447,6 +41664,9 @@ class SelectControl extends ValueNode {
41447
41664
  const option = this.mapOptionsByValue().get(value);
41448
41665
  return option?.label?.asString ?? null;
41449
41666
  }
41667
+ getAttributes() {
41668
+ return this.attributeState.getAttributes();
41669
+ }
41450
41670
  }
41451
41671
 
41452
41672
  const TRIGGER_INSTANCE_VALUES = {
@@ -41499,6 +41719,7 @@ class TriggerControl extends ValueNode {
41499
41719
  // InstanceNode
41500
41720
  state;
41501
41721
  engineState;
41722
+ attributeState;
41502
41723
  // TriggerNode
41503
41724
  nodeType = "trigger";
41504
41725
  appearances;
@@ -41507,6 +41728,7 @@ class TriggerControl extends ValueNode {
41507
41728
  constructor(parent, instanceNode, definition) {
41508
41729
  super(parent, instanceNode, definition, codec);
41509
41730
  this.appearances = definition.bodyElement.appearances;
41731
+ this.attributeState = createAttributeState(this.scope);
41510
41732
  const state = createSharedNodeState(
41511
41733
  this.scope,
41512
41734
  {
@@ -41517,17 +41739,21 @@ class TriggerControl extends ValueNode {
41517
41739
  label: createNodeLabel(this, definition),
41518
41740
  hint: createFieldHint(this, definition),
41519
41741
  children: null,
41520
- attributes: null,
41742
+ attributes: this.attributeState.getAttributes,
41521
41743
  valueOptions: null,
41522
41744
  value: this.valueState,
41523
41745
  instanceValue: this.getInstanceValue
41524
41746
  },
41525
41747
  this.instanceConfig
41526
41748
  );
41749
+ this.attributeState.setAttributes(buildAttributes(this));
41527
41750
  this.state = state;
41528
41751
  this.engineState = state.engineState;
41529
41752
  this.currentState = state.currentState;
41530
41753
  }
41754
+ getAttributes() {
41755
+ return this.attributeState.getAttributes();
41756
+ }
41531
41757
  // TriggerNode
41532
41758
  setValue(value) {
41533
41759
  this.setValueState(value);
@@ -41716,8 +41942,7 @@ class UploadControl extends DescendantNode {
41716
41942
  this.nodeOptions = definition.bodyElement.options;
41717
41943
  const instanceAttachment = createInstanceAttachment(this);
41718
41944
  this.instanceAttachment = instanceAttachment;
41719
- const attributeState = createAttributeState(this.scope);
41720
- this.attributeState = attributeState;
41945
+ this.attributeState = createAttributeState(this.scope);
41721
41946
  this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
41722
41947
  this.getXPathValue = instanceAttachment.getInstanceValue;
41723
41948
  const state = createSharedNodeState(
@@ -41732,7 +41957,7 @@ class UploadControl extends DescendantNode {
41732
41957
  children: null,
41733
41958
  valueOptions: null,
41734
41959
  value: instanceAttachment.valueState,
41735
- attributes: attributeState.getAttributes,
41960
+ attributes: this.attributeState.getAttributes,
41736
41961
  instanceValue: instanceAttachment.getInstanceValue
41737
41962
  },
41738
41963
  this.instanceConfig
@@ -41741,6 +41966,7 @@ class UploadControl extends DescendantNode {
41741
41966
  this.engineState = state.engineState;
41742
41967
  this.currentState = state.currentState;
41743
41968
  this.validation = createValidationState(this, this.instanceConfig);
41969
+ this.attributeState.setAttributes(buildAttributes(this));
41744
41970
  this.instanceState = createValueNodeInstanceState(this);
41745
41971
  }
41746
41972
  static from(parent, instanceNode, definition) {
@@ -41749,13 +41975,13 @@ class UploadControl extends DescendantNode {
41749
41975
  }
41750
41976
  validation;
41751
41977
  instanceAttachment;
41752
- attributeState;
41753
41978
  // XFormsXPathElement
41754
41979
  [XPathNodeKindKey] = "element";
41755
41980
  getXPathValue;
41756
41981
  // InstanceNode
41757
41982
  state;
41758
41983
  engineState;
41984
+ attributeState;
41759
41985
  // InstanceValueContext
41760
41986
  decodeInstanceValue;
41761
41987
  // UploadNode
@@ -41779,14 +42005,14 @@ class UploadControl extends DescendantNode {
41779
42005
  getChildren() {
41780
42006
  return [];
41781
42007
  }
42008
+ getAttributes() {
42009
+ return this.attributeState.getAttributes();
42010
+ }
41782
42011
  // UploadNode
41783
42012
  setValue(value) {
41784
42013
  this.instanceAttachment.setValue(value);
41785
42014
  return this.root;
41786
42015
  }
41787
- getAttributes() {
41788
- return this.attributeState.getAttributes();
41789
- }
41790
42016
  }
41791
42017
 
41792
42018
  const META_LOCAL_NAME = "meta";
@@ -41872,7 +42098,7 @@ const buildMetaValueElement = (group, localName, value) => {
41872
42098
  const buildDeprecatedIDDefinition = (group, instanceNode) => {
41873
42099
  const nodeset = instanceNode.nodeset;
41874
42100
  const bind = group.model.binds.getOrCreateBindDefinition(nodeset);
41875
- return new LeafNodeDefinition(group.parent.definition, bind, null, instanceNode);
42101
+ return new LeafNodeDefinition(group.model, group.parent.definition, bind, null, instanceNode);
41876
42102
  };
41877
42103
  const buildDeprecatedID = (group, value) => {
41878
42104
  const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
@@ -42068,12 +42294,12 @@ const buildChildren = (parent) => {
42068
42294
 
42069
42295
  class Root extends DescendantNode {
42070
42296
  childrenState;
42071
- attributeState;
42072
42297
  // XFormsXPathElement
42073
42298
  [XPathNodeKindKey] = "element";
42074
42299
  // DescendantNode
42075
42300
  state;
42076
42301
  engineState;
42302
+ attributeState;
42077
42303
  hasReadonlyAncestor = () => false;
42078
42304
  isSelfReadonly = () => false;
42079
42305
  isReadonly = () => false;
@@ -42100,9 +42326,8 @@ class Root extends DescendantNode {
42100
42326
  });
42101
42327
  this.classes = parent.classes;
42102
42328
  const childrenState = createChildrenState(this);
42103
- const attributeState = createAttributeState(this.scope);
42329
+ this.attributeState = createAttributeState(this.scope);
42104
42330
  this.childrenState = childrenState;
42105
- this.attributeState = attributeState;
42106
42331
  this.languages = parent.languages;
42107
42332
  const state = createSharedNodeState(
42108
42333
  this.scope,
@@ -42117,7 +42342,7 @@ class Root extends DescendantNode {
42117
42342
  valueOptions: null,
42118
42343
  value: null,
42119
42344
  children: childrenState.childIds,
42120
- attributes: attributeState.getAttributes
42345
+ attributes: this.attributeState.getAttributes
42121
42346
  },
42122
42347
  this.instanceConfig
42123
42348
  );
@@ -42129,7 +42354,7 @@ class Root extends DescendantNode {
42129
42354
  childrenState
42130
42355
  );
42131
42356
  childrenState.setChildren(buildChildren(this));
42132
- attributeState.setAttributes(buildAttributes(this));
42357
+ this.attributeState.setAttributes(buildAttributes(this));
42133
42358
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
42134
42359
  this.instanceState = createRootInstanceState(this);
42135
42360
  }
@@ -42157,6 +42382,7 @@ class PrimaryInstance extends InstanceNode {
42157
42382
  // InstanceNode
42158
42383
  state;
42159
42384
  engineState;
42385
+ attributeState;
42160
42386
  instanceNode;
42161
42387
  getChildren;
42162
42388
  hasReadonlyAncestor = () => false;
@@ -42183,7 +42409,6 @@ class PrimaryInstance extends InstanceNode {
42183
42409
  isAttached;
42184
42410
  evaluator;
42185
42411
  contextNode = this;
42186
- attributeState;
42187
42412
  constructor(options) {
42188
42413
  const { mode, initialState, scope, model, secondaryInstances, config } = options;
42189
42414
  const { instance: modelInstance } = model;
@@ -42214,9 +42439,8 @@ class PrimaryInstance extends InstanceNode {
42214
42439
  this.evaluator = evaluator;
42215
42440
  this.classes = definition.classes;
42216
42441
  const childrenState = createChildrenState(this);
42217
- const attributeState = createAttributeState(this.scope);
42442
+ this.attributeState = createAttributeState(this.scope);
42218
42443
  this.getChildren = childrenState.getChildren;
42219
- this.attributeState = attributeState;
42220
42444
  const stateSpec = {
42221
42445
  activeLanguage: getActiveLanguage,
42222
42446
  reference: PRIMARY_INSTANCE_REFERENCE,
@@ -42228,7 +42452,7 @@ class PrimaryInstance extends InstanceNode {
42228
42452
  valueOptions: null,
42229
42453
  value: null,
42230
42454
  children: childrenState.childIds,
42231
- attributes: attributeState.getAttributes
42455
+ attributes: this.attributeState.getAttributes
42232
42456
  };
42233
42457
  const state = createSharedNodeState(scope, stateSpec, config);
42234
42458
  this.state = state;
@@ -42243,9 +42467,12 @@ class PrimaryInstance extends InstanceNode {
42243
42467
  };
42244
42468
  this.instanceState = createPrimaryInstanceState(this);
42245
42469
  childrenState.setChildren([root]);
42246
- attributeState.setAttributes(buildAttributes(this));
42470
+ this.attributeState.setAttributes(buildAttributes(this));
42247
42471
  setIsAttached(true);
42248
42472
  }
42473
+ getAttributes() {
42474
+ return this.attributeState.getAttributes();
42475
+ }
42249
42476
  // PrimaryInstanceDocument
42250
42477
  /**
42251
42478
  * @todo Note that this method's signature is intentionally derived from
@@ -42286,9 +42513,6 @@ class PrimaryInstance extends InstanceNode {
42286
42513
  });
42287
42514
  return Promise.resolve(result);
42288
42515
  }
42289
- getAttributes() {
42290
- return this.attributeState.getAttributes();
42291
- }
42292
42516
  }
42293
42517
 
42294
42518
  class FormInstance {
@@ -42297,7 +42521,8 @@ class FormInstance {
42297
42521
  const { mode, initialState, instanceConfig } = options;
42298
42522
  const config = {
42299
42523
  clientStateFactory: instanceConfig.stateFactory ?? identity,
42300
- computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null)
42524
+ computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null),
42525
+ preloadProperties: instanceConfig.preloadProperties ?? {}
42301
42526
  };
42302
42527
  const primaryInstanceOptions = {
42303
42528
  ...options.instanceOptions,