@getodk/xforms-engine 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/client/AttributeNode.d.ts +2 -5
  2. package/dist/client/BaseNode.d.ts +5 -0
  3. package/dist/client/form/FormInstanceConfig.d.ts +15 -0
  4. package/dist/index.js +395 -231
  5. package/dist/index.js.map +1 -1
  6. package/dist/instance/Attribute.d.ts +17 -11
  7. package/dist/instance/Group.d.ts +0 -2
  8. package/dist/instance/InputControl.d.ts +2 -0
  9. package/dist/instance/PrimaryInstance.d.ts +0 -2
  10. package/dist/instance/Root.d.ts +0 -2
  11. package/dist/instance/UploadControl.d.ts +0 -2
  12. package/dist/instance/abstract/InstanceNode.d.ts +2 -2
  13. package/dist/instance/abstract/ValueNode.d.ts +2 -1
  14. package/dist/instance/attachments/buildAttributes.d.ts +6 -2
  15. package/dist/instance/hierarchy.d.ts +1 -2
  16. package/dist/instance/internal-api/AttributeContext.d.ts +6 -0
  17. package/dist/instance/internal-api/InstanceConfig.d.ts +2 -0
  18. package/dist/instance/internal-api/InstanceValueContext.d.ts +6 -0
  19. package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +0 -1
  20. package/dist/instance/internal-api/serialization/ClientReactiveSerializableValueNode.d.ts +4 -0
  21. package/dist/instance/repeat/RepeatInstance.d.ts +0 -2
  22. package/dist/lib/codecs/items/SingleValueItemCodec.d.ts +1 -1
  23. package/dist/lib/reactivity/createInstanceValueState.d.ts +4 -1
  24. package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +2 -2
  25. package/dist/lib/xml-serialization.d.ts +1 -1
  26. package/dist/parse/XFormDOM.d.ts +3 -0
  27. package/dist/parse/expression/ActionComputationExpression.d.ts +4 -0
  28. package/dist/parse/model/ActionDefinition.d.ts +15 -0
  29. package/dist/parse/model/AttributeDefinition.d.ts +3 -1
  30. package/dist/parse/model/BindPreloadDefinition.d.ts +6 -10
  31. package/dist/parse/model/Event.d.ts +8 -0
  32. package/dist/parse/model/LeafNodeDefinition.d.ts +5 -2
  33. package/dist/parse/model/ModelActionMap.d.ts +9 -0
  34. package/dist/parse/model/ModelDefinition.d.ts +8 -1
  35. package/dist/parse/model/NoteNodeDefinition.d.ts +3 -2
  36. package/dist/parse/model/RangeNodeDefinition.d.ts +2 -1
  37. package/dist/parse/model/RootDefinition.d.ts +1 -0
  38. package/dist/solid.js +395 -231
  39. package/dist/solid.js.map +1 -1
  40. package/package.json +21 -17
  41. package/src/client/AttributeNode.ts +2 -5
  42. package/src/client/BaseNode.ts +6 -0
  43. package/src/client/form/FormInstanceConfig.ts +17 -0
  44. package/src/client/validation.ts +1 -1
  45. package/src/entrypoints/FormInstance.ts +1 -0
  46. package/src/instance/Attribute.ts +45 -45
  47. package/src/instance/Group.ts +1 -10
  48. package/src/instance/InputControl.ts +8 -1
  49. package/src/instance/ModelValue.ts +7 -1
  50. package/src/instance/Note.ts +6 -1
  51. package/src/instance/PrimaryInstance.ts +1 -11
  52. package/src/instance/RangeControl.ts +6 -1
  53. package/src/instance/RankControl.ts +7 -1
  54. package/src/instance/Root.ts +1 -10
  55. package/src/instance/SelectControl.ts +6 -1
  56. package/src/instance/TriggerControl.ts +6 -1
  57. package/src/instance/UploadControl.ts +1 -10
  58. package/src/instance/abstract/DescendantNode.ts +0 -5
  59. package/src/instance/abstract/InstanceNode.ts +2 -2
  60. package/src/instance/abstract/ValueNode.ts +2 -1
  61. package/src/instance/attachments/buildAttributes.ts +11 -4
  62. package/src/instance/children/normalizeChildInitOptions.ts +1 -1
  63. package/src/instance/hierarchy.ts +1 -3
  64. package/src/instance/internal-api/AttributeContext.ts +6 -0
  65. package/src/instance/internal-api/InstanceConfig.ts +6 -1
  66. package/src/instance/internal-api/InstanceValueContext.ts +6 -0
  67. package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +0 -1
  68. package/src/instance/internal-api/serialization/ClientReactiveSerializableValueNode.ts +4 -0
  69. package/src/instance/repeat/RepeatInstance.ts +1 -10
  70. package/src/lib/client-reactivity/instance-state/createValueNodeInstanceState.ts +2 -1
  71. package/src/lib/client-reactivity/instance-state/prepareInstancePayload.ts +1 -0
  72. package/src/lib/codecs/NoteCodec.ts +1 -1
  73. package/src/lib/codecs/items/SingleValueItemCodec.ts +1 -3
  74. package/src/lib/reactivity/createInstanceValueState.ts +152 -53
  75. package/src/lib/reactivity/node-state/createSharedNodeState.ts +2 -2
  76. package/src/lib/xml-serialization.ts +9 -1
  77. package/src/parse/XFormDOM.ts +9 -0
  78. package/src/parse/body/GroupElementDefinition.ts +1 -1
  79. package/src/parse/body/control/InputControlDefinition.ts +1 -1
  80. package/src/parse/expression/ActionComputationExpression.ts +12 -0
  81. package/src/parse/model/ActionDefinition.ts +70 -0
  82. package/src/parse/model/AttributeDefinition.ts +3 -2
  83. package/src/parse/model/AttributeDefinitionMap.ts +1 -1
  84. package/src/parse/model/BindDefinition.ts +1 -6
  85. package/src/parse/model/BindPreloadDefinition.ts +44 -12
  86. package/src/parse/model/Event.ts +9 -0
  87. package/src/parse/model/LeafNodeDefinition.ts +5 -1
  88. package/src/parse/model/ModelActionMap.ts +37 -0
  89. package/src/parse/model/ModelDefinition.ts +18 -3
  90. package/src/parse/model/NoteNodeDefinition.ts +5 -2
  91. package/src/parse/model/RangeNodeDefinition.ts +5 -2
  92. package/src/parse/model/RootDefinition.ts +22 -4
  93. package/dist/lib/reactivity/createAttributeValueState.d.ts +0 -15
  94. package/src/lib/reactivity/createAttributeValueState.ts +0 -189
package/dist/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
  }
@@ -21230,6 +21238,105 @@ class ItextTranslationsDefinition extends Map {
21230
21238
  }
21231
21239
  }
21232
21240
 
21241
+ class ActionComputationExpression extends DependentExpression {
21242
+ constructor(resultType, expression) {
21243
+ super(resultType, expression);
21244
+ }
21245
+ }
21246
+
21247
+ const XFORM_EVENT = {
21248
+ odkInstanceLoad: "odk-instance-load",
21249
+ odkInstanceFirstLoad: "odk-instance-first-load",
21250
+ odkNewRepeat: "odk-new-repeat",
21251
+ xformsRevalidate: "xforms-revalidate",
21252
+ xformsValueChanged: "xforms-value-changed"
21253
+ };
21254
+
21255
+ class ActionDefinition {
21256
+ constructor(model, element, source) {
21257
+ this.element = element;
21258
+ const ref = ActionDefinition.getRef(model, element);
21259
+ if (!ref) {
21260
+ throw new Error(
21261
+ 'Invalid setvalue element - you must define either "ref" or "bind" attribute'
21262
+ );
21263
+ }
21264
+ this.ref = ref;
21265
+ this.events = ActionDefinition.getEvents(element);
21266
+ const value = ActionDefinition.getValue(element);
21267
+ this.computation = new ActionComputationExpression("string", value);
21268
+ this.source = source;
21269
+ }
21270
+ static getRef(model, setValueElement) {
21271
+ if (setValueElement.hasAttribute("ref")) {
21272
+ return setValueElement.getAttribute("ref") ?? null;
21273
+ }
21274
+ if (setValueElement.hasAttribute("bind")) {
21275
+ const bindId = setValueElement.getAttribute("bind");
21276
+ const bindDefinition = Array.from(model.binds.values()).find((definition) => {
21277
+ return definition.bindElement.getAttribute("id") === bindId;
21278
+ });
21279
+ return bindDefinition?.nodeset ?? null;
21280
+ }
21281
+ return null;
21282
+ }
21283
+ static getValue(element) {
21284
+ if (element.hasAttribute("value")) {
21285
+ return element.getAttribute("value") || "''";
21286
+ }
21287
+ if (element.firstChild && isTextNode(element.firstChild)) {
21288
+ return `'${element.firstChild.nodeValue}'`;
21289
+ }
21290
+ return "''";
21291
+ }
21292
+ static isKnownEvent = (event) => {
21293
+ return Object.values(XFORM_EVENT).includes(event);
21294
+ };
21295
+ static getEvents(element) {
21296
+ const events = element.getAttribute("event")?.split(" ") ?? [];
21297
+ const unknownEvents = events.filter((event) => !this.isKnownEvent(event));
21298
+ if (unknownEvents.length) {
21299
+ throw new Error(
21300
+ `An action was registered for unsupported events: ${unknownEvents.join(", ")}`
21301
+ );
21302
+ }
21303
+ return events;
21304
+ }
21305
+ ref;
21306
+ events;
21307
+ computation;
21308
+ source;
21309
+ }
21310
+
21311
+ const REPEAT_REGEX = /(\[[^\]]*\])/gm;
21312
+ class ModelActionMap extends Map {
21313
+ static fromModel(model) {
21314
+ return new this(model);
21315
+ }
21316
+ static getKey(ref) {
21317
+ return ref.replace(REPEAT_REGEX, "");
21318
+ }
21319
+ constructor(model) {
21320
+ super(
21321
+ model.form.xformDOM.setValues.map((setValueElement) => {
21322
+ const action = new ActionDefinition(model, setValueElement);
21323
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
21324
+ throw new Error('Model contains "setvalue" element with "odk-new-repeat" event');
21325
+ }
21326
+ const key = ModelActionMap.getKey(action.ref);
21327
+ return [key, action];
21328
+ })
21329
+ );
21330
+ }
21331
+ get(ref) {
21332
+ return super.get(ModelActionMap.getKey(ref));
21333
+ }
21334
+ add(action) {
21335
+ const key = ModelActionMap.getKey(action.ref);
21336
+ this.set(key, action);
21337
+ }
21338
+ }
21339
+
21233
21340
  const defaultBindComputationExpressions = {
21234
21341
  calculate: null,
21235
21342
  constraint: "true()",
@@ -21295,6 +21402,7 @@ class MessageDefinition extends TextRangeDefinition {
21295
21402
  chunks;
21296
21403
  }
21297
21404
 
21405
+ const PRELOAD_UID_EXPRESSION = 'concat("uuid:", uuid())';
21298
21406
  const getPreloadInput = (bindElement) => {
21299
21407
  const type = bindElement.getAttributeNS(JAVAROSA_NAMESPACE_URI$1, "preload");
21300
21408
  if (type == null) {
@@ -21319,9 +21427,38 @@ class BindPreloadDefinition {
21319
21427
  }
21320
21428
  type;
21321
21429
  parameter;
21430
+ event;
21431
+ getValue(context) {
21432
+ if (this.type === "uid") {
21433
+ return context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION);
21434
+ }
21435
+ if (this.type === "timestamp") {
21436
+ return context.evaluator.evaluateString("now()");
21437
+ }
21438
+ if (this.type === "date") {
21439
+ return context.evaluator.evaluateString("today()");
21440
+ }
21441
+ if (this.type === "property") {
21442
+ const properties = context.instanceConfig.preloadProperties;
21443
+ if (this.parameter === "deviceid") {
21444
+ return properties.deviceID;
21445
+ }
21446
+ if (this.parameter === "email") {
21447
+ return properties.email;
21448
+ }
21449
+ if (this.parameter === "phonenumber") {
21450
+ return properties.phoneNumber;
21451
+ }
21452
+ if (this.parameter === "username") {
21453
+ return properties.username;
21454
+ }
21455
+ }
21456
+ return;
21457
+ }
21322
21458
  constructor(input) {
21323
21459
  this.type = input.type;
21324
21460
  this.parameter = input.parameter;
21461
+ this.event = this.type === "timestamp" && this.parameter === "end" ? XFORM_EVENT.xformsRevalidate : XFORM_EVENT.odkInstanceFirstLoad;
21325
21462
  }
21326
21463
  }
21327
21464
 
@@ -21468,10 +21605,7 @@ class BindDefinition extends DependencyContext {
21468
21605
  // TODO: it is unclear whether this will need to be supported.
21469
21606
  // https://github.com/getodk/collect/issues/3758 mentions deprecation.
21470
21607
  saveIncomplete;
21471
- // TODO: these are deferred until prioritized
21472
- // readonly preload: string | null;
21473
- // readonly preloadParams: string | null;
21474
- // readonly 'max-pixels': string | null;
21608
+ // TODO: deferred until prioritized: readonly 'max-pixels': string | null;
21475
21609
  _parentBind;
21476
21610
  get parentBind() {
21477
21611
  let bind = this._parentBind;
@@ -21637,8 +21771,14 @@ const serializeParentElementXML = (qualifiedName, children, attributes, namespac
21637
21771
  namespaceDeclarations
21638
21772
  );
21639
21773
  };
21640
- const serializeLeafElementXML = (qualifiedName, xmlValue, namespaceDeclarations) => {
21641
- return serializeElementXML(qualifiedName, xmlValue.normalize(), "", namespaceDeclarations);
21774
+ const serializeLeafElementXML = (qualifiedName, xmlValue, attributes, namespaceDeclarations) => {
21775
+ const serializedAttributes = attributes?.map((attribute) => attribute.instanceState.instanceXML).join("") ?? "";
21776
+ return serializeElementXML(
21777
+ qualifiedName,
21778
+ xmlValue.normalize(),
21779
+ serializedAttributes,
21780
+ namespaceDeclarations
21781
+ );
21642
21782
  };
21643
21783
 
21644
21784
  class NamespaceDeclaration {
@@ -21868,11 +22008,12 @@ class NodeDefinition {
21868
22008
  }
21869
22009
 
21870
22010
  class AttributeDefinition extends NodeDefinition {
21871
- constructor(root, bind, template) {
22011
+ constructor(model, bind, template) {
21872
22012
  super(bind);
22013
+ this.model = model;
21873
22014
  this.template = template;
21874
22015
  const { value } = template;
21875
- this.root = root;
22016
+ this.root = model.root;
21876
22017
  this.value = value;
21877
22018
  this.qualifiedName = template.qualifiedName;
21878
22019
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
@@ -21907,7 +22048,7 @@ class AttributeDefinitionMap extends Map {
21907
22048
  const nonNamespaceAttributes = instanceNode.attributes.filter(isNonNamespaceAttribute);
21908
22049
  const definitions = nonNamespaceAttributes.map((attribute) => {
21909
22050
  const bind = model.binds.getOrCreateBindDefinition(attribute.nodeset);
21910
- return new AttributeDefinition(model.root, bind, attribute);
22051
+ return new AttributeDefinition(model, bind, attribute);
21911
22052
  });
21912
22053
  return new this(definitions);
21913
22054
  }
@@ -21959,22 +22100,24 @@ class GroupDefinition extends DescendentNodeDefinition {
21959
22100
  }
21960
22101
 
21961
22102
  class LeafNodeDefinition extends DescendentNodeDefinition {
21962
- constructor(parent, bind, bodyElement, template) {
22103
+ constructor(model, parent, bind, bodyElement, template) {
21963
22104
  if (bodyElement != null && bodyElement.category !== "control") {
21964
22105
  throw new Error(`Unexpected body element for nodeset ${bind.nodeset}`);
21965
22106
  }
21966
22107
  super(parent, bind, bodyElement);
22108
+ this.model = model;
21967
22109
  this.template = template;
21968
22110
  this.valueType = bind.type.resolved;
21969
22111
  this.qualifiedName = template.qualifiedName;
21970
22112
  this.namespaceDeclarations = new NamespaceDeclarationMap(this);
22113
+ this.attributes = AttributeDefinitionMap.from(model, template);
21971
22114
  }
21972
22115
  type = "leaf-node";
21973
22116
  valueType;
21974
22117
  namespaceDeclarations;
21975
22118
  qualifiedName;
21976
22119
  children = null;
21977
- attributes = null;
22120
+ attributes;
21978
22121
  toJSON() {
21979
22122
  const { bind, bodyElement, parent, root, ...rest } = this;
21980
22123
  return rest;
@@ -21985,13 +22128,13 @@ const isNoteBindDefinition = (bind) => {
21985
22128
  return bind.readonly.isConstantTruthyExpression();
21986
22129
  };
21987
22130
  class NoteNodeDefinition extends LeafNodeDefinition {
21988
- constructor(parent, bind, bodyElement, noteTextDefinition, template) {
21989
- super(parent, bind, bodyElement, template);
22131
+ constructor(model, parent, bind, bodyElement, noteTextDefinition, template) {
22132
+ super(model, parent, bind, bodyElement, template);
21990
22133
  this.bind = bind;
21991
22134
  this.bodyElement = bodyElement;
21992
22135
  this.noteTextDefinition = noteTextDefinition;
21993
22136
  }
21994
- static from(parent, bind, bodyElement, node) {
22137
+ static from(model, parent, bind, bodyElement, node) {
21995
22138
  if (!isNoteBindDefinition(bind) || bodyElement?.type !== "input") {
21996
22139
  return null;
21997
22140
  }
@@ -22000,7 +22143,7 @@ class NoteNodeDefinition extends LeafNodeDefinition {
22000
22143
  if (noteTextDefinition == null) {
22001
22144
  return null;
22002
22145
  }
22003
- return new this(parent, bind, bodyElement, noteTextDefinition, node);
22146
+ return new this(model, parent, bind, bodyElement, noteTextDefinition, node);
22004
22147
  }
22005
22148
  }
22006
22149
 
@@ -26211,15 +26354,15 @@ class RangeNodeBoundsDefinition {
26211
26354
  }
26212
26355
  }
26213
26356
  class RangeNodeDefinition extends LeafNodeDefinition {
26214
- constructor(parent, bind, bodyElement, node) {
26215
- super(parent, bind, bodyElement, node);
26357
+ constructor(model, parent, bind, bodyElement, node) {
26358
+ super(model, parent, bind, bodyElement, node);
26216
26359
  this.bind = bind;
26217
26360
  this.bodyElement = bodyElement;
26218
26361
  this.bounds = RangeNodeBoundsDefinition.from(bodyElement.bounds, bind);
26219
26362
  }
26220
- static from(parent, bind, bodyElement, node) {
26363
+ static from(model, parent, bind, bodyElement, node) {
26221
26364
  assertRangeBindDefinition(bind);
26222
- return new this(parent, bind, bodyElement, node);
26365
+ return new this(model, parent, bind, bodyElement, node);
26223
26366
  }
26224
26367
  bounds;
26225
26368
  }
@@ -26355,6 +26498,18 @@ class RootDefinition extends NodeDefinition {
26355
26498
  attributes;
26356
26499
  children;
26357
26500
  isTranslated = false;
26501
+ mapActions(bodyElement) {
26502
+ const source = bodyElement.reference;
26503
+ if (!source) {
26504
+ return;
26505
+ }
26506
+ for (const child of bodyElement.element.children) {
26507
+ if (child.nodeName === "setvalue") {
26508
+ const action = new ActionDefinition(this.model, child, source);
26509
+ this.model.actions.add(action);
26510
+ }
26511
+ }
26512
+ }
26358
26513
  buildSubtree(parent, node) {
26359
26514
  const { form, model } = this;
26360
26515
  const { body } = form;
@@ -26377,6 +26532,9 @@ class RootDefinition extends NodeDefinition {
26377
26532
  const bind = binds.getOrCreateBindDefinition(nodeset);
26378
26533
  const bodyElement = body.getBodyElement(nodeset);
26379
26534
  const [firstChild, ...restChildren] = children;
26535
+ if (bodyElement) {
26536
+ this.mapActions(bodyElement);
26537
+ }
26380
26538
  if (bodyElement?.type === "repeat") {
26381
26539
  return RepeatDefinition.from(model, parent, bind, bodyElement, children);
26382
26540
  }
@@ -26386,9 +26544,9 @@ class RootDefinition extends NodeDefinition {
26386
26544
  const element = firstChild;
26387
26545
  if (element.isLeafElement()) {
26388
26546
  if (bodyElement?.type === "range") {
26389
- return RangeNodeDefinition.from(parent, bind, bodyElement, element);
26547
+ return RangeNodeDefinition.from(model, parent, bind, bodyElement, element);
26390
26548
  }
26391
- return NoteNodeDefinition.from(parent, bind, bodyElement, element) ?? new LeafNodeDefinition(parent, bind, bodyElement, element);
26549
+ return NoteNodeDefinition.from(model, parent, bind, bodyElement, element) ?? new LeafNodeDefinition(model, parent, bind, bodyElement, element);
26392
26550
  }
26393
26551
  return new GroupDefinition(model, parent, bind, bodyElement, element);
26394
26552
  });
@@ -26436,6 +26594,7 @@ class ModelDefinition {
26436
26594
  this.form = form;
26437
26595
  const submission = new SubmissionDefinition(form.xformDOM);
26438
26596
  this.binds = ModelBindMap.fromModel(this);
26597
+ this.actions = ModelActionMap.fromModel(this);
26439
26598
  this.instance = parseStaticDocumentFromDOMSubtree(form.xformDOM.primaryInstanceRoot, {
26440
26599
  nodesetPrefix: "/"
26441
26600
  });
@@ -26443,13 +26602,16 @@ class ModelDefinition {
26443
26602
  this.nodes = nodeDefinitionMap(this.root);
26444
26603
  this.itextTranslations = ItextTranslationsDefinition.from(form.xformDOM);
26445
26604
  this.itextChunks = generateItextChunks(form.xformDOM.itextTranslationElements);
26605
+ this.xformsRevalidateListeners = /* @__PURE__ */ new Map();
26446
26606
  }
26447
26607
  binds;
26608
+ actions;
26448
26609
  root;
26449
26610
  nodes;
26450
26611
  instance;
26451
26612
  itextTranslations;
26452
26613
  itextChunks;
26614
+ xformsRevalidateListeners;
26453
26615
  getNodeDefinition(nodeset) {
26454
26616
  const definition = this.nodes.get(nodeset);
26455
26617
  if (definition == null) {
@@ -26464,14 +26626,20 @@ class ModelDefinition {
26464
26626
  }
26465
26627
  return definition;
26466
26628
  }
26467
- toJSON() {
26468
- const { form, ...rest } = this;
26469
- return rest;
26629
+ registerXformsRevalidateListener(ref, listener) {
26630
+ this.xformsRevalidateListeners.set(ref, listener);
26631
+ }
26632
+ triggerXformsRevalidateListeners() {
26633
+ this.xformsRevalidateListeners.forEach((listener) => listener());
26470
26634
  }
26471
26635
  getTranslationChunks(itextId, activeLanguage) {
26472
26636
  const languageMap = this.itextChunks.get(activeLanguage.language);
26473
26637
  return languageMap?.get(itextId) ?? [];
26474
26638
  }
26639
+ toJSON() {
26640
+ const { form, ...rest } = this;
26641
+ return rest;
26642
+ }
26475
26643
  }
26476
26644
 
26477
26645
  class XFormDefinition {
@@ -28535,6 +28703,7 @@ const chunkedInstancePayload = (validation, submissionMeta, instanceFile, attach
28535
28703
  };
28536
28704
  };
28537
28705
  const prepareInstancePayload = (instanceRoot, options) => {
28706
+ instanceRoot.root.parent.model.triggerXformsRevalidateListeners();
28538
28707
  const validation = validateInstance(instanceRoot);
28539
28708
  const submissionMeta = instanceRoot.definition.submission;
28540
28709
  const instanceFile = new InstanceFile(instanceRoot);
@@ -28963,17 +29132,21 @@ const createComputedExpression = (context, dependentExpression, options = {}) =>
28963
29132
  });
28964
29133
  };
28965
29134
 
28966
- const isInstanceFirstLoad$1 = (context) => {
29135
+ const REPEAT_INDEX_REGEX = /([^[]*)(\[[0-9]+\])/g;
29136
+ const isInstanceFirstLoad = (context) => {
28967
29137
  return context.rootDocument.initializationMode === "create";
28968
29138
  };
28969
- const isEditInitialLoad$1 = (context) => {
29139
+ const isAddingRepeatChild = (context) => {
29140
+ return context.rootDocument.isAttached();
29141
+ };
29142
+ const isEditInitialLoad = (context) => {
28970
29143
  return context.rootDocument.initializationMode === "edit";
28971
29144
  };
28972
- const getInitialValue$1 = (context) => {
29145
+ const getInitialValue = (context) => {
28973
29146
  const sourceNode = context.instanceNode ?? context.definition.template;
28974
29147
  return context.decodeInstanceValue(sourceNode.value);
28975
29148
  };
28976
- const createRelevantValueState$1 = (context, baseValueState) => {
29149
+ const createRelevantValueState = (context, baseValueState) => {
28977
29150
  return context.scope.runTask(() => {
28978
29151
  const [getRelevantValue, setValue] = baseValueState;
28979
29152
  const getValue = createMemo(() => {
@@ -28985,7 +29158,7 @@ const createRelevantValueState$1 = (context, baseValueState) => {
28985
29158
  return [getValue, setValue];
28986
29159
  });
28987
29160
  };
28988
- const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29161
+ const guardDownstreamReadonlyWrites = (context, baseState) => {
28989
29162
  const { readonly } = context.definition.bind;
28990
29163
  if (readonly.isDefaultExpression) {
28991
29164
  return baseState;
@@ -29000,88 +29173,161 @@ const guardDownstreamReadonlyWrites$1 = (context, baseState) => {
29000
29173
  };
29001
29174
  return [getValue, setValue];
29002
29175
  };
29003
- const PRELOAD_UID_EXPRESSION$1 = 'concat("uuid:", uuid())';
29004
- const shouldPreloadUID$1 = (context) => {
29005
- return isInstanceFirstLoad$1(context) || isEditInitialLoad$1(context);
29176
+ const isLoading = (context) => {
29177
+ return isInstanceFirstLoad(context) || isEditInitialLoad(context);
29178
+ };
29179
+ const setValueIfPreloadDefined = (context, setValue, preload) => {
29180
+ const value = preload.getValue(context);
29181
+ if (value) {
29182
+ setValue(value);
29183
+ }
29184
+ };
29185
+ const postloadValue = (context, setValue, preload) => {
29186
+ const ref = context.contextReference();
29187
+ context.definition.model.registerXformsRevalidateListener(ref, () => {
29188
+ setValueIfPreloadDefined(context, setValue, preload);
29189
+ });
29006
29190
  };
29007
- const setPreloadUIDValue$1 = (context, valueState) => {
29191
+ const preloadValue = (context, setValue) => {
29008
29192
  const { preload } = context.definition.bind;
29009
- if (preload?.type !== "uid" || !shouldPreloadUID$1(context)) {
29193
+ if (!preload) {
29010
29194
  return;
29011
29195
  }
29012
- const preloadUIDValue = context.evaluator.evaluateString(PRELOAD_UID_EXPRESSION$1, {
29196
+ if (preload.event === XFORM_EVENT.xformsRevalidate) {
29197
+ postloadValue(context, setValue, preload);
29198
+ return;
29199
+ }
29200
+ if (isLoading(context)) {
29201
+ setValueIfPreloadDefined(context, setValue, preload);
29202
+ }
29203
+ };
29204
+ const referencesCurrentNode = (context, ref) => {
29205
+ const nodes = context.evaluator.evaluateNodes(ref, {
29013
29206
  contextNode: context.contextNode
29014
29207
  });
29015
- const [, setValue] = valueState;
29016
- setValue(preloadUIDValue);
29208
+ if (nodes.length > 1) {
29209
+ throw new Error(
29210
+ "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."
29211
+ );
29212
+ }
29213
+ return nodes.includes(context.contextNode);
29017
29214
  };
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);
29215
+ const bindToRepeatInstance = (context, action) => {
29216
+ let source = action.source;
29217
+ let ref = action.ref;
29218
+ if (source) {
29219
+ const contextRef = context.contextReference();
29220
+ for (const part of contextRef.matchAll(REPEAT_INDEX_REGEX)) {
29221
+ const unbound = part[1] + "/";
29222
+ if (source.includes(unbound)) {
29223
+ const bound = part[0] + "/";
29224
+ source = source.replace(unbound, bound);
29225
+ ref = ref.replace(unbound, bound);
29028
29226
  }
29029
- });
29227
+ }
29228
+ }
29229
+ return { source, ref };
29230
+ };
29231
+ const createCalculation = (context, setRelevantValue, computation) => {
29232
+ const calculate = createComputedExpression(context, computation);
29233
+ createComputed(() => {
29234
+ if (context.isAttached() && context.isRelevant()) {
29235
+ const calculated = calculate();
29236
+ const value = context.decodeInstanceValue(calculated);
29237
+ setRelevantValue(value);
29238
+ }
29239
+ });
29240
+ };
29241
+ const createValueChangedCalculation = (context, setRelevantValue, action) => {
29242
+ const { source, ref } = bindToRepeatInstance(context, action);
29243
+ if (!source) {
29244
+ return;
29245
+ }
29246
+ let previous = "";
29247
+ const sourceElementExpression = new ActionComputationExpression("string", source);
29248
+ const calculateValueSource = createComputedExpression(context, sourceElementExpression);
29249
+ createComputed(() => {
29250
+ if (context.isAttached() && context.isRelevant()) {
29251
+ const valueSource = calculateValueSource();
29252
+ if (previous !== valueSource) {
29253
+ if (referencesCurrentNode(context, ref)) {
29254
+ const calc = context.evaluator.evaluateString(action.computation.expression, context);
29255
+ const value = context.decodeInstanceValue(calc);
29256
+ setRelevantValue(value);
29257
+ }
29258
+ }
29259
+ previous = valueSource;
29260
+ }
29030
29261
  });
29031
29262
  };
29032
- const createAttributeValueState = (context) => {
29263
+ const registerAction = (context, setValue, action) => {
29264
+ if (action.events.includes(XFORM_EVENT.odkInstanceFirstLoad)) {
29265
+ if (isInstanceFirstLoad(context)) {
29266
+ createCalculation(context, setValue, action.computation);
29267
+ }
29268
+ }
29269
+ if (action.events.includes(XFORM_EVENT.odkInstanceLoad)) {
29270
+ if (!isAddingRepeatChild(context)) {
29271
+ createCalculation(context, setValue, action.computation);
29272
+ }
29273
+ }
29274
+ if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
29275
+ if (isAddingRepeatChild(context)) {
29276
+ createCalculation(context, setValue, action.computation);
29277
+ }
29278
+ }
29279
+ if (action.events.includes(XFORM_EVENT.xformsValueChanged)) {
29280
+ createValueChangedCalculation(context, setValue, action);
29281
+ }
29282
+ };
29283
+ const createInstanceValueState = (context) => {
29033
29284
  return context.scope.runTask(() => {
29034
- const initialValue = getInitialValue$1(context);
29285
+ const initialValue = getInitialValue(context);
29035
29286
  const baseValueState = createSignal(initialValue);
29036
- const relevantValueState = createRelevantValueState$1(context, baseValueState);
29037
- setPreloadUIDValue$1(context, relevantValueState);
29287
+ const relevantValueState = createRelevantValueState(context, baseValueState);
29288
+ const [, setValue] = relevantValueState;
29289
+ preloadValue(context, setValue);
29038
29290
  const { calculate } = context.definition.bind;
29039
29291
  if (calculate != null) {
29040
- const [, setValue] = relevantValueState;
29041
- createCalculation$1(context, setValue, calculate);
29292
+ createCalculation(context, setValue, calculate);
29042
29293
  }
29043
- return guardDownstreamReadonlyWrites$1(context, relevantValueState);
29294
+ const action = context.definition.model.actions.get(context.contextReference());
29295
+ if (action) {
29296
+ registerAction(context, setValue, action);
29297
+ }
29298
+ return guardDownstreamReadonlyWrites(context, relevantValueState);
29044
29299
  });
29045
29300
  };
29046
29301
 
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
- });
29302
+ class Attribute {
29303
+ constructor(owner, definition, instanceNode) {
29304
+ this.owner = owner;
29305
+ this.definition = definition;
29054
29306
  this.instanceNode = instanceNode;
29055
- this.root = parent.root;
29056
- this.getActiveLanguage = parent.getActiveLanguage;
29307
+ const codec = getSharedValueCodec("string");
29308
+ this.contextNode = owner;
29309
+ this.scope = owner.scope;
29310
+ this.rootDocument = owner.rootDocument;
29311
+ this.root = owner.root;
29312
+ this.instanceConfig = owner.instanceConfig;
29313
+ this.getActiveLanguage = owner.getActiveLanguage;
29057
29314
  this.validationState = { violations: [] };
29058
29315
  this.valueType = "string";
29059
- this.evaluator = parent.evaluator;
29316
+ this.evaluator = owner.evaluator;
29060
29317
  this.decodeInstanceValue = codec.decodeInstanceValue;
29061
- const instanceValueState = createAttributeValueState(this);
29318
+ const instanceValueState = createInstanceValueState(this);
29062
29319
  const valueState = codec.createRuntimeValueState(instanceValueState);
29063
29320
  const [getInstanceValue] = instanceValueState;
29064
29321
  const [, setValueState] = valueState;
29065
29322
  this.getInstanceValue = getInstanceValue;
29066
29323
  this.setValueState = setValueState;
29067
- this.getXPathValue = () => {
29068
- return this.getInstanceValue();
29069
- };
29070
29324
  this.valueState = valueState;
29071
29325
  const state = createSharedNodeState(
29072
- this.scope,
29326
+ owner.scope,
29073
29327
  {
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
29328
  value: this.valueState,
29083
29329
  instanceValue: this.getInstanceValue,
29084
- attributes: null
29330
+ relevant: this.owner.isRelevant
29085
29331
  },
29086
29332
  this.instanceConfig
29087
29333
  );
@@ -29106,23 +29352,30 @@ class Attribute extends InstanceNode {
29106
29352
  setValueState;
29107
29353
  evaluator;
29108
29354
  getActiveLanguage;
29355
+ contextNode;
29356
+ scope;
29357
+ rootDocument;
29358
+ instanceConfig;
29109
29359
  root;
29110
29360
  isRelevant = () => {
29111
- return this.parent.isRelevant();
29361
+ return this.owner.isRelevant();
29112
29362
  };
29113
29363
  isAttached = () => {
29114
- return this.parent.isAttached();
29364
+ return this.owner.isAttached();
29115
29365
  };
29116
29366
  isReadonly = () => {
29117
29367
  return true;
29118
29368
  };
29119
29369
  hasReadonlyAncestor = () => {
29120
- const { parent } = this;
29121
- return parent.hasReadonlyAncestor() || parent.isReadonly();
29370
+ const { owner } = this;
29371
+ return owner.hasReadonlyAncestor() || owner.isReadonly();
29122
29372
  };
29123
29373
  hasNonRelevantAncestor = () => {
29124
- const { parent } = this;
29125
- return parent.hasNonRelevantAncestor() || !parent.isRelevant();
29374
+ const { owner } = this;
29375
+ return owner.hasNonRelevantAncestor() || !owner.isRelevant();
29376
+ };
29377
+ contextReference = () => {
29378
+ return this.owner.contextReference() + "/@" + this.definition.qualifiedName.getPrefixedName();
29126
29379
  };
29127
29380
  setValue(value) {
29128
29381
  this.setValueState(value);
@@ -29131,11 +29384,17 @@ class Attribute extends InstanceNode {
29131
29384
  getChildren() {
29132
29385
  return [];
29133
29386
  }
29387
+ getXPathChildNodes() {
29388
+ return [];
29389
+ }
29390
+ getXPathValue() {
29391
+ return "";
29392
+ }
29134
29393
  }
29135
29394
 
29136
- function buildAttributes(parent) {
29137
- return Array.from(parent.definition.attributes.values()).map((attributeDefinition) => {
29138
- return new Attribute(parent, attributeDefinition, attributeDefinition.template);
29395
+ function buildAttributes(owner) {
29396
+ return Array.from(owner.definition.attributes.values()).map((attributeDefinition) => {
29397
+ return new Attribute(owner, attributeDefinition, attributeDefinition.template);
29139
29398
  });
29140
29399
  }
29141
29400
 
@@ -29239,11 +29498,6 @@ class DescendantNode extends InstanceNode {
29239
29498
  return true;
29240
29499
  }
29241
29500
  }
29242
- for (const attr of parent.getAttributes()) {
29243
- if (attr === self) {
29244
- return true;
29245
- }
29246
- }
29247
29501
  return false;
29248
29502
  });
29249
29503
  });
@@ -39633,7 +39887,6 @@ const createNodeLabel = (context, definition) => {
39633
39887
 
39634
39888
  class Group extends DescendantNode {
39635
39889
  childrenState;
39636
- attributeState;
39637
39890
  [XPathNodeKindKey] = "element";
39638
39891
  // InstanceNode
39639
39892
  state;
@@ -39651,7 +39904,6 @@ class Group extends DescendantNode {
39651
39904
  const childrenState = createChildrenState(this);
39652
39905
  const attributeState = createAttributeState(this.scope);
39653
39906
  this.childrenState = childrenState;
39654
- this.attributeState = attributeState;
39655
39907
  const state = createSharedNodeState(
39656
39908
  this.scope,
39657
39909
  {
@@ -39683,9 +39935,6 @@ class Group extends DescendantNode {
39683
39935
  getChildren() {
39684
39936
  return this.childrenState.getChildren();
39685
39937
  }
39686
- getAttributes() {
39687
- return this.attributeState.getAttributes();
39688
- }
39689
39938
  }
39690
39939
 
39691
39940
  const createFieldHint = (context, definition) => {
@@ -39704,92 +39953,12 @@ const createValueNodeInstanceState = (node) => {
39704
39953
  return "";
39705
39954
  }
39706
39955
  const xmlValue = escapeXMLText(node.currentState.instanceValue);
39707
- return serializeLeafElementXML(qualifiedName, xmlValue);
39956
+ const attributes = node.currentState.attributes;
39957
+ return serializeLeafElementXML(qualifiedName, xmlValue, attributes);
39708
39958
  }
39709
39959
  };
39710
39960
  };
39711
39961
 
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}`);
39744
- }
39745
- return baseSetValue(value);
39746
- };
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
- };
39792
-
39793
39962
  const engineViolationMessage = (context, role) => {
39794
39963
  const messageText = VALIDATION_TEXT[role];
39795
39964
  const chunk = new TextChunk(context, "literal", messageText);
@@ -39979,6 +40148,7 @@ class InputControl extends ValueNode {
39979
40148
  super(parent, instanceNode, definition, codec);
39980
40149
  this.appearances = definition.bodyElement.appearances;
39981
40150
  this.nodeOptions = nodeOptionsFactoryByType[definition.valueType](definition.bodyElement);
40151
+ const attributeState = createAttributeState(this.scope);
39982
40152
  const state = createSharedNodeState(
39983
40153
  this.scope,
39984
40154
  {
@@ -39989,13 +40159,14 @@ class InputControl extends ValueNode {
39989
40159
  label: createNodeLabel(this, definition),
39990
40160
  hint: createFieldHint(this, definition),
39991
40161
  children: null,
39992
- attributes: null,
40162
+ attributes: attributeState.getAttributes,
39993
40163
  valueOptions: null,
39994
40164
  value: this.valueState,
39995
40165
  instanceValue: this.getInstanceValue
39996
40166
  },
39997
40167
  this.instanceConfig
39998
40168
  );
40169
+ attributeState.setAttributes(buildAttributes(this));
39999
40170
  this.state = state;
40000
40171
  this.engineState = state.engineState;
40001
40172
  this.currentState = state.currentState;
@@ -40023,6 +40194,7 @@ class ModelValue extends ValueNode {
40023
40194
  constructor(parent, instanceNode, definition) {
40024
40195
  const codec = getSharedValueCodec(definition.valueType);
40025
40196
  super(parent, instanceNode, definition, codec);
40197
+ const attributeState = createAttributeState(this.scope);
40026
40198
  const state = createSharedNodeState(
40027
40199
  this.scope,
40028
40200
  {
@@ -40033,13 +40205,14 @@ class ModelValue extends ValueNode {
40033
40205
  label: null,
40034
40206
  hint: null,
40035
40207
  children: null,
40036
- attributes: null,
40208
+ attributes: attributeState.getAttributes,
40037
40209
  valueOptions: null,
40038
40210
  value: this.valueState,
40039
40211
  instanceValue: this.getInstanceValue
40040
40212
  },
40041
40213
  this.instanceConfig
40042
40214
  );
40215
+ attributeState.setAttributes(buildAttributes(this));
40043
40216
  this.state = state;
40044
40217
  this.engineState = state.engineState;
40045
40218
  this.currentState = state.currentState;
@@ -40131,6 +40304,7 @@ class Note extends ValueNode {
40131
40304
  this.appearances = definition.bodyElement.appearances;
40132
40305
  const isReadonly = createNoteReadonlyThunk(this, definition);
40133
40306
  const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
40307
+ const attributeState = createAttributeState(this.scope);
40134
40308
  let noteText;
40135
40309
  let label;
40136
40310
  let hint;
@@ -40161,13 +40335,14 @@ class Note extends ValueNode {
40161
40335
  hint,
40162
40336
  noteText,
40163
40337
  children: null,
40164
- attributes: null,
40338
+ attributes: attributeState.getAttributes,
40165
40339
  valueOptions: null,
40166
40340
  value: this.valueState,
40167
40341
  instanceValue: this.getInstanceValue
40168
40342
  },
40169
40343
  this.instanceConfig
40170
40344
  );
40345
+ attributeState.setAttributes(buildAttributes(this));
40171
40346
  this.state = state;
40172
40347
  this.engineState = state.engineState;
40173
40348
  this.currentState = state.currentState;
@@ -40231,6 +40406,7 @@ class RangeControl extends ValueNode {
40231
40406
  const codec = new RangeCodec(baseCodec, definition);
40232
40407
  super(parent, instanceNode, definition, codec);
40233
40408
  this.appearances = definition.bodyElement.appearances;
40409
+ const attributeState = createAttributeState(this.scope);
40234
40410
  const state = createSharedNodeState(
40235
40411
  this.scope,
40236
40412
  {
@@ -40241,13 +40417,14 @@ class RangeControl extends ValueNode {
40241
40417
  label: createNodeLabel(this, definition),
40242
40418
  hint: createFieldHint(this, definition),
40243
40419
  children: null,
40244
- attributes: null,
40420
+ attributes: attributeState.getAttributes,
40245
40421
  valueOptions: null,
40246
40422
  value: this.valueState,
40247
40423
  instanceValue: this.getInstanceValue
40248
40424
  },
40249
40425
  this.instanceConfig
40250
40426
  );
40427
+ attributeState.setAttributes(buildAttributes(this));
40251
40428
  this.state = state;
40252
40429
  this.engineState = state.engineState;
40253
40430
  this.currentState = state.currentState;
@@ -40465,6 +40642,7 @@ class RankControl extends ValueNode {
40465
40642
  this.mapOptionsByValue = mapOptionsByValue;
40466
40643
  const baseValueState = this.valueState;
40467
40644
  const [baseGetValue, setValue] = baseValueState;
40645
+ const attributeState = createAttributeState(this.scope);
40468
40646
  const getValue = this.scope.runTask(() => {
40469
40647
  return createMemo(() => {
40470
40648
  const options = valueOptions();
@@ -40499,13 +40677,14 @@ class RankControl extends ValueNode {
40499
40677
  label: createNodeLabel(this, definition),
40500
40678
  hint: createFieldHint(this, definition),
40501
40679
  children: null,
40502
- attributes: null,
40680
+ attributes: attributeState.getAttributes,
40503
40681
  valueOptions,
40504
40682
  value: valueState,
40505
40683
  instanceValue: this.getInstanceValue
40506
40684
  },
40507
40685
  this.instanceConfig
40508
40686
  );
40687
+ attributeState.setAttributes(buildAttributes(this));
40509
40688
  this.state = state;
40510
40689
  this.engineState = state.engineState;
40511
40690
  this.currentState = state.currentState;
@@ -40594,7 +40773,6 @@ class RepeatInstance extends DescendantNode {
40594
40773
  const childrenState = createChildrenState(this);
40595
40774
  const attributeState = createAttributeState(this.scope);
40596
40775
  this.childrenState = childrenState;
40597
- this.attributeState = attributeState;
40598
40776
  this.currentIndex = currentIndex;
40599
40777
  const state = createSharedNodeState(
40600
40778
  this.scope,
@@ -40629,7 +40807,6 @@ class RepeatInstance extends DescendantNode {
40629
40807
  this.instanceState = createTemplatedNodeInstanceState(this);
40630
40808
  }
40631
40809
  childrenState;
40632
- attributeState;
40633
40810
  currentIndex;
40634
40811
  [XPathNodeKindKey] = "element";
40635
40812
  // InstanceNode
@@ -40664,9 +40841,6 @@ class RepeatInstance extends DescendantNode {
40664
40841
  getChildren() {
40665
40842
  return this.childrenState.getChildren();
40666
40843
  }
40667
- getAttributes() {
40668
- return this.attributeState.getAttributes();
40669
- }
40670
40844
  }
40671
40845
 
40672
40846
  class BaseRepeatRange extends DescendantNode {
@@ -41002,6 +41176,7 @@ class SelectControl extends ValueNode {
41002
41176
  super(parent, instanceNode, definition, codec);
41003
41177
  this.appearances = definition.bodyElement.appearances;
41004
41178
  this.selectType = definition.bodyElement.type;
41179
+ const attributeState = createAttributeState(this.scope);
41005
41180
  const valueOptions = createItemCollection(this);
41006
41181
  const isSelectWithImages = this.scope.runTask(() => {
41007
41182
  return createMemo(() => valueOptions().some((item) => !!item.label.imageSource));
@@ -41038,7 +41213,7 @@ class SelectControl extends ValueNode {
41038
41213
  label: createNodeLabel(this, definition),
41039
41214
  hint: createFieldHint(this, definition),
41040
41215
  children: null,
41041
- attributes: null,
41216
+ attributes: attributeState.getAttributes,
41042
41217
  valueOptions,
41043
41218
  value: valueState,
41044
41219
  instanceValue: this.getInstanceValue,
@@ -41046,6 +41221,7 @@ class SelectControl extends ValueNode {
41046
41221
  },
41047
41222
  this.instanceConfig
41048
41223
  );
41224
+ attributeState.setAttributes(buildAttributes(this));
41049
41225
  this.state = state;
41050
41226
  this.engineState = state.engineState;
41051
41227
  this.currentState = state.currentState;
@@ -41164,6 +41340,7 @@ class TriggerControl extends ValueNode {
41164
41340
  constructor(parent, instanceNode, definition) {
41165
41341
  super(parent, instanceNode, definition, codec);
41166
41342
  this.appearances = definition.bodyElement.appearances;
41343
+ const attributeState = createAttributeState(this.scope);
41167
41344
  const state = createSharedNodeState(
41168
41345
  this.scope,
41169
41346
  {
@@ -41174,13 +41351,14 @@ class TriggerControl extends ValueNode {
41174
41351
  label: createNodeLabel(this, definition),
41175
41352
  hint: createFieldHint(this, definition),
41176
41353
  children: null,
41177
- attributes: null,
41354
+ attributes: attributeState.getAttributes,
41178
41355
  valueOptions: null,
41179
41356
  value: this.valueState,
41180
41357
  instanceValue: this.getInstanceValue
41181
41358
  },
41182
41359
  this.instanceConfig
41183
41360
  );
41361
+ attributeState.setAttributes(buildAttributes(this));
41184
41362
  this.state = state;
41185
41363
  this.engineState = state.engineState;
41186
41364
  this.currentState = state.currentState;
@@ -41374,7 +41552,6 @@ class UploadControl extends DescendantNode {
41374
41552
  const instanceAttachment = createInstanceAttachment(this);
41375
41553
  this.instanceAttachment = instanceAttachment;
41376
41554
  const attributeState = createAttributeState(this.scope);
41377
- this.attributeState = attributeState;
41378
41555
  this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
41379
41556
  this.getXPathValue = instanceAttachment.getInstanceValue;
41380
41557
  const state = createSharedNodeState(
@@ -41406,7 +41583,6 @@ class UploadControl extends DescendantNode {
41406
41583
  }
41407
41584
  validation;
41408
41585
  instanceAttachment;
41409
- attributeState;
41410
41586
  // XFormsXPathElement
41411
41587
  [XPathNodeKindKey] = "element";
41412
41588
  getXPathValue;
@@ -41441,9 +41617,6 @@ class UploadControl extends DescendantNode {
41441
41617
  this.instanceAttachment.setValue(value);
41442
41618
  return this.root;
41443
41619
  }
41444
- getAttributes() {
41445
- return this.attributeState.getAttributes();
41446
- }
41447
41620
  }
41448
41621
 
41449
41622
  const META_LOCAL_NAME = "meta";
@@ -41529,7 +41702,7 @@ const buildMetaValueElement = (group, localName, value) => {
41529
41702
  const buildDeprecatedIDDefinition = (group, instanceNode) => {
41530
41703
  const nodeset = instanceNode.nodeset;
41531
41704
  const bind = group.model.binds.getOrCreateBindDefinition(nodeset);
41532
- return new LeafNodeDefinition(group.parent.definition, bind, null, instanceNode);
41705
+ return new LeafNodeDefinition(group.model, group.parent.definition, bind, null, instanceNode);
41533
41706
  };
41534
41707
  const buildDeprecatedID = (group, value) => {
41535
41708
  const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
@@ -41725,7 +41898,6 @@ const buildChildren = (parent) => {
41725
41898
 
41726
41899
  class Root extends DescendantNode {
41727
41900
  childrenState;
41728
- attributeState;
41729
41901
  // XFormsXPathElement
41730
41902
  [XPathNodeKindKey] = "element";
41731
41903
  // DescendantNode
@@ -41759,7 +41931,6 @@ class Root extends DescendantNode {
41759
41931
  const childrenState = createChildrenState(this);
41760
41932
  const attributeState = createAttributeState(this.scope);
41761
41933
  this.childrenState = childrenState;
41762
- this.attributeState = attributeState;
41763
41934
  this.languages = parent.languages;
41764
41935
  const state = createSharedNodeState(
41765
41936
  this.scope,
@@ -41793,9 +41964,6 @@ class Root extends DescendantNode {
41793
41964
  getChildren() {
41794
41965
  return this.childrenState.getChildren();
41795
41966
  }
41796
- getAttributes() {
41797
- return this.attributeState.getAttributes();
41798
- }
41799
41967
  // RootNode
41800
41968
  setLanguage(language) {
41801
41969
  this.rootDocument.setLanguage(language);
@@ -41840,7 +42008,6 @@ class PrimaryInstance extends InstanceNode {
41840
42008
  isAttached;
41841
42009
  evaluator;
41842
42010
  contextNode = this;
41843
- attributeState;
41844
42011
  constructor(options) {
41845
42012
  const { mode, initialState, scope, model, secondaryInstances, config } = options;
41846
42013
  const { instance: modelInstance } = model;
@@ -41873,7 +42040,6 @@ class PrimaryInstance extends InstanceNode {
41873
42040
  const childrenState = createChildrenState(this);
41874
42041
  const attributeState = createAttributeState(this.scope);
41875
42042
  this.getChildren = childrenState.getChildren;
41876
- this.attributeState = attributeState;
41877
42043
  const stateSpec = {
41878
42044
  activeLanguage: getActiveLanguage,
41879
42045
  reference: PRIMARY_INSTANCE_REFERENCE,
@@ -41943,9 +42109,6 @@ class PrimaryInstance extends InstanceNode {
41943
42109
  });
41944
42110
  return Promise.resolve(result);
41945
42111
  }
41946
- getAttributes() {
41947
- return this.attributeState.getAttributes();
41948
- }
41949
42112
  }
41950
42113
 
41951
42114
  class FormInstance {
@@ -41954,7 +42117,8 @@ class FormInstance {
41954
42117
  const { mode, initialState, instanceConfig } = options;
41955
42118
  const config = {
41956
42119
  clientStateFactory: instanceConfig.stateFactory ?? identity,
41957
- computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null)
42120
+ computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null),
42121
+ preloadProperties: instanceConfig.preloadProperties ?? {}
41958
42122
  };
41959
42123
  const primaryInstanceOptions = {
41960
42124
  ...options.instanceOptions,