@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,8 +1,9 @@
|
|
|
1
1
|
import type { XFormsXPathEvaluator } from '@getodk/xpath';
|
|
2
2
|
import type { Accessor, Signal } from 'solid-js';
|
|
3
|
-
import { createSignal } from 'solid-js';
|
|
4
3
|
import type { BaseNode } from '../../client/BaseNode.ts';
|
|
4
|
+
import type { NodeAppearances } from '../../client/NodeAppearances.ts';
|
|
5
5
|
import type { InstanceNodeType } from '../../client/node-types.ts';
|
|
6
|
+
import type { NodeValidationState } from '../../client/validation.ts';
|
|
6
7
|
import type { TextRange } from '../../index.ts';
|
|
7
8
|
import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
8
9
|
import type { CurrentState } from '../../lib/reactivity/node-state/createCurrentState.ts';
|
|
@@ -40,10 +41,6 @@ type AnyInstanceNode = InstanceNode<
|
|
|
40
41
|
any
|
|
41
42
|
>;
|
|
42
43
|
|
|
43
|
-
interface InitializedStateOptions<T, K extends keyof T> {
|
|
44
|
-
readonly uninitializedFallback: T[K];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
44
|
/**
|
|
48
45
|
* This type has the same effect as {@link MaterializedChildren}, but abstractly
|
|
49
46
|
* handles leaf node types as well.
|
|
@@ -61,6 +58,21 @@ export type InstanceNodeCurrentState<
|
|
|
61
58
|
: null;
|
|
62
59
|
};
|
|
63
60
|
|
|
61
|
+
interface ComputableReferenceNode {
|
|
62
|
+
readonly parent: AnyParentNode | null;
|
|
63
|
+
readonly definition: AnyNodeDefinition;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type ComputeInstanceNodeReference = <This extends ComputableReferenceNode>(
|
|
67
|
+
this: This,
|
|
68
|
+
parent: This['parent'],
|
|
69
|
+
definition: This['definition']
|
|
70
|
+
) => string;
|
|
71
|
+
|
|
72
|
+
export interface InstanceNodeOptions {
|
|
73
|
+
readonly computeReference?: () => string;
|
|
74
|
+
}
|
|
75
|
+
|
|
64
76
|
export abstract class InstanceNode<
|
|
65
77
|
Definition extends AnyNodeDefinition,
|
|
66
78
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -69,60 +81,32 @@ export abstract class InstanceNode<
|
|
|
69
81
|
>
|
|
70
82
|
implements BaseNode, EvaluationContext, SubscribableDependency
|
|
71
83
|
{
|
|
72
|
-
protected readonly isStateInitialized: Accessor<boolean>;
|
|
73
|
-
|
|
74
84
|
protected abstract readonly state: SharedNodeState<Spec>;
|
|
75
85
|
protected abstract readonly engineState: EngineState<Spec>;
|
|
76
86
|
|
|
77
87
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* defined and thus isn't assigned.
|
|
81
|
-
*
|
|
82
|
-
* The fallback value specified in {@link options} will be returned on access
|
|
83
|
-
* until {@link isStateInitialized} returns true. This ensures:
|
|
84
|
-
*
|
|
85
|
-
* - a value of the expected type will be available
|
|
86
|
-
* - any read access will become reactive to the actual state, once it has
|
|
87
|
-
* been initialized and {@link engineState} is assigned
|
|
88
|
-
*
|
|
89
|
-
* @todo This is one among several chicken/egg problems encountered trying to
|
|
90
|
-
* support state initialization in which some aspects of the state derive from
|
|
91
|
-
* other aspects of it. It would be nice to dispense with this entirely. But
|
|
92
|
-
* if it must persist, we should also consider replacing the method with a
|
|
93
|
-
* direct accessor once state initialization completes, so the initialized
|
|
94
|
-
* check is only called until it becomes impertinent.
|
|
88
|
+
* @package Exposed on every node type to facilitate inheritance, as well as
|
|
89
|
+
* conditional behavior for value nodes.
|
|
95
90
|
*/
|
|
96
|
-
|
|
97
|
-
key: K,
|
|
98
|
-
options: InitializedStateOptions<EngineState<Spec>, K>
|
|
99
|
-
): EngineState<Spec>[K] {
|
|
100
|
-
if (this.isStateInitialized()) {
|
|
101
|
-
return this.engineState[key];
|
|
102
|
-
}
|
|
91
|
+
abstract readonly hasReadonlyAncestor: Accessor<boolean>;
|
|
103
92
|
|
|
104
|
-
|
|
105
|
-
|
|
93
|
+
/**
|
|
94
|
+
* @package Exposed on every node type to facilitate inheritance, as well as
|
|
95
|
+
* conditional behavior for value nodes.
|
|
96
|
+
*/
|
|
97
|
+
abstract readonly isReadonly: Accessor<boolean>;
|
|
106
98
|
|
|
107
99
|
/**
|
|
108
100
|
* @package Exposed on every node type to facilitate inheritance, as well as
|
|
109
101
|
* conditional behavior for value nodes.
|
|
110
102
|
*/
|
|
111
|
-
|
|
112
|
-
return (this as AnyInstanceNode).getInitializedState('readonly', {
|
|
113
|
-
uninitializedFallback: false,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
103
|
+
abstract readonly hasNonRelevantAncestor: Accessor<boolean>;
|
|
116
104
|
|
|
117
105
|
/**
|
|
118
106
|
* @package Exposed on every node type to facilitate inheritance, as well as
|
|
119
107
|
* conditional behavior for value nodes.
|
|
120
108
|
*/
|
|
121
|
-
|
|
122
|
-
return (this as AnyInstanceNode).getInitializedState('relevant', {
|
|
123
|
-
uninitializedFallback: true,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
109
|
+
abstract readonly isRelevant: Accessor<boolean>;
|
|
126
110
|
|
|
127
111
|
// BaseNode: identity
|
|
128
112
|
readonly nodeId: NodeID;
|
|
@@ -130,8 +114,12 @@ export abstract class InstanceNode<
|
|
|
130
114
|
// BaseNode: node types and variants (e.g. for narrowing)
|
|
131
115
|
abstract readonly nodeType: InstanceNodeType;
|
|
132
116
|
|
|
117
|
+
abstract readonly appearances: NodeAppearances<Definition>;
|
|
118
|
+
|
|
133
119
|
abstract readonly currentState: InstanceNodeCurrentState<Spec, Child>;
|
|
134
120
|
|
|
121
|
+
abstract readonly validationState: NodeValidationState;
|
|
122
|
+
|
|
135
123
|
// BaseNode: structural
|
|
136
124
|
abstract readonly root: Root;
|
|
137
125
|
|
|
@@ -141,35 +129,40 @@ export abstract class InstanceNode<
|
|
|
141
129
|
// EvaluationContext *and* Subscribable: node-specific
|
|
142
130
|
readonly scope: ReactiveScope;
|
|
143
131
|
|
|
132
|
+
readonly computeReference: ComputeInstanceNodeReference;
|
|
133
|
+
|
|
134
|
+
protected readonly computeChildStepReference: ComputeInstanceNodeReference = (
|
|
135
|
+
parent,
|
|
136
|
+
definition
|
|
137
|
+
): string => {
|
|
138
|
+
if (parent == null) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
'Cannot compute child step reference of node without parent (was this called from `Root`?)'
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return `${parent.contextReference()}/${definition.nodeName}`;
|
|
145
|
+
};
|
|
146
|
+
|
|
144
147
|
// EvaluationContext: node-specific
|
|
145
|
-
|
|
148
|
+
readonly contextReference = (): string => {
|
|
146
149
|
return this.computeReference(this.parent, this.definition);
|
|
147
|
-
}
|
|
150
|
+
};
|
|
148
151
|
|
|
149
152
|
abstract readonly contextNode: Element;
|
|
150
153
|
|
|
151
154
|
constructor(
|
|
152
155
|
readonly engineConfig: InstanceConfig,
|
|
153
156
|
readonly parent: AnyParentNode | null,
|
|
154
|
-
readonly definition: Definition
|
|
157
|
+
readonly definition: Definition,
|
|
158
|
+
options?: InstanceNodeOptions
|
|
155
159
|
) {
|
|
160
|
+
this.computeReference = options?.computeReference ?? this.computeChildStepReference;
|
|
161
|
+
|
|
156
162
|
this.scope = createReactiveScope();
|
|
157
163
|
this.engineConfig = engineConfig;
|
|
158
164
|
this.nodeId = declareNodeID(engineConfig.createUniqueId());
|
|
159
165
|
this.definition = definition;
|
|
160
|
-
|
|
161
|
-
const checkStateInitialized = () => this.engineState != null;
|
|
162
|
-
const [isStateInitialized, setStateInitialized] = createSignal(checkStateInitialized());
|
|
163
|
-
|
|
164
|
-
this.isStateInitialized = isStateInitialized;
|
|
165
|
-
|
|
166
|
-
queueMicrotask(() => {
|
|
167
|
-
if (checkStateInitialized()) {
|
|
168
|
-
setStateInitialized(true);
|
|
169
|
-
} else {
|
|
170
|
-
throw new Error('Node state was never initialized');
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
166
|
}
|
|
174
167
|
|
|
175
168
|
/**
|
|
@@ -184,18 +177,13 @@ export abstract class InstanceNode<
|
|
|
184
177
|
*/
|
|
185
178
|
abstract getChildren(this: AnyInstanceNode): readonly AnyChildNode[];
|
|
186
179
|
|
|
187
|
-
|
|
188
|
-
parent: AnyInstanceNode | null,
|
|
189
|
-
definition: Definition
|
|
190
|
-
): string;
|
|
191
|
-
|
|
192
|
-
getNodeByReference(
|
|
180
|
+
getNodesByReference(
|
|
193
181
|
this: AnyNode,
|
|
194
182
|
visited: WeakSet<AnyNode>,
|
|
195
183
|
dependencyReference: string
|
|
196
|
-
): SubscribableDependency
|
|
184
|
+
): readonly SubscribableDependency[] {
|
|
197
185
|
if (visited.has(this)) {
|
|
198
|
-
return
|
|
186
|
+
return [];
|
|
199
187
|
}
|
|
200
188
|
|
|
201
189
|
visited.add(this);
|
|
@@ -203,39 +191,37 @@ export abstract class InstanceNode<
|
|
|
203
191
|
const { nodeset } = this.definition;
|
|
204
192
|
|
|
205
193
|
if (dependencyReference === nodeset) {
|
|
206
|
-
|
|
194
|
+
if (this.nodeType === 'repeat-instance') {
|
|
195
|
+
return [this.parent];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return [this];
|
|
207
199
|
}
|
|
208
200
|
|
|
209
201
|
if (
|
|
210
202
|
dependencyReference.startsWith(`${nodeset}/`) ||
|
|
211
203
|
dependencyReference.startsWith(`${nodeset}[`)
|
|
212
204
|
) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
for (const child of children) {
|
|
220
|
-
const dependency = child.getNodeByReference(visited, dependencyReference);
|
|
221
|
-
|
|
222
|
-
if (dependency != null) {
|
|
223
|
-
return dependency;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
205
|
+
return this.getChildren().flatMap((child) => {
|
|
206
|
+
return child.getNodesByReference(visited, dependencyReference);
|
|
207
|
+
});
|
|
226
208
|
}
|
|
227
209
|
|
|
228
|
-
return this.parent?.
|
|
210
|
+
return this.parent?.getNodesByReference(visited, dependencyReference) ?? [];
|
|
229
211
|
}
|
|
230
212
|
|
|
231
213
|
// EvaluationContext: node-relative
|
|
232
|
-
|
|
214
|
+
getSubscribableDependenciesByReference(
|
|
233
215
|
this: AnyNode,
|
|
234
216
|
reference: string
|
|
235
|
-
): SubscribableDependency
|
|
236
|
-
|
|
217
|
+
): readonly SubscribableDependency[] {
|
|
218
|
+
if (this.nodeType === 'root') {
|
|
219
|
+
const visited = new WeakSet<AnyNode>();
|
|
237
220
|
|
|
238
|
-
|
|
221
|
+
return this.getNodesByReference(visited, reference);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return this.root.getSubscribableDependenciesByReference(reference);
|
|
239
225
|
}
|
|
240
226
|
|
|
241
227
|
// SubscribableDependency
|
|
@@ -247,11 +233,22 @@ export abstract class InstanceNode<
|
|
|
247
233
|
subscribe(): void {
|
|
248
234
|
const { engineState } = this;
|
|
249
235
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
236
|
+
// Note: a previous iteration of this default implementation guarded these
|
|
237
|
+
// reactive reads behind a relevance check. This caused timing issues for
|
|
238
|
+
// downstream computations referencing a node whose relevance changes.
|
|
239
|
+
//
|
|
240
|
+
// That original guard was intended to reduce excessive redundant
|
|
241
|
+
// computations, and so removing it is intended as a naive compromise of
|
|
242
|
+
// performance for obvious correctness improvements.
|
|
243
|
+
//
|
|
244
|
+
// This compromise, like many others, will be moot if/when we decide to
|
|
245
|
+
// decouple XPath evaluation from the browser/XML DOM: reactive
|
|
246
|
+
// subscriptions would be established by evaluation of the expressions
|
|
247
|
+
// themselves (as they traverse instance state and access values), rather
|
|
248
|
+
// than this safer/less focused approach.
|
|
249
|
+
engineState.reference;
|
|
250
|
+
engineState.relevant;
|
|
251
|
+
engineState.children;
|
|
252
|
+
engineState.value;
|
|
256
253
|
}
|
|
257
254
|
}
|
package/src/instance/children.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { UnreachableError } from '@getodk/common/lib/error/UnreachableError.ts';
|
|
2
|
-
import { SelectDefinition } from '../body/control/select/SelectDefinition.ts';
|
|
3
2
|
import type { GroupDefinition } from '../client/GroupNode.ts';
|
|
4
3
|
import type { SubtreeDefinition } from '../client/SubtreeNode.ts';
|
|
4
|
+
import type { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
|
|
5
5
|
import type { SubtreeDefinition as ModelSubtreeDefinition } from '../model/SubtreeDefinition.ts';
|
|
6
|
+
import { NoteNodeDefinition } from '../parse/NoteNodeDefinition.ts';
|
|
6
7
|
import { Group } from './Group.ts';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
|
|
9
|
+
import { ModelValue, type ModelValueDefinition } from './ModelValue.ts';
|
|
10
|
+
import { Note } from './Note.ts';
|
|
11
|
+
import { RepeatRangeControlled } from './repeat/RepeatRangeControlled.ts';
|
|
12
|
+
import { RepeatRangeUncontrolled } from './repeat/RepeatRangeUncontrolled.ts';
|
|
13
|
+
import type { SelectFieldDefinition } from './SelectField.ts';
|
|
14
|
+
import { SelectField } from './SelectField.ts';
|
|
15
|
+
import type { StringFieldDefinition } from './StringField.ts';
|
|
9
16
|
import { StringField } from './StringField.ts';
|
|
10
17
|
import { Subtree } from './Subtree.ts';
|
|
11
|
-
import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
|
|
12
18
|
|
|
13
19
|
const isSubtreeDefinition = (
|
|
14
20
|
definition: ModelSubtreeDefinition
|
|
@@ -16,6 +22,22 @@ const isSubtreeDefinition = (
|
|
|
16
22
|
return definition.bodyElement == null;
|
|
17
23
|
};
|
|
18
24
|
|
|
25
|
+
type ControlNodeDefinition = SelectFieldDefinition | StringFieldDefinition;
|
|
26
|
+
|
|
27
|
+
type AnyLeafNodeDefinition = ControlNodeDefinition | ModelValueDefinition;
|
|
28
|
+
|
|
29
|
+
const isModelValueDefinition = (
|
|
30
|
+
definition: LeafNodeDefinition
|
|
31
|
+
): definition is ModelValueDefinition => {
|
|
32
|
+
return definition.bodyElement == null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const isStringFieldDefinition = (
|
|
36
|
+
definition: ControlNodeDefinition
|
|
37
|
+
): definition is StringFieldDefinition => {
|
|
38
|
+
return definition.bodyElement.type === 'input';
|
|
39
|
+
};
|
|
40
|
+
|
|
19
41
|
export const buildChildren = (parent: GeneralParentNode): GeneralChildNode[] => {
|
|
20
42
|
const { children } = parent.definition;
|
|
21
43
|
|
|
@@ -32,16 +54,31 @@ export const buildChildren = (parent: GeneralParentNode): GeneralChildNode[] =>
|
|
|
32
54
|
return new Group(parent, child as GroupDefinition);
|
|
33
55
|
}
|
|
34
56
|
|
|
35
|
-
case 'repeat-
|
|
36
|
-
|
|
57
|
+
case 'repeat-range': {
|
|
58
|
+
if (child.isControlled()) {
|
|
59
|
+
return new RepeatRangeControlled(parent, child);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return new RepeatRangeUncontrolled(parent, child);
|
|
37
63
|
}
|
|
38
64
|
|
|
39
|
-
case '
|
|
40
|
-
if (child
|
|
41
|
-
return new
|
|
65
|
+
case 'leaf-node': {
|
|
66
|
+
if (child instanceof NoteNodeDefinition) {
|
|
67
|
+
return new Note(parent, child);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// More specific type helps with narrowing below
|
|
71
|
+
const leafChild: AnyLeafNodeDefinition = child;
|
|
72
|
+
|
|
73
|
+
if (isModelValueDefinition(leafChild)) {
|
|
74
|
+
return new ModelValue(parent, leafChild);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isStringFieldDefinition(leafChild)) {
|
|
78
|
+
return new StringField(parent, leafChild);
|
|
42
79
|
}
|
|
43
80
|
|
|
44
|
-
return new
|
|
81
|
+
return new SelectField(parent, leafChild);
|
|
45
82
|
}
|
|
46
83
|
|
|
47
84
|
default: {
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import type { Group } from './Group.ts';
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
2
|
+
import type { ModelValue } from './ModelValue.ts';
|
|
3
|
+
import type { Note } from './Note.ts';
|
|
4
|
+
import type { RepeatInstance } from './repeat/RepeatInstance.ts';
|
|
5
|
+
import type { RepeatRangeControlled } from './repeat/RepeatRangeControlled.ts';
|
|
6
|
+
import type { RepeatRangeUncontrolled } from './repeat/RepeatRangeUncontrolled.ts';
|
|
4
7
|
import type { Root } from './Root.ts';
|
|
5
8
|
import type { SelectField } from './SelectField.ts';
|
|
6
9
|
import type { StringField } from './StringField.ts';
|
|
7
10
|
import type { Subtree } from './Subtree.ts';
|
|
8
11
|
|
|
12
|
+
export type RepeatRange = RepeatRangeControlled | RepeatRangeUncontrolled;
|
|
13
|
+
|
|
9
14
|
// prettier-ignore
|
|
10
15
|
export type AnyNode =
|
|
11
16
|
// eslint-disable-next-line @typescript-eslint/sort-type-constituents
|
|
@@ -14,6 +19,8 @@ export type AnyNode =
|
|
|
14
19
|
| Subtree
|
|
15
20
|
| RepeatRange
|
|
16
21
|
| RepeatInstance
|
|
22
|
+
| Note
|
|
23
|
+
| ModelValue
|
|
17
24
|
| StringField
|
|
18
25
|
| SelectField;
|
|
19
26
|
|
|
@@ -41,6 +48,8 @@ export type AnyChildNode =
|
|
|
41
48
|
| Subtree
|
|
42
49
|
| RepeatRange
|
|
43
50
|
| RepeatInstance
|
|
51
|
+
| ModelValue
|
|
52
|
+
| Note
|
|
44
53
|
| StringField
|
|
45
54
|
| SelectField;
|
|
46
55
|
|
|
@@ -50,5 +59,15 @@ export type GeneralChildNode =
|
|
|
50
59
|
| Group
|
|
51
60
|
| Subtree
|
|
52
61
|
| RepeatRange
|
|
62
|
+
| ModelValue
|
|
63
|
+
| Note
|
|
64
|
+
| StringField
|
|
65
|
+
| SelectField;
|
|
66
|
+
|
|
67
|
+
// prettier-ignore
|
|
68
|
+
export type AnyValueNode =
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/sort-type-constituents
|
|
70
|
+
| ModelValue
|
|
71
|
+
| Note
|
|
53
72
|
| StringField
|
|
54
73
|
| SelectField;
|
package/src/instance/index.ts
CHANGED
|
@@ -31,7 +31,7 @@ export const initializeForm = async (
|
|
|
31
31
|
const sourceXML = await retrieveSourceXMLResource(input, engineConfig);
|
|
32
32
|
const form = new XFormDefinition(sourceXML);
|
|
33
33
|
|
|
34
|
-
return Root
|
|
34
|
+
return new Root(form.xformDOM, form.model.root, engineConfig);
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
initializeForm satisfies InitializeForm;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { XFormsXPathEvaluator } from '@getodk/xpath';
|
|
2
|
+
import type { Accessor } from 'solid-js';
|
|
2
3
|
import type { DependentExpression } from '../../expression/DependentExpression.ts';
|
|
3
4
|
import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
|
|
4
5
|
import type { SubscribableDependency } from './SubscribableDependency.ts';
|
|
@@ -27,15 +28,13 @@ export interface EvaluationContext {
|
|
|
27
28
|
* Produces the current absolute reference to the {@link contextNode}, where
|
|
28
29
|
* the absolute `/` resolves to the active form state's primary instance root.
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
readonly contextReference: Accessor<string>;
|
|
31
32
|
|
|
32
33
|
readonly contextNode: Node;
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
|
-
* Resolves
|
|
36
|
-
* {@link EvaluationContext.contextNode}.
|
|
36
|
+
* Resolves nodes corresponding to the provided node-set reference, possibly
|
|
37
|
+
* relative to the {@link EvaluationContext.contextNode}.
|
|
37
38
|
*/
|
|
38
|
-
|
|
39
|
-
reference: string
|
|
40
|
-
) => SubscribableDependency | null;
|
|
39
|
+
getSubscribableDependenciesByReference(reference: string): readonly SubscribableDependency[];
|
|
41
40
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BindComputation } from '../../model/BindComputation.ts';
|
|
2
|
+
import type { MessageDefinition } from '../../parse/text/MessageDefinition.ts';
|
|
3
|
+
import type { EvaluationContext } from './EvaluationContext.ts';
|
|
4
|
+
import type { SubscribableDependency } from './SubscribableDependency.ts';
|
|
5
|
+
|
|
6
|
+
interface ValidationContextDefinitionBind {
|
|
7
|
+
readonly constraint: BindComputation<'constraint'>;
|
|
8
|
+
readonly constraintMsg: MessageDefinition<'constraintMsg'> | null;
|
|
9
|
+
readonly required: BindComputation<'required'>;
|
|
10
|
+
readonly requiredMsg: MessageDefinition<'requiredMsg'> | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ValidationContextDefinition {
|
|
14
|
+
readonly bind: ValidationContextDefinitionBind;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ValidationContext extends EvaluationContext, SubscribableDependency {
|
|
18
|
+
readonly definition: ValidationContextDefinition;
|
|
19
|
+
|
|
20
|
+
isRelevant(): boolean;
|
|
21
|
+
isRequired(): boolean;
|
|
22
|
+
isBlank(): boolean;
|
|
23
|
+
}
|
|
@@ -19,8 +19,8 @@ export interface ValueContext<RuntimeValue> extends EvaluationContext {
|
|
|
19
19
|
readonly definition: ValueContextDefinition;
|
|
20
20
|
readonly contextNode: Element;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
isReadonly(): boolean;
|
|
23
|
+
isRelevant(): boolean;
|
|
24
24
|
|
|
25
25
|
readonly encodeValue: (this: unknown, runtimeValue: RuntimeValue) => InstanceValue;
|
|
26
26
|
readonly decodeValue: (this: unknown, instanceValue: InstanceValue) => RuntimeValue;
|