@getodk/xforms-engine 0.5.0 → 0.6.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/README.md +1 -1
- package/dist/client/BaseNode.d.ts +4 -0
- package/dist/client/BaseValueNode.d.ts +1 -1
- package/dist/client/GroupNode.d.ts +1 -0
- package/dist/client/InputNode.d.ts +32 -3
- package/dist/client/ModelValueNode.d.ts +1 -0
- package/dist/client/NoteNode.d.ts +24 -7
- package/dist/client/RangeNode.d.ts +36 -0
- package/dist/client/RankNode.d.ts +46 -0
- package/dist/client/RootNode.d.ts +6 -3
- package/dist/client/SelectNode.d.ts +47 -25
- package/dist/client/SubtreeNode.d.ts +1 -0
- package/dist/client/TriggerNode.d.ts +10 -6
- package/dist/client/hierarchy.d.ts +5 -5
- package/dist/client/node-types.d.ts +2 -2
- package/dist/client/unsupported/UnsupportedControlNode.d.ts +1 -3
- package/dist/error/RankMissingValueError.d.ts +3 -0
- package/dist/error/RankValueTypeError.d.ts +6 -0
- package/dist/error/SelectValueTypeError.d.ts +15 -0
- package/dist/error/XFormsSpecViolationError.d.ts +2 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +5604 -4666
- package/dist/index.js.map +1 -1
- package/dist/instance/Group.d.ts +1 -0
- package/dist/instance/InputControl.d.ts +5 -3
- package/dist/instance/ModelValue.d.ts +2 -0
- package/dist/instance/Note.d.ts +13 -25
- package/dist/instance/PrimaryInstance.d.ts +1 -0
- package/dist/instance/RangeControl.d.ts +34 -0
- package/dist/instance/RankControl.d.ts +40 -0
- package/dist/instance/Root.d.ts +1 -0
- package/dist/instance/SelectControl.d.ts +66 -0
- package/dist/instance/Subtree.d.ts +1 -0
- package/dist/instance/TriggerControl.d.ts +9 -22
- package/dist/instance/abstract/DescendantNode.d.ts +1 -2
- package/dist/instance/abstract/InstanceNode.d.ts +3 -1
- package/dist/instance/abstract/UnsupportedControl.d.ts +1 -0
- package/dist/instance/abstract/ValueNode.d.ts +0 -1
- package/dist/instance/hierarchy.d.ts +9 -9
- package/dist/instance/internal-api/InstanceValueContext.d.ts +2 -0
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableLeafNode.d.ts +2 -1
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableParentNode.d.ts +2 -1
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableValueNode.d.ts +2 -1
- package/dist/instance/repeat/BaseRepeatRange.d.ts +1 -0
- package/dist/instance/repeat/RepeatInstance.d.ts +1 -0
- package/dist/integration/xpath/adapter/names.d.ts +1 -11
- package/dist/integration/xpath/adapter/traversal.d.ts +10 -9
- package/dist/integration/xpath/static-dom/StaticAttribute.d.ts +10 -3
- package/dist/integration/xpath/static-dom/StaticDocument.d.ts +0 -1
- package/dist/integration/xpath/static-dom/StaticElement.d.ts +12 -4
- package/dist/lib/client-reactivity/submission/createRootSubmissionState.d.ts +3 -0
- package/dist/lib/codecs/Geopoint/Geopoint.d.ts +48 -0
- package/dist/lib/codecs/Geopoint/GeopointValueCodec.d.ts +5 -0
- package/dist/lib/codecs/NoteCodec.d.ts +8 -0
- package/dist/lib/codecs/RangeCodec.d.ts +8 -0
- package/dist/lib/codecs/TriggerCodec.d.ts +7 -0
- package/dist/lib/codecs/ValueArrayCodec.d.ts +11 -0
- package/dist/lib/codecs/ValueCodec.d.ts +2 -2
- package/dist/lib/codecs/getNoteCodec.d.ts +3 -0
- package/dist/lib/codecs/getSelectCodec.d.ts +5 -0
- package/dist/lib/codecs/getSharedValueCodec.d.ts +3 -2
- package/dist/lib/codecs/items/BaseItemCodec.d.ts +9 -0
- package/dist/lib/codecs/items/MultipleValueItemCodec.d.ts +14 -0
- package/dist/lib/codecs/items/SingleValueItemCodec.d.ts +24 -0
- package/dist/lib/dom/query.d.ts +1 -2
- package/dist/lib/names/NamespaceDeclaration.d.ts +45 -0
- package/dist/lib/names/NamespaceDeclarationMap.d.ts +137 -0
- package/dist/lib/names/NamespaceURL.d.ts +30 -0
- package/dist/lib/names/QualifiedName.d.ts +113 -0
- package/dist/lib/number-parsers.d.ts +2 -0
- package/dist/lib/reactivity/createItemCollection.d.ts +21 -0
- package/dist/lib/xml-serialization.d.ts +11 -2
- package/dist/parse/XFormDOM.d.ts +1 -1
- package/dist/parse/body/BodyDefinition.d.ts +2 -2
- package/dist/parse/body/appearance/rangeAppearanceParser.d.ts +3 -0
- package/dist/parse/body/control/InputControlDefinition.d.ts +3 -0
- package/dist/parse/body/control/ItemDefinition.d.ts +14 -0
- package/dist/parse/body/control/ItemsetDefinition.d.ts +18 -0
- package/dist/parse/body/control/RangeControlDefinition.d.ts +31 -2
- package/dist/parse/body/control/RankControlDefinition.d.ts +7 -3
- package/dist/parse/body/control/{select/SelectDefinition.d.ts → SelectControlDefinition.d.ts} +9 -9
- package/dist/parse/expression/ItemsetNodesetExpression.d.ts +1 -1
- package/dist/parse/expression/ItemsetValueExpression.d.ts +1 -1
- package/dist/parse/model/BindDefinition.d.ts +3 -1
- package/dist/parse/model/BindPreloadDefinition.d.ts +42 -0
- package/dist/parse/model/DescendentNodeDefinition.d.ts +4 -13
- package/dist/parse/model/ItextTranslation/ItextTranslationRootDefinition.d.ts +2 -1
- package/dist/parse/model/LeafNodeDefinition.d.ts +7 -4
- package/dist/parse/model/ModelBindMap.d.ts +1 -1
- package/dist/parse/model/NodeDefinition.d.ts +16 -19
- package/dist/parse/model/NoteNodeDefinition.d.ts +6 -5
- package/dist/parse/model/RangeNodeDefinition.d.ts +41 -0
- package/dist/parse/model/RepeatInstanceDefinition.d.ts +7 -4
- package/dist/parse/model/RepeatRangeDefinition.d.ts +7 -4
- package/dist/parse/model/RepeatTemplateDefinition.d.ts +7 -4
- package/dist/parse/model/RootAttributeDefinition.d.ts +24 -0
- package/dist/parse/model/RootAttributeMap.d.ts +23 -0
- package/dist/parse/model/RootDefinition.d.ts +9 -7
- package/dist/parse/model/SubtreeDefinition.d.ts +7 -4
- package/dist/parse/shared/parseStaticDocumentFromDOMSubtree.d.ts +2 -3
- package/dist/parse/text/ItemLabelDefinition.d.ts +1 -1
- package/dist/parse/text/ItemsetLabelDefinition.d.ts +2 -2
- package/dist/parse/text/abstract/TextElementDefinition.d.ts +1 -1
- package/dist/parse/xpath/semantic-analysis.d.ts +1 -3
- package/dist/solid.js +5603 -4665
- package/dist/solid.js.map +1 -1
- package/package.json +15 -12
- package/src/client/BaseNode.ts +5 -0
- package/src/client/BaseValueNode.ts +1 -1
- package/src/client/GroupNode.ts +1 -0
- package/src/client/InputNode.ts +38 -2
- package/src/client/ModelValueNode.ts +1 -0
- package/src/client/NoteNode.ts +43 -7
- package/src/client/RangeNode.ts +51 -0
- package/src/client/RankNode.ts +54 -0
- package/src/client/RootNode.ts +11 -5
- package/src/client/SelectNode.ts +53 -26
- package/src/client/SubtreeNode.ts +1 -0
- package/src/client/TriggerNode.ts +12 -6
- package/src/client/hierarchy.ts +7 -8
- package/src/client/node-types.ts +1 -1
- package/src/client/unsupported/UnsupportedControlNode.ts +2 -6
- package/src/error/RankMissingValueError.ts +5 -0
- package/src/error/RankValueTypeError.ts +13 -0
- package/src/error/SelectValueTypeError.ts +22 -0
- package/src/error/XFormsSpecViolationError.ts +1 -0
- package/src/index.ts +2 -12
- package/src/instance/Group.ts +1 -0
- package/src/instance/InputControl.ts +42 -2
- package/src/instance/ModelValue.ts +2 -0
- package/src/instance/Note.ts +34 -59
- package/src/instance/PrimaryInstance.ts +1 -0
- package/src/instance/RangeControl.ts +113 -0
- package/src/instance/RankControl.ts +199 -0
- package/src/instance/Root.ts +3 -2
- package/src/instance/SelectControl.ts +219 -0
- package/src/instance/Subtree.ts +1 -0
- package/src/instance/TriggerControl.ts +36 -75
- package/src/instance/abstract/DescendantNode.ts +1 -6
- package/src/instance/abstract/InstanceNode.ts +10 -2
- package/src/instance/abstract/UnsupportedControl.ts +1 -0
- package/src/instance/abstract/ValueNode.ts +3 -2
- package/src/instance/children.ts +71 -30
- package/src/instance/hierarchy.ts +21 -16
- package/src/instance/internal-api/InstanceValueContext.ts +2 -0
- package/src/instance/internal-api/submission/ClientReactiveSubmittableLeafNode.ts +2 -1
- package/src/instance/internal-api/submission/ClientReactiveSubmittableParentNode.ts +2 -1
- package/src/instance/internal-api/submission/ClientReactiveSubmittableValueNode.ts +2 -1
- package/src/instance/repeat/BaseRepeatRange.ts +2 -0
- package/src/instance/repeat/RepeatInstance.ts +1 -0
- package/src/instance/resource.ts +4 -1
- package/src/integration/xpath/adapter/names.ts +66 -17
- package/src/integration/xpath/adapter/traversal.ts +10 -9
- package/src/integration/xpath/static-dom/StaticAttribute.ts +15 -7
- package/src/integration/xpath/static-dom/StaticDocument.ts +0 -2
- package/src/integration/xpath/static-dom/StaticElement.ts +21 -8
- package/src/lib/client-reactivity/submission/createLeafNodeSubmissionState.ts +1 -1
- package/src/lib/client-reactivity/submission/createParentNodeSubmissionState.ts +1 -1
- package/src/lib/client-reactivity/submission/createRootSubmissionState.ts +19 -0
- package/src/lib/client-reactivity/submission/createValueNodeSubmissionState.ts +2 -2
- package/src/lib/codecs/Geopoint/Geopoint.ts +150 -0
- package/src/lib/codecs/Geopoint/GeopointValueCodec.ts +20 -0
- package/src/lib/codecs/NoteCodec.ts +32 -0
- package/src/lib/codecs/RangeCodec.ts +65 -0
- package/src/lib/codecs/TriggerCodec.ts +64 -0
- package/src/lib/codecs/ValueArrayCodec.ts +42 -0
- package/src/lib/codecs/ValueCodec.ts +2 -2
- package/src/lib/codecs/getNoteCodec.ts +27 -0
- package/src/lib/codecs/getSelectCodec.ts +27 -0
- package/src/lib/codecs/getSharedValueCodec.ts +5 -3
- package/src/lib/codecs/items/BaseItemCodec.ts +20 -0
- package/src/lib/codecs/items/MultipleValueItemCodec.ts +28 -0
- package/src/lib/codecs/items/SingleValueItemCodec.ts +67 -0
- package/src/lib/dom/query.ts +1 -2
- package/src/lib/names/NamespaceDeclaration.ts +106 -0
- package/src/lib/names/NamespaceDeclarationMap.ts +228 -0
- package/src/lib/names/NamespaceURL.ts +44 -0
- package/src/lib/names/QualifiedName.ts +170 -0
- package/src/lib/number-parsers.ts +25 -0
- package/src/lib/reactivity/createInstanceValueState.ts +50 -0
- package/src/lib/reactivity/{createSelectItems.ts → createItemCollection.ts} +41 -36
- package/src/lib/xml-serialization.ts +76 -9
- package/src/parse/XFormDOM.ts +141 -21
- package/src/parse/XFormDefinition.ts +1 -4
- package/src/parse/body/BodyDefinition.ts +4 -4
- package/src/parse/body/appearance/rangeAppearanceParser.ts +11 -0
- package/src/parse/body/control/InputControlDefinition.ts +9 -0
- package/src/parse/body/control/{select/ItemDefinition.ts → ItemDefinition.ts} +8 -6
- package/src/parse/body/control/{select/ItemsetDefinition.ts → ItemsetDefinition.ts} +11 -9
- package/src/parse/body/control/RangeControlDefinition.ts +91 -6
- package/src/parse/body/control/RankControlDefinition.ts +25 -7
- package/src/parse/body/control/{select/SelectDefinition.ts → SelectControlDefinition.ts} +9 -9
- package/src/parse/expression/ItemsetNodesetExpression.ts +1 -1
- package/src/parse/expression/ItemsetValueExpression.ts +1 -1
- package/src/parse/model/BindDefinition.ts +4 -0
- package/src/parse/model/BindPreloadDefinition.ts +100 -0
- package/src/parse/model/DescendentNodeDefinition.ts +7 -25
- package/src/parse/model/ItextTranslation/ItextTranslationRootDefinition.ts +2 -1
- package/src/parse/model/LeafNodeDefinition.ts +11 -4
- package/src/parse/model/NodeDefinition.ts +24 -45
- package/src/parse/model/NoteNodeDefinition.ts +8 -7
- package/src/parse/model/RangeNodeDefinition.ts +118 -0
- package/src/parse/model/RepeatInstanceDefinition.ts +11 -7
- package/src/parse/model/RepeatRangeDefinition.ts +11 -7
- package/src/parse/model/RepeatTemplateDefinition.ts +11 -7
- package/src/parse/model/RootAttributeDefinition.ts +45 -0
- package/src/parse/model/RootAttributeMap.ts +44 -0
- package/src/parse/model/RootDefinition.ts +29 -28
- package/src/parse/model/SecondaryInstance/sources/GeoJSONExternalSecondaryInstance.ts +1 -0
- package/src/parse/model/SubtreeDefinition.ts +12 -12
- package/src/parse/shared/parseStaticDocumentFromDOMSubtree.ts +3 -3
- package/src/parse/text/ItemLabelDefinition.ts +1 -1
- package/src/parse/text/ItemsetLabelDefinition.ts +2 -2
- package/src/parse/text/abstract/TextElementDefinition.ts +1 -1
- package/src/parse/xpath/semantic-analysis.ts +4 -3
- package/dist/client/unsupported/RangeNode.d.ts +0 -9
- package/dist/client/unsupported/RankNode.d.ts +0 -9
- package/dist/instance/SelectField.d.ts +0 -58
- package/dist/instance/unsupported/RangeControl.d.ts +0 -6
- package/dist/instance/unsupported/RankControl.d.ts +0 -6
- package/dist/integration/xpath/static-dom/StaticNamedNode.d.ts +0 -17
- package/dist/lib/reactivity/createSelectItems.d.ts +0 -16
- package/dist/parse/body/control/select/ItemDefinition.d.ts +0 -13
- package/dist/parse/body/control/select/ItemsetDefinition.d.ts +0 -17
- package/dist/parse/body/control/select/ItemsetNodesetContext.d.ts +0 -9
- package/src/client/unsupported/RangeNode.ts +0 -14
- package/src/client/unsupported/RankNode.ts +0 -14
- package/src/instance/SelectField.ts +0 -263
- package/src/instance/unsupported/RangeControl.ts +0 -9
- package/src/instance/unsupported/RankControl.ts +0 -9
- package/src/integration/xpath/static-dom/StaticNamedNode.ts +0 -45
- package/src/parse/body/control/select/ItemsetNodesetContext.ts +0 -21
package/src/instance/Root.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { SubmissionResult } from '../client/submission/SubmissionResult.ts'
|
|
|
12
12
|
import type { SubmissionState } from '../client/submission/SubmissionState.ts';
|
|
13
13
|
import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
14
14
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
15
|
-
import {
|
|
15
|
+
import { createRootSubmissionState } from '../lib/client-reactivity/submission/createRootSubmissionState.ts';
|
|
16
16
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
17
17
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
18
18
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -76,6 +76,7 @@ export class Root
|
|
|
76
76
|
// RootNode
|
|
77
77
|
readonly nodeType = 'root';
|
|
78
78
|
readonly appearances = null;
|
|
79
|
+
readonly nodeOptions = null;
|
|
79
80
|
readonly classes: BodyClassList;
|
|
80
81
|
readonly currentState: MaterializedChildren<CurrentState<RootStateSpec>, GeneralChildNode>;
|
|
81
82
|
readonly validationState: AncestorNodeValidationState;
|
|
@@ -136,7 +137,7 @@ export class Root
|
|
|
136
137
|
|
|
137
138
|
childrenState.setChildren(buildChildren(this));
|
|
138
139
|
this.validationState = createAggregatedViolations(this, sharedStateOptions);
|
|
139
|
-
this.submissionState =
|
|
140
|
+
this.submissionState = createRootSubmissionState(this);
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
getChildren(): readonly GeneralChildNode[] {
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { XPathNodeKindKey } from '@getodk/xpath';
|
|
2
|
+
import type { Accessor } from 'solid-js';
|
|
3
|
+
import { createMemo } from 'solid-js';
|
|
4
|
+
import type {
|
|
5
|
+
SelectDefinition,
|
|
6
|
+
SelectItem,
|
|
7
|
+
SelectNode,
|
|
8
|
+
SelectNodeAppearances,
|
|
9
|
+
SelectValueOptions,
|
|
10
|
+
} from '../client/SelectNode.ts';
|
|
11
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
12
|
+
import type { ValueType } from '../client/ValueType.ts';
|
|
13
|
+
import { SelectValueTypeError } from '../error/SelectValueTypeError.ts';
|
|
14
|
+
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
15
|
+
import { getSelectCodec } from '../lib/codecs/getSelectCodec.ts';
|
|
16
|
+
import { createItemCollection } from '../lib/reactivity/createItemCollection.ts';
|
|
17
|
+
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
18
|
+
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
19
|
+
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
20
|
+
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
21
|
+
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
22
|
+
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
23
|
+
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
24
|
+
import type { SelectType } from '../parse/body/control/SelectControlDefinition.ts';
|
|
25
|
+
import type { Root } from './Root.ts';
|
|
26
|
+
import type { ValueNodeStateSpec } from './abstract/ValueNode.ts';
|
|
27
|
+
import { ValueNode } from './abstract/ValueNode.ts';
|
|
28
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
29
|
+
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
30
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
31
|
+
import type { ClientReactiveSubmittableValueNode } from './internal-api/submission/ClientReactiveSubmittableValueNode.ts';
|
|
32
|
+
|
|
33
|
+
export type AnySelectDefinition = {
|
|
34
|
+
[V in ValueType]: SelectDefinition<V>;
|
|
35
|
+
}[ValueType];
|
|
36
|
+
|
|
37
|
+
type AssertSupportedSelectValueType = (
|
|
38
|
+
definition: AnySelectDefinition
|
|
39
|
+
) => asserts definition is SelectDefinition<'string'>;
|
|
40
|
+
|
|
41
|
+
const assertSupportedSelectValueType: AssertSupportedSelectValueType = (definition) => {
|
|
42
|
+
if (definition.valueType !== 'string') {
|
|
43
|
+
throw new SelectValueTypeError(definition);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type SelectItemMap = ReadonlyMap<string, SelectItem>;
|
|
48
|
+
|
|
49
|
+
interface SelectControlStateSpec extends ValueNodeStateSpec<readonly string[]> {
|
|
50
|
+
readonly label: Accessor<TextRange<'label'> | null>;
|
|
51
|
+
readonly hint: Accessor<TextRange<'hint'> | null>;
|
|
52
|
+
readonly valueOptions: Accessor<SelectValueOptions>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class SelectControl
|
|
56
|
+
extends ValueNode<'string', SelectDefinition<'string'>, readonly string[], readonly string[]>
|
|
57
|
+
implements
|
|
58
|
+
SelectNode,
|
|
59
|
+
XFormsXPathElement,
|
|
60
|
+
EvaluationContext,
|
|
61
|
+
ValidationContext,
|
|
62
|
+
ClientReactiveSubmittableValueNode
|
|
63
|
+
{
|
|
64
|
+
static from(parent: GeneralParentNode, definition: SelectDefinition): SelectControl;
|
|
65
|
+
static from(parent: GeneralParentNode, definition: AnySelectDefinition): SelectControl {
|
|
66
|
+
assertSupportedSelectValueType(definition);
|
|
67
|
+
|
|
68
|
+
return new this(parent, definition);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private readonly mapOptionsByValue: Accessor<SelectItemMap>;
|
|
72
|
+
|
|
73
|
+
protected override readonly getInstanceValue: Accessor<string>;
|
|
74
|
+
|
|
75
|
+
// XFormsXPathElement
|
|
76
|
+
override readonly [XPathNodeKindKey] = 'element';
|
|
77
|
+
|
|
78
|
+
// InstanceNode
|
|
79
|
+
protected readonly state: SharedNodeState<SelectControlStateSpec>;
|
|
80
|
+
protected readonly engineState: EngineState<SelectControlStateSpec>;
|
|
81
|
+
|
|
82
|
+
// SelectNode
|
|
83
|
+
readonly nodeType = 'select';
|
|
84
|
+
readonly selectType: SelectType;
|
|
85
|
+
readonly appearances: SelectNodeAppearances;
|
|
86
|
+
readonly nodeOptions = null;
|
|
87
|
+
readonly currentState: CurrentState<SelectControlStateSpec>;
|
|
88
|
+
|
|
89
|
+
private constructor(parent: GeneralParentNode, definition: SelectDefinition<'string'>) {
|
|
90
|
+
const codec = getSelectCodec(definition);
|
|
91
|
+
|
|
92
|
+
super(parent, definition, codec);
|
|
93
|
+
|
|
94
|
+
this.appearances = definition.bodyElement.appearances;
|
|
95
|
+
this.selectType = definition.bodyElement.type;
|
|
96
|
+
|
|
97
|
+
const valueOptions = createItemCollection(this);
|
|
98
|
+
|
|
99
|
+
const mapOptionsByValue: Accessor<SelectItemMap> = this.scope.runTask(() => {
|
|
100
|
+
return createMemo(() => {
|
|
101
|
+
return new Map(valueOptions().map((item) => [item.value, item]));
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
this.mapOptionsByValue = mapOptionsByValue;
|
|
106
|
+
|
|
107
|
+
const baseValueState = this.valueState;
|
|
108
|
+
const [baseGetValue, setValue] = baseValueState;
|
|
109
|
+
const getValue = this.scope.runTask(() => {
|
|
110
|
+
return createMemo(() => {
|
|
111
|
+
const optionsByValue = mapOptionsByValue();
|
|
112
|
+
|
|
113
|
+
return baseGetValue().filter((value) => {
|
|
114
|
+
return optionsByValue.has(value);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
const valueState: SimpleAtomicState<readonly string[]> = [getValue, setValue];
|
|
119
|
+
|
|
120
|
+
this.getInstanceValue = this.scope.runTask(() => {
|
|
121
|
+
return createMemo(() => {
|
|
122
|
+
return codec.encodeValue(getValue());
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const sharedStateOptions = {
|
|
127
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const state = createSharedNodeState(
|
|
131
|
+
this.scope,
|
|
132
|
+
{
|
|
133
|
+
reference: this.contextReference,
|
|
134
|
+
readonly: this.isReadonly,
|
|
135
|
+
relevant: this.isRelevant,
|
|
136
|
+
required: this.isRequired,
|
|
137
|
+
|
|
138
|
+
label: createNodeLabel(this, definition),
|
|
139
|
+
hint: createFieldHint(this, definition),
|
|
140
|
+
children: null,
|
|
141
|
+
valueOptions,
|
|
142
|
+
value: valueState,
|
|
143
|
+
instanceValue: this.getInstanceValue,
|
|
144
|
+
},
|
|
145
|
+
sharedStateOptions
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
this.state = state;
|
|
149
|
+
this.engineState = state.engineState;
|
|
150
|
+
this.currentState = state.currentState;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Filters {@link values} to include only those values which are currently
|
|
155
|
+
* available in the mapping produced by {@link mapOptionsByValue}, i.e. within
|
|
156
|
+
* a potentially filtered itemset.
|
|
157
|
+
*
|
|
158
|
+
* Note: this method effectively produces an intersection of
|
|
159
|
+
* {@link sourceValues} and {@link values}. **Importantly**, ordering of the
|
|
160
|
+
* results is deterministic, preserving the order of values as yielded _by
|
|
161
|
+
* {@link sourceValues}_.
|
|
162
|
+
*
|
|
163
|
+
* At time of writing, there are several tests (in `@getodk/scenario`, ported
|
|
164
|
+
* from JavaRosa) which expect the values of a `<select>` to match the order
|
|
165
|
+
* they appear in the control's (potentially filtered) `<itemset>` (or list of
|
|
166
|
+
* `<item>`s, for forms defining those inline).
|
|
167
|
+
*
|
|
168
|
+
* @todo The `<odk:rank>` control, having semantics very similar to
|
|
169
|
+
* `<select>`, will likely perform similar filtering logic. However, one of
|
|
170
|
+
* the important distinctions between these controls is that `<odk:rank>`
|
|
171
|
+
* exists explicitly to control the order of values. It's quite likely that
|
|
172
|
+
* would be achieved by invoking the same logic with the parameter order
|
|
173
|
+
* reversed.
|
|
174
|
+
*/
|
|
175
|
+
private filterValues(
|
|
176
|
+
sourceValues: Iterable<string>,
|
|
177
|
+
values: Iterable<string>
|
|
178
|
+
): readonly string[] {
|
|
179
|
+
const selectedValues = new Set(values);
|
|
180
|
+
|
|
181
|
+
return Array.from(sourceValues).filter((sourceValue) => {
|
|
182
|
+
return selectedValues.has(sourceValue);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// SelectNode
|
|
187
|
+
getValueOption(value: string): SelectItem | null {
|
|
188
|
+
// Note: this method is a client-facing convenience API for reading state,
|
|
189
|
+
// so it **MUST** read from client-reactive state!
|
|
190
|
+
const valueOption = this.currentState.valueOptions.find((item) => {
|
|
191
|
+
return item.value === value;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return valueOption ?? null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
isSelected(value: string): boolean {
|
|
198
|
+
// Note: this method is a client-facing convenience API for reading state,
|
|
199
|
+
// so it **MUST** read from client-reactive state!
|
|
200
|
+
return this.currentState.value.includes(value);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
selectValue(value: string | null): Root {
|
|
204
|
+
if (value == null) {
|
|
205
|
+
return this.selectValues([]);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return this.selectValues([value]);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
selectValues(values: readonly string[]): Root {
|
|
212
|
+
const sourceValues = this.mapOptionsByValue().keys();
|
|
213
|
+
const effectiveValues = this.filterValues(sourceValues, values);
|
|
214
|
+
|
|
215
|
+
this.setValueState(effectiveValues);
|
|
216
|
+
|
|
217
|
+
return this.root;
|
|
218
|
+
}
|
|
219
|
+
}
|
package/src/instance/Subtree.ts
CHANGED
|
@@ -49,6 +49,7 @@ export class Subtree
|
|
|
49
49
|
// SubtreeNode
|
|
50
50
|
readonly nodeType = 'subtree';
|
|
51
51
|
readonly appearances = null;
|
|
52
|
+
readonly nodeOptions = null;
|
|
52
53
|
readonly currentState: MaterializedChildren<CurrentState<SubtreeStateSpec>, GeneralChildNode>;
|
|
53
54
|
readonly validationState: AncestorNodeValidationState;
|
|
54
55
|
readonly submissionState: SubmissionState;
|
|
@@ -2,51 +2,61 @@ import { XPathNodeKindKey } from '@getodk/xpath';
|
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
3
|
import type { TextRange } from '../client/TextRange.ts';
|
|
4
4
|
import type { TriggerNode, TriggerNodeDefinition } from '../client/TriggerNode.ts';
|
|
5
|
-
import type {
|
|
6
|
-
import
|
|
5
|
+
import type { ValueType } from '../client/ValueType.ts';
|
|
6
|
+
import { ErrorProductionDesignPendingError } from '../error/ErrorProductionDesignPendingError.ts';
|
|
7
7
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import type { TriggerInputValue, TriggerRuntimeValue } from '../lib/codecs/TriggerCodec.ts';
|
|
9
|
+
import { TriggerCodec } from '../lib/codecs/TriggerCodec.ts';
|
|
10
10
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
11
11
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
12
12
|
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
13
13
|
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
14
14
|
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
15
15
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
16
|
-
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
17
|
-
import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
18
|
-
import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
19
16
|
import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
|
|
20
17
|
import type { Root } from './Root.ts';
|
|
21
|
-
import type
|
|
22
|
-
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
18
|
+
import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
|
|
23
19
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
24
20
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
25
21
|
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
26
|
-
import type {
|
|
27
|
-
import type { ClientReactiveSubmittableLeafNode } from './internal-api/submission/ClientReactiveSubmittableLeafNode.ts';
|
|
22
|
+
import type { ClientReactiveSubmittableValueNode } from './internal-api/submission/ClientReactiveSubmittableValueNode.ts';
|
|
28
23
|
|
|
29
|
-
interface TriggerControlStateSpec extends
|
|
24
|
+
interface TriggerControlStateSpec extends ValueNodeStateSpec<TriggerRuntimeValue> {
|
|
30
25
|
readonly label: Accessor<TextRange<'label'> | null>;
|
|
31
26
|
readonly hint: Accessor<TextRange<'hint'> | null>;
|
|
32
|
-
readonly children: null;
|
|
33
|
-
readonly value: SimpleAtomicState<boolean>;
|
|
34
27
|
readonly valueOptions: null;
|
|
35
28
|
}
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
type AnyTriggerNodeDefinition = {
|
|
31
|
+
[V in ValueType]: TriggerNodeDefinition<V>;
|
|
32
|
+
}[ValueType];
|
|
33
|
+
|
|
34
|
+
const codec = new TriggerCodec();
|
|
38
35
|
|
|
39
36
|
export class TriggerControl
|
|
40
|
-
extends
|
|
37
|
+
extends ValueNode<
|
|
38
|
+
'string',
|
|
39
|
+
TriggerNodeDefinition<'string'>,
|
|
40
|
+
TriggerRuntimeValue,
|
|
41
|
+
TriggerInputValue
|
|
42
|
+
>
|
|
41
43
|
implements
|
|
42
44
|
TriggerNode,
|
|
43
45
|
XFormsXPathElement,
|
|
44
46
|
EvaluationContext,
|
|
45
47
|
ValidationContext,
|
|
46
|
-
|
|
47
|
-
ClientReactiveSubmittableLeafNode<boolean>
|
|
48
|
+
ClientReactiveSubmittableValueNode
|
|
48
49
|
{
|
|
49
|
-
|
|
50
|
+
static from(parent: GeneralParentNode, definition: TriggerNodeDefinition): TriggerControl;
|
|
51
|
+
static from(parent: GeneralParentNode, definition: AnyTriggerNodeDefinition): TriggerControl {
|
|
52
|
+
if (definition.valueType !== 'string') {
|
|
53
|
+
throw new ErrorProductionDesignPendingError(
|
|
54
|
+
`Unsupported trigger value type: ${definition.valueType}`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return new this(parent, definition);
|
|
59
|
+
}
|
|
50
60
|
|
|
51
61
|
// XFormsXPathElement
|
|
52
62
|
override readonly [XPathNodeKindKey] = 'element';
|
|
@@ -58,42 +68,13 @@ export class TriggerControl
|
|
|
58
68
|
// TriggerNode
|
|
59
69
|
readonly nodeType = 'trigger';
|
|
60
70
|
readonly appearances: UnknownAppearanceDefinition;
|
|
71
|
+
readonly nodeOptions = null;
|
|
61
72
|
readonly currentState: CurrentState<TriggerControlStateSpec>;
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
readonly submissionState: SubmissionState;
|
|
68
|
-
|
|
69
|
-
// ValueContext
|
|
70
|
-
override readonly contextNode = this;
|
|
71
|
-
readonly encodeValue: (runtimeValue: boolean) => string;
|
|
72
|
-
readonly decodeValue: (instanceValue: string) => boolean;
|
|
73
|
-
|
|
74
|
-
constructor(parent: GeneralParentNode, definition: TriggerNodeDefinition) {
|
|
75
|
-
super(parent, definition);
|
|
74
|
+
private constructor(parent: GeneralParentNode, definition: TriggerNodeDefinition<'string'>) {
|
|
75
|
+
super(parent, definition, codec);
|
|
76
76
|
|
|
77
77
|
this.appearances = definition.bodyElement.appearances;
|
|
78
|
-
this.encodeValue = (runtimeValue) => {
|
|
79
|
-
return runtimeValue ? TRIGGER_ASSIGNED_VALUE : '';
|
|
80
|
-
};
|
|
81
|
-
this.decodeValue = (instanceValue) => {
|
|
82
|
-
const value = instanceValue.trim();
|
|
83
|
-
|
|
84
|
-
switch (value) {
|
|
85
|
-
case TRIGGER_ASSIGNED_VALUE:
|
|
86
|
-
return true;
|
|
87
|
-
|
|
88
|
-
case '':
|
|
89
|
-
return false;
|
|
90
|
-
|
|
91
|
-
// TODO (robustness principle): Case insensitivity? Handle
|
|
92
|
-
// XPath-semantic booleans?? Other known/common equivalents?
|
|
93
|
-
default:
|
|
94
|
-
throw new Error(`Unexpected trigger value: ${value}`);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
78
|
|
|
98
79
|
const sharedStateOptions = {
|
|
99
80
|
clientStateFactory: this.engineConfig.stateFactory,
|
|
@@ -111,7 +92,8 @@ export class TriggerControl
|
|
|
111
92
|
hint: createFieldHint(this, definition),
|
|
112
93
|
children: null,
|
|
113
94
|
valueOptions: null,
|
|
114
|
-
value:
|
|
95
|
+
value: this.valueState,
|
|
96
|
+
instanceValue: this.getInstanceValue,
|
|
115
97
|
},
|
|
116
98
|
sharedStateOptions
|
|
117
99
|
);
|
|
@@ -119,32 +101,11 @@ export class TriggerControl
|
|
|
119
101
|
this.state = state;
|
|
120
102
|
this.engineState = state.engineState;
|
|
121
103
|
this.currentState = state.currentState;
|
|
122
|
-
this.validation = createValidationState(this, sharedStateOptions);
|
|
123
|
-
this.submissionState = createLeafNodeSubmissionState(this);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// XFormsXPathElement
|
|
127
|
-
override getXPathValue(): string {
|
|
128
|
-
return this.encodeValue(this.engineState.value);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ValidationContext
|
|
132
|
-
getViolation(): AnyViolation | null {
|
|
133
|
-
return this.validation.engineState.violation;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
isBlank(): boolean {
|
|
137
|
-
return this.engineState.value == null;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// InstanceNode
|
|
141
|
-
getChildren(): readonly [] {
|
|
142
|
-
return [];
|
|
143
104
|
}
|
|
144
105
|
|
|
145
106
|
// TriggerNode
|
|
146
|
-
setValue(value:
|
|
147
|
-
this.
|
|
107
|
+
setValue(value: TriggerInputValue): Root {
|
|
108
|
+
this.setValueState(value);
|
|
148
109
|
|
|
149
110
|
return this.root;
|
|
150
111
|
}
|
|
@@ -13,7 +13,6 @@ import { XFORMS_XPATH_NODE_RANGE_KIND } from '../../integration/xpath/adapter/XF
|
|
|
13
13
|
import type { EngineXPathEvaluator } from '../../integration/xpath/EngineXPathEvaluator.ts';
|
|
14
14
|
import { createComputedExpression } from '../../lib/reactivity/createComputedExpression.ts';
|
|
15
15
|
import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
|
|
16
|
-
import type { AnyDescendantNodeDefinition } from '../../parse/model/DescendentNodeDefinition.ts';
|
|
17
16
|
import type { AnyNodeDefinition } from '../../parse/model/NodeDefinition.ts';
|
|
18
17
|
import type { AnyChildNode, AnyParentNode, RepeatRange } from '../hierarchy.ts';
|
|
19
18
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
@@ -35,11 +34,7 @@ export type DescendantNodeStateSpec<Value = never> =
|
|
|
35
34
|
& InstanceNodeStateSpec<Value>
|
|
36
35
|
& DescendantNodeSharedStateSpec;
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
export type DescendantNodeDefinition = Extract<
|
|
40
|
-
AnyNodeDefinition,
|
|
41
|
-
AnyDescendantNodeDefinition
|
|
42
|
-
>;
|
|
37
|
+
export type DescendantNodeDefinition = AnyNodeDefinition;
|
|
43
38
|
|
|
44
39
|
export type AnyDescendantNode = DescendantNode<
|
|
45
40
|
DescendantNodeDefinition,
|
|
@@ -34,6 +34,12 @@ export interface BaseEngineNode extends Omit<BaseNode, 'nodeType'> {
|
|
|
34
34
|
readonly nodeType: EngineInstanceNodeType;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// prettier-ignore
|
|
38
|
+
export type InstanceNodeValueOptionsStateSpec =
|
|
39
|
+
| Accessor<null>
|
|
40
|
+
| Accessor<readonly unknown[]>
|
|
41
|
+
| null
|
|
42
|
+
|
|
37
43
|
export interface InstanceNodeStateSpec<Value = never> {
|
|
38
44
|
readonly reference: Accessor<string> | string;
|
|
39
45
|
readonly readonly: Accessor<boolean> | boolean;
|
|
@@ -42,7 +48,7 @@ export interface InstanceNodeStateSpec<Value = never> {
|
|
|
42
48
|
readonly label: Accessor<TextRange<'label'> | null> | null;
|
|
43
49
|
readonly hint: Accessor<TextRange<'hint'> | null> | null;
|
|
44
50
|
readonly children: Accessor<readonly FormNodeID[]> | null;
|
|
45
|
-
readonly valueOptions:
|
|
51
|
+
readonly valueOptions: InstanceNodeValueOptionsStateSpec;
|
|
46
52
|
readonly value: Signal<Value> | SimpleAtomicState<Value> | null;
|
|
47
53
|
}
|
|
48
54
|
|
|
@@ -136,6 +142,8 @@ export abstract class InstanceNode<
|
|
|
136
142
|
|
|
137
143
|
abstract readonly appearances: NodeAppearances<Definition>;
|
|
138
144
|
|
|
145
|
+
abstract readonly nodeOptions: object | null;
|
|
146
|
+
|
|
139
147
|
abstract readonly currentState: InstanceNodeCurrentState<Spec, Child>;
|
|
140
148
|
|
|
141
149
|
abstract readonly validationState: NodeValidationState;
|
|
@@ -161,7 +169,7 @@ export abstract class InstanceNode<
|
|
|
161
169
|
);
|
|
162
170
|
}
|
|
163
171
|
|
|
164
|
-
return `${parent.contextReference()}/${definition.
|
|
172
|
+
return `${parent.contextReference()}/${definition.qualifiedName.getPrefixedName()}`;
|
|
165
173
|
};
|
|
166
174
|
|
|
167
175
|
// EvaluationContext: node-specific
|
|
@@ -92,6 +92,7 @@ export abstract class UnsupportedControl<Type extends UnsupportedControlNodeType
|
|
|
92
92
|
abstract override readonly nodeType: Type;
|
|
93
93
|
|
|
94
94
|
readonly appearances: UnknownAppearanceDefinition;
|
|
95
|
+
readonly nodeOptions = null;
|
|
95
96
|
readonly currentState: CurrentState<UnsupportedControlStateSpec>;
|
|
96
97
|
|
|
97
98
|
get validationState(): LeafNodeValidationState {
|
|
@@ -35,7 +35,6 @@ export type ValueNodeDefinition<V extends ValueType> = LeafNodeDefinition<V>;
|
|
|
35
35
|
|
|
36
36
|
export interface ValueNodeStateSpec<RuntimeValue> extends DescendantNodeStateSpec<RuntimeValue> {
|
|
37
37
|
readonly children: null;
|
|
38
|
-
readonly valueOptions: null;
|
|
39
38
|
readonly value: SimpleAtomicState<RuntimeValue>;
|
|
40
39
|
readonly instanceValue: Accessor<string>;
|
|
41
40
|
}
|
|
@@ -103,7 +102,9 @@ export abstract class ValueNode<
|
|
|
103
102
|
|
|
104
103
|
this.getInstanceValue = getInstanceValue;
|
|
105
104
|
this.setValueState = setValueState;
|
|
106
|
-
this.getXPathValue =
|
|
105
|
+
this.getXPathValue = () => {
|
|
106
|
+
return this.getInstanceValue();
|
|
107
|
+
};
|
|
107
108
|
this.valueState = valueState;
|
|
108
109
|
this.validation = createValidationState(this, {
|
|
109
110
|
clientStateFactory: this.engineConfig.stateFactory,
|
package/src/instance/children.ts
CHANGED
|
@@ -2,28 +2,32 @@ import { UnreachableError } from '@getodk/common/lib/error/UnreachableError.ts';
|
|
|
2
2
|
import type { GroupDefinition } from '../client/GroupNode.ts';
|
|
3
3
|
import type { InputDefinition } from '../client/InputNode.ts';
|
|
4
4
|
import type { ModelValueDefinition } from '../client/ModelValueNode.ts';
|
|
5
|
+
import type { SelectDefinition } from '../client/SelectNode.ts';
|
|
5
6
|
import type { SubtreeDefinition } from '../client/SubtreeNode.ts';
|
|
6
7
|
import type { TriggerNodeDefinition } from '../client/TriggerNode.ts';
|
|
7
|
-
import type {
|
|
8
|
-
import type { RankNodeDefinition } from '../client/unsupported/RankNode.ts';
|
|
9
|
-
import type { UnsupportedControlDefinition } from '../client/unsupported/UnsupportedControlNode.ts';
|
|
8
|
+
import type { RankDefinition } from '../client/RankNode.ts';
|
|
10
9
|
import type { UploadNodeDefinition } from '../client/unsupported/UploadNode.ts';
|
|
10
|
+
import { ErrorProductionDesignPendingError } from '../error/ErrorProductionDesignPendingError.ts';
|
|
11
11
|
import type { LeafNodeDefinition } from '../parse/model/LeafNodeDefinition.ts';
|
|
12
12
|
import { NoteNodeDefinition } from '../parse/model/NoteNodeDefinition.ts';
|
|
13
|
+
import type {
|
|
14
|
+
AnyRangeNodeDefinition,
|
|
15
|
+
RangeLeafNodeDefinition,
|
|
16
|
+
} from '../parse/model/RangeNodeDefinition.ts';
|
|
17
|
+
import { RangeNodeDefinition } from '../parse/model/RangeNodeDefinition.ts';
|
|
13
18
|
import type { SubtreeDefinition as ModelSubtreeDefinition } from '../parse/model/SubtreeDefinition.ts';
|
|
14
19
|
import { Group } from './Group.ts';
|
|
15
20
|
import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
|
|
16
21
|
import { InputControl } from './InputControl.ts';
|
|
17
22
|
import { ModelValue } from './ModelValue.ts';
|
|
18
23
|
import { Note } from './Note.ts';
|
|
24
|
+
import { RangeControl } from './RangeControl.ts';
|
|
19
25
|
import { RepeatRangeControlled } from './repeat/RepeatRangeControlled.ts';
|
|
20
26
|
import { RepeatRangeUncontrolled } from './repeat/RepeatRangeUncontrolled.ts';
|
|
21
|
-
import
|
|
22
|
-
import { SelectField } from './SelectField.ts';
|
|
27
|
+
import { SelectControl } from './SelectControl.ts';
|
|
23
28
|
import { Subtree } from './Subtree.ts';
|
|
24
29
|
import { TriggerControl } from './TriggerControl.ts';
|
|
25
|
-
import {
|
|
26
|
-
import { RankControl } from './unsupported/RankControl.ts';
|
|
30
|
+
import { RankControl } from './RankControl.ts';
|
|
27
31
|
import { UploadControl } from './unsupported/UploadControl.ts';
|
|
28
32
|
|
|
29
33
|
const isSubtreeDefinition = (
|
|
@@ -32,16 +36,16 @@ const isSubtreeDefinition = (
|
|
|
32
36
|
return definition.bodyElement == null;
|
|
33
37
|
};
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| RankNodeDefinition
|
|
38
|
-
| UploadNodeDefinition;
|
|
39
|
+
// prettier-ignore
|
|
40
|
+
type AnyUnsupportedControlDefinition = UploadNodeDefinition;
|
|
39
41
|
|
|
40
42
|
// prettier-ignore
|
|
41
43
|
type ControlNodeDefinition =
|
|
42
44
|
// eslint-disable-next-line @typescript-eslint/sort-type-constituents
|
|
43
45
|
| InputDefinition
|
|
44
|
-
|
|
|
46
|
+
| RangeLeafNodeDefinition
|
|
47
|
+
| SelectDefinition
|
|
48
|
+
| RankDefinition
|
|
45
49
|
| TriggerNodeDefinition
|
|
46
50
|
| AnyUnsupportedControlDefinition;
|
|
47
51
|
|
|
@@ -57,22 +61,57 @@ const isInputDefinition = (definition: ControlNodeDefinition): definition is Inp
|
|
|
57
61
|
return definition.bodyElement.type === 'input';
|
|
58
62
|
};
|
|
59
63
|
|
|
60
|
-
const
|
|
61
|
-
definition: ControlNodeDefinition
|
|
62
|
-
): definition is SelectFieldDefinition => {
|
|
64
|
+
const isSelectDefinition = (definition: ControlNodeDefinition): definition is SelectDefinition => {
|
|
63
65
|
return definition.bodyElement.type === 'select' || definition.bodyElement.type === 'select1';
|
|
64
66
|
};
|
|
65
67
|
|
|
66
|
-
const
|
|
67
|
-
definition
|
|
68
|
-
|
|
68
|
+
const isRankDefinition = (definition: ControlNodeDefinition): definition is RankDefinition => {
|
|
69
|
+
return definition.bodyElement.type === 'rank';
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const isRangeLeafNodeDefinition = (
|
|
73
|
+
definition: ControlNodeDefinition
|
|
74
|
+
): definition is RangeLeafNodeDefinition => {
|
|
69
75
|
return definition.bodyElement.type === 'range';
|
|
70
76
|
};
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
definition:
|
|
74
|
-
)
|
|
75
|
-
|
|
78
|
+
type AssertRangeNodeDefinition = (
|
|
79
|
+
definition: RangeLeafNodeDefinition
|
|
80
|
+
) => asserts definition is AnyRangeNodeDefinition;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* We need some way to narrow the base {@link RangeLeafNodeDefinition} type to
|
|
84
|
+
* {@link RankNodeDefinition} type.
|
|
85
|
+
*
|
|
86
|
+
* At time of writing, we know there is no code path to produce the broader
|
|
87
|
+
* type, but appeasing the type checker for it will help guard against
|
|
88
|
+
* introducing one. (And it would have caught exactly such a mistake in this
|
|
89
|
+
* phase of development, where a more optimistic type cast did not.)
|
|
90
|
+
*
|
|
91
|
+
* An `instanceof` check is appropriate because the narrower type refines all of
|
|
92
|
+
* the following:
|
|
93
|
+
*
|
|
94
|
+
* - `valueType` is a subset of the full range of
|
|
95
|
+
* {@link ValueType | specified value types} (only `int` or `decimal` are
|
|
96
|
+
* supported for range controls)
|
|
97
|
+
*
|
|
98
|
+
* - addition of range-specific properties: `min`, `max`, `step`
|
|
99
|
+
*/
|
|
100
|
+
const assertRangeNodeDefinition: AssertRangeNodeDefinition = (definition) => {
|
|
101
|
+
if (definition instanceof RangeNodeDefinition) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* At time of writing we know there is no code path producing this
|
|
107
|
+
* case, but appeasing the type checker for it now will guard against
|
|
108
|
+
* it happening mistakenly in any future refactoring. (Hint: it
|
|
109
|
+
* occurred during some refactoring that arrived here, which is why
|
|
110
|
+
* this isn't a type cast!)
|
|
111
|
+
*/
|
|
112
|
+
throw new ErrorProductionDesignPendingError(
|
|
113
|
+
`Invalid <range> definition with value type: ${definition.valueType}`
|
|
114
|
+
);
|
|
76
115
|
};
|
|
77
116
|
|
|
78
117
|
const isTriggerNodeDefinition = (
|
|
@@ -127,20 +166,22 @@ export const buildChildren = (parent: GeneralParentNode): GeneralChildNode[] =>
|
|
|
127
166
|
return InputControl.from(parent, leafChild);
|
|
128
167
|
}
|
|
129
168
|
|
|
130
|
-
if (
|
|
131
|
-
return
|
|
169
|
+
if (isSelectDefinition(leafChild)) {
|
|
170
|
+
return SelectControl.from(parent, leafChild);
|
|
132
171
|
}
|
|
133
172
|
|
|
134
|
-
if (
|
|
135
|
-
return
|
|
173
|
+
if (isRankDefinition(leafChild)) {
|
|
174
|
+
return RankControl.from(parent, leafChild);
|
|
136
175
|
}
|
|
137
176
|
|
|
138
|
-
if (
|
|
139
|
-
return
|
|
177
|
+
if (isTriggerNodeDefinition(leafChild)) {
|
|
178
|
+
return TriggerControl.from(parent, leafChild);
|
|
140
179
|
}
|
|
141
180
|
|
|
142
|
-
if (
|
|
143
|
-
|
|
181
|
+
if (isRangeLeafNodeDefinition(leafChild)) {
|
|
182
|
+
assertRangeNodeDefinition(leafChild);
|
|
183
|
+
|
|
184
|
+
return RangeControl.from(parent, leafChild);
|
|
144
185
|
}
|
|
145
186
|
|
|
146
187
|
if (isUploadNodeDefinition(leafChild)) {
|