@getodk/xforms-engine 0.13.0 → 0.15.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/client/AttributeNode.d.ts +53 -0
- package/dist/client/BaseItem.d.ts +6 -0
- package/dist/client/GroupNode.d.ts +4 -4
- package/dist/client/MarkdownNode.d.ts +33 -0
- package/dist/client/RankNode.d.ts +2 -4
- package/dist/client/SelectNode.d.ts +2 -5
- package/dist/client/TextRange.d.ts +2 -2
- package/dist/client/hierarchy.d.ts +1 -2
- package/dist/client/index.d.ts +2 -1
- package/dist/client/node-types.d.ts +2 -2
- package/dist/client/validation.d.ts +7 -1
- package/dist/index.js +10758 -402
- package/dist/index.js.map +1 -1
- package/dist/instance/Attribute.d.ts +58 -0
- package/dist/instance/Group.d.ts +4 -0
- package/dist/instance/PrimaryInstance.d.ts +4 -0
- package/dist/instance/Root.d.ts +4 -0
- package/dist/instance/UploadControl.d.ts +4 -0
- package/dist/instance/abstract/InstanceNode.d.ts +7 -4
- package/dist/instance/abstract/ValueNode.d.ts +1 -0
- package/dist/instance/attachments/buildAttributes.d.ts +3 -0
- package/dist/instance/hierarchy.d.ts +6 -6
- package/dist/instance/internal-api/AttributeContext.d.ts +29 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +16 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableParentNode.d.ts +2 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.d.ts +2 -2
- package/dist/instance/markdown/MarkdownNode.d.ts +75 -0
- package/dist/instance/repeat/BaseRepeatRange.d.ts +5 -0
- package/dist/instance/repeat/RepeatInstance.d.ts +4 -2
- package/dist/instance/text/TextChunk.d.ts +0 -1
- package/dist/instance/text/TextRange.d.ts +2 -1
- package/dist/instance/text/markdownFormat.d.ts +3 -0
- package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +2 -2
- package/dist/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.d.ts +3 -0
- package/dist/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.d.ts +0 -3
- package/dist/lib/names/NamespaceDeclarationMap.d.ts +1 -1
- package/dist/lib/reactivity/createAttributeState.d.ts +16 -0
- package/dist/lib/reactivity/createAttributeValueState.d.ts +15 -0
- package/dist/lib/reactivity/createItemCollection.d.ts +5 -7
- package/dist/lib/xml-serialization.d.ts +5 -9
- package/dist/parse/XFormDOM.d.ts +1 -1
- package/dist/parse/body/BodyDefinition.d.ts +2 -8
- package/dist/parse/body/GroupElementDefinition.d.ts +22 -0
- package/dist/parse/body/control/ItemsetDefinition.d.ts +3 -0
- package/dist/parse/expression/ItemPropertyExpression.d.ts +6 -0
- package/dist/parse/model/AttributeDefinition.d.ts +22 -0
- package/dist/parse/model/{RootAttributeMap.d.ts → AttributeDefinitionMap.d.ts} +4 -10
- package/dist/parse/model/{SubtreeDefinition.d.ts → GroupDefinition.d.ts} +8 -4
- package/dist/parse/model/LeafNodeDefinition.d.ts +1 -0
- package/dist/parse/model/NodeDefinition.d.ts +13 -9
- package/dist/parse/model/RepeatDefinition.d.ts +5 -2
- package/dist/parse/model/RootDefinition.d.ts +3 -3
- package/dist/parse/text/LabelDefinition.d.ts +4 -5
- package/dist/solid.js +10758 -402
- package/dist/solid.js.map +1 -1
- package/package.json +6 -5
- package/src/client/AttributeNode.ts +62 -0
- package/src/client/BaseItem.ts +7 -0
- package/src/client/GroupNode.ts +4 -10
- package/src/client/MarkdownNode.ts +53 -0
- package/src/client/RankNode.ts +2 -5
- package/src/client/SelectNode.ts +2 -6
- package/src/client/TextRange.ts +2 -2
- package/src/client/hierarchy.ts +0 -2
- package/src/client/index.ts +2 -1
- package/src/client/node-types.ts +1 -1
- package/src/client/validation.ts +9 -1
- package/src/instance/Attribute.ts +164 -0
- package/src/instance/Group.ts +17 -1
- package/src/instance/InputControl.ts +1 -0
- package/src/instance/ModelValue.ts +1 -0
- package/src/instance/Note.ts +1 -0
- package/src/instance/PrimaryInstance.ts +17 -0
- package/src/instance/RangeControl.ts +1 -0
- package/src/instance/RankControl.ts +1 -0
- package/src/instance/Root.ts +16 -0
- package/src/instance/SelectControl.ts +1 -0
- package/src/instance/TriggerControl.ts +1 -0
- package/src/instance/UploadControl.ts +14 -0
- package/src/instance/abstract/DescendantNode.ts +5 -1
- package/src/instance/abstract/InstanceNode.ts +6 -3
- package/src/instance/abstract/ValueNode.ts +1 -0
- package/src/instance/attachments/buildAttributes.ts +8 -0
- package/src/instance/children/buildChildren.ts +1 -17
- package/src/instance/children/normalizeChildInitOptions.ts +44 -59
- package/src/instance/hierarchy.ts +3 -7
- package/src/instance/internal-api/AttributeContext.ts +34 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +19 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableParentNode.ts +2 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.ts +2 -3
- package/src/instance/markdown/MarkdownNode.ts +115 -0
- package/src/instance/repeat/BaseRepeatRange.ts +14 -0
- package/src/instance/repeat/RepeatInstance.ts +14 -5
- package/src/instance/text/TextChunk.ts +0 -5
- package/src/instance/text/TextRange.ts +5 -3
- package/src/instance/text/markdownFormat.ts +214 -0
- package/src/integration/xpath/adapter/XFormsXPathNode.ts +3 -1
- package/src/integration/xpath/adapter/names.ts +0 -1
- package/src/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.ts +16 -0
- package/src/lib/client-reactivity/instance-state/createParentNodeInstanceState.ts +5 -5
- package/src/lib/client-reactivity/instance-state/createRootInstanceState.ts +6 -9
- package/src/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.ts +5 -15
- package/src/lib/names/NamespaceDeclarationMap.ts +1 -1
- package/src/lib/reactivity/createAttributeState.ts +51 -0
- package/src/lib/reactivity/createAttributeValueState.ts +189 -0
- package/src/lib/reactivity/createItemCollection.ts +25 -9
- package/src/lib/xml-serialization.ts +30 -34
- package/src/parse/body/BodyDefinition.ts +7 -34
- package/src/parse/body/GroupElementDefinition.ts +47 -0
- package/src/parse/body/control/ItemsetDefinition.ts +7 -0
- package/src/parse/expression/ItemPropertyExpression.ts +12 -0
- package/src/parse/model/AttributeDefinition.ts +58 -0
- package/src/parse/model/{RootAttributeMap.ts → AttributeDefinitionMap.ts} +7 -13
- package/src/parse/model/{SubtreeDefinition.ts → GroupDefinition.ts} +12 -8
- package/src/parse/model/LeafNodeDefinition.ts +1 -0
- package/src/parse/model/NodeDefinition.ts +19 -12
- package/src/parse/model/RepeatDefinition.ts +10 -3
- package/src/parse/model/RootDefinition.ts +6 -6
- package/src/parse/model/nodeDefinitionMap.ts +1 -1
- package/src/parse/text/LabelDefinition.ts +4 -9
- package/dist/client/SubtreeNode.d.ts +0 -56
- package/dist/error/TemplatedNodeAttributeSerializationError.d.ts +0 -22
- package/dist/instance/Subtree.d.ts +0 -38
- package/dist/instance/text/FormattedTextStub.d.ts +0 -1
- package/dist/parse/body/group/BaseGroupDefinition.d.ts +0 -40
- package/dist/parse/body/group/LogicalGroupDefinition.d.ts +0 -6
- package/dist/parse/body/group/PresentationGroupDefinition.d.ts +0 -11
- package/dist/parse/body/group/StructuralGroupDefinition.d.ts +0 -6
- package/dist/parse/model/RootAttributeDefinition.d.ts +0 -21
- package/src/client/SubtreeNode.ts +0 -61
- package/src/error/TemplatedNodeAttributeSerializationError.ts +0 -24
- package/src/instance/Subtree.ts +0 -102
- package/src/instance/text/FormattedTextStub.ts +0 -8
- package/src/parse/body/group/BaseGroupDefinition.ts +0 -89
- package/src/parse/body/group/LogicalGroupDefinition.ts +0 -11
- package/src/parse/body/group/PresentationGroupDefinition.ts +0 -28
- package/src/parse/body/group/StructuralGroupDefinition.ts +0 -11
- package/src/parse/model/RootAttributeDefinition.ts +0 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getodk/xforms-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "XForms engine for ODK Web Forms",
|
|
6
6
|
"type": "module",
|
|
@@ -55,22 +55,23 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"bin-packer": "1.7.0",
|
|
58
|
+
"mdast-util-from-markdown": "^2.0.2",
|
|
58
59
|
"papaparse": "^5.5.3",
|
|
59
60
|
"solid-js": "^1.9.7",
|
|
60
61
|
"temporal-polyfill": "^0.3.0"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@babel/core": "^7.28.0",
|
|
64
|
-
"@getodk/tree-sitter-xpath": "0.2.
|
|
65
|
-
"@getodk/xpath": "0.
|
|
66
|
-
"@playwright/test": "^1.
|
|
65
|
+
"@getodk/tree-sitter-xpath": "0.2.1",
|
|
66
|
+
"@getodk/xpath": "0.9.0",
|
|
67
|
+
"@playwright/test": "^1.55.1",
|
|
67
68
|
"@types/papaparse": "^5.3.16",
|
|
68
69
|
"@vitest/browser": "^3.2.4",
|
|
69
70
|
"babel-plugin-transform-jsbi-to-bigint": "^1.4.2",
|
|
70
71
|
"http-server": "^14.1.1",
|
|
71
72
|
"jsdom": "^26.1.0",
|
|
72
73
|
"typedoc": "^0.28.7",
|
|
73
|
-
"vite": "^7.0.
|
|
74
|
+
"vite": "^7.0.8",
|
|
74
75
|
"vite-plugin-dts": "^4.5.4",
|
|
75
76
|
"vite-plugin-no-bundle": "^4.0.0",
|
|
76
77
|
"vitest": "^3.2.4"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Root } from '../instance/Root.ts';
|
|
2
|
+
import type { AttributeDefinition } from '../parse/model/AttributeDefinition.ts';
|
|
3
|
+
import type { OpaqueReactiveObjectFactory } from './OpaqueReactiveObjectFactory.ts';
|
|
4
|
+
import type { InstanceState } from './serialization/InstanceState.ts';
|
|
5
|
+
|
|
6
|
+
export interface AttributeNodeState {
|
|
7
|
+
get value(): string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base interface for common/shared aspects of attributes.
|
|
12
|
+
*/
|
|
13
|
+
export interface AttributeNode {
|
|
14
|
+
/**
|
|
15
|
+
* Specifies the node's general type. This can be useful for narrowing types,
|
|
16
|
+
* e.g. those of children.
|
|
17
|
+
*/
|
|
18
|
+
readonly nodeType: 'attribute';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Each node has a definition which specifies aspects of the node defined in
|
|
22
|
+
* the form. These aspects include (but are not limited to) the node's data
|
|
23
|
+
* type, its body presentation constraints (if any), its bound nodeset, and
|
|
24
|
+
* so on...
|
|
25
|
+
*/
|
|
26
|
+
readonly definition: AttributeDefinition;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Each node links back to the node representing the root of the form.
|
|
30
|
+
*/
|
|
31
|
+
readonly root: Root;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Each node links back to its parent, if any. All nodes have a parent except
|
|
35
|
+
* the form's {@link root}.
|
|
36
|
+
*/
|
|
37
|
+
readonly parent: unknown;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Each node provides a discrete object representing the stateful aspects of
|
|
41
|
+
* that node which will change over time. This includes state which is either
|
|
42
|
+
* client-/user-mutable, or state which is computed based on the core XForms
|
|
43
|
+
* computation model. Each node also exposes {@link validationState}, which
|
|
44
|
+
* reflects the validity of the node, or its descendants.
|
|
45
|
+
*
|
|
46
|
+
* When a client provides a {@link OpaqueReactiveObjectFactory}, the engine
|
|
47
|
+
* will update the properties of this object as their respective states
|
|
48
|
+
* change, so a client can implement reactive updates that respond to changes
|
|
49
|
+
* as they occur.
|
|
50
|
+
*/
|
|
51
|
+
readonly currentState: AttributeNodeState;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Represents the current instance state of the node.
|
|
55
|
+
*
|
|
56
|
+
* @see {@link InstanceState.instanceXML} for additional detail.
|
|
57
|
+
*/
|
|
58
|
+
readonly instanceState: InstanceState;
|
|
59
|
+
|
|
60
|
+
readonly appearances: null;
|
|
61
|
+
readonly nodeOptions: null;
|
|
62
|
+
}
|
package/src/client/GroupNode.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { GroupElementDefinition } from '../parse/body/GroupElementDefinition.ts';
|
|
2
|
+
import type { GroupDefinition as GroupNodeDefinition } from '../parse/model/GroupDefinition.ts';
|
|
3
3
|
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
4
4
|
import type { NodeAppearances } from './NodeAppearances.ts';
|
|
5
5
|
import type { RootNode } from './RootNode.ts';
|
|
@@ -13,10 +13,8 @@ export interface GroupNodeState extends BaseNodeState {
|
|
|
13
13
|
get value(): null;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export interface GroupDefinition extends SubtreeDefinition {
|
|
19
|
-
readonly bodyElement: AnyGroupElementDefinition;
|
|
16
|
+
export interface GroupDefinition extends GroupNodeDefinition {
|
|
17
|
+
readonly bodyElement: GroupElementDefinition;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
20
|
export type GroupNodeAppearances = NodeAppearances<GroupDefinition>;
|
|
@@ -24,10 +22,6 @@ export type GroupNodeAppearances = NodeAppearances<GroupDefinition>;
|
|
|
24
22
|
/**
|
|
25
23
|
* A node corresponding to an XForms `<group>`.
|
|
26
24
|
*/
|
|
27
|
-
// TODO: test (fix?) case where a `<group>` is implicitly connected to a
|
|
28
|
-
// subtree, but doesn't reference it directly. See
|
|
29
|
-
// https://github.com/getodk/web-forms/blob/6cfff8b4c5a2cf6a23a71ef6d4308343bccd2436/packages/odk-web-forms/src/lib/xform/model/ModelDefinition.test.ts#L480-L540
|
|
30
|
-
// for context.
|
|
31
25
|
export interface GroupNode extends BaseNode {
|
|
32
26
|
readonly nodeType: 'group';
|
|
33
27
|
readonly appearances: GroupNodeAppearances;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type Heading = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
2
|
+
|
|
3
|
+
export type ElementName =
|
|
4
|
+
| Heading
|
|
5
|
+
| 'a'
|
|
6
|
+
| 'div'
|
|
7
|
+
| 'em'
|
|
8
|
+
| 'li'
|
|
9
|
+
| 'ol'
|
|
10
|
+
| 'p'
|
|
11
|
+
| 'span'
|
|
12
|
+
| 'strong'
|
|
13
|
+
| 'u'
|
|
14
|
+
| 'ul';
|
|
15
|
+
|
|
16
|
+
export type MarkdownNode = ChildMarkdownNode | HtmlMarkdownNode | ParentMarkdownNode;
|
|
17
|
+
|
|
18
|
+
export interface ParentMarkdownNode {
|
|
19
|
+
readonly role: 'parent';
|
|
20
|
+
readonly elementName: string;
|
|
21
|
+
readonly children: MarkdownNode[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ChildMarkdownNode {
|
|
25
|
+
readonly role: 'child';
|
|
26
|
+
readonly value: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface HtmlMarkdownNode {
|
|
30
|
+
readonly role: 'html';
|
|
31
|
+
readonly unsafeHtml: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AnchorMarkdownNode extends ParentMarkdownNode {
|
|
35
|
+
readonly elementName: 'a';
|
|
36
|
+
readonly url: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface StyledMarkdownNode extends ParentMarkdownNode {
|
|
40
|
+
readonly elementName: 'div' | 'p' | 'span';
|
|
41
|
+
readonly properties: MarkdownProperty | undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface MarkdownProperty {
|
|
45
|
+
readonly style: StyleProperty;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface StyleProperty {
|
|
49
|
+
readonly color: string | undefined;
|
|
50
|
+
readonly 'font-family': string | undefined;
|
|
51
|
+
readonly 'text-align': 'center' | 'left' | 'right' | undefined;
|
|
52
|
+
readonly 'font-size': string | undefined;
|
|
53
|
+
}
|
package/src/client/RankNode.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RankControlDefinition } from '../parse/body/control/RankControlDefinition.ts';
|
|
2
2
|
import type { LeafNodeDefinition } from '../parse/model/LeafNodeDefinition.ts';
|
|
3
3
|
import type { BaseValueNode, BaseValueNodeState } from './BaseValueNode.ts';
|
|
4
|
+
import type { BaseItem } from './BaseItem.ts';
|
|
4
5
|
import type { RootNode } from './RootNode.ts';
|
|
5
6
|
import type { TextRange } from './TextRange.ts';
|
|
6
7
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
@@ -8,11 +9,7 @@ import type { LeafNodeValidationState } from './validation.ts';
|
|
|
8
9
|
import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
|
|
9
10
|
import type { ValueType } from './ValueType.ts';
|
|
10
11
|
|
|
11
|
-
export
|
|
12
|
-
get label(): TextRange<'item-label'>;
|
|
13
|
-
get value(): string;
|
|
14
|
-
}
|
|
15
|
-
|
|
12
|
+
export type RankItem = BaseItem;
|
|
16
13
|
export type RankValueOptions = readonly RankItem[];
|
|
17
14
|
|
|
18
15
|
export interface RankNodeState extends BaseValueNodeState<readonly string[]> {
|
package/src/client/SelectNode.ts
CHANGED
|
@@ -4,18 +4,14 @@ import type {
|
|
|
4
4
|
} from '../parse/body/control/SelectControlDefinition.ts';
|
|
5
5
|
import type { LeafNodeDefinition } from '../parse/model/LeafNodeDefinition.ts';
|
|
6
6
|
import type { BaseValueNode, BaseValueNodeState } from './BaseValueNode.ts';
|
|
7
|
+
import type { BaseItem } from './BaseItem.ts';
|
|
7
8
|
import type { NodeAppearances } from './NodeAppearances.ts';
|
|
8
9
|
import type { RootNode } from './RootNode.ts';
|
|
9
|
-
import type { TextRange } from './TextRange.ts';
|
|
10
10
|
import type { ValueType } from './ValueType.ts';
|
|
11
11
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
12
12
|
import type { LeafNodeValidationState } from './validation.ts';
|
|
13
13
|
|
|
14
|
-
export
|
|
15
|
-
get label(): TextRange<'item-label'>;
|
|
16
|
-
get value(): string;
|
|
17
|
-
}
|
|
18
|
-
|
|
14
|
+
export type SelectItem = BaseItem;
|
|
19
15
|
export type SelectValueOptions = readonly SelectItem[];
|
|
20
16
|
|
|
21
17
|
export interface SelectNodeState extends BaseValueNodeState<readonly string[]> {
|
package/src/client/TextRange.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
2
2
|
import type { ActiveLanguage } from './FormLanguage.ts';
|
|
3
|
+
import type { MarkdownNode } from './MarkdownNode.ts';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* **COMMENTARY**
|
|
@@ -73,7 +74,6 @@ export interface TextChunk {
|
|
|
73
74
|
get language(): ActiveLanguage;
|
|
74
75
|
|
|
75
76
|
get asString(): string;
|
|
76
|
-
get formatted(): unknown;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// eslint-disable-next-line @typescript-eslint/sort-type-constituents
|
|
@@ -146,7 +146,7 @@ export interface TextRange<Role extends TextRole, Origin extends TextOrigin = Te
|
|
|
146
146
|
[Symbol.iterator](): Iterable<TextChunk>;
|
|
147
147
|
|
|
148
148
|
get asString(): string;
|
|
149
|
-
get formatted():
|
|
149
|
+
get formatted(): MarkdownNode[];
|
|
150
150
|
|
|
151
151
|
get imageSource(): JRResourceURL | undefined;
|
|
152
152
|
get audioSource(): JRResourceURL | undefined;
|
package/src/client/hierarchy.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type { RepeatRangeControlledNode } from './repeat/RepeatRangeControlledNo
|
|
|
10
10
|
import type { RepeatRangeUncontrolledNode } from './repeat/RepeatRangeUncontrolledNode.ts';
|
|
11
11
|
import type { RootNode } from './RootNode.ts';
|
|
12
12
|
import type { SelectNode } from './SelectNode.ts';
|
|
13
|
-
import type { SubtreeNode } from './SubtreeNode.ts';
|
|
14
13
|
import type { TriggerNode } from './TriggerNode.ts';
|
|
15
14
|
import type { UploadNode } from './UploadNode.ts';
|
|
16
15
|
|
|
@@ -40,7 +39,6 @@ export type RepeatRangeNode =
|
|
|
40
39
|
*/
|
|
41
40
|
export type GeneralParentNode =
|
|
42
41
|
| RootNode // eslint-disable-line @typescript-eslint/sort-type-constituents
|
|
43
|
-
| SubtreeNode
|
|
44
42
|
| GroupNode
|
|
45
43
|
| RepeatInstanceNode;
|
|
46
44
|
|
package/src/client/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type * from './attachments/InstanceAttachmentMeta.ts';
|
|
2
2
|
export type * from './attachments/InstanceAttachmentsConfig.ts';
|
|
3
|
+
export type * from './AttributeNode.ts';
|
|
3
4
|
export type * from './constants.ts';
|
|
4
5
|
export * as constants from './constants.ts';
|
|
5
6
|
export type * from './form/CreateFormInstance.ts';
|
|
@@ -24,6 +25,7 @@ export type {
|
|
|
24
25
|
} from './hierarchy.ts';
|
|
25
26
|
export type * from './identity.ts';
|
|
26
27
|
export type * from './InputNode.ts';
|
|
28
|
+
export type * from './MarkdownNode.ts';
|
|
27
29
|
export type * from './ModelValueNode.ts';
|
|
28
30
|
export type * from './NoteNode.ts';
|
|
29
31
|
export type * from './OpaqueReactiveObjectFactory.ts';
|
|
@@ -41,7 +43,6 @@ export type * from './serialization/InstancePayload.ts';
|
|
|
41
43
|
export type * from './serialization/InstancePayloadOptions.ts';
|
|
42
44
|
export type * from './serialization/InstanceState.ts';
|
|
43
45
|
export type * from './submission/SubmissionMeta.ts';
|
|
44
|
-
export type * from './SubtreeNode.ts';
|
|
45
46
|
export type * from './TextRange.ts';
|
|
46
47
|
export type * from './TriggerNode.ts';
|
|
47
48
|
export type * from './UploadNode.ts';
|
package/src/client/node-types.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type LeafNodeType =
|
|
|
13
13
|
| 'trigger'
|
|
14
14
|
| 'range'
|
|
15
15
|
| 'rank'
|
|
16
|
+
| 'attribute'
|
|
16
17
|
| 'upload';
|
|
17
18
|
|
|
18
19
|
// prettier-ignore
|
|
@@ -22,5 +23,4 @@ export type InstanceNodeType =
|
|
|
22
23
|
| RepeatRangeNodeType
|
|
23
24
|
| 'repeat-instance'
|
|
24
25
|
| 'group'
|
|
25
|
-
| 'subtree'
|
|
26
26
|
| LeafNodeType;
|
package/src/client/validation.ts
CHANGED
|
@@ -193,7 +193,15 @@ export interface AncestorNodeValidationState {
|
|
|
193
193
|
get violations(): readonly DescendantNodeViolationReference[];
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Convenience interface for nodes that cannot be invalid.
|
|
198
|
+
*/
|
|
199
|
+
export interface NullValidationState {
|
|
200
|
+
get violations(): readonly [];
|
|
201
|
+
}
|
|
202
|
+
|
|
196
203
|
// prettier-ignore
|
|
197
204
|
export type NodeValidationState =
|
|
198
205
|
| AncestorNodeValidationState
|
|
199
|
-
| LeafNodeValidationState
|
|
206
|
+
| LeafNodeValidationState
|
|
207
|
+
| NullValidationState;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { XPathNodeKindKey } from '@getodk/xpath';
|
|
2
|
+
import type { Accessor } from 'solid-js';
|
|
3
|
+
import type { AttributeNode } from '../client/AttributeNode.ts';
|
|
4
|
+
import type { ActiveLanguage, InstanceState, NullValidationState } from '../client/index.ts';
|
|
5
|
+
import type { XFormsXPathAttribute } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
6
|
+
import type { EngineXPathEvaluator } from '../integration/xpath/EngineXPathEvaluator.ts';
|
|
7
|
+
import type { StaticAttribute } from '../integration/xpath/static-dom/StaticAttribute.ts';
|
|
8
|
+
import { createAttributeNodeInstanceState } from '../lib/client-reactivity/instance-state/createAttributeNodeInstanceState.ts';
|
|
9
|
+
import {
|
|
10
|
+
getSharedValueCodec,
|
|
11
|
+
type RuntimeInputValue,
|
|
12
|
+
type RuntimeValue,
|
|
13
|
+
} from '../lib/codecs/getSharedValueCodec.ts';
|
|
14
|
+
import type { RuntimeValueSetter, RuntimeValueState } from '../lib/codecs/ValueCodec.ts';
|
|
15
|
+
import { createAttributeValueState } from '../lib/reactivity/createAttributeValueState.ts';
|
|
16
|
+
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
17
|
+
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
18
|
+
import {
|
|
19
|
+
createSharedNodeState,
|
|
20
|
+
type SharedNodeState,
|
|
21
|
+
} from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
22
|
+
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
23
|
+
import type { AttributeDefinition } from '../parse/model/AttributeDefinition.ts';
|
|
24
|
+
import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
|
|
25
|
+
import { InstanceNode } from './abstract/InstanceNode.ts';
|
|
26
|
+
import type { AnyParentNode } from './hierarchy.ts';
|
|
27
|
+
import type { AttributeContext } from './internal-api/AttributeContext.ts';
|
|
28
|
+
import type { DecodeInstanceValue } from './internal-api/InstanceValueContext.ts';
|
|
29
|
+
import type { ClientReactiveSerializableAttributeNode } from './internal-api/serialization/ClientReactiveSerializableAttributeNode.ts';
|
|
30
|
+
import type { Root } from './Root.ts';
|
|
31
|
+
|
|
32
|
+
export interface AttributeStateSpec extends DescendantNodeSharedStateSpec {
|
|
33
|
+
readonly children: null;
|
|
34
|
+
readonly attributes: null;
|
|
35
|
+
readonly value: SimpleAtomicState<string>;
|
|
36
|
+
readonly instanceValue: Accessor<string>;
|
|
37
|
+
readonly label: null;
|
|
38
|
+
readonly hint: null;
|
|
39
|
+
readonly valueOptions: null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class Attribute
|
|
43
|
+
extends InstanceNode<AttributeDefinition, AttributeStateSpec, AnyParentNode, null>
|
|
44
|
+
implements
|
|
45
|
+
AttributeNode,
|
|
46
|
+
ClientReactiveSerializableAttributeNode,
|
|
47
|
+
AttributeContext,
|
|
48
|
+
XFormsXPathAttribute
|
|
49
|
+
{
|
|
50
|
+
override readonly [XPathNodeKindKey] = 'attribute';
|
|
51
|
+
|
|
52
|
+
protected readonly state: SharedNodeState<AttributeStateSpec>;
|
|
53
|
+
protected readonly engineState: EngineState<AttributeStateSpec>;
|
|
54
|
+
readonly validationState: NullValidationState;
|
|
55
|
+
|
|
56
|
+
readonly nodeType = 'attribute';
|
|
57
|
+
readonly currentState: CurrentState<AttributeStateSpec>;
|
|
58
|
+
override readonly instanceState: InstanceState;
|
|
59
|
+
|
|
60
|
+
readonly appearances = null;
|
|
61
|
+
readonly nodeOptions = null;
|
|
62
|
+
|
|
63
|
+
readonly valueType: string;
|
|
64
|
+
readonly decodeInstanceValue: DecodeInstanceValue;
|
|
65
|
+
|
|
66
|
+
protected readonly getInstanceValue: Accessor<string>;
|
|
67
|
+
protected readonly valueState: RuntimeValueState<RuntimeValue<'string'>>;
|
|
68
|
+
protected readonly setValueState: RuntimeValueSetter<RuntimeInputValue<'string'>>;
|
|
69
|
+
readonly evaluator: EngineXPathEvaluator;
|
|
70
|
+
readonly getActiveLanguage: Accessor<ActiveLanguage>;
|
|
71
|
+
|
|
72
|
+
override readonly root: Root;
|
|
73
|
+
|
|
74
|
+
readonly isRelevant: Accessor<boolean> = () => {
|
|
75
|
+
return this.parent.isRelevant();
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
readonly isAttached: Accessor<boolean> = () => {
|
|
79
|
+
return this.parent.isAttached();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
readonly isReadonly: Accessor<boolean> = () => {
|
|
83
|
+
return true;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
readonly hasReadonlyAncestor: Accessor<boolean> = () => {
|
|
87
|
+
const { parent } = this;
|
|
88
|
+
return parent.hasReadonlyAncestor() || parent.isReadonly();
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
readonly hasNonRelevantAncestor: Accessor<boolean> = () => {
|
|
92
|
+
const { parent } = this;
|
|
93
|
+
return parent.hasNonRelevantAncestor() || !parent.isRelevant();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
constructor(
|
|
97
|
+
parent: AnyParentNode,
|
|
98
|
+
definition: AttributeDefinition,
|
|
99
|
+
override readonly instanceNode: StaticAttribute
|
|
100
|
+
) {
|
|
101
|
+
const codec = getSharedValueCodec('string');
|
|
102
|
+
|
|
103
|
+
super(parent.instanceConfig, parent, instanceNode, definition, {
|
|
104
|
+
scope: parent.scope,
|
|
105
|
+
computeReference: (): string => '@' + this.definition.qualifiedName.getPrefixedName(),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
this.root = parent.root;
|
|
109
|
+
|
|
110
|
+
this.getActiveLanguage = parent.getActiveLanguage;
|
|
111
|
+
this.validationState = { violations: [] };
|
|
112
|
+
|
|
113
|
+
this.valueType = 'string';
|
|
114
|
+
this.evaluator = parent.evaluator;
|
|
115
|
+
this.decodeInstanceValue = codec.decodeInstanceValue;
|
|
116
|
+
|
|
117
|
+
const instanceValueState = createAttributeValueState(this);
|
|
118
|
+
const valueState = codec.createRuntimeValueState(instanceValueState);
|
|
119
|
+
|
|
120
|
+
const [getInstanceValue] = instanceValueState;
|
|
121
|
+
const [, setValueState] = valueState;
|
|
122
|
+
|
|
123
|
+
this.getInstanceValue = getInstanceValue;
|
|
124
|
+
this.setValueState = setValueState;
|
|
125
|
+
this.getXPathValue = () => {
|
|
126
|
+
return this.getInstanceValue();
|
|
127
|
+
};
|
|
128
|
+
this.valueState = valueState;
|
|
129
|
+
|
|
130
|
+
const state = createSharedNodeState(
|
|
131
|
+
this.scope,
|
|
132
|
+
{
|
|
133
|
+
reference: this.contextReference,
|
|
134
|
+
readonly: this.isReadonly,
|
|
135
|
+
relevant: this.isRelevant,
|
|
136
|
+
required: () => false,
|
|
137
|
+
|
|
138
|
+
label: null,
|
|
139
|
+
hint: null,
|
|
140
|
+
children: null,
|
|
141
|
+
valueOptions: null,
|
|
142
|
+
value: this.valueState,
|
|
143
|
+
instanceValue: this.getInstanceValue,
|
|
144
|
+
attributes: null,
|
|
145
|
+
},
|
|
146
|
+
this.instanceConfig
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
this.state = state;
|
|
150
|
+
this.engineState = state.engineState;
|
|
151
|
+
this.currentState = state.currentState;
|
|
152
|
+
this.instanceState = createAttributeNodeInstanceState(this);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
setValue(value: string): Root {
|
|
156
|
+
this.setValueState(value);
|
|
157
|
+
|
|
158
|
+
return this.root;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getChildren(): readonly [] {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
package/src/instance/Group.ts
CHANGED
|
@@ -8,6 +8,10 @@ import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
|
8
8
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
9
9
|
import type { StaticElement } from '../integration/xpath/static-dom/StaticElement.ts';
|
|
10
10
|
import { createParentNodeInstanceState } from '../lib/client-reactivity/instance-state/createParentNodeInstanceState.ts';
|
|
11
|
+
import {
|
|
12
|
+
createAttributeState,
|
|
13
|
+
type AttributeState,
|
|
14
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
11
15
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
12
16
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
13
17
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -20,6 +24,8 @@ import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
|
20
24
|
import { createAggregatedViolations } from '../lib/reactivity/validation/createAggregatedViolations.ts';
|
|
21
25
|
import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
|
|
22
26
|
import { DescendantNode } from './abstract/DescendantNode.ts';
|
|
27
|
+
import { buildAttributes } from './attachments/buildAttributes.ts';
|
|
28
|
+
import { Attribute } from './Attribute.ts';
|
|
23
29
|
import { buildChildren } from './children/buildChildren.ts';
|
|
24
30
|
import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
|
|
25
31
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
@@ -30,6 +36,7 @@ interface GroupStateSpec extends DescendantNodeSharedStateSpec {
|
|
|
30
36
|
readonly label: Accessor<TextRange<'label'> | null>;
|
|
31
37
|
readonly hint: null;
|
|
32
38
|
readonly children: Accessor<readonly FormNodeID[]>;
|
|
39
|
+
readonly attributes: Accessor<readonly Attribute[]>;
|
|
33
40
|
readonly valueOptions: null;
|
|
34
41
|
readonly value: null;
|
|
35
42
|
}
|
|
@@ -43,6 +50,7 @@ export class Group
|
|
|
43
50
|
ClientReactiveSerializableParentNode<GeneralChildNode>
|
|
44
51
|
{
|
|
45
52
|
private readonly childrenState: ChildrenState<GeneralChildNode>;
|
|
53
|
+
private readonly attributeState: AttributeState;
|
|
46
54
|
|
|
47
55
|
override readonly [XPathNodeKindKey] = 'element';
|
|
48
56
|
|
|
@@ -65,11 +73,13 @@ export class Group
|
|
|
65
73
|
) {
|
|
66
74
|
super(parent, instanceNode, definition);
|
|
67
75
|
|
|
68
|
-
this.appearances = definition.bodyElement
|
|
76
|
+
this.appearances = definition.bodyElement?.appearances ?? null;
|
|
69
77
|
|
|
70
78
|
const childrenState = createChildrenState<Group, GeneralChildNode>(this);
|
|
79
|
+
const attributeState = createAttributeState(this.scope);
|
|
71
80
|
|
|
72
81
|
this.childrenState = childrenState;
|
|
82
|
+
this.attributeState = attributeState;
|
|
73
83
|
|
|
74
84
|
const state = createSharedNodeState(
|
|
75
85
|
this.scope,
|
|
@@ -82,6 +92,7 @@ export class Group
|
|
|
82
92
|
label: createNodeLabel(this, definition),
|
|
83
93
|
hint: null,
|
|
84
94
|
children: childrenState.childIds,
|
|
95
|
+
attributes: attributeState.getAttributes,
|
|
85
96
|
valueOptions: null,
|
|
86
97
|
value: null,
|
|
87
98
|
},
|
|
@@ -97,6 +108,7 @@ export class Group
|
|
|
97
108
|
);
|
|
98
109
|
|
|
99
110
|
childrenState.setChildren(buildChildren(this));
|
|
111
|
+
attributeState.setAttributes(buildAttributes(this));
|
|
100
112
|
this.validationState = createAggregatedViolations(this, this.instanceConfig);
|
|
101
113
|
this.instanceState = createParentNodeInstanceState(this);
|
|
102
114
|
}
|
|
@@ -104,4 +116,8 @@ export class Group
|
|
|
104
116
|
getChildren(): readonly GeneralChildNode[] {
|
|
105
117
|
return this.childrenState.getChildren();
|
|
106
118
|
}
|
|
119
|
+
|
|
120
|
+
getAttributes(): readonly Attribute[] {
|
|
121
|
+
return this.attributeState.getAttributes();
|
|
122
|
+
}
|
|
107
123
|
}
|
|
@@ -130,6 +130,7 @@ export class InputControl<V extends ValueType = ValueType>
|
|
|
130
130
|
label: createNodeLabel(this, definition),
|
|
131
131
|
hint: createFieldHint(this, definition),
|
|
132
132
|
children: null,
|
|
133
|
+
attributes: null,
|
|
133
134
|
valueOptions: null,
|
|
134
135
|
value: this.valueState,
|
|
135
136
|
instanceValue: this.getInstanceValue,
|
package/src/instance/Note.ts
CHANGED
|
@@ -17,6 +17,10 @@ import { EngineXPathEvaluator } from '../integration/xpath/EngineXPathEvaluator.
|
|
|
17
17
|
import type { StaticDocument } from '../integration/xpath/static-dom/StaticDocument.ts';
|
|
18
18
|
import { createPrimaryInstanceState } from '../lib/client-reactivity/instance-state/createPrimaryInstanceState.ts';
|
|
19
19
|
import { prepareInstancePayload } from '../lib/client-reactivity/instance-state/prepareInstancePayload.ts';
|
|
20
|
+
import {
|
|
21
|
+
createAttributeState,
|
|
22
|
+
type AttributeState,
|
|
23
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
20
24
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
21
25
|
import { createTranslationState } from '../lib/reactivity/createTranslationState.ts';
|
|
22
26
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -32,7 +36,9 @@ import type { ModelDefinition } from '../parse/model/ModelDefinition.ts';
|
|
|
32
36
|
import type { RootDefinition } from '../parse/model/RootDefinition.ts';
|
|
33
37
|
import type { SecondaryInstancesDefinition } from '../parse/model/SecondaryInstance/SecondaryInstancesDefinition.ts';
|
|
34
38
|
import { InstanceNode } from './abstract/InstanceNode.ts';
|
|
39
|
+
import { buildAttributes } from './attachments/buildAttributes.ts';
|
|
35
40
|
import { InstanceAttachmentsState } from './attachments/InstanceAttachmentsState.ts';
|
|
41
|
+
import type { Attribute } from './Attribute.ts';
|
|
36
42
|
import type { InitialInstanceState } from './input/InitialInstanceState.ts';
|
|
37
43
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
38
44
|
import type { InstanceConfig } from './internal-api/InstanceConfig.ts';
|
|
@@ -71,6 +77,7 @@ interface PrimaryInstanceStateSpec {
|
|
|
71
77
|
readonly label: null;
|
|
72
78
|
readonly hint: null;
|
|
73
79
|
readonly children: Accessor<readonly FormNodeID[]>;
|
|
80
|
+
readonly attributes: Accessor<readonly Attribute[]>;
|
|
74
81
|
readonly valueOptions: null;
|
|
75
82
|
readonly value: null;
|
|
76
83
|
|
|
@@ -154,6 +161,8 @@ export class PrimaryInstance<
|
|
|
154
161
|
readonly evaluator: EngineXPathEvaluator;
|
|
155
162
|
override readonly contextNode = this;
|
|
156
163
|
|
|
164
|
+
private readonly attributeState: AttributeState;
|
|
165
|
+
|
|
157
166
|
constructor(options: PrimaryInstanceOptions<Mode>) {
|
|
158
167
|
const { mode, initialState, scope, model, secondaryInstances, config } = options;
|
|
159
168
|
const { instance: modelInstance } = model;
|
|
@@ -193,8 +202,10 @@ export class PrimaryInstance<
|
|
|
193
202
|
this.classes = definition.classes;
|
|
194
203
|
|
|
195
204
|
const childrenState = createChildrenState<this, Root>(this);
|
|
205
|
+
const attributeState = createAttributeState(this.scope);
|
|
196
206
|
|
|
197
207
|
this.getChildren = childrenState.getChildren;
|
|
208
|
+
this.attributeState = attributeState;
|
|
198
209
|
|
|
199
210
|
const stateSpec: PrimaryInstanceStateSpec = {
|
|
200
211
|
activeLanguage: getActiveLanguage,
|
|
@@ -207,6 +218,7 @@ export class PrimaryInstance<
|
|
|
207
218
|
valueOptions: null,
|
|
208
219
|
value: null,
|
|
209
220
|
children: childrenState.childIds,
|
|
221
|
+
attributes: attributeState.getAttributes,
|
|
210
222
|
};
|
|
211
223
|
|
|
212
224
|
const state = createSharedNodeState(scope, stateSpec, config);
|
|
@@ -227,6 +239,7 @@ export class PrimaryInstance<
|
|
|
227
239
|
this.instanceState = createPrimaryInstanceState(this);
|
|
228
240
|
|
|
229
241
|
childrenState.setChildren([root]);
|
|
242
|
+
attributeState.setAttributes(buildAttributes(this));
|
|
230
243
|
setIsAttached(true);
|
|
231
244
|
}
|
|
232
245
|
|
|
@@ -279,4 +292,8 @@ export class PrimaryInstance<
|
|
|
279
292
|
|
|
280
293
|
return Promise.resolve(result);
|
|
281
294
|
}
|
|
295
|
+
|
|
296
|
+
getAttributes(): readonly Attribute[] {
|
|
297
|
+
return this.attributeState.getAttributes();
|
|
298
|
+
}
|
|
282
299
|
}
|