@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
|
@@ -2,8 +2,9 @@ import { xmlXPathWhitespaceSeparatedList } from '@getodk/common/lib/string/white
|
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
3
|
import { untrack } from 'solid-js';
|
|
4
4
|
import type { AnySelectDefinition } from '../body/control/select/SelectDefinition.ts';
|
|
5
|
-
import type { SelectItem, SelectNode } from '../client/SelectNode.ts';
|
|
6
|
-
import type { TextRange } from '../
|
|
5
|
+
import type { SelectItem, SelectNode, SelectNodeAppearances } from '../client/SelectNode.ts';
|
|
6
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
7
|
+
import type { AnyViolation, LeafNodeValidationState } from '../client/validation.ts';
|
|
7
8
|
import { createSelectItems } from '../lib/reactivity/createSelectItems.ts';
|
|
8
9
|
import { createValueState } from '../lib/reactivity/createValueState.ts';
|
|
9
10
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
@@ -13,16 +14,19 @@ import { createSharedNodeState } from '../lib/reactivity/node-state/createShared
|
|
|
13
14
|
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
14
15
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
15
16
|
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
16
|
-
import type {
|
|
17
|
+
import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
18
|
+
import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
19
|
+
import type { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
|
|
17
20
|
import type { Root } from './Root.ts';
|
|
18
21
|
import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
|
|
19
22
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
20
23
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
21
24
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
22
25
|
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
26
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
23
27
|
import type { ValueContext } from './internal-api/ValueContext.ts';
|
|
24
28
|
|
|
25
|
-
export interface SelectFieldDefinition extends
|
|
29
|
+
export interface SelectFieldDefinition extends LeafNodeDefinition {
|
|
26
30
|
readonly bodyElement: AnySelectDefinition;
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -40,9 +44,11 @@ export class SelectField
|
|
|
40
44
|
SelectNode,
|
|
41
45
|
EvaluationContext,
|
|
42
46
|
SubscribableDependency,
|
|
47
|
+
ValidationContext,
|
|
43
48
|
ValueContext<readonly SelectItem[]>
|
|
44
49
|
{
|
|
45
50
|
private readonly selectExclusive: boolean;
|
|
51
|
+
private readonly validation: SharedValidationState;
|
|
46
52
|
|
|
47
53
|
// InstanceNode
|
|
48
54
|
protected readonly state: SharedNodeState<SelectFieldStateSpec>;
|
|
@@ -50,9 +56,13 @@ export class SelectField
|
|
|
50
56
|
|
|
51
57
|
// SelectNode
|
|
52
58
|
readonly nodeType = 'select';
|
|
53
|
-
|
|
59
|
+
readonly appearances: SelectNodeAppearances;
|
|
54
60
|
readonly currentState: CurrentState<SelectFieldStateSpec>;
|
|
55
61
|
|
|
62
|
+
get validationState(): LeafNodeValidationState {
|
|
63
|
+
return this.validation.currentState;
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
// ValueContext
|
|
57
67
|
readonly encodeValue = (runtimeValue: readonly SelectItem[]): string => {
|
|
58
68
|
const itemValues = new Set(runtimeValue.map(({ value }) => value));
|
|
@@ -83,16 +93,24 @@ export class SelectField
|
|
|
83
93
|
constructor(parent: GeneralParentNode, definition: SelectFieldDefinition) {
|
|
84
94
|
super(parent, definition);
|
|
85
95
|
|
|
96
|
+
this.appearances = definition.bodyElement.appearances;
|
|
86
97
|
this.selectExclusive = definition.bodyElement.type === 'select1';
|
|
87
98
|
|
|
88
99
|
const valueOptions = createSelectItems(this);
|
|
89
100
|
|
|
90
101
|
this.getValueOptions = valueOptions;
|
|
91
102
|
|
|
103
|
+
const sharedStateOptions = {
|
|
104
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
105
|
+
};
|
|
106
|
+
|
|
92
107
|
const state = createSharedNodeState(
|
|
93
108
|
this.scope,
|
|
94
109
|
{
|
|
95
|
-
|
|
110
|
+
reference: this.contextReference,
|
|
111
|
+
readonly: this.isReadonly,
|
|
112
|
+
relevant: this.isRelevant,
|
|
113
|
+
required: this.isRequired,
|
|
96
114
|
|
|
97
115
|
label: createNodeLabel(this, definition),
|
|
98
116
|
hint: createFieldHint(this, definition),
|
|
@@ -100,14 +118,17 @@ export class SelectField
|
|
|
100
118
|
value: createValueState(this),
|
|
101
119
|
valueOptions,
|
|
102
120
|
},
|
|
103
|
-
|
|
104
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
105
|
-
}
|
|
121
|
+
sharedStateOptions
|
|
106
122
|
);
|
|
107
123
|
|
|
108
124
|
this.state = state;
|
|
109
125
|
this.engineState = state.engineState;
|
|
110
126
|
this.currentState = state.currentState;
|
|
127
|
+
this.validation = createValidationState(this, sharedStateOptions);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getViolation(): AnyViolation | null {
|
|
131
|
+
return this.validation.engineState.violation;
|
|
111
132
|
}
|
|
112
133
|
|
|
113
134
|
protected getSelectItemsByValue(
|
|
@@ -120,10 +141,6 @@ export class SelectField
|
|
|
120
141
|
);
|
|
121
142
|
}
|
|
122
143
|
|
|
123
|
-
protected computeReference(parent: GeneralParentNode): string {
|
|
124
|
-
return this.computeChildStepReference(parent);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
144
|
protected updateSelectedItemValues(values: readonly string[]) {
|
|
128
145
|
const itemsByValue = untrack(() => this.getSelectItemsByValue());
|
|
129
146
|
|
|
@@ -201,4 +218,9 @@ export class SelectField
|
|
|
201
218
|
getChildren(): readonly [] {
|
|
202
219
|
return [];
|
|
203
220
|
}
|
|
221
|
+
|
|
222
|
+
// ValidationContext
|
|
223
|
+
isBlank(): boolean {
|
|
224
|
+
return this.engineState.value.length === 0;
|
|
225
|
+
}
|
|
204
226
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { identity } from '@getodk/common/lib/identity.ts';
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
3
|
import type { InputDefinition } from '../body/control/InputDefinition.ts';
|
|
4
|
-
import type { StringNode } from '../client/StringNode.ts';
|
|
5
|
-
import type { TextRange } from '../
|
|
4
|
+
import type { StringNode, StringNodeAppearances } from '../client/StringNode.ts';
|
|
5
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
6
|
+
import type { AnyViolation, LeafNodeValidationState } from '../client/validation.ts';
|
|
6
7
|
import { createValueState } from '../lib/reactivity/createValueState.ts';
|
|
7
8
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
8
9
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
@@ -11,17 +12,20 @@ import { createSharedNodeState } from '../lib/reactivity/node-state/createShared
|
|
|
11
12
|
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
12
13
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
13
14
|
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
14
|
-
import type {
|
|
15
|
+
import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
16
|
+
import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
17
|
+
import type { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
|
|
15
18
|
import type { Root } from './Root.ts';
|
|
16
19
|
import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
|
|
17
20
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
18
21
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
19
22
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
20
23
|
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
24
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
21
25
|
import type { ValueContext } from './internal-api/ValueContext.ts';
|
|
22
26
|
|
|
23
|
-
export interface StringFieldDefinition extends
|
|
24
|
-
readonly bodyElement: InputDefinition
|
|
27
|
+
export interface StringFieldDefinition extends LeafNodeDefinition {
|
|
28
|
+
readonly bodyElement: InputDefinition;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
interface StringFieldStateSpec extends DescendantNodeStateSpec<string> {
|
|
@@ -34,8 +38,14 @@ interface StringFieldStateSpec extends DescendantNodeStateSpec<string> {
|
|
|
34
38
|
|
|
35
39
|
export class StringField
|
|
36
40
|
extends DescendantNode<StringFieldDefinition, StringFieldStateSpec, null>
|
|
37
|
-
implements
|
|
41
|
+
implements
|
|
42
|
+
StringNode,
|
|
43
|
+
EvaluationContext,
|
|
44
|
+
SubscribableDependency,
|
|
45
|
+
ValidationContext,
|
|
46
|
+
ValueContext<string>
|
|
38
47
|
{
|
|
48
|
+
private readonly validation: SharedValidationState;
|
|
39
49
|
protected readonly state: SharedNodeState<StringFieldStateSpec>;
|
|
40
50
|
|
|
41
51
|
// InstanceNode
|
|
@@ -43,9 +53,13 @@ export class StringField
|
|
|
43
53
|
|
|
44
54
|
// StringNode
|
|
45
55
|
readonly nodeType = 'string';
|
|
46
|
-
|
|
56
|
+
readonly appearances: StringNodeAppearances;
|
|
47
57
|
readonly currentState: CurrentState<StringFieldStateSpec>;
|
|
48
58
|
|
|
59
|
+
get validationState(): LeafNodeValidationState {
|
|
60
|
+
return this.validation.currentState;
|
|
61
|
+
}
|
|
62
|
+
|
|
49
63
|
// ValueContext
|
|
50
64
|
readonly encodeValue = identity<string>;
|
|
51
65
|
|
|
@@ -54,10 +68,19 @@ export class StringField
|
|
|
54
68
|
constructor(parent: GeneralParentNode, definition: StringFieldDefinition) {
|
|
55
69
|
super(parent, definition);
|
|
56
70
|
|
|
71
|
+
this.appearances = definition.bodyElement.appearances;
|
|
72
|
+
|
|
73
|
+
const sharedStateOptions = {
|
|
74
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
75
|
+
};
|
|
76
|
+
|
|
57
77
|
const state = createSharedNodeState(
|
|
58
78
|
this.scope,
|
|
59
79
|
{
|
|
60
|
-
|
|
80
|
+
reference: this.contextReference,
|
|
81
|
+
readonly: this.isReadonly,
|
|
82
|
+
relevant: this.isRelevant,
|
|
83
|
+
required: this.isRequired,
|
|
61
84
|
|
|
62
85
|
label: createNodeLabel(this, definition),
|
|
63
86
|
hint: createFieldHint(this, definition),
|
|
@@ -65,18 +88,22 @@ export class StringField
|
|
|
65
88
|
valueOptions: null,
|
|
66
89
|
value: createValueState(this),
|
|
67
90
|
},
|
|
68
|
-
|
|
69
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
70
|
-
}
|
|
91
|
+
sharedStateOptions
|
|
71
92
|
);
|
|
72
93
|
|
|
73
94
|
this.state = state;
|
|
74
95
|
this.engineState = state.engineState;
|
|
75
96
|
this.currentState = state.currentState;
|
|
97
|
+
this.validation = createValidationState(this, sharedStateOptions);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getViolation(): AnyViolation | null {
|
|
101
|
+
return this.validation.engineState.violation;
|
|
76
102
|
}
|
|
77
103
|
|
|
78
|
-
|
|
79
|
-
|
|
104
|
+
// ValidationContext
|
|
105
|
+
isBlank(): boolean {
|
|
106
|
+
return this.engineState.value === '';
|
|
80
107
|
}
|
|
81
108
|
|
|
82
109
|
// InstanceNode
|
package/src/instance/Subtree.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Accessor } from 'solid-js';
|
|
2
2
|
import type { SubtreeDefinition, SubtreeNode } from '../client/SubtreeNode.ts';
|
|
3
|
+
import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
3
4
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
4
5
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
5
6
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -8,6 +9,7 @@ import type { CurrentState } from '../lib/reactivity/node-state/createCurrentSta
|
|
|
8
9
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
9
10
|
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
10
11
|
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
12
|
+
import { createAggregatedViolations } from '../lib/reactivity/validation/createAggregatedViolations.ts';
|
|
11
13
|
import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
|
|
12
14
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
13
15
|
import { buildChildren } from './children.ts';
|
|
@@ -36,8 +38,9 @@ export class Subtree
|
|
|
36
38
|
|
|
37
39
|
// SubtreeNode
|
|
38
40
|
readonly nodeType = 'subtree';
|
|
39
|
-
|
|
41
|
+
readonly appearances = null;
|
|
40
42
|
readonly currentState: MaterializedChildren<CurrentState<SubtreeStateSpec>, GeneralChildNode>;
|
|
43
|
+
readonly validationState: AncestorNodeValidationState;
|
|
41
44
|
|
|
42
45
|
constructor(parent: GeneralParentNode, definition: SubtreeDefinition) {
|
|
43
46
|
super(parent, definition);
|
|
@@ -46,10 +49,17 @@ export class Subtree
|
|
|
46
49
|
|
|
47
50
|
this.childrenState = childrenState;
|
|
48
51
|
|
|
52
|
+
const sharedStateOptions = {
|
|
53
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
54
|
+
};
|
|
55
|
+
|
|
49
56
|
const state = createSharedNodeState(
|
|
50
57
|
this.scope,
|
|
51
58
|
{
|
|
52
|
-
|
|
59
|
+
reference: this.contextReference,
|
|
60
|
+
readonly: this.isReadonly,
|
|
61
|
+
relevant: this.isRelevant,
|
|
62
|
+
required: this.isRequired,
|
|
53
63
|
|
|
54
64
|
label: null,
|
|
55
65
|
hint: null,
|
|
@@ -57,20 +67,19 @@ export class Subtree
|
|
|
57
67
|
valueOptions: null,
|
|
58
68
|
value: null,
|
|
59
69
|
},
|
|
60
|
-
|
|
61
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
62
|
-
}
|
|
70
|
+
sharedStateOptions
|
|
63
71
|
);
|
|
64
72
|
|
|
65
73
|
this.state = state;
|
|
66
74
|
this.engineState = state.engineState;
|
|
67
|
-
this.currentState = materializeCurrentStateChildren(
|
|
75
|
+
this.currentState = materializeCurrentStateChildren(
|
|
76
|
+
this.scope,
|
|
77
|
+
state.currentState,
|
|
78
|
+
childrenState
|
|
79
|
+
);
|
|
68
80
|
|
|
69
81
|
childrenState.setChildren(buildChildren(this));
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
protected computeReference(parent: GeneralParentNode): string {
|
|
73
|
-
return this.computeChildStepReference(parent);
|
|
82
|
+
this.validationState = createAggregatedViolations(this, sharedStateOptions);
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
getChildren(): readonly GeneralChildNode[] {
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import type { XFormsXPathEvaluator } from '@getodk/xpath';
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
|
-
import { createMemo } from 'solid-js';
|
|
4
3
|
import type { BaseNode } from '../../client/BaseNode.ts';
|
|
5
4
|
import { createComputedExpression } from '../../lib/reactivity/createComputedExpression.ts';
|
|
6
5
|
import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
|
|
7
6
|
import type { AnyDescendantNodeDefinition } from '../../model/DescendentNodeDefinition.ts';
|
|
7
|
+
import type { LeafNodeDefinition } from '../../model/LeafNodeDefinition.ts';
|
|
8
8
|
import type { AnyNodeDefinition } from '../../model/NodeDefinition.ts';
|
|
9
9
|
import type { RepeatInstanceDefinition } from '../../model/RepeatInstanceDefinition.ts';
|
|
10
|
-
import type {
|
|
11
|
-
import type { RepeatInstance } from '../RepeatInstance.ts';
|
|
12
|
-
import type { RepeatRange } from '../RepeatRange.ts';
|
|
13
|
-
import type { Root } from '../Root.ts';
|
|
14
|
-
import type { AnyChildNode, GeneralParentNode } from '../hierarchy.ts';
|
|
10
|
+
import type { AnyChildNode, GeneralParentNode, RepeatRange } from '../hierarchy.ts';
|
|
15
11
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
16
12
|
import type { SubscribableDependency } from '../internal-api/SubscribableDependency.ts';
|
|
13
|
+
import type { RepeatInstance } from '../repeat/RepeatInstance.ts';
|
|
14
|
+
import type { Root } from '../Root.ts';
|
|
17
15
|
import type { InstanceNodeStateSpec } from './InstanceNode.ts';
|
|
18
16
|
import { InstanceNode } from './InstanceNode.ts';
|
|
19
17
|
|
|
@@ -38,7 +36,7 @@ export type DescendantNodeDefinition = Extract<
|
|
|
38
36
|
|
|
39
37
|
// prettier-ignore
|
|
40
38
|
export type DescendantNodeParent<Definition extends DescendantNodeDefinition> =
|
|
41
|
-
Definition extends
|
|
39
|
+
Definition extends LeafNodeDefinition
|
|
42
40
|
? GeneralParentNode
|
|
43
41
|
: Definition extends RepeatInstanceDefinition
|
|
44
42
|
? RepeatRange
|
|
@@ -52,6 +50,10 @@ export type AnyDescendantNode = DescendantNode<
|
|
|
52
50
|
any
|
|
53
51
|
>;
|
|
54
52
|
|
|
53
|
+
interface DescendantNodeOptions {
|
|
54
|
+
readonly computeReference?: Accessor<string>;
|
|
55
|
+
}
|
|
56
|
+
|
|
55
57
|
export abstract class DescendantNode<
|
|
56
58
|
Definition extends DescendantNodeDefinition,
|
|
57
59
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -61,63 +63,62 @@ export abstract class DescendantNode<
|
|
|
61
63
|
extends InstanceNode<Definition, Spec, Child>
|
|
62
64
|
implements BaseNode, EvaluationContext, SubscribableDependency
|
|
63
65
|
{
|
|
66
|
+
readonly hasReadonlyAncestor: Accessor<boolean> = () => {
|
|
67
|
+
const { parent } = this;
|
|
68
|
+
|
|
69
|
+
return parent.hasReadonlyAncestor() || parent.isReadonly();
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
readonly isSelfReadonly: Accessor<boolean>;
|
|
73
|
+
|
|
74
|
+
readonly isReadonly: Accessor<boolean> = () => {
|
|
75
|
+
if (this.hasReadonlyAncestor()) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return this.isSelfReadonly();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
readonly hasNonRelevantAncestor: Accessor<boolean> = () => {
|
|
83
|
+
const { parent } = this;
|
|
84
|
+
|
|
85
|
+
return parent.hasNonRelevantAncestor() || !parent.isRelevant();
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
readonly isSelfRelevant: Accessor<boolean>;
|
|
89
|
+
|
|
90
|
+
readonly isRelevant: Accessor<boolean> = () => {
|
|
91
|
+
if (this.hasNonRelevantAncestor()) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return this.isSelfRelevant();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
readonly isRequired: Accessor<boolean>;
|
|
99
|
+
|
|
64
100
|
readonly root: Root;
|
|
65
101
|
readonly evaluator: XFormsXPathEvaluator;
|
|
66
102
|
readonly contextNode: Element;
|
|
67
103
|
|
|
68
104
|
constructor(
|
|
69
105
|
override readonly parent: DescendantNodeParent<Definition>,
|
|
70
|
-
override readonly definition: Definition
|
|
106
|
+
override readonly definition: Definition,
|
|
107
|
+
options?: DescendantNodeOptions
|
|
71
108
|
) {
|
|
72
|
-
super(parent.engineConfig, parent, definition);
|
|
109
|
+
super(parent.engineConfig, parent, definition, options);
|
|
73
110
|
|
|
74
111
|
const { evaluator, root } = parent;
|
|
75
112
|
|
|
76
113
|
this.root = root;
|
|
77
114
|
this.evaluator = evaluator;
|
|
78
115
|
this.contextNode = this.initializeContextNode(parent.contextNode, definition.nodeName);
|
|
79
|
-
}
|
|
80
116
|
|
|
81
|
-
|
|
82
|
-
return `${parent.contextReference}/${this.definition.nodeName}`;
|
|
83
|
-
}
|
|
117
|
+
const { readonly, relevant, required } = definition.bind;
|
|
84
118
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
): string;
|
|
89
|
-
|
|
90
|
-
protected buildSharedStateSpec(
|
|
91
|
-
parent: DescendantNodeParent<Definition>,
|
|
92
|
-
definition: Definition
|
|
93
|
-
): DescendantNodeSharedStateSpec {
|
|
94
|
-
return this.scope.runTask(() => {
|
|
95
|
-
const reference = createMemo(() => this.contextReference);
|
|
96
|
-
const { bind } = definition;
|
|
97
|
-
|
|
98
|
-
// TODO: we can likely short-circuit `readonly` computation when a node
|
|
99
|
-
// is non-relevant.
|
|
100
|
-
const selfReadonly = createComputedExpression(this, bind.readonly);
|
|
101
|
-
const readonly = createMemo(() => {
|
|
102
|
-
return parent.isReadonly || selfReadonly();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const selfRelevant = createComputedExpression(this, bind.relevant);
|
|
106
|
-
const relevant = createMemo(() => {
|
|
107
|
-
return parent.isRelevant && selfRelevant();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// TODO: we can likely short-circuit `required` computation when a node
|
|
111
|
-
// is non-relevant.
|
|
112
|
-
const required = createComputedExpression(this, bind.required);
|
|
113
|
-
|
|
114
|
-
return {
|
|
115
|
-
reference,
|
|
116
|
-
readonly,
|
|
117
|
-
relevant,
|
|
118
|
-
required,
|
|
119
|
-
};
|
|
120
|
-
});
|
|
119
|
+
this.isSelfReadonly = createComputedExpression(this, readonly);
|
|
120
|
+
this.isSelfRelevant = createComputedExpression(this, relevant);
|
|
121
|
+
this.isRequired = createComputedExpression(this, required);
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
protected createContextNode(parentContextNode: Element, nodeName: string): Element {
|