@getodk/xforms-engine 0.1.1 → 0.3.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 (228) hide show
  1. package/dist/body/BodyDefinition.d.ts +24 -7
  2. package/dist/body/BodyElementDefinition.d.ts +4 -3
  3. package/dist/body/RepeatElementDefinition.d.ts +19 -0
  4. package/dist/body/appearance/inputAppearanceParser.d.ts +4 -0
  5. package/dist/body/appearance/selectAppearanceParser.d.ts +4 -0
  6. package/dist/body/appearance/structureElementAppearanceParser.d.ts +4 -0
  7. package/dist/body/control/ControlDefinition.d.ts +4 -2
  8. package/dist/body/control/InputDefinition.d.ts +5 -0
  9. package/dist/body/control/select/ItemDefinition.d.ts +2 -2
  10. package/dist/body/control/select/ItemsetDefinition.d.ts +5 -4
  11. package/dist/body/control/select/SelectDefinition.d.ts +11 -1
  12. package/dist/body/group/BaseGroupDefinition.d.ts +4 -9
  13. package/dist/body/group/PresentationGroupDefinition.d.ts +1 -1
  14. package/dist/client/BaseNode.d.ts +74 -3
  15. package/dist/client/GroupNode.d.ts +7 -2
  16. package/dist/client/ModelValueNode.d.ts +37 -0
  17. package/dist/client/NodeAppearances.d.ts +15 -0
  18. package/dist/client/NoteNode.d.ts +53 -0
  19. package/dist/client/RootNode.d.ts +21 -0
  20. package/dist/client/SelectNode.d.ts +8 -3
  21. package/dist/client/StringNode.d.ts +8 -3
  22. package/dist/client/SubtreeNode.d.ts +3 -0
  23. package/dist/client/TextRange.d.ts +85 -2
  24. package/dist/client/constants.d.ts +9 -0
  25. package/dist/client/hierarchy.d.ts +14 -9
  26. package/dist/client/node-types.d.ts +2 -1
  27. package/dist/client/{RepeatRangeNode.d.ts → repeat/BaseRepeatRangeNode.d.ts} +19 -15
  28. package/dist/client/{RepeatInstanceNode.d.ts → repeat/RepeatInstanceNode.d.ts} +11 -7
  29. package/dist/client/repeat/RepeatRangeControlledNode.d.ts +19 -0
  30. package/dist/client/repeat/RepeatRangeUncontrolledNode.d.ts +20 -0
  31. package/dist/client/validation.d.ts +163 -0
  32. package/dist/expression/DependentExpression.d.ts +12 -8
  33. package/dist/index.d.ts +9 -4
  34. package/dist/index.js +3173 -960
  35. package/dist/index.js.map +1 -1
  36. package/dist/instance/Group.d.ts +6 -4
  37. package/dist/instance/ModelValue.d.ts +40 -0
  38. package/dist/instance/Note.d.ts +42 -0
  39. package/dist/instance/Root.d.ts +10 -23
  40. package/dist/instance/SelectField.d.ts +12 -6
  41. package/dist/instance/StringField.d.ts +13 -7
  42. package/dist/instance/Subtree.d.ts +3 -1
  43. package/dist/instance/abstract/DescendantNode.d.ts +16 -9
  44. package/dist/instance/abstract/InstanceNode.d.ts +28 -29
  45. package/dist/instance/hierarchy.d.ts +10 -5
  46. package/dist/instance/internal-api/EvaluationContext.d.ts +5 -4
  47. package/dist/instance/internal-api/ValidationContext.d.ts +21 -0
  48. package/dist/instance/internal-api/ValueContext.d.ts +2 -2
  49. package/dist/instance/repeat/BaseRepeatRange.d.ts +160 -0
  50. package/dist/instance/{RepeatInstance.d.ts → repeat/RepeatInstance.d.ts} +38 -13
  51. package/dist/instance/repeat/RepeatRangeControlled.d.ts +16 -0
  52. package/dist/instance/repeat/RepeatRangeUncontrolled.d.ts +35 -0
  53. package/dist/instance/text/TextRange.d.ts +4 -4
  54. package/dist/lib/TokenListParser.d.ts +84 -0
  55. package/dist/lib/dom/query.d.ts +5 -0
  56. package/dist/lib/reactivity/createComputedExpression.d.ts +6 -1
  57. package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +5 -0
  58. package/dist/lib/reactivity/materializeCurrentStateChildren.d.ts +2 -1
  59. package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +1 -1
  60. package/dist/lib/reactivity/node-state/createSpecifiedState.d.ts +1 -1
  61. package/dist/lib/reactivity/text/createFieldHint.d.ts +3 -3
  62. package/dist/lib/reactivity/text/createNodeLabel.d.ts +2 -2
  63. package/dist/lib/reactivity/text/createNoteText.d.ts +25 -0
  64. package/dist/lib/reactivity/text/createTextRange.d.ts +5 -7
  65. package/dist/lib/reactivity/validation/createAggregatedViolations.d.ts +9 -0
  66. package/dist/lib/reactivity/validation/createValidation.d.ts +18 -0
  67. package/dist/model/BindDefinition.d.ts +4 -2
  68. package/dist/model/BindElement.d.ts +1 -0
  69. package/dist/model/DescendentNodeDefinition.d.ts +1 -2
  70. package/dist/model/{ValueNodeDefinition.d.ts → LeafNodeDefinition.d.ts} +3 -4
  71. package/dist/model/NodeDefinition.d.ts +16 -16
  72. package/dist/model/RepeatInstanceDefinition.d.ts +5 -6
  73. package/dist/model/RepeatRangeDefinition.d.ts +30 -0
  74. package/dist/model/RepeatTemplateDefinition.d.ts +6 -7
  75. package/dist/model/RootDefinition.d.ts +3 -1
  76. package/dist/model/SubtreeDefinition.d.ts +2 -2
  77. package/dist/parse/NoteNodeDefinition.d.ts +31 -0
  78. package/dist/parse/expression/RepeatCountControlExpression.d.ts +19 -0
  79. package/dist/parse/text/HintDefinition.d.ts +9 -0
  80. package/dist/parse/text/ItemLabelDefinition.d.ts +9 -0
  81. package/dist/parse/text/ItemsetLabelDefinition.d.ts +13 -0
  82. package/dist/parse/text/LabelDefinition.d.ts +15 -0
  83. package/dist/parse/text/MessageDefinition.d.ts +15 -0
  84. package/dist/parse/text/OutputChunkDefinition.d.ts +8 -0
  85. package/dist/parse/text/ReferenceChunkDefinition.d.ts +8 -0
  86. package/dist/parse/text/StaticTextChunkDefinition.d.ts +10 -0
  87. package/dist/parse/text/TranslationChunkDefinition.d.ts +9 -0
  88. package/dist/parse/text/abstract/TextChunkDefinition.d.ts +18 -0
  89. package/dist/parse/text/abstract/TextElementDefinition.d.ts +23 -0
  90. package/dist/parse/text/abstract/TextRangeDefinition.d.ts +35 -0
  91. package/dist/parse/xpath/dependency-analysis.d.ts +40 -0
  92. package/dist/parse/xpath/path-resolution.d.ts +70 -0
  93. package/dist/parse/xpath/predicate-analysis.d.ts +30 -0
  94. package/dist/parse/xpath/reference-parsing.d.ts +18 -0
  95. package/dist/parse/xpath/semantic-analysis.d.ts +98 -0
  96. package/dist/parse/xpath/syntax-traversal.d.ts +69 -0
  97. package/dist/solid.js +3174 -961
  98. package/dist/solid.js.map +1 -1
  99. package/package.json +14 -15
  100. package/src/XFormDOM.ts +81 -8
  101. package/src/body/BodyDefinition.ts +38 -23
  102. package/src/body/BodyElementDefinition.ts +4 -3
  103. package/src/body/RepeatElementDefinition.ts +58 -0
  104. package/src/body/appearance/inputAppearanceParser.ts +39 -0
  105. package/src/body/appearance/selectAppearanceParser.ts +38 -0
  106. package/src/body/appearance/structureElementAppearanceParser.ts +7 -0
  107. package/src/body/control/ControlDefinition.ts +8 -3
  108. package/src/body/control/InputDefinition.ts +13 -0
  109. package/src/body/control/select/ItemDefinition.ts +3 -3
  110. package/src/body/control/select/ItemsetDefinition.ts +29 -12
  111. package/src/body/control/select/ItemsetNodesetExpression.ts +1 -1
  112. package/src/body/control/select/SelectDefinition.ts +14 -5
  113. package/src/body/group/BaseGroupDefinition.ts +14 -51
  114. package/src/body/group/PresentationGroupDefinition.ts +1 -1
  115. package/src/client/BaseNode.ts +82 -8
  116. package/src/client/GroupNode.ts +8 -2
  117. package/src/client/ModelValueNode.ts +40 -0
  118. package/src/client/NodeAppearances.ts +22 -0
  119. package/src/client/NoteNode.ts +74 -0
  120. package/src/client/README.md +1 -0
  121. package/src/client/RootNode.ts +24 -0
  122. package/src/client/SelectNode.ts +9 -3
  123. package/src/client/StringNode.ts +9 -3
  124. package/src/client/SubtreeNode.ts +3 -0
  125. package/src/client/TextRange.ts +99 -2
  126. package/src/client/constants.ts +10 -0
  127. package/src/client/hierarchy.ts +30 -14
  128. package/src/client/node-types.ts +8 -1
  129. package/src/client/{RepeatRangeNode.ts → repeat/BaseRepeatRangeNode.ts} +20 -17
  130. package/src/client/{RepeatInstanceNode.ts → repeat/RepeatInstanceNode.ts} +13 -7
  131. package/src/client/repeat/RepeatRangeControlledNode.ts +20 -0
  132. package/src/client/repeat/RepeatRangeUncontrolledNode.ts +21 -0
  133. package/src/client/validation.ts +199 -0
  134. package/src/expression/DependentExpression.ts +45 -27
  135. package/src/index.ts +15 -8
  136. package/src/instance/Group.ts +24 -13
  137. package/src/instance/ModelValue.ts +104 -0
  138. package/src/instance/Note.ts +142 -0
  139. package/src/instance/Root.ts +29 -67
  140. package/src/instance/SelectField.ts +35 -13
  141. package/src/instance/StringField.ts +40 -13
  142. package/src/instance/Subtree.ts +19 -10
  143. package/src/instance/abstract/DescendantNode.ts +50 -49
  144. package/src/instance/abstract/InstanceNode.ts +89 -92
  145. package/src/instance/children.ts +47 -10
  146. package/src/instance/hierarchy.ts +21 -2
  147. package/src/instance/index.ts +1 -1
  148. package/src/instance/internal-api/EvaluationContext.ts +5 -6
  149. package/src/instance/internal-api/ValidationContext.ts +23 -0
  150. package/src/instance/internal-api/ValueContext.ts +2 -2
  151. package/src/instance/repeat/BaseRepeatRange.ts +347 -0
  152. package/src/instance/{RepeatInstance.ts → repeat/RepeatInstance.ts} +85 -36
  153. package/src/instance/repeat/RepeatRangeControlled.ts +82 -0
  154. package/src/instance/repeat/RepeatRangeUncontrolled.ts +67 -0
  155. package/src/instance/text/TextRange.ts +10 -4
  156. package/src/lib/TokenListParser.ts +156 -0
  157. package/src/lib/dom/query.ts +13 -0
  158. package/src/lib/reactivity/createChildrenState.ts +51 -6
  159. package/src/lib/reactivity/createComputedExpression.ts +23 -25
  160. package/src/lib/reactivity/createNoteReadonlyThunk.ts +33 -0
  161. package/src/lib/reactivity/createSelectItems.ts +25 -20
  162. package/src/lib/reactivity/createValueState.ts +6 -6
  163. package/src/lib/reactivity/materializeCurrentStateChildren.ts +3 -1
  164. package/src/lib/reactivity/node-state/createSharedNodeState.ts +1 -1
  165. package/src/lib/reactivity/text/createFieldHint.ts +9 -7
  166. package/src/lib/reactivity/text/createNodeLabel.ts +7 -5
  167. package/src/lib/reactivity/text/createNoteText.ts +72 -0
  168. package/src/lib/reactivity/text/createTextRange.ts +17 -90
  169. package/src/lib/reactivity/validation/createAggregatedViolations.ts +70 -0
  170. package/src/lib/reactivity/validation/createValidation.ts +196 -0
  171. package/src/model/BindComputation.ts +0 -4
  172. package/src/model/BindDefinition.ts +8 -6
  173. package/src/model/BindElement.ts +1 -0
  174. package/src/model/DescendentNodeDefinition.ts +1 -2
  175. package/src/model/{ValueNodeDefinition.ts → LeafNodeDefinition.ts} +5 -6
  176. package/src/model/ModelBindMap.ts +4 -0
  177. package/src/model/ModelDefinition.ts +1 -1
  178. package/src/model/NodeDefinition.ts +21 -21
  179. package/src/model/RepeatInstanceDefinition.ts +8 -13
  180. package/src/model/RepeatRangeDefinition.ts +94 -0
  181. package/src/model/RepeatTemplateDefinition.ts +10 -15
  182. package/src/model/RootDefinition.ts +12 -14
  183. package/src/model/SubtreeDefinition.ts +3 -3
  184. package/src/parse/NoteNodeDefinition.ts +70 -0
  185. package/src/parse/TODO.md +3 -0
  186. package/src/parse/expression/RepeatCountControlExpression.ts +44 -0
  187. package/src/parse/text/HintDefinition.ts +25 -0
  188. package/src/parse/text/ItemLabelDefinition.ts +25 -0
  189. package/src/parse/text/ItemsetLabelDefinition.ts +44 -0
  190. package/src/parse/text/LabelDefinition.ts +61 -0
  191. package/src/parse/text/MessageDefinition.ts +49 -0
  192. package/src/parse/text/OutputChunkDefinition.ts +25 -0
  193. package/src/parse/text/ReferenceChunkDefinition.ts +14 -0
  194. package/src/parse/text/StaticTextChunkDefinition.ts +19 -0
  195. package/src/parse/text/TranslationChunkDefinition.ts +38 -0
  196. package/src/parse/text/abstract/TextChunkDefinition.ts +38 -0
  197. package/src/parse/text/abstract/TextElementDefinition.ts +71 -0
  198. package/src/parse/text/abstract/TextRangeDefinition.ts +70 -0
  199. package/src/parse/xpath/dependency-analysis.ts +105 -0
  200. package/src/parse/xpath/path-resolution.ts +475 -0
  201. package/src/parse/xpath/predicate-analysis.ts +61 -0
  202. package/src/parse/xpath/reference-parsing.ts +90 -0
  203. package/src/parse/xpath/semantic-analysis.ts +466 -0
  204. package/src/parse/xpath/syntax-traversal.ts +129 -0
  205. package/dist/body/RepeatDefinition.d.ts +0 -16
  206. package/dist/body/group/RepeatGroupDefinition.d.ts +0 -13
  207. package/dist/body/text/HintDefinition.d.ts +0 -11
  208. package/dist/body/text/LabelDefinition.d.ts +0 -20
  209. package/dist/body/text/TextElementDefinition.d.ts +0 -33
  210. package/dist/body/text/TextElementOutputPart.d.ts +0 -13
  211. package/dist/body/text/TextElementPart.d.ts +0 -13
  212. package/dist/body/text/TextElementReferencePart.d.ts +0 -7
  213. package/dist/body/text/TextElementStaticPart.d.ts +0 -7
  214. package/dist/instance/RepeatRange.d.ts +0 -80
  215. package/dist/lib/xpath/analysis.d.ts +0 -23
  216. package/dist/model/RepeatSequenceDefinition.d.ts +0 -20
  217. package/src/body/RepeatDefinition.ts +0 -54
  218. package/src/body/group/RepeatGroupDefinition.ts +0 -91
  219. package/src/body/text/HintDefinition.ts +0 -26
  220. package/src/body/text/LabelDefinition.ts +0 -54
  221. package/src/body/text/TextElementDefinition.ts +0 -97
  222. package/src/body/text/TextElementOutputPart.ts +0 -27
  223. package/src/body/text/TextElementPart.ts +0 -31
  224. package/src/body/text/TextElementReferencePart.ts +0 -21
  225. package/src/body/text/TextElementStaticPart.ts +0 -26
  226. package/src/instance/RepeatRange.ts +0 -214
  227. package/src/lib/xpath/analysis.ts +0 -241
  228. package/src/model/RepeatSequenceDefinition.ts +0 -53
@@ -1,12 +1,12 @@
1
1
  import type { AnyBodyElementDefinition } from '../body/BodyDefinition.ts';
2
- import type { RepeatDefinition } from '../body/RepeatDefinition.ts';
2
+ import type { RepeatElementDefinition } from '../body/RepeatElementDefinition.ts';
3
3
  import type { BindDefinition } from './BindDefinition.ts';
4
+ import type { LeafNodeDefinition } from './LeafNodeDefinition.ts';
4
5
  import type { RepeatInstanceDefinition } from './RepeatInstanceDefinition.ts';
5
- import type { RepeatSequenceDefinition } from './RepeatSequenceDefinition.ts';
6
+ import type { AnyRepeatRangeDefinition } from './RepeatRangeDefinition.ts';
6
7
  import type { RepeatTemplateDefinition } from './RepeatTemplateDefinition.ts';
7
8
  import type { RootDefinition } from './RootDefinition.ts';
8
9
  import type { SubtreeDefinition } from './SubtreeDefinition.ts';
9
- import type { ValueNodeDefinition } from './ValueNodeDefinition.ts';
10
10
 
11
11
  /**
12
12
  * Corresponds to the model/entry DOM root node, i.e.:
@@ -17,13 +17,13 @@ import type { ValueNodeDefinition } from './ValueNodeDefinition.ts';
17
17
  export type RootNodeType = 'root';
18
18
 
19
19
  /**
20
- * Corresponds to a sequence of model/entry DOM subtrees which in turn
20
+ * Corresponds to a range/sequence of model/entry DOM subtrees which in turn
21
21
  * corresponds to a <repeat> in the form body definition.
22
22
  */
23
- export type RepeatSequenceType = 'repeat-sequence';
23
+ export type RepeatRangeType = 'repeat-range';
24
24
 
25
25
  /**
26
- * Corresponds to a template definition for a repeat sequence, which either has
26
+ * Corresponds to a template definition for a repeat range, which either has
27
27
  * an explicit `jr:template=""` attribute in the form definition or is inferred
28
28
  * as a template from the form's first element matched by a <repeat nodeset>.
29
29
  */
@@ -32,7 +32,7 @@ export type RepeatTemplateType = 'repeat-template';
32
32
  /**
33
33
  * Corresponds to a single instance of a model/entry DOM subtree which
34
34
  * in turn corresponds to a <repeat> in the form body definition, and a
35
- * 'repeat-sequence' definition.
35
+ * 'repeat-range' definition.
36
36
  */
37
37
  export type RepeatInstanceType = 'repeat-instance';
38
38
 
@@ -49,17 +49,17 @@ export type SubtreeNodeType = 'subtree';
49
49
  * - An element with no child elements
50
50
  * - Any attribute corresponding to a bind's `nodeset` expression
51
51
  */
52
- export type ValueNodeType = 'value-node';
52
+ export type LeafNodeType = 'leaf-node';
53
53
 
54
54
  // prettier-ignore
55
55
  export type NodeDefinitionType =
56
56
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
57
57
  | RootNodeType
58
- | RepeatSequenceType
58
+ | RepeatRangeType
59
59
  | RepeatTemplateType
60
60
  | RepeatInstanceType
61
61
  | SubtreeNodeType
62
- | ValueNodeType;
62
+ | LeafNodeType;
63
63
 
64
64
  // prettier-ignore
65
65
  export type ParentNodeDefinition =
@@ -71,9 +71,9 @@ export type ParentNodeDefinition =
71
71
 
72
72
  // prettier-ignore
73
73
  export type ChildNodeDefinition =
74
- | RepeatSequenceDefinition
75
- | SubtreeDefinition
76
- | ValueNodeDefinition;
74
+ | AnyRepeatRangeDefinition
75
+ | LeafNodeDefinition
76
+ | SubtreeDefinition;
77
77
 
78
78
  // prettier-ignore
79
79
  export type ChildNodeInstanceDefinition =
@@ -81,7 +81,7 @@ export type ChildNodeInstanceDefinition =
81
81
  | RepeatTemplateDefinition
82
82
  | RepeatInstanceDefinition
83
83
  | SubtreeDefinition
84
- | ValueNodeDefinition;
84
+ | LeafNodeDefinition;
85
85
 
86
86
  // prettier-ignore
87
87
  export type NodeChildren<Type extends NodeDefinitionType> =
@@ -91,7 +91,7 @@ export type NodeChildren<Type extends NodeDefinitionType> =
91
91
 
92
92
  // prettier-ignore
93
93
  export type NodeInstances<Type extends NodeDefinitionType> =
94
- Type extends 'repeat-sequence'
94
+ Type extends 'repeat-range'
95
95
  ? readonly RepeatInstanceDefinition[]
96
96
  : null;
97
97
 
@@ -101,16 +101,16 @@ export type NodeParent<Type extends NodeDefinitionType> =
101
101
  ? ParentNodeDefinition
102
102
  : null;
103
103
 
104
- // TODO: value-node may be Attr
104
+ // TODO: leaf-node may be Attr
105
105
  // prettier-ignore
106
106
  export type ModelNode<Type extends NodeDefinitionType> =
107
- Type extends 'repeat-sequence'
107
+ Type extends 'repeat-range'
108
108
  ? null
109
109
  : Element;
110
110
 
111
111
  // prettier-ignore
112
112
  export type NodeDefaultValue<Type extends NodeDefinitionType> =
113
- Type extends 'value-node'
113
+ Type extends 'leaf-node'
114
114
  ? string
115
115
  : null;
116
116
 
@@ -120,7 +120,7 @@ export interface NodeDefinition<Type extends NodeDefinitionType> {
120
120
  readonly bind: BindDefinition;
121
121
  readonly nodeset: string;
122
122
  readonly nodeName: string;
123
- readonly bodyElement: AnyBodyElementDefinition | RepeatDefinition | null;
123
+ readonly bodyElement: AnyBodyElementDefinition | RepeatElementDefinition | null;
124
124
 
125
125
  readonly isTranslated: boolean;
126
126
  readonly dependencyExpressions: ReadonlySet<string>;
@@ -137,10 +137,10 @@ export interface NodeDefinition<Type extends NodeDefinitionType> {
137
137
  export type AnyNodeDefinition =
138
138
  // eslint-disable-next-line @typescript-eslint/sort-type-constituents
139
139
  | RootDefinition
140
- | RepeatSequenceDefinition
140
+ | AnyRepeatRangeDefinition
141
141
  | RepeatTemplateDefinition
142
142
  | RepeatInstanceDefinition
143
143
  | SubtreeDefinition
144
- | ValueNodeDefinition;
144
+ | LeafNodeDefinition;
145
145
 
146
146
  export type TypedNodeDefinition<Type> = Extract<AnyNodeDefinition, { readonly type: Type }>;
@@ -1,10 +1,10 @@
1
- import { RepeatDefinition } from '../body/RepeatDefinition.ts';
1
+ import { RepeatElementDefinition } from '../body/RepeatElementDefinition.ts';
2
2
  import { DescendentNodeDefinition } from './DescendentNodeDefinition.ts';
3
3
  import type { ChildNodeDefinition, NodeDefinition } from './NodeDefinition.ts';
4
- import type { RepeatSequenceDefinition } from './RepeatSequenceDefinition.ts';
4
+ import type { AnyRepeatRangeDefinition } from './RepeatRangeDefinition.ts';
5
5
 
6
6
  export class RepeatInstanceDefinition
7
- extends DescendentNodeDefinition<'repeat-instance', RepeatDefinition>
7
+ extends DescendentNodeDefinition<'repeat-instance', RepeatElementDefinition>
8
8
  implements NodeDefinition<'repeat-instance'>
9
9
  {
10
10
  readonly type = 'repeat-instance';
@@ -15,24 +15,19 @@ export class RepeatInstanceDefinition
15
15
  readonly defaultValue = null;
16
16
 
17
17
  constructor(
18
- protected readonly sequence: RepeatSequenceDefinition,
18
+ range: AnyRepeatRangeDefinition,
19
19
  readonly node: Element
20
20
  ) {
21
- const {
22
- bind,
23
- bodyElement: repeatGroupBodyElement,
24
- parent: repeatSequenceParent,
25
- root,
26
- } = sequence;
21
+ const { bind, bodyElement, parent, root } = range;
27
22
 
28
- super(repeatSequenceParent, bind, repeatGroupBodyElement.repeat);
23
+ super(parent, bind, bodyElement);
29
24
 
30
- this.nodeName = sequence.nodeName;
25
+ this.nodeName = range.nodeName;
31
26
  this.children = root.buildSubtree(this);
32
27
  }
33
28
 
34
29
  toJSON() {
35
- const { bind, bodyElement, parent, root, sequence, ...rest } = this;
30
+ const { bind, bodyElement, parent, root, ...rest } = this;
36
31
 
37
32
  return rest;
38
33
  }
@@ -0,0 +1,94 @@
1
+ import type { RepeatElementDefinition } from '../body/RepeatElementDefinition.ts';
2
+ import { RepeatCountControlExpression } from '../parse/expression/RepeatCountControlExpression.ts';
3
+ import type { BindDefinition } from './BindDefinition.ts';
4
+ import { DescendentNodeDefinition } from './DescendentNodeDefinition.ts';
5
+ import type { NodeDefinition, ParentNodeDefinition } from './NodeDefinition.ts';
6
+ import { RepeatInstanceDefinition } from './RepeatInstanceDefinition.ts';
7
+ import { RepeatTemplateDefinition } from './RepeatTemplateDefinition.ts';
8
+
9
+ export interface ControlledRepeatRangeDefinition extends RepeatRangeDefinition {
10
+ readonly count: RepeatCountControlExpression;
11
+ }
12
+
13
+ export interface UncontrolledRepeatRangeDefinition extends RepeatRangeDefinition {
14
+ readonly count: null;
15
+ }
16
+
17
+ // prettier-ignore
18
+ export type AnyRepeatRangeDefinition =
19
+ | ControlledRepeatRangeDefinition
20
+ | UncontrolledRepeatRangeDefinition;
21
+
22
+ type AssertRepeatRangeDefinitionUnion = (
23
+ definition: RepeatRangeDefinition
24
+ ) => asserts definition is AnyRepeatRangeDefinition;
25
+
26
+ const assertRepeatRangeDefinitionUnion: AssertRepeatRangeDefinitionUnion = (_definition) => {
27
+ // Intentional no-op, used to guide the type checker. Implementation would
28
+ // check _definition.count == null || _definition.count != null, which is
29
+ // tautologically true!
30
+ };
31
+
32
+ export class RepeatRangeDefinition
33
+ extends DescendentNodeDefinition<'repeat-range', RepeatElementDefinition>
34
+ implements NodeDefinition<'repeat-range'>
35
+ {
36
+ static from(
37
+ parent: ParentNodeDefinition,
38
+ bind: BindDefinition,
39
+ bodyElement: RepeatElementDefinition,
40
+ modelNodes: readonly [Element, ...Element[]]
41
+ ): AnyRepeatRangeDefinition {
42
+ const definition = new this(parent, bind, bodyElement, modelNodes);
43
+
44
+ assertRepeatRangeDefinitionUnion(definition);
45
+
46
+ return definition;
47
+ }
48
+
49
+ readonly type = 'repeat-range';
50
+
51
+ readonly template: RepeatTemplateDefinition;
52
+ readonly children = null;
53
+ readonly instances: RepeatInstanceDefinition[];
54
+ readonly count: RepeatCountControlExpression | null;
55
+
56
+ readonly node = null;
57
+ readonly nodeName: string;
58
+ readonly defaultValue = null;
59
+
60
+ private constructor(
61
+ parent: ParentNodeDefinition,
62
+ bind: BindDefinition,
63
+ bodyElement: RepeatElementDefinition,
64
+ modelNodes: readonly [Element, ...Element[]]
65
+ ) {
66
+ super(parent, bind, bodyElement);
67
+
68
+ const { template, instanceNodes } = RepeatTemplateDefinition.parseModelNodes(this, modelNodes);
69
+
70
+ this.template = template;
71
+ this.nodeName = template.nodeName;
72
+ this.count = RepeatCountControlExpression.from(bodyElement, instanceNodes.length);
73
+
74
+ assertRepeatRangeDefinitionUnion(this);
75
+
76
+ this.instances = instanceNodes.map((element) => {
77
+ return new RepeatInstanceDefinition(this, element);
78
+ });
79
+ }
80
+
81
+ isControlled(): this is ControlledRepeatRangeDefinition {
82
+ return this.count != null;
83
+ }
84
+
85
+ isUncontrolled(): this is UncontrolledRepeatRangeDefinition {
86
+ return this.count == null;
87
+ }
88
+
89
+ toJSON() {
90
+ const { bind, bodyElement: groupDefinition, parent, root, ...rest } = this;
91
+
92
+ return rest;
93
+ }
94
+ }
@@ -1,9 +1,9 @@
1
1
  import { JAVAROSA_NAMESPACE_URI } from '@getodk/common/constants/xmlns.ts';
2
- import type { RepeatDefinition } from '../body/RepeatDefinition.ts';
2
+ import type { RepeatElementDefinition } from '../body/RepeatElementDefinition.ts';
3
3
  import { BindDefinition } from './BindDefinition.ts';
4
4
  import { DescendentNodeDefinition } from './DescendentNodeDefinition.ts';
5
5
  import type { ChildNodeDefinition, NodeDefinition } from './NodeDefinition.ts';
6
- import type { RepeatSequenceDefinition } from './RepeatSequenceDefinition.ts';
6
+ import type { RepeatRangeDefinition } from './RepeatRangeDefinition.ts';
7
7
 
8
8
  const repeatTemplates = new WeakMap<BindDefinition, RepeatTemplateDefinition>();
9
9
 
@@ -73,14 +73,14 @@ interface ParsedRepeatNodes {
73
73
  }
74
74
 
75
75
  export class RepeatTemplateDefinition
76
- extends DescendentNodeDefinition<'repeat-template', RepeatDefinition>
76
+ extends DescendentNodeDefinition<'repeat-template', RepeatElementDefinition>
77
77
  implements NodeDefinition<'repeat-template'>
78
78
  {
79
79
  static parseModelNodes(
80
- sequence: RepeatSequenceDefinition,
80
+ range: RepeatRangeDefinition,
81
81
  modelNodes: readonly [Element, ...Element[]]
82
82
  ): ParsedRepeatNodes {
83
- const { bind } = sequence;
83
+ const { bind } = range;
84
84
 
85
85
  let template = repeatTemplates.get(bind);
86
86
  let instanceNodes: readonly Element[];
@@ -89,7 +89,7 @@ export class RepeatTemplateDefinition
89
89
  const [templateNode, ...rest] = splitInstanceNodes(modelNodes);
90
90
 
91
91
  instanceNodes = rest;
92
- template = new this(sequence, templateNode);
92
+ template = new this(range, templateNode);
93
93
  } else {
94
94
  // TODO: this is under the assumption that for any depth > 1, if a
95
95
  // template has already been defined for the given form definition, any
@@ -121,17 +121,12 @@ export class RepeatTemplateDefinition
121
121
  readonly defaultValue = null;
122
122
 
123
123
  protected constructor(
124
- protected readonly sequence: RepeatSequenceDefinition,
124
+ range: RepeatRangeDefinition,
125
125
  protected readonly templateNode: ExplicitRepeatTemplateElement
126
126
  ) {
127
- const {
128
- bind,
129
- bodyElement: repeatGroupBodyElement,
130
- parent: repeatSequenceParent,
131
- root,
132
- } = sequence;
127
+ const { bind, bodyElement, parent, root } = range;
133
128
 
134
- super(repeatSequenceParent, bind, repeatGroupBodyElement.repeat);
129
+ super(parent, bind, bodyElement);
135
130
 
136
131
  const node = templateNode.cloneNode(true) as Element;
137
132
 
@@ -143,7 +138,7 @@ export class RepeatTemplateDefinition
143
138
  }
144
139
 
145
140
  toJSON() {
146
- const { bind, bodyElement, parent, root, sequence, ...rest } = this;
141
+ const { bind, bodyElement, parent, root, ...rest } = this;
147
142
 
148
143
  return rest;
149
144
  }
@@ -1,15 +1,16 @@
1
1
  import type { XFormDefinition } from '../XFormDefinition.ts';
2
- import type { RepeatGroupDefinition } from '../body/group/RepeatGroupDefinition.ts';
2
+ import type { BodyClassList } from '../body/BodyDefinition.ts';
3
+ import { NoteNodeDefinition } from '../parse/NoteNodeDefinition.ts';
3
4
  import type { BindDefinition } from './BindDefinition.ts';
5
+ import { LeafNodeDefinition } from './LeafNodeDefinition.ts';
4
6
  import type { ModelDefinition } from './ModelDefinition.ts';
5
7
  import type {
6
8
  ChildNodeDefinition,
7
9
  NodeDefinition,
8
10
  ParentNodeDefinition,
9
11
  } from './NodeDefinition.ts';
10
- import { RepeatSequenceDefinition } from './RepeatSequenceDefinition.ts';
12
+ import { RepeatRangeDefinition } from './RepeatRangeDefinition.ts';
11
13
  import { SubtreeDefinition } from './SubtreeDefinition.ts';
12
- import { ValueNodeDefinition } from './ValueNodeDefinition.ts';
13
14
 
14
15
  export class RootDefinition implements NodeDefinition<'root'> {
15
16
  readonly type = 'root';
@@ -29,7 +30,8 @@ export class RootDefinition implements NodeDefinition<'root'> {
29
30
 
30
31
  constructor(
31
32
  protected readonly form: XFormDefinition,
32
- protected readonly model: ModelDefinition
33
+ protected readonly model: ModelDefinition,
34
+ readonly classes: BodyClassList
33
35
  ) {
34
36
  // TODO: theoretically the pertinent step in the bind's `nodeset` *could* be
35
37
  // namespaced. It also may make more sense to determine the root nodeset
@@ -86,16 +88,9 @@ export class RootDefinition implements NodeDefinition<'root'> {
86
88
  const bind = binds.getOrCreateBindDefinition(nodeset);
87
89
  const bodyElement = body.getBodyElement(nodeset);
88
90
  const [firstChild, ...restChildren] = children;
89
- const repeatGroup = body.getRepeatGroup(nodeset);
90
91
 
91
- if (repeatGroup != null) {
92
- const repeatDefinition = (bodyElement as RepeatGroupDefinition).repeat;
93
-
94
- if (repeatDefinition == null) {
95
- throw 'TODO: this is why I have hesitated to pick an "is repeat" predicate direction';
96
- }
97
-
98
- return new RepeatSequenceDefinition(parent, bind, repeatGroup, children);
92
+ if (bodyElement?.type === 'repeat') {
93
+ return RepeatRangeDefinition.from(parent, bind, bodyElement, children);
99
94
  }
100
95
 
101
96
  if (restChildren.length) {
@@ -106,7 +101,10 @@ export class RootDefinition implements NodeDefinition<'root'> {
106
101
  const isLeafNode = element.childElementCount === 0;
107
102
 
108
103
  if (isLeafNode) {
109
- return new ValueNodeDefinition(parent, bind, bodyElement, element);
104
+ return (
105
+ NoteNodeDefinition.from(parent, bind, bodyElement, element) ??
106
+ new LeafNodeDefinition(parent, bind, bodyElement, element)
107
+ );
110
108
  }
111
109
 
112
110
  return new SubtreeDefinition(parent, bind, bodyElement, element);
@@ -1,6 +1,6 @@
1
1
  import type {
2
2
  AnyBodyElementDefinition,
3
- NonRepeatGroupElementDefinition,
3
+ AnyGroupElementDefinition,
4
4
  } from '../body/BodyDefinition.ts';
5
5
  import type { BindDefinition } from './BindDefinition.ts';
6
6
  import { DescendentNodeDefinition } from './DescendentNodeDefinition.ts';
@@ -11,7 +11,7 @@ import type {
11
11
  } from './NodeDefinition.ts';
12
12
 
13
13
  export class SubtreeDefinition
14
- extends DescendentNodeDefinition<'subtree', NonRepeatGroupElementDefinition | null>
14
+ extends DescendentNodeDefinition<'subtree', AnyGroupElementDefinition | null>
15
15
  implements NodeDefinition<'subtree'>
16
16
  {
17
17
  readonly type = 'subtree';
@@ -29,7 +29,7 @@ export class SubtreeDefinition
29
29
  ) {
30
30
  if (
31
31
  bodyElement != null &&
32
- (bodyElement.category !== 'structure' || bodyElement.type === 'repeat-group')
32
+ (bodyElement.category !== 'structure' || bodyElement.type === 'repeat')
33
33
  ) {
34
34
  throw new Error(`Unexpected body element for nodeset ${bind.nodeset}`);
35
35
  }
@@ -0,0 +1,70 @@
1
+ import type { AnyBodyElementDefinition } from '../body/BodyDefinition.ts';
2
+ import type { InputDefinition } from '../body/control/InputDefinition.ts';
3
+ import type { NoteNode } from '../client/NoteNode.ts';
4
+ import type { ConstantTruthyDependentExpression } from '../expression/DependentExpression.ts';
5
+ import { BindComputation } from '../model/BindComputation.ts';
6
+ import type { BindDefinition } from '../model/BindDefinition.ts';
7
+ import { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
8
+ import type { ParentNodeDefinition } from '../model/NodeDefinition.ts';
9
+ import type { HintDefinition } from './text/HintDefinition.ts';
10
+ import type { LabelDefinition } from './text/LabelDefinition.ts';
11
+
12
+ // prettier-ignore
13
+ export type NoteReadonlyDefinition =
14
+ & BindComputation<'readonly'>
15
+ & ConstantTruthyDependentExpression;
16
+
17
+ export interface NoteBindDefinition extends BindDefinition {
18
+ readonly readonly: NoteReadonlyDefinition;
19
+ }
20
+
21
+ const isNoteBindDefinition = (bind: BindDefinition): bind is NoteBindDefinition => {
22
+ return bind.readonly.isConstantTruthyExpression();
23
+ };
24
+
25
+ // prettier-ignore
26
+ export type NoteTextDefinition =
27
+ // eslint-disable-next-line @typescript-eslint/sort-type-constituents
28
+ | LabelDefinition
29
+ | HintDefinition;
30
+
31
+ /**
32
+ * @package This class is used internally, both in static types and at runtime,
33
+ * to guard and guide the distinction between instance state nodes for 'note'
34
+ * and 'string' node types. It is intentionally package-private! The less
35
+ * specific {@link NoteNode.definition} type, if it has any client value at all,
36
+ * should be more than sufficient. Clients are otherwise expected to use other
37
+ * aspects of the node's interface (such as its {@link NoteNode.nodeType} and
38
+ * distinct {@link NoteNode.currentState} types) to handle note-specific logic.
39
+ */
40
+ export class NoteNodeDefinition extends LeafNodeDefinition {
41
+ static from(
42
+ parent: ParentNodeDefinition,
43
+ bind: BindDefinition,
44
+ bodyElement: AnyBodyElementDefinition | null,
45
+ node: Element
46
+ ): NoteNodeDefinition | null {
47
+ if (!isNoteBindDefinition(bind) || bodyElement?.type !== 'input') {
48
+ return null;
49
+ }
50
+
51
+ const { label, hint } = bodyElement;
52
+ const noteTextDefinition = label ?? hint;
53
+
54
+ if (noteTextDefinition == null) {
55
+ return null;
56
+ }
57
+
58
+ return new this(parent, bind, bodyElement, noteTextDefinition, node);
59
+ }
60
+
61
+ constructor(
62
+ parent: ParentNodeDefinition,
63
+ override readonly bind: NoteBindDefinition,
64
+ override readonly bodyElement: InputDefinition,
65
+ readonly noteTextDefinition: NoteTextDefinition,
66
+ node: Element
67
+ ) {
68
+ super(parent, bind, bodyElement, node);
69
+ }
70
+ }
@@ -0,0 +1,3 @@
1
+ # @getodk/xforms-engine: parse
2
+
3
+ Presence of this file is intended to be temporary! It is here to signal the intent to make a clearer distinction between the parsing and runtime aspects of the engine implementation. For entirely pragmatic purposes, newly introduced will be added here to start. We can decide in review if we want to move the rest into this directory right away. (For existing/untouched code, this would just mean moving the files and updating imports to reflect that. Small effort, lots of potential diff noise.)
@@ -0,0 +1,44 @@
1
+ import { RepeatElementDefinition } from '../../body/RepeatElementDefinition.ts';
2
+ import type { RepeatRangeControlledNode } from '../../client/repeat/RepeatRangeControlledNode.ts';
3
+ import { DependentExpression } from '../../expression/DependentExpression.ts';
4
+ import { isConstantTruthyExpression } from '../xpath/semantic-analysis.ts';
5
+
6
+ /**
7
+ * Represents either of these
8
+ * {@link https://getodk.github.io/xforms-spec/#body-attributes | body attributes}:
9
+ *
10
+ * - `jr:count`
11
+ * - `jr:noAddRemove`
12
+ *
13
+ * In both cases, the downstream effect is that the engine is responsible for
14
+ * controlling the count of a repeat range's instances. Representing both cases
15
+ * should simplify client usage, as well as implementation of the internal
16
+ * representation of {@link RepeatRangeControlledNode}.
17
+ */
18
+ export class RepeatCountControlExpression extends DependentExpression<'number'> {
19
+ static from(
20
+ bodyElement: RepeatElementDefinition,
21
+ initialCount: number
22
+ ): RepeatCountControlExpression | null {
23
+ const { countExpression, noAddRemoveExpression } = bodyElement;
24
+
25
+ if (countExpression != null) {
26
+ return new this(bodyElement, countExpression);
27
+ }
28
+
29
+ if (noAddRemoveExpression != null && isConstantTruthyExpression(noAddRemoveExpression)) {
30
+ // Assumption: `noAddRemove` with no form-defined repeat instances has no
31
+ // purpose. Infer intent as a single repeat instance, as defined by the
32
+ // repeat's template.
33
+ const fixedCountExpression = String(Math.max(initialCount, 1));
34
+
35
+ return new this(bodyElement, fixedCountExpression);
36
+ }
37
+
38
+ return null;
39
+ }
40
+
41
+ private constructor(context: RepeatElementDefinition, expression: string) {
42
+ super(context, 'number', expression);
43
+ }
44
+ }
@@ -0,0 +1,25 @@
1
+ import type { LocalNamedElement } from '@getodk/common/types/dom.ts';
2
+ import type { XFormDefinition } from '../../XFormDefinition.ts';
3
+ import type { AnyControlDefinition } from '../../body/control/ControlDefinition.ts';
4
+ import { getHintElement } from '../../lib/dom/query.ts';
5
+ import { TextElementDefinition } from './abstract/TextElementDefinition.ts';
6
+
7
+ interface HintElement extends LocalNamedElement<'hint'> {}
8
+
9
+ export class HintDefinition extends TextElementDefinition<'hint'> {
10
+ static forElement(form: XFormDefinition, owner: AnyControlDefinition): HintDefinition | null {
11
+ const hintElement = getHintElement(owner.element);
12
+
13
+ if (hintElement == null) {
14
+ return null;
15
+ }
16
+
17
+ return new this(form, owner, hintElement);
18
+ }
19
+
20
+ readonly role = 'hint';
21
+
22
+ private constructor(form: XFormDefinition, owner: AnyControlDefinition, element: HintElement) {
23
+ super(form, owner, element);
24
+ }
25
+ }
@@ -0,0 +1,25 @@
1
+ import type { LocalNamedElement } from '@getodk/common/types/dom.ts';
2
+ import type { XFormDefinition } from '../../XFormDefinition.ts';
3
+ import type { ItemDefinition } from '../../body/control/select/ItemDefinition.ts';
4
+ import { getLabelElement } from '../../lib/dom/query.ts';
5
+ import { TextElementDefinition } from './abstract/TextElementDefinition.ts';
6
+
7
+ interface LabelElement extends LocalNamedElement<'label'> {}
8
+
9
+ export class ItemLabelDefinition extends TextElementDefinition<'item-label'> {
10
+ static from(form: XFormDefinition, owner: ItemDefinition): ItemLabelDefinition | null {
11
+ const labelElement = getLabelElement(owner.element);
12
+
13
+ if (labelElement == null) {
14
+ return null;
15
+ }
16
+
17
+ return new this(form, owner, labelElement);
18
+ }
19
+
20
+ readonly role = 'item-label';
21
+
22
+ private constructor(form: XFormDefinition, owner: ItemDefinition, element: LabelElement) {
23
+ super(form, owner, element);
24
+ }
25
+ }
@@ -0,0 +1,44 @@
1
+ import type { LocalNamedElement } from '@getodk/common/types/dom.ts';
2
+ import type { XFormDefinition } from '../../XFormDefinition.ts';
3
+ import type { ItemDefinition } from '../../body/control/select/ItemDefinition.ts';
4
+ import type { ItemsetDefinition } from '../../body/control/select/ItemsetDefinition.ts';
5
+ import { getLabelElement } from '../../lib/dom/query.ts';
6
+ import { ReferenceChunkDefinition } from './ReferenceChunkDefinition.ts';
7
+ import { TranslationChunkDefinition } from './TranslationChunkDefinition.ts';
8
+ import type { RefAttributeChunk } from './abstract/TextElementDefinition.ts';
9
+ import { TextRangeDefinition } from './abstract/TextRangeDefinition.ts';
10
+
11
+ export type ItemLabelOwner = ItemDefinition | ItemsetDefinition;
12
+
13
+ interface LabelElement extends LocalNamedElement<'label'> {}
14
+
15
+ export class ItemsetLabelDefinition extends TextRangeDefinition<'item-label'> {
16
+ static from(form: XFormDefinition, owner: ItemsetDefinition): ItemsetLabelDefinition | null {
17
+ const labelElement = getLabelElement(owner.element);
18
+
19
+ if (labelElement == null) {
20
+ return null;
21
+ }
22
+
23
+ return new this(form, owner, labelElement);
24
+ }
25
+
26
+ readonly role = 'item-label';
27
+ readonly chunks: readonly [RefAttributeChunk];
28
+
29
+ private constructor(form: XFormDefinition, owner: ItemsetDefinition, element: LabelElement) {
30
+ super(form, owner, element);
31
+
32
+ const refExpression = element.getAttribute('ref');
33
+
34
+ if (refExpression == null) {
35
+ throw new Error('<itemset><label> missing ref attribute');
36
+ }
37
+
38
+ const refChunk =
39
+ TranslationChunkDefinition.from(this, refExpression) ??
40
+ ReferenceChunkDefinition.from(this, refExpression);
41
+
42
+ this.chunks = [refChunk];
43
+ }
44
+ }