@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,214 +0,0 @@
|
|
|
1
|
-
import { insertAtIndex } from '@getodk/common/lib/array/insert.ts';
|
|
2
|
-
import type { Accessor } from 'solid-js';
|
|
3
|
-
import type { RepeatRangeNode } from '../client/RepeatRangeNode.ts';
|
|
4
|
-
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
5
|
-
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
6
|
-
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
7
|
-
import { materializeCurrentStateChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
8
|
-
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
9
|
-
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
10
|
-
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
11
|
-
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
12
|
-
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
13
|
-
import type { RepeatSequenceDefinition } from '../model/RepeatSequenceDefinition.ts';
|
|
14
|
-
import type { RepeatDefinition } from './RepeatInstance.ts';
|
|
15
|
-
import { RepeatInstance } from './RepeatInstance.ts';
|
|
16
|
-
import type { Root } from './Root.ts';
|
|
17
|
-
import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
|
|
18
|
-
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
19
|
-
import type { GeneralParentNode } from './hierarchy.ts';
|
|
20
|
-
import type { NodeID } from './identity.ts';
|
|
21
|
-
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
22
|
-
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
23
|
-
import type { TextRange } from './text/TextRange.ts';
|
|
24
|
-
|
|
25
|
-
interface RepeatRangeStateSpec extends DescendantNodeSharedStateSpec {
|
|
26
|
-
readonly hint: null;
|
|
27
|
-
readonly label: Accessor<TextRange<'label'> | null>;
|
|
28
|
-
readonly children: Accessor<readonly NodeID[]>;
|
|
29
|
-
readonly valueOptions: null;
|
|
30
|
-
readonly value: null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class RepeatRange
|
|
34
|
-
extends DescendantNode<RepeatSequenceDefinition, RepeatRangeStateSpec, RepeatInstance>
|
|
35
|
-
implements RepeatRangeNode, EvaluationContext, SubscribableDependency
|
|
36
|
-
{
|
|
37
|
-
/**
|
|
38
|
-
* A repeat range doesn't have a corresponding primary instance element of its
|
|
39
|
-
* own, and its instances are appended to the range's parent element. During
|
|
40
|
-
* creation of the initial primary instance state and DOM trees, we _could_
|
|
41
|
-
* reliably append all of the range's instances in order as the definition
|
|
42
|
-
* tree is recursed. But that would fail to handle some instance addition
|
|
43
|
-
* cases afterwards.
|
|
44
|
-
*
|
|
45
|
-
* Most notably, we need to know where in the primary instance tree to append
|
|
46
|
-
* instances created for a range which is currently empty. As a lucky
|
|
47
|
-
* coincidence, this need coincides with the ability to add instances at any
|
|
48
|
-
* arbitrary index within the range. In each case, we can reference a primary
|
|
49
|
-
* instance DOM node which will become the new instance's preceding sibling.
|
|
50
|
-
* Where the range is empty, we use this {@link Comment} node (itself created
|
|
51
|
-
* and appended during range initialization) in lieu of a nonexistent
|
|
52
|
-
* preceding instance's {@link contextNode}.
|
|
53
|
-
*
|
|
54
|
-
* @todo We likely want to remove these during submission serialization.
|
|
55
|
-
* @todo Can we use a
|
|
56
|
-
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Range | DOM Range}
|
|
57
|
-
* instead?
|
|
58
|
-
*/
|
|
59
|
-
private readonly anchorNode: Comment;
|
|
60
|
-
|
|
61
|
-
private readonly childrenState: ChildrenState<RepeatInstance>;
|
|
62
|
-
|
|
63
|
-
// InstanceNode
|
|
64
|
-
protected readonly state: SharedNodeState<RepeatRangeStateSpec>;
|
|
65
|
-
protected override engineState: EngineState<RepeatRangeStateSpec>;
|
|
66
|
-
|
|
67
|
-
// RepeatRangeNode
|
|
68
|
-
readonly nodeType = 'repeat-range';
|
|
69
|
-
|
|
70
|
-
readonly currentState: MaterializedChildren<CurrentState<RepeatRangeStateSpec>, RepeatInstance>;
|
|
71
|
-
|
|
72
|
-
constructor(parent: GeneralParentNode, definition: RepeatSequenceDefinition) {
|
|
73
|
-
super(parent, definition);
|
|
74
|
-
|
|
75
|
-
const childrenState = createChildrenState<RepeatRange, RepeatInstance>(this);
|
|
76
|
-
|
|
77
|
-
this.childrenState = childrenState;
|
|
78
|
-
|
|
79
|
-
const state = createSharedNodeState(
|
|
80
|
-
this.scope,
|
|
81
|
-
{
|
|
82
|
-
...this.buildSharedStateSpec(parent, definition),
|
|
83
|
-
|
|
84
|
-
label: createNodeLabel(this, definition),
|
|
85
|
-
hint: null,
|
|
86
|
-
children: childrenState.childIds,
|
|
87
|
-
valueOptions: null,
|
|
88
|
-
value: null,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
this.anchorNode = this.contextNode.ownerDocument.createComment(
|
|
96
|
-
`Begin repeat range: ${definition.nodeset}`
|
|
97
|
-
);
|
|
98
|
-
this.contextNode.append(this.anchorNode);
|
|
99
|
-
|
|
100
|
-
this.state = state;
|
|
101
|
-
this.engineState = state.engineState;
|
|
102
|
-
this.currentState = materializeCurrentStateChildren(state.currentState, childrenState);
|
|
103
|
-
|
|
104
|
-
definition.instances.forEach((instanceDefinition, index) => {
|
|
105
|
-
const afterIndex = index - 1;
|
|
106
|
-
|
|
107
|
-
this.addInstances(afterIndex, 1, instanceDefinition);
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private getLastIndex(): number {
|
|
112
|
-
return this.engineState.children.length - 1;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
protected override initializeContextNode(parentContextNode: Element): Element {
|
|
116
|
-
return parentContextNode;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
protected computeReference(parent: GeneralParentNode): string {
|
|
120
|
-
return this.computeChildStepReference(parent);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
getInstanceIndex(instance: RepeatInstance): number {
|
|
124
|
-
return this.engineState.children.indexOf(instance.nodeId);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
addInstances(
|
|
128
|
-
afterIndex = this.getLastIndex(),
|
|
129
|
-
count = 1,
|
|
130
|
-
definition: RepeatDefinition = this.definition.template
|
|
131
|
-
): Root {
|
|
132
|
-
return this.scope.runTask(() => {
|
|
133
|
-
let precedingInstance: RepeatInstance | null;
|
|
134
|
-
|
|
135
|
-
if (afterIndex === -1) {
|
|
136
|
-
precedingInstance = null;
|
|
137
|
-
} else {
|
|
138
|
-
const instance = this.childrenState.getChildren()[afterIndex];
|
|
139
|
-
|
|
140
|
-
if (instance == null) {
|
|
141
|
-
throw new Error(`No repeat instance at index ${afterIndex}`);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
precedingInstance = instance;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const precedingPrimaryInstanceNode = precedingInstance?.contextNode ?? this.anchorNode;
|
|
148
|
-
|
|
149
|
-
const newInstance = new RepeatInstance(this, definition, {
|
|
150
|
-
precedingPrimaryInstanceNode,
|
|
151
|
-
precedingInstance,
|
|
152
|
-
});
|
|
153
|
-
const initialIndex = afterIndex + 1;
|
|
154
|
-
|
|
155
|
-
this.childrenState.setChildren((currentInstances) => {
|
|
156
|
-
return insertAtIndex(currentInstances, initialIndex, newInstance);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
if (count > 1) {
|
|
160
|
-
return this.addInstances(initialIndex, count - 1);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return this.root;
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Removes the {@link RepeatInstance}s corresponding to the specified range of
|
|
169
|
-
* indexes, and then removes those repeat instances from the repeat range's
|
|
170
|
-
* own children state in that order:
|
|
171
|
-
*
|
|
172
|
-
* 1. Identify the set of {@link RepeatInstance}s to be removed.
|
|
173
|
-
*
|
|
174
|
-
* 2. For each {@link RepeatInstance} pending removal, perform that node's
|
|
175
|
-
* removal logic. @see {@link RepeatInstance.remove} for more detail.
|
|
176
|
-
*
|
|
177
|
-
* 3. Finalize update to the repeat range's own {@link childrenState},
|
|
178
|
-
* omitting those {@link RepeatInstance}s which were removed.
|
|
179
|
-
*
|
|
180
|
-
* This ordering ensures a consistent representation of state is established
|
|
181
|
-
* prior to any downstream reactive updates, and ensures that removed nodes'
|
|
182
|
-
* reactivity is cleaned up.
|
|
183
|
-
*/
|
|
184
|
-
removeInstances(startIndex: number, count = 1): Root {
|
|
185
|
-
return this.scope.runTask(() => {
|
|
186
|
-
this.childrenState.setChildren((currentInstances) => {
|
|
187
|
-
const updatedInstances = currentInstances.slice();
|
|
188
|
-
const removedInstances = updatedInstances.splice(startIndex, count);
|
|
189
|
-
|
|
190
|
-
removedInstances.forEach((instance) => {
|
|
191
|
-
instance.remove();
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
return updatedInstances;
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return this.root;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
override subscribe(): void {
|
|
202
|
-
super.subscribe();
|
|
203
|
-
|
|
204
|
-
// Subscribing to children can support reactive expressions dependent on the
|
|
205
|
-
// repeat range itself (e.g. `count()`).
|
|
206
|
-
this.childrenState.getChildren().forEach((child) => {
|
|
207
|
-
child.subscribe();
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
getChildren(): readonly RepeatInstance[] {
|
|
212
|
-
return this.childrenState.getChildren();
|
|
213
|
-
}
|
|
214
|
-
}
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { UnreachableError } from '@getodk/common/lib/error/UnreachableError';
|
|
2
|
-
import { expressionParser } from '@getodk/xpath/expressionParser.js';
|
|
3
|
-
import type {
|
|
4
|
-
AbsoluteLocationPathNode,
|
|
5
|
-
AnyBinaryExprNode,
|
|
6
|
-
AnySyntaxNode,
|
|
7
|
-
FilterPathExprNode,
|
|
8
|
-
LocalPartNode,
|
|
9
|
-
PrefixedNameNode,
|
|
10
|
-
RelativeLocationPathNode,
|
|
11
|
-
UnprefixedNameNode,
|
|
12
|
-
} from '@getodk/xpath/static/grammar/SyntaxNode.js';
|
|
13
|
-
import type { AnyBinaryExprType } from '@getodk/xpath/static/grammar/type-names.js';
|
|
14
|
-
|
|
15
|
-
export type SingleChildNode = Extract<
|
|
16
|
-
AnySyntaxNode,
|
|
17
|
-
{ readonly children: readonly [AnySyntaxNode] }
|
|
18
|
-
>;
|
|
19
|
-
|
|
20
|
-
const isSingleNodeChild = (node: AnySyntaxNode): node is SingleChildNode => {
|
|
21
|
-
return node.childCount === 1;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const binaryExprNodeTypes = new Set<AnyBinaryExprType>([
|
|
25
|
-
'addition_expr',
|
|
26
|
-
'and_expr',
|
|
27
|
-
'division_expr',
|
|
28
|
-
'eq_expr',
|
|
29
|
-
'gt_expr',
|
|
30
|
-
'gte_expr',
|
|
31
|
-
'lt_expr',
|
|
32
|
-
'lte_expr',
|
|
33
|
-
'modulo_expr',
|
|
34
|
-
'multiplication_expr',
|
|
35
|
-
'ne_expr',
|
|
36
|
-
'or_expr',
|
|
37
|
-
'subtraction_expr',
|
|
38
|
-
'union_expr',
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const isBinaryExprNode = (node: AnySyntaxNode): node is AnyBinaryExprNode => {
|
|
42
|
-
return binaryExprNodeTypes.has(node.type as AnyBinaryExprType);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const matchesLocalName = (
|
|
46
|
-
localName: string,
|
|
47
|
-
nameNode: PrefixedNameNode | UnprefixedNameNode
|
|
48
|
-
): boolean => {
|
|
49
|
-
const localPartNode: LocalPartNode | UnprefixedNameNode =
|
|
50
|
-
nameNode.type === 'prefixed_name' ? nameNode.children[1] : nameNode;
|
|
51
|
-
|
|
52
|
-
return localPartNode.text === localName;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const isFunctionCalled = (localName: string, node: AnySyntaxNode): boolean => {
|
|
56
|
-
if (!node.text.includes(localName)) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (isSingleNodeChild(node)) {
|
|
61
|
-
const [child] = node.children;
|
|
62
|
-
|
|
63
|
-
return isFunctionCalled(localName, child);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (isBinaryExprNode(node)) {
|
|
67
|
-
const [lhs, rhs] = node.children;
|
|
68
|
-
|
|
69
|
-
return isFunctionCalled(localName, lhs) || isFunctionCalled(localName, rhs);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
switch (node.type) {
|
|
73
|
-
// Terminal nodes
|
|
74
|
-
case 'number':
|
|
75
|
-
case 'string_literal':
|
|
76
|
-
case 'variable_reference':
|
|
77
|
-
|
|
78
|
-
// Path sub-nodes which could not have a function call child
|
|
79
|
-
//
|
|
80
|
-
// This only errors because this set of cases is commented:
|
|
81
|
-
// eslint-disable-next-line no-fallthrough
|
|
82
|
-
case '//':
|
|
83
|
-
case 'absolute_root_location_path':
|
|
84
|
-
case 'axis_name':
|
|
85
|
-
case 'node_type_test':
|
|
86
|
-
case 'parent':
|
|
87
|
-
case 'self':
|
|
88
|
-
|
|
89
|
-
// Name nodes are also not function call parents
|
|
90
|
-
//
|
|
91
|
-
// This only errors because this set of cases is commented:
|
|
92
|
-
// eslint-disable-next-line no-fallthrough
|
|
93
|
-
case 'local_part':
|
|
94
|
-
case 'prefixed_name':
|
|
95
|
-
case 'prefix':
|
|
96
|
-
case 'unprefixed_name':
|
|
97
|
-
case 'unprefixed_wildcard_name_test':
|
|
98
|
-
return false;
|
|
99
|
-
|
|
100
|
-
// Path sub-nodes which could have a function call child
|
|
101
|
-
case 'abbreviated_absolute_location_path':
|
|
102
|
-
case 'abbreviated_step':
|
|
103
|
-
case 'absolute_location_path':
|
|
104
|
-
case 'axis_test':
|
|
105
|
-
case 'filter_path_expr':
|
|
106
|
-
case 'relative_location_path':
|
|
107
|
-
case 'step':
|
|
108
|
-
return node.children.some((childNode) => isFunctionCalled(localName, childNode));
|
|
109
|
-
|
|
110
|
-
case 'function_call': {
|
|
111
|
-
const [functionNameNode] = node.children;
|
|
112
|
-
const [nameNode] = functionNameNode.children;
|
|
113
|
-
|
|
114
|
-
return matchesLocalName(localName, nameNode);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
default:
|
|
118
|
-
throw new UnreachableError(node);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export const isItextFunctionCalled = (expression: string): boolean => {
|
|
123
|
-
const { rootNode } = expressionParser.parse(expression);
|
|
124
|
-
|
|
125
|
-
return isFunctionCalled('itext', rootNode);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
type LocationPathSubExpressionNode =
|
|
129
|
-
| AbsoluteLocationPathNode
|
|
130
|
-
| FilterPathExprNode
|
|
131
|
-
| RelativeLocationPathNode;
|
|
132
|
-
|
|
133
|
-
const isAnyLocationPathExprNode = (node: AnySyntaxNode): node is LocationPathSubExpressionNode => {
|
|
134
|
-
const { type } = node;
|
|
135
|
-
|
|
136
|
-
if (type === 'absolute_location_path' || type === 'relative_location_path') {
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return false;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// TODO: this does not currently even attempt to find sub-expressions nested
|
|
144
|
-
// within sub-expressions.
|
|
145
|
-
const findLocationPathExprNodes = (
|
|
146
|
-
node: AnySyntaxNode
|
|
147
|
-
): readonly LocationPathSubExpressionNode[] => {
|
|
148
|
-
const results: LocationPathSubExpressionNode[] = [];
|
|
149
|
-
|
|
150
|
-
if (isAnyLocationPathExprNode(node)) {
|
|
151
|
-
results.push(node);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
results.push(
|
|
155
|
-
...node.children.flatMap((childNode) => {
|
|
156
|
-
return findLocationPathExprNodes(childNode);
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
return results;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// TODO: this is a very small subset of resolution that needs to be supported,
|
|
164
|
-
// and it's a hamfisted hack. **This is temporary** to unblock progress on
|
|
165
|
-
// computations, but a longer term solution will need to address:
|
|
166
|
-
//
|
|
167
|
-
// - non-abbreviation axes (parent, child, self) according to XForms spec
|
|
168
|
-
// - non-leading axes
|
|
169
|
-
// - context expressions which are more complex than a series of explicit
|
|
170
|
-
// element name test steps (this may be fine for binds!)
|
|
171
|
-
const resolveRelativeSubExpression = (contextReference: string | null, expression: string) => {
|
|
172
|
-
if (contextReference == null) {
|
|
173
|
-
return expression;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const [, axisAbbreviation, relativeExpression = ''] = expression.match(/^(\.{1,2})(\/.*$)?/) ?? [
|
|
177
|
-
null,
|
|
178
|
-
'',
|
|
179
|
-
expression,
|
|
180
|
-
];
|
|
181
|
-
|
|
182
|
-
switch (axisAbbreviation) {
|
|
183
|
-
case '':
|
|
184
|
-
return expression;
|
|
185
|
-
|
|
186
|
-
case '.':
|
|
187
|
-
return `${contextReference}${relativeExpression}`;
|
|
188
|
-
|
|
189
|
-
case '..':
|
|
190
|
-
return `${contextReference.replace(/\/[^/]+$/, '')}${relativeExpression}`;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
throw new Error(`Unexpected relative expression: ${expression}`);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
interface GetNodesetDependenciesOptions {
|
|
197
|
-
readonly contextReference?: string | null;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @default false
|
|
201
|
-
*/
|
|
202
|
-
readonly ignoreContextReference?: boolean;
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Ignores location path sub-expressions whose full text is `null`. While this
|
|
206
|
-
* is technically a valid relative name test step, it seems that real forms in
|
|
207
|
-
* the wild use it as if XPath had an actual `null` token/value.
|
|
208
|
-
*
|
|
209
|
-
* @default true
|
|
210
|
-
*/
|
|
211
|
-
readonly ignoreNullExpressions?: boolean;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export const getNodesetDependencies = (
|
|
215
|
-
expression: string,
|
|
216
|
-
options: GetNodesetDependenciesOptions = {}
|
|
217
|
-
): Set<string> => {
|
|
218
|
-
const { rootNode } = expressionParser.parse(expression);
|
|
219
|
-
const subExpressionNodes = findLocationPathExprNodes(rootNode);
|
|
220
|
-
const {
|
|
221
|
-
contextReference = null,
|
|
222
|
-
ignoreContextReference = false,
|
|
223
|
-
ignoreNullExpressions = true,
|
|
224
|
-
} = options;
|
|
225
|
-
|
|
226
|
-
const subExpressions = subExpressionNodes
|
|
227
|
-
.map((syntaxNode) => resolveRelativeSubExpression(contextReference, syntaxNode.text))
|
|
228
|
-
.filter((subExpression) => {
|
|
229
|
-
if (ignoreContextReference && subExpression === contextReference) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (ignoreNullExpressions && subExpression === 'null') {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return true;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
return new Set(subExpressions);
|
|
241
|
-
};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { RepeatGroupDefinition } from '../body/group/RepeatGroupDefinition.ts';
|
|
2
|
-
import type { BindDefinition } from './BindDefinition.ts';
|
|
3
|
-
import { DescendentNodeDefinition } from './DescendentNodeDefinition.ts';
|
|
4
|
-
import type { NodeDefinition, ParentNodeDefinition } from './NodeDefinition.ts';
|
|
5
|
-
import { RepeatInstanceDefinition } from './RepeatInstanceDefinition.ts';
|
|
6
|
-
import { RepeatTemplateDefinition } from './RepeatTemplateDefinition.ts';
|
|
7
|
-
|
|
8
|
-
export class RepeatSequenceDefinition
|
|
9
|
-
extends DescendentNodeDefinition<'repeat-sequence', RepeatGroupDefinition>
|
|
10
|
-
implements NodeDefinition<'repeat-sequence'>
|
|
11
|
-
{
|
|
12
|
-
// TODO: if an implicit template is derived from an instance in a form
|
|
13
|
-
// definition, should its default values (if any) be cleared? Probably!
|
|
14
|
-
static createTemplateElement(instanceElement: Element): Element {
|
|
15
|
-
return instanceElement.cloneNode(true) as Element;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static createInstanceElement(templateElement: Element): Element {
|
|
19
|
-
return templateElement.cloneNode(true) as Element;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
readonly type = 'repeat-sequence';
|
|
23
|
-
|
|
24
|
-
readonly template: RepeatTemplateDefinition;
|
|
25
|
-
readonly children = null;
|
|
26
|
-
readonly instances: RepeatInstanceDefinition[];
|
|
27
|
-
|
|
28
|
-
readonly node = null;
|
|
29
|
-
readonly nodeName: string;
|
|
30
|
-
readonly defaultValue = null;
|
|
31
|
-
|
|
32
|
-
constructor(
|
|
33
|
-
parent: ParentNodeDefinition,
|
|
34
|
-
bind: BindDefinition,
|
|
35
|
-
bodyElement: RepeatGroupDefinition,
|
|
36
|
-
modelNodes: readonly [Element, ...Element[]]
|
|
37
|
-
) {
|
|
38
|
-
super(parent, bind, bodyElement);
|
|
39
|
-
const { template, instanceNodes } = RepeatTemplateDefinition.parseModelNodes(this, modelNodes);
|
|
40
|
-
|
|
41
|
-
this.template = template;
|
|
42
|
-
this.nodeName = template.nodeName;
|
|
43
|
-
this.instances = instanceNodes.map((element) => {
|
|
44
|
-
return new RepeatInstanceDefinition(this, element);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
toJSON() {
|
|
49
|
-
const { bind, bodyElement: groupDefinition, parent, root, ...rest } = this;
|
|
50
|
-
|
|
51
|
-
return rest;
|
|
52
|
-
}
|
|
53
|
-
}
|