@getodk/xforms-engine 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/client/BaseNode.d.ts +18 -3
- package/dist/client/BaseValueNode.d.ts +32 -0
- package/dist/client/EngineConfig.d.ts +49 -48
- package/dist/client/GroupNode.d.ts +1 -0
- package/dist/client/InputNode.d.ts +82 -0
- package/dist/client/ModelValueNode.d.ts +13 -7
- package/dist/client/NoteNode.d.ts +26 -9
- package/dist/client/RangeNode.d.ts +36 -0
- package/dist/client/RankNode.d.ts +46 -0
- package/dist/client/RootNode.d.ts +37 -7
- package/dist/client/SelectNode.d.ts +47 -25
- package/dist/client/SubtreeNode.d.ts +1 -0
- package/dist/client/TriggerNode.d.ts +10 -6
- package/dist/client/ValueType.d.ts +3 -0
- package/dist/client/constants.d.ts +50 -0
- package/dist/client/hierarchy.d.ts +8 -8
- package/dist/client/identity.d.ts +14 -0
- package/dist/client/node-types.d.ts +3 -2
- package/dist/client/resources.d.ts +93 -0
- package/dist/client/submission/SubmissionData.d.ts +7 -0
- package/dist/client/submission/SubmissionDefinition.d.ts +14 -0
- package/dist/client/submission/SubmissionInstanceFile.d.ts +6 -0
- package/dist/client/submission/SubmissionOptions.d.ts +23 -0
- package/dist/client/submission/SubmissionResult.d.ts +91 -0
- package/dist/client/submission/SubmissionState.d.ts +12 -0
- package/dist/client/unsupported/UnsupportedControlNode.d.ts +1 -3
- package/dist/client/validation.d.ts +2 -2
- package/dist/error/ErrorProductionDesignPendingError.d.ts +7 -0
- package/dist/error/RankMissingValueError.d.ts +3 -0
- package/dist/error/RankValueTypeError.d.ts +6 -0
- package/dist/error/SelectValueTypeError.d.ts +15 -0
- package/dist/error/ValueTypeInvariantError.d.ts +17 -0
- package/dist/error/XFormsSpecViolationError.d.ts +2 -0
- package/dist/error/XPathFunctionalityError.d.ts +14 -0
- package/dist/error/XPathFunctionalityNotSupportedError.d.ts +7 -0
- package/dist/error/XPathFunctionalityPendingError.d.ts +7 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.js +17864 -14655
- package/dist/index.js.map +1 -1
- package/dist/instance/Group.d.ts +10 -4
- package/dist/instance/InputControl.d.ts +38 -0
- package/dist/instance/ModelValue.d.ts +17 -25
- package/dist/instance/Note.d.ts +16 -21
- package/dist/instance/PrimaryInstance.d.ts +85 -0
- package/dist/instance/RangeControl.d.ts +34 -0
- package/dist/instance/RankControl.d.ts +40 -0
- package/dist/instance/Root.d.ts +30 -25
- package/dist/instance/SelectControl.d.ts +66 -0
- package/dist/instance/Subtree.d.ts +11 -5
- package/dist/instance/TriggerControl.d.ts +13 -19
- package/dist/instance/abstract/DescendantNode.d.ts +32 -25
- package/dist/instance/abstract/InstanceNode.d.ts +52 -30
- package/dist/instance/abstract/UnsupportedControl.d.ts +11 -3
- package/dist/instance/abstract/ValueNode.d.ts +47 -0
- package/dist/instance/hierarchy.d.ts +13 -12
- package/dist/instance/identity.d.ts +2 -7
- package/dist/instance/internal-api/EvaluationContext.d.ts +53 -12
- package/dist/instance/internal-api/InstanceConfig.d.ts +8 -2
- package/dist/instance/internal-api/InstanceValueContext.d.ts +22 -0
- package/dist/instance/internal-api/PrimaryInstanceDocument.d.ts +36 -0
- package/dist/instance/internal-api/TranslationContext.d.ts +3 -2
- package/dist/instance/internal-api/ValidationContext.d.ts +3 -4
- package/dist/instance/internal-api/ValueContext.d.ts +2 -1
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableInstance.d.ts +14 -0
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableLeafNode.d.ts +32 -0
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableParentNode.d.ts +19 -0
- package/dist/instance/internal-api/submission/ClientReactiveSubmittableValueNode.d.ts +18 -0
- package/dist/instance/repeat/BaseRepeatRange.d.ts +40 -83
- package/dist/instance/repeat/RepeatInstance.d.ts +12 -29
- package/dist/instance/repeat/RepeatRangeControlled.d.ts +2 -2
- package/dist/instance/repeat/RepeatRangeUncontrolled.d.ts +2 -2
- package/dist/instance/resource.d.ts +1 -1
- package/dist/instance/text/TextRange.d.ts +1 -1
- package/dist/instance/unsupported/UploadControl.d.ts +3 -1
- package/dist/integration/xpath/EngineXPathEvaluator.d.ts +14 -0
- package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +71 -0
- package/dist/integration/xpath/adapter/engineDOMAdapter.d.ts +5 -0
- package/dist/integration/xpath/adapter/kind.d.ts +32 -0
- package/dist/integration/xpath/adapter/names.d.ts +6 -0
- package/dist/integration/xpath/adapter/traversal.d.ts +26 -0
- package/dist/integration/xpath/adapter/values.d.ts +2 -0
- package/dist/integration/xpath/static-dom/StaticAttribute.d.ts +26 -0
- package/dist/integration/xpath/static-dom/StaticDocument.d.ts +15 -0
- package/dist/integration/xpath/static-dom/StaticElement.d.ts +48 -0
- package/dist/integration/xpath/static-dom/StaticNode.d.ts +33 -0
- package/dist/integration/xpath/static-dom/StaticText.d.ts +16 -0
- package/dist/lib/client-reactivity/submission/createInstanceSubmissionState.d.ts +3 -0
- package/dist/lib/client-reactivity/submission/createLeafNodeSubmissionState.d.ts +3 -0
- package/dist/lib/client-reactivity/submission/createNodeRangeSubmissionState.d.ts +4 -0
- package/dist/lib/client-reactivity/submission/createParentNodeSubmissionState.d.ts +4 -0
- package/dist/lib/client-reactivity/submission/createRootSubmissionState.d.ts +3 -0
- package/dist/lib/client-reactivity/submission/createValueNodeSubmissionState.d.ts +3 -0
- package/dist/lib/client-reactivity/submission/prepareSubmission.d.ts +8 -0
- package/dist/lib/codecs/DecimalValueCodec.d.ts +6 -0
- package/dist/lib/codecs/Geopoint/Geopoint.d.ts +48 -0
- package/dist/lib/codecs/Geopoint/GeopointValueCodec.d.ts +5 -0
- package/dist/lib/codecs/IntValueCodec.d.ts +6 -0
- package/dist/lib/codecs/NoteCodec.d.ts +8 -0
- package/dist/lib/codecs/RangeCodec.d.ts +8 -0
- package/dist/lib/codecs/StringValueCodec.d.ts +4 -0
- package/dist/lib/codecs/TriggerCodec.d.ts +7 -0
- package/dist/lib/codecs/ValueArrayCodec.d.ts +11 -0
- package/dist/lib/codecs/ValueCodec.d.ts +30 -0
- package/dist/lib/codecs/ValueTypePlaceholderCodec.d.ts +12 -0
- package/dist/lib/codecs/getNoteCodec.d.ts +3 -0
- package/dist/lib/codecs/getSelectCodec.d.ts +5 -0
- package/dist/lib/codecs/getSharedValueCodec.d.ts +48 -0
- package/dist/lib/codecs/items/BaseItemCodec.d.ts +9 -0
- package/dist/lib/codecs/items/MultipleValueItemCodec.d.ts +14 -0
- package/dist/lib/codecs/items/SingleValueItemCodec.d.ts +24 -0
- package/dist/lib/dom/query.d.ts +4 -2
- package/dist/lib/names/NamespaceDeclaration.d.ts +45 -0
- package/dist/lib/names/NamespaceDeclarationMap.d.ts +137 -0
- package/dist/lib/names/NamespaceURL.d.ts +30 -0
- package/dist/lib/names/QualifiedName.d.ts +113 -0
- package/dist/lib/number-parsers.d.ts +2 -0
- package/dist/lib/reactivity/createChildrenState.d.ts +7 -5
- package/dist/lib/reactivity/createComputedExpression.d.ts +18 -5
- package/dist/lib/reactivity/createInstanceValueState.d.ts +40 -0
- package/dist/lib/reactivity/createItemCollection.d.ts +21 -0
- package/dist/lib/reactivity/createNoteReadonlyThunk.d.ts +2 -2
- package/dist/lib/reactivity/createTranslationState.d.ts +19 -0
- package/dist/lib/reactivity/createValueState.d.ts +6 -10
- package/dist/lib/reactivity/materializeCurrentStateChildren.d.ts +4 -4
- package/dist/lib/xml-serialization.d.ts +50 -0
- package/dist/parse/XFormDOM.d.ts +18 -7
- package/dist/parse/XFormDefinition.d.ts +1 -2
- package/dist/parse/attachments/FormAttachmentResource.d.ts +27 -0
- package/dist/parse/body/BodyDefinition.d.ts +4 -4
- package/dist/parse/body/RepeatElementDefinition.d.ts +1 -1
- package/dist/parse/body/appearance/inputAppearanceParser.d.ts +1 -1
- package/dist/parse/body/appearance/rangeAppearanceParser.d.ts +3 -0
- package/dist/parse/body/control/{InputDefinition.d.ts → InputControlDefinition.d.ts} +4 -1
- package/dist/parse/body/control/ItemDefinition.d.ts +14 -0
- package/dist/parse/body/control/ItemsetDefinition.d.ts +18 -0
- package/dist/parse/body/control/RangeControlDefinition.d.ts +31 -2
- package/dist/parse/body/control/RankControlDefinition.d.ts +7 -3
- package/dist/parse/body/control/{select/SelectDefinition.d.ts → SelectControlDefinition.d.ts} +9 -9
- package/dist/parse/expression/ItemsetNodesetExpression.d.ts +1 -1
- package/dist/parse/expression/ItemsetValueExpression.d.ts +1 -1
- package/dist/parse/expression/abstract/DependencyContext.d.ts +0 -5
- package/dist/parse/expression/abstract/DependentExpression.d.ts +2 -3
- package/dist/parse/model/BindDefinition.d.ts +6 -5
- package/dist/parse/model/BindPreloadDefinition.d.ts +42 -0
- package/dist/parse/model/BindTypeDefinition.d.ts +20 -0
- package/dist/parse/model/DescendentNodeDefinition.d.ts +4 -14
- package/dist/parse/model/FormSubmissionDefinition.d.ts +8 -0
- package/dist/parse/model/ItextTranslation/ItextTranslationDefinition.d.ts +4 -0
- package/dist/parse/model/ItextTranslation/ItextTranslationRootDefinition.d.ts +9 -0
- package/dist/parse/model/ItextTranslation/ItextTranslationsDefinition.d.ts +8 -0
- package/dist/parse/model/LeafNodeDefinition.d.ts +9 -4
- package/dist/parse/model/ModelBindMap.d.ts +1 -1
- package/dist/parse/model/ModelDefinition.d.ts +2 -0
- package/dist/parse/model/NodeDefinition.d.ts +16 -20
- package/dist/parse/model/NoteNodeDefinition.d.ts +9 -8
- package/dist/parse/model/RangeNodeDefinition.d.ts +41 -0
- package/dist/parse/model/RepeatInstanceDefinition.d.ts +7 -4
- package/dist/parse/model/RepeatRangeDefinition.d.ts +7 -4
- package/dist/parse/model/RepeatTemplateDefinition.d.ts +7 -4
- package/dist/parse/model/RootAttributeDefinition.d.ts +24 -0
- package/dist/parse/model/RootAttributeMap.d.ts +23 -0
- package/dist/parse/model/RootDefinition.d.ts +12 -9
- package/dist/parse/model/SecondaryInstance/SecondaryInstanceDefinition.d.ts +4 -0
- package/dist/parse/model/SecondaryInstance/SecondaryInstanceRootDefinition.d.ts +7 -0
- package/dist/parse/model/SecondaryInstance/SecondaryInstancesDefinition.d.ts +13 -0
- package/dist/parse/model/SecondaryInstance/sources/BlankSecondaryInstanceSource.d.ts +14 -0
- package/dist/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.d.ts +22 -0
- package/dist/parse/model/SecondaryInstance/sources/ExternalSecondaryInstanceResource.d.ts +23 -0
- package/dist/parse/model/SecondaryInstance/sources/ExternalSecondaryInstanceSource.d.ts +9 -0
- package/dist/parse/model/SecondaryInstance/sources/GeoJSONExternalSecondaryInstance.d.ts +5 -0
- package/dist/parse/model/SecondaryInstance/sources/InternalSecondaryInstanceSource.d.ts +7 -0
- package/dist/parse/model/SecondaryInstance/sources/SecondaryInstanceSource.d.ts +13 -0
- package/dist/parse/model/SecondaryInstance/sources/XMLExternalSecondaryInstanceSource.d.ts +12 -0
- package/dist/parse/model/SubtreeDefinition.d.ts +7 -4
- package/dist/parse/shared/parseStaticDocumentFromDOMSubtree.d.ts +23 -0
- package/dist/parse/text/ItemLabelDefinition.d.ts +1 -1
- package/dist/parse/text/ItemsetLabelDefinition.d.ts +2 -2
- package/dist/parse/text/abstract/TextElementDefinition.d.ts +1 -1
- package/dist/parse/text/abstract/TextRangeDefinition.d.ts +0 -2
- package/dist/parse/xpath/semantic-analysis.d.ts +6 -3
- package/dist/solid.js +15437 -12246
- package/dist/solid.js.map +1 -1
- package/package.json +18 -13
- package/src/client/BaseNode.ts +21 -6
- package/src/client/BaseValueNode.ts +35 -0
- package/src/client/EngineConfig.ts +52 -51
- package/src/client/GroupNode.ts +1 -0
- package/src/client/InputNode.ts +113 -0
- package/src/client/ModelValueNode.ts +31 -7
- package/src/client/NoteNode.ts +45 -9
- package/src/client/RangeNode.ts +51 -0
- package/src/client/RankNode.ts +54 -0
- package/src/client/RootNode.ts +43 -7
- package/src/client/SelectNode.ts +53 -26
- package/src/client/SubtreeNode.ts +1 -0
- package/src/client/TriggerNode.ts +12 -6
- package/src/client/ValueType.ts +4 -0
- package/src/client/constants.ts +67 -0
- package/src/client/hierarchy.ts +12 -13
- package/src/client/identity.ts +16 -0
- package/src/client/node-types.ts +13 -7
- package/src/client/resources.ts +118 -0
- package/src/client/submission/SubmissionData.ts +12 -0
- package/src/client/submission/SubmissionDefinition.ts +16 -0
- package/src/client/submission/SubmissionInstanceFile.ts +9 -0
- package/src/client/submission/SubmissionOptions.ts +28 -0
- package/src/client/submission/SubmissionResult.ts +124 -0
- package/src/client/submission/SubmissionState.ts +14 -0
- package/src/client/unsupported/UnsupportedControlNode.ts +2 -6
- package/src/client/validation.ts +2 -2
- package/src/error/ErrorProductionDesignPendingError.ts +6 -0
- package/src/error/RankMissingValueError.ts +5 -0
- package/src/error/RankValueTypeError.ts +13 -0
- package/src/error/SelectValueTypeError.ts +22 -0
- package/src/error/ValueTypeInvariantError.ts +22 -0
- package/src/error/XFormsSpecViolationError.ts +1 -0
- package/src/error/XPathFunctionalityError.ts +26 -0
- package/src/error/XPathFunctionalityNotSupportedError.ts +18 -0
- package/src/error/XPathFunctionalityPendingError.ts +18 -0
- package/src/index.ts +12 -13
- package/src/instance/Group.ts +18 -5
- package/src/instance/InputControl.ts +159 -0
- package/src/instance/ModelValue.ts +48 -53
- package/src/instance/Note.ts +40 -49
- package/src/instance/PrimaryInstance.ts +245 -0
- package/src/instance/RangeControl.ts +113 -0
- package/src/instance/RankControl.ts +199 -0
- package/src/instance/Root.ts +63 -134
- package/src/instance/SelectControl.ts +219 -0
- package/src/instance/Subtree.ts +20 -7
- package/src/instance/TriggerControl.ts +44 -66
- package/src/instance/abstract/DescendantNode.ts +91 -51
- package/src/instance/abstract/InstanceNode.ts +113 -107
- package/src/instance/abstract/UnsupportedControl.ts +29 -5
- package/src/instance/abstract/ValueNode.ts +128 -0
- package/src/instance/children.ts +80 -40
- package/src/instance/hierarchy.ts +39 -30
- package/src/instance/identity.ts +3 -9
- package/src/instance/index.ts +25 -7
- package/src/instance/internal-api/EvaluationContext.ts +60 -13
- package/src/instance/internal-api/InstanceConfig.ts +9 -2
- package/src/instance/internal-api/InstanceValueContext.ts +26 -0
- package/src/instance/internal-api/PrimaryInstanceDocument.ts +53 -0
- package/src/instance/internal-api/TranslationContext.ts +3 -2
- package/src/instance/internal-api/ValidationContext.ts +3 -4
- package/src/instance/internal-api/ValueContext.ts +2 -1
- package/src/instance/internal-api/submission/ClientReactiveSubmittableInstance.ts +20 -0
- package/src/instance/internal-api/submission/ClientReactiveSubmittableLeafNode.ts +43 -0
- package/src/instance/internal-api/submission/ClientReactiveSubmittableParentNode.ts +26 -0
- package/src/instance/internal-api/submission/ClientReactiveSubmittableValueNode.ts +24 -0
- package/src/instance/repeat/BaseRepeatRange.ts +52 -131
- package/src/instance/repeat/RepeatInstance.ts +21 -46
- package/src/instance/repeat/RepeatRangeControlled.ts +5 -5
- package/src/instance/repeat/RepeatRangeUncontrolled.ts +2 -4
- package/src/instance/resource.ts +5 -2
- package/src/instance/text/TextChunk.ts +1 -1
- package/src/instance/unsupported/UploadControl.ts +5 -1
- package/src/integration/xpath/EngineXPathEvaluator.ts +22 -0
- package/src/integration/xpath/adapter/XFormsXPathNode.ts +126 -0
- package/src/integration/xpath/adapter/engineDOMAdapter.ts +57 -0
- package/src/integration/xpath/adapter/kind.ts +114 -0
- package/src/integration/xpath/adapter/names.ts +148 -0
- package/src/integration/xpath/adapter/traversal.ts +229 -0
- package/src/integration/xpath/adapter/values.ts +5 -0
- package/src/integration/xpath/static-dom/StaticAttribute.ts +41 -0
- package/src/integration/xpath/static-dom/StaticDocument.ts +36 -0
- package/src/integration/xpath/static-dom/StaticElement.ts +119 -0
- package/src/integration/xpath/static-dom/StaticNode.ts +68 -0
- package/src/integration/xpath/static-dom/StaticText.ts +28 -0
- package/src/lib/client-reactivity/README.md +0 -0
- package/src/lib/client-reactivity/submission/createInstanceSubmissionState.ts +12 -0
- package/src/lib/client-reactivity/submission/createLeafNodeSubmissionState.ts +20 -0
- package/src/lib/client-reactivity/submission/createNodeRangeSubmissionState.ts +17 -0
- package/src/lib/client-reactivity/submission/createParentNodeSubmissionState.ts +22 -0
- package/src/lib/client-reactivity/submission/createRootSubmissionState.ts +19 -0
- package/src/lib/client-reactivity/submission/createValueNodeSubmissionState.ts +21 -0
- package/src/lib/client-reactivity/submission/prepareSubmission.ts +172 -0
- package/src/lib/codecs/DecimalValueCodec.ts +46 -0
- package/src/lib/codecs/Geopoint/Geopoint.ts +150 -0
- package/src/lib/codecs/Geopoint/GeopointValueCodec.ts +20 -0
- package/src/lib/codecs/IntValueCodec.ts +100 -0
- package/src/lib/codecs/NoteCodec.ts +32 -0
- package/src/lib/codecs/RangeCodec.ts +65 -0
- package/src/lib/codecs/StringValueCodec.ts +11 -0
- package/src/lib/codecs/TriggerCodec.ts +64 -0
- package/src/lib/codecs/ValueArrayCodec.ts +42 -0
- package/src/lib/codecs/ValueCodec.ts +106 -0
- package/src/lib/codecs/ValueTypePlaceholderCodec.ts +19 -0
- package/src/lib/codecs/getNoteCodec.ts +27 -0
- package/src/lib/codecs/getSelectCodec.ts +27 -0
- package/src/lib/codecs/getSharedValueCodec.ts +79 -0
- package/src/lib/codecs/items/BaseItemCodec.ts +20 -0
- package/src/lib/codecs/items/MultipleValueItemCodec.ts +28 -0
- package/src/lib/codecs/items/SingleValueItemCodec.ts +67 -0
- package/src/lib/dom/query.ts +8 -2
- package/src/lib/names/NamespaceDeclaration.ts +106 -0
- package/src/lib/names/NamespaceDeclarationMap.ts +228 -0
- package/src/lib/names/NamespaceURL.ts +44 -0
- package/src/lib/names/QualifiedName.ts +170 -0
- package/src/lib/number-parsers.ts +25 -0
- package/src/lib/reactivity/createChildrenState.ts +8 -6
- package/src/lib/reactivity/createComputedExpression.ts +57 -34
- package/src/lib/reactivity/createInstanceValueState.ts +216 -0
- package/src/lib/reactivity/createItemCollection.ts +173 -0
- package/src/lib/reactivity/createNoteReadonlyThunk.ts +12 -7
- package/src/lib/reactivity/createTranslationState.ts +61 -0
- package/src/lib/reactivity/createValueState.ts +62 -120
- package/src/lib/reactivity/materializeCurrentStateChildren.ts +7 -7
- package/src/lib/reactivity/text/createTextRange.ts +4 -3
- package/src/lib/reactivity/validation/createAggregatedViolations.ts +1 -1
- package/src/lib/reactivity/validation/createValidation.ts +2 -3
- package/src/lib/xml-serialization.ts +163 -0
- package/src/parse/XFormDOM.ts +231 -76
- package/src/parse/XFormDefinition.ts +2 -10
- package/src/parse/attachments/FormAttachmentResource.ts +40 -0
- package/src/parse/body/BodyDefinition.ts +7 -7
- package/src/parse/body/appearance/inputAppearanceParser.ts +1 -1
- package/src/parse/body/appearance/rangeAppearanceParser.ts +11 -0
- package/src/parse/body/control/InputControlDefinition.ts +29 -0
- package/src/parse/body/control/{select/ItemDefinition.ts → ItemDefinition.ts} +8 -6
- package/src/parse/body/control/{select/ItemsetDefinition.ts → ItemsetDefinition.ts} +11 -9
- package/src/parse/body/control/RangeControlDefinition.ts +91 -6
- package/src/parse/body/control/RankControlDefinition.ts +25 -7
- package/src/parse/body/control/{select/SelectDefinition.ts → SelectControlDefinition.ts} +9 -9
- package/src/parse/expression/ItemsetNodesetExpression.ts +1 -1
- package/src/parse/expression/ItemsetValueExpression.ts +1 -1
- package/src/parse/expression/abstract/DependencyContext.ts +0 -26
- package/src/parse/expression/abstract/DependentExpression.ts +2 -13
- package/src/parse/model/BindDefinition.ts +9 -8
- package/src/parse/model/BindPreloadDefinition.ts +100 -0
- package/src/parse/model/BindTypeDefinition.ts +175 -0
- package/src/parse/model/DescendentNodeDefinition.ts +7 -31
- package/src/parse/model/FormSubmissionDefinition.ts +44 -0
- package/src/parse/model/ItextTranslation/ItextTranslationDefinition.ts +4 -0
- package/src/parse/model/ItextTranslation/ItextTranslationRootDefinition.ts +42 -0
- package/src/parse/model/ItextTranslation/ItextTranslationsDefinition.ts +31 -0
- package/src/parse/model/LeafNodeDefinition.ts +15 -5
- package/src/parse/model/ModelBindMap.ts +6 -8
- package/src/parse/model/ModelDefinition.ts +6 -1
- package/src/parse/model/NodeDefinition.ts +24 -48
- package/src/parse/model/NoteNodeDefinition.ts +11 -10
- package/src/parse/model/RangeNodeDefinition.ts +118 -0
- package/src/parse/model/RepeatInstanceDefinition.ts +11 -7
- package/src/parse/model/RepeatRangeDefinition.ts +11 -7
- package/src/parse/model/RepeatTemplateDefinition.ts +11 -7
- package/src/parse/model/RootAttributeDefinition.ts +45 -0
- package/src/parse/model/RootAttributeMap.ts +44 -0
- package/src/parse/model/RootDefinition.ts +31 -29
- package/src/parse/model/SecondaryInstance/SecondaryInstanceDefinition.ts +4 -0
- package/src/parse/model/SecondaryInstance/SecondaryInstanceRootDefinition.ts +12 -0
- package/src/parse/model/SecondaryInstance/SecondaryInstancesDefinition.ts +102 -0
- package/src/parse/model/SecondaryInstance/sources/BlankSecondaryInstanceSource.ts +40 -0
- package/src/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.ts +288 -0
- package/src/parse/model/SecondaryInstance/sources/ExternalSecondaryInstanceResource.ts +222 -0
- package/src/parse/model/SecondaryInstance/sources/ExternalSecondaryInstanceSource.ts +22 -0
- package/src/parse/model/SecondaryInstance/sources/GeoJSONExternalSecondaryInstance.ts +415 -0
- package/src/parse/model/SecondaryInstance/sources/InternalSecondaryInstanceSource.ts +19 -0
- package/src/parse/model/SecondaryInstance/sources/SecondaryInstanceSource.ts +29 -0
- package/src/parse/model/SecondaryInstance/sources/XMLExternalSecondaryInstanceSource.ts +32 -0
- package/src/parse/model/SubtreeDefinition.ts +12 -12
- package/src/parse/shared/parseStaticDocumentFromDOMSubtree.ts +149 -0
- package/src/parse/text/ItemLabelDefinition.ts +1 -1
- package/src/parse/text/ItemsetLabelDefinition.ts +2 -2
- package/src/parse/text/abstract/TextElementDefinition.ts +1 -1
- package/src/parse/text/abstract/TextRangeDefinition.ts +0 -6
- package/src/parse/xpath/semantic-analysis.ts +33 -3
- package/dist/client/StringNode.d.ts +0 -46
- package/dist/client/unsupported/RangeNode.d.ts +0 -9
- package/dist/client/unsupported/RankNode.d.ts +0 -9
- package/dist/instance/SelectField.d.ts +0 -50
- package/dist/instance/StringField.d.ts +0 -44
- package/dist/instance/internal-api/SubscribableDependency.d.ts +0 -59
- package/dist/instance/unsupported/RangeControl.d.ts +0 -4
- package/dist/instance/unsupported/RankControl.d.ts +0 -4
- package/dist/lib/reactivity/createSelectItems.d.ts +0 -16
- package/dist/parse/XFormDataType.d.ts +0 -25
- package/dist/parse/body/control/select/ItemDefinition.d.ts +0 -13
- package/dist/parse/body/control/select/ItemsetDefinition.d.ts +0 -17
- package/dist/parse/body/control/select/ItemsetNodesetContext.d.ts +0 -11
- package/src/client/StringNode.ts +0 -52
- package/src/client/unsupported/RangeNode.ts +0 -14
- package/src/client/unsupported/RankNode.ts +0 -14
- package/src/instance/SelectField.ts +0 -226
- package/src/instance/StringField.ts +0 -120
- package/src/instance/internal-api/SubscribableDependency.ts +0 -61
- package/src/instance/unsupported/RangeControl.ts +0 -5
- package/src/instance/unsupported/RankControl.ts +0 -5
- package/src/lib/reactivity/createSelectItems.ts +0 -168
- package/src/parse/XFormDataType.ts +0 -62
- package/src/parse/body/control/InputDefinition.ts +0 -22
- package/src/parse/body/control/select/ItemsetNodesetContext.ts +0 -26
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { NamespaceDeclarationMap } from './names/NamespaceDeclarationMap.ts';
|
|
2
|
+
import type { QualifiedName } from './names/QualifiedName.ts';
|
|
3
|
+
|
|
4
|
+
declare const ESCAPED_XML_TEXT_BRAND: unique symbol;
|
|
5
|
+
|
|
6
|
+
export type EscapedXMLText = string & { readonly [ESCAPED_XML_TEXT_BRAND]: true };
|
|
7
|
+
|
|
8
|
+
const ATTR_REGEX = /[&<>"]/;
|
|
9
|
+
const CONTENT_REGEX = /[&<>]/;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This is based on the `escapeHTML` implementation in
|
|
13
|
+
* {@link https://github.com/ryansolid/dom-expressions} (Solid's JSX transform).
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://github.com/ryansolid/dom-expressions/pull/27} for
|
|
16
|
+
* motivation to derive this implementation approach.
|
|
17
|
+
*
|
|
18
|
+
* The intent is that this can be updated easily if the base implementation
|
|
19
|
+
* changes. As such, some aspects of this implementation differ from some of our
|
|
20
|
+
* typical code style preferences.
|
|
21
|
+
*
|
|
22
|
+
* Notable changes from the base implementation:
|
|
23
|
+
*
|
|
24
|
+
* - Formatting: automated only.
|
|
25
|
+
* - Naming: the {@link text} parameter is named `html` in the base
|
|
26
|
+
* implementation. That would be confusing if preserved.
|
|
27
|
+
* - Types:
|
|
28
|
+
* - Parameter types are added (of course)
|
|
29
|
+
* - Return type is branded as {@link EscapedXMLText}, to allow downstream
|
|
30
|
+
* checks that escaping has been performed. Return statements are cast
|
|
31
|
+
* accordingly.
|
|
32
|
+
* - {@link text} attempts to minimize risk of double-escaping by excluding
|
|
33
|
+
* that same branded type.
|
|
34
|
+
* - The '>' character is also escaped, necessary for producing valid XML.
|
|
35
|
+
*
|
|
36
|
+
* As with the base implementation, we leave some characters unescaped:
|
|
37
|
+
*
|
|
38
|
+
* - " (double quote): except when {@link attr} is `true`.
|
|
39
|
+
*
|
|
40
|
+
* - ' (single quote): on the assumption that attributes are always serialized
|
|
41
|
+
* in double quotes. If we ever move this to `@getodk/common`, we'd want to
|
|
42
|
+
* reconsider this assumption.
|
|
43
|
+
*/
|
|
44
|
+
export const escapeXMLText = <Text extends string>(
|
|
45
|
+
text: Exclude<Text, EscapedXMLText>,
|
|
46
|
+
attr?: boolean
|
|
47
|
+
): EscapedXMLText => {
|
|
48
|
+
const match = (attr ? ATTR_REGEX : CONTENT_REGEX).exec(text);
|
|
49
|
+
if (!match) return text as string as EscapedXMLText;
|
|
50
|
+
let index = 0;
|
|
51
|
+
let lastIndex = 0;
|
|
52
|
+
let out = '';
|
|
53
|
+
let escape = '';
|
|
54
|
+
for (index = match.index; index < text.length; index++) {
|
|
55
|
+
switch (text.charCodeAt(index)) {
|
|
56
|
+
case 34: // "
|
|
57
|
+
if (!attr) continue;
|
|
58
|
+
escape = '"';
|
|
59
|
+
break;
|
|
60
|
+
case 38: // &
|
|
61
|
+
escape = '&';
|
|
62
|
+
break;
|
|
63
|
+
case 60: // <
|
|
64
|
+
escape = '<';
|
|
65
|
+
break;
|
|
66
|
+
case 62: // >
|
|
67
|
+
escape = '>';
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (lastIndex !== index) out += text.substring(lastIndex, index);
|
|
73
|
+
lastIndex = index + 1;
|
|
74
|
+
out += escape;
|
|
75
|
+
}
|
|
76
|
+
return lastIndex !== index
|
|
77
|
+
? ((out + text.substring(lastIndex, index)) as EscapedXMLText)
|
|
78
|
+
: (out as EscapedXMLText);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
interface SerializableElementAttribute {
|
|
82
|
+
serializeAttributeXML(): string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface ElementXMLSerializationOptions {
|
|
86
|
+
readonly namespaceDeclarations?: NamespaceDeclarationMap;
|
|
87
|
+
readonly attributes?: readonly SerializableElementAttribute[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const serializeElementNamespaceDeclarationXML = (
|
|
91
|
+
namespaceDeclarations?: NamespaceDeclarationMap
|
|
92
|
+
): string => {
|
|
93
|
+
if (namespaceDeclarations == null) {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return Array.from(namespaceDeclarations.values())
|
|
98
|
+
.map((namespaceDeclaration) => {
|
|
99
|
+
return namespaceDeclaration.serializeNamespaceDeclarationXML({
|
|
100
|
+
omitDefaultNamespace: true,
|
|
101
|
+
});
|
|
102
|
+
})
|
|
103
|
+
.join('');
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const serializeElementAttributeXML = (
|
|
107
|
+
attributes?: readonly SerializableElementAttribute[]
|
|
108
|
+
): string => {
|
|
109
|
+
if (attributes == null) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return attributes
|
|
114
|
+
.map((attribute) => {
|
|
115
|
+
return attribute.serializeAttributeXML();
|
|
116
|
+
})
|
|
117
|
+
.join('');
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const serializeElementXML = (
|
|
121
|
+
qualifiedName: QualifiedName,
|
|
122
|
+
children: string,
|
|
123
|
+
options: ElementXMLSerializationOptions = {}
|
|
124
|
+
): string => {
|
|
125
|
+
// See JSDoc for the `getPrefixedName` method. If we find we do actually need
|
|
126
|
+
// custom element (subtree) prefix resolution, we'd uncomment the argument
|
|
127
|
+
// below. (Either way, at time of writing the affected tests pass where
|
|
128
|
+
// expected when the option is passed. It's omitted on the presumption that it
|
|
129
|
+
// would be redundant, since the nodes being serialized are already resolved
|
|
130
|
+
// with the same set of namespace declarations which would affect them.)
|
|
131
|
+
//
|
|
132
|
+
// prettier-ignore
|
|
133
|
+
const nodeName = qualifiedName.getPrefixedName(
|
|
134
|
+
// options.namespaceDeclarations
|
|
135
|
+
);
|
|
136
|
+
const namespaceDeclarations = serializeElementNamespaceDeclarationXML(
|
|
137
|
+
options.namespaceDeclarations
|
|
138
|
+
);
|
|
139
|
+
const attributes = serializeElementAttributeXML(options.attributes);
|
|
140
|
+
const prefix = `<${nodeName}${namespaceDeclarations}${attributes}`;
|
|
141
|
+
|
|
142
|
+
if (children === '') {
|
|
143
|
+
return `${prefix}/>`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return `${prefix}>${children}</${nodeName}>`;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const serializeParentElementXML = (
|
|
150
|
+
qualifiedName: QualifiedName,
|
|
151
|
+
serializedChildren: readonly string[],
|
|
152
|
+
options?: ElementXMLSerializationOptions
|
|
153
|
+
): string => {
|
|
154
|
+
return serializeElementXML(qualifiedName, serializedChildren.join(''), options);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const serializeLeafElementXML = (
|
|
158
|
+
qualifiedName: QualifiedName,
|
|
159
|
+
xmlValue: EscapedXMLText,
|
|
160
|
+
options?: ElementXMLSerializationOptions
|
|
161
|
+
): string => {
|
|
162
|
+
return serializeElementXML(qualifiedName, xmlValue.normalize(), options);
|
|
163
|
+
};
|
package/src/parse/XFormDOM.ts
CHANGED
|
@@ -1,5 +1,154 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
JAVAROSA_NAMESPACE_URI,
|
|
3
|
+
OPENROSA_XFORMS_NAMESPACE_URI,
|
|
4
|
+
XFORMS_NAMESPACE_URI,
|
|
5
|
+
XMLNS_NAMESPACE_URI,
|
|
6
|
+
} from '@getodk/common/constants/xmlns.ts';
|
|
7
|
+
import type {
|
|
8
|
+
KnownAttributeLocalNamedElement,
|
|
9
|
+
LocalNamedElement,
|
|
10
|
+
} from '@getodk/common/types/dom.ts';
|
|
11
|
+
import { DefaultEvaluator } from '@getodk/xpath';
|
|
12
|
+
|
|
13
|
+
interface DOMBindElement extends KnownAttributeLocalNamedElement<'bind', 'nodeset'> {}
|
|
14
|
+
|
|
15
|
+
const getMetaElement = (primaryInstanceRoot: Element): Element | null => {
|
|
16
|
+
for (const child of primaryInstanceRoot.children) {
|
|
17
|
+
const { localName, namespaceURI } = child;
|
|
18
|
+
|
|
19
|
+
if (
|
|
20
|
+
(namespaceURI === OPENROSA_XFORMS_NAMESPACE_URI || namespaceURI === XFORMS_NAMESPACE_URI) &&
|
|
21
|
+
localName === 'meta'
|
|
22
|
+
) {
|
|
23
|
+
return child;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const getMetaChildElement = (meta: Element | null, localName: string): Element | null => {
|
|
31
|
+
if (meta == null) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { namespaceURI } = meta;
|
|
36
|
+
|
|
37
|
+
for (const child of meta.children) {
|
|
38
|
+
if (child.localName === localName && child.namespaceURI === namespaceURI) {
|
|
39
|
+
return child;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const getQualifiedName = (
|
|
47
|
+
contextNode: Node,
|
|
48
|
+
namespaceURI: string | null,
|
|
49
|
+
localName: string
|
|
50
|
+
): string => {
|
|
51
|
+
const prefix = contextNode.lookupPrefix(namespaceURI);
|
|
52
|
+
|
|
53
|
+
if (prefix == null) {
|
|
54
|
+
return localName;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return `${prefix}:${localName}`;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const createNamespacedChildElement = (
|
|
61
|
+
parent: Element,
|
|
62
|
+
namespaceURI: string | null,
|
|
63
|
+
localName: string
|
|
64
|
+
): Element => {
|
|
65
|
+
const qualifiedName = getQualifiedName(parent, namespaceURI, localName);
|
|
66
|
+
const child = parent.ownerDocument.createElementNS(namespaceURI, qualifiedName);
|
|
67
|
+
|
|
68
|
+
parent.append(child);
|
|
69
|
+
|
|
70
|
+
return child;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const setNamespacedAttributeValue = (
|
|
74
|
+
element: Element,
|
|
75
|
+
namespaceURI: string | null,
|
|
76
|
+
localName: string,
|
|
77
|
+
value: string
|
|
78
|
+
) => {
|
|
79
|
+
const qualifiedName = getQualifiedName(element, namespaceURI, localName);
|
|
80
|
+
|
|
81
|
+
element.setAttributeNS(namespaceURI, qualifiedName, value);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const createDefaultInstanceIDBinding = (
|
|
85
|
+
model: Element,
|
|
86
|
+
primaryInstanceRoot: Element,
|
|
87
|
+
meta: Element,
|
|
88
|
+
instanceID: Element
|
|
89
|
+
): DOMBindElement => {
|
|
90
|
+
const bind = createNamespacedChildElement(model, model.namespaceURI, 'bind');
|
|
91
|
+
const nodeset = `/${primaryInstanceRoot.nodeName}/${meta.nodeName}/${instanceID.nodeName}`;
|
|
92
|
+
|
|
93
|
+
bind.setAttribute('nodeset', nodeset);
|
|
94
|
+
setNamespacedAttributeValue(bind, JAVAROSA_NAMESPACE_URI, 'preload', 'uid');
|
|
95
|
+
|
|
96
|
+
return bind as DOMBindElement;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const normalizeDefaultMetaBindings = (
|
|
100
|
+
model: Element,
|
|
101
|
+
primaryInstanceRoot: Element,
|
|
102
|
+
binds: readonly DOMBindElement[]
|
|
103
|
+
): readonly DOMBindElement[] => {
|
|
104
|
+
let meta = getMetaElement(primaryInstanceRoot);
|
|
105
|
+
let instanceID = getMetaChildElement(meta, 'instanceID');
|
|
106
|
+
|
|
107
|
+
if (meta == null) {
|
|
108
|
+
meta = createNamespacedChildElement(primaryInstanceRoot, OPENROSA_XFORMS_NAMESPACE_URI, 'meta');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (instanceID == null) {
|
|
112
|
+
instanceID = createNamespacedChildElement(meta, meta.namespaceURI, 'instanceID');
|
|
113
|
+
|
|
114
|
+
const instanceIDBinding = createDefaultInstanceIDBinding(
|
|
115
|
+
model,
|
|
116
|
+
primaryInstanceRoot,
|
|
117
|
+
meta,
|
|
118
|
+
instanceID
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return [...binds, instanceIDBinding];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return binds;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export interface DOMItextTranslationElement
|
|
128
|
+
extends KnownAttributeLocalNamedElement<'translation', 'lang'> {}
|
|
129
|
+
|
|
130
|
+
interface DOMInstanceElement extends LocalNamedElement<'instance'> {}
|
|
131
|
+
|
|
132
|
+
export interface DOMSecondaryInstanceElement
|
|
133
|
+
extends KnownAttributeLocalNamedElement<'instance', 'id'> {}
|
|
134
|
+
|
|
135
|
+
type AssertDOMSecondaryInstanceElement = (
|
|
136
|
+
element: DOMInstanceElement
|
|
137
|
+
) => asserts element is DOMSecondaryInstanceElement;
|
|
138
|
+
|
|
139
|
+
const assertDOMSecondaryInstanceElement: AssertDOMSecondaryInstanceElement = (element) => {
|
|
140
|
+
if (!element.hasAttribute('id')) {
|
|
141
|
+
throw new Error('Invalid secondary instance element: missing `id` attribute');
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
type AssertDOMSecondaryInstanceElements = (
|
|
146
|
+
elements: readonly DOMInstanceElement[]
|
|
147
|
+
) => asserts elements is readonly DOMSecondaryInstanceElement[];
|
|
148
|
+
|
|
149
|
+
const assertDOMSecondaryInstanceElements: AssertDOMSecondaryInstanceElements = (elements) => {
|
|
150
|
+
elements.forEach(assertDOMSecondaryInstanceElement);
|
|
151
|
+
};
|
|
3
152
|
|
|
4
153
|
const domParser = new DOMParser();
|
|
5
154
|
|
|
@@ -145,61 +294,33 @@ const normalizeRepeatGroups = (body: Element): void => {
|
|
|
145
294
|
}
|
|
146
295
|
};
|
|
147
296
|
|
|
148
|
-
interface NormalizedXForm {
|
|
149
|
-
readonly xformDocument: XMLDocument;
|
|
150
|
-
readonly rootEvaluator: XFormsXPathEvaluator;
|
|
151
|
-
readonly html: Element;
|
|
152
|
-
readonly body: Element;
|
|
153
|
-
readonly normalizedXML: string;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
interface XFormDOMNormalizationOptions {
|
|
157
|
-
readonly isNormalized: boolean;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
297
|
/**
|
|
161
|
-
* Performs preprocess operations to normalize certain aspects of an
|
|
162
|
-
*
|
|
298
|
+
* Performs preprocess operations to normalize certain aspects of the body of an
|
|
299
|
+
* XForm, for consistency when parsing its runtime representations.
|
|
300
|
+
*
|
|
163
301
|
* Currently this preprocessing:
|
|
164
302
|
*
|
|
165
|
-
* - Ensures consistent use of `ref` and `nodeset` where ambiguous in the
|
|
166
|
-
*
|
|
167
|
-
* - Ensures `<repeat>` body elements are always enclosed by a `<group>`
|
|
168
|
-
*
|
|
303
|
+
* - Ensures consistent use of `ref` and `nodeset` where ambiguous in the ODK
|
|
304
|
+
* XForms spec
|
|
305
|
+
* - Ensures `<repeat>` body elements are always enclosed by a `<group>` with
|
|
306
|
+
* the same `ref`
|
|
169
307
|
*/
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
): NormalizedXForm => {
|
|
174
|
-
const xformDocument: XMLDocument = domParser.parseFromString(sourceXML, 'text/xml');
|
|
175
|
-
const rootEvaluator = new XFormsXPathEvaluator({
|
|
176
|
-
rootNode: xformDocument,
|
|
177
|
-
});
|
|
178
|
-
const html = rootEvaluator.evaluateNonNullElement('/h:html');
|
|
179
|
-
const body = rootEvaluator.evaluateNonNullElement('./h:body', {
|
|
180
|
-
contextNode: html,
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
let normalizedXML: string;
|
|
184
|
-
|
|
185
|
-
if (options.isNormalized) {
|
|
186
|
-
normalizedXML = sourceXML;
|
|
187
|
-
} else {
|
|
188
|
-
normalizeBodyRefNodesetAttributes(body);
|
|
189
|
-
normalizeRepeatGroups(body);
|
|
308
|
+
const normalizeXFormBody = <T extends Element>(body: T): T => {
|
|
309
|
+
normalizeBodyRefNodesetAttributes(body);
|
|
310
|
+
normalizeRepeatGroups(body);
|
|
190
311
|
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return {
|
|
195
|
-
xformDocument,
|
|
196
|
-
rootEvaluator,
|
|
197
|
-
html,
|
|
198
|
-
body,
|
|
199
|
-
normalizedXML,
|
|
200
|
-
};
|
|
312
|
+
return body;
|
|
201
313
|
};
|
|
202
314
|
|
|
315
|
+
interface XFormDOMOptions {
|
|
316
|
+
readonly isNormalized: boolean;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @todo **Everything** in this class should be cacheable. Maybe not worth it
|
|
321
|
+
* for small forms, but may make a pretty substantial difference for very large
|
|
322
|
+
* forms (in bytes) in sessions creating multiple instances of the same form.
|
|
323
|
+
*/
|
|
203
324
|
export class XFormDOM {
|
|
204
325
|
static from(sourceXML: string) {
|
|
205
326
|
return new this(sourceXML, { isNormalized: false });
|
|
@@ -207,10 +328,6 @@ export class XFormDOM {
|
|
|
207
328
|
|
|
208
329
|
protected readonly normalizedXML: string;
|
|
209
330
|
|
|
210
|
-
// XPath
|
|
211
|
-
readonly rootEvaluator: XFormsXPathEvaluator;
|
|
212
|
-
readonly primaryInstanceEvaluator: XFormsXPathEvaluator;
|
|
213
|
-
|
|
214
331
|
// Commonly accessed landmark nodes
|
|
215
332
|
readonly xformDocument: XMLDocument;
|
|
216
333
|
|
|
@@ -220,59 +337,97 @@ export class XFormDOM {
|
|
|
220
337
|
readonly title: Element;
|
|
221
338
|
|
|
222
339
|
readonly model: Element;
|
|
340
|
+
readonly binds: readonly DOMBindElement[];
|
|
223
341
|
readonly primaryInstance: Element;
|
|
224
342
|
readonly primaryInstanceRoot: Element;
|
|
225
343
|
|
|
344
|
+
readonly itextTranslationElements: readonly DOMItextTranslationElement[];
|
|
345
|
+
readonly secondaryInstanceElements: readonly DOMSecondaryInstanceElement[];
|
|
346
|
+
|
|
226
347
|
readonly body: Element;
|
|
227
348
|
|
|
228
349
|
protected constructor(
|
|
229
350
|
protected readonly sourceXML: string,
|
|
230
|
-
options:
|
|
351
|
+
options: XFormDOMOptions
|
|
231
352
|
) {
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
353
|
+
const evaluator = new DefaultEvaluator();
|
|
354
|
+
const xformDocument: XMLDocument = domParser.parseFromString(sourceXML, 'text/xml');
|
|
355
|
+
const html = evaluator.evaluateNonNullElement('/h:html', {
|
|
356
|
+
contextNode: xformDocument,
|
|
357
|
+
});
|
|
358
|
+
const head = evaluator.evaluateNonNullElement('./h:head', {
|
|
235
359
|
contextNode: html,
|
|
236
360
|
});
|
|
237
|
-
const title =
|
|
361
|
+
const title = evaluator.evaluateNonNullElement('./h:title', {
|
|
238
362
|
contextNode: head,
|
|
239
363
|
});
|
|
240
|
-
const model =
|
|
364
|
+
const model = evaluator.evaluateNonNullElement('./xf:model', {
|
|
241
365
|
contextNode: head,
|
|
242
366
|
});
|
|
243
|
-
|
|
244
|
-
|
|
367
|
+
let binds: readonly DOMBindElement[] = evaluator.evaluateNodes<DOMBindElement>(
|
|
368
|
+
'./xf:bind[@nodeset]',
|
|
369
|
+
{
|
|
370
|
+
contextNode: model,
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
const instances = evaluator.evaluateNodes<DOMInstanceElement>('./xf:instance', {
|
|
245
375
|
contextNode: model,
|
|
246
376
|
});
|
|
247
|
-
|
|
248
|
-
const primaryInstance =
|
|
249
|
-
|
|
377
|
+
|
|
378
|
+
const [primaryInstance, ...secondaryInstanceElements] = instances;
|
|
379
|
+
|
|
380
|
+
assertDOMSecondaryInstanceElements(secondaryInstanceElements);
|
|
381
|
+
|
|
382
|
+
if (primaryInstance == null) {
|
|
383
|
+
throw new Error('Form is missing primary instance');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// TODO: Evidently primary instance root will not always have an id
|
|
387
|
+
const primaryInstanceRoot = evaluator.evaluateNonNullElement('./*[@id]', {
|
|
388
|
+
contextNode: primaryInstance,
|
|
250
389
|
});
|
|
251
390
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
391
|
+
const itextTranslationElements = evaluator.evaluateNodes<DOMItextTranslationElement>(
|
|
392
|
+
'./xf:itext/xf:translation[@lang]',
|
|
393
|
+
{
|
|
394
|
+
contextNode: model,
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
let body = evaluator.evaluateNonNullElement('./h:body', {
|
|
399
|
+
contextNode: html,
|
|
256
400
|
});
|
|
401
|
+
let normalizedXML: string;
|
|
402
|
+
|
|
403
|
+
if (options.isNormalized) {
|
|
404
|
+
normalizedXML = sourceXML;
|
|
405
|
+
} else {
|
|
406
|
+
body = normalizeXFormBody(body);
|
|
407
|
+
binds = normalizeDefaultMetaBindings(model, primaryInstanceRoot, binds);
|
|
408
|
+
|
|
409
|
+
// TODO: if we keep doing normalization this way long term (or using the DOM
|
|
410
|
+
// for parsing long term, for that matter!), we should measure this. And we
|
|
411
|
+
// should measure against XMLSerializer while we're at it!
|
|
412
|
+
normalizedXML = xformDocument.documentElement.outerHTML;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
this.normalizedXML = normalizedXML;
|
|
257
416
|
this.xformDocument = xformDocument;
|
|
258
417
|
this.html = html;
|
|
259
418
|
this.head = head;
|
|
260
419
|
this.title = title;
|
|
261
420
|
this.model = model;
|
|
421
|
+
this.binds = binds;
|
|
262
422
|
this.primaryInstance = primaryInstance;
|
|
263
423
|
this.primaryInstanceRoot = primaryInstanceRoot;
|
|
424
|
+
this.itextTranslationElements = itextTranslationElements;
|
|
425
|
+
this.secondaryInstanceElements = secondaryInstanceElements;
|
|
264
426
|
this.body = body;
|
|
265
427
|
}
|
|
266
428
|
|
|
267
|
-
// TODO: anticipating this will be an entry point for edits as well
|
|
268
|
-
createInstance(): XFormDOM {
|
|
269
|
-
return new XFormDOM(this.normalizedXML, { isNormalized: true });
|
|
270
|
-
}
|
|
271
|
-
|
|
272
429
|
toJSON() {
|
|
273
430
|
const {
|
|
274
|
-
rootEvaluator,
|
|
275
|
-
primaryInstanceEvaluator,
|
|
276
431
|
html,
|
|
277
432
|
head,
|
|
278
433
|
title,
|
|
@@ -3,7 +3,6 @@ import { ModelDefinition } from './model/ModelDefinition.ts';
|
|
|
3
3
|
import { XFormDOM } from './XFormDOM.ts';
|
|
4
4
|
|
|
5
5
|
export class XFormDefinition {
|
|
6
|
-
readonly xformDOM: XFormDOM;
|
|
7
6
|
readonly xformDocument: XMLDocument;
|
|
8
7
|
|
|
9
8
|
readonly id: string;
|
|
@@ -14,11 +13,7 @@ export class XFormDefinition {
|
|
|
14
13
|
readonly body: BodyDefinition;
|
|
15
14
|
readonly model: ModelDefinition;
|
|
16
15
|
|
|
17
|
-
constructor(readonly
|
|
18
|
-
const xformDOM = XFormDOM.from(sourceXML);
|
|
19
|
-
|
|
20
|
-
this.xformDOM = xformDOM;
|
|
21
|
-
|
|
16
|
+
constructor(readonly xformDOM: XFormDOM) {
|
|
22
17
|
const { primaryInstanceRoot, title, xformDocument } = xformDOM;
|
|
23
18
|
const id = primaryInstanceRoot.getAttribute('id');
|
|
24
19
|
|
|
@@ -29,10 +24,7 @@ export class XFormDefinition {
|
|
|
29
24
|
this.xformDocument = xformDocument;
|
|
30
25
|
this.id = id;
|
|
31
26
|
this.title = title.textContent ?? '';
|
|
32
|
-
|
|
33
|
-
// TODO: highly unlikely primary instance root will need a namespace prefix
|
|
34
|
-
// but noting it just in case there is such weird usage...
|
|
35
|
-
this.rootReference = `/${primaryInstanceRoot.localName}`;
|
|
27
|
+
this.rootReference = `/${primaryInstanceRoot.nodeName}`;
|
|
36
28
|
|
|
37
29
|
this.body = new BodyDefinition(this);
|
|
38
30
|
this.model = new ModelDefinition(this);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
2
|
+
|
|
3
|
+
export type FormAttachmentDataType = 'media' | 'secondary-instance';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @todo This type anticipates work to support media form attachments, which
|
|
7
|
+
* will tend to be associated with binary data. The
|
|
8
|
+
* expectation is that:
|
|
9
|
+
*
|
|
10
|
+
* - {@link Blob} would be appropriate for representing data from attachment
|
|
11
|
+
* resources which are conventionally loaded to completion (where network
|
|
12
|
+
* conditions are favorable), such as images
|
|
13
|
+
*
|
|
14
|
+
* - {@link MediaSource} or {@link ReadableStream} may be more appropriate for
|
|
15
|
+
* representing data from resources which are conventionally streamed in a
|
|
16
|
+
* browser context (often regardless of network conditions), such as video and
|
|
17
|
+
* audio
|
|
18
|
+
*/
|
|
19
|
+
// prettier-ignore
|
|
20
|
+
export type FormAttachmentMediaData =
|
|
21
|
+
| Blob
|
|
22
|
+
| MediaSource
|
|
23
|
+
| ReadableStream<unknown>;
|
|
24
|
+
|
|
25
|
+
export type FormAttachmentSecondaryInstanceData = string;
|
|
26
|
+
|
|
27
|
+
// prettier-ignore
|
|
28
|
+
type FormAttachmentData<DataType extends FormAttachmentDataType> =
|
|
29
|
+
DataType extends 'media'
|
|
30
|
+
? FormAttachmentMediaData
|
|
31
|
+
: FormAttachmentSecondaryInstanceData;
|
|
32
|
+
|
|
33
|
+
export abstract class FormAttachmentResource<DataType extends FormAttachmentDataType> {
|
|
34
|
+
protected constructor(
|
|
35
|
+
readonly dataType: DataType,
|
|
36
|
+
readonly resourceURL: JRResourceURL,
|
|
37
|
+
readonly contentType: string,
|
|
38
|
+
readonly data: FormAttachmentData<DataType>
|
|
39
|
+
) {}
|
|
40
|
+
}
|
|
@@ -3,11 +3,11 @@ import { TokenListParser } from '../../lib/TokenListParser.ts';
|
|
|
3
3
|
import type { XFormDefinition } from '../../parse/XFormDefinition.ts';
|
|
4
4
|
import { DependencyContext } from '../expression/abstract/DependencyContext.ts';
|
|
5
5
|
import { ControlDefinition } from './control/ControlDefinition.ts';
|
|
6
|
-
import {
|
|
6
|
+
import { InputControlDefinition } from './control/InputControlDefinition.ts';
|
|
7
7
|
import { RangeControlDefinition } from './control/RangeControlDefinition.ts';
|
|
8
8
|
import { RankControlDefinition } from './control/RankControlDefinition.ts';
|
|
9
|
-
import type {
|
|
10
|
-
import {
|
|
9
|
+
import type { AnySelectControlDefinition } from './control/SelectControlDefinition.ts';
|
|
10
|
+
import { SelectControlDefinition } from './control/SelectControlDefinition.ts';
|
|
11
11
|
import { TriggerControlDefinition } from './control/TriggerControlDefinition.ts';
|
|
12
12
|
import { UploadControlDefinition } from './control/UploadControlDefinition.ts';
|
|
13
13
|
import { LogicalGroupDefinition } from './group/LogicalGroupDefinition.ts';
|
|
@@ -24,8 +24,8 @@ export interface BodyElementParentContext {
|
|
|
24
24
|
|
|
25
25
|
// prettier-ignore
|
|
26
26
|
export type ControlElementDefinition =
|
|
27
|
-
|
|
|
28
|
-
|
|
|
27
|
+
| AnySelectControlDefinition
|
|
28
|
+
| InputControlDefinition
|
|
29
29
|
| RangeControlDefinition
|
|
30
30
|
| RankControlDefinition
|
|
31
31
|
| TriggerControlDefinition
|
|
@@ -47,8 +47,8 @@ const BodyElementDefinitionConstructors = [
|
|
|
47
47
|
LogicalGroupDefinition,
|
|
48
48
|
PresentationGroupDefinition,
|
|
49
49
|
StructuralGroupDefinition,
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
InputControlDefinition,
|
|
51
|
+
SelectControlDefinition,
|
|
52
52
|
RangeControlDefinition,
|
|
53
53
|
RankControlDefinition,
|
|
54
54
|
TriggerControlDefinition,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ParsedTokenList } from '../../../lib/TokenListParser.ts';
|
|
2
|
+
import { TokenListParser } from '../../../lib/TokenListParser.ts';
|
|
3
|
+
|
|
4
|
+
export const rangeAppearanceParser = new TokenListParser([
|
|
5
|
+
'no-ticks',
|
|
6
|
+
'picker',
|
|
7
|
+
'rating',
|
|
8
|
+
'vertical',
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export type RangeAppearanceDefinition = ParsedTokenList<typeof rangeAppearanceParser>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { XFormDefinition } from '../../XFormDefinition.ts';
|
|
2
|
+
import type { InputAppearanceDefinition } from '../appearance/inputAppearanceParser.ts';
|
|
3
|
+
import { inputAppearanceParser } from '../appearance/inputAppearanceParser.ts';
|
|
4
|
+
import type { BodyElementParentContext } from '../BodyDefinition.ts';
|
|
5
|
+
import { parseToFloat, parseToInteger } from '../../../lib/number-parsers.ts';
|
|
6
|
+
import { ControlDefinition } from './ControlDefinition.ts';
|
|
7
|
+
|
|
8
|
+
export class InputControlDefinition extends ControlDefinition<'input'> {
|
|
9
|
+
static override isCompatible(localName: string): boolean {
|
|
10
|
+
return localName === 'input';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
readonly type = 'input';
|
|
14
|
+
readonly appearances: InputAppearanceDefinition;
|
|
15
|
+
readonly rows: number | null;
|
|
16
|
+
readonly accuracyThreshold: number | null;
|
|
17
|
+
readonly unacceptableAccuracyThreshold: number | null;
|
|
18
|
+
|
|
19
|
+
constructor(form: XFormDefinition, parent: BodyElementParentContext, element: Element) {
|
|
20
|
+
super(form, parent, element);
|
|
21
|
+
|
|
22
|
+
this.appearances = inputAppearanceParser.parseFrom(element, 'appearance');
|
|
23
|
+
this.rows = parseToInteger(element.getAttribute('rows'));
|
|
24
|
+
this.accuracyThreshold = parseToFloat(element.getAttribute('accuracyThreshold'));
|
|
25
|
+
this.unacceptableAccuracyThreshold = parseToFloat(
|
|
26
|
+
element.getAttribute('unacceptableAccuracyThreshold')
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|