@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,9 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
TextRange as ClientTextRange,
|
|
3
|
+
TextChunk,
|
|
4
|
+
TextOrigin,
|
|
5
|
+
TextRole,
|
|
6
|
+
} from '../../client/TextRange.ts';
|
|
2
7
|
import { FormattedTextStub } from './FormattedTextStub.ts';
|
|
3
8
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
export class TextRange<Role extends TextRole, Origin extends TextOrigin>
|
|
10
|
+
implements ClientTextRange<Role, Origin>
|
|
11
|
+
{
|
|
7
12
|
*[Symbol.iterator]() {
|
|
8
13
|
yield* this.chunks;
|
|
9
14
|
}
|
|
@@ -17,6 +22,7 @@ export class TextRange<Role extends TextRole> implements ClientTextRange<Role> {
|
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
constructor(
|
|
25
|
+
readonly origin: Origin,
|
|
20
26
|
readonly role: Role,
|
|
21
27
|
protected readonly chunks: readonly TextChunk[]
|
|
22
28
|
) {}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { xmlXPathWhitespaceSeparatedList } from '@getodk/common/lib/string/whitespace.ts';
|
|
2
|
+
import type { PartiallyKnownString } from '@getodk/common/types/string/PartiallyKnownString.ts';
|
|
3
|
+
|
|
4
|
+
type SymbolIterator = typeof Symbol.iterator;
|
|
5
|
+
|
|
6
|
+
type TokenListKey<CanonicalToken extends string> =
|
|
7
|
+
| PartiallyKnownString<CanonicalToken>
|
|
8
|
+
| SymbolIterator;
|
|
9
|
+
|
|
10
|
+
type TokenListIterator<CanonicalToken extends string> = IterableIterator<
|
|
11
|
+
PartiallyKnownString<CanonicalToken>
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @see {@link TokenListParser}
|
|
16
|
+
*/
|
|
17
|
+
// prettier-ignore
|
|
18
|
+
export type TokenList<CanonicalToken extends string = string> = {
|
|
19
|
+
readonly [Key in TokenListKey<CanonicalToken>]:
|
|
20
|
+
Key extends SymbolIterator
|
|
21
|
+
? () => TokenListIterator<CanonicalToken>
|
|
22
|
+
: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
interface TokenListAlias<CanonicalToken extends string> {
|
|
26
|
+
readonly fromAlias: string;
|
|
27
|
+
readonly toCanonical: CanonicalToken;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type TokenAliases<CanonicalToken extends string> = ReadonlyArray<TokenListAlias<CanonicalToken>>;
|
|
31
|
+
|
|
32
|
+
interface TokenListParserOptions<CanonicalToken extends string> {
|
|
33
|
+
readonly aliases?: TokenAliases<CanonicalToken>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type TokenListAttributeName = PartiallyKnownString<'appearance' | 'class'>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Intended primarily for use in parsing these features:
|
|
40
|
+
*
|
|
41
|
+
* - {@link https://getodk.github.io/xforms-spec/#appearances | appearances} ({@link https://xlsform.org/en/#appearance | additional documentation})
|
|
42
|
+
*
|
|
43
|
+
* - {@link https://getodk.github.io/xforms-spec/#body-attributes | body `class` attribute}
|
|
44
|
+
*
|
|
45
|
+
* This class is named as a reference to {@link DOMTokenList}
|
|
46
|
+
* ({@link https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList | MDN}),
|
|
47
|
+
* with these similarities:
|
|
48
|
+
*
|
|
49
|
+
* - Represents a value whose serialization is a space-separated list.
|
|
50
|
+
* - Each member ("token") is a string (without whitespace).
|
|
51
|
+
* - Provides set-like semantics to determine presence of members.
|
|
52
|
+
* - Provides ordering semantics as determined by the serialization.
|
|
53
|
+
*
|
|
54
|
+
* This class differs from that prior art in that:
|
|
55
|
+
*
|
|
56
|
+
* - It provides a notion of "canonical" members. This is _mostly_ (but not
|
|
57
|
+
* entirely) intended as a convenience to client developers, automatically
|
|
58
|
+
* populating canonical/known tokens for a given parser type in
|
|
59
|
+
* editor-provided autocomplete, etc. **Importantly**, non-canonical tokens
|
|
60
|
+
* _are not ignored_ in either the {@link TokenList}'s types or runtime
|
|
61
|
+
* values.
|
|
62
|
+
*
|
|
63
|
+
* - Provided "canonical" members may also be used to specify
|
|
64
|
+
* {@link TokenListParserOptions.aliases | optional aliases}. (Example: when
|
|
65
|
+
* parsing "appearances", an alias might map an older deprecated appearance to
|
|
66
|
+
* a newer canonical equivalent.) **Importantly**, when a token matches an
|
|
67
|
+
* alias, both that alias _and the token as-specified_ will be present in the
|
|
68
|
+
* produced {@link TokenList}.
|
|
69
|
+
*
|
|
70
|
+
* - As a parser, it is intended to be read-only. The serialized format which it
|
|
71
|
+
* parses is _generally_ the source of truth (excepting e.g. aliases).
|
|
72
|
+
* Notably, and as mentioned above, ordering is determined by:
|
|
73
|
+
*
|
|
74
|
+
* - Iterating each member, as provided by the serialized representation
|
|
75
|
+
*
|
|
76
|
+
* - If that member corresponds to an alias, that alias is yielded first
|
|
77
|
+
*
|
|
78
|
+
* - Regardless of whether the member corresponds to an alias, the member is
|
|
79
|
+
* yielded as-specified
|
|
80
|
+
*
|
|
81
|
+
* - A parsed {@link TokenList} is intended to maximize convenience of read-only
|
|
82
|
+
* access. Despite many _conceptual similarities_, most of the
|
|
83
|
+
* {@link DOMTokenList} **interface** is eschewed in favor of two (mutually
|
|
84
|
+
* equivalent) access mechanisms:
|
|
85
|
+
*
|
|
86
|
+
* - `Iterable<Token>`, with the ordering semantics described above
|
|
87
|
+
* - `Record<Token, boolean>`
|
|
88
|
+
*
|
|
89
|
+
* \* This may change, as we refine requirements. In the future, we may
|
|
90
|
+
* introduce a notion of mutually exclusive tokens (e.g. "appearances" which
|
|
91
|
+
* cannot be used together), which may in turn utilize instance-defined ordering
|
|
92
|
+
* as part of that mechanism.
|
|
93
|
+
*/
|
|
94
|
+
export class TokenListParser<
|
|
95
|
+
CanonicalToken extends string,
|
|
96
|
+
// Note: this is a separate type parameter so that specifying an alias does
|
|
97
|
+
// not cause it to be mistakenly inferred as a `CanonicalToken` which was
|
|
98
|
+
// not otherwise specified.
|
|
99
|
+
TokenAlias extends CanonicalToken = CanonicalToken,
|
|
100
|
+
> {
|
|
101
|
+
private readonly aliases: ReadonlyMap<string, CanonicalToken>;
|
|
102
|
+
|
|
103
|
+
constructor(
|
|
104
|
+
readonly canonicalTokens: readonly CanonicalToken[],
|
|
105
|
+
options?: TokenListParserOptions<TokenAlias>
|
|
106
|
+
) {
|
|
107
|
+
this.aliases = new Map(
|
|
108
|
+
(options?.aliases ?? []).map(({ fromAlias, toCanonical }) => {
|
|
109
|
+
return [fromAlias, toCanonical];
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
parseFrom(element: Element, attributeName: TokenListAttributeName): TokenList<CanonicalToken> {
|
|
115
|
+
const serialized = element.getAttribute(attributeName) ?? '';
|
|
116
|
+
const specified = xmlXPathWhitespaceSeparatedList(serialized, {
|
|
117
|
+
ignoreEmpty: true,
|
|
118
|
+
});
|
|
119
|
+
const { aliases } = this;
|
|
120
|
+
const resolved = specified.flatMap((token) => {
|
|
121
|
+
const alias = aliases.get(token);
|
|
122
|
+
|
|
123
|
+
if (alias == null) {
|
|
124
|
+
return token;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [alias, token];
|
|
128
|
+
});
|
|
129
|
+
const tokens = new Set(resolved);
|
|
130
|
+
|
|
131
|
+
return new Proxy(
|
|
132
|
+
{
|
|
133
|
+
[Symbol.iterator]() {
|
|
134
|
+
return resolved.values();
|
|
135
|
+
},
|
|
136
|
+
} satisfies TokenList<string> as TokenList<CanonicalToken>,
|
|
137
|
+
{
|
|
138
|
+
get(target, property, receiver) {
|
|
139
|
+
if (typeof property === 'symbol') {
|
|
140
|
+
return Reflect.get(target, property, receiver);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return tokens.has(property);
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
set() {
|
|
147
|
+
return false;
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
|
+
export type ParsedTokenList<Parser extends TokenListParser<any>> =
|
|
156
|
+
Parser extends TokenListParser<infer CanonicalToken> ? TokenList<CanonicalToken> : never;
|
package/src/lib/dom/query.ts
CHANGED
|
@@ -9,6 +9,10 @@ const hintLookup = new ScopedElementLookup(':scope > hint', 'hint');
|
|
|
9
9
|
const itemLookup = new ScopedElementLookup(':scope > item', 'item');
|
|
10
10
|
const itemsetLookup = new ScopedElementLookup(':scope > itemset[nodeset]', 'itemset[nodeset]');
|
|
11
11
|
const labelLookup = new ScopedElementLookup(':scope > label', 'label');
|
|
12
|
+
const repeatGroupLabelLookup = new ScopedElementLookup(
|
|
13
|
+
':scope > label[form-definition-source="repeat-group"]',
|
|
14
|
+
'label[form-definition-source="repeat-group"]'
|
|
15
|
+
);
|
|
12
16
|
const repeatLookup = new ScopedElementLookup(':scope > repeat[nodeset]', 'repeat[nodeset]');
|
|
13
17
|
const valueLookup = new ScopedElementLookup(':scope > value', 'value');
|
|
14
18
|
|
|
@@ -20,6 +24,11 @@ export interface ItemsetElement extends KnownAttributeLocalNamedElement<'itemset
|
|
|
20
24
|
|
|
21
25
|
export interface LabelElement extends LocalNamedElement<'label'> {}
|
|
22
26
|
|
|
27
|
+
export interface RepeatGroupLabelElement extends LabelElement {
|
|
28
|
+
getAttribute(name: 'form-definition-source'): 'repeat-group';
|
|
29
|
+
getAttribute(name: string): string;
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
export interface RepeatElement extends KnownAttributeLocalNamedElement<'repeat', 'nodeset'> {}
|
|
24
33
|
|
|
25
34
|
export interface ValueElement extends LocalNamedElement<'value'> {}
|
|
@@ -40,6 +49,10 @@ export const getLabelElement = (parent: Element): LabelElement | null => {
|
|
|
40
49
|
return labelLookup.getElement<LabelElement>(parent);
|
|
41
50
|
};
|
|
42
51
|
|
|
52
|
+
export const getRepeatGroupLabelElement = (parent: Element): RepeatGroupLabelElement | null => {
|
|
53
|
+
return repeatGroupLabelLookup.getElement<RepeatGroupLabelElement>(parent);
|
|
54
|
+
};
|
|
55
|
+
|
|
43
56
|
export const getRepeatElement = (parent: Element): RepeatElement | null => {
|
|
44
57
|
return repeatLookup.getElement<RepeatElement>(parent);
|
|
45
58
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Accessor, Setter, Signal } from 'solid-js';
|
|
2
|
+
import { createSignal } from 'solid-js';
|
|
2
3
|
import type { OpaqueReactiveObjectFactory } from '../../index.ts';
|
|
3
4
|
import type { AnyChildNode, AnyParentNode } from '../../instance/hierarchy.ts';
|
|
4
5
|
import type { NodeID } from '../../instance/identity.ts';
|
|
@@ -44,11 +45,55 @@ export const createChildrenState = <Parent extends AnyParentNode, Child extends
|
|
|
44
45
|
parent: Parent
|
|
45
46
|
): ChildrenState<Child> => {
|
|
46
47
|
return parent.scope.runTask(() => {
|
|
47
|
-
const
|
|
48
|
-
const [getChildren,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const baseState = createSignal<readonly Child[]>([]);
|
|
49
|
+
const [getChildren, baseSetChildren] = baseState;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Note: this is clearly derived state. It would be obvious to use
|
|
53
|
+
* `createMemo`, which is exactly what a previous iteration did. This caused
|
|
54
|
+
* mysterious issues when clients:
|
|
55
|
+
*
|
|
56
|
+
* - Also used Solid-based reactivity
|
|
57
|
+
* - Accessed node children state within their own `createMemo` calls
|
|
58
|
+
*
|
|
59
|
+
* It's quite likely that there's a more robust and general solution, which
|
|
60
|
+
* may be applicable if we also generalize this approach to
|
|
61
|
+
* encode/materialize shared structured state (e.g. it may be applicable for
|
|
62
|
+
* select values, form language, probably much more in coming features).
|
|
63
|
+
*
|
|
64
|
+
* In the meantime, while this approach is marginally more complex, it is
|
|
65
|
+
* likely also slightly more efficient. We can revisit the tradeoff if/when
|
|
66
|
+
* those hypothetical generalizations become a priority.
|
|
67
|
+
*/
|
|
68
|
+
const ids = createSignal<readonly NodeID[]>([]);
|
|
69
|
+
const [childIds, setChildIds] = ids;
|
|
70
|
+
|
|
71
|
+
type ChildrenSetterCallback = (prev: readonly Child[]) => readonly Child[];
|
|
72
|
+
type ChildrenOrSetterCallback = ChildrenSetterCallback | readonly Child[];
|
|
73
|
+
|
|
74
|
+
const setChildren: Setter<readonly Child[]> = (
|
|
75
|
+
valueOrSetterCallback: ChildrenOrSetterCallback
|
|
76
|
+
) => {
|
|
77
|
+
let setterCallback: ChildrenSetterCallback;
|
|
78
|
+
|
|
79
|
+
if (typeof valueOrSetterCallback === 'function') {
|
|
80
|
+
setterCallback = valueOrSetterCallback;
|
|
81
|
+
} else {
|
|
82
|
+
setterCallback = (_) => valueOrSetterCallback;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return baseSetChildren((prev) => {
|
|
86
|
+
const result = setterCallback(prev);
|
|
87
|
+
|
|
88
|
+
setChildIds(() => {
|
|
89
|
+
return result.map((child) => child.nodeId);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
return result;
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const children: Signal<readonly Child[]> = [getChildren, setChildren];
|
|
52
97
|
|
|
53
98
|
return {
|
|
54
99
|
children,
|
|
@@ -8,10 +8,12 @@ import type {
|
|
|
8
8
|
} from '../../expression/DependentExpression.ts';
|
|
9
9
|
import type { EvaluationContext } from '../../instance/internal-api/EvaluationContext.ts';
|
|
10
10
|
import type { SubscribableDependency } from '../../instance/internal-api/SubscribableDependency.ts';
|
|
11
|
+
import { isConstantExpression } from '../../parse/xpath/semantic-analysis.ts';
|
|
11
12
|
|
|
12
13
|
interface ComputedExpressionResults {
|
|
13
14
|
readonly boolean: boolean;
|
|
14
15
|
readonly nodes: Node[];
|
|
16
|
+
readonly number: number;
|
|
15
17
|
readonly string: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
@@ -44,6 +46,11 @@ const expressionEvaluator = <Type extends DependentExpressionResultType>(
|
|
|
44
46
|
return evaluator.evaluateNodes(expression, options);
|
|
45
47
|
}) as ExpressionEvaluator<Type>;
|
|
46
48
|
|
|
49
|
+
case 'number':
|
|
50
|
+
return (() => {
|
|
51
|
+
return evaluator.evaluateNumber(expression, options);
|
|
52
|
+
}) as ExpressionEvaluator<Type>;
|
|
53
|
+
|
|
47
54
|
case 'string':
|
|
48
55
|
return (() => {
|
|
49
56
|
return evaluator.evaluateString(expression, options);
|
|
@@ -54,26 +61,19 @@ const expressionEvaluator = <Type extends DependentExpressionResultType>(
|
|
|
54
61
|
}
|
|
55
62
|
};
|
|
56
63
|
|
|
57
|
-
/**
|
|
58
|
-
* Determines if an XPath expression will always produce the same value.
|
|
59
|
-
*
|
|
60
|
-
* @todo There are quite a few more cases than this, and it also likely belongs
|
|
61
|
-
* in another `lib` module.
|
|
62
|
-
*/
|
|
63
|
-
const isConstantExpression = (expression: string): boolean => {
|
|
64
|
-
const normalized = expression.replaceAll(/\s/g, '');
|
|
65
|
-
|
|
66
|
-
return normalized === 'true()' || normalized === 'false()';
|
|
67
|
-
};
|
|
68
|
-
|
|
69
64
|
// prettier-ignore
|
|
70
65
|
type ComputedExpression<Type extends DependentExpressionResultType> = Accessor<
|
|
71
66
|
EvaluatedExpression<Type>
|
|
72
67
|
>;
|
|
73
68
|
|
|
69
|
+
interface CreateComputedExpressionOptions {
|
|
70
|
+
readonly arbitraryDependencies?: readonly SubscribableDependency[];
|
|
71
|
+
}
|
|
72
|
+
|
|
74
73
|
export const createComputedExpression = <Type extends DependentExpressionResultType>(
|
|
75
74
|
context: EvaluationContext,
|
|
76
|
-
dependentExpression: DependentExpression<Type
|
|
75
|
+
dependentExpression: DependentExpression<Type>,
|
|
76
|
+
options: CreateComputedExpressionOptions = {}
|
|
77
77
|
): ComputedExpression<Type> => {
|
|
78
78
|
const { contextNode, evaluator, root, scope } = context;
|
|
79
79
|
const { expression, isTranslated, resultType } = dependentExpression;
|
|
@@ -85,26 +85,24 @@ export const createComputedExpression = <Type extends DependentExpressionResultT
|
|
|
85
85
|
return createMemo(evaluateExpression);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
const { arbitraryDependencies = [] } = options;
|
|
89
|
+
|
|
88
90
|
const getReferencedDependencies = createMemo(() => {
|
|
89
91
|
return dependencyReferences.flatMap((reference) => {
|
|
90
|
-
return context.
|
|
92
|
+
return context.getSubscribableDependenciesByReference(reference) ?? [];
|
|
91
93
|
});
|
|
92
94
|
});
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
return createMemo(() => {
|
|
97
|
+
if (isTranslated) {
|
|
98
|
+
root.subscribe();
|
|
99
|
+
}
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return [root, ...getReferencedDependencies()];
|
|
101
|
+
arbitraryDependencies.forEach((dependency) => {
|
|
102
|
+
dependency.subscribe();
|
|
99
103
|
});
|
|
100
|
-
} else {
|
|
101
|
-
getDependencies = getReferencedDependencies;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return createMemo(() => {
|
|
105
|
-
const dependencies = getDependencies();
|
|
106
104
|
|
|
107
|
-
|
|
105
|
+
getReferencedDependencies().forEach((dependency) => {
|
|
108
106
|
dependency.subscribe();
|
|
109
107
|
});
|
|
110
108
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Accessor } from 'solid-js';
|
|
2
|
+
import type { EvaluationContext } from '../../instance/internal-api/EvaluationContext.ts';
|
|
3
|
+
import type { BindComputation } from '../../model/BindComputation.ts';
|
|
4
|
+
import { createComputedExpression } from './createComputedExpression.ts';
|
|
5
|
+
|
|
6
|
+
export const createNoteReadonlyThunk = (
|
|
7
|
+
context: EvaluationContext,
|
|
8
|
+
readonlyDefinition: BindComputation<'readonly'>
|
|
9
|
+
): Accessor<true> => {
|
|
10
|
+
if (!readonlyDefinition.isConstantTruthyExpression()) {
|
|
11
|
+
throw new Error('Expected a static readonly expression');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let result = true;
|
|
15
|
+
|
|
16
|
+
if (import.meta.env.DEV) {
|
|
17
|
+
const { expression } = readonlyDefinition;
|
|
18
|
+
|
|
19
|
+
if (readonlyDefinition.dependencyReferences.size > 0) {
|
|
20
|
+
throw new Error(`Expected expression ${expression} to have no dependencies`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const computedExpression = createComputedExpression(context, readonlyDefinition);
|
|
24
|
+
|
|
25
|
+
result = computedExpression();
|
|
26
|
+
|
|
27
|
+
if (result !== true) {
|
|
28
|
+
throw new Error(`Expected expression ${readonlyDefinition.expression} to return true`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return () => result;
|
|
33
|
+
};
|
|
@@ -4,6 +4,7 @@ import type { Accessor } from 'solid-js';
|
|
|
4
4
|
import { createMemo } from 'solid-js';
|
|
5
5
|
import type { ItemDefinition } from '../../body/control/select/ItemDefinition.ts';
|
|
6
6
|
import type { ItemsetDefinition } from '../../body/control/select/ItemsetDefinition.ts';
|
|
7
|
+
import type { TextRange as ClientTextRange } from '../../client/TextRange.ts';
|
|
7
8
|
import type { SelectItem } from '../../index.ts';
|
|
8
9
|
import type { SelectField } from '../../instance/SelectField.ts';
|
|
9
10
|
import type {
|
|
@@ -11,20 +12,31 @@ import type {
|
|
|
11
12
|
EvaluationContextRoot,
|
|
12
13
|
} from '../../instance/internal-api/EvaluationContext.ts';
|
|
13
14
|
import type { SubscribableDependency } from '../../instance/internal-api/SubscribableDependency.ts';
|
|
14
|
-
import
|
|
15
|
+
import { TextChunk } from '../../instance/text/TextChunk.ts';
|
|
16
|
+
import { TextRange } from '../../instance/text/TextRange.ts';
|
|
15
17
|
import { createComputedExpression } from './createComputedExpression.ts';
|
|
16
18
|
import type { ReactiveScope } from './scope.ts';
|
|
17
19
|
import { createTextRange } from './text/createTextRange.ts';
|
|
18
20
|
|
|
21
|
+
type DerivedItemLabel = ClientTextRange<'item-label', 'form-derived'>;
|
|
22
|
+
|
|
23
|
+
const derivedItemLabel = (context: EvaluationContext, value: string): DerivedItemLabel => {
|
|
24
|
+
const chunk = new TextChunk(context.root, 'static', value);
|
|
25
|
+
|
|
26
|
+
return new TextRange('form-derived', 'item-label', [chunk]);
|
|
27
|
+
};
|
|
28
|
+
|
|
19
29
|
const createSelectItemLabel = (
|
|
20
30
|
context: EvaluationContext,
|
|
21
31
|
definition: ItemDefinition
|
|
22
|
-
): Accessor<
|
|
32
|
+
): Accessor<ClientTextRange<'item-label'>> => {
|
|
23
33
|
const { label, value } = definition;
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
35
|
+
if (label == null) {
|
|
36
|
+
return () => derivedItemLabel(context, value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return createTextRange(context, 'item-label', label);
|
|
28
40
|
};
|
|
29
41
|
|
|
30
42
|
const createTranslatedStaticSelectItems = (
|
|
@@ -52,10 +64,7 @@ class ItemsetItemEvaluationContext implements EvaluationContext {
|
|
|
52
64
|
readonly scope: ReactiveScope;
|
|
53
65
|
readonly evaluator: XFormsXPathEvaluator;
|
|
54
66
|
readonly root: EvaluationContextRoot;
|
|
55
|
-
|
|
56
|
-
get contextReference(): string {
|
|
57
|
-
return this.selectField.contextReference;
|
|
58
|
-
}
|
|
67
|
+
readonly contextReference: Accessor<string>;
|
|
59
68
|
|
|
60
69
|
constructor(
|
|
61
70
|
private readonly selectField: SelectField,
|
|
@@ -64,10 +73,11 @@ class ItemsetItemEvaluationContext implements EvaluationContext {
|
|
|
64
73
|
this.scope = selectField.scope;
|
|
65
74
|
this.evaluator = selectField.evaluator;
|
|
66
75
|
this.root = selectField.root;
|
|
76
|
+
this.contextReference = selectField.contextReference;
|
|
67
77
|
}
|
|
68
78
|
|
|
69
|
-
|
|
70
|
-
return this.selectField.
|
|
79
|
+
getSubscribableDependenciesByReference(reference: string): readonly SubscribableDependency[] {
|
|
80
|
+
return this.selectField.getSubscribableDependenciesByReference(reference);
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
|
|
@@ -75,25 +85,20 @@ const createSelectItemsetItemLabel = (
|
|
|
75
85
|
context: EvaluationContext,
|
|
76
86
|
definition: ItemsetDefinition,
|
|
77
87
|
itemValue: Accessor<string>
|
|
78
|
-
): Accessor<
|
|
88
|
+
): Accessor<ClientTextRange<'item-label'>> => {
|
|
79
89
|
const { label } = definition;
|
|
80
90
|
|
|
81
91
|
if (label == null) {
|
|
82
92
|
return createMemo(() => {
|
|
83
|
-
|
|
84
|
-
const staticValueLabel = createTextRange(context, 'label', label, {
|
|
85
|
-
fallbackValue: value,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return staticValueLabel();
|
|
93
|
+
return derivedItemLabel(context, itemValue());
|
|
89
94
|
});
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
return createTextRange(context, 'label', label);
|
|
97
|
+
return createTextRange(context, 'item-label', label);
|
|
93
98
|
};
|
|
94
99
|
|
|
95
100
|
interface ItemsetItem {
|
|
96
|
-
label():
|
|
101
|
+
label(): ClientTextRange<'item-label'>;
|
|
97
102
|
value(): string;
|
|
98
103
|
}
|
|
99
104
|
|
|
@@ -72,7 +72,7 @@ const createPrimaryInstanceValueState = <RuntimeValue>(
|
|
|
72
72
|
|
|
73
73
|
const persistedValueState = createSignal<PersistedValueState>(
|
|
74
74
|
{
|
|
75
|
-
isRelevant: context.isRelevant,
|
|
75
|
+
isRelevant: context.isRelevant(),
|
|
76
76
|
value: initialValue,
|
|
77
77
|
},
|
|
78
78
|
{
|
|
@@ -91,7 +91,7 @@ const createPrimaryInstanceValueState = <RuntimeValue>(
|
|
|
91
91
|
const [persistedValue, setValueForPersistence] = persistedValueState;
|
|
92
92
|
|
|
93
93
|
createComputed(() => {
|
|
94
|
-
const isRelevant = context.isRelevant;
|
|
94
|
+
const isRelevant = context.isRelevant();
|
|
95
95
|
|
|
96
96
|
setValueForPersistence((persisted) => {
|
|
97
97
|
return {
|
|
@@ -122,7 +122,7 @@ const createPrimaryInstanceValueState = <RuntimeValue>(
|
|
|
122
122
|
const setPrimaryInstanceValue: SimpleAtomicStateSetter<string> = (value) => {
|
|
123
123
|
// TODO: Check (error?) for non-relevant value change?
|
|
124
124
|
const persisted = setValueForPersistence({
|
|
125
|
-
isRelevant: context.isRelevant,
|
|
125
|
+
isRelevant: context.isRelevant(),
|
|
126
126
|
value,
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -189,8 +189,8 @@ const guardDownstreamReadonlyWrites = <RuntimeValue>(
|
|
|
189
189
|
const [getValue, baseSetValue] = baseState;
|
|
190
190
|
|
|
191
191
|
const setValue: SimpleAtomicStateSetter<RuntimeValue> = (value) => {
|
|
192
|
-
if (context.isReadonly) {
|
|
193
|
-
const reference = untrack(() => context.contextReference);
|
|
192
|
+
if (context.isReadonly()) {
|
|
193
|
+
const reference = untrack(() => context.contextReference());
|
|
194
194
|
|
|
195
195
|
throw new Error(`Cannot write to readonly field: ${reference}`);
|
|
196
196
|
}
|
|
@@ -215,7 +215,7 @@ const createCalculation = <RuntimeValue>(
|
|
|
215
215
|
const calculate = createComputedExpression(context, calculateDefinition);
|
|
216
216
|
|
|
217
217
|
createComputed(() => {
|
|
218
|
-
if (context.isRelevant) {
|
|
218
|
+
if (context.isRelevant()) {
|
|
219
219
|
const calculated = calculate();
|
|
220
220
|
const value = context.decodeValue(calculated);
|
|
221
221
|
|
|
@@ -3,6 +3,7 @@ import type { NodeID } from '../../instance/identity.ts';
|
|
|
3
3
|
import type { ChildrenState, createChildrenState } from './createChildrenState.ts';
|
|
4
4
|
import type { ClientState } from './node-state/createClientState.ts';
|
|
5
5
|
import type { CurrentState } from './node-state/createCurrentState.ts';
|
|
6
|
+
import type { ReactiveScope } from './scope.ts';
|
|
6
7
|
|
|
7
8
|
interface InconsistentChildrenStateDetails {
|
|
8
9
|
readonly missingIds: readonly NodeID[];
|
|
@@ -96,6 +97,7 @@ export const materializeCurrentStateChildren = <
|
|
|
96
97
|
Child extends AnyChildNode,
|
|
97
98
|
ParentState extends EncodedParentState,
|
|
98
99
|
>(
|
|
100
|
+
scope: ReactiveScope,
|
|
99
101
|
currentState: ParentState,
|
|
100
102
|
childrenState: ChildrenState<Child>
|
|
101
103
|
): MaterializedChildren<ParentState, Child> => {
|
|
@@ -105,7 +107,7 @@ export const materializeCurrentStateChildren = <
|
|
|
105
107
|
return new Proxy(proxyTarget, {
|
|
106
108
|
get(_, key) {
|
|
107
109
|
if (key === 'children') {
|
|
108
|
-
const expectedChildIDs = currentState.children;
|
|
110
|
+
const expectedChildIDs = scope.runTask(() => currentState.children);
|
|
109
111
|
const children = childrenState.getChildren();
|
|
110
112
|
|
|
111
113
|
if (import.meta.env.DEV) {
|
|
@@ -31,7 +31,7 @@ export interface SharedNodeState<Spec extends StateSpec> {
|
|
|
31
31
|
readonly setProperty: SetEnginePropertyState<Spec>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
interface SharedNodeStateOptions<
|
|
34
|
+
export interface SharedNodeStateOptions<
|
|
35
35
|
Factory extends OpaqueReactiveObjectFactory,
|
|
36
36
|
Spec extends StateSpec,
|
|
37
37
|
> {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { type Accessor } from 'solid-js';
|
|
2
|
+
import type { TextRange } from '../../../client/TextRange.ts';
|
|
2
3
|
import type { EvaluationContext } from '../../../instance/internal-api/EvaluationContext.ts';
|
|
3
|
-
import {
|
|
4
|
-
import type { ValueNodeDefinition } from '../../../model/ValueNodeDefinition.ts';
|
|
4
|
+
import type { LeafNodeDefinition } from '../../../model/LeafNodeDefinition.ts';
|
|
5
5
|
import { createTextRange } from './createTextRange.ts';
|
|
6
6
|
|
|
7
7
|
export const createFieldHint = (
|
|
8
8
|
context: EvaluationContext,
|
|
9
|
-
definition:
|
|
10
|
-
): Accessor<TextRange<'hint'> | null> => {
|
|
9
|
+
definition: LeafNodeDefinition
|
|
10
|
+
): Accessor<TextRange<'hint', 'form'> | null> => {
|
|
11
11
|
const hintDefinition = definition.bodyElement?.hint ?? null;
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
13
|
+
if (hintDefinition == null) {
|
|
14
|
+
return () => null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return createTextRange(context, 'hint', hintDefinition);
|
|
16
18
|
};
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { type Accessor } from 'solid-js';
|
|
2
|
+
import type { TextRange } from '../../../client/TextRange.ts';
|
|
2
3
|
import type { EvaluationContext } from '../../../instance/internal-api/EvaluationContext.ts';
|
|
3
|
-
import { TextRange } from '../../../instance/text/TextRange.ts';
|
|
4
4
|
import type { AnyNodeDefinition } from '../../../model/NodeDefinition.ts';
|
|
5
5
|
import { createTextRange } from './createTextRange.ts';
|
|
6
6
|
|
|
7
7
|
export const createNodeLabel = (
|
|
8
8
|
context: EvaluationContext,
|
|
9
9
|
definition: AnyNodeDefinition
|
|
10
|
-
): Accessor<TextRange<'label'> | null> => {
|
|
10
|
+
): Accessor<TextRange<'label', 'form'> | null> => {
|
|
11
11
|
const labelDefinition = definition.bodyElement?.label ?? null;
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
13
|
+
if (labelDefinition == null) {
|
|
14
|
+
return () => null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return createTextRange(context, 'label', labelDefinition);
|
|
16
18
|
};
|