@getodk/xforms-engine 0.12.0 → 0.14.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.
Files changed (95) hide show
  1. package/dist/client/BaseItem.d.ts +6 -0
  2. package/dist/client/GroupNode.d.ts +4 -4
  3. package/dist/client/MarkdownNode.d.ts +33 -0
  4. package/dist/client/RankNode.d.ts +2 -4
  5. package/dist/client/SelectNode.d.ts +2 -5
  6. package/dist/client/TextRange.d.ts +2 -11
  7. package/dist/client/hierarchy.d.ts +1 -2
  8. package/dist/client/index.d.ts +1 -1
  9. package/dist/client/node-types.d.ts +1 -1
  10. package/dist/index.js +10543 -332
  11. package/dist/index.js.map +1 -1
  12. package/dist/instance/RankControl.d.ts +3 -2
  13. package/dist/instance/SelectControl.d.ts +3 -2
  14. package/dist/instance/hierarchy.d.ts +5 -6
  15. package/dist/instance/markdown/MarkdownNode.d.ts +75 -0
  16. package/dist/instance/text/TextChunk.d.ts +0 -1
  17. package/dist/instance/text/TextRange.d.ts +2 -1
  18. package/dist/instance/text/markdownFormat.d.ts +3 -0
  19. package/dist/lib/reactivity/createItemCollection.d.ts +5 -7
  20. package/dist/parse/body/BodyDefinition.d.ts +2 -8
  21. package/dist/parse/body/GroupElementDefinition.d.ts +22 -0
  22. package/dist/parse/body/control/ItemsetDefinition.d.ts +4 -1
  23. package/dist/parse/expression/BindComputationExpression.d.ts +1 -1
  24. package/dist/parse/expression/ItemPropertyExpression.d.ts +6 -0
  25. package/dist/parse/expression/ItemsetNodesetExpression.d.ts +1 -2
  26. package/dist/parse/expression/TextChunkExpression.d.ts +9 -7
  27. package/dist/parse/expression/abstract/DependentExpression.d.ts +1 -15
  28. package/dist/parse/model/{SubtreeDefinition.d.ts → GroupDefinition.d.ts} +4 -3
  29. package/dist/parse/model/ModelDefinition.d.ts +6 -1
  30. package/dist/parse/model/NodeDefinition.d.ts +7 -8
  31. package/dist/parse/model/RepeatDefinition.d.ts +1 -1
  32. package/dist/parse/model/RootDefinition.d.ts +1 -1
  33. package/dist/parse/model/generateItextChunks.d.ts +5 -0
  34. package/dist/parse/text/LabelDefinition.d.ts +4 -5
  35. package/dist/parse/xpath/semantic-analysis.d.ts +1 -0
  36. package/dist/solid.js +10543 -332
  37. package/dist/solid.js.map +1 -1
  38. package/package.json +3 -2
  39. package/src/client/BaseItem.ts +7 -0
  40. package/src/client/GroupNode.ts +4 -10
  41. package/src/client/MarkdownNode.ts +53 -0
  42. package/src/client/RankNode.ts +2 -5
  43. package/src/client/SelectNode.ts +2 -6
  44. package/src/client/TextRange.ts +2 -11
  45. package/src/client/hierarchy.ts +0 -2
  46. package/src/client/index.ts +1 -1
  47. package/src/client/node-types.ts +0 -1
  48. package/src/instance/Group.ts +1 -1
  49. package/src/instance/RankControl.ts +8 -2
  50. package/src/instance/SelectControl.ts +8 -2
  51. package/src/instance/children/buildChildren.ts +1 -17
  52. package/src/instance/children/normalizeChildInitOptions.ts +44 -59
  53. package/src/instance/hierarchy.ts +0 -6
  54. package/src/instance/markdown/MarkdownNode.ts +115 -0
  55. package/src/instance/text/TextChunk.ts +0 -5
  56. package/src/instance/text/TextRange.ts +5 -3
  57. package/src/instance/text/markdownFormat.ts +214 -0
  58. package/src/integration/xpath/adapter/names.ts +0 -1
  59. package/src/lib/reactivity/createItemCollection.ts +25 -9
  60. package/src/lib/reactivity/text/createTextRange.ts +30 -30
  61. package/src/parse/body/BodyDefinition.ts +7 -34
  62. package/src/parse/body/GroupElementDefinition.ts +47 -0
  63. package/src/parse/body/control/ItemsetDefinition.ts +9 -2
  64. package/src/parse/expression/BindComputationExpression.ts +2 -7
  65. package/src/parse/expression/ItemPropertyExpression.ts +12 -0
  66. package/src/parse/expression/ItemsetNodesetExpression.ts +2 -3
  67. package/src/parse/expression/ItemsetValueExpression.ts +1 -1
  68. package/src/parse/expression/RepeatCountControlExpression.ts +4 -4
  69. package/src/parse/expression/TextChunkExpression.ts +25 -35
  70. package/src/parse/expression/abstract/DependentExpression.ts +2 -38
  71. package/src/parse/model/{SubtreeDefinition.ts → GroupDefinition.ts} +6 -8
  72. package/src/parse/model/ModelDefinition.ts +13 -0
  73. package/src/parse/model/NodeDefinition.ts +8 -9
  74. package/src/parse/model/RepeatDefinition.ts +2 -2
  75. package/src/parse/model/RootDefinition.ts +2 -2
  76. package/src/parse/model/generateItextChunks.ts +61 -0
  77. package/src/parse/text/ItemsetLabelDefinition.ts +4 -4
  78. package/src/parse/text/LabelDefinition.ts +4 -9
  79. package/src/parse/text/MessageDefinition.ts +4 -4
  80. package/src/parse/text/abstract/TextElementDefinition.ts +6 -7
  81. package/src/parse/xpath/semantic-analysis.ts +37 -8
  82. package/dist/client/SubtreeNode.d.ts +0 -56
  83. package/dist/instance/Subtree.d.ts +0 -38
  84. package/dist/instance/text/FormattedTextStub.d.ts +0 -1
  85. package/dist/parse/body/group/BaseGroupDefinition.d.ts +0 -40
  86. package/dist/parse/body/group/LogicalGroupDefinition.d.ts +0 -6
  87. package/dist/parse/body/group/PresentationGroupDefinition.d.ts +0 -11
  88. package/dist/parse/body/group/StructuralGroupDefinition.d.ts +0 -6
  89. package/src/client/SubtreeNode.ts +0 -61
  90. package/src/instance/Subtree.ts +0 -102
  91. package/src/instance/text/FormattedTextStub.ts +0 -8
  92. package/src/parse/body/group/BaseGroupDefinition.ts +0 -89
  93. package/src/parse/body/group/LogicalGroupDefinition.ts +0 -11
  94. package/src/parse/body/group/PresentationGroupDefinition.ts +0 -28
  95. package/src/parse/body/group/StructuralGroupDefinition.ts +0 -11
@@ -21,27 +21,26 @@ export abstract class TextElementDefinition<
21
21
  constructor(form: XFormDefinition, owner: TextElementOwner, sourceNode: TextSourceNode<Role>) {
22
22
  super(form, owner, sourceNode);
23
23
 
24
- const context = this as AnyTextElementDefinition;
25
24
  const refExpression = parseNodesetReference(owner, sourceNode, 'ref');
26
25
 
27
26
  if (refExpression == null) {
28
27
  this.chunks = Array.from(sourceNode.childNodes).flatMap((childNode) => {
29
28
  if (isElementNode(childNode)) {
30
- return TextChunkExpression.fromOutput(context, childNode) ?? [];
29
+ return TextChunkExpression.fromOutput(childNode) ?? [];
31
30
  }
32
31
 
33
32
  if (isTextNode(childNode)) {
34
- return TextChunkExpression.fromLiteral(context, childNode.data);
33
+ return TextChunkExpression.fromLiteral(childNode.data);
35
34
  }
36
35
 
37
36
  return [];
38
37
  });
39
38
  } else {
40
- const expression = TextChunkExpression.fromTranslation(context, refExpression);
41
- if (expression != null) {
42
- this.chunks = [expression];
39
+ const translationChunk = TextChunkExpression.fromTranslation(refExpression);
40
+ if (translationChunk) {
41
+ this.chunks = [translationChunk];
43
42
  } else {
44
- this.chunks = [TextChunkExpression.fromReference(context, refExpression)];
43
+ this.chunks = [TextChunkExpression.fromReference(refExpression)];
45
44
  }
46
45
  }
47
46
  }
@@ -20,6 +20,7 @@ import {
20
20
  collectTypedNodes,
21
21
  findTypedPrincipalExpressionNode,
22
22
  isCompleteSubExpression,
23
+ type TypedSyntaxNode,
23
24
  } from './syntax-traversal.ts';
24
25
 
25
26
  // prettier-ignore
@@ -106,6 +107,24 @@ const isTranslationFunctionCall = (syntaxNode: FunctionCallNode): boolean => {
106
107
 
107
108
  export type TranslationExpression = LocalNamedFunctionCallLiteral<'itext'>;
108
109
 
110
+ const findFunctionPrincipalExpressionNode = (
111
+ expression: string
112
+ ): TypedSyntaxNode<'function_call'> | null => {
113
+ let result;
114
+ try {
115
+ result = expressionParser.parse(expression);
116
+ } catch {
117
+ return null;
118
+ }
119
+
120
+ const functionCallNode = findTypedPrincipalExpressionNode(['function_call'], result.rootNode);
121
+ if (functionCallNode == null) {
122
+ return null;
123
+ }
124
+
125
+ return functionCallNode;
126
+ };
127
+
109
128
  /**
110
129
  * Determines if an arbitrary XPath expression is (in whole) a translation
111
130
  * expression (i.e. a call to `jr:itext`).
@@ -117,19 +136,29 @@ export type TranslationExpression = LocalNamedFunctionCallLiteral<'itext'>;
117
136
  export const isTranslationExpression = (
118
137
  expression: string
119
138
  ): expression is TranslationExpression => {
120
- let result;
121
- try {
122
- result = expressionParser.parse(expression);
123
- } catch {
139
+ const functionCallNode = findFunctionPrincipalExpressionNode(expression);
140
+ if (!functionCallNode) {
124
141
  return false;
125
142
  }
143
+ return isTranslationFunctionCall(functionCallNode);
144
+ };
126
145
 
127
- const functionCallNode = findTypedPrincipalExpressionNode(['function_call'], result.rootNode);
128
- if (functionCallNode == null) {
129
- return false;
146
+ export const getTranslationExpression = (expression: string): string | null => {
147
+ const functionCallNode = findFunctionPrincipalExpressionNode(expression);
148
+ if (!functionCallNode) {
149
+ return null;
130
150
  }
131
151
 
132
- return isTranslationFunctionCall(functionCallNode);
152
+ if (!isTranslationFunctionCall(functionCallNode)) {
153
+ return null;
154
+ }
155
+
156
+ const arg = functionCallNode.children.find((child) => child.type === 'argument');
157
+ if (!arg) {
158
+ return null;
159
+ }
160
+
161
+ return arg.text;
133
162
  };
134
163
 
135
164
  const isCurrentFunctionCall = (syntaxNode: FunctionCallNode): boolean => {
@@ -1,56 +0,0 @@
1
- import { SubtreeDefinition as BaseSubtreeDefinition } from '../parse/model/SubtreeDefinition.ts';
2
- import { BaseNode, BaseNodeState } from './BaseNode.ts';
3
- import { RootNode } from './RootNode.ts';
4
- import { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
5
- import { AncestorNodeValidationState } from './validation.ts';
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
- export interface SubtreeDefinition extends BaseSubtreeDefinition {
14
- readonly bodyElement: null;
15
- }
16
- /**
17
- * A non-root node which has children, but **no** corresponding XForms
18
- * `<group>`. A subtree node does not have any direct implications for
19
- * presentation to users, but its descendants may specify presentational details
20
- * in their own {@link BaseNode.definition | definition}s.
21
- *
22
- * @example
23
- *
24
- * A common `SubtreeNode` case will be a form's `<meta>` element:
25
- *
26
- * ```xml
27
- * <!-- /h:html/h:head/model -->
28
- * <instance>
29
- * <data>
30
- * <some-group>
31
- * <some-field />
32
- * </some-group>
33
- * <!-- Note that `meta` does not have a corresponding group body element -->
34
- * <!-- SubtreeNode(/data/meta): { ... -->
35
- * <meta>
36
- * <instanceID/>
37
- * </meta>
38
- * <!-- } -->
39
- * </data>
40
- * </instance>
41
- * <!-- /h:html/h:body -->
42
- * <group ref="/data/some-group">
43
- * <input ref="/data/some-group/some-field" />
44
- * </group>
45
- * ```
46
- */
47
- export interface SubtreeNode extends BaseNode {
48
- readonly nodeType: 'subtree';
49
- readonly appearances: null;
50
- readonly nodeOptions: null;
51
- readonly definition: SubtreeDefinition;
52
- readonly root: RootNode;
53
- readonly parent: GeneralParentNode;
54
- readonly currentState: SubtreeNodeState;
55
- readonly validationState: AncestorNodeValidationState;
56
- }
@@ -1,38 +0,0 @@
1
- import { XPathNodeKindKey } from '@getodk/xpath';
2
- import { Accessor } from 'solid-js';
3
- import { FormNodeID } from '../client/identity.ts';
4
- import { InstanceState } from '../client/serialization/InstanceState.ts';
5
- import { SubtreeDefinition, SubtreeNode } from '../client/SubtreeNode.ts';
6
- import { AncestorNodeValidationState } from '../client/validation.ts';
7
- import { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
8
- import { StaticElement } from '../integration/xpath/static-dom/StaticElement.ts';
9
- import { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
10
- import { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
11
- import { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
12
- import { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
13
- import { DescendantNodeSharedStateSpec, DescendantNode } from './abstract/DescendantNode.ts';
14
- import { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
15
- import { EvaluationContext } from './internal-api/EvaluationContext.ts';
16
- import { ClientReactiveSerializableParentNode } from './internal-api/serialization/ClientReactiveSerializableParentNode.ts';
17
- interface SubtreeStateSpec extends DescendantNodeSharedStateSpec {
18
- readonly label: null;
19
- readonly hint: null;
20
- readonly children: Accessor<readonly FormNodeID[]>;
21
- readonly valueOptions: null;
22
- readonly value: null;
23
- }
24
- export declare class Subtree extends DescendantNode<SubtreeDefinition, SubtreeStateSpec, GeneralParentNode, GeneralChildNode> implements SubtreeNode, XFormsXPathElement, EvaluationContext, ClientReactiveSerializableParentNode<GeneralChildNode> {
25
- private readonly childrenState;
26
- readonly [XPathNodeKindKey] = "element";
27
- protected readonly state: SharedNodeState<SubtreeStateSpec>;
28
- protected readonly engineState: EngineState<SubtreeStateSpec>;
29
- readonly nodeType = "subtree";
30
- readonly appearances: null;
31
- readonly nodeOptions: null;
32
- readonly currentState: MaterializedChildren<CurrentState<SubtreeStateSpec>, GeneralChildNode>;
33
- readonly validationState: AncestorNodeValidationState;
34
- readonly instanceState: InstanceState;
35
- constructor(parent: GeneralParentNode, instanceNode: StaticElement | null, definition: SubtreeDefinition);
36
- getChildren(): readonly GeneralChildNode[];
37
- }
38
- export {};
@@ -1 +0,0 @@
1
- export declare const FormattedTextStub: Record<PropertyKey, unknown>;
@@ -1,40 +0,0 @@
1
- import { LabelDefinition } from '../../text/LabelDefinition.ts';
2
- import { XFormDefinition } from '../../XFormDefinition.ts';
3
- import { StructureElementAppearanceDefinition } from '../appearance/structureElementAppearanceParser.ts';
4
- import { BodyElementDefinitionArray, BodyElementParentContext } from '../BodyDefinition.ts';
5
- import { BodyElementDefinition } from '../BodyElementDefinition.ts';
6
- /**
7
- * These type names are derived from **and expand upon** the language used in
8
- * the ODK XForms spec to describe various group usage. Whereas the spec
9
- * language allows for a group to be described as more than one case, the intent
10
- * here is to establish exclusive naming which may or may not compound. As such:
11
- *
12
- * - `logical-group`, per spec language, is a group with a `ref`; its usage here
13
- * differs from the spec language in that it _may_ have a `<label>` child but
14
- * is not also treated as a `presentation-group` (which is only used for
15
- * groups which do not have a `ref`)
16
- * - `presentation-group` is a group with a `<label>` child; its usage here
17
- * differs from the spec language in that `presentation-group` does **not**
18
- * have a `ref`
19
- * - `structural-group` is any `<group>` element which does not satisfy any of
20
- * the other usage scenarios; this isn't exactly the terminology used, but is
21
- * the most closely fitting name for the concept where the other sceanarios
22
- * do not apply
23
- *
24
- * A more succinct decision tree:
25
- *
26
- * - `<group ref="$ref">` -> `logical-group`, else
27
- * - `<group><label>` -> `presentation-group`, else
28
- * - `<group>` -> `structural-group`
29
- */
30
- export type GroupType = 'logical-group' | 'presentation-group' | 'structural-group';
31
- export declare abstract class BaseGroupDefinition<Type extends GroupType> extends BodyElementDefinition<Type> {
32
- private static groupTypes;
33
- protected static getGroupType(localName: string, element: Element): GroupType | null;
34
- readonly category = "structure";
35
- readonly children: BodyElementDefinitionArray;
36
- readonly reference: string | null;
37
- readonly appearances: StructureElementAppearanceDefinition;
38
- readonly label: LabelDefinition | null;
39
- constructor(form: XFormDefinition, parent: BodyElementParentContext, element: Element);
40
- }
@@ -1,6 +0,0 @@
1
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
2
- export declare class LogicalGroupDefinition extends BaseGroupDefinition<'logical-group'> {
3
- static isCompatible(localName: string, element: Element): boolean;
4
- readonly type = "logical-group";
5
- }
6
- export type LogicalGroupDefinitionClass = typeof LogicalGroupDefinition;
@@ -1,11 +0,0 @@
1
- import { LabelDefinition } from '../../text/LabelDefinition.ts';
2
- import { XFormDefinition } from '../../XFormDefinition.ts';
3
- import { BodyElementParentContext } from '../BodyDefinition.ts';
4
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
5
- export declare class PresentationGroupDefinition extends BaseGroupDefinition<'presentation-group'> {
6
- static isCompatible(localName: string, element: Element): boolean;
7
- readonly type = "presentation-group";
8
- readonly label: LabelDefinition;
9
- constructor(form: XFormDefinition, parent: BodyElementParentContext, element: Element);
10
- }
11
- export type PresentationGroupDefinitionClass = typeof PresentationGroupDefinition;
@@ -1,6 +0,0 @@
1
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
2
- export declare class StructuralGroupDefinition extends BaseGroupDefinition<'structural-group'> {
3
- static isCompatible(localName: string, element: Element): boolean;
4
- readonly type = "structural-group";
5
- }
6
- export type StructuralGroupDefinitionClass = typeof StructuralGroupDefinition;
@@ -1,61 +0,0 @@
1
- import type { SubtreeDefinition as BaseSubtreeDefinition } from '../parse/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
- import type { AncestorNodeValidationState } from './validation.ts';
6
-
7
- export interface SubtreeNodeState extends BaseNodeState {
8
- get label(): null;
9
- get hint(): null;
10
- get children(): readonly GeneralChildNode[];
11
- get valueOptions(): null;
12
- get value(): null;
13
- }
14
-
15
- // TODO: obviously there is a naming inconsistency emerging here.
16
- export interface SubtreeDefinition extends BaseSubtreeDefinition {
17
- readonly bodyElement: null;
18
- }
19
-
20
- /**
21
- * A non-root node which has children, but **no** corresponding XForms
22
- * `<group>`. A subtree node does not have any direct implications for
23
- * presentation to users, but its descendants may specify presentational details
24
- * in their own {@link BaseNode.definition | definition}s.
25
- *
26
- * @example
27
- *
28
- * A common `SubtreeNode` case will be a form's `<meta>` element:
29
- *
30
- * ```xml
31
- * <!-- /h:html/h:head/model -->
32
- * <instance>
33
- * <data>
34
- * <some-group>
35
- * <some-field />
36
- * </some-group>
37
- * <!-- Note that `meta` does not have a corresponding group body element -->
38
- * <!-- SubtreeNode(/data/meta): { ... -->
39
- * <meta>
40
- * <instanceID/>
41
- * </meta>
42
- * <!-- } -->
43
- * </data>
44
- * </instance>
45
- * <!-- /h:html/h:body -->
46
- * <group ref="/data/some-group">
47
- * <input ref="/data/some-group/some-field" />
48
- * </group>
49
- * ```
50
- */
51
- // TODO: directly test presentation of non-group subtree children/descendants
52
- export interface SubtreeNode extends BaseNode {
53
- readonly nodeType: 'subtree';
54
- readonly appearances: null;
55
- readonly nodeOptions: null;
56
- readonly definition: SubtreeDefinition;
57
- readonly root: RootNode;
58
- readonly parent: GeneralParentNode;
59
- readonly currentState: SubtreeNodeState;
60
- readonly validationState: AncestorNodeValidationState;
61
- }
@@ -1,102 +0,0 @@
1
- import { XPathNodeKindKey } from '@getodk/xpath';
2
- import type { Accessor } from 'solid-js';
3
- import type { FormNodeID } from '../client/identity.ts';
4
- import type { InstanceState } from '../client/serialization/InstanceState.ts';
5
- import type { SubtreeDefinition, SubtreeNode } from '../client/SubtreeNode.ts';
6
- import type { AncestorNodeValidationState } from '../client/validation.ts';
7
- import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
8
- import type { StaticElement } from '../integration/xpath/static-dom/StaticElement.ts';
9
- import { createParentNodeInstanceState } from '../lib/client-reactivity/instance-state/createParentNodeInstanceState.ts';
10
- import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
11
- import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
12
- import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
13
- import { materializeCurrentStateChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
14
- import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
15
- import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
16
- import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
17
- import { createSharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
18
- import { createAggregatedViolations } from '../lib/reactivity/validation/createAggregatedViolations.ts';
19
- import type { DescendantNodeSharedStateSpec } from './abstract/DescendantNode.ts';
20
- import { DescendantNode } from './abstract/DescendantNode.ts';
21
- import { buildChildren } from './children/buildChildren.ts';
22
- import type { GeneralChildNode, GeneralParentNode } from './hierarchy.ts';
23
- import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
24
- import type { ClientReactiveSerializableParentNode } from './internal-api/serialization/ClientReactiveSerializableParentNode.ts';
25
-
26
- interface SubtreeStateSpec extends DescendantNodeSharedStateSpec {
27
- readonly label: null;
28
- readonly hint: null;
29
- readonly children: Accessor<readonly FormNodeID[]>;
30
- readonly valueOptions: null;
31
- readonly value: null;
32
- }
33
-
34
- export class Subtree
35
- extends DescendantNode<SubtreeDefinition, SubtreeStateSpec, GeneralParentNode, GeneralChildNode>
36
- implements
37
- SubtreeNode,
38
- XFormsXPathElement,
39
- EvaluationContext,
40
- ClientReactiveSerializableParentNode<GeneralChildNode>
41
- {
42
- private readonly childrenState: ChildrenState<GeneralChildNode>;
43
-
44
- override readonly [XPathNodeKindKey] = 'element';
45
-
46
- // InstanceNode
47
- protected readonly state: SharedNodeState<SubtreeStateSpec>;
48
- protected readonly engineState: EngineState<SubtreeStateSpec>;
49
-
50
- // SubtreeNode
51
- readonly nodeType = 'subtree';
52
- readonly appearances = null;
53
- readonly nodeOptions = null;
54
- readonly currentState: MaterializedChildren<CurrentState<SubtreeStateSpec>, GeneralChildNode>;
55
- readonly validationState: AncestorNodeValidationState;
56
- readonly instanceState: InstanceState;
57
-
58
- constructor(
59
- parent: GeneralParentNode,
60
- instanceNode: StaticElement | null,
61
- definition: SubtreeDefinition
62
- ) {
63
- super(parent, instanceNode, definition);
64
-
65
- const childrenState = createChildrenState<Subtree, GeneralChildNode>(this);
66
-
67
- this.childrenState = childrenState;
68
-
69
- const state = createSharedNodeState(
70
- this.scope,
71
- {
72
- reference: this.contextReference,
73
- readonly: this.isReadonly,
74
- relevant: this.isRelevant,
75
- required: this.isRequired,
76
-
77
- label: null,
78
- hint: null,
79
- children: childrenState.childIds,
80
- valueOptions: null,
81
- value: null,
82
- },
83
- this.instanceConfig
84
- );
85
-
86
- this.state = state;
87
- this.engineState = state.engineState;
88
- this.currentState = materializeCurrentStateChildren(
89
- this.scope,
90
- state.currentState,
91
- childrenState
92
- );
93
-
94
- childrenState.setChildren(buildChildren(this));
95
- this.validationState = createAggregatedViolations(this, this.instanceConfig);
96
- this.instanceState = createParentNodeInstanceState(this);
97
- }
98
-
99
- getChildren(): readonly GeneralChildNode[] {
100
- return this.childrenState.getChildren();
101
- }
102
- }
@@ -1,8 +0,0 @@
1
- export const FormattedTextStub = new Proxy({} as Record<PropertyKey, unknown>, {
2
- get() {
3
- throw new TypeError('Not implemented');
4
- },
5
- set() {
6
- return false;
7
- },
8
- });
@@ -1,89 +0,0 @@
1
- import { UpsertableMap } from '@getodk/common/lib/collections/UpsertableMap.ts';
2
- import { getLabelElement } from '../../../lib/dom/query.ts';
3
- import { LabelDefinition } from '../../text/LabelDefinition.ts';
4
- import type { XFormDefinition } from '../../XFormDefinition.ts';
5
- import { parseNodesetReference } from '../../xpath/reference-parsing.ts';
6
- import type { StructureElementAppearanceDefinition } from '../appearance/structureElementAppearanceParser.ts';
7
- import { structureElementAppearanceParser } from '../appearance/structureElementAppearanceParser.ts';
8
- import {
9
- type BodyElementDefinitionArray,
10
- type BodyElementParentContext,
11
- } from '../BodyDefinition.ts';
12
- import { BodyElementDefinition } from '../BodyElementDefinition.ts';
13
-
14
- /**
15
- * These type names are derived from **and expand upon** the language used in
16
- * the ODK XForms spec to describe various group usage. Whereas the spec
17
- * language allows for a group to be described as more than one case, the intent
18
- * here is to establish exclusive naming which may or may not compound. As such:
19
- *
20
- * - `logical-group`, per spec language, is a group with a `ref`; its usage here
21
- * differs from the spec language in that it _may_ have a `<label>` child but
22
- * is not also treated as a `presentation-group` (which is only used for
23
- * groups which do not have a `ref`)
24
- * - `presentation-group` is a group with a `<label>` child; its usage here
25
- * differs from the spec language in that `presentation-group` does **not**
26
- * have a `ref`
27
- * - `structural-group` is any `<group>` element which does not satisfy any of
28
- * the other usage scenarios; this isn't exactly the terminology used, but is
29
- * the most closely fitting name for the concept where the other sceanarios
30
- * do not apply
31
- *
32
- * A more succinct decision tree:
33
- *
34
- * - `<group ref="$ref">` -> `logical-group`, else
35
- * - `<group><label>` -> `presentation-group`, else
36
- * - `<group>` -> `structural-group`
37
- */
38
- export type GroupType = 'logical-group' | 'presentation-group' | 'structural-group';
39
-
40
- export abstract class BaseGroupDefinition<
41
- Type extends GroupType,
42
- > extends BodyElementDefinition<Type> {
43
- // TODO: does this really accomplish anything? It seems highly unlikely it
44
- // has enough performance benefit to outweigh its memory and lookup costs.
45
- private static groupTypes = new UpsertableMap<Element, GroupType | null>();
46
-
47
- protected static getGroupType(localName: string, element: Element): GroupType | null {
48
- return this.groupTypes.upsert(element, () => {
49
- if (localName !== 'group') {
50
- return null;
51
- }
52
-
53
- if (element.hasAttribute('ref')) {
54
- return 'logical-group';
55
- }
56
-
57
- const label = getLabelElement(element);
58
-
59
- if (label == null) {
60
- return 'structural-group';
61
- }
62
-
63
- return 'presentation-group';
64
- });
65
- }
66
-
67
- override readonly category = 'structure';
68
-
69
- readonly children: BodyElementDefinitionArray;
70
-
71
- override readonly reference: string | null;
72
- readonly appearances: StructureElementAppearanceDefinition;
73
- override readonly label: LabelDefinition | null;
74
-
75
- constructor(form: XFormDefinition, parent: BodyElementParentContext, element: Element) {
76
- super(form, parent, element);
77
-
78
- const childElements = Array.from(element.children).filter((child) => {
79
- const childName = child.localName;
80
-
81
- return childName !== 'label';
82
- });
83
-
84
- this.children = this.body.getChildElementDefinitions(form, this, element, childElements);
85
- this.reference = parseNodesetReference(parent, element, 'ref');
86
- this.appearances = structureElementAppearanceParser.parseFrom(element, 'appearance');
87
- this.label = LabelDefinition.forGroup(form, this);
88
- }
89
- }
@@ -1,11 +0,0 @@
1
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
2
-
3
- export class LogicalGroupDefinition extends BaseGroupDefinition<'logical-group'> {
4
- static override isCompatible(localName: string, element: Element): boolean {
5
- return this.getGroupType(localName, element) === 'logical-group';
6
- }
7
-
8
- readonly type = 'logical-group';
9
- }
10
-
11
- export type LogicalGroupDefinitionClass = typeof LogicalGroupDefinition;
@@ -1,28 +0,0 @@
1
- import { LabelDefinition } from '../../text/LabelDefinition.ts';
2
- import type { XFormDefinition } from '../../XFormDefinition.ts';
3
- import type { BodyElementParentContext } from '../BodyDefinition.ts';
4
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
5
-
6
- export class PresentationGroupDefinition extends BaseGroupDefinition<'presentation-group'> {
7
- static override isCompatible(localName: string, element: Element): boolean {
8
- return this.getGroupType(localName, element) === 'presentation-group';
9
- }
10
-
11
- readonly type = 'presentation-group';
12
-
13
- override readonly label: LabelDefinition;
14
-
15
- constructor(form: XFormDefinition, parent: BodyElementParentContext, element: Element) {
16
- super(form, parent, element);
17
-
18
- const label = LabelDefinition.forGroup(form, this);
19
-
20
- if (label == null) {
21
- throw new Error('Invalid presentation-group: missing label');
22
- }
23
-
24
- this.label = label;
25
- }
26
- }
27
-
28
- export type PresentationGroupDefinitionClass = typeof PresentationGroupDefinition;
@@ -1,11 +0,0 @@
1
- import { BaseGroupDefinition } from './BaseGroupDefinition.ts';
2
-
3
- export class StructuralGroupDefinition extends BaseGroupDefinition<'structural-group'> {
4
- static override isCompatible(localName: string, element: Element): boolean {
5
- return this.getGroupType(localName, element) === 'structural-group';
6
- }
7
-
8
- readonly type = 'structural-group';
9
- }
10
-
11
- export type StructuralGroupDefinitionClass = typeof StructuralGroupDefinition;