@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/solid.js CHANGED
@@ -19301,6 +19301,12 @@ class XFormDOM {
19301
19301
  contextNode: model
19302
19302
  }
19303
19303
  );
19304
+ const setValues = evaluator.evaluateNodes(
19305
+ "./xf:setvalue[@event]",
19306
+ {
19307
+ contextNode: model
19308
+ }
19309
+ );
19304
19310
  const instances = evaluator.evaluateNodes("./xf:instance", {
19305
19311
  contextNode: model
19306
19312
  });
@@ -19336,6 +19342,7 @@ class XFormDOM {
19336
19342
  this.title = title;
19337
19343
  this.model = model;
19338
19344
  this.binds = binds;
19345
+ this.setValues = setValues;
19339
19346
  this.primaryInstance = primaryInstance;
19340
19347
  this.primaryInstanceRoot = primaryInstanceRoot;
19341
19348
  this.itextTranslationElements = itextTranslationElements;
@@ -19353,6 +19360,7 @@ class XFormDOM {
19353
19360
  title;
19354
19361
  model;
19355
19362
  binds;
19363
+ setValues;
19356
19364
  primaryInstance;
19357
19365
  primaryInstanceRoot;
19358
19366
  itextTranslationElements;
@@ -20193,6 +20201,27 @@ class ControlDefinition extends BodyElementDefinition {
20193
20201
  }
20194
20202
  }
20195
20203
 
20204
+ const parseToInteger = (value) => {
20205
+ if (value === null) {
20206
+ return null;
20207
+ }
20208
+ const parsed = Number(value);
20209
+ if (typeof value !== "string" || value.trim() === "" || !Number.isInteger(parsed)) {
20210
+ throw new Error(`Expected an integer, but got: ${value}`);
20211
+ }
20212
+ return parsed;
20213
+ };
20214
+ const parseToFloat = (value) => {
20215
+ if (value === null) {
20216
+ return null;
20217
+ }
20218
+ const parsed = Number(value);
20219
+ if (typeof value !== "string" || value.trim() === "" || Number.isNaN(parsed)) {
20220
+ throw new Error(`Expected a float, but got: ${value}`);
20221
+ }
20222
+ return parsed;
20223
+ };
20224
+
20196
20225
  const inputAppearanceParser = new TokenListParser([
20197
20226
  "multiline",
20198
20227
  "numbers",
@@ -20226,27 +20255,6 @@ const inputAppearanceParser = new TokenListParser([
20226
20255
  "masked"
20227
20256
  ]);
20228
20257
 
20229
- const parseToInteger = (value) => {
20230
- if (value === null) {
20231
- return null;
20232
- }
20233
- const parsed = Number(value);
20234
- if (typeof value !== "string" || value.trim() === "" || !Number.isInteger(parsed)) {
20235
- throw new Error(`Expected an integer, but got: ${value}`);
20236
- }
20237
- return parsed;
20238
- };
20239
- const parseToFloat = (value) => {
20240
- if (value === null) {
20241
- return null;
20242
- }
20243
- const parsed = Number(value);
20244
- if (typeof value !== "string" || value.trim() === "" || Number.isNaN(parsed)) {
20245
- throw new Error(`Expected a float, but got: ${value}`);
20246
- }
20247
- return parsed;
20248
- };
20249
-
20250
20258
  class InputControlDefinition extends ControlDefinition {
20251
20259
  static isCompatible(localName) {
20252
20260
  return localName === "input";
@@ -20623,8 +20631,8 @@ class GroupElementDefinition extends BodyElementDefinition {
20623
20631
  const childName = child.localName;
20624
20632
  return childName !== "label";
20625
20633
  });
20626
- this.children = this.body.getChildElementDefinitions(form, this, element, childElements);
20627
20634
  this.reference = parseNodesetReference(parent, element, "ref");
20635
+ this.children = this.body.getChildElementDefinitions(form, this, element, childElements);
20628
20636
  this.appearances = structureElementAppearanceParser.parseFrom(element, "appearance");
20629
20637
  this.label = LabelDefinition.forGroup(form, this);
20630
20638
  }
@@ -20901,6 +20909,7 @@ class StaticAttribute extends StaticNode {
20901
20909
  nodeset;
20902
20910
  attributes = [];
20903
20911
  children = null;
20912
+ childElements = [];
20904
20913
  value;
20905
20914
  // XFormsXPathAttribute
20906
20915
  getXPathValue() {
@@ -21230,6 +21239,105 @@ class ItextTranslationsDefinition extends Map {
21230
21239
  }
21231
21240
  }
21232
21241
 
21242
+ class ActionComputationExpression extends DependentExpression {
21243
+ constructor(resultType, expression) {
21244
+ super(resultType, expression);
21245
+ }
21246
+ }
21247
+
21248
+ const XFORM_EVENT = {
21249
+ odkInstanceLoad: "odk-instance-load",
21250
+ odkInstanceFirstLoad: "odk-instance-first-load",
21251
+ odkNewRepeat: "odk-new-repeat",
21252
+ xformsRevalidate: "xforms-revalidate",
21253
+ xformsValueChanged: "xforms-value-changed"
21254
+ };
21255
+
21256
+ class ActionDefinition {
21257
+ constructor(model, element, source) {
21258
+ this.element = element;
21259
+ const ref = ActionDefinition.getRef(model, element);
21260
+ if (!ref) {
21261
+ throw new Error(
21262
+ 'Invalid setvalue element - you must define either "ref" or "bind" attribute'
21263
+ );
21264
+ }
21265
+ this.ref = ref;
21266
+ this.events = ActionDefinition.getEvents(element);
21267
+ const value = ActionDefinition.getValue(element);
21268
+ this.computation = new ActionComputationExpression("string", value);
21269
+ this.source = source;
21270
+ }
21271
+ static getRef(model, setValueElement) {
21272
+ if (setValueElement.hasAttribute("ref")) {
21273
+ return setValueElement.getAttribute("ref") ?? null;
21274
+ }
21275
+ if (setValueElement.hasAttribute("bind")) {
21276
+ const bindId = setValueElement.getAttribute("bind");
21277
+ const bindDefinition = Array.from(model.binds.values()).find((definition) => {
21278
+ return definition.bindElement.getAttribute("id") === bindId;
21279
+ });
21280
+ return bindDefinition?.nodeset ?? null;
21281
+ }
21282
+ return null;
21283
+ }
21284
+ static getValue(element) {
21285
+ if (element.hasAttribute("value")) {
21286
+ return element.getAttribute("value") || "''";
21287
+ }
21288
+ if (element.firstChild && isTextNode(element.firstChild)) {
21289
+ return `'${element.firstChild.nodeValue}'`;
21290
+ }
21291
+ return "''";
21292
+ }
21293
+ static isKnownEvent = (event) => {
21294
+ return Object.values(XFORM_EVENT).includes(event);
21295
+ };
21296
+ static getEvents(element) {
21297
+ const events = element.getAttribute("event")?.split(" ") ?? [];
21298
+ const unknownEvents = events.filter((event) => !this.isKnownEvent(event));
21299
+ if (unknownEvents.length) {
21300
+ throw new Error(
21301
+ `An action was registered for unsupported events: ${unknownEvents.join(", ")}`
21302
+ );
21303
+ }
21304
+ return events;
21305
+ }
21306
+ ref;
21307
+ events;
21308
+ computation;
21309
+ source;
21310
+ }
21311
+
21312
+ const REPEAT_REGEX = /(\[[^\]]*\])/gm;
21313
+ class ModelActionMap extends Map {
21314
+ static fromModel(model) {
21315
+ return new this(model);
21316
+ }
21317
+ static getKey(ref) {
21318
+ return ref.replace(REPEAT_REGEX, "");
21319
+ }
21320
+ constructor(model) {
21321
+ super(
21322
+ model.form.xformDOM.setValues.map((setValueElement) => {
21323
+ const action = new ActionDefinition(model, setValueElement);
21324
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
21325
+ throw new Error('Model contains "setvalue" element with "odk-new-repeat" event');
21326
+ }
21327
+ const key = ModelActionMap.getKey(action.ref);
21328
+ return [key, action];
21329
+ })
21330
+ );
21331
+ }
21332
+ get(ref) {
21333
+ return super.get(ModelActionMap.getKey(ref));
21334
+ }
21335
+ add(action) {
21336
+ const key = ModelActionMap.getKey(action.ref);
21337
+ this.set(key, action);
21338
+ }
21339
+ }
21340
+
21233
21341
  const defaultBindComputationExpressions = {
21234
21342
  calculate: null,
21235
21343
  constraint: "true()",
@@ -21295,6 +21403,7 @@ class MessageDefinition extends TextRangeDefinition {
21295
21403
  chunks;
21296
21404
  }
21297
21405
 
21406
+ const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
21298
21407
  const getPreloadInput = (bindElement) => {
21299
21408
  const type = bindElement.getAttributeNS(JAVAROSA_NAMESPACE_URI$1, "preload");
21300
21409
  if (type == null) {
@@ -21319,9 +21428,38 @@ class BindPreloadDefinition {
21319
21428
  }
21320
21429
  type;
21321
21430
  parameter;
21431
+ event;
21432
+ getValue(context) {
21433
+ if (this.type === "uid") {
21434
+ return context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION);
21435
+ }
21436
+ if (this.type === "timestamp") {
21437
+ return context.evaluator.evaluateString("now()");
21438
+ }
21439
+ if (this.type === "date") {
21440
+ return context.evaluator.evaluateString("today()");
21441
+ }
21442
+ if (this.type === "property") {
21443
+ const properties = context.instanceConfig.preloadProperties;
21444
+ if (this.parameter === "deviceid") {
21445
+ return properties.deviceID;
21446
+ }
21447
+ if (this.parameter === "email") {
21448
+ return properties.email;
21449
+ }
21450
+ if (this.parameter === "phonenumber") {
21451
+ return properties.phoneNumber;
21452
+ }
21453
+ if (this.parameter === "username") {
21454
+ return properties.username;
21455
+ }
21456
+ }
21457
+ return;
21458
+ }
21322
21459
  constructor(input) {
21323
21460
  this.type = input.type;
21324
21461
  this.parameter = input.parameter;
21462
+ this.event = this.type === "timestamp" && this.parameter === "end" ? XFORM_EVENT.xformsRevalidate : XFORM_EVENT.odkInstanceFirstLoad;
21325
21463
  }
21326
21464
  }
21327
21465
 
@@ -21468,10 +21606,7 @@ class BindDefinition extends DependencyContext {
21468
21606
  // TODO: it is unclear whether this will need to be supported.
21469
21607
  // https://github.com/getodk/collect/issues/3758 mentions deprecation.
21470
21608
  saveIncomplete;
21471
- // TODO: these are deferred until prioritized
21472
- // readonly preload: string | null;
21473
- // readonly preloadParams: string | null;
21474
- // readonly 'max-pixels': string | null;
21609
+ // TODO: deferred until prioritized: readonly 'max-pixels': string | null;
21475
21610
  _parentBind;
21476
21611
  get parentBind() {
21477
21612
  let bind = this._parentBind;
@@ -21637,8 +21772,14 @@ const serializeParentElementXML = (qualifiedName, children, attributes, namespac
21637
21772
  namespaceDeclarations
21638
21773
  );
21639
21774
  };
21640
- const serializeLeafElementXML = (qualifiedName, xmlValue, namespaceDeclarations) => {
21641
- return serializeElementXML(qualifiedName, xmlValue.normalize(), "", namespaceDeclarations);
21775
+ const serializeLeafElementXML = (qualifiedName, xmlValue, attributes, namespaceDeclarations) => {
21776
+ const serializedAttributes = attributes?.map((attribute) => attribute.instanceState.instanceXML).join("") ?? "";
21777
+ return serializeElementXML(
21778
+ qualifiedName,
21779
+ xmlValue.normalize(),
21780
+ serializedAttributes,
21781
+ namespaceDeclarations
21782
+ );
21642
21783
  };
21643
21784
 
21644
21785
  class NamespaceDeclaration {
@@ -21868,11 +22009,12 @@ class NodeDefinition {
21868
22009
  }
21869
22010
 
21870
22011
  class AttributeDefinition extends NodeDefinition {
21871
- constructor(root, bind, template) {
22012
+ constructor(model, bind, template) {
21872
22013
  super(bind);
22014
+ this.model = model;
21873
22015
  this.template = template;
21874
22016
  const { value } = template;
21875
- this.root = root;
22017
+ this.root = model.root;
21876
22018
  this.value = value;
21877
22019
  this.qualifiedName = template.qualifiedName;
21878
22020
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
@@ -21886,6 +22028,7 @@ class AttributeDefinition extends NodeDefinition {
21886
22028
  serializedXML;
21887
22029
  value;
21888
22030
  type = "attribute";
22031
+ valueType = "string";
21889
22032
  namespaceDeclarations;
21890
22033
  bodyElement = null;
21891
22034
  root;
@@ -21897,6 +22040,10 @@ class AttributeDefinition extends NodeDefinition {
21897
22040
  serializeAttributeXML() {
21898
22041
  return this.serializedXML;
21899
22042
  }
22043
+ toJSON() {
22044
+ const { bind, bodyElement, parent, root, ...rest } = this;
22045
+ return rest;
22046
+ }
21900
22047
  }
21901
22048
 
21902
22049
  const isNonNamespaceAttribute = (attribute) => {
@@ -21907,7 +22054,7 @@ class AttributeDefinitionMap extends Map {
21907
22054
  const nonNamespaceAttributes = instanceNode.attributes.filter(isNonNamespaceAttribute);
21908
22055
  const definitions = nonNamespaceAttributes.map((attribute) => {
21909
22056
  const bind = model.binds.getOrCreateBindDefinition(attribute.nodeset);
21910
- return new AttributeDefinition(model.root, bind, attribute);
22057
+ return new AttributeDefinition(model, bind, attribute);
21911
22058
  });
21912
22059
  return new this(definitions);
21913
22060
  }
@@ -21959,22 +22106,24 @@ class GroupDefinition extends DescendentNodeDefinition {
21959
22106
  }
21960
22107
 
21961
22108
  class LeafNodeDefinition extends DescendentNodeDefinition {
21962
- constructor(parent, bind, bodyElement, template) {
22109
+ constructor(model, parent, bind, bodyElement, template) {
21963
22110
  if (bodyElement != null && bodyElement.category !== "control") {
21964
22111
  throw new Error(`Unexpected body element for nodeset ${bind.nodeset}`);
21965
22112
  }
21966
22113
  super(parent, bind, bodyElement);
22114
+ this.model = model;
21967
22115
  this.template = template;
21968
22116
  this.valueType = bind.type.resolved;
21969
22117
  this.qualifiedName = template.qualifiedName;
21970
22118
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
22119
+ this.attributes = AttributeDefinitionMap.from(model, template);
21971
22120
  }
21972
22121
  type = "leaf-node";
21973
22122
  valueType;
21974
22123
  namespaceDeclarations;
21975
22124
  qualifiedName;
21976
22125
  children = null;
21977
- attributes = null;
22126
+ attributes;
21978
22127
  toJSON() {
21979
22128
  const { bind, bodyElement, parent, root, ...rest } = this;
21980
22129
  return rest;
@@ -21985,13 +22134,13 @@ const isNoteBindDefinition = (bind) => {
21985
22134
  return bind.readonly.isConstantTruthyExpression();
21986
22135
  };
21987
22136
  class NoteNodeDefinition extends LeafNodeDefinition {
21988
- constructor(parent, bind, bodyElement, noteTextDefinition, template) {
21989
- super(parent, bind, bodyElement, template);
22137
+ constructor(model, parent, bind, bodyElement, noteTextDefinition, template) {
22138
+ super(model, parent, bind, bodyElement, template);
21990
22139
  this.bind = bind;
21991
22140
  this.bodyElement = bodyElement;
21992
22141
  this.noteTextDefinition = noteTextDefinition;
21993
22142
  }
21994
- static from(parent, bind, bodyElement, node) {
22143
+ static from(model, parent, bind, bodyElement, node) {
21995
22144
  if (!isNoteBindDefinition(bind) || bodyElement?.type !== "input") {
21996
22145
  return null;
21997
22146
  }
@@ -22000,7 +22149,7 @@ class NoteNodeDefinition extends LeafNodeDefinition {
22000
22149
  if (noteTextDefinition == null) {
22001
22150
  return null;
22002
22151
  }
22003
- return new this(parent, bind, bodyElement, noteTextDefinition, node);
22152
+ return new this(model, parent, bind, bodyElement, noteTextDefinition, node);
22004
22153
  }
22005
22154
  }
22006
22155
 
@@ -26211,15 +26360,15 @@ class RangeNodeBoundsDefinition {
26211
26360
  }
26212
26361
  }
26213
26362
  class RangeNodeDefinition extends LeafNodeDefinition {
26214
- constructor(parent, bind, bodyElement, node) {
26215
- super(parent, bind, bodyElement, node);
26363
+ constructor(model, parent, bind, bodyElement, node) {
26364
+ super(model, parent, bind, bodyElement, node);
26216
26365
  this.bind = bind;
26217
26366
  this.bodyElement = bodyElement;
26218
26367
  this.bounds = RangeNodeBoundsDefinition.from(bodyElement.bounds, bind);
26219
26368
  }
26220
- static from(parent, bind, bodyElement, node) {
26369
+ static from(model, parent, bind, bodyElement, node) {
26221
26370
  assertRangeBindDefinition(bind);
26222
- return new this(parent, bind, bodyElement, node);
26371
+ return new this(model, parent, bind, bodyElement, node);
26223
26372
  }
26224
26373
  bounds;
26225
26374
  }
@@ -26355,6 +26504,18 @@ class RootDefinition extends NodeDefinition {
26355
26504
  attributes;
26356
26505
  children;
26357
26506
  isTranslated = false;
26507
+ mapActions(bodyElement) {
26508
+ const source = bodyElement.reference;
26509
+ if (!source) {
26510
+ return;
26511
+ }
26512
+ for (const child of bodyElement.element.children) {
26513
+ if (child.nodeName === "setvalue") {
26514
+ const action = new ActionDefinition(this.model, child, source);
26515
+ this.model.actions.add(action);
26516
+ }
26517
+ }
26518
+ }
26358
26519
  buildSubtree(parent, node) {
26359
26520
  const { form, model } = this;
26360
26521
  const { body } = form;
@@ -26377,6 +26538,9 @@ class RootDefinition extends NodeDefinition {
26377
26538
  const bind = binds.getOrCreateBindDefinition(nodeset);
26378
26539
  const bodyElement = body.getBodyElement(nodeset);
26379
26540
  const [firstChild, ...restChildren] = children;
26541
+ if (bodyElement) {
26542
+ this.mapActions(bodyElement);
26543
+ }
26380
26544
  if (bodyElement?.type === "repeat") {
26381
26545
  return RepeatDefinition.from(model, parent, bind, bodyElement, children);
26382
26546
  }
@@ -26386,9 +26550,9 @@ class RootDefinition extends NodeDefinition {
26386
26550
  const element = firstChild;
26387
26551
  if (element.isLeafElement()) {
26388
26552
  if (bodyElement?.type === "range") {
26389
- return RangeNodeDefinition.from(parent, bind, bodyElement, element);
26553
+ return RangeNodeDefinition.from(model, parent, bind, bodyElement, element);
26390
26554
  }
26391
- return NoteNodeDefinition.from(parent, bind, bodyElement, element) ?? new LeafNodeDefinition(parent, bind, bodyElement, element);
26555
+ return NoteNodeDefinition.from(model, parent, bind, bodyElement, element) ?? new LeafNodeDefinition(model, parent, bind, bodyElement, element);
26392
26556
  }
26393
26557
  return new GroupDefinition(model, parent, bind, bodyElement, element);
26394
26558
  });
@@ -26436,6 +26600,7 @@ class ModelDefinition {
26436
26600
  this.form = form;
26437
26601
  const submission = new SubmissionDefinition(form.xformDOM);
26438
26602
  this.binds = ModelBindMap.fromModel(this);
26603
+ this.actions = ModelActionMap.fromModel(this);
26439
26604
  this.instance = parseStaticDocumentFromDOMSubtree(form.xformDOM.primaryInstanceRoot, {
26440
26605
  nodesetPrefix: "/"
26441
26606
  });
@@ -26443,13 +26608,16 @@ class ModelDefinition {
26443
26608
  this.nodes = nodeDefinitionMap(this.root);
26444
26609
  this.itextTranslations = ItextTranslationsDefinition.from(form.xformDOM);
26445
26610
  this.itextChunks = generateItextChunks(form.xformDOM.itextTranslationElements);
26611
+ this.xformsRevalidateListeners = /* @__PURE__ */ new Map();
26446
26612
  }
26447
26613
  binds;
26614
+ actions;
26448
26615
  root;
26449
26616
  nodes;
26450
26617
  instance;
26451
26618
  itextTranslations;
26452
26619
  itextChunks;
26620
+ xformsRevalidateListeners;
26453
26621
  getNodeDefinition(nodeset) {
26454
26622
  const definition = this.nodes.get(nodeset);
26455
26623
  if (definition == null) {
@@ -26464,14 +26632,20 @@ class ModelDefinition {
26464
26632
  }
26465
26633
  return definition;
26466
26634
  }
26467
- toJSON() {
26468
- const { form, ...rest } = this;
26469
- return rest;
26635
+ registerXformsRevalidateListener(ref, listener) {
26636
+ this.xformsRevalidateListeners.set(ref, listener);
26637
+ }
26638
+ triggerXformsRevalidateListeners() {
26639
+ this.xformsRevalidateListeners.forEach((listener) => listener());
26470
26640
  }
26471
26641
  getTranslationChunks(itextId, activeLanguage) {
26472
26642
  const languageMap = this.itextChunks.get(activeLanguage.language);
26473
26643
  return languageMap?.get(itextId) ?? [];
26474
26644
  }
26645
+ toJSON() {
26646
+ const { form, ...rest } = this;
26647
+ return rest;
26648
+ }
26475
26649
  }
26476
26650
 
26477
26651
  class XFormDefinition {
@@ -27442,6 +27616,7 @@ const resolveEngineXPathNodeNamespaceURI = (node, prefix) => {
27442
27616
  case "static-element":
27443
27617
  case "static-text":
27444
27618
  return resolveNamespaceURIFromStaticNodeContext(node, prefix);
27619
+ case "attribute":
27445
27620
  case "group":
27446
27621
  case "input":
27447
27622
  case "model-value":
@@ -27474,10 +27649,13 @@ class XPathFunctionalityPendingError extends XPathFunctionalityError {
27474
27649
  const getContainingEngineXPathDocument = (node) => {
27475
27650
  return node.rootDocument;
27476
27651
  };
27477
- const getEngineXPathAttributes = (node) => {
27652
+ const getAttributes = (node) => {
27478
27653
  if (node.nodeType === "static-element") {
27479
27654
  return node.attributes;
27480
27655
  }
27656
+ if (isEngineXPathElement(node)) {
27657
+ return node.getAttributes();
27658
+ }
27481
27659
  return [];
27482
27660
  };
27483
27661
  const getNamespaceDeclarations = () => [];
@@ -27634,7 +27812,7 @@ const engineDOMAdapter = {
27634
27812
  getNodeValue: getEngineXPathNodeValue,
27635
27813
  // XPathTraversalAdapter
27636
27814
  compareDocumentOrder,
27637
- getAttributes: getEngineXPathAttributes,
27815
+ getAttributes,
27638
27816
  getChildElements,
27639
27817
  getChildNodes,
27640
27818
  getContainingDocument: getContainingEngineXPathDocument,
@@ -28535,6 +28713,7 @@ const chunkedInstancePayload = (validation, submissionMeta, instanceFile, attach
28535
28713
  };
28536
28714
  };
28537
28715
  const prepareInstancePayload = (instanceRoot, options) => {
28716
+ instanceRoot.root.parent.model.triggerXformsRevalidateListeners();
28538
28717
  const validation = validateInstance(instanceRoot);
28539
28718
  const submissionMeta = instanceRoot.definition.submission;
28540
28719
  const instanceFile = new InstanceFile(instanceRoot);
@@ -28963,17 +29142,21 @@ const createComputedExpression = (context, dependentExpression, options = {}) =>
28963
29142
  });
28964
29143
  };
28965
29144
 
28966
- const isInstanceFirstLoad$1 = (context) => {
29145
+ const REPEAT_INDEX_REGEX = /([^[]*)(\[[0-9]+\])/g;
29146
+ const isInstanceFirstLoad = (context) => {
28967
29147
  return context.rootDocument.initializationMode === "create";
28968
29148
  };
28969
- const isEditInitialLoad$1 = (context) => {
29149
+ const isAddingRepeatChild = (context) => {
29150
+ return context.rootDocument.isAttached();
29151
+ };
29152
+ const isEditInitialLoad = (context) => {
28970
29153
  return context.rootDocument.initializationMode === "edit";
28971
29154
  };
28972
- const getInitialValue$1 = (context) => {
29155
+ const getInitialValue = (context) => {
28973
29156
  const sourceNode = context.instanceNode ?? context.definition.template;
28974
29157
  return context.decodeInstanceValue(sourceNode.value);
28975
29158
  };
28976
- const createRelevantValueState$1 = (context, baseValueState) => {
29159
+ const createRelevantValueState = (context, baseValueState) => {
28977
29160
  return context.scope.runTask(() => {
28978
29161
  const [getRelevantValue, setValue] = baseValueState;
28979
29162
  const getValue = createMemo(() => {
@@ -28985,7 +29168,7 @@ const createRelevantValueState$1 = (context, baseValueState) => {
28985
29168
  return [getValue, setValue];
28986
29169
  });
28987
29170
  };
28988
- const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29171
+ const guardDownstreamReadonlyWrites = (context, baseState) => {
28989
29172
  const { readonly } = context.definition.bind;
28990
29173
  if (readonly.isDefaultExpression) {
28991
29174
  return baseState;
@@ -29000,215 +29183,144 @@ const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29000
29183
  };
29001
29184
  return [getValue, setValue];
29002
29185
  };
29003
- const PRELOAD_UID_EXPRESSION$1 = 'concat("uuid:", uuid())';
29004
- const shouldPreloadUID$1 = (context) => {
29005
- return isInstanceFirstLoad$1(context) || isEditInitialLoad$1(context);
29186
+ const isLoading = (context) => {
29187
+ return isInstanceFirstLoad(context) || isEditInitialLoad(context);
29006
29188
  };
29007
- const setPreloadUIDValue$1 = (context, valueState) => {
29189
+ const setValueIfPreloadDefined = (context, setValue, preload) => {
29190
+ const value = preload.getValue(context);
29191
+ if (value) {
29192
+ setValue(value);
29193
+ }
29194
+ };
29195
+ const postloadValue = (context, setValue, preload) => {
29196
+ const ref = context.contextReference();
29197
+ context.definition.model.registerXformsRevalidateListener(ref, () => {
29198
+ setValueIfPreloadDefined(context, setValue, preload);
29199
+ });
29200
+ };
29201
+ const preloadValue = (context, setValue) => {
29008
29202
  const { preload } = context.definition.bind;
29009
- if (preload?.type !== "uid" || !shouldPreloadUID$1(context)) {
29203
+ if (!preload) {
29010
29204
  return;
29011
29205
  }
29012
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION$1, {
29206
+ if (preload.event === XFORM_EVENT.xformsRevalidate) {
29207
+ postloadValue(context, setValue, preload);
29208
+ return;
29209
+ }
29210
+ if (isLoading(context)) {
29211
+ setValueIfPreloadDefined(context, setValue, preload);
29212
+ }
29213
+ };
29214
+ const referencesCurrentNode = (context, ref) => {
29215
+ const nodes = context.evaluator.evaluateNodes(ref, {
29013
29216
  contextNode: context.contextNode
29014
29217
  });
29015
- const [, setValue] = valueState;
29016
- setValue(preloadUIDValue);
29218
+ if (nodes.length > 1) {
29219
+ throw new Error(
29220
+ "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."
29221
+ );
29222
+ }
29223
+ return nodes.includes(context.contextNode);
29017
29224
  };
29018
- const createCalculation$1 = (context, setRelevantValue, calculateDefinition) => {
29019
- context.scope.runTask(() => {
29020
- const calculate = createComputedExpression(context, calculateDefinition, {
29021
- defaultValue: ""
29022
- });
29023
- createComputed(() => {
29024
- if (context.isAttached() && context.isRelevant()) {
29025
- const calculated = calculate();
29026
- const value = context.decodeInstanceValue(calculated);
29027
- setRelevantValue(value);
29225
+ const bindToRepeatInstance = (context, action) => {
29226
+ let source = action.source;
29227
+ let ref = action.ref;
29228
+ if (source) {
29229
+ const contextRef = context.contextReference();
29230
+ for (const part of contextRef.matchAll(REPEAT_INDEX_REGEX)) {
29231
+ const unbound = part[1] + "/";
29232
+ if (source.includes(unbound)) {
29233
+ const bound = part[0] + "/";
29234
+ source = source.replace(unbound, bound);
29235
+ ref = ref.replace(unbound, bound);
29028
29236
  }
29029
- });
29237
+ }
29238
+ }
29239
+ return { source, ref };
29240
+ };
29241
+ const createCalculation = (context, setRelevantValue, computation) => {
29242
+ const calculate = createComputedExpression(context, computation);
29243
+ createComputed(() => {
29244
+ if (context.isAttached() && context.isRelevant()) {
29245
+ const calculated = calculate();
29246
+ const value = context.decodeInstanceValue(calculated);
29247
+ setRelevantValue(value);
29248
+ }
29030
29249
  });
29031
29250
  };
29032
- const createAttributeValueState = (context) => {
29033
- return context.scope.runTask(() => {
29034
- const initialValue = getInitialValue$1(context);
29035
- const baseValueState = createSignal(initialValue);
29036
- const relevantValueState = createRelevantValueState$1(context, baseValueState);
29037
- setPreloadUIDValue$1(context, relevantValueState);
29038
- const { calculate } = context.definition.bind;
29039
- if (calculate != null) {
29040
- const [, setValue] = relevantValueState;
29041
- createCalculation$1(context, setValue, calculate);
29251
+ const createActionCalculation = (context, setRelevantValue, computation) => {
29252
+ createComputed(() => {
29253
+ if (context.isAttached()) {
29254
+ const relevant = untrack(() => context.isRelevant());
29255
+ if (!relevant) {
29256
+ return;
29257
+ }
29258
+ const calculated = untrack(() => {
29259
+ return context.evaluator.evaluateString(computation.expression, context);
29260
+ });
29261
+ const value = context.decodeInstanceValue(calculated);
29262
+ setRelevantValue(value);
29042
29263
  }
29043
- return guardDownstreamReadonlyWrites$1(context, relevantValueState);
29044
29264
  });
29045
29265
  };
29046
-
29047
- class Attribute extends InstanceNode {
29048
- constructor(parent, definition, instanceNode) {
29049
- const codec = getSharedValueCodec("string");
29050
- super(parent.instanceConfig, parent, instanceNode, definition, {
29051
- scope: parent.scope,
29052
- computeReference: () => "@" + this.definition.qualifiedName.getPrefixedName()
29053
- });
29054
- this.instanceNode = instanceNode;
29055
- this.root = parent.root;
29056
- this.getActiveLanguage = parent.getActiveLanguage;
29057
- this.validationState = { violations: [] };
29058
- this.valueType = "string";
29059
- this.evaluator = parent.evaluator;
29060
- this.decodeInstanceValue = codec.decodeInstanceValue;
29061
- const instanceValueState = createAttributeValueState(this);
29062
- const valueState = codec.createRuntimeValueState(instanceValueState);
29063
- const [getInstanceValue] = instanceValueState;
29064
- const [, setValueState] = valueState;
29065
- this.getInstanceValue = getInstanceValue;
29066
- this.setValueState = setValueState;
29067
- this.getXPathValue = () => {
29068
- return this.getInstanceValue();
29069
- };
29070
- this.valueState = valueState;
29071
- const state = createSharedNodeState(
29072
- this.scope,
29073
- {
29074
- reference: this.contextReference,
29075
- readonly: this.isReadonly,
29076
- relevant: this.isRelevant,
29077
- required: () => false,
29078
- label: null,
29079
- hint: null,
29080
- children: null,
29081
- valueOptions: null,
29082
- value: this.valueState,
29083
- instanceValue: this.getInstanceValue,
29084
- attributes: null
29085
- },
29086
- this.instanceConfig
29087
- );
29088
- this.state = state;
29089
- this.engineState = state.engineState;
29090
- this.currentState = state.currentState;
29091
- this.instanceState = createAttributeNodeInstanceState(this);
29092
- }
29093
- [XPathNodeKindKey] = "attribute";
29094
- state;
29095
- engineState;
29096
- validationState;
29097
- nodeType = "attribute";
29098
- currentState;
29099
- instanceState;
29100
- appearances = null;
29101
- nodeOptions = null;
29102
- valueType;
29103
- decodeInstanceValue;
29104
- getInstanceValue;
29105
- valueState;
29106
- setValueState;
29107
- evaluator;
29108
- getActiveLanguage;
29109
- root;
29110
- isRelevant = () => {
29111
- return this.parent.isRelevant();
29112
- };
29113
- isAttached = () => {
29114
- return this.parent.isAttached();
29115
- };
29116
- isReadonly = () => {
29117
- return true;
29118
- };
29119
- hasReadonlyAncestor = () => {
29120
- const { parent } = this;
29121
- return parent.hasReadonlyAncestor() || parent.isReadonly();
29122
- };
29123
- hasNonRelevantAncestor = () => {
29124
- const { parent } = this;
29125
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29126
- };
29127
- setValue(value) {
29128
- this.setValueState(value);
29129
- return this.root;
29130
- }
29131
- getChildren() {
29132
- return [];
29266
+ const createValueChangedCalculation = (context, setRelevantValue, action) => {
29267
+ const { source, ref } = bindToRepeatInstance(context, action);
29268
+ if (!source) {
29269
+ return;
29133
29270
  }
29134
- }
29135
-
29136
- function buildAttributes(parent) {
29137
- return Array.from(parent.definition.attributes.values()).map((attributeDefinition) => {
29138
- return new Attribute(parent, attributeDefinition, attributeDefinition.template);
29271
+ let previous = "";
29272
+ const sourceElementExpression = new ActionComputationExpression("string", source);
29273
+ const calculateValueSource = createComputedExpression(context, sourceElementExpression);
29274
+ createComputed(() => {
29275
+ if (context.isAttached() && context.isRelevant()) {
29276
+ const valueSource = calculateValueSource();
29277
+ if (previous !== valueSource) {
29278
+ if (referencesCurrentNode(context, ref)) {
29279
+ const calc = context.evaluator.evaluateString(action.computation.expression, context);
29280
+ const value = context.decodeInstanceValue(calc);
29281
+ setRelevantValue(value);
29282
+ }
29283
+ }
29284
+ previous = valueSource;
29285
+ }
29139
29286
  });
29140
- }
29141
-
29142
- class InstanceAttachmentsState extends Map {
29143
- constructor(sourceAttachments = null) {
29144
- super();
29145
- this.sourceAttachments = sourceAttachments;
29287
+ };
29288
+ const registerAction = (context, setValue, action) => {
29289
+ if (action.events.includes(XFORM_EVENT.odkInstanceFirstLoad)) {
29290
+ if (isInstanceFirstLoad(context)) {
29291
+ createActionCalculation(context, setValue, action.computation);
29292
+ }
29146
29293
  }
29147
- getInitialFileValue(instanceNode) {
29148
- if (instanceNode == null) {
29149
- return null;
29294
+ if (action.events.includes(XFORM_EVENT.odkInstanceLoad)) {
29295
+ if (!isAddingRepeatChild(context)) {
29296
+ createActionCalculation(context, setValue, action.computation);
29150
29297
  }
29151
- return this.sourceAttachments?.get(instanceNode.value) ?? null;
29152
29298
  }
29153
- }
29154
-
29155
- const createRootInstanceState = (node) => {
29156
- return {
29157
- get instanceXML() {
29158
- return serializeParentElementXML(
29159
- node.definition.qualifiedName,
29160
- node.currentState.children,
29161
- node.currentState.attributes,
29162
- node.definition.namespaceDeclarations
29163
- );
29299
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
29300
+ if (isAddingRepeatChild(context)) {
29301
+ createActionCalculation(context, setValue, action.computation);
29164
29302
  }
29165
- };
29166
- };
29167
-
29168
- const violationReference = (node) => {
29169
- const violation = node.getViolation();
29170
- if (violation == null) {
29171
- return null;
29172
29303
  }
29173
- const { nodeId } = node;
29174
- return {
29175
- nodeId,
29176
- get reference() {
29177
- return node.currentState.reference;
29178
- },
29179
- violation
29180
- };
29304
+ if (action.events.includes(XFORM_EVENT.xformsValueChanged)) {
29305
+ createValueChangedCalculation(context, setValue, action);
29306
+ }
29181
29307
  };
29182
- const collectViolationReferences = (context) => {
29183
- return context.getChildren().flatMap((child) => {
29184
- switch (child.nodeType) {
29185
- case "model-value":
29186
- case "input":
29187
- case "note":
29188
- case "select":
29189
- case "range":
29190
- case "rank":
29191
- case "trigger":
29192
- case "upload": {
29193
- const reference = violationReference(child);
29194
- if (reference == null) {
29195
- return [];
29196
- }
29197
- return [reference];
29198
- }
29199
- default:
29200
- return collectViolationReferences(child);
29308
+ const createInstanceValueState = (context) => {
29309
+ return context.scope.runTask(() => {
29310
+ const initialValue = getInitialValue(context);
29311
+ const baseValueState = createSignal(initialValue);
29312
+ const relevantValueState = createRelevantValueState(context, baseValueState);
29313
+ const [, setValue] = relevantValueState;
29314
+ preloadValue(context, setValue);
29315
+ const { calculate } = context.definition.bind;
29316
+ if (calculate != null) {
29317
+ createCalculation(context, setValue, calculate);
29201
29318
  }
29202
- });
29203
- };
29204
- const createAggregatedViolations = (context, options) => {
29205
- const { scope } = context;
29206
- return scope.runTask(() => {
29207
- const violations = createMemo(() => {
29208
- return collectViolationReferences(context);
29209
- });
29210
- const spec = { violations };
29211
- return createSharedNodeState(scope, spec, options).currentState;
29319
+ const action = context.definition.model.actions.get(context.contextReference());
29320
+ if (action) {
29321
+ registerAction(context, setValue, action);
29322
+ }
29323
+ return guardDownstreamReadonlyWrites(context, relevantValueState);
29212
29324
  });
29213
29325
  };
29214
29326
 
@@ -29239,11 +29351,6 @@ class DescendantNode extends InstanceNode {
29239
29351
  return true;
29240
29352
  }
29241
29353
  }
29242
- for (const attr of parent.getAttributes()) {
29243
- if (attr === self) {
29244
- return true;
29245
- }
29246
- }
29247
29354
  return false;
29248
29355
  });
29249
29356
  });
@@ -29279,75 +29386,234 @@ class DescendantNode extends InstanceNode {
29279
29386
  if (this.hasReadonlyAncestor()) {
29280
29387
  return true;
29281
29388
  }
29282
- return this.isSelfReadonly();
29389
+ return this.isSelfReadonly();
29390
+ };
29391
+ hasNonRelevantAncestor = () => {
29392
+ const { parent } = this;
29393
+ return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29394
+ };
29395
+ isSelfRelevant;
29396
+ isRelevant = () => {
29397
+ if (this.hasNonRelevantAncestor()) {
29398
+ return false;
29399
+ }
29400
+ return this.isSelfRelevant();
29401
+ };
29402
+ isRequired;
29403
+ // XFormsXPathPrimaryInstanceDescendantNode
29404
+ /**
29405
+ * WARNING! Ideally, this would be an abstract property, defined by each
29406
+ * concrete subclass (or other intermediate abstract classes, where
29407
+ * appropriate). Unfortunately it must be assigned here, so it will be present
29408
+ * for certain XPath DOM adapter functionality **during** each concrete node's
29409
+ * construction.
29410
+ *
29411
+ * Those subclasses nevertheless override this same property, assigning the
29412
+ * same value, for the purposes of narrowing the XPath node kind semantics
29413
+ * appropriate for each node type.
29414
+ */
29415
+ [XPathNodeKindKey];
29416
+ root;
29417
+ // EvaluationContext
29418
+ isAttached;
29419
+ evaluator;
29420
+ contextNode = this;
29421
+ getActiveLanguage;
29422
+ /**
29423
+ * @package
29424
+ *
29425
+ * Performs recursive removal, first of the node's descendants, then of the
29426
+ * node itself. For all {@link DescendantNode}s, removal involves **at least**
29427
+ * disposal of its {@link scope} ({@link ReactiveScope}).
29428
+ *
29429
+ * It is expected that the outermost node targeted for removal will always be
29430
+ * a {@link RepeatInstance}. @see {@link RepeatInstance.remove} for additional
29431
+ * details.
29432
+ *
29433
+ * It is also expected that upon that outermost node's removal, its parent
29434
+ * {@link RepeatRange} will perform a reactive update to its children state so
29435
+ * that:
29436
+ *
29437
+ * 1. Any downstream computations affected by the removal are updated.
29438
+ * 2. The client invoking removal is also reactively updated (where
29439
+ * applicable).
29440
+ *
29441
+ * @see {@link RepeatInstance.remove} and {@link RepeatRange.removeInstances}
29442
+ * for additional details about their respective node-specific removal
29443
+ * behaviors and ordering.
29444
+ *
29445
+ * @todo Possibly retain removed repeat instances in memory. This came up as a
29446
+ * behavior of Collect/JavaRosa, and we should investigate the details and
29447
+ * ramifications of that, and whether it's the desired behavior.
29448
+ */
29449
+ remove() {
29450
+ this.scope.runTask(() => {
29451
+ this.getChildren().forEach((child) => {
29452
+ child.remove();
29453
+ });
29454
+ });
29455
+ this.scope.dispose();
29456
+ }
29457
+ }
29458
+
29459
+ class Attribute extends DescendantNode {
29460
+ constructor(owner, definition, instanceNode) {
29461
+ const computeReference = () => {
29462
+ return `${this.owner.contextReference()}/@${this.definition.qualifiedName.getPrefixedName()}`;
29463
+ };
29464
+ super(owner, instanceNode, definition, { computeReference });
29465
+ this.owner = owner;
29466
+ this.instanceNode = instanceNode;
29467
+ const codec = getSharedValueCodec("string");
29468
+ this.validationState = { violations: [] };
29469
+ this.valueType = "string";
29470
+ this.decodeInstanceValue = codec.decodeInstanceValue;
29471
+ const instanceValueState = createInstanceValueState(this);
29472
+ const valueState = codec.createRuntimeValueState(instanceValueState);
29473
+ const [getInstanceValue] = instanceValueState;
29474
+ const [, setValueState] = valueState;
29475
+ this.getInstanceValue = getInstanceValue;
29476
+ this.setValueState = setValueState;
29477
+ this.valueState = valueState;
29478
+ const state = createSharedNodeState(
29479
+ owner.scope,
29480
+ {
29481
+ value: this.valueState,
29482
+ instanceValue: this.getInstanceValue,
29483
+ relevant: this.owner.isRelevant,
29484
+ readonly: () => true,
29485
+ reference: this.contextReference,
29486
+ required: () => false,
29487
+ children: null,
29488
+ label: () => null,
29489
+ hint: () => null,
29490
+ attributes: () => [],
29491
+ valueOptions: () => []
29492
+ },
29493
+ this.instanceConfig
29494
+ );
29495
+ this.state = state;
29496
+ this.engineState = state.engineState;
29497
+ this.currentState = state.currentState;
29498
+ this.instanceState = createAttributeNodeInstanceState(this);
29499
+ this.attributeState = createAttributeState(this.scope);
29500
+ this.getXPathValue = () => {
29501
+ return this.getInstanceValue();
29502
+ };
29503
+ }
29504
+ [XPathNodeKindKey] = "attribute";
29505
+ state;
29506
+ engineState;
29507
+ validationState;
29508
+ nodeType = "attribute";
29509
+ currentState;
29510
+ instanceState;
29511
+ appearances = null;
29512
+ nodeOptions = null;
29513
+ valueType;
29514
+ decodeInstanceValue;
29515
+ getInstanceValue;
29516
+ valueState;
29517
+ setValueState;
29518
+ attributeState;
29519
+ isAttached = () => {
29520
+ return this.owner.isAttached();
29521
+ };
29522
+ getXPathValue;
29523
+ setValue(value) {
29524
+ this.setValueState(value);
29525
+ return this.root;
29526
+ }
29527
+ getAttributes() {
29528
+ return [];
29529
+ }
29530
+ getChildren() {
29531
+ return [];
29532
+ }
29533
+ }
29534
+
29535
+ function buildAttributes(owner) {
29536
+ const attributes = owner.definition.attributes;
29537
+ if (!attributes) {
29538
+ return [];
29539
+ }
29540
+ return Array.from(attributes.values()).map((attributeDefinition) => {
29541
+ return new Attribute(owner, attributeDefinition, attributeDefinition.template);
29542
+ });
29543
+ }
29544
+
29545
+ class InstanceAttachmentsState extends Map {
29546
+ constructor(sourceAttachments = null) {
29547
+ super();
29548
+ this.sourceAttachments = sourceAttachments;
29549
+ }
29550
+ getInitialFileValue(instanceNode) {
29551
+ if (instanceNode == null) {
29552
+ return null;
29553
+ }
29554
+ return this.sourceAttachments?.get(instanceNode.value) ?? null;
29555
+ }
29556
+ }
29557
+
29558
+ const createRootInstanceState = (node) => {
29559
+ return {
29560
+ get instanceXML() {
29561
+ return serializeParentElementXML(
29562
+ node.definition.qualifiedName,
29563
+ node.currentState.children,
29564
+ node.currentState.attributes,
29565
+ node.definition.namespaceDeclarations
29566
+ );
29567
+ }
29283
29568
  };
29284
- hasNonRelevantAncestor = () => {
29285
- const { parent } = this;
29286
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29569
+ };
29570
+
29571
+ const violationReference = (node) => {
29572
+ const violation = node.getViolation();
29573
+ if (violation == null) {
29574
+ return null;
29575
+ }
29576
+ const { nodeId } = node;
29577
+ return {
29578
+ nodeId,
29579
+ get reference() {
29580
+ return node.currentState.reference;
29581
+ },
29582
+ violation
29287
29583
  };
29288
- isSelfRelevant;
29289
- isRelevant = () => {
29290
- if (this.hasNonRelevantAncestor()) {
29291
- return false;
29584
+ };
29585
+ const collectViolationReferences = (context) => {
29586
+ return context.getChildren().flatMap((child) => {
29587
+ switch (child.nodeType) {
29588
+ case "model-value":
29589
+ case "input":
29590
+ case "note":
29591
+ case "select":
29592
+ case "range":
29593
+ case "rank":
29594
+ case "trigger":
29595
+ case "upload": {
29596
+ const reference = violationReference(child);
29597
+ if (reference == null) {
29598
+ return [];
29599
+ }
29600
+ return [reference];
29601
+ }
29602
+ default:
29603
+ return collectViolationReferences(child);
29292
29604
  }
29293
- return this.isSelfRelevant();
29294
- };
29295
- isRequired;
29296
- // XFormsXPathPrimaryInstanceDescendantNode
29297
- /**
29298
- * WARNING! Ideally, this would be an abstract property, defined by each
29299
- * concrete subclass (or other intermediate abstract classes, where
29300
- * appropriate). Unfortunately it must be assigned here, so it will be present
29301
- * for certain XPath DOM adapter functionality **during** each concrete node's
29302
- * construction.
29303
- *
29304
- * Those subclasses nevertheless override this same property, assigning the
29305
- * same value, for the purposes of narrowing the XPath node kind semantics
29306
- * appropriate for each node type.
29307
- */
29308
- [XPathNodeKindKey];
29309
- root;
29310
- // EvaluationContext
29311
- isAttached;
29312
- evaluator;
29313
- contextNode = this;
29314
- getActiveLanguage;
29315
- /**
29316
- * @package
29317
- *
29318
- * Performs recursive removal, first of the node's descendants, then of the
29319
- * node itself. For all {@link DescendantNode}s, removal involves **at least**
29320
- * disposal of its {@link scope} ({@link ReactiveScope}).
29321
- *
29322
- * It is expected that the outermost node targeted for removal will always be
29323
- * a {@link RepeatInstance}. @see {@link RepeatInstance.remove} for additional
29324
- * details.
29325
- *
29326
- * It is also expected that upon that outermost node's removal, its parent
29327
- * {@link RepeatRange} will perform a reactive update to its children state so
29328
- * that:
29329
- *
29330
- * 1. Any downstream computations affected by the removal are updated.
29331
- * 2. The client invoking removal is also reactively updated (where
29332
- * applicable).
29333
- *
29334
- * @see {@link RepeatInstance.remove} and {@link RepeatRange.removeInstances}
29335
- * for additional details about their respective node-specific removal
29336
- * behaviors and ordering.
29337
- *
29338
- * @todo Possibly retain removed repeat instances in memory. This came up as a
29339
- * behavior of Collect/JavaRosa, and we should investigate the details and
29340
- * ramifications of that, and whether it's the desired behavior.
29341
- */
29342
- remove() {
29343
- this.scope.runTask(() => {
29344
- this.getChildren().forEach((child) => {
29345
- child.remove();
29346
- });
29605
+ });
29606
+ };
29607
+ const createAggregatedViolations = (context, options) => {
29608
+ const { scope } = context;
29609
+ return scope.runTask(() => {
29610
+ const violations = createMemo(() => {
29611
+ return collectViolationReferences(context);
29347
29612
  });
29348
- this.scope.dispose();
29349
- }
29350
- }
29613
+ const spec = { violations };
29614
+ return createSharedNodeState(scope, spec, options).currentState;
29615
+ });
29616
+ };
29351
29617
 
29352
29618
  const createParentNodeInstanceState = (node) => {
29353
29619
  return {
@@ -39633,11 +39899,11 @@ const createNodeLabel = (context, definition) => {
39633
39899
 
39634
39900
  class Group extends DescendantNode {
39635
39901
  childrenState;
39636
- attributeState;
39637
39902
  [XPathNodeKindKey] = "element";
39638
39903
  // InstanceNode
39639
39904
  state;
39640
39905
  engineState;
39906
+ attributeState;
39641
39907
  // GroupNode
39642
39908
  nodeType = "group";
39643
39909
  appearances;
@@ -39649,9 +39915,8 @@ class Group extends DescendantNode {
39649
39915
  super(parent, instanceNode, definition);
39650
39916
  this.appearances = definition.bodyElement?.appearances ?? null;
39651
39917
  const childrenState = createChildrenState(this);
39652
- const attributeState = createAttributeState(this.scope);
39918
+ this.attributeState = createAttributeState(this.scope);
39653
39919
  this.childrenState = childrenState;
39654
- this.attributeState = attributeState;
39655
39920
  const state = createSharedNodeState(
39656
39921
  this.scope,
39657
39922
  {
@@ -39662,7 +39927,7 @@ class Group extends DescendantNode {
39662
39927
  label: createNodeLabel(this, definition),
39663
39928
  hint: null,
39664
39929
  children: childrenState.childIds,
39665
- attributes: attributeState.getAttributes,
39930
+ attributes: this.attributeState.getAttributes,
39666
39931
  valueOptions: null,
39667
39932
  value: null
39668
39933
  },
@@ -39676,7 +39941,7 @@ class Group extends DescendantNode {
39676
39941
  childrenState
39677
39942
  );
39678
39943
  childrenState.setChildren(buildChildren(this));
39679
- attributeState.setAttributes(buildAttributes(this));
39944
+ this.attributeState.setAttributes(buildAttributes(this));
39680
39945
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
39681
39946
  this.instanceState = createParentNodeInstanceState(this);
39682
39947
  }
@@ -39704,90 +39969,10 @@ const createValueNodeInstanceState = (node) => {
39704
39969
  return "";
39705
39970
  }
39706
39971
  const xmlValue = escapeXMLText(node.currentState.instanceValue);
39707
- return serializeLeafElementXML(qualifiedName, xmlValue);
39708
- }
39709
- };
39710
- };
39711
-
39712
- const isInstanceFirstLoad = (context) => {
39713
- return context.rootDocument.initializationMode === "create";
39714
- };
39715
- const isEditInitialLoad = (context) => {
39716
- return context.rootDocument.initializationMode === "edit";
39717
- };
39718
- const getInitialValue = (context) => {
39719
- const sourceNode = context.instanceNode ?? context.definition.template;
39720
- return context.decodeInstanceValue(sourceNode.value);
39721
- };
39722
- const createRelevantValueState = (context, baseValueState) => {
39723
- return context.scope.runTask(() => {
39724
- const [getRelevantValue, setValue] = baseValueState;
39725
- const getValue = createMemo(() => {
39726
- if (context.isRelevant()) {
39727
- return getRelevantValue();
39728
- }
39729
- return "";
39730
- });
39731
- return [getValue, setValue];
39732
- });
39733
- };
39734
- const guardDownstreamReadonlyWrites = (context, baseState) => {
39735
- const { readonly } = context.definition.bind;
39736
- if (readonly.isDefaultExpression) {
39737
- return baseState;
39738
- }
39739
- const [getValue, baseSetValue] = baseState;
39740
- const setValue = (value) => {
39741
- if (context.isReadonly()) {
39742
- const reference = untrack(() => context.contextReference());
39743
- throw new Error(`Cannot write to readonly field: ${reference}`);
39972
+ const attributes = node.currentState.attributes;
39973
+ return serializeLeafElementXML(qualifiedName, xmlValue, attributes);
39744
39974
  }
39745
- return baseSetValue(value);
39746
39975
  };
39747
- return [getValue, setValue];
39748
- };
39749
- const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
39750
- const shouldPreloadUID = (context) => {
39751
- return isInstanceFirstLoad(context) || isEditInitialLoad(context);
39752
- };
39753
- const setPreloadUIDValue = (context, valueState) => {
39754
- const { preload } = context.definition.bind;
39755
- if (preload?.type !== "uid" || !shouldPreloadUID(context)) {
39756
- return;
39757
- }
39758
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION, {
39759
- contextNode: context.contextNode
39760
- });
39761
- const [, setValue] = valueState;
39762
- setValue(preloadUIDValue);
39763
- };
39764
- const createCalculation = (context, setRelevantValue, calculateDefinition) => {
39765
- context.scope.runTask(() => {
39766
- const calculate = createComputedExpression(context, calculateDefinition, {
39767
- defaultValue: ""
39768
- });
39769
- createComputed(() => {
39770
- if (context.isAttached() && context.isRelevant()) {
39771
- const calculated = calculate();
39772
- const value = context.decodeInstanceValue(calculated);
39773
- setRelevantValue(value);
39774
- }
39775
- });
39776
- });
39777
- };
39778
- const createInstanceValueState = (context) => {
39779
- return context.scope.runTask(() => {
39780
- const initialValue = getInitialValue(context);
39781
- const baseValueState = createSignal(initialValue);
39782
- const relevantValueState = createRelevantValueState(context, baseValueState);
39783
- setPreloadUIDValue(context, relevantValueState);
39784
- const { calculate } = context.definition.bind;
39785
- if (calculate != null) {
39786
- const [, setValue] = relevantValueState;
39787
- createCalculation(context, setValue, calculate);
39788
- }
39789
- return guardDownstreamReadonlyWrites(context, relevantValueState);
39790
- });
39791
39976
  };
39792
39977
 
39793
39978
  const engineViolationMessage = (context, role) => {
@@ -39969,6 +40154,7 @@ class InputControl extends ValueNode {
39969
40154
  // InstanceNode
39970
40155
  state;
39971
40156
  engineState;
40157
+ attributeState;
39972
40158
  // InputNode
39973
40159
  nodeType = "input";
39974
40160
  appearances;
@@ -39979,6 +40165,7 @@ class InputControl extends ValueNode {
39979
40165
  super(parent, instanceNode, definition, codec);
39980
40166
  this.appearances = definition.bodyElement.appearances;
39981
40167
  this.nodeOptions = nodeOptionsFactoryByType[definition.valueType](definition.bodyElement);
40168
+ this.attributeState = createAttributeState(this.scope);
39982
40169
  const state = createSharedNodeState(
39983
40170
  this.scope,
39984
40171
  {
@@ -39989,13 +40176,14 @@ class InputControl extends ValueNode {
39989
40176
  label: createNodeLabel(this, definition),
39990
40177
  hint: createFieldHint(this, definition),
39991
40178
  children: null,
39992
- attributes: null,
40179
+ attributes: this.attributeState.getAttributes,
39993
40180
  valueOptions: null,
39994
40181
  value: this.valueState,
39995
40182
  instanceValue: this.getInstanceValue
39996
40183
  },
39997
40184
  this.instanceConfig
39998
40185
  );
40186
+ this.attributeState.setAttributes(buildAttributes(this));
39999
40187
  this.state = state;
40000
40188
  this.engineState = state.engineState;
40001
40189
  this.currentState = state.currentState;
@@ -40004,6 +40192,9 @@ class InputControl extends ValueNode {
40004
40192
  this.setValueState(value);
40005
40193
  return this.root;
40006
40194
  }
40195
+ getAttributes() {
40196
+ return this.attributeState.getAttributes();
40197
+ }
40007
40198
  }
40008
40199
 
40009
40200
  class ModelValue extends ValueNode {
@@ -40015,6 +40206,7 @@ class ModelValue extends ValueNode {
40015
40206
  // InstanceNode
40016
40207
  state;
40017
40208
  engineState;
40209
+ attributeState;
40018
40210
  // ModelValueNode
40019
40211
  nodeType = "model-value";
40020
40212
  appearances = null;
@@ -40023,6 +40215,7 @@ class ModelValue extends ValueNode {
40023
40215
  constructor(parent, instanceNode, definition) {
40024
40216
  const codec = getSharedValueCodec(definition.valueType);
40025
40217
  super(parent, instanceNode, definition, codec);
40218
+ this.attributeState = createAttributeState(this.scope);
40026
40219
  const state = createSharedNodeState(
40027
40220
  this.scope,
40028
40221
  {
@@ -40033,17 +40226,21 @@ class ModelValue extends ValueNode {
40033
40226
  label: null,
40034
40227
  hint: null,
40035
40228
  children: null,
40036
- attributes: null,
40229
+ attributes: this.attributeState.getAttributes,
40037
40230
  valueOptions: null,
40038
40231
  value: this.valueState,
40039
40232
  instanceValue: this.getInstanceValue
40040
40233
  },
40041
40234
  this.instanceConfig
40042
40235
  );
40236
+ this.attributeState.setAttributes(buildAttributes(this));
40043
40237
  this.state = state;
40044
40238
  this.engineState = state.engineState;
40045
40239
  this.currentState = state.currentState;
40046
40240
  }
40241
+ getAttributes() {
40242
+ return this.attributeState.getAttributes();
40243
+ }
40047
40244
  }
40048
40245
 
40049
40246
  class NoteCodec extends ValueCodec {
@@ -40120,6 +40317,7 @@ class Note extends ValueNode {
40120
40317
  // InstanceNode
40121
40318
  state;
40122
40319
  engineState;
40320
+ attributeState;
40123
40321
  // NoteNode
40124
40322
  nodeType = "note";
40125
40323
  appearances;
@@ -40131,6 +40329,7 @@ class Note extends ValueNode {
40131
40329
  this.appearances = definition.bodyElement.appearances;
40132
40330
  const isReadonly = createNoteReadonlyThunk(this, definition);
40133
40331
  const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
40332
+ this.attributeState = createAttributeState(this.scope);
40134
40333
  let noteText;
40135
40334
  let label;
40136
40335
  let hint;
@@ -40161,17 +40360,21 @@ class Note extends ValueNode {
40161
40360
  hint,
40162
40361
  noteText,
40163
40362
  children: null,
40164
- attributes: null,
40363
+ attributes: this.attributeState.getAttributes,
40165
40364
  valueOptions: null,
40166
40365
  value: this.valueState,
40167
40366
  instanceValue: this.getInstanceValue
40168
40367
  },
40169
40368
  this.instanceConfig
40170
40369
  );
40370
+ this.attributeState.setAttributes(buildAttributes(this));
40171
40371
  this.state = state;
40172
40372
  this.engineState = state.engineState;
40173
40373
  this.currentState = state.currentState;
40174
40374
  }
40375
+ getAttributes() {
40376
+ return this.attributeState.getAttributes();
40377
+ }
40175
40378
  }
40176
40379
 
40177
40380
  class RangeCodec extends ValueCodec {
@@ -40221,6 +40424,7 @@ class RangeControl extends ValueNode {
40221
40424
  // InstanceNode
40222
40425
  state;
40223
40426
  engineState;
40427
+ attributeState;
40224
40428
  // RangeNode
40225
40429
  nodeType = "range";
40226
40430
  appearances;
@@ -40231,6 +40435,7 @@ class RangeControl extends ValueNode {
40231
40435
  const codec = new RangeCodec(baseCodec, definition);
40232
40436
  super(parent, instanceNode, definition, codec);
40233
40437
  this.appearances = definition.bodyElement.appearances;
40438
+ this.attributeState = createAttributeState(this.scope);
40234
40439
  const state = createSharedNodeState(
40235
40440
  this.scope,
40236
40441
  {
@@ -40241,13 +40446,14 @@ class RangeControl extends ValueNode {
40241
40446
  label: createNodeLabel(this, definition),
40242
40447
  hint: createFieldHint(this, definition),
40243
40448
  children: null,
40244
- attributes: null,
40449
+ attributes: this.attributeState.getAttributes,
40245
40450
  valueOptions: null,
40246
40451
  value: this.valueState,
40247
40452
  instanceValue: this.getInstanceValue
40248
40453
  },
40249
40454
  this.instanceConfig
40250
40455
  );
40456
+ this.attributeState.setAttributes(buildAttributes(this));
40251
40457
  this.state = state;
40252
40458
  this.engineState = state.engineState;
40253
40459
  this.currentState = state.currentState;
@@ -40256,6 +40462,9 @@ class RangeControl extends ValueNode {
40256
40462
  this.setValueState(value);
40257
40463
  return this.root;
40258
40464
  }
40465
+ getAttributes() {
40466
+ return this.attributeState.getAttributes();
40467
+ }
40259
40468
  }
40260
40469
 
40261
40470
  class RankMissingValueError extends Error {
@@ -40447,6 +40656,7 @@ class RankControl extends ValueNode {
40447
40656
  // InstanceNode
40448
40657
  state;
40449
40658
  engineState;
40659
+ attributeState;
40450
40660
  // RankNode
40451
40661
  nodeType = "rank";
40452
40662
  appearances;
@@ -40465,6 +40675,7 @@ class RankControl extends ValueNode {
40465
40675
  this.mapOptionsByValue = mapOptionsByValue;
40466
40676
  const baseValueState = this.valueState;
40467
40677
  const [baseGetValue, setValue] = baseValueState;
40678
+ this.attributeState = createAttributeState(this.scope);
40468
40679
  const getValue = this.scope.runTask(() => {
40469
40680
  return createMemo(() => {
40470
40681
  const options = valueOptions();
@@ -40499,17 +40710,21 @@ class RankControl extends ValueNode {
40499
40710
  label: createNodeLabel(this, definition),
40500
40711
  hint: createFieldHint(this, definition),
40501
40712
  children: null,
40502
- attributes: null,
40713
+ attributes: this.attributeState.getAttributes,
40503
40714
  valueOptions,
40504
40715
  value: valueState,
40505
40716
  instanceValue: this.getInstanceValue
40506
40717
  },
40507
40718
  this.instanceConfig
40508
40719
  );
40720
+ this.attributeState.setAttributes(buildAttributes(this));
40509
40721
  this.state = state;
40510
40722
  this.engineState = state.engineState;
40511
40723
  this.currentState = state.currentState;
40512
40724
  }
40725
+ getAttributes() {
40726
+ return this.attributeState.getAttributes();
40727
+ }
40513
40728
  getValueLabel(value) {
40514
40729
  const valueOption = this.currentState.valueOptions.find((item) => item.value === value);
40515
40730
  return valueOption?.label ?? null;
@@ -40592,9 +40807,8 @@ class RepeatInstance extends DescendantNode {
40592
40807
  this.parent = parent;
40593
40808
  this.appearances = definition.bodyElement.appearances;
40594
40809
  const childrenState = createChildrenState(this);
40595
- const attributeState = createAttributeState(this.scope);
40810
+ this.attributeState = createAttributeState(this.scope);
40596
40811
  this.childrenState = childrenState;
40597
- this.attributeState = attributeState;
40598
40812
  this.currentIndex = currentIndex;
40599
40813
  const state = createSharedNodeState(
40600
40814
  this.scope,
@@ -40606,7 +40820,7 @@ class RepeatInstance extends DescendantNode {
40606
40820
  // TODO: only-child <group><label>
40607
40821
  label: createNodeLabel(this, definition),
40608
40822
  hint: null,
40609
- attributes: attributeState.getAttributes,
40823
+ attributes: this.attributeState.getAttributes,
40610
40824
  children: childrenState.childIds,
40611
40825
  valueOptions: null,
40612
40826
  value: null
@@ -40991,6 +41205,7 @@ class SelectControl extends ValueNode {
40991
41205
  // InstanceNode
40992
41206
  state;
40993
41207
  engineState;
41208
+ attributeState;
40994
41209
  // SelectNode
40995
41210
  nodeType = "select";
40996
41211
  selectType;
@@ -41002,6 +41217,7 @@ class SelectControl extends ValueNode {
41002
41217
  super(parent, instanceNode, definition, codec);
41003
41218
  this.appearances = definition.bodyElement.appearances;
41004
41219
  this.selectType = definition.bodyElement.type;
41220
+ this.attributeState = createAttributeState(this.scope);
41005
41221
  const valueOptions = createItemCollection(this);
41006
41222
  const isSelectWithImages = this.scope.runTask(() => {
41007
41223
  return createMemo(() => valueOptions().some((item) => !!item.label.imageSource));
@@ -41038,7 +41254,7 @@ class SelectControl extends ValueNode {
41038
41254
  label: createNodeLabel(this, definition),
41039
41255
  hint: createFieldHint(this, definition),
41040
41256
  children: null,
41041
- attributes: null,
41257
+ attributes: this.attributeState.getAttributes,
41042
41258
  valueOptions,
41043
41259
  value: valueState,
41044
41260
  instanceValue: this.getInstanceValue,
@@ -41046,6 +41262,7 @@ class SelectControl extends ValueNode {
41046
41262
  },
41047
41263
  this.instanceConfig
41048
41264
  );
41265
+ this.attributeState.setAttributes(buildAttributes(this));
41049
41266
  this.state = state;
41050
41267
  this.engineState = state.engineState;
41051
41268
  this.currentState = state.currentState;
@@ -41104,6 +41321,9 @@ class SelectControl extends ValueNode {
41104
41321
  const option = this.mapOptionsByValue().get(value);
41105
41322
  return option?.label?.asString ?? null;
41106
41323
  }
41324
+ getAttributes() {
41325
+ return this.attributeState.getAttributes();
41326
+ }
41107
41327
  }
41108
41328
 
41109
41329
  const TRIGGER_INSTANCE_VALUES = {
@@ -41156,6 +41376,7 @@ class TriggerControl extends ValueNode {
41156
41376
  // InstanceNode
41157
41377
  state;
41158
41378
  engineState;
41379
+ attributeState;
41159
41380
  // TriggerNode
41160
41381
  nodeType = "trigger";
41161
41382
  appearances;
@@ -41164,6 +41385,7 @@ class TriggerControl extends ValueNode {
41164
41385
  constructor(parent, instanceNode, definition) {
41165
41386
  super(parent, instanceNode, definition, codec);
41166
41387
  this.appearances = definition.bodyElement.appearances;
41388
+ this.attributeState = createAttributeState(this.scope);
41167
41389
  const state = createSharedNodeState(
41168
41390
  this.scope,
41169
41391
  {
@@ -41174,17 +41396,21 @@ class TriggerControl extends ValueNode {
41174
41396
  label: createNodeLabel(this, definition),
41175
41397
  hint: createFieldHint(this, definition),
41176
41398
  children: null,
41177
- attributes: null,
41399
+ attributes: this.attributeState.getAttributes,
41178
41400
  valueOptions: null,
41179
41401
  value: this.valueState,
41180
41402
  instanceValue: this.getInstanceValue
41181
41403
  },
41182
41404
  this.instanceConfig
41183
41405
  );
41406
+ this.attributeState.setAttributes(buildAttributes(this));
41184
41407
  this.state = state;
41185
41408
  this.engineState = state.engineState;
41186
41409
  this.currentState = state.currentState;
41187
41410
  }
41411
+ getAttributes() {
41412
+ return this.attributeState.getAttributes();
41413
+ }
41188
41414
  // TriggerNode
41189
41415
  setValue(value) {
41190
41416
  this.setValueState(value);
@@ -41373,8 +41599,7 @@ class UploadControl extends DescendantNode {
41373
41599
  this.nodeOptions = definition.bodyElement.options;
41374
41600
  const instanceAttachment = createInstanceAttachment(this);
41375
41601
  this.instanceAttachment = instanceAttachment;
41376
- const attributeState = createAttributeState(this.scope);
41377
- this.attributeState = attributeState;
41602
+ this.attributeState = createAttributeState(this.scope);
41378
41603
  this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
41379
41604
  this.getXPathValue = instanceAttachment.getInstanceValue;
41380
41605
  const state = createSharedNodeState(
@@ -41389,7 +41614,7 @@ class UploadControl extends DescendantNode {
41389
41614
  children: null,
41390
41615
  valueOptions: null,
41391
41616
  value: instanceAttachment.valueState,
41392
- attributes: attributeState.getAttributes,
41617
+ attributes: this.attributeState.getAttributes,
41393
41618
  instanceValue: instanceAttachment.getInstanceValue
41394
41619
  },
41395
41620
  this.instanceConfig
@@ -41398,6 +41623,7 @@ class UploadControl extends DescendantNode {
41398
41623
  this.engineState = state.engineState;
41399
41624
  this.currentState = state.currentState;
41400
41625
  this.validation = createValidationState(this, this.instanceConfig);
41626
+ this.attributeState.setAttributes(buildAttributes(this));
41401
41627
  this.instanceState = createValueNodeInstanceState(this);
41402
41628
  }
41403
41629
  static from(parent, instanceNode, definition) {
@@ -41406,13 +41632,13 @@ class UploadControl extends DescendantNode {
41406
41632
  }
41407
41633
  validation;
41408
41634
  instanceAttachment;
41409
- attributeState;
41410
41635
  // XFormsXPathElement
41411
41636
  [XPathNodeKindKey] = "element";
41412
41637
  getXPathValue;
41413
41638
  // InstanceNode
41414
41639
  state;
41415
41640
  engineState;
41641
+ attributeState;
41416
41642
  // InstanceValueContext
41417
41643
  decodeInstanceValue;
41418
41644
  // UploadNode
@@ -41436,14 +41662,14 @@ class UploadControl extends DescendantNode {
41436
41662
  getChildren() {
41437
41663
  return [];
41438
41664
  }
41665
+ getAttributes() {
41666
+ return this.attributeState.getAttributes();
41667
+ }
41439
41668
  // UploadNode
41440
41669
  setValue(value) {
41441
41670
  this.instanceAttachment.setValue(value);
41442
41671
  return this.root;
41443
41672
  }
41444
- getAttributes() {
41445
- return this.attributeState.getAttributes();
41446
- }
41447
41673
  }
41448
41674
 
41449
41675
  const META_LOCAL_NAME = "meta";
@@ -41529,7 +41755,7 @@ const buildMetaValueElement = (group, localName, value) => {
41529
41755
  const buildDeprecatedIDDefinition = (group, instanceNode) => {
41530
41756
  const nodeset = instanceNode.nodeset;
41531
41757
  const bind = group.model.binds.getOrCreateBindDefinition(nodeset);
41532
- return new LeafNodeDefinition(group.parent.definition, bind, null, instanceNode);
41758
+ return new LeafNodeDefinition(group.model, group.parent.definition, bind, null, instanceNode);
41533
41759
  };
41534
41760
  const buildDeprecatedID = (group, value) => {
41535
41761
  const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
@@ -41725,12 +41951,12 @@ const buildChildren = (parent) => {
41725
41951
 
41726
41952
  class Root extends DescendantNode {
41727
41953
  childrenState;
41728
- attributeState;
41729
41954
  // XFormsXPathElement
41730
41955
  [XPathNodeKindKey] = "element";
41731
41956
  // DescendantNode
41732
41957
  state;
41733
41958
  engineState;
41959
+ attributeState;
41734
41960
  hasReadonlyAncestor = () => false;
41735
41961
  isSelfReadonly = () => false;
41736
41962
  isReadonly = () => false;
@@ -41757,9 +41983,8 @@ class Root extends DescendantNode {
41757
41983
  });
41758
41984
  this.classes = parent.classes;
41759
41985
  const childrenState = createChildrenState(this);
41760
- const attributeState = createAttributeState(this.scope);
41986
+ this.attributeState = createAttributeState(this.scope);
41761
41987
  this.childrenState = childrenState;
41762
- this.attributeState = attributeState;
41763
41988
  this.languages = parent.languages;
41764
41989
  const state = createSharedNodeState(
41765
41990
  this.scope,
@@ -41774,7 +41999,7 @@ class Root extends DescendantNode {
41774
41999
  valueOptions: null,
41775
42000
  value: null,
41776
42001
  children: childrenState.childIds,
41777
- attributes: attributeState.getAttributes
42002
+ attributes: this.attributeState.getAttributes
41778
42003
  },
41779
42004
  this.instanceConfig
41780
42005
  );
@@ -41786,7 +42011,7 @@ class Root extends DescendantNode {
41786
42011
  childrenState
41787
42012
  );
41788
42013
  childrenState.setChildren(buildChildren(this));
41789
- attributeState.setAttributes(buildAttributes(this));
42014
+ this.attributeState.setAttributes(buildAttributes(this));
41790
42015
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
41791
42016
  this.instanceState = createRootInstanceState(this);
41792
42017
  }
@@ -41814,6 +42039,7 @@ class PrimaryInstance extends InstanceNode {
41814
42039
  // InstanceNode
41815
42040
  state;
41816
42041
  engineState;
42042
+ attributeState;
41817
42043
  instanceNode;
41818
42044
  getChildren;
41819
42045
  hasReadonlyAncestor = () => false;
@@ -41840,7 +42066,6 @@ class PrimaryInstance extends InstanceNode {
41840
42066
  isAttached;
41841
42067
  evaluator;
41842
42068
  contextNode = this;
41843
- attributeState;
41844
42069
  constructor(options) {
41845
42070
  const { mode, initialState, scope, model, secondaryInstances, config } = options;
41846
42071
  const { instance: modelInstance } = model;
@@ -41871,9 +42096,8 @@ class PrimaryInstance extends InstanceNode {
41871
42096
  this.evaluator = evaluator;
41872
42097
  this.classes = definition.classes;
41873
42098
  const childrenState = createChildrenState(this);
41874
- const attributeState = createAttributeState(this.scope);
42099
+ this.attributeState = createAttributeState(this.scope);
41875
42100
  this.getChildren = childrenState.getChildren;
41876
- this.attributeState = attributeState;
41877
42101
  const stateSpec = {
41878
42102
  activeLanguage: getActiveLanguage,
41879
42103
  reference: PRIMARY_INSTANCE_REFERENCE,
@@ -41885,7 +42109,7 @@ class PrimaryInstance extends InstanceNode {
41885
42109
  valueOptions: null,
41886
42110
  value: null,
41887
42111
  children: childrenState.childIds,
41888
- attributes: attributeState.getAttributes
42112
+ attributes: this.attributeState.getAttributes
41889
42113
  };
41890
42114
  const state = createSharedNodeState(scope, stateSpec, config);
41891
42115
  this.state = state;
@@ -41900,9 +42124,12 @@ class PrimaryInstance extends InstanceNode {
41900
42124
  };
41901
42125
  this.instanceState = createPrimaryInstanceState(this);
41902
42126
  childrenState.setChildren([root]);
41903
- attributeState.setAttributes(buildAttributes(this));
42127
+ this.attributeState.setAttributes(buildAttributes(this));
41904
42128
  setIsAttached(true);
41905
42129
  }
42130
+ getAttributes() {
42131
+ return this.attributeState.getAttributes();
42132
+ }
41906
42133
  // PrimaryInstanceDocument
41907
42134
  /**
41908
42135
  * @todo Note that this method's signature is intentionally derived from
@@ -41943,9 +42170,6 @@ class PrimaryInstance extends InstanceNode {
41943
42170
  });
41944
42171
  return Promise.resolve(result);
41945
42172
  }
41946
- getAttributes() {
41947
- return this.attributeState.getAttributes();
41948
- }
41949
42173
  }
41950
42174
 
41951
42175
  class FormInstance {
@@ -41954,7 +42178,8 @@ class FormInstance {
41954
42178
  const { mode, initialState, instanceConfig } = options;
41955
42179
  const config = {
41956
42180
  clientStateFactory: instanceConfig.stateFactory ?? identity,
41957
- computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null)
42181
+ computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null),
42182
+ preloadProperties: instanceConfig.preloadProperties ?? {}
41958
42183
  };
41959
42184
  const primaryInstanceOptions = {
41960
42185
  ...options.instanceOptions,