@getodk/xforms-engine 0.2.0 → 0.4.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 (292) hide show
  1. package/dist/client/BaseNode.d.ts +69 -4
  2. package/dist/client/EngineConfig.d.ts +0 -1
  3. package/dist/client/GroupNode.d.ts +4 -3
  4. package/dist/client/ModelValueNode.d.ts +36 -0
  5. package/dist/client/NodeAppearances.d.ts +1 -2
  6. package/dist/client/NoteNode.d.ts +52 -0
  7. package/dist/client/RootNode.d.ts +4 -3
  8. package/dist/client/SelectNode.d.ts +6 -5
  9. package/dist/client/StringNode.d.ts +6 -5
  10. package/dist/client/SubtreeNode.d.ts +3 -2
  11. package/dist/client/TextRange.d.ts +85 -3
  12. package/dist/client/TriggerNode.d.ts +25 -0
  13. package/dist/client/constants.d.ts +8 -0
  14. package/dist/client/hierarchy.d.ts +19 -10
  15. package/dist/client/index.d.ts +0 -1
  16. package/dist/client/node-types.d.ts +3 -1
  17. package/dist/client/{RepeatRangeNode.d.ts → repeat/BaseRepeatRangeNode.d.ts} +18 -18
  18. package/dist/client/{RepeatInstanceNode.d.ts → repeat/RepeatInstanceNode.d.ts} +9 -9
  19. package/dist/client/repeat/RepeatRangeControlledNode.d.ts +18 -0
  20. package/dist/client/repeat/RepeatRangeUncontrolledNode.d.ts +19 -0
  21. package/dist/client/unsupported/RangeNode.d.ts +9 -0
  22. package/dist/client/unsupported/RankNode.d.ts +9 -0
  23. package/dist/client/unsupported/UnsupportedControlNode.d.ts +32 -0
  24. package/dist/client/unsupported/UploadNode.d.ts +9 -0
  25. package/dist/client/validation.d.ts +162 -0
  26. package/dist/index.d.ts +14 -6
  27. package/dist/index.js +39696 -36151
  28. package/dist/index.js.map +1 -1
  29. package/dist/instance/Group.d.ts +3 -2
  30. package/dist/instance/ModelValue.d.ts +39 -0
  31. package/dist/instance/Note.d.ts +41 -0
  32. package/dist/instance/Root.d.ts +5 -4
  33. package/dist/instance/SelectField.d.ts +11 -6
  34. package/dist/instance/StringField.d.ts +12 -7
  35. package/dist/instance/Subtree.d.ts +2 -1
  36. package/dist/instance/TriggerControl.d.ts +40 -0
  37. package/dist/instance/abstract/DescendantNode.d.ts +8 -10
  38. package/dist/instance/abstract/InstanceNode.d.ts +3 -2
  39. package/dist/instance/abstract/UnsupportedControl.d.ts +46 -0
  40. package/dist/instance/children.d.ts +0 -1
  41. package/dist/instance/hierarchy.d.ts +15 -6
  42. package/dist/instance/index.d.ts +0 -1
  43. package/dist/instance/internal-api/EvaluationContext.d.ts +0 -1
  44. package/dist/instance/internal-api/InstanceConfig.d.ts +0 -1
  45. package/dist/instance/internal-api/SubscribableDependency.d.ts +0 -1
  46. package/dist/instance/internal-api/TranslationContext.d.ts +0 -1
  47. package/dist/instance/internal-api/ValidationContext.d.ts +28 -0
  48. package/dist/instance/internal-api/ValueContext.d.ts +3 -4
  49. package/dist/instance/{RepeatRange.d.ts → repeat/BaseRepeatRange.d.ts} +46 -46
  50. package/dist/instance/{RepeatInstance.d.ts → repeat/RepeatInstance.d.ts} +13 -13
  51. package/dist/instance/repeat/RepeatRangeControlled.d.ts +15 -0
  52. package/dist/instance/repeat/RepeatRangeUncontrolled.d.ts +34 -0
  53. package/dist/instance/resource.d.ts +0 -1
  54. package/dist/instance/text/TextChunk.d.ts +0 -1
  55. package/dist/instance/text/TextRange.d.ts +4 -5
  56. package/dist/instance/unsupported/RangeControl.d.ts +4 -0
  57. package/dist/instance/unsupported/RankControl.d.ts +4 -0
  58. package/dist/instance/unsupported/UploadControl.d.ts +4 -0
  59. package/dist/lib/TokenListParser.d.ts +3 -3
  60. package/dist/lib/dom/query.d.ts +1 -2
  61. package/dist/lib/reactivity/createChildrenState.d.ts +0 -1
  62. package/dist/lib/reactivity/createComputedExpression.d.ts +7 -3
  63. package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +4 -0
  64. package/dist/lib/reactivity/createSelectItems.d.ts +0 -1
  65. package/dist/lib/reactivity/createValueState.d.ts +0 -1
  66. package/dist/lib/reactivity/materializeCurrentStateChildren.d.ts +0 -1
  67. package/dist/lib/reactivity/node-state/createClientState.d.ts +0 -1
  68. package/dist/lib/reactivity/node-state/createCurrentState.d.ts +0 -1
  69. package/dist/lib/reactivity/node-state/createEngineState.d.ts +0 -1
  70. package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +1 -2
  71. package/dist/lib/reactivity/node-state/createSpecifiedPropertyDescriptor.d.ts +0 -1
  72. package/dist/lib/reactivity/node-state/createSpecifiedState.d.ts +1 -2
  73. package/dist/lib/reactivity/node-state/representations.d.ts +0 -1
  74. package/dist/lib/reactivity/scope.d.ts +0 -1
  75. package/dist/lib/reactivity/text/createFieldHint.d.ts +3 -4
  76. package/dist/lib/reactivity/text/createNodeLabel.d.ts +3 -4
  77. package/dist/lib/reactivity/text/createNoteText.d.ts +24 -0
  78. package/dist/lib/reactivity/text/createTextRange.d.ts +5 -8
  79. package/dist/lib/reactivity/types.d.ts +0 -1
  80. package/dist/lib/reactivity/validation/createAggregatedViolations.d.ts +8 -0
  81. package/dist/lib/reactivity/validation/createValidation.d.ts +17 -0
  82. package/dist/{XFormDOM.d.ts → parse/XFormDOM.d.ts} +1 -2
  83. package/dist/{XFormDataType.d.ts → parse/XFormDataType.d.ts} +2 -4
  84. package/dist/{XFormDefinition.d.ts → parse/XFormDefinition.d.ts} +2 -3
  85. package/dist/{body → parse/body}/BodyDefinition.d.ts +15 -10
  86. package/dist/{body → parse/body}/BodyElementDefinition.d.ts +8 -7
  87. package/dist/{body → parse/body}/RepeatElementDefinition.d.ts +4 -5
  88. package/dist/{body → parse/body}/UnsupportedBodyElementDefinition.d.ts +0 -1
  89. package/dist/{body → parse/body}/appearance/inputAppearanceParser.d.ts +1 -2
  90. package/dist/{body → parse/body}/appearance/selectAppearanceParser.d.ts +1 -2
  91. package/dist/{body → parse/body}/appearance/structureElementAppearanceParser.d.ts +1 -2
  92. package/dist/parse/body/appearance/unknownAppearanceParser.d.ts +3 -0
  93. package/dist/{body → parse/body}/control/ControlDefinition.d.ts +3 -4
  94. package/dist/{body → parse/body}/control/InputDefinition.d.ts +1 -2
  95. package/dist/parse/body/control/RangeControlDefinition.d.ts +11 -0
  96. package/dist/parse/body/control/RankControlDefinition.d.ts +11 -0
  97. package/dist/parse/body/control/TriggerControlDefinition.d.ts +11 -0
  98. package/dist/parse/body/control/UploadControlDefinition.d.ts +11 -0
  99. package/dist/{body → parse/body}/control/select/ItemDefinition.d.ts +3 -4
  100. package/dist/{body → parse/body}/control/select/ItemsetDefinition.d.ts +7 -7
  101. package/dist/{body → parse/body}/control/select/ItemsetNodesetContext.d.ts +2 -3
  102. package/dist/{body → parse/body}/control/select/SelectDefinition.d.ts +3 -12
  103. package/dist/{body → parse/body}/group/BaseGroupDefinition.d.ts +3 -5
  104. package/dist/{body → parse/body}/group/LogicalGroupDefinition.d.ts +0 -1
  105. package/dist/{body → parse/body}/group/PresentationGroupDefinition.d.ts +1 -2
  106. package/dist/{body → parse/body}/group/StructuralGroupDefinition.d.ts +0 -1
  107. package/dist/{model/BindComputation.d.ts → parse/expression/BindComputationExpression.d.ts} +5 -6
  108. package/dist/{body/control/select → parse/expression}/ItemsetNodesetExpression.d.ts +2 -3
  109. package/dist/{body/control/select → parse/expression}/ItemsetValueExpression.d.ts +2 -3
  110. package/dist/parse/expression/RepeatCountControlExpression.d.ts +18 -0
  111. package/dist/parse/expression/TextLiteralExpression.d.ts +9 -0
  112. package/dist/parse/expression/TextOutputExpression.d.ts +7 -0
  113. package/dist/parse/expression/TextReferenceExpression.d.ts +7 -0
  114. package/dist/parse/expression/TextTranslationExpression.d.ts +8 -0
  115. package/dist/{expression → parse/expression/abstract}/DependencyContext.d.ts +0 -1
  116. package/dist/{expression → parse/expression/abstract}/DependentExpression.d.ts +13 -10
  117. package/dist/parse/expression/abstract/TextChunkExpression.d.ts +17 -0
  118. package/dist/parse/model/BindDefinition.d.ts +39 -0
  119. package/dist/{model → parse/model}/BindElement.d.ts +1 -0
  120. package/dist/{model → parse/model}/DescendentNodeDefinition.d.ts +0 -1
  121. package/dist/{model/ValueNodeDefinition.d.ts → parse/model/LeafNodeDefinition.d.ts} +3 -4
  122. package/dist/{model → parse/model}/ModelBindMap.d.ts +0 -1
  123. package/dist/{model → parse/model}/ModelDefinition.d.ts +1 -2
  124. package/dist/{model → parse/model}/NodeDefinition.d.ts +8 -9
  125. package/dist/parse/model/NoteNodeDefinition.d.ts +30 -0
  126. package/dist/{model → parse/model}/RepeatInstanceDefinition.d.ts +3 -4
  127. package/dist/{model → parse/model}/RepeatRangeDefinition.d.ts +14 -5
  128. package/dist/{model → parse/model}/RepeatTemplateDefinition.d.ts +2 -3
  129. package/dist/{model → parse/model}/RootDefinition.d.ts +2 -3
  130. package/dist/{model → parse/model}/SubtreeDefinition.d.ts +1 -2
  131. package/dist/parse/text/HintDefinition.d.ts +8 -0
  132. package/dist/parse/text/ItemLabelDefinition.d.ts +8 -0
  133. package/dist/parse/text/ItemsetLabelDefinition.d.ts +12 -0
  134. package/dist/parse/text/LabelDefinition.d.ts +14 -0
  135. package/dist/parse/text/MessageDefinition.d.ts +14 -0
  136. package/dist/parse/text/abstract/TextElementDefinition.d.ts +22 -0
  137. package/dist/parse/text/abstract/TextRangeDefinition.d.ts +34 -0
  138. package/dist/parse/xpath/dependency-analysis.d.ts +40 -0
  139. package/dist/parse/xpath/path-resolution.d.ts +69 -0
  140. package/dist/parse/xpath/predicate-analysis.d.ts +29 -0
  141. package/dist/parse/xpath/reference-parsing.d.ts +17 -0
  142. package/dist/parse/xpath/semantic-analysis.d.ts +97 -0
  143. package/dist/parse/xpath/syntax-traversal.d.ts +68 -0
  144. package/dist/solid.js +8745 -5186
  145. package/dist/solid.js.map +1 -1
  146. package/package.json +15 -16
  147. package/src/client/BaseNode.ts +74 -8
  148. package/src/client/GroupNode.ts +4 -2
  149. package/src/client/ModelValueNode.ts +40 -0
  150. package/src/client/NodeAppearances.ts +1 -1
  151. package/src/client/NoteNode.ts +74 -0
  152. package/src/client/README.md +1 -0
  153. package/src/client/RootNode.ts +4 -2
  154. package/src/client/SelectNode.ts +6 -4
  155. package/src/client/StringNode.ts +6 -4
  156. package/src/client/SubtreeNode.ts +3 -1
  157. package/src/client/TextRange.ts +98 -2
  158. package/src/client/TriggerNode.ts +29 -0
  159. package/src/client/constants.ts +10 -0
  160. package/src/client/hierarchy.ts +43 -15
  161. package/src/client/node-types.ts +17 -2
  162. package/src/client/{RepeatRangeNode.ts → repeat/BaseRepeatRangeNode.ts} +18 -19
  163. package/src/client/{RepeatInstanceNode.ts → repeat/RepeatInstanceNode.ts} +10 -8
  164. package/src/client/repeat/RepeatRangeControlledNode.ts +20 -0
  165. package/src/client/repeat/RepeatRangeUncontrolledNode.ts +21 -0
  166. package/src/client/unsupported/RangeNode.ts +14 -0
  167. package/src/client/unsupported/RankNode.ts +14 -0
  168. package/src/client/unsupported/UnsupportedControlNode.ts +40 -0
  169. package/src/client/unsupported/UploadNode.ts +14 -0
  170. package/src/client/validation.ts +199 -0
  171. package/src/index.ts +21 -9
  172. package/src/instance/Group.ts +10 -4
  173. package/src/instance/ModelValue.ts +104 -0
  174. package/src/instance/Note.ts +142 -0
  175. package/src/instance/Root.ts +16 -6
  176. package/src/instance/SelectField.ts +29 -7
  177. package/src/instance/StringField.ts +36 -10
  178. package/src/instance/Subtree.ts +9 -3
  179. package/src/instance/TriggerControl.ts +134 -0
  180. package/src/instance/abstract/DescendantNode.ts +9 -10
  181. package/src/instance/abstract/InstanceNode.ts +29 -7
  182. package/src/instance/abstract/UnsupportedControl.ts +151 -0
  183. package/src/instance/children.ts +113 -16
  184. package/src/instance/hierarchy.ts +42 -5
  185. package/src/instance/index.ts +1 -1
  186. package/src/instance/internal-api/EvaluationContext.ts +1 -1
  187. package/src/instance/internal-api/ValidationContext.ts +32 -0
  188. package/src/instance/internal-api/ValueContext.ts +3 -3
  189. package/src/instance/{RepeatRange.ts → repeat/BaseRepeatRange.ts} +114 -99
  190. package/src/instance/{RepeatInstance.ts → repeat/RepeatInstance.ts} +27 -22
  191. package/src/instance/repeat/RepeatRangeControlled.ts +82 -0
  192. package/src/instance/repeat/RepeatRangeUncontrolled.ts +67 -0
  193. package/src/instance/text/TextRange.ts +10 -4
  194. package/src/instance/unsupported/RangeControl.ts +5 -0
  195. package/src/instance/unsupported/RankControl.ts +5 -0
  196. package/src/instance/unsupported/UploadControl.ts +5 -0
  197. package/src/lib/TokenListParser.ts +11 -7
  198. package/src/lib/dom/query.ts +1 -1
  199. package/src/lib/reactivity/createComputedExpression.ts +25 -27
  200. package/src/lib/reactivity/createNoteReadonlyThunk.ts +33 -0
  201. package/src/lib/reactivity/createSelectItems.ts +23 -16
  202. package/src/lib/reactivity/createValueState.ts +3 -3
  203. package/src/lib/reactivity/node-state/createSharedNodeState.ts +1 -1
  204. package/src/lib/reactivity/node-state/createSpecifiedState.ts +1 -1
  205. package/src/lib/reactivity/text/createFieldHint.ts +9 -7
  206. package/src/lib/reactivity/text/createNodeLabel.ts +8 -6
  207. package/src/lib/reactivity/text/createNoteText.ts +72 -0
  208. package/src/lib/reactivity/text/createTextRange.ts +17 -90
  209. package/src/lib/reactivity/validation/createAggregatedViolations.ts +75 -0
  210. package/src/lib/reactivity/validation/createValidation.ts +196 -0
  211. package/src/{XFormDataType.ts → parse/XFormDataType.ts} +1 -3
  212. package/src/{XFormDefinition.ts → parse/XFormDefinition.ts} +2 -2
  213. package/src/{body → parse/body}/BodyDefinition.ts +44 -27
  214. package/src/{body → parse/body}/BodyElementDefinition.ts +13 -6
  215. package/src/{body → parse/body}/RepeatElementDefinition.ts +10 -20
  216. package/src/{body → parse/body}/appearance/inputAppearanceParser.ts +1 -1
  217. package/src/{body → parse/body}/appearance/selectAppearanceParser.ts +1 -1
  218. package/src/{body → parse/body}/appearance/structureElementAppearanceParser.ts +1 -1
  219. package/src/parse/body/appearance/unknownAppearanceParser.ts +5 -0
  220. package/src/{body → parse/body}/control/ControlDefinition.ts +5 -4
  221. package/src/parse/body/control/RangeControlDefinition.ts +26 -0
  222. package/src/parse/body/control/RankControlDefinition.ts +27 -0
  223. package/src/parse/body/control/TriggerControlDefinition.ts +26 -0
  224. package/src/parse/body/control/UploadControlDefinition.ts +26 -0
  225. package/src/{body → parse/body}/control/select/ItemDefinition.ts +4 -4
  226. package/src/parse/body/control/select/ItemsetDefinition.ts +53 -0
  227. package/src/{body → parse/body}/control/select/ItemsetNodesetContext.ts +2 -2
  228. package/src/{body → parse/body}/control/select/SelectDefinition.ts +3 -11
  229. package/src/{body → parse/body}/group/BaseGroupDefinition.ts +11 -21
  230. package/src/{body → parse/body}/group/PresentationGroupDefinition.ts +1 -1
  231. package/src/{model/BindComputation.ts → parse/expression/BindComputationExpression.ts} +8 -12
  232. package/src/parse/expression/ItemsetNodesetExpression.ts +8 -0
  233. package/src/{body/control/select → parse/expression}/ItemsetValueExpression.ts +2 -2
  234. package/src/parse/expression/RepeatCountControlExpression.ts +44 -0
  235. package/src/parse/expression/TextLiteralExpression.ts +19 -0
  236. package/src/parse/expression/TextOutputExpression.ts +25 -0
  237. package/src/parse/expression/TextReferenceExpression.ts +14 -0
  238. package/src/parse/expression/TextTranslationExpression.ts +38 -0
  239. package/src/{expression → parse/expression/abstract}/DependentExpression.ts +46 -28
  240. package/src/parse/expression/abstract/TextChunkExpression.ts +38 -0
  241. package/src/{model → parse/model}/BindDefinition.ts +30 -27
  242. package/src/{model → parse/model}/BindElement.ts +1 -0
  243. package/src/{model/ValueNodeDefinition.ts → parse/model/LeafNodeDefinition.ts} +4 -4
  244. package/src/{model → parse/model}/ModelBindMap.ts +4 -0
  245. package/src/{model → parse/model}/NodeDefinition.ts +12 -12
  246. package/src/parse/model/NoteNodeDefinition.ts +70 -0
  247. package/src/{model → parse/model}/RepeatInstanceDefinition.ts +2 -2
  248. package/src/parse/model/RepeatRangeDefinition.ts +94 -0
  249. package/src/{model → parse/model}/RootDefinition.ts +8 -4
  250. package/src/parse/text/HintDefinition.ts +25 -0
  251. package/src/parse/text/ItemLabelDefinition.ts +25 -0
  252. package/src/parse/text/ItemsetLabelDefinition.ts +44 -0
  253. package/src/parse/text/LabelDefinition.ts +61 -0
  254. package/src/parse/text/MessageDefinition.ts +49 -0
  255. package/src/parse/text/abstract/TextElementDefinition.ts +71 -0
  256. package/src/parse/text/abstract/TextRangeDefinition.ts +70 -0
  257. package/src/parse/xpath/dependency-analysis.ts +105 -0
  258. package/src/parse/xpath/path-resolution.ts +475 -0
  259. package/src/parse/xpath/predicate-analysis.ts +61 -0
  260. package/src/parse/xpath/reference-parsing.ts +90 -0
  261. package/src/parse/xpath/semantic-analysis.ts +466 -0
  262. package/src/parse/xpath/syntax-traversal.ts +129 -0
  263. package/dist/body/text/HintDefinition.d.ts +0 -11
  264. package/dist/body/text/LabelDefinition.d.ts +0 -22
  265. package/dist/body/text/TextElementDefinition.d.ts +0 -33
  266. package/dist/body/text/TextElementOutputPart.d.ts +0 -13
  267. package/dist/body/text/TextElementPart.d.ts +0 -13
  268. package/dist/body/text/TextElementReferencePart.d.ts +0 -7
  269. package/dist/body/text/TextElementStaticPart.d.ts +0 -7
  270. package/dist/lib/xpath/analysis.d.ts +0 -23
  271. package/dist/model/BindDefinition.d.ts +0 -32
  272. package/src/body/control/select/ItemsetDefinition.ts +0 -36
  273. package/src/body/control/select/ItemsetNodesetExpression.ts +0 -8
  274. package/src/body/text/HintDefinition.ts +0 -26
  275. package/src/body/text/LabelDefinition.ts +0 -68
  276. package/src/body/text/TextElementDefinition.ts +0 -97
  277. package/src/body/text/TextElementOutputPart.ts +0 -27
  278. package/src/body/text/TextElementPart.ts +0 -31
  279. package/src/body/text/TextElementReferencePart.ts +0 -21
  280. package/src/body/text/TextElementStaticPart.ts +0 -26
  281. package/src/lib/xpath/analysis.ts +0 -241
  282. package/src/model/RepeatRangeDefinition.ts +0 -53
  283. package/src/{XFormDOM.ts → parse/XFormDOM.ts} +0 -0
  284. package/src/{body → parse/body}/UnsupportedBodyElementDefinition.ts +0 -0
  285. package/src/{body → parse/body}/control/InputDefinition.ts +1 -1
  286. /package/src/{body → parse/body}/group/LogicalGroupDefinition.ts +0 -0
  287. /package/src/{body → parse/body}/group/StructuralGroupDefinition.ts +0 -0
  288. /package/src/{expression → parse/expression/abstract}/DependencyContext.ts +0 -0
  289. /package/src/{model → parse/model}/DescendentNodeDefinition.ts +0 -0
  290. /package/src/{model → parse/model}/ModelDefinition.ts +0 -0
  291. /package/src/{model → parse/model}/RepeatTemplateDefinition.ts +0 -0
  292. /package/src/{model → parse/model}/SubtreeDefinition.ts +0 -0
@@ -0,0 +1,32 @@
1
+ import type { AnyViolation } from '../../client/validation.ts';
2
+ import type { BindComputationExpression } from '../../parse/expression/BindComputationExpression.ts';
3
+ import type { MessageDefinition } from '../../parse/text/MessageDefinition.ts';
4
+ import type { NodeID } from '../identity.ts';
5
+ import type { EvaluationContext } from './EvaluationContext.ts';
6
+ import type { SubscribableDependency } from './SubscribableDependency.ts';
7
+
8
+ interface ValidationContextCurrentState {
9
+ get reference(): string;
10
+ }
11
+
12
+ interface ValidationContextDefinitionBind {
13
+ readonly constraint: BindComputationExpression<'constraint'>;
14
+ readonly constraintMsg: MessageDefinition<'constraintMsg'> | null;
15
+ readonly required: BindComputationExpression<'required'>;
16
+ readonly requiredMsg: MessageDefinition<'requiredMsg'> | null;
17
+ }
18
+
19
+ interface ValidationContextDefinition {
20
+ readonly bind: ValidationContextDefinitionBind;
21
+ }
22
+
23
+ export interface ValidationContext extends EvaluationContext, SubscribableDependency {
24
+ readonly nodeId: NodeID;
25
+ readonly definition: ValidationContextDefinition;
26
+ readonly currentState: ValidationContextCurrentState;
27
+
28
+ getViolation(): AnyViolation | null;
29
+ isRelevant(): boolean;
30
+ isRequired(): boolean;
31
+ isBlank(): boolean;
32
+ }
@@ -1,12 +1,12 @@
1
1
  import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
2
- import type { BindComputation } from '../../model/BindComputation.ts';
2
+ import type { BindComputationExpression } from '../../parse/expression/BindComputationExpression.ts';
3
3
  import type { EvaluationContext } from './EvaluationContext.ts';
4
4
 
5
5
  export type InstanceValue = string;
6
6
 
7
7
  interface ValueContextDefinitionBind {
8
- readonly calculate: BindComputation<'calculate'> | null;
9
- readonly readonly: BindComputation<'readonly'>;
8
+ readonly calculate: BindComputationExpression<'calculate'> | null;
9
+ readonly readonly: BindComputationExpression<'readonly'>;
10
10
  }
11
11
 
12
12
  export interface ValueContextDefinition {
@@ -1,27 +1,34 @@
1
1
  import { insertAtIndex } from '@getodk/common/lib/array/insert.ts';
2
- import type { Accessor } from 'solid-js';
3
- import type { RepeatRangeNode, RepeatRangeNodeAppearances } from '../client/RepeatRangeNode.ts';
4
- import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
5
- import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
6
- import { createComputedExpression } from '../lib/reactivity/createComputedExpression.ts';
7
- import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
8
- import { materializeCurrentStateChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
9
- import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
10
- import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
11
- import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
12
- import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
13
- import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
14
- import type { RepeatRangeDefinition } from '../model/RepeatRangeDefinition.ts';
15
- import type { RepeatDefinition } from './RepeatInstance.ts';
16
- import { RepeatInstance } from './RepeatInstance.ts';
17
- import type { Root } from './Root.ts';
18
- import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
19
- import { DescendantNode } from './abstract/DescendantNode.ts';
20
- import type { GeneralParentNode } from './hierarchy.ts';
21
- import type { NodeID } from './identity.ts';
22
- import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
23
- import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
24
- import type { TextRange } from './text/TextRange.ts';
2
+ import { untrack, type Accessor } from 'solid-js';
3
+ import type { NodeAppearances } from '../../client/NodeAppearances.ts';
4
+ import type { BaseRepeatRangeNode } from '../../client/repeat/BaseRepeatRangeNode.ts';
5
+ import type { TextRange } from '../../client/TextRange.ts';
6
+ import type { AncestorNodeValidationState } from '../../client/validation.ts';
7
+ import type { ChildrenState } from '../../lib/reactivity/createChildrenState.ts';
8
+ import { createChildrenState } from '../../lib/reactivity/createChildrenState.ts';
9
+ import { createComputedExpression } from '../../lib/reactivity/createComputedExpression.ts';
10
+ import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
11
+ import { materializeCurrentStateChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
12
+ import type { CurrentState } from '../../lib/reactivity/node-state/createCurrentState.ts';
13
+ import type { EngineState } from '../../lib/reactivity/node-state/createEngineState.ts';
14
+ import type { SharedNodeState } from '../../lib/reactivity/node-state/createSharedNodeState.ts';
15
+ import { createSharedNodeState } from '../../lib/reactivity/node-state/createSharedNodeState.ts';
16
+ import { createNodeLabel } from '../../lib/reactivity/text/createNodeLabel.ts';
17
+ import type {
18
+ AnyRepeatRangeDefinition,
19
+ ControlledRepeatRangeDefinition,
20
+ } from '../../parse/model/RepeatRangeDefinition.ts';
21
+ import type {
22
+ AnyDescendantNode,
23
+ DescendantNodeParent,
24
+ DescendantNodeSharedStateSpec,
25
+ } from '../abstract/DescendantNode.ts';
26
+ import { DescendantNode } from '../abstract/DescendantNode.ts';
27
+ import type { RepeatRange } from '../hierarchy.ts';
28
+ import type { NodeID } from '../identity.ts';
29
+ import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
30
+ import type { SubscribableDependency } from '../internal-api/SubscribableDependency.ts';
31
+ import { RepeatInstance, type RepeatDefinition } from './RepeatInstance.ts';
25
32
 
26
33
  interface RepeatRangeStateSpec extends DescendantNodeSharedStateSpec {
27
34
  readonly hint: null;
@@ -31,9 +38,15 @@ interface RepeatRangeStateSpec extends DescendantNodeSharedStateSpec {
31
38
  readonly value: null;
32
39
  }
33
40
 
34
- export class RepeatRange
35
- extends DescendantNode<RepeatRangeDefinition, RepeatRangeStateSpec, RepeatInstance>
36
- implements RepeatRangeNode, EvaluationContext, SubscribableDependency
41
+ // prettier-ignore
42
+ type BaseRepeatRangeNodeType<Definition extends AnyRepeatRangeDefinition> =
43
+ Definition extends ControlledRepeatRangeDefinition
44
+ ? 'repeat-range:controlled'
45
+ : 'repeat-range:uncontrolled';
46
+
47
+ export abstract class BaseRepeatRange<Definition extends AnyRepeatRangeDefinition>
48
+ extends DescendantNode<Definition, RepeatRangeStateSpec, RepeatInstance>
49
+ implements BaseRepeatRangeNode, EvaluationContext, SubscribableDependency
37
50
  {
38
51
  /**
39
52
  * A repeat range doesn't have a corresponding primary instance element of its
@@ -57,14 +70,36 @@ export class RepeatRange
57
70
  * {@link https://developer.mozilla.org/en-US/docs/Web/API/Range | DOM Range}
58
71
  * instead?
59
72
  */
60
- private readonly anchorNode: Comment;
73
+ protected readonly anchorNode: Comment;
74
+
75
+ protected readonly childrenState: ChildrenState<RepeatInstance>;
76
+
77
+ /**
78
+ * Provides an {@link EvaluationContext} from which to evaluate expressions
79
+ * where some LocationPath sub-expressions may be **relative to the repeat
80
+ * range itself**. This is useful for evaluation of expressions where:
81
+ *
82
+ * - the expression is typically contextualized to any of its
83
+ * {@link RepeatInstance} children, but it presently has none (i.e.
84
+ * `relevant`)
85
+ *
86
+ * - the expression is conceptually intended to be evaluated in the context of
87
+ * the repeat range itself (i.e. `jr:count`)
88
+ */
89
+ protected readonly selfEvaluationContext: EvaluationContext & {
90
+ readonly contextNode: Comment;
91
+ };
61
92
 
62
- private readonly childrenState: ChildrenState<RepeatInstance>;
93
+ /**
94
+ * @see {@link isSelfRelevant}
95
+ */
96
+ protected readonly isEmptyRangeSelfRelevant: Accessor<boolean>;
63
97
 
64
98
  // InstanceNode
65
99
  protected readonly state: SharedNodeState<RepeatRangeStateSpec>;
66
100
  protected override engineState: EngineState<RepeatRangeStateSpec>;
67
101
 
102
+ // DescendantNode
68
103
  /**
69
104
  * @todo Should we special case repeat `readonly` state the same way
70
105
  * we do for `relevant`?
@@ -73,15 +108,6 @@ export class RepeatRange
73
108
  */
74
109
  declare isSelfReadonly: Accessor<boolean>;
75
110
 
76
- private readonly emptyRangeEvaluationContext: EvaluationContext & {
77
- readonly contextNode: Comment;
78
- };
79
-
80
- /**
81
- * @see {@link isSelfRelevant}
82
- */
83
- private readonly isEmptyRangeSelfRelevant: Accessor<boolean>;
84
-
85
111
  /**
86
112
  * A repeat range does not exist in the primary instance tree. A `relevant`
87
113
  * expression applies to each {@link RepeatInstance} child of the repeat
@@ -125,8 +151,8 @@ export class RepeatRange
125
151
  return this.isEmptyRangeSelfRelevant();
126
152
  };
127
153
 
128
- // RepeatRangeNode
129
- readonly nodeType = 'repeat-range';
154
+ // BaseRepeatRangeNode
155
+ abstract override readonly nodeType: BaseRepeatRangeNodeType<Definition>;
130
156
 
131
157
  /**
132
158
  * @todo RepeatRange*, RepeatInstance* (and RepeatTemplate*) all share the
@@ -161,16 +187,18 @@ export class RepeatRange
161
187
  * All of the above creates considerable ambiguity about where "repeat
162
188
  * appearances" should apply, under which circumstances.
163
189
  */
164
- readonly appearances: RepeatRangeNodeAppearances;
190
+ abstract override readonly appearances: NodeAppearances<Definition>;
165
191
 
166
192
  readonly currentState: MaterializedChildren<CurrentState<RepeatRangeStateSpec>, RepeatInstance>;
167
193
 
168
- constructor(parent: GeneralParentNode, definition: RepeatRangeDefinition) {
194
+ abstract override readonly validationState: AncestorNodeValidationState;
195
+
196
+ constructor(parent: DescendantNodeParent<Definition>, definition: Definition) {
169
197
  super(parent, definition);
170
198
 
171
- this.appearances = definition.bodyElement.appearances;
199
+ const repeatRange = this as AnyDescendantNode as RepeatRange;
172
200
 
173
- const childrenState = createChildrenState<RepeatRange, RepeatInstance>(this);
201
+ const childrenState = createChildrenState<RepeatRange, RepeatInstance>(repeatRange);
174
202
 
175
203
  this.childrenState = childrenState;
176
204
 
@@ -179,7 +207,7 @@ export class RepeatRange
179
207
  );
180
208
  this.contextNode.append(this.anchorNode);
181
209
 
182
- this.emptyRangeEvaluationContext = {
210
+ this.selfEvaluationContext = {
183
211
  scope: this.scope,
184
212
  evaluator: this.evaluator,
185
213
  root: this.root,
@@ -187,15 +215,19 @@ export class RepeatRange
187
215
  contextNode: this.anchorNode,
188
216
 
189
217
  getSubscribableDependenciesByReference: (reference) => {
190
- return this.getSubscribableDependenciesByReference(reference);
218
+ return repeatRange.getSubscribableDependenciesByReference(reference);
191
219
  },
192
220
  };
193
221
 
194
222
  this.isEmptyRangeSelfRelevant = createComputedExpression(
195
- this.emptyRangeEvaluationContext,
223
+ this.selfEvaluationContext,
196
224
  definition.bind.relevant
197
225
  );
198
226
 
227
+ const sharedStateOptions = {
228
+ clientStateFactory: this.engineConfig.stateFactory,
229
+ };
230
+
199
231
  const state = createSharedNodeState(
200
232
  this.scope,
201
233
  {
@@ -210,9 +242,7 @@ export class RepeatRange
210
242
  valueOptions: null,
211
243
  value: null,
212
244
  },
213
- {
214
- clientStateFactory: this.engineConfig.stateFactory,
215
- }
245
+ sharedStateOptions
216
246
  );
217
247
 
218
248
  this.state = state;
@@ -222,15 +252,9 @@ export class RepeatRange
222
252
  state.currentState,
223
253
  childrenState
224
254
  );
225
-
226
- definition.instances.forEach((instanceDefinition, index) => {
227
- const afterIndex = index - 1;
228
-
229
- this.addInstances(afterIndex, 1, instanceDefinition);
230
- });
231
255
  }
232
256
 
233
- private getLastIndex(): number {
257
+ protected getLastIndex(): number {
234
258
  return this.engineState.children.length - 1;
235
259
  }
236
260
 
@@ -242,66 +266,59 @@ export class RepeatRange
242
266
  return this.engineState.children.indexOf(instance.nodeId);
243
267
  }
244
268
 
245
- addInstances(
246
- afterIndex = this.getLastIndex(),
247
- count = 1,
248
- definition: RepeatDefinition = this.definition.template
249
- ): Root {
269
+ private createChildren(
270
+ afterIndex: number,
271
+ definitions: readonly RepeatDefinition[]
272
+ ): readonly RepeatInstance[] {
250
273
  return this.scope.runTask(() => {
251
- let precedingInstance: RepeatInstance | null;
274
+ let initialPrecedingInstance: RepeatInstance | null;
252
275
 
253
276
  if (afterIndex === -1) {
254
- precedingInstance = null;
277
+ initialPrecedingInstance = null;
255
278
  } else {
256
- const instance = this.childrenState.getChildren()[afterIndex];
279
+ const instance = untrack(() => this.childrenState.getChildren()[afterIndex]);
257
280
 
258
281
  if (instance == null) {
259
282
  throw new Error(`No repeat instance at index ${afterIndex}`);
260
283
  }
261
284
 
262
- precedingInstance = instance;
285
+ initialPrecedingInstance = instance;
263
286
  }
264
287
 
265
- const precedingPrimaryInstanceNode = precedingInstance?.contextNode ?? this.anchorNode;
288
+ const repeatRange = this as AnyDescendantNode as RepeatRange;
266
289
 
267
- const newInstance = new RepeatInstance(this, definition, {
268
- precedingPrimaryInstanceNode,
269
- precedingInstance,
270
- });
271
- const initialIndex = afterIndex + 1;
290
+ return definitions.reduce<RepeatInstance[]>((acc, definition) => {
291
+ const precedingInstance = acc[acc.length - 1] ?? initialPrecedingInstance;
292
+ const precedingPrimaryInstanceNode = precedingInstance?.contextNode ?? this.anchorNode;
293
+ const newInstance = new RepeatInstance(repeatRange, definition, {
294
+ precedingPrimaryInstanceNode,
295
+ precedingInstance,
296
+ });
272
297
 
273
- this.childrenState.setChildren((currentInstances) => {
274
- return insertAtIndex(currentInstances, initialIndex, newInstance);
275
- });
298
+ acc.push(newInstance);
276
299
 
277
- if (count > 1) {
278
- return this.addInstances(initialIndex, count - 1);
279
- }
300
+ return acc;
301
+ }, []);
302
+ });
303
+ }
280
304
 
281
- return this.root;
305
+ protected addChildren(
306
+ afterIndex: number,
307
+ definitions: readonly RepeatDefinition[]
308
+ ): readonly RepeatInstance[] {
309
+ return this.scope.runTask(() => {
310
+ const initialIndex = afterIndex + 1;
311
+ const newInstances = this.createChildren(afterIndex, definitions);
312
+
313
+ return this.childrenState.setChildren((currentInstances) => {
314
+ return insertAtIndex(currentInstances, initialIndex, newInstances);
315
+ });
282
316
  });
283
317
  }
284
318
 
285
- /**
286
- * Removes the {@link RepeatInstance}s corresponding to the specified range of
287
- * indexes, and then removes those repeat instances from the repeat range's
288
- * own children state in that order:
289
- *
290
- * 1. Identify the set of {@link RepeatInstance}s to be removed.
291
- *
292
- * 2. For each {@link RepeatInstance} pending removal, perform that node's
293
- * removal logic. @see {@link RepeatInstance.remove} for more detail.
294
- *
295
- * 3. Finalize update to the repeat range's own {@link childrenState},
296
- * omitting those {@link RepeatInstance}s which were removed.
297
- *
298
- * This ordering ensures a consistent representation of state is established
299
- * prior to any downstream reactive updates, and ensures that removed nodes'
300
- * reactivity is cleaned up.
301
- */
302
- removeInstances(startIndex: number, count = 1): Root {
319
+ protected removeChildren(startIndex: number, count: number): readonly RepeatInstance[] {
303
320
  return this.scope.runTask(() => {
304
- this.childrenState.setChildren((currentInstances) => {
321
+ return this.childrenState.setChildren((currentInstances) => {
305
322
  const updatedInstances = currentInstances.slice();
306
323
  const removedInstances = updatedInstances.splice(startIndex, count);
307
324
 
@@ -311,8 +328,6 @@ export class RepeatRange
311
328
 
312
329
  return updatedInstances;
313
330
  });
314
-
315
- return this.root;
316
331
  });
317
332
  }
318
333
 
@@ -4,25 +4,26 @@ import type {
4
4
  RepeatDefinition,
5
5
  RepeatInstanceNode,
6
6
  RepeatInstanceNodeAppearances,
7
- } from '../client/RepeatInstanceNode.ts';
8
- import type { TextRange } from '../index.ts';
9
- import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
10
- import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
11
- import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
12
- import { materializeCurrentStateChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
13
- import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
14
- import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
15
- import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
16
- import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
17
- import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
18
- import type { RepeatRange } from './RepeatRange.ts';
19
- import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
20
- import { DescendantNode } from './abstract/DescendantNode.ts';
21
- import { buildChildren } from './children.ts';
22
- import type { AnyChildNode, GeneralChildNode } from './hierarchy.ts';
23
- import type { NodeID } from './identity.ts';
24
- import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
25
- import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
7
+ } from '../../client/repeat/RepeatInstanceNode.ts';
8
+ import type { TextRange } from '../../client/TextRange.ts';
9
+ import type { AncestorNodeValidationState } from '../../client/validation.ts';
10
+ import type { ChildrenState } from '../../lib/reactivity/createChildrenState.ts';
11
+ import { createChildrenState } from '../../lib/reactivity/createChildrenState.ts';
12
+ import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
13
+ import { materializeCurrentStateChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
14
+ import type { CurrentState } from '../../lib/reactivity/node-state/createCurrentState.ts';
15
+ import type { EngineState } from '../../lib/reactivity/node-state/createEngineState.ts';
16
+ import type { SharedNodeState } from '../../lib/reactivity/node-state/createSharedNodeState.ts';
17
+ import { createSharedNodeState } from '../../lib/reactivity/node-state/createSharedNodeState.ts';
18
+ import { createNodeLabel } from '../../lib/reactivity/text/createNodeLabel.ts';
19
+ import { createAggregatedViolations } from '../../lib/reactivity/validation/createAggregatedViolations.ts';
20
+ import type { DescendantNodeSharedStateSpec } from '../abstract/DescendantNode.ts';
21
+ import { DescendantNode } from '../abstract/DescendantNode.ts';
22
+ import { buildChildren } from '../children.ts';
23
+ import type { AnyChildNode, GeneralChildNode, RepeatRange } from '../hierarchy.ts';
24
+ import type { NodeID } from '../identity.ts';
25
+ import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
26
+ import type { SubscribableDependency } from '../internal-api/SubscribableDependency.ts';
26
27
 
27
28
  export type { RepeatDefinition };
28
29
 
@@ -87,6 +88,7 @@ export class RepeatInstance
87
88
  CurrentState<RepeatInstanceStateSpec>,
88
89
  GeneralChildNode
89
90
  >;
91
+ readonly validationState: AncestorNodeValidationState;
90
92
 
91
93
  constructor(
92
94
  override readonly parent: RepeatRange,
@@ -116,6 +118,10 @@ export class RepeatInstance
116
118
 
117
119
  this.currentIndex = currentIndex;
118
120
 
121
+ const sharedStateOptions = {
122
+ clientStateFactory: this.engineConfig.stateFactory,
123
+ };
124
+
119
125
  const state = createSharedNodeState(
120
126
  this.scope,
121
127
  {
@@ -131,9 +137,7 @@ export class RepeatInstance
131
137
  valueOptions: null,
132
138
  value: null,
133
139
  },
134
- {
135
- clientStateFactory: this.engineConfig.stateFactory,
136
- }
140
+ sharedStateOptions
137
141
  );
138
142
 
139
143
  this.state = state;
@@ -166,6 +170,7 @@ export class RepeatInstance
166
170
  });
167
171
 
168
172
  childrenState.setChildren(buildChildren(this));
173
+ this.validationState = createAggregatedViolations(this, sharedStateOptions);
169
174
  }
170
175
 
171
176
  protected override initializeContextNode(parentContextNode: Element, nodeName: string): Element {
@@ -0,0 +1,82 @@
1
+ import { createComputed } from 'solid-js';
2
+ import type { RepeatRangeNodeAppearances } from '../../client/repeat/BaseRepeatRangeNode.ts';
3
+ import type { RepeatRangeControlledNode } from '../../client/repeat/RepeatRangeControlledNode.ts';
4
+ import type { AncestorNodeValidationState } from '../../client/validation.ts';
5
+ import { createComputedExpression } from '../../lib/reactivity/createComputedExpression.ts';
6
+ import { createAggregatedViolations } from '../../lib/reactivity/validation/createAggregatedViolations.ts';
7
+ import type { ControlledRepeatRangeDefinition } from '../../parse/model/RepeatRangeDefinition.ts';
8
+ import type { GeneralParentNode } from '../hierarchy.ts';
9
+ import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
10
+ import type { SubscribableDependency } from '../internal-api/SubscribableDependency.ts';
11
+ import { BaseRepeatRange } from './BaseRepeatRange.ts';
12
+ import type { RepeatDefinition } from './RepeatInstance.ts';
13
+
14
+ export class RepeatRangeControlled
15
+ extends BaseRepeatRange<ControlledRepeatRangeDefinition>
16
+ implements RepeatRangeControlledNode, EvaluationContext, SubscribableDependency
17
+ {
18
+ // RepeatRangeControlledNode
19
+ readonly nodeType = 'repeat-range:controlled';
20
+
21
+ readonly appearances: RepeatRangeNodeAppearances;
22
+
23
+ readonly validationState: AncestorNodeValidationState;
24
+
25
+ constructor(parent: GeneralParentNode, definition: ControlledRepeatRangeDefinition) {
26
+ super(parent, definition);
27
+
28
+ this.appearances = definition.bodyElement.appearances;
29
+
30
+ this.initializeControlledChildrenState(definition);
31
+
32
+ this.validationState = createAggregatedViolations(this, {
33
+ clientStateFactory: this.engineConfig.stateFactory,
34
+ });
35
+ }
36
+
37
+ private initializeControlledChildrenState(definition: ControlledRepeatRangeDefinition): void {
38
+ this.scope.runTask(() => {
39
+ const { count, instances, template } = definition;
40
+ const computeCount = createComputedExpression(this.selfEvaluationContext, count);
41
+
42
+ createComputed<number>((previousCount) => {
43
+ let currentCount = computeCount();
44
+
45
+ if (Number.isFinite(currentCount) && currentCount < 0) {
46
+ currentCount = 0;
47
+ }
48
+
49
+ if (
50
+ currentCount === previousCount ||
51
+ // TODO: the intent of this check is to defer a count update when the
52
+ // count expression produces a blank value. This "feels right" when
53
+ // the count is directly controlled by the user (i.e. entering a
54
+ // number in an input), but probably does not make sense in every
55
+ // scenario! For instance, when a referenced node's relevance changes.
56
+ Number.isNaN(currentCount)
57
+ ) {
58
+ return previousCount;
59
+ }
60
+
61
+ if (currentCount > previousCount) {
62
+ const delta = currentCount - previousCount;
63
+ const definitions = Array<RepeatDefinition>(delta)
64
+ .fill(template)
65
+ .map((baseDefinition, index) => {
66
+ const instanceIndex = previousCount + index;
67
+
68
+ return instances[instanceIndex] ?? baseDefinition;
69
+ });
70
+
71
+ this.addChildren(previousCount - 1, definitions);
72
+ } else {
73
+ const delta = previousCount - currentCount;
74
+
75
+ this.removeChildren(currentCount, delta);
76
+ }
77
+
78
+ return currentCount;
79
+ }, 0);
80
+ });
81
+ }
82
+ }
@@ -0,0 +1,67 @@
1
+ import type { RepeatRangeNodeAppearances } from '../../client/repeat/BaseRepeatRangeNode.ts';
2
+ import type { RepeatRangeUncontrolledNode } from '../../client/repeat/RepeatRangeUncontrolledNode.ts';
3
+ import type { AncestorNodeValidationState } from '../../client/validation.ts';
4
+ import { createAggregatedViolations } from '../../lib/reactivity/validation/createAggregatedViolations.ts';
5
+ import type { UncontrolledRepeatRangeDefinition } from '../../parse/model/RepeatRangeDefinition.ts';
6
+ import type { GeneralParentNode } from '../hierarchy.ts';
7
+ import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
8
+ import type { SubscribableDependency } from '../internal-api/SubscribableDependency.ts';
9
+ import type { Root } from '../Root.ts';
10
+ import { BaseRepeatRange } from './BaseRepeatRange.ts';
11
+ import { RepeatInstance } from './RepeatInstance.ts';
12
+
13
+ export class RepeatRangeUncontrolled
14
+ extends BaseRepeatRange<UncontrolledRepeatRangeDefinition>
15
+ implements RepeatRangeUncontrolledNode, EvaluationContext, SubscribableDependency
16
+ {
17
+ // RepeatRangeUncontrolledNode
18
+ readonly nodeType = 'repeat-range:uncontrolled';
19
+
20
+ readonly appearances: RepeatRangeNodeAppearances;
21
+
22
+ readonly validationState: AncestorNodeValidationState;
23
+
24
+ constructor(parent: GeneralParentNode, definition: UncontrolledRepeatRangeDefinition) {
25
+ super(parent, definition);
26
+
27
+ this.appearances = definition.bodyElement.appearances;
28
+
29
+ this.addChildren(-1, definition.instances);
30
+
31
+ this.validationState = createAggregatedViolations(this, {
32
+ clientStateFactory: this.engineConfig.stateFactory,
33
+ });
34
+ }
35
+
36
+ // RepeatRangeUncontrolledNode
37
+ addInstances(afterIndex = this.getLastIndex(), count = 1): Root {
38
+ const definitions = Array(count).fill(this.definition.template);
39
+
40
+ this.addChildren(afterIndex, definitions);
41
+
42
+ return this.root;
43
+ }
44
+
45
+ /**
46
+ * Removes the {@link RepeatInstance}s corresponding to the specified range of
47
+ * indexes, and then removes those repeat instances from the repeat range's
48
+ * own children state in that order:
49
+ *
50
+ * 1. Identify the set of {@link RepeatInstance}s to be removed.
51
+ *
52
+ * 2. For each {@link RepeatInstance} pending removal, perform that node's
53
+ * removal logic. @see {@link RepeatInstance.remove} for more detail.
54
+ *
55
+ * 3. Finalize update to the repeat range's own {@link childrenState},
56
+ * omitting those {@link RepeatInstance}s which were removed.
57
+ *
58
+ * This ordering ensures a consistent representation of state is established
59
+ * prior to any downstream reactive updates, and ensures that removed nodes'
60
+ * reactivity is cleaned up.
61
+ */
62
+ removeInstances(startIndex: number, count = 1): Root {
63
+ this.removeChildren(startIndex, count);
64
+
65
+ return this.root;
66
+ }
67
+ }
@@ -1,9 +1,14 @@
1
- import type { TextRange as ClientTextRange, TextChunk } from '../../client/TextRange.ts';
1
+ import type {
2
+ TextRange as ClientTextRange,
3
+ TextChunk,
4
+ TextOrigin,
5
+ TextRole,
6
+ } from '../../client/TextRange.ts';
2
7
  import { FormattedTextStub } from './FormattedTextStub.ts';
3
8
 
4
- export type TextRole = 'hint' | 'label';
5
-
6
- export class TextRange<Role extends TextRole> implements ClientTextRange<Role> {
9
+ export class TextRange<Role extends TextRole, Origin extends TextOrigin>
10
+ implements ClientTextRange<Role, Origin>
11
+ {
7
12
  *[Symbol.iterator]() {
8
13
  yield* this.chunks;
9
14
  }
@@ -17,6 +22,7 @@ export class TextRange<Role extends TextRole> implements ClientTextRange<Role> {
17
22
  }
18
23
 
19
24
  constructor(
25
+ readonly origin: Origin,
20
26
  readonly role: Role,
21
27
  protected readonly chunks: readonly TextChunk[]
22
28
  ) {}
@@ -0,0 +1,5 @@
1
+ import { UnsupportedControl } from '../abstract/UnsupportedControl.ts';
2
+
3
+ export class RangeControl extends UnsupportedControl<'range'> {
4
+ readonly nodeType = 'range';
5
+ }
@@ -0,0 +1,5 @@
1
+ import { UnsupportedControl } from '../abstract/UnsupportedControl.ts';
2
+
3
+ export class RankControl extends UnsupportedControl<'rank'> {
4
+ readonly nodeType = 'rank';
5
+ }
@@ -0,0 +1,5 @@
1
+ import { UnsupportedControl } from '../abstract/UnsupportedControl.ts';
2
+
3
+ export class UploadControl extends UnsupportedControl<'upload'> {
4
+ readonly nodeType = 'upload';
5
+ }