@getodk/xforms-engine 0.16.1 → 0.17.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/InputNode.d.ts +8 -4
- package/dist/client/MarkdownNode.d.ts +3 -0
- package/dist/client/NoteNode.d.ts +6 -2
- package/dist/client/form/FormInstanceConfig.d.ts +4 -0
- package/dist/client/form/LoadFormResult.d.ts +5 -14
- package/dist/client/form/ResetFormInstance.d.ts +13 -0
- package/dist/entrypoints/FormResult/BaseFormResult.d.ts +1 -0
- package/dist/entrypoints/FormResult/BaseInstantiableFormResult.d.ts +2 -0
- package/dist/entrypoints/FormResult/FormFailureResult.d.ts +2 -0
- package/dist/entrypoints/createPotentiallyClientOwnedReactiveScope.d.ts +19 -0
- package/dist/index.js +21681 -25500
- package/dist/index.js.map +1 -1
- package/dist/instance/PrimaryInstance.d.ts +4 -1
- package/dist/instance/internal-api/AttributeContext.d.ts +1 -0
- package/dist/instance/internal-api/InstanceConfig.d.ts +2 -1
- package/dist/instance/internal-api/InstanceValueContext.d.ts +1 -0
- package/dist/instance/markdown/MarkdownNode.d.ts +14 -9
- package/dist/integration/xpath/static-dom/StaticDocument.d.ts +2 -0
- package/dist/lib/codecs/{Geopoint/Geopoint.d.ts → geolocation/Geolocation.d.ts} +11 -15
- package/dist/lib/codecs/geolocation/Geopoint.d.ts +7 -0
- package/dist/lib/codecs/geolocation/Geoshape.d.ts +7 -0
- package/dist/lib/codecs/geolocation/Geotrace.d.ts +7 -0
- package/dist/lib/codecs/geolocation/createGeolocationValueCodec.d.ts +3 -0
- package/dist/lib/codecs/getSharedValueCodec.d.ts +7 -5
- package/dist/lib/reactivity/text/createTextRange.d.ts +0 -2
- package/dist/parse/XFormDOM.d.ts +7 -1
- package/dist/parse/body/appearance/inputAppearanceParser.d.ts +1 -1
- package/dist/parse/model/ActionDefinition.d.ts +1 -1
- package/dist/parse/model/BindPreloadDefinition.d.ts +2 -1
- package/dist/parse/model/ModelActionMap.d.ts +3 -2
- package/dist/parse/model/ModelDefinition.d.ts +3 -5
- package/dist/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.d.ts +0 -17
- package/dist/parse/model/SecondaryInstance/sources/external-instance-csv-parser.d.ts +8 -0
- package/dist/parse/model/TranslationDefinitionMap.d.ts +4 -0
- package/dist/solid.js +21407 -25226
- package/dist/solid.js.map +1 -1
- package/package.json +2 -2
- package/src/client/InputNode.ts +11 -3
- package/src/client/MarkdownNode.ts +3 -0
- package/src/client/NoteNode.ts +9 -1
- package/src/client/form/FormInstanceConfig.ts +6 -0
- package/src/client/form/LoadFormResult.ts +5 -17
- package/src/client/form/ResetFormInstance.ts +17 -0
- package/src/entrypoints/FormInstance.ts +2 -0
- package/src/entrypoints/FormResult/BaseFormResult.ts +1 -0
- package/src/entrypoints/FormResult/BaseInstantiableFormResult.ts +10 -1
- package/src/entrypoints/FormResult/FormFailureResult.ts +3 -0
- package/src/entrypoints/createPotentiallyClientOwnedReactiveScope.ts +30 -0
- package/src/entrypoints/loadForm.ts +1 -31
- package/src/instance/InputControl.ts +3 -5
- package/src/instance/PrimaryInstance.ts +17 -2
- package/src/instance/attachments/buildAttributes.ts +21 -1
- package/src/instance/internal-api/AttributeContext.ts +1 -0
- package/src/instance/internal-api/InstanceConfig.ts +3 -0
- package/src/instance/internal-api/InstanceValueContext.ts +1 -0
- package/src/instance/markdown/MarkdownNode.ts +19 -7
- package/src/instance/text/markdownFormat.ts +4 -3
- package/src/integration/xpath/static-dom/StaticDocument.ts +2 -0
- package/src/lib/codecs/{Geopoint/Geopoint.ts → geolocation/Geolocation.ts} +43 -24
- package/src/lib/codecs/geolocation/Geopoint.ts +15 -0
- package/src/lib/codecs/geolocation/Geoshape.ts +36 -0
- package/src/lib/codecs/geolocation/Geotrace.ts +36 -0
- package/src/lib/codecs/geolocation/createGeolocationValueCodec.ts +18 -0
- package/src/lib/codecs/getSharedValueCodec.ts +37 -11
- package/src/lib/reactivity/createInstanceValueState.ts +64 -34
- package/src/lib/reactivity/text/createTextRange.ts +71 -45
- package/src/parse/XFormDOM.ts +22 -2
- package/src/parse/model/ActionDefinition.ts +6 -6
- package/src/parse/model/BindDefinition.ts +1 -1
- package/src/parse/model/BindPreloadDefinition.ts +21 -14
- package/src/parse/model/ModelActionMap.ts +30 -13
- package/src/parse/model/ModelDefinition.ts +5 -10
- package/src/parse/model/RootDefinition.ts +2 -1
- package/src/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.ts +2 -184
- package/src/parse/model/SecondaryInstance/sources/external-instance-csv-parser.ts +185 -0
- package/src/parse/model/TranslationDefinitionMap.ts +23 -0
- package/dist/lib/codecs/Geopoint/GeopointValueCodec.d.ts +0 -5
- package/dist/parse/model/generateItextChunks.d.ts +0 -5
- package/src/lib/codecs/Geopoint/GeopointValueCodec.ts +0 -20
- package/src/parse/model/generateItextChunks.ts +0 -61
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getodk/xforms-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "XForms engine for ODK Web Forms",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@babel/core": "^7.28.5",
|
|
65
65
|
"@getodk/tree-sitter-xpath": "0.2.2",
|
|
66
|
-
"@getodk/xpath": "0.
|
|
66
|
+
"@getodk/xpath": "0.10.0",
|
|
67
67
|
"@playwright/test": "^1.57.0",
|
|
68
68
|
"@types/papaparse": "^5.5.0",
|
|
69
69
|
"@vitest/browser": "^3.2.4",
|
package/src/client/InputNode.ts
CHANGED
|
@@ -49,8 +49,8 @@ interface InputNodeOptionsByValueType {
|
|
|
49
49
|
readonly time: null;
|
|
50
50
|
readonly dateTime: null;
|
|
51
51
|
readonly geopoint: GeoInputNodeOptions;
|
|
52
|
-
readonly geotrace:
|
|
53
|
-
readonly geoshape:
|
|
52
|
+
readonly geotrace: null;
|
|
53
|
+
readonly geoshape: null;
|
|
54
54
|
readonly binary: null;
|
|
55
55
|
readonly barcode: null;
|
|
56
56
|
readonly intent: null;
|
|
@@ -86,12 +86,16 @@ export type IntInputValue = InputValue<'int'>;
|
|
|
86
86
|
export type DecimalInputValue = InputValue<'decimal'>;
|
|
87
87
|
export type DateInputValue = InputValue<'date'>;
|
|
88
88
|
export type GeopointInputValue = InputValue<'geopoint'>;
|
|
89
|
+
export type GeoshapeInputValue = InputValue<'geoshape'>;
|
|
90
|
+
export type GeotraceInputValue = InputValue<'geotrace'>;
|
|
89
91
|
|
|
90
92
|
export type StringInputNode = InputNode<'string'>;
|
|
91
93
|
export type IntInputNode = InputNode<'int'>;
|
|
92
94
|
export type DecimalInputNode = InputNode<'decimal'>;
|
|
93
95
|
export type DateInputNode = InputNode<'date'>;
|
|
94
96
|
export type GeopointInputNode = InputNode<'geopoint'>;
|
|
97
|
+
export type GeoshapeInputNode = InputNode<'geoshape'>;
|
|
98
|
+
export type GeotraceInputNode = InputNode<'geotrace'>;
|
|
95
99
|
|
|
96
100
|
// prettier-ignore
|
|
97
101
|
type SupportedInputValueType =
|
|
@@ -100,7 +104,9 @@ type SupportedInputValueType =
|
|
|
100
104
|
| 'int'
|
|
101
105
|
| 'decimal'
|
|
102
106
|
| 'date'
|
|
103
|
-
| 'geopoint'
|
|
107
|
+
| 'geopoint'
|
|
108
|
+
| 'geoshape'
|
|
109
|
+
| 'geotrace';
|
|
104
110
|
|
|
105
111
|
type TemporaryStringValueType = Exclude<ValueType, SupportedInputValueType>;
|
|
106
112
|
|
|
@@ -114,4 +120,6 @@ export type AnyInputNode =
|
|
|
114
120
|
| DecimalInputNode
|
|
115
121
|
| DateInputNode
|
|
116
122
|
| GeopointInputNode
|
|
123
|
+
| GeoshapeInputNode
|
|
124
|
+
| GeotraceInputNode
|
|
117
125
|
| TemporaryStringValueInputNode;
|
|
@@ -16,17 +16,20 @@ export type ElementName =
|
|
|
16
16
|
export type MarkdownNode = ChildMarkdownNode | HtmlMarkdownNode | ParentMarkdownNode;
|
|
17
17
|
|
|
18
18
|
export interface ParentMarkdownNode {
|
|
19
|
+
readonly id: string;
|
|
19
20
|
readonly role: 'parent';
|
|
20
21
|
readonly elementName: string;
|
|
21
22
|
readonly children: MarkdownNode[];
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export interface ChildMarkdownNode {
|
|
26
|
+
readonly id: string;
|
|
25
27
|
readonly role: 'child';
|
|
26
28
|
readonly value: string;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export interface HtmlMarkdownNode {
|
|
32
|
+
readonly id: string;
|
|
30
33
|
readonly role: 'html';
|
|
31
34
|
readonly unsafeHtml: string;
|
|
32
35
|
}
|
package/src/client/NoteNode.ts
CHANGED
|
@@ -83,12 +83,16 @@ export type IntNoteValue = NoteValue<'int'>;
|
|
|
83
83
|
export type DecimalNoteValue = NoteValue<'decimal'>;
|
|
84
84
|
export type DateNoteValue = NoteValue<'date'>;
|
|
85
85
|
export type GeopointNoteValue = NoteValue<'geopoint'>;
|
|
86
|
+
export type GeoshapeNoteValue = NoteValue<'geoshape'>;
|
|
87
|
+
export type GeotraceNoteValue = NoteValue<'geotrace'>;
|
|
86
88
|
|
|
87
89
|
export type StringNoteNode = NoteNode<'string'>;
|
|
88
90
|
export type IntNoteNode = NoteNode<'int'>;
|
|
89
91
|
export type DecimalNoteNode = NoteNode<'decimal'>;
|
|
90
92
|
export type DateNoteNode = NoteNode<'date'>;
|
|
91
93
|
export type GeopointNoteNode = NoteNode<'geopoint'>;
|
|
94
|
+
export type GeoshapeNoteNode = NoteNode<'geoshape'>;
|
|
95
|
+
export type GeotraceNoteNode = NoteNode<'geotrace'>;
|
|
92
96
|
|
|
93
97
|
// prettier-ignore
|
|
94
98
|
type SupportedNoteValueType =
|
|
@@ -97,7 +101,9 @@ type SupportedNoteValueType =
|
|
|
97
101
|
| 'int'
|
|
98
102
|
| 'decimal'
|
|
99
103
|
| 'date'
|
|
100
|
-
| 'geopoint'
|
|
104
|
+
| 'geopoint'
|
|
105
|
+
| 'geoshape'
|
|
106
|
+
| 'geotrace';
|
|
101
107
|
|
|
102
108
|
type TemporaryStringValueType = Exclude<ValueType, SupportedNoteValueType>;
|
|
103
109
|
|
|
@@ -111,4 +117,6 @@ export type AnyNoteNode =
|
|
|
111
117
|
| DecimalNoteNode
|
|
112
118
|
| DateNoteNode
|
|
113
119
|
| GeopointNoteNode
|
|
120
|
+
| GeoshapeNoteNode
|
|
121
|
+
| GeotraceNoteNode
|
|
114
122
|
| TemporaryStringValueNoteNode;
|
|
@@ -16,6 +16,10 @@ export interface PreloadProperties {
|
|
|
16
16
|
readonly phoneNumber?: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export interface GeolocationProvider {
|
|
20
|
+
getLocation(): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
export interface FormInstanceConfig {
|
|
20
24
|
/**
|
|
21
25
|
* A client may specify a generic function for constructing stateful objects.
|
|
@@ -35,4 +39,6 @@ export interface FormInstanceConfig {
|
|
|
35
39
|
readonly instanceAttachments?: InstanceAttachmentsConfig;
|
|
36
40
|
|
|
37
41
|
readonly preloadProperties?: PreloadProperties;
|
|
42
|
+
|
|
43
|
+
readonly geolocationProvider?: GeolocationProvider;
|
|
38
44
|
}
|
|
@@ -3,6 +3,7 @@ import type { AnyFunction } from '@getodk/common/types/helpers.js';
|
|
|
3
3
|
import type { LoadFormFailureError } from '../../error/LoadFormFailureError.ts';
|
|
4
4
|
import type { CreateFormInstance } from './CreateFormInstance.ts';
|
|
5
5
|
import type { EditFormInstance } from './EditFormInstance.ts';
|
|
6
|
+
import type { ResetFormInstance } from './ResetFormInstance.ts';
|
|
6
7
|
import type { RestoreFormInstance } from './RestoreFormInstance.ts';
|
|
7
8
|
|
|
8
9
|
// Re-export for client access
|
|
@@ -44,6 +45,7 @@ interface BaseLoadFormResult {
|
|
|
44
45
|
readonly warnings: LoadFormWarnings | null;
|
|
45
46
|
readonly error: LoadFormFailureError | null;
|
|
46
47
|
readonly createInstance: FallibleLoadFormResultMethod<CreateFormInstance>;
|
|
48
|
+
readonly resetInstance: FallibleLoadFormResultMethod<ResetFormInstance>;
|
|
47
49
|
readonly editInstance: FallibleLoadFormResultMethod<EditFormInstance>;
|
|
48
50
|
readonly restoreInstance: FallibleLoadFormResultMethod<RestoreFormInstance>;
|
|
49
51
|
}
|
|
@@ -53,6 +55,7 @@ export interface LoadFormSuccessResult extends BaseLoadFormResult {
|
|
|
53
55
|
readonly warnings: null;
|
|
54
56
|
readonly error: null;
|
|
55
57
|
readonly createInstance: CreateFormInstance;
|
|
58
|
+
readonly resetInstance: ResetFormInstance;
|
|
56
59
|
readonly editInstance: EditFormInstance;
|
|
57
60
|
readonly restoreInstance: RestoreFormInstance;
|
|
58
61
|
}
|
|
@@ -62,6 +65,7 @@ export interface LoadFormWarningResult extends BaseLoadFormResult {
|
|
|
62
65
|
readonly warnings: LoadFormWarnings;
|
|
63
66
|
readonly error: null;
|
|
64
67
|
readonly createInstance: CreateFormInstance;
|
|
68
|
+
readonly resetInstance: ResetFormInstance;
|
|
65
69
|
readonly editInstance: EditFormInstance;
|
|
66
70
|
readonly restoreInstance: RestoreFormInstance;
|
|
67
71
|
}
|
|
@@ -70,25 +74,9 @@ export interface LoadFormFailureResult extends BaseLoadFormResult {
|
|
|
70
74
|
readonly status: 'failure';
|
|
71
75
|
readonly warnings: LoadFormWarnings | null;
|
|
72
76
|
readonly error: LoadFormFailureError;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @example A temporary demo integration was built during development of this
|
|
76
|
-
* interface.
|
|
77
|
-
*
|
|
78
|
-
* @see
|
|
79
|
-
* {@link https://github.com/getodk/web-forms/pull/345/commits/9ef36355d89dd1450d3a87c3a55506bb9b0fc414}
|
|
80
|
-
*/
|
|
81
77
|
readonly createInstance: FailedLoadFormResultMethod<CreateFormInstance>;
|
|
82
|
-
|
|
78
|
+
readonly resetInstance: FailedLoadFormResultMethod<ResetFormInstance>;
|
|
83
79
|
readonly editInstance: FailedLoadFormResultMethod<EditFormInstance>;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* @example A temporary demo integration was built during development of this
|
|
87
|
-
* interface.
|
|
88
|
-
*
|
|
89
|
-
* @see
|
|
90
|
-
* {@link https://github.com/getodk/web-forms/pull/345/commits/9ef36355d89dd1450d3a87c3a55506bb9b0fc414}
|
|
91
|
-
*/
|
|
92
80
|
readonly restoreInstance: FailedLoadFormResultMethod<RestoreFormInstance>;
|
|
93
81
|
}
|
|
94
82
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RootNode } from '../RootNode.ts';
|
|
2
|
+
import type { CreatedFormInstance } from './CreateFormInstance.ts';
|
|
3
|
+
import type { FormInstanceConfig } from './FormInstanceConfig.ts';
|
|
4
|
+
import type { LoadForm } from './LoadForm.ts';
|
|
5
|
+
import type { LoadFormResult } from './LoadFormResult.ts';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @todo This is fallible! Client-facing interfaces will need to account for
|
|
9
|
+
* this. We've begun addressing fallibility _at the interface level_ in
|
|
10
|
+
* {@link LoadForm} (with {@link LoadFormResult}). We'll eventually have a more
|
|
11
|
+
* general interface pattern for this, and we'll apply it here as well. The baby
|
|
12
|
+
* step approach in {@link LoadFormResult} is impractical here due to
|
|
13
|
+
* engine-internal designs, and revising that is currently out of scope. As
|
|
14
|
+
* such, explicit interface-level documentation of fallibility is deferred here,
|
|
15
|
+
* on {@link RootNode} itself, and into any of its sub-interfaces.
|
|
16
|
+
*/
|
|
17
|
+
export type ResetFormInstance = (config?: FormInstanceConfig) => CreatedFormInstance;
|
|
@@ -42,6 +42,7 @@ export class FormInstance<Mode extends FormInstanceInitializationMode>
|
|
|
42
42
|
clientStateFactory: instanceConfig.stateFactory ?? identity,
|
|
43
43
|
computeAttachmentName: instanceConfig.instanceAttachments?.fileNameFactory ?? (() => null),
|
|
44
44
|
preloadProperties: instanceConfig.preloadProperties ?? {},
|
|
45
|
+
geolocationProvider: instanceConfig.geolocationProvider,
|
|
45
46
|
};
|
|
46
47
|
const primaryInstanceOptions: PrimaryInstanceOptions<Mode> = {
|
|
47
48
|
...options.instanceOptions,
|
|
@@ -49,6 +50,7 @@ export class FormInstance<Mode extends FormInstanceInitializationMode>
|
|
|
49
50
|
initialState,
|
|
50
51
|
config,
|
|
51
52
|
};
|
|
53
|
+
|
|
52
54
|
const { root } = new PrimaryInstance(primaryInstanceOptions);
|
|
53
55
|
|
|
54
56
|
this.mode = mode;
|
|
@@ -29,6 +29,7 @@ export abstract class BaseFormResult<Status extends FormResultStatus> {
|
|
|
29
29
|
readonly error: BaseFormResultProperty<Status, 'error'>;
|
|
30
30
|
|
|
31
31
|
abstract readonly createInstance: BaseFormResultProperty<Status, 'createInstance'>;
|
|
32
|
+
abstract readonly resetInstance: BaseFormResultProperty<Status, 'resetInstance'>;
|
|
32
33
|
abstract readonly editInstance: BaseFormResultProperty<Status, 'editInstance'>;
|
|
33
34
|
abstract readonly restoreInstance: BaseFormResultProperty<Status, 'restoreInstance'>;
|
|
34
35
|
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
} from '../../client/form/EditFormInstance.ts';
|
|
6
6
|
import type { FormInstanceConfig } from '../../client/form/FormInstanceConfig.ts';
|
|
7
7
|
import type { FormResultStatus } from '../../client/form/LoadFormResult.ts';
|
|
8
|
+
import type { ResetFormInstance } from '../../client/form/ResetFormInstance.ts';
|
|
8
9
|
import type {
|
|
9
10
|
RestoreFormInstance,
|
|
10
11
|
RestoreFormInstanceInput,
|
|
@@ -13,7 +14,8 @@ import { ErrorProductionDesignPendingError } from '../../error/ErrorProductionDe
|
|
|
13
14
|
import { InitialInstanceState } from '../../instance/input/InitialInstanceState.ts';
|
|
14
15
|
import type { BasePrimaryInstanceOptions } from '../../instance/PrimaryInstance.ts';
|
|
15
16
|
import type { FormResource } from '../../instance/resource.ts';
|
|
16
|
-
import type
|
|
17
|
+
import { type ReactiveScope } from '../../lib/reactivity/scope.ts';
|
|
18
|
+
import { createPotentiallyClientOwnedReactiveScope } from '../createPotentiallyClientOwnedReactiveScope.ts';
|
|
17
19
|
import type { InstantiableFormResult } from '../FormInstance.ts';
|
|
18
20
|
import { FormInstance } from '../FormInstance.ts';
|
|
19
21
|
import type { BaseFormResultProperty } from './BaseFormResult.ts';
|
|
@@ -37,6 +39,7 @@ export abstract class BaseInstantiableFormResult<
|
|
|
37
39
|
Status extends InstantiableFormResultStatus,
|
|
38
40
|
> extends BaseFormResult<Status> {
|
|
39
41
|
readonly createInstance: CreateFormInstance;
|
|
42
|
+
readonly resetInstance: ResetFormInstance;
|
|
40
43
|
readonly editInstance: EditFormInstance;
|
|
41
44
|
readonly restoreInstance: RestoreFormInstance;
|
|
42
45
|
|
|
@@ -60,6 +63,12 @@ export abstract class BaseInstantiableFormResult<
|
|
|
60
63
|
});
|
|
61
64
|
};
|
|
62
65
|
|
|
66
|
+
this.resetInstance = (instanceConfig: FormInstanceConfig = {}) => {
|
|
67
|
+
instanceOptions.scope.dispose();
|
|
68
|
+
instanceOptions.scope = createPotentiallyClientOwnedReactiveScope();
|
|
69
|
+
return this.createInstance(instanceConfig);
|
|
70
|
+
};
|
|
71
|
+
|
|
63
72
|
this.editInstance = async (
|
|
64
73
|
input: EditFormInstanceInput,
|
|
65
74
|
instanceConfig: FormInstanceConfig = {}
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
LoadFormFailureResult,
|
|
7
7
|
LoadFormWarnings,
|
|
8
8
|
} from '../../client/form/LoadFormResult.ts';
|
|
9
|
+
import type { ResetFormInstance } from '../../client/form/ResetFormInstance.ts';
|
|
9
10
|
import type { RestoreFormInstance } from '../../client/form/RestoreFormInstance.ts';
|
|
10
11
|
import { LoadFormFailureError } from '../../error/LoadFormFailureError.ts';
|
|
11
12
|
import { BaseFormResult } from './BaseFormResult.ts';
|
|
@@ -25,6 +26,7 @@ const failedFormResultMethodFactory = <T extends AnyFunction>(
|
|
|
25
26
|
|
|
26
27
|
export class FormFailureResult extends BaseFormResult<'failure'> implements LoadFormFailureResult {
|
|
27
28
|
readonly createInstance: FailedLoadFormResultMethod<CreateFormInstance>;
|
|
29
|
+
readonly resetInstance: FailedLoadFormResultMethod<ResetFormInstance>;
|
|
28
30
|
readonly editInstance: FailedLoadFormResultMethod<EditFormInstance>;
|
|
29
31
|
readonly restoreInstance: FailedLoadFormResultMethod<RestoreFormInstance>;
|
|
30
32
|
|
|
@@ -38,6 +40,7 @@ export class FormFailureResult extends BaseFormResult<'failure'> implements Load
|
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
this.createInstance = failedFormResultMethodFactory(error);
|
|
43
|
+
this.resetInstance = failedFormResultMethodFactory(error);
|
|
41
44
|
this.editInstance = failedFormResultMethodFactory(error);
|
|
42
45
|
this.restoreInstance = failedFormResultMethodFactory(error);
|
|
43
46
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getOwner, type Owner } from 'solid-js';
|
|
2
|
+
import { createReactiveScope, type ReactiveScope } from '../lib/reactivity/scope';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a {@link ReactiveScope | reactive scope} from which all form
|
|
6
|
+
* instances derive, and:
|
|
7
|
+
*
|
|
8
|
+
* - if a client loads a form within a Solid reactive context, the scope will be
|
|
9
|
+
* disposed along with the client's reactive context; OR
|
|
10
|
+
* - if a client loads a form outside a Solid reactive context (typically: if a
|
|
11
|
+
* client does not use Solid reactivity), the scope will disposed if and when
|
|
12
|
+
* the engine drops access to the loaded form
|
|
13
|
+
*
|
|
14
|
+
* **IMPORTANT:** this **MUST** be called synchronously. If it is called in an
|
|
15
|
+
* `async` function, it **MUST** be called before any `await` expression; if it
|
|
16
|
+
* is called in any other flow with mixed synchrony, it must be called before
|
|
17
|
+
* yielding to the event loop. Failing to do this will cause the engine to lose
|
|
18
|
+
* access to a client's Solid reactive context, potentially leaking form
|
|
19
|
+
* reactivity indefinitely.
|
|
20
|
+
*/
|
|
21
|
+
export const createPotentiallyClientOwnedReactiveScope = (): ReactiveScope => {
|
|
22
|
+
/**
|
|
23
|
+
* A {@link clientOwner | client owner} is the owner of a client's Solid
|
|
24
|
+
* reactive context, if one exists. If none exists, the {@link ReactiveScope}
|
|
25
|
+
* is fully owned by the engine.
|
|
26
|
+
*/
|
|
27
|
+
const clientOwner: Owner | null = getOwner();
|
|
28
|
+
|
|
29
|
+
return createReactiveScope({ owner: clientOwner });
|
|
30
|
+
};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Owner } from 'solid-js';
|
|
2
|
-
import { getOwner } from 'solid-js';
|
|
3
1
|
import { MISSING_RESOURCE_BEHAVIOR } from '../client/constants.ts';
|
|
4
2
|
import type { FormResource } from '../client/form/FormResource.ts';
|
|
5
3
|
import type { LoadForm, LoadFormOptions } from '../client/form/LoadForm.ts';
|
|
@@ -7,40 +5,12 @@ import type { LoadFormResult } from '../client/form/LoadFormResult.ts';
|
|
|
7
5
|
import { LoadFormFailureError } from '../error/LoadFormFailureError.ts';
|
|
8
6
|
import { retrieveFormDefinition } from '../instance/resource.ts';
|
|
9
7
|
import type { ReactiveScope } from '../lib/reactivity/scope.ts';
|
|
10
|
-
import { createReactiveScope } from '../lib/reactivity/scope.ts';
|
|
11
8
|
import { XFormDOM } from '../parse/XFormDOM.ts';
|
|
12
9
|
import { XFormDefinition } from '../parse/XFormDefinition.ts';
|
|
13
10
|
import { SecondaryInstancesDefinition } from '../parse/model/SecondaryInstance/SecondaryInstancesDefinition.ts';
|
|
14
11
|
import { FormFailureResult } from './FormResult/FormFailureResult.ts';
|
|
15
12
|
import { FormSuccessResult } from './FormResult/FormSuccessResult.ts';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Creates a {@link ReactiveScope | reactive scope} from which all form
|
|
19
|
-
* instances derive, and:
|
|
20
|
-
*
|
|
21
|
-
* - if a client loads a form within a Solid reactive context, the scope will be
|
|
22
|
-
* disposed along with the client's reactive context; OR
|
|
23
|
-
* - if a client loads a form outside a Solid reactive context (typically: if a
|
|
24
|
-
* client does not use Solid reactivity), the scope will disposed if and when
|
|
25
|
-
* the engine drops access to the loaded form
|
|
26
|
-
*
|
|
27
|
-
* **IMPORTANT:** this **MUST** be called synchronously. If it is called in an
|
|
28
|
-
* `async` function, it **MUST** be called before any `await` expression; if it
|
|
29
|
-
* is called in any other flow with mixed synchrony, it must be called before
|
|
30
|
-
* yielding to the event loop. Failing to do this will cause the engine to lose
|
|
31
|
-
* access to a client's Solid reactive context, potentially leaking form
|
|
32
|
-
* reactivity indefinitely.
|
|
33
|
-
*/
|
|
34
|
-
const createPotentiallyClientOwnedReactiveScope = (): ReactiveScope => {
|
|
35
|
-
/**
|
|
36
|
-
* A {@link clientOwner | client owner} is the owner of a client's Solid
|
|
37
|
-
* reactive context, if one exists. If none exists, the {@link ReactiveScope}
|
|
38
|
-
* is fully owned by the engine.
|
|
39
|
-
*/
|
|
40
|
-
const clientOwner: Owner | null = getOwner();
|
|
41
|
-
|
|
42
|
-
return createReactiveScope({ owner: clientOwner });
|
|
43
|
-
};
|
|
13
|
+
import { createPotentiallyClientOwnedReactiveScope } from './createPotentiallyClientOwnedReactiveScope.ts';
|
|
44
14
|
|
|
45
15
|
type GlobalFetch = typeof globalThis.fetch;
|
|
46
16
|
|
|
@@ -41,9 +41,7 @@ const stringInputNodeOptions = (control: InputControlDefinition): InputNodeOptio
|
|
|
41
41
|
rows: control.rows,
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
const geoInputNodeOptions = (
|
|
45
|
-
control: InputControlDefinition
|
|
46
|
-
): InputNodeOptions<'geopoint' | 'geoshape' | 'geotrace'> => ({
|
|
44
|
+
const geoInputNodeOptions = (control: InputControlDefinition): InputNodeOptions<'geopoint'> => ({
|
|
47
45
|
accuracyThreshold: control.accuracyThreshold,
|
|
48
46
|
unacceptableAccuracyThreshold: control.unacceptableAccuracyThreshold,
|
|
49
47
|
});
|
|
@@ -65,8 +63,8 @@ const nodeOptionsFactoryByType: NodeOptionsFactoryByType = {
|
|
|
65
63
|
time: () => null,
|
|
66
64
|
dateTime: () => null,
|
|
67
65
|
geopoint: geoInputNodeOptions,
|
|
68
|
-
geotrace:
|
|
69
|
-
geoshape:
|
|
66
|
+
geotrace: () => null,
|
|
67
|
+
geoshape: () => null,
|
|
70
68
|
binary: () => null,
|
|
71
69
|
barcode: () => null,
|
|
72
70
|
intent: () => null,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { XPathNodeKindKey } from '@getodk/xpath';
|
|
1
|
+
import { clearCache, XPathNodeKindKey } from '@getodk/xpath';
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
3
|
import { createSignal } from 'solid-js';
|
|
4
|
+
import type { GeolocationProvider } from '../client';
|
|
4
5
|
import type { FormInstanceInitializationMode } from '../client/form/FormInstance.ts';
|
|
5
6
|
import type { ActiveLanguage, FormLanguage, FormLanguages } from '../client/FormLanguage.ts';
|
|
6
7
|
import type { FormNodeID } from '../client/identity.ts';
|
|
@@ -87,6 +88,7 @@ interface PrimaryInstanceStateSpec {
|
|
|
87
88
|
|
|
88
89
|
interface PrimaryInstanceStateInputByMode {
|
|
89
90
|
readonly create: null;
|
|
91
|
+
readonly reset: null;
|
|
90
92
|
readonly edit: InitialInstanceState;
|
|
91
93
|
readonly restore: InitialInstanceState;
|
|
92
94
|
}
|
|
@@ -95,7 +97,7 @@ export type PrimaryInstanceInitialState<Mode extends FormInstanceInitializationM
|
|
|
95
97
|
PrimaryInstanceStateInputByMode[Mode];
|
|
96
98
|
|
|
97
99
|
export interface BasePrimaryInstanceOptions {
|
|
98
|
-
|
|
100
|
+
scope: ReactiveScope;
|
|
99
101
|
readonly model: ModelDefinition;
|
|
100
102
|
readonly secondaryInstances: SecondaryInstancesDefinition;
|
|
101
103
|
}
|
|
@@ -137,6 +139,7 @@ export class PrimaryInstance<
|
|
|
137
139
|
readonly hasNonRelevantAncestor = () => false;
|
|
138
140
|
readonly isRelevant = () => true;
|
|
139
141
|
|
|
142
|
+
private geolocationProvider: GeolocationProvider | undefined;
|
|
140
143
|
// TranslationContext (support)
|
|
141
144
|
private readonly setActiveLanguage: SimpleAtomicStateSetter<FormLanguage>;
|
|
142
145
|
|
|
@@ -168,6 +171,8 @@ export class PrimaryInstance<
|
|
|
168
171
|
const activeInstance = initialState?.document ?? modelInstance;
|
|
169
172
|
const definition = model.getRootDefinition(activeInstance);
|
|
170
173
|
|
|
174
|
+
clearCache();
|
|
175
|
+
|
|
171
176
|
super(config, null, activeInstance, definition, {
|
|
172
177
|
scope,
|
|
173
178
|
computeReference: () => PRIMARY_INSTANCE_REFERENCE,
|
|
@@ -177,6 +182,7 @@ export class PrimaryInstance<
|
|
|
177
182
|
this.model = model;
|
|
178
183
|
this.attachments = new InstanceAttachmentsState(initialState?.attachments);
|
|
179
184
|
this.instanceNode = activeInstance;
|
|
185
|
+
this.geolocationProvider = config.geolocationProvider;
|
|
180
186
|
|
|
181
187
|
const [isAttached, setIsAttached] = createSignal(false);
|
|
182
188
|
|
|
@@ -294,4 +300,13 @@ export class PrimaryInstance<
|
|
|
294
300
|
|
|
295
301
|
return Promise.resolve(result);
|
|
296
302
|
}
|
|
303
|
+
|
|
304
|
+
async getBackgroundGeopoint(): Promise<string> {
|
|
305
|
+
if (!this.geolocationProvider) {
|
|
306
|
+
return '';
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const location = await this.geolocationProvider.getLocation();
|
|
310
|
+
return location ?? '';
|
|
311
|
+
}
|
|
297
312
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
|
|
2
|
+
import type { StaticDocument } from '../../integration/xpath/static-dom/StaticDocument.ts';
|
|
3
|
+
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
1
4
|
import { Attribute } from '../Attribute';
|
|
2
5
|
import type { AnyNode } from '../hierarchy.ts';
|
|
3
6
|
import type { InputControl } from '../InputControl.ts';
|
|
@@ -5,6 +8,19 @@ import type { ModelValue } from '../ModelValue.ts';
|
|
|
5
8
|
import type { Note } from '../Note.ts';
|
|
6
9
|
import type { RangeControl } from '../RangeControl.ts';
|
|
7
10
|
|
|
11
|
+
function buildInstanceAttributeMap(
|
|
12
|
+
instanceNode: StaticAttribute | StaticDocument | StaticElement | null
|
|
13
|
+
): Map<string, StaticAttribute> {
|
|
14
|
+
const map = new Map<string, StaticAttribute>();
|
|
15
|
+
if (!instanceNode) {
|
|
16
|
+
return map;
|
|
17
|
+
}
|
|
18
|
+
for (const attribute of instanceNode.attributes) {
|
|
19
|
+
map.set(attribute.qualifiedName.getPrefixedName(), attribute);
|
|
20
|
+
}
|
|
21
|
+
return map;
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
export function buildAttributes(
|
|
9
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
26
|
owner: AnyNode | InputControl<any> | ModelValue<any> | Note<any> | RangeControl<any>
|
|
@@ -13,7 +29,11 @@ export function buildAttributes(
|
|
|
13
29
|
if (!attributes) {
|
|
14
30
|
return [];
|
|
15
31
|
}
|
|
32
|
+
const instanceAttributes = buildInstanceAttributeMap(owner.instanceNode);
|
|
16
33
|
return Array.from(attributes.values()).map((attributeDefinition) => {
|
|
17
|
-
|
|
34
|
+
const instanceNode =
|
|
35
|
+
instanceAttributes.get(attributeDefinition.qualifiedName.getPrefixedName()) ??
|
|
36
|
+
attributeDefinition.template;
|
|
37
|
+
return new Attribute(owner, attributeDefinition, instanceNode);
|
|
18
38
|
});
|
|
19
39
|
}
|
|
@@ -11,6 +11,7 @@ import type { InstanceConfig } from './InstanceConfig.ts';
|
|
|
11
11
|
export interface InstanceAttributeContextDocument {
|
|
12
12
|
readonly initializationMode: FormInstanceInitializationMode;
|
|
13
13
|
readonly isAttached: Accessor<boolean>;
|
|
14
|
+
getBackgroundGeopoint: Accessor<Promise<string>>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type DecodeInstanceValue = (value: string) => string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InstanceAttachmentFileNameFactory } from '../../client/attachments/InstanceAttachmentsConfig.ts';
|
|
2
2
|
import type {
|
|
3
3
|
FormInstanceConfig,
|
|
4
|
+
GeolocationProvider,
|
|
4
5
|
PreloadProperties,
|
|
5
6
|
} from '../../client/form/FormInstanceConfig.ts';
|
|
6
7
|
import type { OpaqueReactiveObjectFactory } from '../../client/OpaqueReactiveObjectFactory.ts';
|
|
@@ -14,4 +15,6 @@ export interface InstanceConfig {
|
|
|
14
15
|
readonly computeAttachmentName: InstanceAttachmentFileNameFactory;
|
|
15
16
|
|
|
16
17
|
readonly preloadProperties: PreloadProperties;
|
|
18
|
+
|
|
19
|
+
readonly geolocationProvider: GeolocationProvider | undefined;
|
|
17
20
|
}
|
|
@@ -11,6 +11,7 @@ import type { InstanceConfig } from './InstanceConfig.ts';
|
|
|
11
11
|
export interface InstanceValueContextDocument {
|
|
12
12
|
readonly initializationMode: FormInstanceInitializationMode;
|
|
13
13
|
readonly isAttached: Accessor<boolean>;
|
|
14
|
+
getBackgroundGeopoint: Accessor<Promise<string>>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type DecodeInstanceValue = (value: string) => string;
|
|
@@ -2,18 +2,26 @@ import {
|
|
|
2
2
|
type AnchorMarkdownNode,
|
|
3
3
|
type ChildMarkdownNode as ClientChildMarkdownNode,
|
|
4
4
|
type HtmlMarkdownNode as ClientHtmlMarkdownNode,
|
|
5
|
+
type MarkdownNode as ClientMarkdownNode,
|
|
5
6
|
type ParentMarkdownNode as ClientParentMarkdownNode,
|
|
6
7
|
type StyledMarkdownNode as ClientStyledMarkdownNode,
|
|
7
8
|
type ElementName,
|
|
8
|
-
type MarkdownNode,
|
|
9
9
|
type MarkdownProperty,
|
|
10
10
|
} from '../../client';
|
|
11
11
|
|
|
12
|
-
abstract class
|
|
12
|
+
abstract class MarkdownNode {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.id = crypto.randomUUID();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
abstract class ParentMarkdownNode extends MarkdownNode implements ClientParentMarkdownNode {
|
|
13
20
|
readonly children;
|
|
14
21
|
readonly role = 'parent';
|
|
15
22
|
abstract elementName: ElementName;
|
|
16
|
-
constructor(children:
|
|
23
|
+
constructor(children: ClientMarkdownNode[]) {
|
|
24
|
+
super();
|
|
17
25
|
this.children = children;
|
|
18
26
|
}
|
|
19
27
|
}
|
|
@@ -69,18 +77,20 @@ export class ListItem extends ParentMarkdownNode {
|
|
|
69
77
|
export class Anchor extends ParentMarkdownNode implements AnchorMarkdownNode {
|
|
70
78
|
readonly elementName = 'a';
|
|
71
79
|
readonly url: string;
|
|
72
|
-
constructor(children:
|
|
80
|
+
constructor(children: ClientMarkdownNode[], url: string) {
|
|
73
81
|
super(children);
|
|
74
82
|
this.url = url;
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
abstract class StyledMarkdownNode implements ClientParentMarkdownNode {
|
|
87
|
+
readonly id: string;
|
|
79
88
|
readonly children;
|
|
80
89
|
readonly role = 'parent';
|
|
81
90
|
abstract elementName: ElementName;
|
|
82
91
|
readonly properties: MarkdownProperty | undefined;
|
|
83
|
-
constructor(children:
|
|
92
|
+
constructor(children: ClientMarkdownNode[], properties: MarkdownProperty | undefined) {
|
|
93
|
+
this.id = crypto.randomUUID();
|
|
84
94
|
this.children = children;
|
|
85
95
|
this.properties = properties;
|
|
86
96
|
}
|
|
@@ -98,18 +108,20 @@ export class Div extends StyledMarkdownNode implements ClientStyledMarkdownNode
|
|
|
98
108
|
readonly elementName = 'div';
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
export class ChildMarkdownNode implements ClientChildMarkdownNode {
|
|
111
|
+
export class ChildMarkdownNode extends MarkdownNode implements ClientChildMarkdownNode {
|
|
102
112
|
readonly role = 'child';
|
|
103
113
|
readonly value: string;
|
|
104
114
|
constructor(value: string) {
|
|
115
|
+
super();
|
|
105
116
|
this.value = value;
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
|
|
109
|
-
export class Html implements ClientHtmlMarkdownNode {
|
|
120
|
+
export class Html extends MarkdownNode implements ClientHtmlMarkdownNode {
|
|
110
121
|
readonly role = 'html';
|
|
111
122
|
readonly unsafeHtml: string;
|
|
112
123
|
constructor(unsafeHtml: string) {
|
|
124
|
+
super();
|
|
113
125
|
this.unsafeHtml = unsafeHtml;
|
|
114
126
|
}
|
|
115
127
|
}
|
|
@@ -42,7 +42,7 @@ const SUPPORTED_HTML_TAGS = Object.entries(HTML_TAG_MAP).map(([tag, type]) => {
|
|
|
42
42
|
};
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
const outputStrings = new Map<string, string>();
|
|
46
46
|
|
|
47
47
|
function validateStyleProperty(name: string | undefined, value: string | undefined): boolean {
|
|
48
48
|
if (!name || !value) {
|
|
@@ -208,7 +208,8 @@ function toOdkMarkdown(str: string): MarkdownNode[] {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
export function format(chunks: readonly TextChunk[]): MarkdownNode[] {
|
|
211
|
-
outputStrings = new Map<string, string>();
|
|
212
211
|
const str = escapeEditableChunks(chunks);
|
|
213
|
-
|
|
212
|
+
const result = toOdkMarkdown(str);
|
|
213
|
+
outputStrings.clear();
|
|
214
|
+
return result;
|
|
214
215
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { XFormsXPathDocument } from '../adapter/XFormsXPathNode.ts';
|
|
2
|
+
import type { StaticAttribute } from './StaticAttribute.ts';
|
|
2
3
|
import type { StaticElementOptions } from './StaticElement.ts';
|
|
3
4
|
import { StaticElement } from './StaticElement.ts';
|
|
4
5
|
import { StaticParentNode } from './StaticParentNode.ts';
|
|
@@ -15,6 +16,7 @@ export class StaticDocument extends StaticParentNode<'document'> implements XFor
|
|
|
15
16
|
readonly nodeset: string;
|
|
16
17
|
readonly children: readonly [root: StaticElement];
|
|
17
18
|
readonly childElements: readonly [root: StaticElement];
|
|
19
|
+
readonly attributes: readonly StaticAttribute[] = [];
|
|
18
20
|
|
|
19
21
|
constructor(options: StaticDocumentOptions) {
|
|
20
22
|
super('document');
|