@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,288 @@
|
|
|
1
|
+
import { XFORMS_NAMESPACE_URI } from '@getodk/common/constants/xmlns.ts';
|
|
2
|
+
import type { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
3
|
+
import * as papa from 'papaparse';
|
|
4
|
+
import { ErrorProductionDesignPendingError } from '../../../../error/ErrorProductionDesignPendingError.ts';
|
|
5
|
+
import { StaticAttribute } from '../../../../integration/xpath/static-dom/StaticAttribute.ts';
|
|
6
|
+
import { StaticElement } from '../../../../integration/xpath/static-dom/StaticElement.ts';
|
|
7
|
+
import { StaticText } from '../../../../integration/xpath/static-dom/StaticText.ts';
|
|
8
|
+
import { SecondaryInstanceDefinition } from '../SecondaryInstanceDefinition.ts';
|
|
9
|
+
import { SecondaryInstanceRootDefinition } from '../SecondaryInstanceRootDefinition.ts';
|
|
10
|
+
import { ExternalSecondaryInstanceSource } from './ExternalSecondaryInstanceSource.ts';
|
|
11
|
+
|
|
12
|
+
type CSVColumn = string;
|
|
13
|
+
type CSVRow = readonly CSVColumn[];
|
|
14
|
+
|
|
15
|
+
type AssertCSVRow = (columns: unknown) => asserts columns is CSVRow;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Based on {@link https://github.com/getodk/central-frontend/commit/29cebcc870c9be70ab0d222e3349e34639045d19}
|
|
19
|
+
*
|
|
20
|
+
* Central performs this check for header and rows. A comment is included there for the header check, but the logic is the same in both cases.
|
|
21
|
+
*/
|
|
22
|
+
const rejectNullCharacters = (cell: string) => {
|
|
23
|
+
if (cell.includes('\0')) {
|
|
24
|
+
throw new ErrorProductionDesignPendingError(`Failed to parse CSV: null character`);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const assertCSVRow: AssertCSVRow = (columns) => {
|
|
29
|
+
if (!Array.isArray(columns)) {
|
|
30
|
+
throw new ErrorProductionDesignPendingError('Failed to parse CSV columns');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (const [index, column] of columns.entries()) {
|
|
34
|
+
if (typeof column !== 'string') {
|
|
35
|
+
throw new ErrorProductionDesignPendingError(`Failed to parse CSV column at index ${index}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
rejectNullCharacters(column);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type AssertPapaparseSuccess = (
|
|
43
|
+
resourceURL: JRResourceURL,
|
|
44
|
+
errors: readonly papa.ParseError[]
|
|
45
|
+
) => asserts errors is readonly [];
|
|
46
|
+
|
|
47
|
+
const assertPapaparseSuccess: AssertPapaparseSuccess = (resourceURL, errors) => {
|
|
48
|
+
if (errors.length > 0) {
|
|
49
|
+
const cause = new AggregateError(errors);
|
|
50
|
+
throw new ErrorProductionDesignPendingError(
|
|
51
|
+
`Failed to parse CSV external secondary instance ${resourceURL.href}`,
|
|
52
|
+
{ cause }
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
interface ParsedCSVHeader {
|
|
58
|
+
readonly columns: CSVRow;
|
|
59
|
+
readonly errors: readonly [];
|
|
60
|
+
readonly meta: papa.ParseMeta;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ParseCSVOptions {
|
|
64
|
+
readonly columns: readonly string[];
|
|
65
|
+
readonly delimiter: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const stripTrailingEmptyCells = (columns: CSVRow, row: CSVRow): CSVRow => {
|
|
69
|
+
const result = row.slice();
|
|
70
|
+
|
|
71
|
+
while (result.length > columns.length && result.at(-1) === '') {
|
|
72
|
+
result.pop();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
interface ParsedCSVRows {
|
|
79
|
+
readonly rows: readonly CSVRow[];
|
|
80
|
+
readonly errors: readonly [];
|
|
81
|
+
readonly meta: papa.ParseMeta;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface CSVExternalSecondaryInstanceItemColumn {
|
|
85
|
+
readonly columnName: string;
|
|
86
|
+
readonly cellValue: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type CSVExternalSecondaryInstanceItem = readonly CSVExternalSecondaryInstanceItemColumn[];
|
|
90
|
+
|
|
91
|
+
class CSVExternalSecondaryInstanceColumnElement extends StaticElement {
|
|
92
|
+
constructor(parent: StaticElement, column: CSVExternalSecondaryInstanceItemColumn) {
|
|
93
|
+
const { columnName, cellValue } = column;
|
|
94
|
+
|
|
95
|
+
super(
|
|
96
|
+
parent,
|
|
97
|
+
() => [],
|
|
98
|
+
(self) => [new StaticText(self, cellValue)],
|
|
99
|
+
{
|
|
100
|
+
namespaceURI: XFORMS_NAMESPACE_URI,
|
|
101
|
+
localName: columnName,
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
class CSVExternalSecondaryInstanceItemElement extends StaticElement {
|
|
108
|
+
constructor(parent: StaticElement, item: CSVExternalSecondaryInstanceItem) {
|
|
109
|
+
super(
|
|
110
|
+
parent,
|
|
111
|
+
() => [],
|
|
112
|
+
(self) => {
|
|
113
|
+
return item.map((column) => {
|
|
114
|
+
return new CSVExternalSecondaryInstanceColumnElement(self, column);
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
namespaceURI: XFORMS_NAMESPACE_URI,
|
|
119
|
+
localName: 'item',
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class CSVExternalSecondaryInstanceRootElement extends StaticElement {
|
|
126
|
+
constructor(parent: StaticElement, items: readonly CSVExternalSecondaryInstanceItem[]) {
|
|
127
|
+
super(
|
|
128
|
+
parent,
|
|
129
|
+
() => [],
|
|
130
|
+
(self) => {
|
|
131
|
+
return items.map((item) => {
|
|
132
|
+
return new CSVExternalSecondaryInstanceItemElement(self, item);
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
namespaceURI: XFORMS_NAMESPACE_URI,
|
|
137
|
+
localName: 'root',
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
class CSVExternalSecondaryInstanceDocumentElement extends SecondaryInstanceRootDefinition {
|
|
144
|
+
constructor(
|
|
145
|
+
instanceId: string,
|
|
146
|
+
parent: CSVExternalSecondaryInstanceDefinition,
|
|
147
|
+
items: readonly CSVExternalSecondaryInstanceItem[]
|
|
148
|
+
) {
|
|
149
|
+
super(
|
|
150
|
+
parent,
|
|
151
|
+
(self) => [
|
|
152
|
+
new StaticAttribute(self, {
|
|
153
|
+
namespaceURI: XFORMS_NAMESPACE_URI,
|
|
154
|
+
localName: 'id',
|
|
155
|
+
value: instanceId,
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
(self) => [new CSVExternalSecondaryInstanceRootElement(self, items)],
|
|
159
|
+
{
|
|
160
|
+
namespaceURI: XFORMS_NAMESPACE_URI,
|
|
161
|
+
localName: 'instance',
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
class CSVExternalSecondaryInstanceDefinition extends SecondaryInstanceDefinition {
|
|
168
|
+
constructor(instanceId: string, items: readonly CSVExternalSecondaryInstanceItem[]) {
|
|
169
|
+
super((self) => {
|
|
170
|
+
return new CSVExternalSecondaryInstanceDocumentElement(instanceId, self, items);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export class CSVExternalSecondaryInstanceSource extends ExternalSecondaryInstanceSource<'csv'> {
|
|
176
|
+
/**
|
|
177
|
+
* Based on
|
|
178
|
+
* {@link https://github.com/getodk/central-frontend/blob/42c9277709e593480d1462e28b4be5f1364532b7/src/util/csv.js#L79} (and {@link https://github.com/getodk/central-frontend/blob/42c9277709e593480d1462e28b4be5f1364532b7/src/util/csv.js#L13}).
|
|
179
|
+
*
|
|
180
|
+
* The most significant deviations at time of writing:
|
|
181
|
+
*
|
|
182
|
+
* - we have already retrieved the CSV resource, so we are parsing the raw CSV data directly.
|
|
183
|
+
* - we have no need for asynchronous/streaming parsing at this point in the
|
|
184
|
+
* form initialization process, so we can dispense with those details of the
|
|
185
|
+
* {@link papa | papaparse} API/config.
|
|
186
|
+
*/
|
|
187
|
+
private parseCSVHeader(csvData: string): ParsedCSVHeader {
|
|
188
|
+
const { data, errors, meta } = papa.parse(csvData, {
|
|
189
|
+
delimitersToGuess: [',', ';', '\t', '|'],
|
|
190
|
+
download: false,
|
|
191
|
+
preview: 1,
|
|
192
|
+
});
|
|
193
|
+
const [columns = []] = data;
|
|
194
|
+
|
|
195
|
+
assertCSVRow(columns);
|
|
196
|
+
assertPapaparseSuccess(this.resourceURL, errors);
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
errors,
|
|
200
|
+
meta,
|
|
201
|
+
columns,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Largely based on {@link https://github.com/getodk/central-frontend/blob/42c9277709e593480d1462e28b4be5f1364532b7/src/util/csv.js#L170}
|
|
207
|
+
*/
|
|
208
|
+
private parseCSVRows(csvData: string, options: ParseCSVOptions): ParsedCSVRows {
|
|
209
|
+
const { columns, delimiter } = options;
|
|
210
|
+
const { data, errors, meta } = papa.parse(csvData, {
|
|
211
|
+
delimiter,
|
|
212
|
+
download: false,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
assertPapaparseSuccess(this.resourceURL, errors);
|
|
216
|
+
|
|
217
|
+
const rowData = data.slice(1);
|
|
218
|
+
const lastRowIndex = rowData.length - 1;
|
|
219
|
+
|
|
220
|
+
let stripLastRow = false;
|
|
221
|
+
|
|
222
|
+
const rows = rowData.map((values, index) => {
|
|
223
|
+
assertCSVRow(values);
|
|
224
|
+
|
|
225
|
+
const rowIndex = index + 1;
|
|
226
|
+
|
|
227
|
+
// Central: Remove trailing empty cells.
|
|
228
|
+
const row = stripTrailingEmptyCells(columns, values);
|
|
229
|
+
|
|
230
|
+
// Central: Skip trailing empty rows and do not check them for warnings.
|
|
231
|
+
// Throw for an empty row that is not trailing.
|
|
232
|
+
if (row.every((cell) => cell === '')) {
|
|
233
|
+
if (index === lastRowIndex) {
|
|
234
|
+
stripLastRow = true;
|
|
235
|
+
} else {
|
|
236
|
+
throw new ErrorProductionDesignPendingError(
|
|
237
|
+
`Failed to parse CSV row ${rowIndex}: unexpected empty row`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Central: Throw if there are too many cells.
|
|
243
|
+
if (row.length > columns.length) {
|
|
244
|
+
throw new ErrorProductionDesignPendingError(
|
|
245
|
+
`Failed to parse CSV row ${rowIndex}: expected ${columns.length} columns, got ${row.length}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return row;
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
if (stripLastRow) {
|
|
253
|
+
rows.pop();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
errors,
|
|
258
|
+
meta,
|
|
259
|
+
rows,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private toItems(
|
|
264
|
+
columns: CSVRow,
|
|
265
|
+
rows: readonly CSVRow[]
|
|
266
|
+
): readonly CSVExternalSecondaryInstanceItem[] {
|
|
267
|
+
return rows.map((row) => {
|
|
268
|
+
return columns.map((columnName, index) => {
|
|
269
|
+
return {
|
|
270
|
+
columnName,
|
|
271
|
+
cellValue: row[index] ?? '',
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
parseDefinition(): SecondaryInstanceDefinition {
|
|
278
|
+
const csvData = this.resource.data.replace(/[\n\r]+$/, '');
|
|
279
|
+
const { columns, meta } = this.parseCSVHeader(csvData);
|
|
280
|
+
const { rows } = this.parseCSVRows(csvData, {
|
|
281
|
+
columns,
|
|
282
|
+
delimiter: meta.delimiter,
|
|
283
|
+
});
|
|
284
|
+
const items = this.toItems(columns, rows);
|
|
285
|
+
|
|
286
|
+
return new CSVExternalSecondaryInstanceDefinition(this.instanceId, items);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import type { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
2
|
+
import type { MissingResourceBehavior } from '../../../../client/constants.ts';
|
|
3
|
+
import type { FetchResource, FetchResourceResponse } from '../../../../client/resources.ts';
|
|
4
|
+
import { ErrorProductionDesignPendingError } from '../../../../error/ErrorProductionDesignPendingError.ts';
|
|
5
|
+
import { FormAttachmentResource } from '../../../attachments/FormAttachmentResource.ts';
|
|
6
|
+
import type { ExternalSecondaryInstanceSourceFormat } from './SecondaryInstanceSource.ts';
|
|
7
|
+
|
|
8
|
+
const assertResponseSuccess = (resourceURL: JRResourceURL, response: FetchResourceResponse) => {
|
|
9
|
+
const { ok = true, status = 200 } = response;
|
|
10
|
+
|
|
11
|
+
if (!ok || status !== 200) {
|
|
12
|
+
throw new ErrorProductionDesignPendingError(`Failed to load ${resourceURL.href}`);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const stripContentTypeCharset = (contentType: string): string => {
|
|
17
|
+
return contentType.replace(/;charset=.*$/, '');
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getResponseContentType = (response: FetchResourceResponse): string | null => {
|
|
21
|
+
const { headers } = response;
|
|
22
|
+
|
|
23
|
+
if (headers == null) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const contentType = headers.get('content-type');
|
|
28
|
+
|
|
29
|
+
if (contentType != null) {
|
|
30
|
+
return stripContentTypeCharset(contentType);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (headers instanceof Headers) {
|
|
34
|
+
return contentType;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const [header, value] of headers) {
|
|
38
|
+
if (header.toLowerCase() === 'content-type') {
|
|
39
|
+
return stripContentTypeCharset(value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
interface ExternalSecondaryInstanceResourceMetadata<
|
|
47
|
+
Format extends ExternalSecondaryInstanceSourceFormat = ExternalSecondaryInstanceSourceFormat,
|
|
48
|
+
> {
|
|
49
|
+
readonly contentType: string;
|
|
50
|
+
readonly format: Format;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const inferSecondaryInstanceResourceMetadata = (
|
|
54
|
+
resourceURL: JRResourceURL,
|
|
55
|
+
contentType: string | null,
|
|
56
|
+
data: string
|
|
57
|
+
): ExternalSecondaryInstanceResourceMetadata => {
|
|
58
|
+
const url = resourceURL.href;
|
|
59
|
+
|
|
60
|
+
let format: ExternalSecondaryInstanceSourceFormat | null = null;
|
|
61
|
+
|
|
62
|
+
if (url.endsWith('.xml') && data.startsWith('<')) {
|
|
63
|
+
format = 'xml';
|
|
64
|
+
} else if (url.endsWith('.csv')) {
|
|
65
|
+
format = 'csv';
|
|
66
|
+
} else if (url.endsWith('.geojson') && data.startsWith('{')) {
|
|
67
|
+
format = 'geojson';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (format == null) {
|
|
71
|
+
throw new ErrorProductionDesignPendingError(
|
|
72
|
+
`Failed to infer external secondary instance format/content type for resource ${url} (response content type: ${contentType}, data: ${data})`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
contentType: contentType ?? 'text/plain',
|
|
78
|
+
format,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const detectSecondaryInstanceResourceMetadata = (
|
|
83
|
+
resourceURL: JRResourceURL,
|
|
84
|
+
response: FetchResourceResponse,
|
|
85
|
+
data: string
|
|
86
|
+
): ExternalSecondaryInstanceResourceMetadata => {
|
|
87
|
+
const contentType = getResponseContentType(response);
|
|
88
|
+
|
|
89
|
+
if (contentType == null || contentType === 'text/plain') {
|
|
90
|
+
return inferSecondaryInstanceResourceMetadata(resourceURL, contentType, data);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let format: ExternalSecondaryInstanceSourceFormat | null = null;
|
|
94
|
+
|
|
95
|
+
switch (contentType) {
|
|
96
|
+
case 'text/csv':
|
|
97
|
+
format = 'csv';
|
|
98
|
+
break;
|
|
99
|
+
|
|
100
|
+
case 'application/geo+json':
|
|
101
|
+
format = 'geojson';
|
|
102
|
+
break;
|
|
103
|
+
|
|
104
|
+
case 'text/xml':
|
|
105
|
+
format = 'xml';
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (format == null) {
|
|
110
|
+
throw new ErrorProductionDesignPendingError(
|
|
111
|
+
`Failed to detect external secondary instance format for resource ${resourceURL.href} (response content type: ${contentType}, data: ${data})`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
contentType,
|
|
117
|
+
format,
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
interface MissingResourceResponse extends FetchResourceResponse {
|
|
122
|
+
readonly status: 404;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface ExternalSecondaryInstanceResourceLoadOptions {
|
|
126
|
+
readonly fetchResource: FetchResource<JRResourceURL>;
|
|
127
|
+
readonly missingResourceBehavior: MissingResourceBehavior;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
type LoadedExternalSecondaryInstanceResource = {
|
|
131
|
+
[Format in ExternalSecondaryInstanceSourceFormat]: ExternalSecondaryInstanceResource<Format>;
|
|
132
|
+
}[ExternalSecondaryInstanceSourceFormat];
|
|
133
|
+
|
|
134
|
+
interface ExternalSecondaryInstanceResourceOptions {
|
|
135
|
+
readonly isExplicitlyBlank?: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class ExternalSecondaryInstanceResource<
|
|
139
|
+
Format extends ExternalSecondaryInstanceSourceFormat = ExternalSecondaryInstanceSourceFormat,
|
|
140
|
+
> extends FormAttachmentResource<'secondary-instance'> {
|
|
141
|
+
private static isMissingResource(
|
|
142
|
+
response: FetchResourceResponse
|
|
143
|
+
): response is MissingResourceResponse {
|
|
144
|
+
return response.status === 404;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private static createBlankResource(
|
|
148
|
+
instanceId: string,
|
|
149
|
+
resourceURL: JRResourceURL,
|
|
150
|
+
response: MissingResourceResponse,
|
|
151
|
+
options: ExternalSecondaryInstanceResourceLoadOptions
|
|
152
|
+
) {
|
|
153
|
+
if (options.missingResourceBehavior === 'BLANK') {
|
|
154
|
+
return new this(
|
|
155
|
+
response.status,
|
|
156
|
+
instanceId,
|
|
157
|
+
resourceURL,
|
|
158
|
+
{
|
|
159
|
+
format: 'xml',
|
|
160
|
+
contentType: 'text/xml',
|
|
161
|
+
},
|
|
162
|
+
'',
|
|
163
|
+
{ isExplicitlyBlank: true }
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
throw new ErrorProductionDesignPendingError(
|
|
168
|
+
`Failed to load resource: ${resourceURL.href}: resource is missing (status: ${response.status})`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static async load(
|
|
173
|
+
instanceId: string,
|
|
174
|
+
resourceURL: JRResourceURL,
|
|
175
|
+
options: ExternalSecondaryInstanceResourceLoadOptions
|
|
176
|
+
): Promise<LoadedExternalSecondaryInstanceResource> {
|
|
177
|
+
const response = await options.fetchResource(resourceURL);
|
|
178
|
+
|
|
179
|
+
if (this.isMissingResource(response)) {
|
|
180
|
+
return this.createBlankResource(instanceId, resourceURL, response, options);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
assertResponseSuccess(resourceURL, response);
|
|
184
|
+
|
|
185
|
+
const data = await response.text();
|
|
186
|
+
const metadata = detectSecondaryInstanceResourceMetadata(resourceURL, response, data);
|
|
187
|
+
|
|
188
|
+
return new this(response.status ?? null, instanceId, resourceURL, metadata, data, {
|
|
189
|
+
isExplicitlyBlank: false,
|
|
190
|
+
}) satisfies ExternalSecondaryInstanceResource as LoadedExternalSecondaryInstanceResource;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
readonly format: Format;
|
|
194
|
+
readonly isBlank: boolean;
|
|
195
|
+
|
|
196
|
+
private constructor(
|
|
197
|
+
readonly responseStatus: number | null,
|
|
198
|
+
readonly instanceId: string,
|
|
199
|
+
resourceURL: JRResourceURL,
|
|
200
|
+
metadata: ExternalSecondaryInstanceResourceMetadata<Format>,
|
|
201
|
+
data: string,
|
|
202
|
+
options: ExternalSecondaryInstanceResourceOptions
|
|
203
|
+
) {
|
|
204
|
+
const { contentType, format } = metadata;
|
|
205
|
+
|
|
206
|
+
super('secondary-instance', resourceURL, contentType, data);
|
|
207
|
+
|
|
208
|
+
this.format = format;
|
|
209
|
+
|
|
210
|
+
if (data === '') {
|
|
211
|
+
if (options.isExplicitlyBlank) {
|
|
212
|
+
this.isBlank = true;
|
|
213
|
+
} else {
|
|
214
|
+
throw new ErrorProductionDesignPendingError(
|
|
215
|
+
`Failed to load blank external secndary instance ${resourceURL.href}`
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
this.isBlank = false;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
2
|
+
import type { DOMSecondaryInstanceElement } from '../../../XFormDOM.ts';
|
|
3
|
+
import type { ExternalSecondaryInstanceResource } from './ExternalSecondaryInstanceResource.ts';
|
|
4
|
+
import type { ExternalSecondaryInstanceSourceFormat } from './SecondaryInstanceSource.ts';
|
|
5
|
+
import { SecondaryInstanceSource } from './SecondaryInstanceSource.ts';
|
|
6
|
+
|
|
7
|
+
export abstract class ExternalSecondaryInstanceSource<
|
|
8
|
+
Format extends ExternalSecondaryInstanceSourceFormat = ExternalSecondaryInstanceSourceFormat,
|
|
9
|
+
> extends SecondaryInstanceSource<Format> {
|
|
10
|
+
override readonly resourceURL: JRResourceURL;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
domElement: DOMSecondaryInstanceElement,
|
|
14
|
+
protected readonly resource: ExternalSecondaryInstanceResource<Format>
|
|
15
|
+
) {
|
|
16
|
+
const { format, instanceId, resourceURL } = resource;
|
|
17
|
+
|
|
18
|
+
super(format, instanceId, resourceURL, domElement);
|
|
19
|
+
|
|
20
|
+
this.resourceURL = resourceURL;
|
|
21
|
+
}
|
|
22
|
+
}
|