@getodk/xforms-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/.vite/manifest.json +7 -0
- package/dist/XFormDOM.d.ts +31 -0
- package/dist/XFormDataType.d.ts +26 -0
- package/dist/XFormDefinition.d.ts +14 -0
- package/dist/body/BodyDefinition.d.ts +52 -0
- package/dist/body/BodyElementDefinition.d.ts +32 -0
- package/dist/body/RepeatDefinition.d.ts +15 -0
- package/dist/body/UnsupportedBodyElementDefinition.d.ts +10 -0
- package/dist/body/control/ControlDefinition.d.ts +16 -0
- package/dist/body/control/InputDefinition.d.ts +5 -0
- package/dist/body/control/select/ItemDefinition.d.ts +13 -0
- package/dist/body/control/select/ItemsetDefinition.d.ts +16 -0
- package/dist/body/control/select/ItemsetNodesetContext.d.ts +11 -0
- package/dist/body/control/select/ItemsetNodesetExpression.d.ts +5 -0
- package/dist/body/control/select/ItemsetValueExpression.d.ts +6 -0
- package/dist/body/control/select/SelectDefinition.d.ts +23 -0
- package/dist/body/group/BaseGroupDefinition.d.ts +46 -0
- package/dist/body/group/LogicalGroupDefinition.d.ts +6 -0
- package/dist/body/group/PresentationGroupDefinition.d.ts +11 -0
- package/dist/body/group/RepeatGroupDefinition.d.ts +12 -0
- package/dist/body/group/StructuralGroupDefinition.d.ts +6 -0
- package/dist/body/text/HintDefinition.d.ts +11 -0
- package/dist/body/text/LabelDefinition.d.ts +20 -0
- package/dist/body/text/TextElementDefinition.d.ts +32 -0
- package/dist/body/text/TextElementOutputPart.d.ts +12 -0
- package/dist/body/text/TextElementPart.d.ts +12 -0
- package/dist/body/text/TextElementReferencePart.d.ts +6 -0
- package/dist/body/text/TextElementStaticPart.d.ts +6 -0
- package/dist/client/BaseNode.d.ts +138 -0
- package/dist/client/EngineConfig.d.ts +78 -0
- package/dist/client/FormLanguage.d.ts +63 -0
- package/dist/client/GroupNode.d.ts +24 -0
- package/dist/client/OpaqueReactiveObjectFactory.d.ts +70 -0
- package/dist/client/RepeatInstanceNode.d.ts +28 -0
- package/dist/client/RepeatRangeNode.d.ts +94 -0
- package/dist/client/RootNode.d.ts +31 -0
- package/dist/client/SelectNode.d.ts +60 -0
- package/dist/client/StringNode.d.ts +41 -0
- package/dist/client/SubtreeNode.d.ts +52 -0
- package/dist/client/TextRange.d.ts +55 -0
- package/dist/client/hierarchy.d.ts +48 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/node-types.d.ts +1 -0
- package/dist/expression/DependencyContext.d.ts +12 -0
- package/dist/expression/DependentExpression.d.ts +43 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +37622 -0
- package/dist/index.js.map +1 -0
- package/dist/instance/Group.d.ts +31 -0
- package/dist/instance/RepeatInstance.d.ts +60 -0
- package/dist/instance/RepeatRange.d.ts +81 -0
- package/dist/instance/Root.d.ts +70 -0
- package/dist/instance/SelectField.d.ts +45 -0
- package/dist/instance/StringField.d.ts +39 -0
- package/dist/instance/Subtree.d.ts +30 -0
- package/dist/instance/abstract/DescendantNode.d.ts +76 -0
- package/dist/instance/abstract/InstanceNode.d.ts +107 -0
- package/dist/instance/children.d.ts +2 -0
- package/dist/instance/hierarchy.d.ts +12 -0
- package/dist/instance/identity.d.ts +7 -0
- package/dist/instance/index.d.ts +8 -0
- package/dist/instance/internal-api/EvaluationContext.d.ts +34 -0
- package/dist/instance/internal-api/InstanceConfig.d.ts +8 -0
- package/dist/instance/internal-api/SubscribableDependency.d.ts +59 -0
- package/dist/instance/internal-api/TranslationContext.d.ts +4 -0
- package/dist/instance/internal-api/ValueContext.d.ts +22 -0
- package/dist/instance/resource.d.ts +10 -0
- package/dist/instance/text/FormattedTextStub.d.ts +1 -0
- package/dist/instance/text/TextChunk.d.ts +11 -0
- package/dist/instance/text/TextRange.d.ts +10 -0
- package/dist/lib/dom/query.d.ts +20 -0
- package/dist/lib/reactivity/createChildrenState.d.ts +36 -0
- package/dist/lib/reactivity/createComputedExpression.d.ts +12 -0
- package/dist/lib/reactivity/createSelectItems.d.ts +16 -0
- package/dist/lib/reactivity/createValueState.d.ts +44 -0
- package/dist/lib/reactivity/materializeCurrentStateChildren.d.ts +18 -0
- package/dist/lib/reactivity/node-state/createClientState.d.ts +9 -0
- package/dist/lib/reactivity/node-state/createCurrentState.d.ts +6 -0
- package/dist/lib/reactivity/node-state/createEngineState.d.ts +5 -0
- package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +22 -0
- package/dist/lib/reactivity/node-state/createSpecifiedPropertyDescriptor.d.ts +6 -0
- package/dist/lib/reactivity/node-state/createSpecifiedState.d.ts +139 -0
- package/dist/lib/reactivity/node-state/representations.d.ts +25 -0
- package/dist/lib/reactivity/scope.d.ts +23 -0
- package/dist/lib/reactivity/text/createFieldHint.d.ts +5 -0
- package/dist/lib/reactivity/text/createNodeLabel.d.ts +5 -0
- package/dist/lib/reactivity/text/createTextRange.d.ts +19 -0
- package/dist/lib/reactivity/types.d.ts +21 -0
- package/dist/lib/unique-id.d.ts +27 -0
- package/dist/lib/xpath/analysis.d.ts +22 -0
- package/dist/model/BindComputation.d.ts +30 -0
- package/dist/model/BindDefinition.d.ts +31 -0
- package/dist/model/BindElement.d.ts +6 -0
- package/dist/model/DescendentNodeDefinition.d.ts +25 -0
- package/dist/model/ModelBindMap.d.ts +15 -0
- package/dist/model/ModelDefinition.d.ts +10 -0
- package/dist/model/NodeDefinition.d.ts +74 -0
- package/dist/model/RepeatInstanceDefinition.d.ts +15 -0
- package/dist/model/RepeatSequenceDefinition.d.ts +19 -0
- package/dist/model/RepeatTemplateDefinition.d.ts +29 -0
- package/dist/model/RootDefinition.d.ts +24 -0
- package/dist/model/SubtreeDefinition.d.ts +14 -0
- package/dist/model/ValueNodeDefinition.d.ts +15 -0
- package/dist/solid.js +37273 -0
- package/dist/solid.js.map +1 -0
- package/package.json +87 -0
- package/src/XFormDOM.ts +224 -0
- package/src/XFormDataType.ts +64 -0
- package/src/XFormDefinition.ts +40 -0
- package/src/body/BodyDefinition.ts +202 -0
- package/src/body/BodyElementDefinition.ts +62 -0
- package/src/body/RepeatDefinition.ts +54 -0
- package/src/body/UnsupportedBodyElementDefinition.ts +17 -0
- package/src/body/control/ControlDefinition.ts +42 -0
- package/src/body/control/InputDefinition.ts +9 -0
- package/src/body/control/select/ItemDefinition.ts +31 -0
- package/src/body/control/select/ItemsetDefinition.ts +36 -0
- package/src/body/control/select/ItemsetNodesetContext.ts +26 -0
- package/src/body/control/select/ItemsetNodesetExpression.ts +8 -0
- package/src/body/control/select/ItemsetValueExpression.ts +11 -0
- package/src/body/control/select/SelectDefinition.ts +74 -0
- package/src/body/group/BaseGroupDefinition.ts +137 -0
- package/src/body/group/LogicalGroupDefinition.ts +11 -0
- package/src/body/group/PresentationGroupDefinition.ts +28 -0
- package/src/body/group/RepeatGroupDefinition.ts +91 -0
- package/src/body/group/StructuralGroupDefinition.ts +11 -0
- package/src/body/text/HintDefinition.ts +26 -0
- package/src/body/text/LabelDefinition.ts +54 -0
- package/src/body/text/TextElementDefinition.ts +97 -0
- package/src/body/text/TextElementOutputPart.ts +27 -0
- package/src/body/text/TextElementPart.ts +31 -0
- package/src/body/text/TextElementReferencePart.ts +21 -0
- package/src/body/text/TextElementStaticPart.ts +26 -0
- package/src/client/BaseNode.ts +180 -0
- package/src/client/EngineConfig.ts +83 -0
- package/src/client/FormLanguage.ts +77 -0
- package/src/client/GroupNode.ts +33 -0
- package/src/client/OpaqueReactiveObjectFactory.ts +100 -0
- package/src/client/README.md +39 -0
- package/src/client/RepeatInstanceNode.ts +41 -0
- package/src/client/RepeatRangeNode.ts +100 -0
- package/src/client/RootNode.ts +36 -0
- package/src/client/SelectNode.ts +69 -0
- package/src/client/StringNode.ts +46 -0
- package/src/client/SubtreeNode.ts +57 -0
- package/src/client/TextRange.ts +63 -0
- package/src/client/hierarchy.ts +63 -0
- package/src/client/index.ts +29 -0
- package/src/client/node-types.ts +10 -0
- package/src/expression/DependencyContext.ts +53 -0
- package/src/expression/DependentExpression.ts +102 -0
- package/src/index.ts +35 -0
- package/src/instance/Group.ts +82 -0
- package/src/instance/RepeatInstance.ts +164 -0
- package/src/instance/RepeatRange.ts +214 -0
- package/src/instance/Root.ts +264 -0
- package/src/instance/SelectField.ts +204 -0
- package/src/instance/StringField.ts +93 -0
- package/src/instance/Subtree.ts +79 -0
- package/src/instance/abstract/DescendantNode.ts +182 -0
- package/src/instance/abstract/InstanceNode.ts +257 -0
- package/src/instance/children.ts +52 -0
- package/src/instance/hierarchy.ts +54 -0
- package/src/instance/identity.ts +11 -0
- package/src/instance/index.ts +37 -0
- package/src/instance/internal-api/EvaluationContext.ts +41 -0
- package/src/instance/internal-api/InstanceConfig.ts +9 -0
- package/src/instance/internal-api/SubscribableDependency.ts +61 -0
- package/src/instance/internal-api/TranslationContext.ts +5 -0
- package/src/instance/internal-api/ValueContext.ts +27 -0
- package/src/instance/resource.ts +75 -0
- package/src/instance/text/FormattedTextStub.ts +8 -0
- package/src/instance/text/TextChunk.ts +20 -0
- package/src/instance/text/TextRange.ts +23 -0
- package/src/lib/dom/query.ts +49 -0
- package/src/lib/reactivity/createChildrenState.ts +60 -0
- package/src/lib/reactivity/createComputedExpression.ts +114 -0
- package/src/lib/reactivity/createSelectItems.ts +163 -0
- package/src/lib/reactivity/createValueState.ts +258 -0
- package/src/lib/reactivity/materializeCurrentStateChildren.ts +121 -0
- package/src/lib/reactivity/node-state/createClientState.ts +51 -0
- package/src/lib/reactivity/node-state/createCurrentState.ts +27 -0
- package/src/lib/reactivity/node-state/createEngineState.ts +18 -0
- package/src/lib/reactivity/node-state/createSharedNodeState.ts +79 -0
- package/src/lib/reactivity/node-state/createSpecifiedPropertyDescriptor.ts +85 -0
- package/src/lib/reactivity/node-state/createSpecifiedState.ts +229 -0
- package/src/lib/reactivity/node-state/representations.ts +64 -0
- package/src/lib/reactivity/scope.ts +106 -0
- package/src/lib/reactivity/text/createFieldHint.ts +16 -0
- package/src/lib/reactivity/text/createNodeLabel.ts +16 -0
- package/src/lib/reactivity/text/createTextRange.ts +155 -0
- package/src/lib/reactivity/types.ts +27 -0
- package/src/lib/unique-id.ts +34 -0
- package/src/lib/xpath/analysis.ts +241 -0
- package/src/model/BindComputation.ts +88 -0
- package/src/model/BindDefinition.ts +104 -0
- package/src/model/BindElement.ts +8 -0
- package/src/model/DescendentNodeDefinition.ts +56 -0
- package/src/model/ModelBindMap.ts +71 -0
- package/src/model/ModelDefinition.ts +19 -0
- package/src/model/NodeDefinition.ts +146 -0
- package/src/model/RepeatInstanceDefinition.ts +39 -0
- package/src/model/RepeatSequenceDefinition.ts +53 -0
- package/src/model/RepeatTemplateDefinition.ts +150 -0
- package/src/model/RootDefinition.ts +121 -0
- package/src/model/SubtreeDefinition.ts +50 -0
- package/src/model/ValueNodeDefinition.ts +39 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { DefineMutableObject } from '../../test/helpers/reactive/internal.ts';
|
|
2
|
+
|
|
3
|
+
// This type is intended to satisfy two goals, each corresponding to the order
|
|
4
|
+
// of the call signatures within the type:
|
|
5
|
+
//
|
|
6
|
+
// 1. Ensure that **general** compatible interfaces are assignable.
|
|
7
|
+
// 2. Ensure that **specific** call sites correctly infer their return type.
|
|
8
|
+
//
|
|
9
|
+
// It does **not** currently satisfy another goal it was originally intended to
|
|
10
|
+
// address: ensure that attempts to assign a function fail when the function
|
|
11
|
+
// **does not** accept an object. The remnants of this attempt are intentionally
|
|
12
|
+
// left here in case we want to try simplifying and clarifying these types
|
|
13
|
+
// further, in a future effort.
|
|
14
|
+
//
|
|
15
|
+
// It also does **not** currently make a difference to:
|
|
16
|
+
//
|
|
17
|
+
// - specify `in out` as is currently specified
|
|
18
|
+
// - specify distinct `in` and `in out` type parameters
|
|
19
|
+
//
|
|
20
|
+
// These TypeScript keywords are intended to allow greater control over the
|
|
21
|
+
// variance of type parameters in function argument/return type positions. It
|
|
22
|
+
// was thought that they might aid in relaxing assignability for Vue's `reactive`,
|
|
23
|
+
// but that didn't pan out (within the timebox allotted thus far). This, too, is
|
|
24
|
+
// left as a remnant in case we want to revisit this in the future.
|
|
25
|
+
interface BaseOpaqueReactiveObjectFactory<in out Input extends object = object> {
|
|
26
|
+
<T extends Input>(object: T): T;
|
|
27
|
+
<T extends object>(object: T): T;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A client-provided reactivity factory. We assume little about the mechanism
|
|
32
|
+
* of reactivity a client provides (and a client may opt to provide no reactive
|
|
33
|
+
* mechanism at all, if it will consume state changes by other means). From an
|
|
34
|
+
* API perspective, the expectation is:
|
|
35
|
+
*
|
|
36
|
+
* - The factory accepts a single argument, which **MUST** be an object.
|
|
37
|
+
* Reactive primitive values are unsupported by this interface.
|
|
38
|
+
* - The factory **MUST** return an object of the same shape (i.e. it must
|
|
39
|
+
* have the same property key/value pairs).
|
|
40
|
+
* - The factory's return object **MUST** be mutable by the web-forms engine.
|
|
41
|
+
* - The web-forms engine **WILL** propagate changes to state as they occur,
|
|
42
|
+
* by mutating properties of the object corresponding to those aspects of
|
|
43
|
+
* state.
|
|
44
|
+
* - The client **MAY** read any property of the factory's returned object.
|
|
45
|
+
* - Because the client's reactivity mechanism (if any) is unknown, it is
|
|
46
|
+
* **ASSUMED** that the engine's mutations are observable by the client,
|
|
47
|
+
* and that the client has a defined means to subscribe to those mutations.
|
|
48
|
+
* It is **IMPLIED** (but **NOT REQUIRED**) that the typical reactive client
|
|
49
|
+
* will subscribe to mutations by reading the pertinent properties of the
|
|
50
|
+
* reactive object in a reactive context appropriate for that client.
|
|
51
|
+
* - In common usage, the engine **MAY** convey computed getter property types
|
|
52
|
+
* back to the client, to indicate that certain aspects the engine mutates
|
|
53
|
+
* are read-only to the client (even if they are mutable by the engine).
|
|
54
|
+
*
|
|
55
|
+
* Real world examples of reactive implementations include:
|
|
56
|
+
*
|
|
57
|
+
* - {@link https://vuejs.org/api/reactivity-core.html#reactive | `reactive` (Vue)}
|
|
58
|
+
* - {@link https://docs.solidjs.com/reference/store-utilities/create-mutable | `createMutable` (Solid)}
|
|
59
|
+
* - {@link DefineMutableObject | our internal `mutable` test helper}
|
|
60
|
+
*
|
|
61
|
+
* Each of these implementations are targeted as part of our effort to ensure
|
|
62
|
+
* the `xforms-engine` is agnostic to a client's framework and/or implementation
|
|
63
|
+
* of state.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* declare const clientFactory: OpaqueReactiveObjectFactory;
|
|
69
|
+
*
|
|
70
|
+
* interface ClientFoo {
|
|
71
|
+
* get bar(): string;
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* interface MutableFoo {
|
|
75
|
+
* bar: string;
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* // State internally updated by engine
|
|
79
|
+
* let mutableFoo = clientFactory<MutableFoo>({ bar: 'bat' });
|
|
80
|
+
*
|
|
81
|
+
* // Same state, consumed by the client as computed but read-only
|
|
82
|
+
* let clientFoo: ClientFoo = engineFoo;
|
|
83
|
+
*
|
|
84
|
+
* // Client: subscribe to mutations by the engine
|
|
85
|
+
* reactiveContext(() => {
|
|
86
|
+
* // Implied client subscription to `clientFoo.bar` on property access
|
|
87
|
+
* doSomethingWith(clientFoo.bar);
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Engine: mutate values to convey state changes to subscribed client
|
|
91
|
+
* engineFoo.bar = 'quux';
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
// prettier-ignore
|
|
95
|
+
export type OpaqueReactiveObjectFactory<Input extends object = object> =
|
|
96
|
+
// Possibly a TypeScript bug? The order of this intersection matters! Changing
|
|
97
|
+
// the order causes types in `createClientState.ts` to fail inexplicably.
|
|
98
|
+
& BaseOpaqueReactiveObjectFactory<Input>
|
|
99
|
+
& ((object: object) => unknown)
|
|
100
|
+
;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @getodk/xforms-engine: Client interface
|
|
2
|
+
|
|
3
|
+
The modules in this directory define the explicit interface between:
|
|
4
|
+
|
|
5
|
+
- an ODK Web Forms client (typically, but not necessarily, providing a user interface), henceforth "client"; and,
|
|
6
|
+
- `@getodk/xforms-engine`; henceforth "the engine"
|
|
7
|
+
|
|
8
|
+
The interface is defined as TypeScript type definitions, with a work-in-progress effort to provide browsable documentation of the same.
|
|
9
|
+
|
|
10
|
+
## Purpose
|
|
11
|
+
|
|
12
|
+
The interface is designed to:
|
|
13
|
+
|
|
14
|
+
- Provide a means for clients to initiate an [ODK XForm](https://getodk.github.io/xforms-spec/)
|
|
15
|
+
- Convey the structure of the form as a tree, _roughly analogous_ in structure to its [primary instance](https://getodk.github.io/xforms-spec/#primary-instance) model
|
|
16
|
+
- Convey definitional aspects of for each of the form's nodes, from which clients may implement particular modes of presentation and user interaction
|
|
17
|
+
- Convey the current state, at any given time, of each node in that tree
|
|
18
|
+
- Provide explicit mechanisms for clients to manipulate pertinent aspects of that state
|
|
19
|
+
- Facilitate propagation of state updates to clients as and where they occur throughout that tree, by means of a client-provided generic state factory[^1]
|
|
20
|
+
- Facilitate loading any of a form's externally referenced resources, by means of a client-provided generic resource accessor[^2]
|
|
21
|
+
|
|
22
|
+
[^1]: This factory **may be** reactive, and for many clients that is the anticipated usage. But no assumptions are made by the engine about reactivity or any other implementation details beyond the factory's type definition.
|
|
23
|
+
[^2]: This accessor **may** access networked resources, and for many clients that is the anticipated usage. But no assumptions are made by the engine about the provenance of any resources it requests beyond the accessor's type definition.
|
|
24
|
+
|
|
25
|
+
### Non-goals
|
|
26
|
+
|
|
27
|
+
The interface is explicitly **not designed** to proscribe any particular mode of presentation or user interaction. Furthermore, it does not specify or mandate:
|
|
28
|
+
|
|
29
|
+
- Any particular reactive behavior, or implementation of reactivity generally
|
|
30
|
+
- Access to any network or other resource store per se, beyond the means to load and execute the engine itself in a compatible runtime environment
|
|
31
|
+
|
|
32
|
+
## Notes on interface contract and stability
|
|
33
|
+
|
|
34
|
+
> [!IMPORTANT]
|
|
35
|
+
> The interface in this directory represents the **complete contract** between a client and the engine. The engine _may_ expose an implementation which exceeds this explicit contract; clients are **strongly discouraged** from depending on details not exposed by the interface itself, as they are considered implementation details subject to change at any time.
|
|
36
|
+
|
|
37
|
+
The general design and approach to this interface has gone through several iterations. The types defined _within this directory_ are expected to be fairly stable, apart from additive changes to support coming feature work.
|
|
38
|
+
|
|
39
|
+
Any types referenced _outside this directory_ should be treated as at least moderately unstable; these types are generally concerned with static aspects of a parsed form (typically referenced as a `definition`). We **will** be revisiting and refining these types as early client work proceeds, and are quite likely to introduce more limited client-facing types much like those within this directory to take their place.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RepeatInstanceDefinition } from '../model/RepeatInstanceDefinition.ts';
|
|
2
|
+
import type { RepeatTemplateDefinition } from '../model/RepeatTemplateDefinition.ts';
|
|
3
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
4
|
+
import type { RepeatRangeNode } from './RepeatRangeNode.ts';
|
|
5
|
+
import type { RootNode } from './RootNode.ts';
|
|
6
|
+
import type { GeneralChildNode } from './hierarchy.ts';
|
|
7
|
+
|
|
8
|
+
export interface RepeatInstanceNodeState extends BaseNodeState {
|
|
9
|
+
// TODO(?): Previous iteration included an `index` getter here. I don't see it
|
|
10
|
+
// accessed by the current (Solid) client, and I don't know that it really has
|
|
11
|
+
// any use to a client that wouldn't be satisfied by accessing the same index
|
|
12
|
+
// while iterating the parent range's children.
|
|
13
|
+
|
|
14
|
+
get hint(): null;
|
|
15
|
+
get children(): readonly GeneralChildNode[];
|
|
16
|
+
get valueOptions(): null;
|
|
17
|
+
get value(): null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// prettier-ignore
|
|
21
|
+
export type RepeatDefinition =
|
|
22
|
+
| RepeatInstanceDefinition
|
|
23
|
+
| RepeatTemplateDefinition;
|
|
24
|
+
|
|
25
|
+
export interface RepeatInstanceNode extends BaseNode {
|
|
26
|
+
readonly nodeType: 'repeat-instance';
|
|
27
|
+
readonly definition: RepeatDefinition;
|
|
28
|
+
readonly root: RootNode;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A repeat instance may only be a child of a {@link RepeatRangeNode}.
|
|
32
|
+
*
|
|
33
|
+
* Note: the web-forms engine's representation of this structure differs from
|
|
34
|
+
* the underlying XForms specification's primary instance structure.
|
|
35
|
+
*
|
|
36
|
+
* @see {@link RepeatRangeNode} for additional detail.
|
|
37
|
+
*/
|
|
38
|
+
readonly parent: RepeatRangeNode;
|
|
39
|
+
|
|
40
|
+
readonly currentState: RepeatInstanceNodeState;
|
|
41
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { RepeatSequenceDefinition } from '../model/RepeatSequenceDefinition.ts';
|
|
2
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
3
|
+
import type { RepeatInstanceNode } from './RepeatInstanceNode.ts';
|
|
4
|
+
import type { RootNode } from './RootNode.ts';
|
|
5
|
+
import type { TextRange } from './TextRange.ts';
|
|
6
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
7
|
+
|
|
8
|
+
export interface RepeatRangeNodeState extends BaseNodeState {
|
|
9
|
+
get hint(): null;
|
|
10
|
+
get label(): TextRange<'label'> | null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A repeat range's children may only be {@link RepeatInstanceNode}s.
|
|
14
|
+
*
|
|
15
|
+
* Note: the web-forms engine's representation of this structure differs from
|
|
16
|
+
* the underlying XForms specification's primary instance structure.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link RepeatRangeNode} for additional detail.
|
|
19
|
+
*/
|
|
20
|
+
get children(): readonly RepeatInstanceNode[];
|
|
21
|
+
|
|
22
|
+
get valueOptions(): null;
|
|
23
|
+
get value(): null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Represents a contiguous set of zero or more {@link RepeatInstanceNode}s
|
|
28
|
+
* (accessed by its
|
|
29
|
+
* {@link RepeatRangeNodeState.children | `currentState.children`}).
|
|
30
|
+
*
|
|
31
|
+
* This structure is modeled as a node, like any other, in the web-forms engine
|
|
32
|
+
* representation, which notably differs from the corresponding structure in the
|
|
33
|
+
* underlying ODK XForms specification's primary instance state.
|
|
34
|
+
*
|
|
35
|
+
* _Conceptually_, it more closely corresponds to the concept of a set of
|
|
36
|
+
* repeats as defined by a `<repeat>` element in the XForms body. Whereas its
|
|
37
|
+
* {@link RepeatInstanceNode} children, if any, correspond directly to the
|
|
38
|
+
* XForms primary instance's state.
|
|
39
|
+
*
|
|
40
|
+
* More precisely, clients should be advised that the presentation aspect of a
|
|
41
|
+
* `RepeatRangeNode` corresponds to a pair of
|
|
42
|
+
* {@link https://getodk.github.io/xforms-spec/#body-elements | `<group>` and `<repeat>` body elements}
|
|
43
|
+
* referencing the same nodeset. (Forms which define a repeat without a
|
|
44
|
+
* corresponding group are semantically equivalent to those with this
|
|
45
|
+
* group/repeat pair. The web-forms engine model simplifies this by producing
|
|
46
|
+
* the same runtime structure for either case.)
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
*
|
|
50
|
+
* To illustrate the structural divergence from the underlying XForms concepts,
|
|
51
|
+
* consider this (abridged) XForm definition:
|
|
52
|
+
*
|
|
53
|
+
* ```xml
|
|
54
|
+
* <!-- /h:html/h:head/model -->
|
|
55
|
+
* <instance>
|
|
56
|
+
* <data>
|
|
57
|
+
* <rep />
|
|
58
|
+
* </data>
|
|
59
|
+
* </instance>
|
|
60
|
+
* <!-- /h:html/h:body -->
|
|
61
|
+
* <repeat nodeset="/data/rep" />
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* The engine's representation maps to that structure roughly like:
|
|
65
|
+
*
|
|
66
|
+
* ```xml
|
|
67
|
+
* <!-- /h:html/h:head/model -->
|
|
68
|
+
* <instance>
|
|
69
|
+
* <data>
|
|
70
|
+
* <!-- RepeatRangeNode(/data/rep).currentState.children: [ -->
|
|
71
|
+
* <!-- RepeatInstanceNode(/data/rep[1]): --> <rep />
|
|
72
|
+
* <!-- RepeatInstanceNode(/data/rep[2]): --> <rep />
|
|
73
|
+
* <!-- ... -->
|
|
74
|
+
* <!-- ] -->
|
|
75
|
+
* </data>
|
|
76
|
+
* </instance>
|
|
77
|
+
* <!-- /h:html/h:body -->
|
|
78
|
+
* <!-- RepeatRangeNode(/data/rep).definition: { ... -->
|
|
79
|
+
* <group ref="/data/rep">
|
|
80
|
+
* <repeat nodeset="/data/rep" />
|
|
81
|
+
* </group>
|
|
82
|
+
* <!-- } -->
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* Importantly, if the state of a given repeat range has no instances, no aspect
|
|
86
|
+
* of these repeats will be present in the underlying XForms primary instance
|
|
87
|
+
* state, but the web-forms engine's representations **retains a reference** to
|
|
88
|
+
* its {@link RepeatRangeNode}.
|
|
89
|
+
*/
|
|
90
|
+
export interface RepeatRangeNode extends BaseNode {
|
|
91
|
+
readonly nodeType: 'repeat-range';
|
|
92
|
+
readonly definition: RepeatSequenceDefinition;
|
|
93
|
+
readonly root: RootNode;
|
|
94
|
+
readonly parent: GeneralParentNode;
|
|
95
|
+
readonly currentState: RepeatRangeNodeState;
|
|
96
|
+
|
|
97
|
+
addInstances(afterIndex?: number, count?: number): RootNode;
|
|
98
|
+
|
|
99
|
+
removeInstances(startIndex: number, count?: number): RootNode;
|
|
100
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RootDefinition } from '../model/RootDefinition.ts';
|
|
2
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
3
|
+
import type { ActiveLanguage, FormLanguage, FormLanguages } from './FormLanguage.ts';
|
|
4
|
+
import type { GeneralChildNode } from './hierarchy.ts';
|
|
5
|
+
|
|
6
|
+
export interface RootNodeState extends BaseNodeState {
|
|
7
|
+
/**
|
|
8
|
+
* This, along with {@link RootNode.languages} is the most significant break
|
|
9
|
+
in consistency across node types' state and static properties. Exposing it
|
|
10
|
+
across all node types seems like a point of potential confusion, so this
|
|
11
|
+
particular divergence seems like the most reasonable compromise.
|
|
12
|
+
*/
|
|
13
|
+
get activeLanguage(): ActiveLanguage;
|
|
14
|
+
|
|
15
|
+
get label(): null;
|
|
16
|
+
get hint(): null;
|
|
17
|
+
get children(): readonly GeneralChildNode[];
|
|
18
|
+
get valueOptions(): null;
|
|
19
|
+
get value(): null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RootNode extends BaseNode {
|
|
23
|
+
readonly nodeType: 'root';
|
|
24
|
+
readonly definition: RootDefinition;
|
|
25
|
+
readonly root: RootNode;
|
|
26
|
+
readonly parent: null;
|
|
27
|
+
readonly currentState: RootNodeState;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @todo as with {@link RootNodeState.activeLanguage}, this is the most
|
|
31
|
+
* significant break in consistency across node types.
|
|
32
|
+
*/
|
|
33
|
+
readonly languages: FormLanguages;
|
|
34
|
+
|
|
35
|
+
setLanguage(language: FormLanguage): RootNode;
|
|
36
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { AnySelectDefinition } from '../body/control/select/SelectDefinition.ts';
|
|
2
|
+
import type { ValueNodeDefinition } from '../model/ValueNodeDefinition.ts';
|
|
3
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
4
|
+
import type { RootNode } from './RootNode.ts';
|
|
5
|
+
import type { StringNode } from './StringNode.ts';
|
|
6
|
+
import type { TextRange } from './TextRange.ts';
|
|
7
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
8
|
+
|
|
9
|
+
export interface SelectItem {
|
|
10
|
+
get value(): string;
|
|
11
|
+
get label(): TextRange<'label'> | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SelectNodeState extends BaseNodeState {
|
|
15
|
+
get children(): null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @todo should {@link BaseNodeState} include this??
|
|
19
|
+
*/
|
|
20
|
+
get valueOptions(): readonly SelectItem[];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* This value is treated as set-like by the engine, where each
|
|
24
|
+
* {@link SelectItem.value | item's `value`} may occur once (at most), and:
|
|
25
|
+
*
|
|
26
|
+
* - Fields defined with an XForms `<select>` may contain multiple items
|
|
27
|
+
* - Fields defined with an XForms `<select1>` will always produce one item
|
|
28
|
+
* (at most)
|
|
29
|
+
*
|
|
30
|
+
* @todo Maybe it makes more sense for the client interface to break these up!
|
|
31
|
+
* Should a `SelectNodeState` have this `value` type, whereas a hypothetical
|
|
32
|
+
* `Select1NodeState` would have `get value(): SelectItem | null`?
|
|
33
|
+
*/
|
|
34
|
+
get value(): readonly SelectItem[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SelectDefinition extends ValueNodeDefinition {
|
|
38
|
+
readonly bodyElement: AnySelectDefinition;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SelectNode extends BaseNode {
|
|
42
|
+
readonly nodeType: 'select';
|
|
43
|
+
readonly definition: SelectDefinition;
|
|
44
|
+
readonly root: RootNode;
|
|
45
|
+
readonly parent: GeneralParentNode;
|
|
46
|
+
readonly currentState: SelectNodeState;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* For use by a client to update the selection of a select node where:
|
|
50
|
+
*
|
|
51
|
+
* - For fields defined with an XForms `<select>`, calling this method is
|
|
52
|
+
* additive, i.e. it will include the item in its
|
|
53
|
+
* {@link SelectNodeState.value}.
|
|
54
|
+
* - For fields defined with an XForms `<select1>`, calling this method will
|
|
55
|
+
* replace the selection (if any).
|
|
56
|
+
*
|
|
57
|
+
* @todo @see {@link StringNode.setValue} re: write restrictions
|
|
58
|
+
* @todo @see {@link SelectNodeState.value} re: breaking up the types
|
|
59
|
+
*/
|
|
60
|
+
select(item: SelectItem): RootNode;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* For use by a client to remove an item from the node's
|
|
64
|
+
* {@link SelectNodeState.value}.
|
|
65
|
+
*
|
|
66
|
+
* @todo @see {@link StringNode.setValue} re: write restrictions
|
|
67
|
+
*/
|
|
68
|
+
deselect(item: SelectItem): RootNode;
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { InputDefinition } from '../body/control/InputDefinition.ts';
|
|
2
|
+
import type { ValueNodeDefinition } from '../model/ValueNodeDefinition.ts';
|
|
3
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
4
|
+
import type { RootNode } from './RootNode.ts';
|
|
5
|
+
import type { GeneralParentNode } from './hierarchy.ts';
|
|
6
|
+
|
|
7
|
+
export interface StringNodeState extends BaseNodeState {
|
|
8
|
+
get children(): null;
|
|
9
|
+
get valueOptions(): null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reflects the current value of a {@link StringNode}. This value may be
|
|
13
|
+
* populated when a form is loaded, and it may be updated by certain
|
|
14
|
+
* computations defined by the form. It may also be updated by a client, using
|
|
15
|
+
* the {@link StringNode.setValue} method.
|
|
16
|
+
*/
|
|
17
|
+
get value(): string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface StringDefinition extends ValueNodeDefinition {
|
|
21
|
+
readonly bodyElement: InputDefinition | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A node which can be assigned a string/text value. A string node **MAY**
|
|
26
|
+
* correspond to form field defined as an XForms `<input>`, which a user-facing
|
|
27
|
+
* client would likely present for a user to fill. It may not correspond to an
|
|
28
|
+
* `<input>`, or necessarily have any presentational implications for a client
|
|
29
|
+
* (for instance if the node is bound to an XForms `calculate` expression).
|
|
30
|
+
*/
|
|
31
|
+
export interface StringNode extends BaseNode {
|
|
32
|
+
readonly nodeType: 'string';
|
|
33
|
+
readonly definition: StringDefinition;
|
|
34
|
+
readonly root: RootNode;
|
|
35
|
+
readonly parent: GeneralParentNode;
|
|
36
|
+
readonly currentState: StringNodeState;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* For use by a client to update the value of a string node.
|
|
40
|
+
*
|
|
41
|
+
* @todo [how] should we express write restrictions to a client? E.g. what
|
|
42
|
+
* happens when a string node is readonly, and a client attempts to call this
|
|
43
|
+
* method?
|
|
44
|
+
*/
|
|
45
|
+
setValue(value: string): RootNode;
|
|
46
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { SubtreeDefinition as BaseSubtreeDefinition } from '../model/SubtreeDefinition.ts';
|
|
2
|
+
import type { BaseNode, BaseNodeState } from './BaseNode.ts';
|
|
3
|
+
import type { RootNode } from './RootNode.ts';
|
|
4
|
+
import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
|
|
5
|
+
|
|
6
|
+
export interface SubtreeNodeState extends BaseNodeState {
|
|
7
|
+
get label(): null;
|
|
8
|
+
get hint(): null;
|
|
9
|
+
get children(): readonly GeneralChildNode[];
|
|
10
|
+
get valueOptions(): null;
|
|
11
|
+
get value(): null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// TODO: obviously there is a naming inconsistency emerging here.
|
|
15
|
+
export interface SubtreeDefinition extends BaseSubtreeDefinition {
|
|
16
|
+
readonly bodyElement: null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A non-root node which has children, but **no** corresponding XForms
|
|
21
|
+
* `<group>`. A subtree node does not have any direct implications for
|
|
22
|
+
* presentation to users, but its descendants may specify presentational details
|
|
23
|
+
* in their own {@link BaseNode.definition | definition}s.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
*
|
|
27
|
+
* A common `SubtreeNode` case will be a form's `<meta>` element:
|
|
28
|
+
*
|
|
29
|
+
* ```xml
|
|
30
|
+
* <!-- /h:html/h:head/model -->
|
|
31
|
+
* <instance>
|
|
32
|
+
* <data>
|
|
33
|
+
* <some-group>
|
|
34
|
+
* <some-field />
|
|
35
|
+
* </some-group>
|
|
36
|
+
* <!-- Note that `meta` does not have a corresponding group body element -->
|
|
37
|
+
* <!-- SubtreeNode(/data/meta): { ... -->
|
|
38
|
+
* <meta>
|
|
39
|
+
* <instanceID/>
|
|
40
|
+
* </meta>
|
|
41
|
+
* <!-- } -->
|
|
42
|
+
* </data>
|
|
43
|
+
* </instance>
|
|
44
|
+
* <!-- /h:html/h:body -->
|
|
45
|
+
* <group ref="/data/some-group">
|
|
46
|
+
* <input ref="/data/some-group/some-field" />
|
|
47
|
+
* </group>
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
// TODO: directly test presentation of non-group subtree children/descendants
|
|
51
|
+
export interface SubtreeNode extends BaseNode {
|
|
52
|
+
readonly nodeType: 'subtree';
|
|
53
|
+
readonly definition: SubtreeDefinition;
|
|
54
|
+
readonly root: RootNode;
|
|
55
|
+
readonly parent: GeneralParentNode;
|
|
56
|
+
readonly currentState: SubtreeNodeState;
|
|
57
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ActiveLanguage } from './FormLanguage.ts';
|
|
2
|
+
import type { RootNodeState } from './RootNode.ts';
|
|
3
|
+
|
|
4
|
+
export type TextChunkSource = 'itext' | 'output' | 'static';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @todo This (and everything else to do with {@link TextRange}s is for
|
|
8
|
+
* illustration purposes, as a starting point where any particular detail is of
|
|
9
|
+
* unknown utility. We can iterate on all aspects of text ranges in actual
|
|
10
|
+
* clients and refine from there.
|
|
11
|
+
*
|
|
12
|
+
* @see {@link TextRange}
|
|
13
|
+
*/
|
|
14
|
+
export interface TextChunk {
|
|
15
|
+
readonly source: TextChunkSource;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @see {@link ActiveLanguage} for additional commentary
|
|
19
|
+
*/
|
|
20
|
+
get language(): ActiveLanguage;
|
|
21
|
+
|
|
22
|
+
get asString(): string;
|
|
23
|
+
get formatted(): unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Represents aspects of a form which produce text, which _might_ be:
|
|
28
|
+
*
|
|
29
|
+
* - Computed from multiple sources
|
|
30
|
+
* - Capable of conveying certain formatting (which may be presentational and/or
|
|
31
|
+
* structural)
|
|
32
|
+
*
|
|
33
|
+
* Computed text values may be updated by:
|
|
34
|
+
*
|
|
35
|
+
* - Changing a {@link RootNodeState.activeLanguage | form's active language}
|
|
36
|
+
* - Changes to any state referenced by an
|
|
37
|
+
* {@link https://getodk.github.io/xforms-spec/#body-elements | output},
|
|
38
|
+
* within any text-presenting aspect of a form (e.g. labels and hints, as well
|
|
39
|
+
* as itext translations referenced by those)
|
|
40
|
+
*
|
|
41
|
+
* As a client interface, the intent is to convey that this text may be dynamic
|
|
42
|
+
* (and thus potentially reactive for clients supplying a
|
|
43
|
+
* {@link OpaqueReactiveObjectFactory}), and may produce multiple spans of text
|
|
44
|
+
* (or none at all) depending on the structure and state of the form.
|
|
45
|
+
*
|
|
46
|
+
* @todo This interface should be considered **incomplete and in flux**, and
|
|
47
|
+
* subject to change as we evaluate client needs and engine responsibilities. In
|
|
48
|
+
* particular, we've deferred a notion of an interface for formatting aspects,
|
|
49
|
+
* while leaving open the possibility that it may come in future iterations.
|
|
50
|
+
*
|
|
51
|
+
* {@link role} is intended to convey that individual text ranges may be
|
|
52
|
+
* reasoned about differently by clients depending on their role (for instance,
|
|
53
|
+
* a text range's role may correspond to the "short" or "guidance" `form` of a
|
|
54
|
+
* {@link https://getodk.github.io/xforms-spec/#languages | translation}).
|
|
55
|
+
*/
|
|
56
|
+
export interface TextRange<Role extends string | null = null> {
|
|
57
|
+
readonly role: Role;
|
|
58
|
+
|
|
59
|
+
[Symbol.iterator](): Iterable<TextChunk>;
|
|
60
|
+
|
|
61
|
+
get asString(): string;
|
|
62
|
+
get formatted(): unknown;
|
|
63
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ExpandUnion } from '@getodk/common/types/helpers.d.ts';
|
|
2
|
+
import type { GroupNode } from './GroupNode.ts';
|
|
3
|
+
import type { RepeatInstanceNode } from './RepeatInstanceNode.ts';
|
|
4
|
+
import type { RepeatRangeNode } from './RepeatRangeNode.ts';
|
|
5
|
+
import type { RootNode } from './RootNode.ts';
|
|
6
|
+
import type { SelectNode } from './SelectNode.ts';
|
|
7
|
+
import type { StringNode } from './StringNode.ts';
|
|
8
|
+
import type { SubtreeNode } from './SubtreeNode.ts';
|
|
9
|
+
|
|
10
|
+
// prettier-ignore
|
|
11
|
+
export type AnyLeafNode =
|
|
12
|
+
| SelectNode
|
|
13
|
+
| StringNode;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Any of the concrete node types which may be a parent of any other node.
|
|
17
|
+
*
|
|
18
|
+
* This is an intermediate type, which shouldn't be referenced by other concrete
|
|
19
|
+
* node types directly. Instead:
|
|
20
|
+
*
|
|
21
|
+
* - Repeat instances should (continue to) specify {@link RepeatRangeNode}.
|
|
22
|
+
* - All other child nodes should specify {@link GeneralParentNode}.
|
|
23
|
+
*/
|
|
24
|
+
export type AnyParentNode =
|
|
25
|
+
| RootNode // eslint-disable-line @typescript-eslint/sort-type-constituents
|
|
26
|
+
| SubtreeNode
|
|
27
|
+
| GroupNode
|
|
28
|
+
| RepeatRangeNode
|
|
29
|
+
| RepeatInstanceNode;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Any of the concrete node types a client may get from the engine's form
|
|
33
|
+
* representation. This union should be updated when any new concrete node type
|
|
34
|
+
* is added (or when any of the current members is changed/removed).
|
|
35
|
+
*
|
|
36
|
+
* @see {@link GeneralParentNode}, which is derived from this type
|
|
37
|
+
* @see {@link GeneralChildNode}, which is derived from this type
|
|
38
|
+
*/
|
|
39
|
+
export type AnyNode = ExpandUnion<AnyLeafNode | AnyParentNode>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Any of the concrete node types which may be a parent of non-repeat instance
|
|
43
|
+
* child nodes.
|
|
44
|
+
*/
|
|
45
|
+
export type GeneralParentNode = Exclude<AnyParentNode, RepeatRangeNode>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Any of the concrete node types which may be a child of any other node.
|
|
49
|
+
*
|
|
50
|
+
* This is an intermediate type, which shouldn't be referenced by other concrete
|
|
51
|
+
* node types directly. Instead:
|
|
52
|
+
*
|
|
53
|
+
* - Repeat ranges should (continue to) specify {@link RepeatInstanceNode}.
|
|
54
|
+
* - All other parent nodes should specify {@link GeneralChildNode}.
|
|
55
|
+
*/
|
|
56
|
+
// prettier-ignore
|
|
57
|
+
export type AnyChildNode = Exclude<AnyNode, RootNode>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Any of the concrete node types which may be a child of non-repeat range
|
|
61
|
+
* parent nodes.
|
|
62
|
+
*/
|
|
63
|
+
export type GeneralChildNode = Exclude<AnyChildNode, RepeatInstanceNode>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EngineConfig } from './EngineConfig.ts';
|
|
2
|
+
import type { RootNode } from './RootNode.ts';
|
|
3
|
+
|
|
4
|
+
export type FormResource = Blob | URL | string;
|
|
5
|
+
|
|
6
|
+
export interface InitializeFormOptions {
|
|
7
|
+
readonly config: EngineConfig;
|
|
8
|
+
|
|
9
|
+
// E.g. opening a submitted form instance for edit. TDOO: the `FormResource`
|
|
10
|
+
// name is shared here for both init input and initial state, but the shape of
|
|
11
|
+
// those resources would differ. Probably a more generic name is appropriate.
|
|
12
|
+
readonly initialState?: FormResource;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates an instance of a form to be filled (or edited) by a client.
|
|
17
|
+
*/
|
|
18
|
+
// TODO: initialization is represented as asynchronous here, so that any
|
|
19
|
+
// requisite resources can be retrieved before passing control to a client. This
|
|
20
|
+
// is an obvious first step, but we can consider a more complex (if optional)
|
|
21
|
+
// flow, e.g.:
|
|
22
|
+
//
|
|
23
|
+
// - Where it can be determined upfront that the form has no need to perform IO
|
|
24
|
+
// - Where the IO may have already been performed (e.g. offline, other potential
|
|
25
|
+
// caching cases where appropriate)
|
|
26
|
+
export type InitializeForm = (
|
|
27
|
+
input: FormResource,
|
|
28
|
+
options?: InitializeFormOptions
|
|
29
|
+
) => Promise<RootNode>;
|