@getodk/xforms-engine 0.13.0 → 0.15.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 (138) hide show
  1. package/dist/client/AttributeNode.d.ts +53 -0
  2. package/dist/client/BaseItem.d.ts +6 -0
  3. package/dist/client/GroupNode.d.ts +4 -4
  4. package/dist/client/MarkdownNode.d.ts +33 -0
  5. package/dist/client/RankNode.d.ts +2 -4
  6. package/dist/client/SelectNode.d.ts +2 -5
  7. package/dist/client/TextRange.d.ts +2 -2
  8. package/dist/client/hierarchy.d.ts +1 -2
  9. package/dist/client/index.d.ts +2 -1
  10. package/dist/client/node-types.d.ts +2 -2
  11. package/dist/client/validation.d.ts +7 -1
  12. package/dist/index.js +10758 -402
  13. package/dist/index.js.map +1 -1
  14. package/dist/instance/Attribute.d.ts +58 -0
  15. package/dist/instance/Group.d.ts +4 -0
  16. package/dist/instance/PrimaryInstance.d.ts +4 -0
  17. package/dist/instance/Root.d.ts +4 -0
  18. package/dist/instance/UploadControl.d.ts +4 -0
  19. package/dist/instance/abstract/InstanceNode.d.ts +7 -4
  20. package/dist/instance/abstract/ValueNode.d.ts +1 -0
  21. package/dist/instance/attachments/buildAttributes.d.ts +3 -0
  22. package/dist/instance/hierarchy.d.ts +6 -6
  23. package/dist/instance/internal-api/AttributeContext.d.ts +29 -0
  24. package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +16 -0
  25. package/dist/instance/internal-api/serialization/ClientReactiveSerializableParentNode.d.ts +2 -0
  26. package/dist/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.d.ts +2 -2
  27. package/dist/instance/markdown/MarkdownNode.d.ts +75 -0
  28. package/dist/instance/repeat/BaseRepeatRange.d.ts +5 -0
  29. package/dist/instance/repeat/RepeatInstance.d.ts +4 -2
  30. package/dist/instance/text/TextChunk.d.ts +0 -1
  31. package/dist/instance/text/TextRange.d.ts +2 -1
  32. package/dist/instance/text/markdownFormat.d.ts +3 -0
  33. package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +2 -2
  34. package/dist/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.d.ts +3 -0
  35. package/dist/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.d.ts +0 -3
  36. package/dist/lib/names/NamespaceDeclarationMap.d.ts +1 -1
  37. package/dist/lib/reactivity/createAttributeState.d.ts +16 -0
  38. package/dist/lib/reactivity/createAttributeValueState.d.ts +15 -0
  39. package/dist/lib/reactivity/createItemCollection.d.ts +5 -7
  40. package/dist/lib/xml-serialization.d.ts +5 -9
  41. package/dist/parse/XFormDOM.d.ts +1 -1
  42. package/dist/parse/body/BodyDefinition.d.ts +2 -8
  43. package/dist/parse/body/GroupElementDefinition.d.ts +22 -0
  44. package/dist/parse/body/control/ItemsetDefinition.d.ts +3 -0
  45. package/dist/parse/expression/ItemPropertyExpression.d.ts +6 -0
  46. package/dist/parse/model/AttributeDefinition.d.ts +22 -0
  47. package/dist/parse/model/{RootAttributeMap.d.ts → AttributeDefinitionMap.d.ts} +4 -10
  48. package/dist/parse/model/{SubtreeDefinition.d.ts → GroupDefinition.d.ts} +8 -4
  49. package/dist/parse/model/LeafNodeDefinition.d.ts +1 -0
  50. package/dist/parse/model/NodeDefinition.d.ts +13 -9
  51. package/dist/parse/model/RepeatDefinition.d.ts +5 -2
  52. package/dist/parse/model/RootDefinition.d.ts +3 -3
  53. package/dist/parse/text/LabelDefinition.d.ts +4 -5
  54. package/dist/solid.js +10758 -402
  55. package/dist/solid.js.map +1 -1
  56. package/package.json +6 -5
  57. package/src/client/AttributeNode.ts +62 -0
  58. package/src/client/BaseItem.ts +7 -0
  59. package/src/client/GroupNode.ts +4 -10
  60. package/src/client/MarkdownNode.ts +53 -0
  61. package/src/client/RankNode.ts +2 -5
  62. package/src/client/SelectNode.ts +2 -6
  63. package/src/client/TextRange.ts +2 -2
  64. package/src/client/hierarchy.ts +0 -2
  65. package/src/client/index.ts +2 -1
  66. package/src/client/node-types.ts +1 -1
  67. package/src/client/validation.ts +9 -1
  68. package/src/instance/Attribute.ts +164 -0
  69. package/src/instance/Group.ts +17 -1
  70. package/src/instance/InputControl.ts +1 -0
  71. package/src/instance/ModelValue.ts +1 -0
  72. package/src/instance/Note.ts +1 -0
  73. package/src/instance/PrimaryInstance.ts +17 -0
  74. package/src/instance/RangeControl.ts +1 -0
  75. package/src/instance/RankControl.ts +1 -0
  76. package/src/instance/Root.ts +16 -0
  77. package/src/instance/SelectControl.ts +1 -0
  78. package/src/instance/TriggerControl.ts +1 -0
  79. package/src/instance/UploadControl.ts +14 -0
  80. package/src/instance/abstract/DescendantNode.ts +5 -1
  81. package/src/instance/abstract/InstanceNode.ts +6 -3
  82. package/src/instance/abstract/ValueNode.ts +1 -0
  83. package/src/instance/attachments/buildAttributes.ts +8 -0
  84. package/src/instance/children/buildChildren.ts +1 -17
  85. package/src/instance/children/normalizeChildInitOptions.ts +44 -59
  86. package/src/instance/hierarchy.ts +3 -7
  87. package/src/instance/internal-api/AttributeContext.ts +34 -0
  88. package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +19 -0
  89. package/src/instance/internal-api/serialization/ClientReactiveSerializableParentNode.ts +2 -0
  90. package/src/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.ts +2 -3
  91. package/src/instance/markdown/MarkdownNode.ts +115 -0
  92. package/src/instance/repeat/BaseRepeatRange.ts +14 -0
  93. package/src/instance/repeat/RepeatInstance.ts +14 -5
  94. package/src/instance/text/TextChunk.ts +0 -5
  95. package/src/instance/text/TextRange.ts +5 -3
  96. package/src/instance/text/markdownFormat.ts +214 -0
  97. package/src/integration/xpath/adapter/XFormsXPathNode.ts +3 -1
  98. package/src/integration/xpath/adapter/names.ts +0 -1
  99. package/src/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.ts +16 -0
  100. package/src/lib/client-reactivity/instance-state/createParentNodeInstanceState.ts +5 -5
  101. package/src/lib/client-reactivity/instance-state/createRootInstanceState.ts +6 -9
  102. package/src/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.ts +5 -15
  103. package/src/lib/names/NamespaceDeclarationMap.ts +1 -1
  104. package/src/lib/reactivity/createAttributeState.ts +51 -0
  105. package/src/lib/reactivity/createAttributeValueState.ts +189 -0
  106. package/src/lib/reactivity/createItemCollection.ts +25 -9
  107. package/src/lib/xml-serialization.ts +30 -34
  108. package/src/parse/body/BodyDefinition.ts +7 -34
  109. package/src/parse/body/GroupElementDefinition.ts +47 -0
  110. package/src/parse/body/control/ItemsetDefinition.ts +7 -0
  111. package/src/parse/expression/ItemPropertyExpression.ts +12 -0
  112. package/src/parse/model/AttributeDefinition.ts +58 -0
  113. package/src/parse/model/{RootAttributeMap.ts → AttributeDefinitionMap.ts} +7 -13
  114. package/src/parse/model/{SubtreeDefinition.ts → GroupDefinition.ts} +12 -8
  115. package/src/parse/model/LeafNodeDefinition.ts +1 -0
  116. package/src/parse/model/NodeDefinition.ts +19 -12
  117. package/src/parse/model/RepeatDefinition.ts +10 -3
  118. package/src/parse/model/RootDefinition.ts +6 -6
  119. package/src/parse/model/nodeDefinitionMap.ts +1 -1
  120. package/src/parse/text/LabelDefinition.ts +4 -9
  121. package/dist/client/SubtreeNode.d.ts +0 -56
  122. package/dist/error/TemplatedNodeAttributeSerializationError.d.ts +0 -22
  123. package/dist/instance/Subtree.d.ts +0 -38
  124. package/dist/instance/text/FormattedTextStub.d.ts +0 -1
  125. package/dist/parse/body/group/BaseGroupDefinition.d.ts +0 -40
  126. package/dist/parse/body/group/LogicalGroupDefinition.d.ts +0 -6
  127. package/dist/parse/body/group/PresentationGroupDefinition.d.ts +0 -11
  128. package/dist/parse/body/group/StructuralGroupDefinition.d.ts +0 -6
  129. package/dist/parse/model/RootAttributeDefinition.d.ts +0 -21
  130. package/src/client/SubtreeNode.ts +0 -61
  131. package/src/error/TemplatedNodeAttributeSerializationError.ts +0 -24
  132. package/src/instance/Subtree.ts +0 -102
  133. package/src/instance/text/FormattedTextStub.ts +0 -8
  134. package/src/parse/body/group/BaseGroupDefinition.ts +0 -89
  135. package/src/parse/body/group/LogicalGroupDefinition.ts +0 -11
  136. package/src/parse/body/group/PresentationGroupDefinition.ts +0 -28
  137. package/src/parse/body/group/StructuralGroupDefinition.ts +0 -11
  138. package/src/parse/model/RootAttributeDefinition.ts +0 -44
@@ -94,6 +94,7 @@ export class RangeControl<V extends RangeValueType = RangeValueType>
94
94
  label: createNodeLabel(this, definition),
95
95
  hint: createFieldHint(this, definition),
96
96
  children: null,
97
+ attributes: null,
97
98
  valueOptions: null,
98
99
  value: this.valueState,
99
100
  instanceValue: this.getInstanceValue,
@@ -174,6 +174,7 @@ export class RankControl
174
174
  label: createNodeLabel(this, definition),
175
175
  hint: createFieldHint(this, definition),
176
176
  children: null,
177
+ attributes: null,
177
178
  valueOptions,
178
179
  value: valueState,
179
180
  instanceValue: this.getInstanceValue,
@@ -12,6 +12,10 @@ import type { InstanceState } from '../client/serialization/InstanceState.ts';
12
12
  import type { AncestorNodeValidationState } from '../client/validation.ts';
13
13
  import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
14
14
  import { createRootInstanceState } from '../lib/client-reactivity/instance-state/createRootInstanceState.ts';
15
+ import {
16
+ createAttributeState,
17
+ type AttributeState,
18
+ } from '../lib/reactivity/createAttributeState.ts';
15
19
  import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
16
20
  import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
17
21
  import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
@@ -24,6 +28,8 @@ import { createAggregatedViolations } from '../lib/reactivity/validation/createA
24
28
  import type { BodyClassList } from '../parse/body/BodyDefinition.ts';
25
29
  import type { RootDefinition } from '../parse/model/RootDefinition.ts';
26
30
  import { DescendantNode } from './abstract/DescendantNode.ts';
31
+ import { buildAttributes } from './attachments/buildAttributes.ts';
32
+ import { Attribute } from './Attribute.ts';
27
33
  import { buildChildren } from './children/buildChildren.ts';
28
34
  import type { GeneralChildNode } from './hierarchy.ts';
29
35
  import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
@@ -39,6 +45,7 @@ interface RootStateSpec {
39
45
  readonly label: null;
40
46
  readonly hint: null;
41
47
  readonly children: Accessor<readonly FormNodeID[]>;
48
+ readonly attributes: Accessor<readonly Attribute[]>;
42
49
  readonly valueOptions: null;
43
50
  readonly value: null;
44
51
 
@@ -56,6 +63,7 @@ export class Root
56
63
  ClientReactiveSerializableParentNode<GeneralChildNode>
57
64
  {
58
65
  private readonly childrenState: ChildrenState<GeneralChildNode>;
66
+ private readonly attributeState: AttributeState;
59
67
 
60
68
  // XFormsXPathElement
61
69
  override readonly [XPathNodeKindKey] = 'element';
@@ -95,8 +103,10 @@ export class Root
95
103
  this.classes = parent.classes;
96
104
 
97
105
  const childrenState = createChildrenState<Root, GeneralChildNode>(this);
106
+ const attributeState = createAttributeState(this.scope);
98
107
 
99
108
  this.childrenState = childrenState;
109
+ this.attributeState = attributeState;
100
110
  this.languages = parent.languages;
101
111
 
102
112
  const state = createSharedNodeState(
@@ -112,6 +122,7 @@ export class Root
112
122
  valueOptions: null,
113
123
  value: null,
114
124
  children: childrenState.childIds,
125
+ attributes: attributeState.getAttributes,
115
126
  },
116
127
  this.instanceConfig
117
128
  );
@@ -125,6 +136,7 @@ export class Root
125
136
  );
126
137
 
127
138
  childrenState.setChildren(buildChildren(this));
139
+ attributeState.setAttributes(buildAttributes(this));
128
140
  this.validationState = createAggregatedViolations(this, this.instanceConfig);
129
141
  this.instanceState = createRootInstanceState(this);
130
142
  }
@@ -133,6 +145,10 @@ export class Root
133
145
  return this.childrenState.getChildren();
134
146
  }
135
147
 
148
+ getAttributes(): readonly Attribute[] {
149
+ return this.attributeState.getAttributes();
150
+ }
151
+
136
152
  // RootNode
137
153
  setLanguage(language: FormLanguage): Root {
138
154
  this.rootDocument.setLanguage(language);
@@ -153,6 +153,7 @@ export class SelectControl
153
153
  label: createNodeLabel(this, definition),
154
154
  hint: createFieldHint(this, definition),
155
155
  children: null,
156
+ attributes: null,
156
157
  valueOptions,
157
158
  value: valueState,
158
159
  instanceValue: this.getInstanceValue,
@@ -100,6 +100,7 @@ export class TriggerControl
100
100
  label: createNodeLabel(this, definition),
101
101
  hint: createFieldHint(this, definition),
102
102
  children: null,
103
+ attributes: null,
103
104
  valueOptions: null,
104
105
  value: this.valueState,
105
106
  instanceValue: this.getInstanceValue,
@@ -9,6 +9,10 @@ import { UploadValueTypeError } from '../error/UploadValueTypeError.ts';
9
9
  import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
10
10
  import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
11
11
  import { createValueNodeInstanceState } from '../lib/client-reactivity/instance-state/createValueNodeInstanceState.ts';
12
+ import {
13
+ createAttributeState,
14
+ type AttributeState,
15
+ } from '../lib/reactivity/createAttributeState.ts';
12
16
  import { createInstanceAttachment } from '../lib/reactivity/createInstanceAttachment.ts';
13
17
  import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
14
18
  import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
@@ -20,6 +24,7 @@ import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
20
24
  import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
21
25
  import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
22
26
  import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
27
+ import type { Attribute } from './Attribute.ts';
23
28
  import type { Root } from './Root.ts';
24
29
  import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
25
30
  import { DescendantNode } from './abstract/DescendantNode.ts';
@@ -57,6 +62,7 @@ interface UploadControlStateSpec extends DescendantNodeStateSpec<InstanceAttachm
57
62
  readonly label: Accessor<TextRange<'label'> | null>;
58
63
  readonly hint: Accessor<TextRange<'hint'> | null>;
59
64
  readonly children: null;
65
+ readonly attributes: Accessor<readonly Attribute[]>;
60
66
  readonly valueOptions: null;
61
67
  readonly value: SimpleAtomicState<InstanceAttachmentRuntimeValue>;
62
68
  readonly instanceValue: Accessor<InstanceAttachmentFileName>;
@@ -95,6 +101,7 @@ export class UploadControl
95
101
 
96
102
  private readonly validation: SharedValidationState;
97
103
  private readonly instanceAttachment: InstanceAttachment;
104
+ private readonly attributeState: AttributeState;
98
105
 
99
106
  // XFormsXPathElement
100
107
  override readonly [XPathNodeKindKey] = 'element';
@@ -133,6 +140,8 @@ export class UploadControl
133
140
  const instanceAttachment = createInstanceAttachment(this);
134
141
 
135
142
  this.instanceAttachment = instanceAttachment;
143
+ const attributeState = createAttributeState(this.scope);
144
+ this.attributeState = attributeState;
136
145
  this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
137
146
  this.getXPathValue = instanceAttachment.getInstanceValue;
138
147
 
@@ -149,6 +158,7 @@ export class UploadControl
149
158
  children: null,
150
159
  valueOptions: null,
151
160
  value: instanceAttachment.valueState,
161
+ attributes: attributeState.getAttributes,
152
162
  instanceValue: instanceAttachment.getInstanceValue,
153
163
  },
154
164
  this.instanceConfig
@@ -181,4 +191,8 @@ export class UploadControl
181
191
 
182
192
  return this.root;
183
193
  }
194
+
195
+ getAttributes(): readonly Attribute[] {
196
+ return this.attributeState.getAttributes();
197
+ }
184
198
  }
@@ -167,7 +167,11 @@ export abstract class DescendantNode<
167
167
  return true;
168
168
  }
169
169
  }
170
-
170
+ for (const attr of parent.getAttributes()) {
171
+ if (attr === self) {
172
+ return true;
173
+ }
174
+ }
171
175
  return false;
172
176
  });
173
177
  });
@@ -13,6 +13,7 @@ import type {
13
13
  XFormsXPathPrimaryInstanceNodeKind,
14
14
  } from '../../integration/xpath/adapter/XFormsXPathNode.ts';
15
15
  import type { PrimaryInstanceXPathNode } from '../../integration/xpath/adapter/kind.ts';
16
+ import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
16
17
  import type { StaticDocument } from '../../integration/xpath/static-dom/StaticDocument.ts';
17
18
  import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
18
19
  import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
@@ -24,6 +25,7 @@ import { createReactiveScope } from '../../lib/reactivity/scope.ts';
24
25
  import type { SimpleAtomicState } from '../../lib/reactivity/types.ts';
25
26
  import { createUniqueId } from '../../lib/unique-id.ts';
26
27
  import type { AnyNodeDefinition } from '../../parse/model/NodeDefinition.ts';
28
+ import type { Attribute } from '../Attribute.ts';
27
29
  import type { PrimaryInstance } from '../PrimaryInstance.ts';
28
30
  import type { Root } from '../Root.ts';
29
31
  import type { AnyChildNode, AnyNode, AnyParentNode } from '../hierarchy.ts';
@@ -51,6 +53,7 @@ export interface InstanceNodeStateSpec<Value = never> {
51
53
  readonly label: Accessor<TextRange<'label'> | null> | null;
52
54
  readonly hint: Accessor<TextRange<'hint'> | null> | null;
53
55
  readonly children: Accessor<readonly FormNodeID[]> | null;
56
+ readonly attributes: Accessor<readonly Attribute[]> | null;
54
57
  readonly valueOptions: InstanceNodeValueOptionsStateSpec;
55
58
  readonly value: Signal<Value> | SimpleAtomicState<Value> | null;
56
59
  }
@@ -191,7 +194,7 @@ export abstract class InstanceNode<
191
194
  constructor(
192
195
  readonly instanceConfig: InstanceConfig,
193
196
  readonly parent: Parent,
194
- readonly instanceNode: StaticDocument | StaticElement | null,
197
+ readonly instanceNode: StaticAttribute | StaticDocument | StaticElement | null,
195
198
  readonly definition: Definition,
196
199
  options?: InstanceNodeOptions
197
200
  ) {
@@ -237,13 +240,13 @@ export abstract class InstanceNode<
237
240
  * (though for those nodes it will always be empty). This affords consistency
238
241
  * and efficiency of interface for those internal uses.
239
242
  */
240
- abstract getChildren(this: AnyInstanceNode): readonly AnyChildNode[];
243
+ abstract getChildren(this: AnyInstanceNode): ReadonlyArray<Exclude<AnyChildNode, Attribute>>;
241
244
 
242
245
  // XFormsXPathNode
243
246
  /**
244
247
  * @todo Values as text nodes(?)
245
248
  */
246
- getXPathChildNodes(): readonly AnyChildNode[] {
249
+ getXPathChildNodes(): ReadonlyArray<Exclude<AnyChildNode, Attribute>> {
247
250
  return (this as AnyInstanceNode).getChildren().flatMap((child) => {
248
251
  switch (child.nodeType) {
249
252
  case 'repeat-range:controlled':
@@ -36,6 +36,7 @@ export type ValueNodeDefinition<V extends ValueType> = LeafNodeDefinition<V>;
36
36
 
37
37
  export interface ValueNodeStateSpec<RuntimeValue> extends DescendantNodeStateSpec<RuntimeValue> {
38
38
  readonly children: null;
39
+ readonly attributes: null;
39
40
  readonly value: SimpleAtomicState<RuntimeValue>;
40
41
  readonly instanceValue: Accessor<string>;
41
42
  }
@@ -0,0 +1,8 @@
1
+ import { Attribute } from '../Attribute';
2
+ import type { AnyParentNode } from '../hierarchy';
3
+
4
+ export function buildAttributes(parent: AnyParentNode): Attribute[] {
5
+ return Array.from(parent.definition.attributes.values()).map((attributeDefinition) => {
6
+ return new Attribute(parent, attributeDefinition, attributeDefinition.template);
7
+ });
8
+ }
@@ -4,7 +4,6 @@ import type { InputDefinition } from '../../client/InputNode.ts';
4
4
  import type { ModelValueDefinition } from '../../client/ModelValueNode.ts';
5
5
  import type { RankDefinition } from '../../client/RankNode.ts';
6
6
  import type { SelectDefinition } from '../../client/SelectNode.ts';
7
- import type { SubtreeDefinition } from '../../client/SubtreeNode.ts';
8
7
  import type { TriggerNodeDefinition } from '../../client/TriggerNode.ts';
9
8
  import type { UploadDefinition } from '../../client/UploadNode.ts';
10
9
  import { ErrorProductionDesignPendingError } from '../../error/ErrorProductionDesignPendingError.ts';
@@ -15,7 +14,6 @@ import type {
15
14
  RangeLeafNodeDefinition,
16
15
  } from '../../parse/model/RangeNodeDefinition.ts';
17
16
  import { RangeNodeDefinition } from '../../parse/model/RangeNodeDefinition.ts';
18
- import type { SubtreeDefinition as ModelSubtreeDefinition } from '../../parse/model/SubtreeDefinition.ts';
19
17
  import { Group } from '../Group.ts';
20
18
  import type { GeneralChildNode, GeneralParentNode } from '../hierarchy.ts';
21
19
  import { InputControl } from '../InputControl.ts';
@@ -26,17 +24,10 @@ import { RankControl } from '../RankControl.ts';
26
24
  import { RepeatRangeControlled } from '../repeat/RepeatRangeControlled.ts';
27
25
  import { RepeatRangeUncontrolled } from '../repeat/RepeatRangeUncontrolled.ts';
28
26
  import { SelectControl } from '../SelectControl.ts';
29
- import { Subtree } from '../Subtree.ts';
30
27
  import { TriggerControl } from '../TriggerControl.ts';
31
28
  import { UploadControl } from '../UploadControl.ts';
32
29
  import { childrenInitOptions } from './childrenInitOptions.ts';
33
30
 
34
- const isSubtreeDefinition = (
35
- definition: ModelSubtreeDefinition
36
- ): definition is SubtreeDefinition => {
37
- return definition.bodyElement == null;
38
- };
39
-
40
31
  // prettier-ignore
41
32
  type ControlNodeDefinition =
42
33
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
@@ -131,14 +122,7 @@ export const buildChildren = (parent: GeneralParentNode): GeneralChildNode[] =>
131
122
  const [instanceNode = null] = instanceNodes;
132
123
 
133
124
  switch (definition.type) {
134
- case 'subtree': {
135
- if (isSubtreeDefinition(definition)) {
136
- return new Subtree(parent, instanceNode, definition);
137
- }
138
-
139
- // TODO: it'd be good to be able to do without this type assertion. The
140
- // only distinction between the types is whether `bodyElement` is
141
- // `null`, but for some reason that's insufficient to narrow the union.
125
+ case 'group': {
142
126
  return new Group(parent, instanceNode, definition as GroupDefinition);
143
127
  }
144
128
 
@@ -3,21 +3,19 @@ import {
3
3
  XFORMS_NAMESPACE_URI,
4
4
  } from '@getodk/common/constants/xmlns.ts';
5
5
  import type { GroupDefinition } from '../../client/GroupNode.ts';
6
- import type { SubtreeDefinition } from '../../client/SubtreeNode.ts';
7
6
  import { ErrorProductionDesignPendingError } from '../../error/ErrorProductionDesignPendingError.ts';
8
7
  import { StaticDocument } from '../../integration/xpath/static-dom/StaticDocument.ts';
9
8
  import type { StaticLeafElement } from '../../integration/xpath/static-dom/StaticElement.ts';
10
9
  import { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
11
10
  import type { NamespaceURL } from '../../lib/names/NamespaceURL.ts';
12
11
  import type { QualifiedName } from '../../lib/names/QualifiedName.ts';
12
+ import type { GroupDefinition as ModelGroupDefinition } from '../../parse/model/GroupDefinition.ts';
13
13
  import { LeafNodeDefinition } from '../../parse/model/LeafNodeDefinition.ts';
14
- import type { SubtreeDefinition as ModelSubtreeDefinition } from '../../parse/model/SubtreeDefinition.ts';
15
14
  import type { XFormDOM } from '../../parse/XFormDOM.ts';
16
15
  import type { Group } from '../Group.ts';
17
16
  import type { GeneralParentNode } from '../hierarchy.ts';
18
17
  import type { PrimaryInstance } from '../PrimaryInstance.ts';
19
18
  import type { Root } from '../Root.ts';
20
- import type { Subtree } from '../Subtree.ts';
21
19
  import type { ChildrenInitOptions } from './childrenInitOptions.ts';
22
20
  import type { DescendantNodeInitOptions } from './DescendantNodeInitOptions.ts';
23
21
 
@@ -65,21 +63,12 @@ interface BaseMetaDefinition {
65
63
  readonly qualifiedName: MetaName;
66
64
  }
67
65
 
68
- const isBaseMetaDefinition = <T extends ModelSubtreeDefinition>(
66
+ const isBaseMetaDefinition = <T extends ModelGroupDefinition>(
69
67
  definition: T
70
68
  ): definition is BaseMetaDefinition & T => {
71
69
  return isMetaName(definition.qualifiedName);
72
70
  };
73
71
 
74
- interface MetaSubtreeDefinition extends SubtreeDefinition {
75
- readonly qualifiedName: MetaName;
76
- }
77
-
78
- interface MetaSubtree extends Subtree {
79
- readonly parent: Root;
80
- readonly definition: MetaSubtreeDefinition;
81
- }
82
-
83
72
  interface MetaGroupDefinition extends GroupDefinition {
84
73
  readonly qualifiedName: MetaName;
85
74
  }
@@ -89,17 +78,15 @@ interface MetaGroup extends Group {
89
78
  readonly definition: MetaGroupDefinition;
90
79
  }
91
80
 
92
- type MetaSubroot = MetaGroup | MetaSubtree;
93
-
94
- interface MetaSubrootInitOptions extends ChildrenInitOptions {
95
- readonly parent: MetaGroup | MetaSubtree;
81
+ interface MetaGroupInitOptions extends ChildrenInitOptions {
82
+ readonly parent: MetaGroup;
96
83
  }
97
84
 
98
- const isMetaSubroot = (options: ChildrenInitOptions): options is MetaSubrootInitOptions => {
85
+ const isMetaGroup = (options: ChildrenInitOptions): options is MetaGroupInitOptions => {
99
86
  const { nodeType } = options.parent;
100
87
 
101
88
  return (
102
- (nodeType === 'subtree' || nodeType === 'group') &&
89
+ nodeType === 'group' &&
103
90
  isDirectRootDescendant(options.parent) &&
104
91
  isBaseMetaDefinition(options.parent.definition)
105
92
  );
@@ -119,16 +106,16 @@ interface EditModeInstanceDescendant {
119
106
  readonly rootDocument: EditModeInstance;
120
107
  }
121
108
 
122
- type EditModeMetaSubroot = EditModeInstanceDescendant & MetaSubroot;
109
+ type EditModeMetaGroup = EditModeInstanceDescendant & MetaGroup;
123
110
 
124
- interface EditModeMetaSubrootInitOptions extends MetaSubrootInitOptions {
125
- readonly parent: EditModeMetaSubroot;
111
+ interface EditModeMetaGroupInitOptions extends MetaGroupInitOptions {
112
+ readonly parent: EditModeMetaGroup;
126
113
  }
127
114
 
128
- const isEditModeMetaSubroot = (
129
- subroot: MetaSubrootInitOptions
130
- ): subroot is EditModeMetaSubrootInitOptions => {
131
- return isEditModeInstance(subroot.parent.rootDocument);
115
+ const isEditModeMetaGroup = (
116
+ group: MetaGroupInitOptions
117
+ ): group is EditModeMetaGroupInitOptions => {
118
+ return isEditModeInstance(group.parent.rootDocument);
132
119
  };
133
120
 
134
121
  interface LeafNodeInitOptions extends DescendantNodeInitOptions {
@@ -147,13 +134,13 @@ const isLeafNodeInitOptions = (
147
134
  type MetaLeafChildEntry = readonly [index: number, child: LeafNodeInitOptions];
148
135
 
149
136
  const findMetaLeafChild = (
150
- subroot: MetaSubrootInitOptions,
137
+ group: MetaGroupInitOptions,
151
138
  localName: string
152
139
  ): MetaLeafChildEntry | null => {
153
- const metaName = subroot.parent.definition.qualifiedName satisfies MetaName;
140
+ const metaName = group.parent.definition.qualifiedName satisfies MetaName;
154
141
  const namespaceURI = metaName.namespaceURI.href satisfies MetaNamespaceURIValue;
155
142
 
156
- const result = Array.from(subroot.children.entries()).find(
143
+ const result = Array.from(group.children.entries()).find(
157
144
  (entry): entry is [number, LeafNodeInitOptions] => {
158
145
  const [, child] = entry;
159
146
 
@@ -173,8 +160,8 @@ const findMetaLeafChild = (
173
160
  return result ?? null;
174
161
  };
175
162
 
176
- const getInstanceIDValue = (subroot: MetaSubrootInitOptions): string | null => {
177
- const [, child = null] = findMetaLeafChild(subroot, INSTANCE_ID_LOCAL_NAME) ?? [];
163
+ const getInstanceIDValue = (group: MetaGroupInitOptions): string | null => {
164
+ const [, child = null] = findMetaLeafChild(group, INSTANCE_ID_LOCAL_NAME) ?? [];
178
165
 
179
166
  if (child == null) {
180
167
  return null;
@@ -200,11 +187,11 @@ const assertStaticLeafElement: AssertStaticLeafElement = (element) => {
200
187
  * on {@link populateDeprecatedID}.
201
188
  */
202
189
  const buildMetaValueElement = (
203
- subroot: MetaSubrootInitOptions,
190
+ group: MetaGroupInitOptions,
204
191
  localName: string,
205
192
  value: string
206
193
  ): StaticLeafElement => {
207
- const { qualifiedName, nodeset } = subroot.parent.definition;
194
+ const { qualifiedName, nodeset } = group.parent.definition;
208
195
  const { namespaceURI, prefix } = qualifiedName;
209
196
  const { root } = new StaticDocument({
210
197
  documentRoot: {
@@ -224,21 +211,21 @@ const buildMetaValueElement = (
224
211
  };
225
212
 
226
213
  const buildDeprecatedIDDefinition = (
227
- subroot: EditModeMetaSubrootInitOptions,
214
+ group: EditModeMetaGroupInitOptions,
228
215
  instanceNode: StaticLeafElement
229
216
  ): LeafNodeDefinition => {
230
217
  const nodeset = instanceNode.nodeset;
231
- const bind = subroot.model.binds.getOrCreateBindDefinition(nodeset);
218
+ const bind = group.model.binds.getOrCreateBindDefinition(nodeset);
232
219
 
233
- return new LeafNodeDefinition(subroot.parent.definition, bind, null, instanceNode);
220
+ return new LeafNodeDefinition(group.parent.definition, bind, null, instanceNode);
234
221
  };
235
222
 
236
223
  const buildDeprecatedID = (
237
- subroot: EditModeMetaSubrootInitOptions,
224
+ group: EditModeMetaGroupInitOptions,
238
225
  value: string
239
226
  ): LeafNodeInitOptions => {
240
- const instanceNode = buildMetaValueElement(subroot, DEPRECATED_ID_LOCAL_NAME, value);
241
- const definition = buildDeprecatedIDDefinition(subroot, instanceNode);
227
+ const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
228
+ const definition = buildDeprecatedIDDefinition(group, instanceNode);
242
229
 
243
230
  return {
244
231
  childNodeset: instanceNode.nodeset,
@@ -248,11 +235,11 @@ const buildDeprecatedID = (
248
235
  };
249
236
 
250
237
  const updateDeprecatedID = (
251
- subroot: EditModeMetaSubrootInitOptions,
238
+ group: EditModeMetaGroupInitOptions,
252
239
  child: LeafNodeInitOptions,
253
240
  value: string
254
241
  ): LeafNodeInitOptions => {
255
- const instanceNode = buildMetaValueElement(subroot, DEPRECATED_ID_LOCAL_NAME, value);
242
+ const instanceNode = buildMetaValueElement(group, DEPRECATED_ID_LOCAL_NAME, value);
256
243
 
257
244
  return {
258
245
  childNodeset: child.childNodeset,
@@ -288,44 +275,42 @@ const replaceOrConcat = <T>(values: readonly T[], index: number | null, value: T
288
275
  * hacky normalization for `instanceID`.
289
276
  */
290
277
  const populateDeprecatedID = (
291
- subroot: EditModeMetaSubrootInitOptions
292
- ): EditModeMetaSubrootInitOptions => {
293
- const value = getInstanceIDValue(subroot);
278
+ group: EditModeMetaGroupInitOptions
279
+ ): EditModeMetaGroupInitOptions => {
280
+ const value = getInstanceIDValue(group);
294
281
 
295
282
  if (value == null) {
296
- return subroot;
283
+ return group;
297
284
  }
298
285
 
299
- const [index, currentDeprecatedID] = findMetaLeafChild(subroot, DEPRECATED_ID_LOCAL_NAME) ?? [
300
- null,
301
- ];
286
+ const [index, currentDeprecatedID] = findMetaLeafChild(group, DEPRECATED_ID_LOCAL_NAME) ?? [null];
302
287
 
303
288
  let deprecatedID: LeafNodeInitOptions;
304
289
 
305
290
  if (currentDeprecatedID == null) {
306
- deprecatedID = buildDeprecatedID(subroot, value);
291
+ deprecatedID = buildDeprecatedID(group, value);
307
292
  } else {
308
- deprecatedID = updateDeprecatedID(subroot, currentDeprecatedID, value);
293
+ deprecatedID = updateDeprecatedID(group, currentDeprecatedID, value);
309
294
  }
310
295
 
311
296
  return {
312
- model: subroot.model,
313
- parent: subroot.parent,
314
- children: replaceOrConcat(subroot.children, index, deprecatedID),
297
+ model: group.model,
298
+ parent: group.parent,
299
+ children: replaceOrConcat(group.children, index, deprecatedID),
315
300
  };
316
301
  };
317
302
 
318
- const normalizeMetaSubroot = (subroot: MetaSubrootInitOptions): MetaSubrootInitOptions => {
319
- if (isEditModeMetaSubroot(subroot)) {
320
- return populateDeprecatedID(subroot);
303
+ const normalizeMetaGroup = (group: MetaGroupInitOptions): MetaGroupInitOptions => {
304
+ if (isEditModeMetaGroup(group)) {
305
+ return populateDeprecatedID(group);
321
306
  }
322
307
 
323
- return subroot;
308
+ return group;
324
309
  };
325
310
 
326
311
  export const normalizeChildInitOptions = (options: ChildrenInitOptions): ChildrenInitOptions => {
327
- if (isMetaSubroot(options)) {
328
- return normalizeMetaSubroot(options);
312
+ if (isMetaGroup(options)) {
313
+ return normalizeMetaGroup(options);
329
314
  }
330
315
 
331
316
  return options;
@@ -1,3 +1,4 @@
1
+ import type { Attribute } from './Attribute.ts';
1
2
  import type { Group } from './Group.ts';
2
3
  import type { AnyInputControl } from './InputControl.ts';
3
4
  import type { AnyModelValue } from './ModelValue.ts';
@@ -10,7 +11,6 @@ import type { RepeatRangeControlled } from './repeat/RepeatRangeControlled.ts';
10
11
  import type { RepeatRangeUncontrolled } from './repeat/RepeatRangeUncontrolled.ts';
11
12
  import type { Root } from './Root.ts';
12
13
  import type { SelectControl } from './SelectControl.ts';
13
- import type { Subtree } from './Subtree.ts';
14
14
  import type { TriggerControl } from './TriggerControl.ts';
15
15
  import type { UploadControl } from './UploadControl.ts';
16
16
 
@@ -22,7 +22,6 @@ export type AnyNode =
22
22
  | PrimaryInstance
23
23
  | Root
24
24
  | Group
25
- | Subtree
26
25
  | RepeatRange
27
26
  | RepeatInstance
28
27
  | AnyNote
@@ -40,7 +39,6 @@ export type AnyParentNode =
40
39
  | PrimaryInstance
41
40
  | Root
42
41
  | Group
43
- | Subtree
44
42
  | RepeatRange
45
43
  | RepeatInstance;
46
44
 
@@ -49,7 +47,6 @@ export type GeneralParentNode =
49
47
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
50
48
  | Root
51
49
  | Group
52
- | Subtree
53
50
  | RepeatInstance;
54
51
 
55
52
  // prettier-ignore
@@ -57,7 +54,6 @@ export type AnyChildNode =
57
54
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
58
55
  | Root
59
56
  | Group
60
- | Subtree
61
57
  | RepeatRange
62
58
  | RepeatInstance
63
59
  | AnyModelValue
@@ -67,13 +63,13 @@ export type AnyChildNode =
67
63
  | RankControl
68
64
  | SelectControl
69
65
  | TriggerControl
70
- | UploadControl;
66
+ | UploadControl
67
+ | Attribute;
71
68
 
72
69
  // prettier-ignore
73
70
  export type GeneralChildNode =
74
71
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
75
72
  | Group
76
- | Subtree
77
73
  | RepeatRange
78
74
  | AnyModelValue
79
75
  | AnyNote
@@ -0,0 +1,34 @@
1
+ import type { FormInstanceInitializationMode } from '../../client/index.ts';
2
+ import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
3
+ import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
4
+ import type { BindComputationExpression } from '../../parse/expression/BindComputationExpression.ts';
5
+ import type { AnyBindPreloadDefinition } from '../../parse/model/BindPreloadDefinition.ts';
6
+ import type { EvaluationContext } from './EvaluationContext.ts';
7
+
8
+ export interface InstanceAttributeContextDocument {
9
+ readonly initializationMode: FormInstanceInitializationMode;
10
+ }
11
+
12
+ export type DecodeInstanceValue = (value: string) => string;
13
+
14
+ interface InstanceAttributeContextDefinitionBind {
15
+ readonly preload: AnyBindPreloadDefinition | null;
16
+ readonly calculate: BindComputationExpression<'calculate'> | null;
17
+ readonly readonly: BindComputationExpression<'readonly'>;
18
+ }
19
+
20
+ export interface InstanceAttributeContextDefinition {
21
+ readonly bind: InstanceAttributeContextDefinitionBind;
22
+ readonly template: StaticAttribute;
23
+ }
24
+
25
+ export interface AttributeContext extends EvaluationContext {
26
+ readonly scope: ReactiveScope;
27
+ readonly rootDocument: InstanceAttributeContextDocument;
28
+ readonly definition: InstanceAttributeContextDefinition;
29
+ readonly instanceNode: StaticAttribute;
30
+ readonly decodeInstanceValue: DecodeInstanceValue;
31
+
32
+ isReadonly(): boolean;
33
+ isRelevant(): boolean;
34
+ }
@@ -0,0 +1,19 @@
1
+ import type { InstanceState } from '../../../client/serialization/InstanceState.ts';
2
+ import type { QualifiedName } from '../../../lib/names/QualifiedName.ts';
3
+
4
+ export type SerializedInstanceValue = string;
5
+
6
+ interface ClientReactiveSerializableAttributeNodeCurrentState {
7
+ get relevant(): boolean;
8
+ get instanceValue(): SerializedInstanceValue;
9
+ }
10
+
11
+ interface ClientReactiveSerializableAttributeNodeDefinition {
12
+ readonly qualifiedName: QualifiedName;
13
+ }
14
+
15
+ export interface ClientReactiveSerializableAttributeNode {
16
+ readonly definition: ClientReactiveSerializableAttributeNodeDefinition;
17
+ readonly currentState: ClientReactiveSerializableAttributeNodeCurrentState;
18
+ readonly instanceState: InstanceState;
19
+ }
@@ -1,5 +1,6 @@
1
1
  import type { InstanceState } from '../../../client/serialization/InstanceState.ts';
2
2
  import type { QualifiedName } from '../../../lib/names/QualifiedName.ts';
3
+ import type { Attribute } from '../../Attribute.ts';
3
4
 
4
5
  export interface ClientReactiveSerializableChildNode {
5
6
  readonly instanceState: InstanceState;
@@ -10,6 +11,7 @@ export interface ClientReactiveSerializableParentNodeCurrentState<
10
11
  > {
11
12
  get relevant(): boolean;
12
13
  get children(): readonly Child[];
14
+ get attributes(): readonly Attribute[];
13
15
  }
14
16
 
15
17
  export interface ClientReactiveSerializableParentNodeDefinition {