@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.
- package/dist/body/BodyDefinition.d.ts +24 -7
- package/dist/body/BodyElementDefinition.d.ts +4 -3
- package/dist/body/RepeatElementDefinition.d.ts +19 -0
- package/dist/body/appearance/inputAppearanceParser.d.ts +4 -0
- package/dist/body/appearance/selectAppearanceParser.d.ts +4 -0
- package/dist/body/appearance/structureElementAppearanceParser.d.ts +4 -0
- package/dist/body/control/ControlDefinition.d.ts +4 -2
- package/dist/body/control/InputDefinition.d.ts +5 -0
- package/dist/body/control/select/ItemDefinition.d.ts +2 -2
- package/dist/body/control/select/ItemsetDefinition.d.ts +5 -4
- package/dist/body/control/select/SelectDefinition.d.ts +11 -1
- package/dist/body/group/BaseGroupDefinition.d.ts +4 -9
- package/dist/body/group/PresentationGroupDefinition.d.ts +1 -1
- package/dist/client/BaseNode.d.ts +74 -3
- package/dist/client/GroupNode.d.ts +7 -2
- package/dist/client/ModelValueNode.d.ts +37 -0
- package/dist/client/NodeAppearances.d.ts +15 -0
- package/dist/client/NoteNode.d.ts +53 -0
- package/dist/client/RootNode.d.ts +21 -0
- package/dist/client/SelectNode.d.ts +8 -3
- package/dist/client/StringNode.d.ts +8 -3
- package/dist/client/SubtreeNode.d.ts +3 -0
- package/dist/client/TextRange.d.ts +85 -2
- package/dist/client/constants.d.ts +9 -0
- package/dist/client/hierarchy.d.ts +14 -9
- package/dist/client/node-types.d.ts +2 -1
- package/dist/client/{RepeatRangeNode.d.ts → repeat/BaseRepeatRangeNode.d.ts} +19 -15
- package/dist/client/{RepeatInstanceNode.d.ts → repeat/RepeatInstanceNode.d.ts} +11 -7
- package/dist/client/repeat/RepeatRangeControlledNode.d.ts +19 -0
- package/dist/client/repeat/RepeatRangeUncontrolledNode.d.ts +20 -0
- package/dist/client/validation.d.ts +163 -0
- package/dist/expression/DependentExpression.d.ts +12 -8
- package/dist/index.d.ts +9 -4
- package/dist/index.js +3173 -960
- package/dist/index.js.map +1 -1
- package/dist/instance/Group.d.ts +6 -4
- package/dist/instance/ModelValue.d.ts +40 -0
- package/dist/instance/Note.d.ts +42 -0
- package/dist/instance/Root.d.ts +10 -23
- package/dist/instance/SelectField.d.ts +12 -6
- package/dist/instance/StringField.d.ts +13 -7
- package/dist/instance/Subtree.d.ts +3 -1
- package/dist/instance/abstract/DescendantNode.d.ts +16 -9
- package/dist/instance/abstract/InstanceNode.d.ts +28 -29
- package/dist/instance/hierarchy.d.ts +10 -5
- package/dist/instance/internal-api/EvaluationContext.d.ts +5 -4
- package/dist/instance/internal-api/ValidationContext.d.ts +21 -0
- package/dist/instance/internal-api/ValueContext.d.ts +2 -2
- package/dist/instance/repeat/BaseRepeatRange.d.ts +160 -0
- package/dist/instance/{RepeatInstance.d.ts → repeat/RepeatInstance.d.ts} +38 -13
- package/dist/instance/repeat/RepeatRangeControlled.d.ts +16 -0
- package/dist/instance/repeat/RepeatRangeUncontrolled.d.ts +35 -0
- package/dist/instance/text/TextRange.d.ts +4 -4
- package/dist/lib/TokenListParser.d.ts +84 -0
- package/dist/lib/dom/query.d.ts +5 -0
- package/dist/lib/reactivity/createComputedExpression.d.ts +6 -1
- package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +5 -0
- package/dist/lib/reactivity/materializeCurrentStateChildren.d.ts +2 -1
- package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +1 -1
- package/dist/lib/reactivity/node-state/createSpecifiedState.d.ts +1 -1
- package/dist/lib/reactivity/text/createFieldHint.d.ts +3 -3
- package/dist/lib/reactivity/text/createNodeLabel.d.ts +2 -2
- package/dist/lib/reactivity/text/createNoteText.d.ts +25 -0
- package/dist/lib/reactivity/text/createTextRange.d.ts +5 -7
- package/dist/lib/reactivity/validation/createAggregatedViolations.d.ts +9 -0
- package/dist/lib/reactivity/validation/createValidation.d.ts +18 -0
- package/dist/model/BindDefinition.d.ts +4 -2
- package/dist/model/BindElement.d.ts +1 -0
- package/dist/model/DescendentNodeDefinition.d.ts +1 -2
- package/dist/model/{ValueNodeDefinition.d.ts → LeafNodeDefinition.d.ts} +3 -4
- package/dist/model/NodeDefinition.d.ts +16 -16
- package/dist/model/RepeatInstanceDefinition.d.ts +5 -6
- package/dist/model/RepeatRangeDefinition.d.ts +30 -0
- package/dist/model/RepeatTemplateDefinition.d.ts +6 -7
- package/dist/model/RootDefinition.d.ts +3 -1
- package/dist/model/SubtreeDefinition.d.ts +2 -2
- package/dist/parse/NoteNodeDefinition.d.ts +31 -0
- package/dist/parse/expression/RepeatCountControlExpression.d.ts +19 -0
- package/dist/parse/text/HintDefinition.d.ts +9 -0
- package/dist/parse/text/ItemLabelDefinition.d.ts +9 -0
- package/dist/parse/text/ItemsetLabelDefinition.d.ts +13 -0
- package/dist/parse/text/LabelDefinition.d.ts +15 -0
- package/dist/parse/text/MessageDefinition.d.ts +15 -0
- package/dist/parse/text/OutputChunkDefinition.d.ts +8 -0
- package/dist/parse/text/ReferenceChunkDefinition.d.ts +8 -0
- package/dist/parse/text/StaticTextChunkDefinition.d.ts +10 -0
- package/dist/parse/text/TranslationChunkDefinition.d.ts +9 -0
- package/dist/parse/text/abstract/TextChunkDefinition.d.ts +18 -0
- package/dist/parse/text/abstract/TextElementDefinition.d.ts +23 -0
- package/dist/parse/text/abstract/TextRangeDefinition.d.ts +35 -0
- package/dist/parse/xpath/dependency-analysis.d.ts +40 -0
- package/dist/parse/xpath/path-resolution.d.ts +70 -0
- package/dist/parse/xpath/predicate-analysis.d.ts +30 -0
- package/dist/parse/xpath/reference-parsing.d.ts +18 -0
- package/dist/parse/xpath/semantic-analysis.d.ts +98 -0
- package/dist/parse/xpath/syntax-traversal.d.ts +69 -0
- package/dist/solid.js +3174 -961
- package/dist/solid.js.map +1 -1
- package/package.json +14 -15
- package/src/XFormDOM.ts +81 -8
- package/src/body/BodyDefinition.ts +38 -23
- package/src/body/BodyElementDefinition.ts +4 -3
- package/src/body/RepeatElementDefinition.ts +58 -0
- package/src/body/appearance/inputAppearanceParser.ts +39 -0
- package/src/body/appearance/selectAppearanceParser.ts +38 -0
- package/src/body/appearance/structureElementAppearanceParser.ts +7 -0
- package/src/body/control/ControlDefinition.ts +8 -3
- package/src/body/control/InputDefinition.ts +13 -0
- package/src/body/control/select/ItemDefinition.ts +3 -3
- package/src/body/control/select/ItemsetDefinition.ts +29 -12
- package/src/body/control/select/ItemsetNodesetExpression.ts +1 -1
- package/src/body/control/select/SelectDefinition.ts +14 -5
- package/src/body/group/BaseGroupDefinition.ts +14 -51
- package/src/body/group/PresentationGroupDefinition.ts +1 -1
- package/src/client/BaseNode.ts +82 -8
- package/src/client/GroupNode.ts +8 -2
- package/src/client/ModelValueNode.ts +40 -0
- package/src/client/NodeAppearances.ts +22 -0
- package/src/client/NoteNode.ts +74 -0
- package/src/client/README.md +1 -0
- package/src/client/RootNode.ts +24 -0
- package/src/client/SelectNode.ts +9 -3
- package/src/client/StringNode.ts +9 -3
- package/src/client/SubtreeNode.ts +3 -0
- package/src/client/TextRange.ts +99 -2
- package/src/client/constants.ts +10 -0
- package/src/client/hierarchy.ts +30 -14
- package/src/client/node-types.ts +8 -1
- package/src/client/{RepeatRangeNode.ts → repeat/BaseRepeatRangeNode.ts} +20 -17
- package/src/client/{RepeatInstanceNode.ts → repeat/RepeatInstanceNode.ts} +13 -7
- package/src/client/repeat/RepeatRangeControlledNode.ts +20 -0
- package/src/client/repeat/RepeatRangeUncontrolledNode.ts +21 -0
- package/src/client/validation.ts +199 -0
- package/src/expression/DependentExpression.ts +45 -27
- package/src/index.ts +15 -8
- package/src/instance/Group.ts +24 -13
- package/src/instance/ModelValue.ts +104 -0
- package/src/instance/Note.ts +142 -0
- package/src/instance/Root.ts +29 -67
- package/src/instance/SelectField.ts +35 -13
- package/src/instance/StringField.ts +40 -13
- package/src/instance/Subtree.ts +19 -10
- package/src/instance/abstract/DescendantNode.ts +50 -49
- package/src/instance/abstract/InstanceNode.ts +89 -92
- package/src/instance/children.ts +47 -10
- package/src/instance/hierarchy.ts +21 -2
- package/src/instance/index.ts +1 -1
- package/src/instance/internal-api/EvaluationContext.ts +5 -6
- package/src/instance/internal-api/ValidationContext.ts +23 -0
- package/src/instance/internal-api/ValueContext.ts +2 -2
- package/src/instance/repeat/BaseRepeatRange.ts +347 -0
- package/src/instance/{RepeatInstance.ts → repeat/RepeatInstance.ts} +85 -36
- package/src/instance/repeat/RepeatRangeControlled.ts +82 -0
- package/src/instance/repeat/RepeatRangeUncontrolled.ts +67 -0
- package/src/instance/text/TextRange.ts +10 -4
- package/src/lib/TokenListParser.ts +156 -0
- package/src/lib/dom/query.ts +13 -0
- package/src/lib/reactivity/createChildrenState.ts +51 -6
- package/src/lib/reactivity/createComputedExpression.ts +23 -25
- package/src/lib/reactivity/createNoteReadonlyThunk.ts +33 -0
- package/src/lib/reactivity/createSelectItems.ts +25 -20
- package/src/lib/reactivity/createValueState.ts +6 -6
- package/src/lib/reactivity/materializeCurrentStateChildren.ts +3 -1
- package/src/lib/reactivity/node-state/createSharedNodeState.ts +1 -1
- package/src/lib/reactivity/text/createFieldHint.ts +9 -7
- package/src/lib/reactivity/text/createNodeLabel.ts +7 -5
- package/src/lib/reactivity/text/createNoteText.ts +72 -0
- package/src/lib/reactivity/text/createTextRange.ts +17 -90
- package/src/lib/reactivity/validation/createAggregatedViolations.ts +70 -0
- package/src/lib/reactivity/validation/createValidation.ts +196 -0
- package/src/model/BindComputation.ts +0 -4
- package/src/model/BindDefinition.ts +8 -6
- package/src/model/BindElement.ts +1 -0
- package/src/model/DescendentNodeDefinition.ts +1 -2
- package/src/model/{ValueNodeDefinition.ts → LeafNodeDefinition.ts} +5 -6
- package/src/model/ModelBindMap.ts +4 -0
- package/src/model/ModelDefinition.ts +1 -1
- package/src/model/NodeDefinition.ts +21 -21
- package/src/model/RepeatInstanceDefinition.ts +8 -13
- package/src/model/RepeatRangeDefinition.ts +94 -0
- package/src/model/RepeatTemplateDefinition.ts +10 -15
- package/src/model/RootDefinition.ts +12 -14
- package/src/model/SubtreeDefinition.ts +3 -3
- package/src/parse/NoteNodeDefinition.ts +70 -0
- package/src/parse/TODO.md +3 -0
- package/src/parse/expression/RepeatCountControlExpression.ts +44 -0
- package/src/parse/text/HintDefinition.ts +25 -0
- package/src/parse/text/ItemLabelDefinition.ts +25 -0
- package/src/parse/text/ItemsetLabelDefinition.ts +44 -0
- package/src/parse/text/LabelDefinition.ts +61 -0
- package/src/parse/text/MessageDefinition.ts +49 -0
- package/src/parse/text/OutputChunkDefinition.ts +25 -0
- package/src/parse/text/ReferenceChunkDefinition.ts +14 -0
- package/src/parse/text/StaticTextChunkDefinition.ts +19 -0
- package/src/parse/text/TranslationChunkDefinition.ts +38 -0
- package/src/parse/text/abstract/TextChunkDefinition.ts +38 -0
- package/src/parse/text/abstract/TextElementDefinition.ts +71 -0
- package/src/parse/text/abstract/TextRangeDefinition.ts +70 -0
- package/src/parse/xpath/dependency-analysis.ts +105 -0
- package/src/parse/xpath/path-resolution.ts +475 -0
- package/src/parse/xpath/predicate-analysis.ts +61 -0
- package/src/parse/xpath/reference-parsing.ts +90 -0
- package/src/parse/xpath/semantic-analysis.ts +466 -0
- package/src/parse/xpath/syntax-traversal.ts +129 -0
- package/dist/body/RepeatDefinition.d.ts +0 -16
- package/dist/body/group/RepeatGroupDefinition.d.ts +0 -13
- package/dist/body/text/HintDefinition.d.ts +0 -11
- package/dist/body/text/LabelDefinition.d.ts +0 -20
- package/dist/body/text/TextElementDefinition.d.ts +0 -33
- package/dist/body/text/TextElementOutputPart.d.ts +0 -13
- package/dist/body/text/TextElementPart.d.ts +0 -13
- package/dist/body/text/TextElementReferencePart.d.ts +0 -7
- package/dist/body/text/TextElementStaticPart.d.ts +0 -7
- package/dist/instance/RepeatRange.d.ts +0 -80
- package/dist/lib/xpath/analysis.d.ts +0 -23
- package/dist/model/RepeatSequenceDefinition.d.ts +0 -20
- package/src/body/RepeatDefinition.ts +0 -54
- package/src/body/group/RepeatGroupDefinition.ts +0 -91
- package/src/body/text/HintDefinition.ts +0 -26
- package/src/body/text/LabelDefinition.ts +0 -54
- package/src/body/text/TextElementDefinition.ts +0 -97
- package/src/body/text/TextElementOutputPart.ts +0 -27
- package/src/body/text/TextElementPart.ts +0 -31
- package/src/body/text/TextElementReferencePart.ts +0 -21
- package/src/body/text/TextElementStaticPart.ts +0 -26
- package/src/instance/RepeatRange.ts +0 -214
- package/src/lib/xpath/analysis.ts +0 -241
- package/src/model/RepeatSequenceDefinition.ts +0 -53
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { AnyBodyElementDefinition } from '../body/BodyDefinition.ts';
|
|
2
|
-
import type {
|
|
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 {
|
|
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
|
|
23
|
+
export type RepeatRangeType = 'repeat-range';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Corresponds to a template definition for a repeat
|
|
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-
|
|
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
|
|
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
|
-
|
|
|
58
|
+
| RepeatRangeType
|
|
59
59
|
| RepeatTemplateType
|
|
60
60
|
| RepeatInstanceType
|
|
61
61
|
| SubtreeNodeType
|
|
62
|
-
|
|
|
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
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
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
|
-
|
|
|
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-
|
|
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:
|
|
104
|
+
// TODO: leaf-node may be Attr
|
|
105
105
|
// prettier-ignore
|
|
106
106
|
export type ModelNode<Type extends NodeDefinitionType> =
|
|
107
|
-
Type extends 'repeat-
|
|
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 '
|
|
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 |
|
|
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
|
-
|
|
|
140
|
+
| AnyRepeatRangeDefinition
|
|
141
141
|
| RepeatTemplateDefinition
|
|
142
142
|
| RepeatInstanceDefinition
|
|
143
143
|
| SubtreeDefinition
|
|
144
|
-
|
|
|
144
|
+
| LeafNodeDefinition;
|
|
145
145
|
|
|
146
146
|
export type TypedNodeDefinition<Type> = Extract<AnyNodeDefinition, { readonly type: Type }>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
4
|
+
import type { AnyRepeatRangeDefinition } from './RepeatRangeDefinition.ts';
|
|
5
5
|
|
|
6
6
|
export class RepeatInstanceDefinition
|
|
7
|
-
extends DescendentNodeDefinition<'repeat-instance',
|
|
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
|
-
|
|
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(
|
|
23
|
+
super(parent, bind, bodyElement);
|
|
29
24
|
|
|
30
|
-
this.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,
|
|
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 {
|
|
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 {
|
|
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',
|
|
76
|
+
extends DescendentNodeDefinition<'repeat-template', RepeatElementDefinition>
|
|
77
77
|
implements NodeDefinition<'repeat-template'>
|
|
78
78
|
{
|
|
79
79
|
static parseModelNodes(
|
|
80
|
-
|
|
80
|
+
range: RepeatRangeDefinition,
|
|
81
81
|
modelNodes: readonly [Element, ...Element[]]
|
|
82
82
|
): ParsedRepeatNodes {
|
|
83
|
-
const { bind } =
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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 {
|
|
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 {
|
|
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 (
|
|
92
|
-
|
|
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
|
|
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
|
-
|
|
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',
|
|
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
|
|
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
|
+
}
|