@getodk/xforms-engine 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/body/BodyElementDefinition.d.ts +4 -3
- package/dist/body/RepeatElementDefinition.d.ts +2 -2
- package/dist/body/control/ControlDefinition.d.ts +2 -2
- package/dist/body/control/select/ItemDefinition.d.ts +2 -2
- package/dist/body/control/select/ItemsetDefinition.d.ts +5 -4
- package/dist/body/group/BaseGroupDefinition.d.ts +1 -1
- package/dist/body/group/PresentationGroupDefinition.d.ts +1 -1
- package/dist/client/BaseNode.d.ts +68 -2
- package/dist/client/GroupNode.d.ts +2 -0
- package/dist/client/ModelValueNode.d.ts +37 -0
- package/dist/client/NoteNode.d.ts +53 -0
- package/dist/client/RootNode.d.ts +2 -0
- package/dist/client/SelectNode.d.ts +5 -3
- package/dist/client/StringNode.d.ts +5 -3
- package/dist/client/SubtreeNode.d.ts +2 -0
- package/dist/client/TextRange.d.ts +85 -2
- package/dist/client/constants.d.ts +9 -0
- package/dist/client/hierarchy.d.ts +14 -9
- package/dist/client/node-types.d.ts +2 -1
- package/dist/client/{RepeatRangeNode.d.ts → repeat/BaseRepeatRangeNode.d.ts} +18 -17
- package/dist/client/{RepeatInstanceNode.d.ts → repeat/RepeatInstanceNode.d.ts} +9 -8
- package/dist/client/repeat/RepeatRangeControlledNode.d.ts +19 -0
- package/dist/client/repeat/RepeatRangeUncontrolledNode.d.ts +20 -0
- package/dist/client/validation.d.ts +163 -0
- package/dist/expression/DependentExpression.d.ts +12 -8
- package/dist/index.d.ts +9 -4
- package/dist/index.js +2635 -678
- package/dist/index.js.map +1 -1
- package/dist/instance/Group.d.ts +3 -1
- package/dist/instance/ModelValue.d.ts +40 -0
- package/dist/instance/Note.d.ts +42 -0
- package/dist/instance/Root.d.ts +2 -0
- package/dist/instance/SelectField.d.ts +10 -4
- package/dist/instance/StringField.d.ts +11 -5
- package/dist/instance/Subtree.d.ts +2 -0
- package/dist/instance/abstract/DescendantNode.d.ts +5 -6
- package/dist/instance/abstract/InstanceNode.d.ts +2 -0
- package/dist/instance/hierarchy.d.ts +10 -5
- package/dist/instance/internal-api/ValidationContext.d.ts +21 -0
- package/dist/instance/{RepeatRange.d.ts → repeat/BaseRepeatRange.d.ts} +46 -45
- package/dist/instance/{RepeatInstance.d.ts → repeat/RepeatInstance.d.ts} +13 -12
- package/dist/instance/repeat/RepeatRangeControlled.d.ts +16 -0
- package/dist/instance/repeat/RepeatRangeUncontrolled.d.ts +35 -0
- package/dist/instance/text/TextRange.d.ts +4 -4
- package/dist/lib/reactivity/createComputedExpression.d.ts +6 -1
- package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +5 -0
- package/dist/lib/reactivity/node-state/createSharedNodeState.d.ts +1 -1
- package/dist/lib/reactivity/node-state/createSpecifiedState.d.ts +1 -1
- package/dist/lib/reactivity/text/createFieldHint.d.ts +3 -3
- package/dist/lib/reactivity/text/createNodeLabel.d.ts +2 -2
- package/dist/lib/reactivity/text/createNoteText.d.ts +25 -0
- package/dist/lib/reactivity/text/createTextRange.d.ts +5 -7
- package/dist/lib/reactivity/validation/createAggregatedViolations.d.ts +9 -0
- package/dist/lib/reactivity/validation/createValidation.d.ts +18 -0
- package/dist/model/BindDefinition.d.ts +4 -2
- package/dist/model/BindElement.d.ts +1 -0
- package/dist/model/{ValueNodeDefinition.d.ts → LeafNodeDefinition.d.ts} +2 -2
- package/dist/model/NodeDefinition.d.ts +8 -8
- package/dist/model/RepeatInstanceDefinition.d.ts +2 -2
- package/dist/model/RepeatRangeDefinition.d.ts +14 -4
- package/dist/parse/NoteNodeDefinition.d.ts +31 -0
- package/dist/parse/expression/RepeatCountControlExpression.d.ts +19 -0
- package/dist/parse/text/HintDefinition.d.ts +9 -0
- package/dist/parse/text/ItemLabelDefinition.d.ts +9 -0
- package/dist/parse/text/ItemsetLabelDefinition.d.ts +13 -0
- package/dist/parse/text/LabelDefinition.d.ts +15 -0
- package/dist/parse/text/MessageDefinition.d.ts +15 -0
- package/dist/parse/text/OutputChunkDefinition.d.ts +8 -0
- package/dist/parse/text/ReferenceChunkDefinition.d.ts +8 -0
- package/dist/parse/text/StaticTextChunkDefinition.d.ts +10 -0
- package/dist/parse/text/TranslationChunkDefinition.d.ts +9 -0
- package/dist/parse/text/abstract/TextChunkDefinition.d.ts +18 -0
- package/dist/parse/text/abstract/TextElementDefinition.d.ts +23 -0
- package/dist/parse/text/abstract/TextRangeDefinition.d.ts +35 -0
- package/dist/parse/xpath/dependency-analysis.d.ts +40 -0
- package/dist/parse/xpath/path-resolution.d.ts +70 -0
- package/dist/parse/xpath/predicate-analysis.d.ts +30 -0
- package/dist/parse/xpath/reference-parsing.d.ts +18 -0
- package/dist/parse/xpath/semantic-analysis.d.ts +98 -0
- package/dist/parse/xpath/syntax-traversal.d.ts +69 -0
- package/dist/solid.js +2636 -679
- package/dist/solid.js.map +1 -1
- package/package.json +14 -15
- package/src/body/BodyElementDefinition.ts +4 -3
- package/src/body/RepeatElementDefinition.ts +5 -17
- package/src/body/control/ControlDefinition.ts +4 -3
- package/src/body/control/select/ItemDefinition.ts +3 -3
- package/src/body/control/select/ItemsetDefinition.ts +29 -12
- package/src/body/control/select/ItemsetNodesetExpression.ts +1 -1
- package/src/body/group/BaseGroupDefinition.ts +3 -2
- package/src/body/group/PresentationGroupDefinition.ts +1 -1
- package/src/client/BaseNode.ts +73 -7
- package/src/client/GroupNode.ts +2 -0
- package/src/client/ModelValueNode.ts +40 -0
- package/src/client/NoteNode.ts +74 -0
- package/src/client/README.md +1 -0
- package/src/client/RootNode.ts +2 -0
- package/src/client/SelectNode.ts +5 -3
- package/src/client/StringNode.ts +5 -3
- package/src/client/SubtreeNode.ts +2 -0
- package/src/client/TextRange.ts +99 -2
- package/src/client/constants.ts +10 -0
- package/src/client/hierarchy.ts +30 -14
- package/src/client/node-types.ts +8 -1
- package/src/client/{RepeatRangeNode.ts → repeat/BaseRepeatRangeNode.ts} +18 -19
- package/src/client/{RepeatInstanceNode.ts → repeat/RepeatInstanceNode.ts} +10 -8
- package/src/client/repeat/RepeatRangeControlledNode.ts +20 -0
- package/src/client/repeat/RepeatRangeUncontrolledNode.ts +21 -0
- package/src/client/validation.ts +199 -0
- package/src/expression/DependentExpression.ts +45 -27
- package/src/index.ts +15 -8
- package/src/instance/Group.ts +10 -4
- package/src/instance/ModelValue.ts +104 -0
- package/src/instance/Note.ts +142 -0
- package/src/instance/Root.ts +9 -3
- package/src/instance/SelectField.ts +28 -6
- package/src/instance/StringField.ts +35 -9
- package/src/instance/Subtree.ts +9 -3
- package/src/instance/abstract/DescendantNode.ts +6 -7
- package/src/instance/abstract/InstanceNode.ts +20 -6
- package/src/instance/children.ts +42 -15
- package/src/instance/hierarchy.ts +21 -2
- package/src/instance/internal-api/ValidationContext.ts +23 -0
- package/src/instance/{RepeatRange.ts → repeat/BaseRepeatRange.ts} +114 -99
- package/src/instance/{RepeatInstance.ts → repeat/RepeatInstance.ts} +27 -22
- package/src/instance/repeat/RepeatRangeControlled.ts +82 -0
- package/src/instance/repeat/RepeatRangeUncontrolled.ts +67 -0
- package/src/instance/text/TextRange.ts +10 -4
- package/src/lib/reactivity/createComputedExpression.ts +22 -24
- package/src/lib/reactivity/createNoteReadonlyThunk.ts +33 -0
- package/src/lib/reactivity/createSelectItems.ts +21 -14
- package/src/lib/reactivity/node-state/createSharedNodeState.ts +1 -1
- package/src/lib/reactivity/text/createFieldHint.ts +9 -7
- package/src/lib/reactivity/text/createNodeLabel.ts +7 -5
- package/src/lib/reactivity/text/createNoteText.ts +72 -0
- package/src/lib/reactivity/text/createTextRange.ts +17 -90
- package/src/lib/reactivity/validation/createAggregatedViolations.ts +70 -0
- package/src/lib/reactivity/validation/createValidation.ts +196 -0
- package/src/model/BindComputation.ts +0 -4
- package/src/model/BindDefinition.ts +8 -6
- package/src/model/BindElement.ts +1 -0
- package/src/model/{ValueNodeDefinition.ts → LeafNodeDefinition.ts} +4 -4
- package/src/model/ModelBindMap.ts +4 -0
- package/src/model/NodeDefinition.ts +12 -12
- package/src/model/RepeatInstanceDefinition.ts +2 -2
- package/src/model/RepeatRangeDefinition.ts +49 -8
- package/src/model/RootDefinition.ts +7 -3
- package/src/parse/NoteNodeDefinition.ts +70 -0
- package/src/parse/TODO.md +3 -0
- package/src/parse/expression/RepeatCountControlExpression.ts +44 -0
- package/src/parse/text/HintDefinition.ts +25 -0
- package/src/parse/text/ItemLabelDefinition.ts +25 -0
- package/src/parse/text/ItemsetLabelDefinition.ts +44 -0
- package/src/parse/text/LabelDefinition.ts +61 -0
- package/src/parse/text/MessageDefinition.ts +49 -0
- package/src/parse/text/OutputChunkDefinition.ts +25 -0
- package/src/parse/text/ReferenceChunkDefinition.ts +14 -0
- package/src/parse/text/StaticTextChunkDefinition.ts +19 -0
- package/src/parse/text/TranslationChunkDefinition.ts +38 -0
- package/src/parse/text/abstract/TextChunkDefinition.ts +38 -0
- package/src/parse/text/abstract/TextElementDefinition.ts +71 -0
- package/src/parse/text/abstract/TextRangeDefinition.ts +70 -0
- package/src/parse/xpath/dependency-analysis.ts +105 -0
- package/src/parse/xpath/path-resolution.ts +475 -0
- package/src/parse/xpath/predicate-analysis.ts +61 -0
- package/src/parse/xpath/reference-parsing.ts +90 -0
- package/src/parse/xpath/semantic-analysis.ts +466 -0
- package/src/parse/xpath/syntax-traversal.ts +129 -0
- package/dist/body/text/HintDefinition.d.ts +0 -11
- package/dist/body/text/LabelDefinition.d.ts +0 -22
- package/dist/body/text/TextElementDefinition.d.ts +0 -33
- package/dist/body/text/TextElementOutputPart.d.ts +0 -13
- package/dist/body/text/TextElementPart.d.ts +0 -13
- package/dist/body/text/TextElementReferencePart.d.ts +0 -7
- package/dist/body/text/TextElementStaticPart.d.ts +0 -7
- package/dist/lib/xpath/analysis.d.ts +0 -23
- package/src/body/text/HintDefinition.ts +0 -26
- package/src/body/text/LabelDefinition.ts +0 -68
- package/src/body/text/TextElementDefinition.ts +0 -97
- package/src/body/text/TextElementOutputPart.ts +0 -27
- package/src/body/text/TextElementPart.ts +0 -31
- package/src/body/text/TextElementReferencePart.ts +0 -21
- package/src/body/text/TextElementStaticPart.ts +0 -26
- package/src/lib/xpath/analysis.ts +0 -241
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AnyTextElementDefinition, TextElement } from './TextElementDefinition.ts';
|
|
2
|
-
import { TextElementPart } from './TextElementPart.ts';
|
|
3
|
-
|
|
4
|
-
export declare class TextElementReferencePart extends TextElementPart<'reference'> {
|
|
5
|
-
static from(context: AnyTextElementDefinition, element: TextElement): TextElementReferencePart | null;
|
|
6
|
-
protected constructor(context: AnyTextElementDefinition, expression: string);
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AnyTextElementDefinition } from './TextElementDefinition.ts';
|
|
2
|
-
import { TextElementPart } from './TextElementPart.ts';
|
|
3
|
-
|
|
4
|
-
export declare class TextElementStaticPart extends TextElementPart<'static'> {
|
|
5
|
-
readonly stringValue: string;
|
|
6
|
-
constructor(context: AnyTextElementDefinition, node: Text);
|
|
7
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { AnySyntaxNode } from '@getodk/xpath/static/grammar/SyntaxNode.js';
|
|
2
|
-
|
|
3
|
-
export type SingleChildNode = Extract<AnySyntaxNode, {
|
|
4
|
-
readonly children: readonly [AnySyntaxNode];
|
|
5
|
-
}>;
|
|
6
|
-
export declare const isItextFunctionCalled: (expression: string) => boolean;
|
|
7
|
-
interface GetNodesetDependenciesOptions {
|
|
8
|
-
readonly contextReference?: string | null;
|
|
9
|
-
/**
|
|
10
|
-
* @default false
|
|
11
|
-
*/
|
|
12
|
-
readonly ignoreContextReference?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Ignores location path sub-expressions whose full text is `null`. While this
|
|
15
|
-
* is technically a valid relative name test step, it seems that real forms in
|
|
16
|
-
* the wild use it as if XPath had an actual `null` token/value.
|
|
17
|
-
*
|
|
18
|
-
* @default true
|
|
19
|
-
*/
|
|
20
|
-
readonly ignoreNullExpressions?: boolean;
|
|
21
|
-
}
|
|
22
|
-
export declare const getNodesetDependencies: (expression: string, options?: GetNodesetDependenciesOptions) => Set<string>;
|
|
23
|
-
export {};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { getHintElement } from '../../lib/dom/query.ts';
|
|
2
|
-
import type { XFormDefinition } from '../../XFormDefinition.ts';
|
|
3
|
-
import type { AnyControlDefinition } from '../control/ControlDefinition.ts';
|
|
4
|
-
import type { TextElement } from './TextElementDefinition.ts';
|
|
5
|
-
import { TextElementDefinition } from './TextElementDefinition.ts';
|
|
6
|
-
|
|
7
|
-
export interface HintElement extends TextElement {
|
|
8
|
-
readonly localName: 'hint';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class HintDefinition extends TextElementDefinition<'hint'> {
|
|
12
|
-
static forElement(
|
|
13
|
-
form: XFormDefinition,
|
|
14
|
-
definition: AnyControlDefinition
|
|
15
|
-
): HintDefinition | null {
|
|
16
|
-
const hintElement = getHintElement(definition.element);
|
|
17
|
-
|
|
18
|
-
if (hintElement == null) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return new this(form, definition, hintElement);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
readonly type = 'hint';
|
|
26
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { getLabelElement, getRepeatGroupLabelElement } from '../../lib/dom/query.ts';
|
|
2
|
-
import type { XFormDefinition } from '../../XFormDefinition.ts';
|
|
3
|
-
import type { AnyControlDefinition } from '../control/ControlDefinition.ts';
|
|
4
|
-
import type { ItemDefinition } from '../control/select/ItemDefinition.ts';
|
|
5
|
-
import type { ItemsetDefinition } from '../control/select/ItemsetDefinition.ts';
|
|
6
|
-
import type { BaseGroupDefinition } from '../group/BaseGroupDefinition.ts';
|
|
7
|
-
import type { RepeatElementDefinition } from '../RepeatElementDefinition.ts';
|
|
8
|
-
import type { TextElement, TextElementOwner } from './TextElementDefinition.ts';
|
|
9
|
-
import { TextElementDefinition } from './TextElementDefinition.ts';
|
|
10
|
-
|
|
11
|
-
export interface LabelElement extends TextElement {
|
|
12
|
-
readonly localName: 'label';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type StaticLabelContext = Exclude<TextElementOwner, ItemsetDefinition>;
|
|
16
|
-
|
|
17
|
-
export class LabelDefinition extends TextElementDefinition<'label'> {
|
|
18
|
-
protected static staticDefinition(
|
|
19
|
-
form: XFormDefinition,
|
|
20
|
-
definition: StaticLabelContext
|
|
21
|
-
): LabelDefinition | null {
|
|
22
|
-
const labelElement = getLabelElement(definition.element);
|
|
23
|
-
|
|
24
|
-
if (labelElement == null) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return new this(form, definition, labelElement);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
static forControl(form: XFormDefinition, control: AnyControlDefinition): LabelDefinition | null {
|
|
32
|
-
return this.staticDefinition(form, control);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static forRepeatGroup(
|
|
36
|
-
form: XFormDefinition,
|
|
37
|
-
repeat: RepeatElementDefinition
|
|
38
|
-
): LabelDefinition | null {
|
|
39
|
-
const repeatGroupLabel = getRepeatGroupLabelElement(repeat.element);
|
|
40
|
-
|
|
41
|
-
if (repeatGroupLabel == null) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return new this(form, repeat, repeatGroupLabel);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
49
|
-
static forGroup(form: XFormDefinition, group: BaseGroupDefinition<any>): LabelDefinition | null {
|
|
50
|
-
return this.staticDefinition(form, group);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
static forItem(form: XFormDefinition, item: ItemDefinition): LabelDefinition | null {
|
|
54
|
-
return this.staticDefinition(form, item);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
static forItemset(form: XFormDefinition, itemset: ItemsetDefinition): LabelDefinition | null {
|
|
58
|
-
const labelElement = getLabelElement(itemset.element);
|
|
59
|
-
|
|
60
|
-
if (labelElement == null) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return new this(form, itemset, labelElement);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
readonly type = 'label';
|
|
68
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { isCommentNode, isElementNode, isTextNode } from '@getodk/common/lib/dom/predicates.ts';
|
|
2
|
-
import type { XFormDefinition } from '../../XFormDefinition.ts';
|
|
3
|
-
import { type AnyDependentExpression } from '../../expression/DependentExpression.ts';
|
|
4
|
-
import type { AnyGroupElementDefinition } from '../BodyDefinition.ts';
|
|
5
|
-
import { BodyElementDefinition } from '../BodyElementDefinition.ts';
|
|
6
|
-
import type { RepeatElementDefinition } from '../RepeatElementDefinition.ts';
|
|
7
|
-
import type { AnyControlDefinition } from '../control/ControlDefinition.ts';
|
|
8
|
-
import type { ItemDefinition } from '../control/select/ItemDefinition.ts';
|
|
9
|
-
import type { ItemsetDefinition } from '../control/select/ItemsetDefinition.ts';
|
|
10
|
-
import { TextElementOutputPart } from './TextElementOutputPart.ts';
|
|
11
|
-
import { TextElementReferencePart } from './TextElementReferencePart.ts';
|
|
12
|
-
import { TextElementStaticPart } from './TextElementStaticPart.ts';
|
|
13
|
-
|
|
14
|
-
export type TextElementType = 'hint' | 'label';
|
|
15
|
-
|
|
16
|
-
export interface TextElement extends Element {
|
|
17
|
-
readonly localName: TextElementType;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type TextElementOwner =
|
|
21
|
-
| AnyControlDefinition
|
|
22
|
-
| AnyGroupElementDefinition
|
|
23
|
-
| ItemDefinition
|
|
24
|
-
| ItemsetDefinition
|
|
25
|
-
| RepeatElementDefinition;
|
|
26
|
-
|
|
27
|
-
export type TextElementChild = TextElementOutputPart | TextElementStaticPart;
|
|
28
|
-
|
|
29
|
-
export abstract class TextElementDefinition<
|
|
30
|
-
Type extends TextElementType,
|
|
31
|
-
> extends BodyElementDefinition<Type> {
|
|
32
|
-
readonly category = 'support';
|
|
33
|
-
abstract override readonly type: Type;
|
|
34
|
-
|
|
35
|
-
override readonly reference: string | null;
|
|
36
|
-
override readonly parentReference: string | null;
|
|
37
|
-
|
|
38
|
-
readonly referenceExpression: TextElementReferencePart | null;
|
|
39
|
-
readonly children: readonly TextElementChild[];
|
|
40
|
-
|
|
41
|
-
override get isTranslated(): boolean {
|
|
42
|
-
return this.owner.isTranslated;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
override set isTranslated(value: true) {
|
|
46
|
-
this.owner.isTranslated = value;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
protected constructor(
|
|
50
|
-
form: XFormDefinition,
|
|
51
|
-
readonly owner: TextElementOwner,
|
|
52
|
-
element: TextElement
|
|
53
|
-
) {
|
|
54
|
-
super(form, owner, element);
|
|
55
|
-
|
|
56
|
-
this.reference = owner.reference;
|
|
57
|
-
this.parentReference = owner.parentReference;
|
|
58
|
-
this.referenceExpression = TextElementReferencePart.from(this, element);
|
|
59
|
-
|
|
60
|
-
const children = Array.from(element.childNodes).flatMap((node) => {
|
|
61
|
-
if (isTextNode(node)) {
|
|
62
|
-
return new TextElementStaticPart(this, node);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (isElementNode(node)) {
|
|
66
|
-
const output = TextElementOutputPart.from(this, node);
|
|
67
|
-
|
|
68
|
-
if (output != null) {
|
|
69
|
-
return output;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (isCommentNode(node)) {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// eslint-disable-next-line no-console
|
|
78
|
-
console.error('Unexpected text element child', node);
|
|
79
|
-
|
|
80
|
-
throw new Error(`Unexpected <${element.nodeName}> child element`);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
this.children = children;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
override registerDependentExpression(expression: AnyDependentExpression): void {
|
|
87
|
-
this.owner.registerDependentExpression(expression);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
override toJSON(): object {
|
|
91
|
-
const { form, owner, parent, ...rest } = this;
|
|
92
|
-
|
|
93
|
-
return rest;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export type AnyTextElementDefinition = TextElementDefinition<TextElementType>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { AnyTextElementDefinition } from './TextElementDefinition.ts';
|
|
2
|
-
import { TextElementPart } from './TextElementPart.ts';
|
|
3
|
-
|
|
4
|
-
interface OutputElement extends Element {
|
|
5
|
-
readonly localName: 'output';
|
|
6
|
-
|
|
7
|
-
getAttribute(name: 'value'): string;
|
|
8
|
-
getAttribute(name: string): string | null;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const isOutputElement = (element: Element): element is OutputElement => {
|
|
12
|
-
return element.localName === 'output' && element.hasAttribute('value');
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export class TextElementOutputPart extends TextElementPart<'output'> {
|
|
16
|
-
static from(context: AnyTextElementDefinition, element: Element): TextElementOutputPart | null {
|
|
17
|
-
if (isOutputElement(element)) {
|
|
18
|
-
return new this(context, element);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
protected constructor(context: AnyTextElementDefinition, element: OutputElement) {
|
|
25
|
-
super('output', context, element.getAttribute('value'));
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { DependentExpression } from '../../expression/DependentExpression.ts';
|
|
2
|
-
import type { AnyTextElementDefinition } from './TextElementDefinition.ts';
|
|
3
|
-
import type { TextElementOutputPart } from './TextElementOutputPart.ts';
|
|
4
|
-
import type { TextElementReferencePart } from './TextElementReferencePart.ts';
|
|
5
|
-
import type { TextElementStaticPart } from './TextElementStaticPart.ts';
|
|
6
|
-
|
|
7
|
-
export type TextElementPartType = 'output' | 'reference' | 'static';
|
|
8
|
-
|
|
9
|
-
export abstract class TextElementPart<
|
|
10
|
-
Type extends TextElementPartType,
|
|
11
|
-
> extends DependentExpression<'string'> {
|
|
12
|
-
readonly stringValue?: string;
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
readonly type: Type,
|
|
16
|
-
context: AnyTextElementDefinition,
|
|
17
|
-
expression: string
|
|
18
|
-
) {
|
|
19
|
-
super(context, 'string', expression, {
|
|
20
|
-
semanticDependencies: {
|
|
21
|
-
translations: type !== 'static',
|
|
22
|
-
},
|
|
23
|
-
ignoreContextReference: true,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type AnyTextElementPart =
|
|
29
|
-
| TextElementOutputPart
|
|
30
|
-
| TextElementReferencePart
|
|
31
|
-
| TextElementStaticPart;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AnyTextElementDefinition, TextElement } from './TextElementDefinition.ts';
|
|
2
|
-
import { TextElementPart } from './TextElementPart.ts';
|
|
3
|
-
|
|
4
|
-
export class TextElementReferencePart extends TextElementPart<'reference'> {
|
|
5
|
-
static from(
|
|
6
|
-
context: AnyTextElementDefinition,
|
|
7
|
-
element: TextElement
|
|
8
|
-
): TextElementReferencePart | null {
|
|
9
|
-
const expression = element.getAttribute('ref');
|
|
10
|
-
|
|
11
|
-
if (expression == null) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return new this(context, expression);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
protected constructor(context: AnyTextElementDefinition, expression: string) {
|
|
19
|
-
super('reference', context, expression);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { AnyTextElementDefinition } from './TextElementDefinition.ts';
|
|
2
|
-
import { TextElementPart } from './TextElementPart.ts';
|
|
3
|
-
|
|
4
|
-
const toStaticXPathExpression = (staticTextValue: string): string => {
|
|
5
|
-
const quote = staticTextValue.includes('"') ? "'" : '"';
|
|
6
|
-
|
|
7
|
-
if (staticTextValue.includes(quote)) {
|
|
8
|
-
// throw new Error('todo concat()');
|
|
9
|
-
return 'todo(concat())';
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return `${quote}${staticTextValue}${quote}`;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export class TextElementStaticPart extends TextElementPart<'static'> {
|
|
16
|
-
override readonly stringValue: string;
|
|
17
|
-
|
|
18
|
-
constructor(context: AnyTextElementDefinition, node: Text) {
|
|
19
|
-
const stringValue = node.data;
|
|
20
|
-
const expression = toStaticXPathExpression(stringValue);
|
|
21
|
-
|
|
22
|
-
super('static', context, expression);
|
|
23
|
-
|
|
24
|
-
this.stringValue = stringValue;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { UnreachableError } from '@getodk/common/lib/error/UnreachableError';
|
|
2
|
-
import { expressionParser } from '@getodk/xpath/expressionParser.js';
|
|
3
|
-
import type {
|
|
4
|
-
AbsoluteLocationPathNode,
|
|
5
|
-
AnyBinaryExprNode,
|
|
6
|
-
AnySyntaxNode,
|
|
7
|
-
FilterPathExprNode,
|
|
8
|
-
LocalPartNode,
|
|
9
|
-
PrefixedNameNode,
|
|
10
|
-
RelativeLocationPathNode,
|
|
11
|
-
UnprefixedNameNode,
|
|
12
|
-
} from '@getodk/xpath/static/grammar/SyntaxNode.js';
|
|
13
|
-
import type { AnyBinaryExprType } from '@getodk/xpath/static/grammar/type-names.js';
|
|
14
|
-
|
|
15
|
-
export type SingleChildNode = Extract<
|
|
16
|
-
AnySyntaxNode,
|
|
17
|
-
{ readonly children: readonly [AnySyntaxNode] }
|
|
18
|
-
>;
|
|
19
|
-
|
|
20
|
-
const isSingleNodeChild = (node: AnySyntaxNode): node is SingleChildNode => {
|
|
21
|
-
return node.childCount === 1;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const binaryExprNodeTypes = new Set<AnyBinaryExprType>([
|
|
25
|
-
'addition_expr',
|
|
26
|
-
'and_expr',
|
|
27
|
-
'division_expr',
|
|
28
|
-
'eq_expr',
|
|
29
|
-
'gt_expr',
|
|
30
|
-
'gte_expr',
|
|
31
|
-
'lt_expr',
|
|
32
|
-
'lte_expr',
|
|
33
|
-
'modulo_expr',
|
|
34
|
-
'multiplication_expr',
|
|
35
|
-
'ne_expr',
|
|
36
|
-
'or_expr',
|
|
37
|
-
'subtraction_expr',
|
|
38
|
-
'union_expr',
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const isBinaryExprNode = (node: AnySyntaxNode): node is AnyBinaryExprNode => {
|
|
42
|
-
return binaryExprNodeTypes.has(node.type as AnyBinaryExprType);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const matchesLocalName = (
|
|
46
|
-
localName: string,
|
|
47
|
-
nameNode: PrefixedNameNode | UnprefixedNameNode
|
|
48
|
-
): boolean => {
|
|
49
|
-
const localPartNode: LocalPartNode | UnprefixedNameNode =
|
|
50
|
-
nameNode.type === 'prefixed_name' ? nameNode.children[1] : nameNode;
|
|
51
|
-
|
|
52
|
-
return localPartNode.text === localName;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const isFunctionCalled = (localName: string, node: AnySyntaxNode): boolean => {
|
|
56
|
-
if (!node.text.includes(localName)) {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (isSingleNodeChild(node)) {
|
|
61
|
-
const [child] = node.children;
|
|
62
|
-
|
|
63
|
-
return isFunctionCalled(localName, child);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (isBinaryExprNode(node)) {
|
|
67
|
-
const [lhs, rhs] = node.children;
|
|
68
|
-
|
|
69
|
-
return isFunctionCalled(localName, lhs) || isFunctionCalled(localName, rhs);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
switch (node.type) {
|
|
73
|
-
// Terminal nodes
|
|
74
|
-
case 'number':
|
|
75
|
-
case 'string_literal':
|
|
76
|
-
case 'variable_reference':
|
|
77
|
-
|
|
78
|
-
// Path sub-nodes which could not have a function call child
|
|
79
|
-
//
|
|
80
|
-
// This only errors because this set of cases is commented:
|
|
81
|
-
// eslint-disable-next-line no-fallthrough
|
|
82
|
-
case '//':
|
|
83
|
-
case 'absolute_root_location_path':
|
|
84
|
-
case 'axis_name':
|
|
85
|
-
case 'node_type_test':
|
|
86
|
-
case 'parent':
|
|
87
|
-
case 'self':
|
|
88
|
-
|
|
89
|
-
// Name nodes are also not function call parents
|
|
90
|
-
//
|
|
91
|
-
// This only errors because this set of cases is commented:
|
|
92
|
-
// eslint-disable-next-line no-fallthrough
|
|
93
|
-
case 'local_part':
|
|
94
|
-
case 'prefixed_name':
|
|
95
|
-
case 'prefix':
|
|
96
|
-
case 'unprefixed_name':
|
|
97
|
-
case 'unprefixed_wildcard_name_test':
|
|
98
|
-
return false;
|
|
99
|
-
|
|
100
|
-
// Path sub-nodes which could have a function call child
|
|
101
|
-
case 'abbreviated_absolute_location_path':
|
|
102
|
-
case 'abbreviated_step':
|
|
103
|
-
case 'absolute_location_path':
|
|
104
|
-
case 'axis_test':
|
|
105
|
-
case 'filter_path_expr':
|
|
106
|
-
case 'relative_location_path':
|
|
107
|
-
case 'step':
|
|
108
|
-
return node.children.some((childNode) => isFunctionCalled(localName, childNode));
|
|
109
|
-
|
|
110
|
-
case 'function_call': {
|
|
111
|
-
const [functionNameNode] = node.children;
|
|
112
|
-
const [nameNode] = functionNameNode.children;
|
|
113
|
-
|
|
114
|
-
return matchesLocalName(localName, nameNode);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
default:
|
|
118
|
-
throw new UnreachableError(node);
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
export const isItextFunctionCalled = (expression: string): boolean => {
|
|
123
|
-
const { rootNode } = expressionParser.parse(expression);
|
|
124
|
-
|
|
125
|
-
return isFunctionCalled('itext', rootNode);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
type LocationPathSubExpressionNode =
|
|
129
|
-
| AbsoluteLocationPathNode
|
|
130
|
-
| FilterPathExprNode
|
|
131
|
-
| RelativeLocationPathNode;
|
|
132
|
-
|
|
133
|
-
const isAnyLocationPathExprNode = (node: AnySyntaxNode): node is LocationPathSubExpressionNode => {
|
|
134
|
-
const { type } = node;
|
|
135
|
-
|
|
136
|
-
if (type === 'absolute_location_path' || type === 'relative_location_path') {
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return false;
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// TODO: this does not currently even attempt to find sub-expressions nested
|
|
144
|
-
// within sub-expressions.
|
|
145
|
-
const findLocationPathExprNodes = (
|
|
146
|
-
node: AnySyntaxNode
|
|
147
|
-
): readonly LocationPathSubExpressionNode[] => {
|
|
148
|
-
const results: LocationPathSubExpressionNode[] = [];
|
|
149
|
-
|
|
150
|
-
if (isAnyLocationPathExprNode(node)) {
|
|
151
|
-
results.push(node);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
results.push(
|
|
155
|
-
...node.children.flatMap((childNode) => {
|
|
156
|
-
return findLocationPathExprNodes(childNode);
|
|
157
|
-
})
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
return results;
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
// TODO: this is a very small subset of resolution that needs to be supported,
|
|
164
|
-
// and it's a hamfisted hack. **This is temporary** to unblock progress on
|
|
165
|
-
// computations, but a longer term solution will need to address:
|
|
166
|
-
//
|
|
167
|
-
// - non-abbreviation axes (parent, child, self) according to XForms spec
|
|
168
|
-
// - non-leading axes
|
|
169
|
-
// - context expressions which are more complex than a series of explicit
|
|
170
|
-
// element name test steps (this may be fine for binds!)
|
|
171
|
-
const resolveRelativeSubExpression = (contextReference: string | null, expression: string) => {
|
|
172
|
-
if (contextReference == null) {
|
|
173
|
-
return expression;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const [, axisAbbreviation, relativeExpression = ''] = expression.match(/^(\.{1,2})(\/.*$)?/) ?? [
|
|
177
|
-
null,
|
|
178
|
-
'',
|
|
179
|
-
expression,
|
|
180
|
-
];
|
|
181
|
-
|
|
182
|
-
switch (axisAbbreviation) {
|
|
183
|
-
case '':
|
|
184
|
-
return expression;
|
|
185
|
-
|
|
186
|
-
case '.':
|
|
187
|
-
return `${contextReference}${relativeExpression}`;
|
|
188
|
-
|
|
189
|
-
case '..':
|
|
190
|
-
return `${contextReference.replace(/\/[^/]+$/, '')}${relativeExpression}`;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
throw new Error(`Unexpected relative expression: ${expression}`);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
interface GetNodesetDependenciesOptions {
|
|
197
|
-
readonly contextReference?: string | null;
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* @default false
|
|
201
|
-
*/
|
|
202
|
-
readonly ignoreContextReference?: boolean;
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Ignores location path sub-expressions whose full text is `null`. While this
|
|
206
|
-
* is technically a valid relative name test step, it seems that real forms in
|
|
207
|
-
* the wild use it as if XPath had an actual `null` token/value.
|
|
208
|
-
*
|
|
209
|
-
* @default true
|
|
210
|
-
*/
|
|
211
|
-
readonly ignoreNullExpressions?: boolean;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export const getNodesetDependencies = (
|
|
215
|
-
expression: string,
|
|
216
|
-
options: GetNodesetDependenciesOptions = {}
|
|
217
|
-
): Set<string> => {
|
|
218
|
-
const { rootNode } = expressionParser.parse(expression);
|
|
219
|
-
const subExpressionNodes = findLocationPathExprNodes(rootNode);
|
|
220
|
-
const {
|
|
221
|
-
contextReference = null,
|
|
222
|
-
ignoreContextReference = false,
|
|
223
|
-
ignoreNullExpressions = true,
|
|
224
|
-
} = options;
|
|
225
|
-
|
|
226
|
-
const subExpressions = subExpressionNodes
|
|
227
|
-
.map((syntaxNode) => resolveRelativeSubExpression(contextReference, syntaxNode.text))
|
|
228
|
-
.filter((subExpression) => {
|
|
229
|
-
if (ignoreContextReference && subExpression === contextReference) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (ignoreNullExpressions && subExpression === 'null') {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return true;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
return new Set(subExpressions);
|
|
241
|
-
};
|