@getodk/xforms-engine 0.2.0 → 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/BodyElementDefinition.d.ts +4 -3
- package/dist/body/RepeatElementDefinition.d.ts +2 -2
- package/dist/body/control/ControlDefinition.d.ts +2 -2
- package/dist/body/control/select/ItemDefinition.d.ts +2 -2
- package/dist/body/control/select/ItemsetDefinition.d.ts +5 -4
- package/dist/body/group/BaseGroupDefinition.d.ts +1 -1
- package/dist/body/group/PresentationGroupDefinition.d.ts +1 -1
- package/dist/client/BaseNode.d.ts +68 -2
- package/dist/client/GroupNode.d.ts +2 -0
- package/dist/client/ModelValueNode.d.ts +37 -0
- package/dist/client/NoteNode.d.ts +53 -0
- package/dist/client/RootNode.d.ts +2 -0
- package/dist/client/SelectNode.d.ts +5 -3
- package/dist/client/StringNode.d.ts +5 -3
- package/dist/client/SubtreeNode.d.ts +2 -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} +18 -17
- package/dist/client/{RepeatInstanceNode.d.ts → repeat/RepeatInstanceNode.d.ts} +9 -8
- 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 +2635 -678
- package/dist/index.js.map +1 -1
- package/dist/instance/Group.d.ts +3 -1
- package/dist/instance/ModelValue.d.ts +40 -0
- package/dist/instance/Note.d.ts +42 -0
- package/dist/instance/Root.d.ts +2 -0
- package/dist/instance/SelectField.d.ts +10 -4
- package/dist/instance/StringField.d.ts +11 -5
- package/dist/instance/Subtree.d.ts +2 -0
- package/dist/instance/abstract/DescendantNode.d.ts +5 -6
- package/dist/instance/abstract/InstanceNode.d.ts +2 -0
- package/dist/instance/hierarchy.d.ts +10 -5
- package/dist/instance/internal-api/ValidationContext.d.ts +21 -0
- package/dist/instance/{RepeatRange.d.ts → repeat/BaseRepeatRange.d.ts} +46 -45
- package/dist/instance/{RepeatInstance.d.ts → repeat/RepeatInstance.d.ts} +13 -12
- 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/reactivity/createComputedExpression.d.ts +6 -1
- package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +5 -0
- 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/{ValueNodeDefinition.d.ts → LeafNodeDefinition.d.ts} +2 -2
- package/dist/model/NodeDefinition.d.ts +8 -8
- package/dist/model/RepeatInstanceDefinition.d.ts +2 -2
- package/dist/model/RepeatRangeDefinition.d.ts +14 -4
- 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 +2636 -679
- package/dist/solid.js.map +1 -1
- package/package.json +14 -15
- package/src/body/BodyElementDefinition.ts +4 -3
- package/src/body/RepeatElementDefinition.ts +5 -17
- package/src/body/control/ControlDefinition.ts +4 -3
- 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/group/BaseGroupDefinition.ts +3 -2
- package/src/body/group/PresentationGroupDefinition.ts +1 -1
- package/src/client/BaseNode.ts +73 -7
- package/src/client/GroupNode.ts +2 -0
- package/src/client/ModelValueNode.ts +40 -0
- package/src/client/NoteNode.ts +74 -0
- package/src/client/README.md +1 -0
- package/src/client/RootNode.ts +2 -0
- package/src/client/SelectNode.ts +5 -3
- package/src/client/StringNode.ts +5 -3
- package/src/client/SubtreeNode.ts +2 -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} +18 -19
- package/src/client/{RepeatInstanceNode.ts → repeat/RepeatInstanceNode.ts} +10 -8
- 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 +10 -4
- package/src/instance/ModelValue.ts +104 -0
- package/src/instance/Note.ts +142 -0
- package/src/instance/Root.ts +9 -3
- package/src/instance/SelectField.ts +28 -6
- package/src/instance/StringField.ts +35 -9
- package/src/instance/Subtree.ts +9 -3
- package/src/instance/abstract/DescendantNode.ts +6 -7
- package/src/instance/abstract/InstanceNode.ts +20 -6
- package/src/instance/children.ts +42 -15
- package/src/instance/hierarchy.ts +21 -2
- package/src/instance/internal-api/ValidationContext.ts +23 -0
- package/src/instance/{RepeatRange.ts → repeat/BaseRepeatRange.ts} +114 -99
- package/src/instance/{RepeatInstance.ts → repeat/RepeatInstance.ts} +27 -22
- 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/reactivity/createComputedExpression.ts +22 -24
- package/src/lib/reactivity/createNoteReadonlyThunk.ts +33 -0
- package/src/lib/reactivity/createSelectItems.ts +21 -14
- 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/{ValueNodeDefinition.ts → LeafNodeDefinition.ts} +4 -4
- package/src/model/ModelBindMap.ts +4 -0
- package/src/model/NodeDefinition.ts +12 -12
- package/src/model/RepeatInstanceDefinition.ts +2 -2
- package/src/model/RepeatRangeDefinition.ts +49 -8
- package/src/model/RootDefinition.ts +7 -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/text/HintDefinition.d.ts +0 -11
- package/dist/body/text/LabelDefinition.d.ts +0 -22
- 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/lib/xpath/analysis.d.ts +0 -23
- package/src/body/text/HintDefinition.ts +0 -26
- package/src/body/text/LabelDefinition.ts +0 -68
- 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/lib/xpath/analysis.ts +0 -241
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import type { XFormsXPathEvaluator } from '@getodk/xpath';
|
|
2
|
-
import {
|
|
2
|
+
import { resolveDependencyNodesets } from '../parse/xpath/dependency-analysis.ts';
|
|
3
|
+
import type {
|
|
4
|
+
ConstantExpression,
|
|
5
|
+
ConstantTruthyExpression,
|
|
6
|
+
} from '../parse/xpath/semantic-analysis.ts';
|
|
7
|
+
import {
|
|
8
|
+
isConstantExpression,
|
|
9
|
+
isConstantTruthyExpression,
|
|
10
|
+
isTranslationExpression,
|
|
11
|
+
} from '../parse/xpath/semantic-analysis.ts';
|
|
3
12
|
import type { DependencyContext } from './DependencyContext.ts';
|
|
4
13
|
|
|
5
14
|
const evaluatorMethodsByResultType = {
|
|
6
15
|
boolean: 'evaluateBoolean',
|
|
7
16
|
nodes: 'evaluateNodes',
|
|
17
|
+
number: 'evaluateNumber',
|
|
8
18
|
string: 'evaluateString',
|
|
9
19
|
} as const;
|
|
10
20
|
|
|
@@ -20,11 +30,6 @@ export type DependentExpressionResult<Type extends DependentExpressionResultType
|
|
|
20
30
|
>;
|
|
21
31
|
|
|
22
32
|
interface SemanticDependencyOptions {
|
|
23
|
-
/**
|
|
24
|
-
* @default false
|
|
25
|
-
*/
|
|
26
|
-
readonly parentContext?: boolean | undefined;
|
|
27
|
-
|
|
28
33
|
/**
|
|
29
34
|
* @default false
|
|
30
35
|
*/
|
|
@@ -37,18 +42,24 @@ interface DependentExpressionOptions {
|
|
|
37
42
|
*/
|
|
38
43
|
readonly ignoreContextReference?: boolean;
|
|
39
44
|
|
|
40
|
-
/**
|
|
41
|
-
* @default true
|
|
42
|
-
*/
|
|
43
|
-
readonly ignoreNullExpressions?: boolean;
|
|
44
|
-
|
|
45
45
|
readonly semanticDependencies?: SemanticDependencyOptions;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
export interface ConstantDependentExpression<Type extends DependentExpressionResultType>
|
|
49
|
+
extends DependentExpression<Type> {
|
|
50
|
+
readonly expression: ConstantExpression;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ConstantTruthyDependentExpression extends ConstantDependentExpression<'boolean'> {
|
|
54
|
+
readonly expression: ConstantTruthyExpression;
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
export class DependentExpression<Type extends DependentExpressionResultType> {
|
|
49
58
|
readonly dependencyReferences: ReadonlySet<string> = new Set();
|
|
50
59
|
readonly isTranslated: boolean = false;
|
|
51
60
|
readonly evaluatorMethod: DependentExpressionEvaluatorMethod<Type>;
|
|
61
|
+
readonly constantExpression: ConstantExpression | null;
|
|
62
|
+
readonly constantTruthyExpression: ConstantTruthyExpression | null;
|
|
52
63
|
|
|
53
64
|
constructor(
|
|
54
65
|
context: DependencyContext,
|
|
@@ -56,34 +67,33 @@ export class DependentExpression<Type extends DependentExpressionResultType> {
|
|
|
56
67
|
readonly expression: string,
|
|
57
68
|
options: DependentExpressionOptions = {}
|
|
58
69
|
) {
|
|
70
|
+
if (resultType === 'boolean' && isConstantTruthyExpression(expression)) {
|
|
71
|
+
this.constantTruthyExpression = expression;
|
|
72
|
+
this.constantExpression = expression;
|
|
73
|
+
} else if (isConstantExpression(expression)) {
|
|
74
|
+
this.constantTruthyExpression = null;
|
|
75
|
+
this.constantExpression = expression;
|
|
76
|
+
} else {
|
|
77
|
+
this.constantTruthyExpression = null;
|
|
78
|
+
this.constantExpression = null;
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
this.evaluatorMethod = evaluatorMethodsByResultType[resultType];
|
|
60
82
|
|
|
61
83
|
const {
|
|
62
84
|
ignoreContextReference = false,
|
|
63
|
-
ignoreNullExpressions = true,
|
|
64
85
|
semanticDependencies = {
|
|
65
|
-
parentContext: false,
|
|
66
86
|
translations: false,
|
|
67
87
|
},
|
|
68
88
|
} = options;
|
|
69
89
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
ignoreContextReference,
|
|
74
|
-
ignoreNullExpressions,
|
|
90
|
+
this.dependencyReferences = new Set(
|
|
91
|
+
resolveDependencyNodesets(context.reference, expression, {
|
|
92
|
+
ignoreReferenceToContextPath: ignoreContextReference,
|
|
75
93
|
})
|
|
76
94
|
);
|
|
77
95
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
if (parentDependency != null) {
|
|
81
|
-
dependencyReferences.add(parentDependency);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
this.dependencyReferences = dependencyReferences;
|
|
85
|
-
|
|
86
|
-
const isTranslated = semanticDependencies.translations && isItextFunctionCalled(expression);
|
|
96
|
+
const isTranslated = semanticDependencies.translations && isTranslationExpression(expression);
|
|
87
97
|
|
|
88
98
|
if (isTranslated) {
|
|
89
99
|
this.isTranslated = true;
|
|
@@ -93,6 +103,14 @@ export class DependentExpression<Type extends DependentExpressionResultType> {
|
|
|
93
103
|
context.registerDependentExpression(this);
|
|
94
104
|
}
|
|
95
105
|
|
|
106
|
+
isConstantExpression(): this is ConstantDependentExpression<Type> {
|
|
107
|
+
return this.constantExpression != null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
isConstantTruthyExpression(): this is ConstantTruthyDependentExpression {
|
|
111
|
+
return this.resultType === 'boolean' && this.constantTruthyExpression != null;
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
toString(): string | null {
|
|
97
115
|
return this.expression;
|
|
98
116
|
}
|
package/src/index.ts
CHANGED
|
@@ -3,26 +3,33 @@ import { initializeForm as engine__initializeForm } from './instance/index.ts';
|
|
|
3
3
|
|
|
4
4
|
export const initializeForm: InitializeForm = engine__initializeForm;
|
|
5
5
|
|
|
6
|
+
export * as constants from './client/constants.ts';
|
|
6
7
|
export type * from './client/EngineConfig.ts';
|
|
7
8
|
export type * from './client/FormLanguage.ts';
|
|
8
9
|
export type * from './client/GroupNode.ts';
|
|
9
|
-
export type * from './client/OpaqueReactiveObjectFactory.ts';
|
|
10
|
-
export type * from './client/RepeatInstanceNode.ts';
|
|
11
|
-
export type * from './client/RepeatRangeNode.ts';
|
|
12
|
-
export type * from './client/RootNode.ts';
|
|
13
|
-
export type * from './client/SelectNode.ts';
|
|
14
|
-
export type * from './client/StringNode.ts';
|
|
15
|
-
export type * from './client/SubtreeNode.ts';
|
|
16
|
-
export type * from './client/TextRange.ts';
|
|
17
10
|
export type {
|
|
18
11
|
AnyChildNode,
|
|
12
|
+
AnyControlNode,
|
|
19
13
|
AnyLeafNode,
|
|
20
14
|
AnyNode,
|
|
21
15
|
AnyParentNode,
|
|
22
16
|
GeneralChildNode,
|
|
23
17
|
GeneralParentNode,
|
|
18
|
+
RepeatRangeNode,
|
|
24
19
|
} from './client/hierarchy.ts';
|
|
25
20
|
export type * from './client/index.ts';
|
|
21
|
+
export type * from './client/ModelValueNode.ts';
|
|
22
|
+
export type * from './client/NoteNode.ts';
|
|
23
|
+
export type * from './client/OpaqueReactiveObjectFactory.ts';
|
|
24
|
+
export type * from './client/repeat/RepeatInstanceNode.ts';
|
|
25
|
+
export type * from './client/repeat/RepeatRangeControlledNode.ts';
|
|
26
|
+
export type * from './client/repeat/RepeatRangeUncontrolledNode.ts';
|
|
27
|
+
export type * from './client/RootNode.ts';
|
|
28
|
+
export type * from './client/SelectNode.ts';
|
|
29
|
+
export type * from './client/StringNode.ts';
|
|
30
|
+
export type * from './client/SubtreeNode.ts';
|
|
31
|
+
export type * from './client/TextRange.ts';
|
|
32
|
+
export type * from './client/validation.ts';
|
|
26
33
|
|
|
27
34
|
// TODO: notwithstanding potential conflicts with parallel work on `web-forms`
|
|
28
35
|
// (former `ui-vue`), these are the last remaining references **outside of
|
package/src/instance/Group.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Accessor } from 'solid-js';
|
|
2
2
|
import type { GroupDefinition, GroupNode, GroupNodeAppearances } from '../client/GroupNode.ts';
|
|
3
|
-
import type { TextRange } from '../
|
|
3
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
4
|
+
import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
4
5
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
5
6
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
6
7
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -10,6 +11,7 @@ import type { EngineState } from '../lib/reactivity/node-state/createEngineState
|
|
|
10
11
|
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
11
12
|
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
12
13
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
14
|
+
import { createAggregatedViolations } from '../lib/reactivity/validation/createAggregatedViolations.ts';
|
|
13
15
|
import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
|
|
14
16
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
15
17
|
import { buildChildren } from './children.ts';
|
|
@@ -41,6 +43,7 @@ export class Group
|
|
|
41
43
|
readonly nodeType = 'group';
|
|
42
44
|
readonly appearances: GroupNodeAppearances;
|
|
43
45
|
readonly currentState: MaterializedChildren<CurrentState<GroupStateSpec>, GeneralChildNode>;
|
|
46
|
+
readonly validationState: AncestorNodeValidationState;
|
|
44
47
|
|
|
45
48
|
constructor(parent: GeneralParentNode, definition: GroupDefinition) {
|
|
46
49
|
super(parent, definition);
|
|
@@ -51,6 +54,10 @@ export class Group
|
|
|
51
54
|
|
|
52
55
|
this.childrenState = childrenState;
|
|
53
56
|
|
|
57
|
+
const sharedStateOptions = {
|
|
58
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
59
|
+
};
|
|
60
|
+
|
|
54
61
|
const state = createSharedNodeState(
|
|
55
62
|
this.scope,
|
|
56
63
|
{
|
|
@@ -65,9 +72,7 @@ export class Group
|
|
|
65
72
|
valueOptions: null,
|
|
66
73
|
value: null,
|
|
67
74
|
},
|
|
68
|
-
|
|
69
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
70
|
-
}
|
|
75
|
+
sharedStateOptions
|
|
71
76
|
);
|
|
72
77
|
|
|
73
78
|
this.state = state;
|
|
@@ -79,6 +84,7 @@ export class Group
|
|
|
79
84
|
);
|
|
80
85
|
|
|
81
86
|
childrenState.setChildren(buildChildren(this));
|
|
87
|
+
this.validationState = createAggregatedViolations(this, sharedStateOptions);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
getChildren(): readonly GeneralChildNode[] {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { identity } from '@getodk/common/lib/identity.ts';
|
|
2
|
+
import type { ModelValueNode } from '../client/ModelValueNode.ts';
|
|
3
|
+
import type { AnyViolation, LeafNodeValidationState } from '../client/validation.ts';
|
|
4
|
+
import { createValueState } from '../lib/reactivity/createValueState.ts';
|
|
5
|
+
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
6
|
+
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
7
|
+
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
8
|
+
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
9
|
+
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
10
|
+
import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
11
|
+
import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
12
|
+
import type { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
|
|
13
|
+
import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
|
|
14
|
+
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
15
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
16
|
+
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
17
|
+
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
18
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
19
|
+
import type { ValueContext } from './internal-api/ValueContext.ts';
|
|
20
|
+
|
|
21
|
+
export interface ModelValueDefinition extends LeafNodeDefinition {
|
|
22
|
+
readonly bodyElement: null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface ModelValueStateSpec extends DescendantNodeStateSpec<string> {
|
|
26
|
+
readonly label: null;
|
|
27
|
+
readonly hint: null;
|
|
28
|
+
readonly children: null;
|
|
29
|
+
readonly value: SimpleAtomicState<string>;
|
|
30
|
+
readonly valueOptions: null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class ModelValue
|
|
34
|
+
extends DescendantNode<ModelValueDefinition, ModelValueStateSpec, null>
|
|
35
|
+
implements
|
|
36
|
+
ModelValueNode,
|
|
37
|
+
EvaluationContext,
|
|
38
|
+
SubscribableDependency,
|
|
39
|
+
ValidationContext,
|
|
40
|
+
ValueContext<string>
|
|
41
|
+
{
|
|
42
|
+
private readonly validation: SharedValidationState;
|
|
43
|
+
protected readonly state: SharedNodeState<ModelValueStateSpec>;
|
|
44
|
+
|
|
45
|
+
// InstanceNode
|
|
46
|
+
protected engineState: EngineState<ModelValueStateSpec>;
|
|
47
|
+
|
|
48
|
+
// ModelValueNode
|
|
49
|
+
readonly nodeType = 'model-value';
|
|
50
|
+
readonly appearances = null;
|
|
51
|
+
readonly currentState: CurrentState<ModelValueStateSpec>;
|
|
52
|
+
|
|
53
|
+
get validationState(): LeafNodeValidationState {
|
|
54
|
+
return this.validation.currentState;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ValueContext
|
|
58
|
+
readonly encodeValue = identity<string>;
|
|
59
|
+
readonly decodeValue = identity<string>;
|
|
60
|
+
|
|
61
|
+
constructor(parent: GeneralParentNode, definition: ModelValueDefinition) {
|
|
62
|
+
super(parent, definition);
|
|
63
|
+
|
|
64
|
+
const sharedStateOptions = {
|
|
65
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const state = createSharedNodeState(
|
|
69
|
+
this.scope,
|
|
70
|
+
{
|
|
71
|
+
reference: this.contextReference,
|
|
72
|
+
readonly: this.isReadonly,
|
|
73
|
+
relevant: this.isRelevant,
|
|
74
|
+
required: this.isRequired,
|
|
75
|
+
|
|
76
|
+
label: null,
|
|
77
|
+
hint: null,
|
|
78
|
+
children: null,
|
|
79
|
+
valueOptions: null,
|
|
80
|
+
value: createValueState(this),
|
|
81
|
+
},
|
|
82
|
+
sharedStateOptions
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
this.state = state;
|
|
86
|
+
this.engineState = state.engineState;
|
|
87
|
+
this.currentState = state.currentState;
|
|
88
|
+
this.validation = createValidationState(this, sharedStateOptions);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getViolation(): AnyViolation | null {
|
|
92
|
+
return this.validation.engineState.violation;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ValidationContext
|
|
96
|
+
isBlank(): boolean {
|
|
97
|
+
return this.engineState.value === '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// InstanceNode
|
|
101
|
+
getChildren(): readonly [] {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { UnreachableError } from '@getodk/common/lib/error/UnreachableError.ts';
|
|
2
|
+
import { identity } from '@getodk/common/lib/identity.ts';
|
|
3
|
+
import type { Accessor } from 'solid-js';
|
|
4
|
+
import type { NoteNode, NoteNodeAppearances } from '../client/NoteNode.ts';
|
|
5
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
6
|
+
import type { AnyViolation, LeafNodeValidationState } from '../client/validation.ts';
|
|
7
|
+
import { createNoteReadonlyThunk } from '../lib/reactivity/createNoteReadonlyThunk.ts';
|
|
8
|
+
import { createValueState } from '../lib/reactivity/createValueState.ts';
|
|
9
|
+
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
10
|
+
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
11
|
+
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
12
|
+
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
13
|
+
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
14
|
+
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
15
|
+
import { createNoteText, type ComputedNoteText } from '../lib/reactivity/text/createNoteText.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
|
+
import type { NoteNodeDefinition } from '../parse/NoteNodeDefinition.ts';
|
|
20
|
+
import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
|
|
21
|
+
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
22
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
23
|
+
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
24
|
+
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
25
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
26
|
+
import type { ValueContext } from './internal-api/ValueContext.ts';
|
|
27
|
+
|
|
28
|
+
interface NoteStateSpec extends DescendantNodeStateSpec<string> {
|
|
29
|
+
readonly readonly: Accessor<true>;
|
|
30
|
+
readonly noteText: ComputedNoteText;
|
|
31
|
+
readonly label: Accessor<TextRange<'label', 'form'> | null>;
|
|
32
|
+
readonly hint: Accessor<TextRange<'hint', 'form'> | null>;
|
|
33
|
+
readonly children: null;
|
|
34
|
+
readonly value: SimpleAtomicState<string>;
|
|
35
|
+
readonly valueOptions: null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class Note
|
|
39
|
+
extends DescendantNode<NoteNodeDefinition, NoteStateSpec, null>
|
|
40
|
+
implements
|
|
41
|
+
NoteNode,
|
|
42
|
+
EvaluationContext,
|
|
43
|
+
SubscribableDependency,
|
|
44
|
+
ValidationContext,
|
|
45
|
+
ValueContext<string>
|
|
46
|
+
{
|
|
47
|
+
private readonly validation: SharedValidationState;
|
|
48
|
+
protected readonly state: SharedNodeState<NoteStateSpec>;
|
|
49
|
+
|
|
50
|
+
// InstanceNode
|
|
51
|
+
protected engineState: EngineState<NoteStateSpec>;
|
|
52
|
+
|
|
53
|
+
// NoteNode
|
|
54
|
+
readonly nodeType = 'note';
|
|
55
|
+
readonly appearances: NoteNodeAppearances;
|
|
56
|
+
readonly currentState: CurrentState<NoteStateSpec>;
|
|
57
|
+
|
|
58
|
+
get validationState(): LeafNodeValidationState {
|
|
59
|
+
return this.validation.currentState;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ValueContext
|
|
63
|
+
readonly encodeValue = identity<string>;
|
|
64
|
+
|
|
65
|
+
readonly decodeValue = identity<string>;
|
|
66
|
+
|
|
67
|
+
constructor(parent: GeneralParentNode, definition: NoteNodeDefinition) {
|
|
68
|
+
super(parent, definition);
|
|
69
|
+
|
|
70
|
+
this.appearances = definition.bodyElement.appearances;
|
|
71
|
+
|
|
72
|
+
const sharedStateOptions = {
|
|
73
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const isReadonly = createNoteReadonlyThunk(this, definition.bind.readonly);
|
|
77
|
+
const noteTextComputation = createNoteText(this, definition.noteTextDefinition);
|
|
78
|
+
|
|
79
|
+
let noteText: ComputedNoteText;
|
|
80
|
+
let label: Accessor<TextRange<'label', 'form'> | null>;
|
|
81
|
+
let hint: Accessor<TextRange<'hint', 'form'> | null>;
|
|
82
|
+
|
|
83
|
+
switch (noteTextComputation.role) {
|
|
84
|
+
case 'label': {
|
|
85
|
+
noteText = noteTextComputation.label;
|
|
86
|
+
label = noteTextComputation.label;
|
|
87
|
+
hint = createFieldHint(this, definition);
|
|
88
|
+
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
case 'hint': {
|
|
93
|
+
noteText = noteTextComputation.hint;
|
|
94
|
+
label = createNodeLabel(this, definition);
|
|
95
|
+
hint = noteTextComputation.hint;
|
|
96
|
+
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
default:
|
|
101
|
+
throw new UnreachableError(noteTextComputation);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const state = createSharedNodeState(
|
|
105
|
+
this.scope,
|
|
106
|
+
{
|
|
107
|
+
reference: this.contextReference,
|
|
108
|
+
readonly: isReadonly,
|
|
109
|
+
relevant: this.isRelevant,
|
|
110
|
+
required: this.isRequired,
|
|
111
|
+
|
|
112
|
+
label,
|
|
113
|
+
hint,
|
|
114
|
+
noteText,
|
|
115
|
+
|
|
116
|
+
children: null,
|
|
117
|
+
valueOptions: null,
|
|
118
|
+
value: createValueState(this),
|
|
119
|
+
},
|
|
120
|
+
sharedStateOptions
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
this.state = state;
|
|
124
|
+
this.engineState = state.engineState;
|
|
125
|
+
this.currentState = state.currentState;
|
|
126
|
+
this.validation = createValidationState(this, sharedStateOptions);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
getViolation(): AnyViolation | null {
|
|
130
|
+
return this.validation.engineState.violation;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ValidationContext
|
|
134
|
+
isBlank(): boolean {
|
|
135
|
+
return this.engineState.value === '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// InstanceNode
|
|
139
|
+
getChildren(): readonly [] {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
package/src/instance/Root.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { XFormDOM } from '../XFormDOM.ts';
|
|
|
5
5
|
import type { BodyClassList } from '../body/BodyDefinition.ts';
|
|
6
6
|
import type { ActiveLanguage, FormLanguage, FormLanguages } from '../client/FormLanguage.ts';
|
|
7
7
|
import type { RootNode } from '../client/RootNode.ts';
|
|
8
|
+
import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
8
9
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
9
10
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
10
11
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -13,6 +14,7 @@ import type { CurrentState } from '../lib/reactivity/node-state/createCurrentSta
|
|
|
13
14
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
14
15
|
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
15
16
|
import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
17
|
+
import { createAggregatedViolations } from '../lib/reactivity/validation/createAggregatedViolations.ts';
|
|
16
18
|
import type { RootDefinition } from '../model/RootDefinition.ts';
|
|
17
19
|
import { InstanceNode } from './abstract/InstanceNode.ts';
|
|
18
20
|
import { buildChildren } from './children.ts';
|
|
@@ -114,6 +116,7 @@ export class Root
|
|
|
114
116
|
readonly appearances = null;
|
|
115
117
|
readonly classes: BodyClassList;
|
|
116
118
|
readonly currentState: MaterializedChildren<CurrentState<RootStateSpec>, GeneralChildNode>;
|
|
119
|
+
readonly validationState: AncestorNodeValidationState;
|
|
117
120
|
|
|
118
121
|
protected readonly instanceDOM: XFormDOM;
|
|
119
122
|
|
|
@@ -152,6 +155,10 @@ export class Root
|
|
|
152
155
|
const evaluator = instanceDOM.primaryInstanceEvaluator;
|
|
153
156
|
const { translations } = evaluator;
|
|
154
157
|
const { defaultLanguage, languages } = getInitialLanguageState(translations);
|
|
158
|
+
const sharedStateOptions = {
|
|
159
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
160
|
+
};
|
|
161
|
+
|
|
155
162
|
const state = createSharedNodeState(
|
|
156
163
|
this.scope,
|
|
157
164
|
{
|
|
@@ -166,9 +173,7 @@ export class Root
|
|
|
166
173
|
value: null,
|
|
167
174
|
children: childrenState.childIds,
|
|
168
175
|
},
|
|
169
|
-
|
|
170
|
-
clientStateFactory: engineConfig.stateFactory,
|
|
171
|
-
}
|
|
176
|
+
sharedStateOptions
|
|
172
177
|
);
|
|
173
178
|
|
|
174
179
|
this.state = state;
|
|
@@ -189,6 +194,7 @@ export class Root
|
|
|
189
194
|
this.languages = languages;
|
|
190
195
|
|
|
191
196
|
childrenState.setChildren(buildChildren(this));
|
|
197
|
+
this.validationState = createAggregatedViolations(this, sharedStateOptions);
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
getChildren(): readonly GeneralChildNode[] {
|
|
@@ -3,7 +3,8 @@ import type { Accessor } from 'solid-js';
|
|
|
3
3
|
import { untrack } from 'solid-js';
|
|
4
4
|
import type { AnySelectDefinition } from '../body/control/select/SelectDefinition.ts';
|
|
5
5
|
import type { SelectItem, SelectNode, SelectNodeAppearances } from '../client/SelectNode.ts';
|
|
6
|
-
import type { TextRange } from '../
|
|
6
|
+
import type { TextRange } from '../client/TextRange.ts';
|
|
7
|
+
import type { AnyViolation, LeafNodeValidationState } from '../client/validation.ts';
|
|
7
8
|
import { createSelectItems } from '../lib/reactivity/createSelectItems.ts';
|
|
8
9
|
import { createValueState } from '../lib/reactivity/createValueState.ts';
|
|
9
10
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
@@ -13,16 +14,19 @@ import { createSharedNodeState } from '../lib/reactivity/node-state/createShared
|
|
|
13
14
|
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
14
15
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
15
16
|
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
16
|
-
import type {
|
|
17
|
+
import type { SharedValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
18
|
+
import { createValidationState } from '../lib/reactivity/validation/createValidation.ts';
|
|
19
|
+
import type { LeafNodeDefinition } from '../model/LeafNodeDefinition.ts';
|
|
17
20
|
import type { Root } from './Root.ts';
|
|
18
21
|
import type { DescendantNodeStateSpec } from './abstract/DescendantNode.ts';
|
|
19
22
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
20
23
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
21
24
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
22
25
|
import type { SubscribableDependency } from './internal-api/SubscribableDependency.ts';
|
|
26
|
+
import type { ValidationContext } from './internal-api/ValidationContext.ts';
|
|
23
27
|
import type { ValueContext } from './internal-api/ValueContext.ts';
|
|
24
28
|
|
|
25
|
-
export interface SelectFieldDefinition extends
|
|
29
|
+
export interface SelectFieldDefinition extends LeafNodeDefinition {
|
|
26
30
|
readonly bodyElement: AnySelectDefinition;
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -40,9 +44,11 @@ export class SelectField
|
|
|
40
44
|
SelectNode,
|
|
41
45
|
EvaluationContext,
|
|
42
46
|
SubscribableDependency,
|
|
47
|
+
ValidationContext,
|
|
43
48
|
ValueContext<readonly SelectItem[]>
|
|
44
49
|
{
|
|
45
50
|
private readonly selectExclusive: boolean;
|
|
51
|
+
private readonly validation: SharedValidationState;
|
|
46
52
|
|
|
47
53
|
// InstanceNode
|
|
48
54
|
protected readonly state: SharedNodeState<SelectFieldStateSpec>;
|
|
@@ -53,6 +59,10 @@ export class SelectField
|
|
|
53
59
|
readonly appearances: SelectNodeAppearances;
|
|
54
60
|
readonly currentState: CurrentState<SelectFieldStateSpec>;
|
|
55
61
|
|
|
62
|
+
get validationState(): LeafNodeValidationState {
|
|
63
|
+
return this.validation.currentState;
|
|
64
|
+
}
|
|
65
|
+
|
|
56
66
|
// ValueContext
|
|
57
67
|
readonly encodeValue = (runtimeValue: readonly SelectItem[]): string => {
|
|
58
68
|
const itemValues = new Set(runtimeValue.map(({ value }) => value));
|
|
@@ -90,6 +100,10 @@ export class SelectField
|
|
|
90
100
|
|
|
91
101
|
this.getValueOptions = valueOptions;
|
|
92
102
|
|
|
103
|
+
const sharedStateOptions = {
|
|
104
|
+
clientStateFactory: this.engineConfig.stateFactory,
|
|
105
|
+
};
|
|
106
|
+
|
|
93
107
|
const state = createSharedNodeState(
|
|
94
108
|
this.scope,
|
|
95
109
|
{
|
|
@@ -104,14 +118,17 @@ export class SelectField
|
|
|
104
118
|
value: createValueState(this),
|
|
105
119
|
valueOptions,
|
|
106
120
|
},
|
|
107
|
-
|
|
108
|
-
clientStateFactory: this.engineConfig.stateFactory,
|
|
109
|
-
}
|
|
121
|
+
sharedStateOptions
|
|
110
122
|
);
|
|
111
123
|
|
|
112
124
|
this.state = state;
|
|
113
125
|
this.engineState = state.engineState;
|
|
114
126
|
this.currentState = state.currentState;
|
|
127
|
+
this.validation = createValidationState(this, sharedStateOptions);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getViolation(): AnyViolation | null {
|
|
131
|
+
return this.validation.engineState.violation;
|
|
115
132
|
}
|
|
116
133
|
|
|
117
134
|
protected getSelectItemsByValue(
|
|
@@ -201,4 +218,9 @@ export class SelectField
|
|
|
201
218
|
getChildren(): readonly [] {
|
|
202
219
|
return [];
|
|
203
220
|
}
|
|
221
|
+
|
|
222
|
+
// ValidationContext
|
|
223
|
+
isBlank(): boolean {
|
|
224
|
+
return this.engineState.value.length === 0;
|
|
225
|
+
}
|
|
204
226
|
}
|