@thomasfosterau/effect-rdf 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +2250 -1
- package/dist/Algebra-CGG4oae3.mjs +433 -0
- package/dist/Algebra-CGG4oae3.mjs.map +1 -0
- package/dist/Algebra-uGsIEOUA.d.mts +446 -0
- package/dist/Ast-CPRZmBvk.mjs +552 -0
- package/dist/Ast-CPRZmBvk.mjs.map +1 -0
- package/dist/Ast-vcw2W-lf.d.mts +827 -0
- package/dist/Bindings-Ck3m7JRC.mjs +249 -0
- package/dist/Bindings-Ck3m7JRC.mjs.map +1 -0
- package/dist/Bindings-DiKpBd7f.d.mts +153 -0
- package/dist/ClientErrors-CpXdFX5u.mjs +128 -0
- package/dist/ClientErrors-CpXdFX5u.mjs.map +1 -0
- package/dist/ClientErrors-D4IZHUM-.d.mts +101 -0
- package/dist/ClientFormats-CXomkXLV.mjs +73 -0
- package/dist/ClientFormats-CXomkXLV.mjs.map +1 -0
- package/dist/ClientFormats-Dm57ZPwR.d.mts +36 -0
- package/dist/Csv2Json-DynEcwCh.mjs +194 -0
- package/dist/Csv2Json-DynEcwCh.mjs.map +1 -0
- package/dist/Csv2Json-aXNVDoXQ.d.mts +40 -0
- package/dist/Csv2Rdf-8maXP6mt.d.mts +41 -0
- package/dist/Csv2Rdf-DuSEkaKE.mjs +161 -0
- package/dist/Csv2Rdf-DuSEkaKE.mjs.map +1 -0
- package/dist/Dataset-BlmlcI7J.mjs +782 -0
- package/dist/Dataset-BlmlcI7J.mjs.map +1 -0
- package/dist/Dataset-DS3ESOcO.d.mts +426 -0
- package/dist/Dataset.d.mts +2 -0
- package/dist/Dataset.mjs +1 -0
- package/dist/Datatype-CxMpamHC.d.mts +212 -0
- package/dist/Datatype-DQvkNkiH.mjs +1001 -0
- package/dist/Datatype-DQvkNkiH.mjs.map +1 -0
- package/dist/Dialect-8ChFj5EX.d.mts +113 -0
- package/dist/Dialect-CzVH38uo.mjs +165 -0
- package/dist/Dialect-CzVH38uo.mjs.map +1 -0
- package/dist/DocumentLoader-D3lZREnB.mjs +346 -0
- package/dist/DocumentLoader-D3lZREnB.mjs.map +1 -0
- package/dist/DocumentLoader-ZUCEVrW5.d.mts +178 -0
- package/dist/DublinCore-AnwqxRx6.mjs +137 -0
- package/dist/DublinCore-AnwqxRx6.mjs.map +1 -0
- package/dist/DublinCore-Dq-tVA5d.d.mts +119 -0
- package/dist/Engine-CYPB3g4h.d.mts +144 -0
- package/dist/Engine-DF8PN7g-.mjs +872 -0
- package/dist/Engine-DF8PN7g-.mjs.map +1 -0
- package/dist/Errors-CMdV1RhU.mjs +37 -0
- package/dist/Errors-CMdV1RhU.mjs.map +1 -0
- package/dist/Errors-u2bDjUeM.d.mts +30 -0
- package/dist/Evaluator-DEsU4d1o.d.mts +50 -0
- package/dist/Evaluator-DOY2-guC.mjs +281 -0
- package/dist/Evaluator-DOY2-guC.mjs.map +1 -0
- package/dist/Exif-CpqniYQd.d.mts +78 -0
- package/dist/Exif-DjkCfEB-.mjs +89 -0
- package/dist/Exif-DjkCfEB-.mjs.map +1 -0
- package/dist/Expression-BIMMvduQ.mjs +230 -0
- package/dist/Expression-BIMMvduQ.mjs.map +1 -0
- package/dist/Expression-W8A9cyX7.d.mts +89 -0
- package/dist/Extract-Bop85jES.mjs +220 -0
- package/dist/Extract-Bop85jES.mjs.map +1 -0
- package/dist/Extract-C_pCvuTC.d.mts +88 -0
- package/dist/Federation-BcNrozc1.d.mts +52 -0
- package/dist/Federation-CHScBkaK.mjs +130 -0
- package/dist/Federation-CHScBkaK.mjs.map +1 -0
- package/dist/Functions-AvjNcId_.mjs +1346 -0
- package/dist/Functions-AvjNcId_.mjs.map +1 -0
- package/dist/Functions-OQJZP-F6.d.mts +111 -0
- package/dist/Generator-C52mmq01.d.mts +50 -0
- package/dist/Generator-D3utCJC7.mjs +205 -0
- package/dist/Generator-D3utCJC7.mjs.map +1 -0
- package/dist/Grammar-CPlSxGH6.mjs +200 -0
- package/dist/Grammar-CPlSxGH6.mjs.map +1 -0
- package/dist/Grammar-CRhnRoCu.d.mts +148 -0
- package/dist/Grammar-D6jZdJQ3.d.mts +169 -0
- package/dist/Grammar-mQ8CgE1M.mjs +258 -0
- package/dist/Grammar-mQ8CgE1M.mjs.map +1 -0
- package/dist/GraphStore-DhUa4nFO.d.mts +45 -0
- package/dist/GraphStore-DvbqwKy1.mjs +212 -0
- package/dist/GraphStore-DvbqwKy1.mjs.map +1 -0
- package/dist/Iri-BB8Ks-BF.d.mts +84 -0
- package/dist/Iri-Cr92gsQV.mjs +232 -0
- package/dist/Iri-Cr92gsQV.mjs.map +1 -0
- package/dist/Iri.d.mts +2 -0
- package/dist/Iri.mjs +1 -0
- package/dist/Isomorphism-B6qTY-xy.d.mts +28 -0
- package/dist/Isomorphism-BmqxhKyJ.mjs +232 -0
- package/dist/Isomorphism-BmqxhKyJ.mjs.map +1 -0
- package/dist/Isomorphism-DInKnWIy.mjs +390 -0
- package/dist/Isomorphism-DInKnWIy.mjs.map +1 -0
- package/dist/Isomorphism-DvSfZXLR.d.mts +37 -0
- package/dist/Isomorphism.d.mts +2 -0
- package/dist/Isomorphism.mjs +1 -0
- package/dist/JsonLd-DOwS2FHg.mjs +2836 -0
- package/dist/JsonLd-DOwS2FHg.mjs.map +1 -0
- package/dist/JsonLd-DobFrQNa.d.mts +242 -0
- package/dist/JsonLdError-C9J-BxfG.mjs +106 -0
- package/dist/JsonLdError-C9J-BxfG.mjs.map +1 -0
- package/dist/JsonLdError-DSOfHkOy.d.mts +43 -0
- package/dist/LanguageTag-BCu8rcmX.d.mts +38 -0
- package/dist/LanguageTag-BcOpMGZ4.mjs +89 -0
- package/dist/LanguageTag-BcOpMGZ4.mjs.map +1 -0
- package/dist/LanguageTag.d.mts +2 -0
- package/dist/LanguageTag.mjs +1 -0
- package/dist/Lexical-Cg0JHrf6.mjs +243 -0
- package/dist/Lexical-Cg0JHrf6.mjs.map +1 -0
- package/dist/Lexical-D3zySYVS.d.mts +163 -0
- package/dist/Manifest-B6xf6mUc.mjs +148 -0
- package/dist/Manifest-B6xf6mUc.mjs.map +1 -0
- package/dist/Manifest-DQUMRBFr.d.mts +98 -0
- package/dist/Mapping-BgG74x3U.d.mts +63 -0
- package/dist/Mapping-Dc1ZGirk.mjs +259 -0
- package/dist/Mapping-Dc1ZGirk.mjs.map +1 -0
- package/dist/Mcp-1DwTTKOK.mjs +48 -0
- package/dist/Mcp-1DwTTKOK.mjs.map +1 -0
- package/dist/Mcp-d-pX9erx.d.mts +25 -0
- package/dist/Message-CK_DGQuu.mjs +95 -0
- package/dist/Message-CK_DGQuu.mjs.map +1 -0
- package/dist/Message-fIvTJSXM.d.mts +49 -0
- package/dist/Metadata-BbffwGDZ.mjs +445 -0
- package/dist/Metadata-BbffwGDZ.mjs.map +1 -0
- package/dist/Metadata-CEt3yc1-.d.mts +901 -0
- package/dist/Metadata-D4HsQNXr.mjs +1273 -0
- package/dist/Metadata-D4HsQNXr.mjs.map +1 -0
- package/dist/Metadata-nzS7QKRj.d.mts +350 -0
- package/dist/Model-DaMmxurZ.d.mts +293 -0
- package/dist/Model-DlPzRYhF.mjs +528 -0
- package/dist/Model-DlPzRYhF.mjs.map +1 -0
- package/dist/N3-BzyV-KIH.mjs +974 -0
- package/dist/N3-BzyV-KIH.mjs.map +1 -0
- package/dist/N3-DSLnonDn.d.mts +100 -0
- package/dist/NQuads-C1VBOJ3-.mjs +117 -0
- package/dist/NQuads-C1VBOJ3-.mjs.map +1 -0
- package/dist/NQuads-FjFZikFg.d.mts +76 -0
- package/dist/NTriples-D-kLSEAf.mjs +120 -0
- package/dist/NTriples-D-kLSEAf.mjs.map +1 -0
- package/dist/NTriples-D34OspfW.d.mts +76 -0
- package/dist/Namespace-ClTUO_ya.d.mts +42 -0
- package/dist/Namespace-DHFIsORd.mjs +75 -0
- package/dist/Namespace-DHFIsORd.mjs.map +1 -0
- package/dist/Namespace.d.mts +2 -0
- package/dist/Namespace.mjs +1 -0
- package/dist/Namespaces-Bz85vpjW.mjs +235 -0
- package/dist/Namespaces-Bz85vpjW.mjs.map +1 -0
- package/dist/Namespaces-C1jW6EDo.d.mts +178 -0
- package/dist/Optimizer-BWWQRQPY.mjs +168 -0
- package/dist/Optimizer-BWWQRQPY.mjs.map +1 -0
- package/dist/Optimizer-DUpUow6k.d.mts +26 -0
- package/dist/Options-BLBGL4HE.mjs +72 -0
- package/dist/Options-BLBGL4HE.mjs.map +1 -0
- package/dist/Options-BommQwP9.d.mts +127 -0
- package/dist/Packet-CA76wVX3.mjs +197 -0
- package/dist/Packet-CA76wVX3.mjs.map +1 -0
- package/dist/Packet-Cy5g6XuW.d.mts +130 -0
- package/dist/Parser-p1Gyr0QN.d.mts +85 -0
- package/dist/Parser-xARsOWXk.mjs +1317 -0
- package/dist/Parser-xARsOWXk.mjs.map +1 -0
- package/dist/Path-B20Yp8KE.mjs +284 -0
- package/dist/Path-B20Yp8KE.mjs.map +1 -0
- package/dist/Path-DRB8e-Zn.d.mts +181 -0
- package/dist/Pdf-B9RZn--8.d.mts +77 -0
- package/dist/Pdf-CKK6dkZn.mjs +89 -0
- package/dist/Pdf-CKK6dkZn.mjs.map +1 -0
- package/dist/PdfA-CUjSuntT.d.mts +109 -0
- package/dist/PdfA-CleOhuL6.mjs +124 -0
- package/dist/PdfA-CleOhuL6.mjs.map +1 -0
- package/dist/Photoshop-CiHo80qV.mjs +233 -0
- package/dist/Photoshop-CiHo80qV.mjs.map +1 -0
- package/dist/Photoshop-udKZ0I3N.d.mts +204 -0
- package/dist/PrefixMap-BHFPDLO-.mjs +103 -0
- package/dist/PrefixMap-BHFPDLO-.mjs.map +1 -0
- package/dist/PrefixMap-BMlXrWNd.d.mts +64 -0
- package/dist/PrefixMap.d.mts +2 -0
- package/dist/PrefixMap.mjs +1 -0
- package/dist/Processor-CMmecFsb.mjs +198 -0
- package/dist/Processor-CMmecFsb.mjs.map +1 -0
- package/dist/Processor-FJPvO0CB.d.mts +435 -0
- package/dist/Protocol-BA7OkNgp.mjs +202 -0
- package/dist/Protocol-BA7OkNgp.mjs.map +1 -0
- package/dist/Protocol-DlSoiIKB.d.mts +108 -0
- package/dist/ProtocolErrors-Ckfejnl6.d.mts +84 -0
- package/dist/ProtocolErrors-czDPVcX5.mjs +129 -0
- package/dist/ProtocolErrors-czDPVcX5.mjs.map +1 -0
- package/dist/Query-D9A6LOpP.mjs +364 -0
- package/dist/Query-D9A6LOpP.mjs.map +1 -0
- package/dist/Query-KqSkTYyG.d.mts +96 -0
- package/dist/QueryBuilder-BLK9Vfbz.mjs +674 -0
- package/dist/QueryBuilder-BLK9Vfbz.mjs.map +1 -0
- package/dist/QueryBuilder-DUqh4ECe.d.mts +529 -0
- package/dist/RdfJs-D6-49XB5.mjs +86 -0
- package/dist/RdfJs-D6-49XB5.mjs.map +1 -0
- package/dist/RdfJs-DXFqdWrd.d.mts +76 -0
- package/dist/RdfJs.d.mts +2 -0
- package/dist/RdfJs.mjs +1 -0
- package/dist/RdfJson-5aKPDlPS.d.mts +297 -0
- package/dist/RdfJson-BNocgW4f.mjs +548 -0
- package/dist/RdfJson-BNocgW4f.mjs.map +1 -0
- package/dist/RdfXml-DJ9G4gOq.mjs +1014 -0
- package/dist/RdfXml-DJ9G4gOq.mjs.map +1 -0
- package/dist/RdfXml-_N7yxWEp.d.mts +149 -0
- package/dist/Rdfs-BRVPsAjc.d.mts +84 -0
- package/dist/Rdfs-CyY2wVHI.mjs +167 -0
- package/dist/Rdfs-CyY2wVHI.mjs.map +1 -0
- package/dist/Rdfs.d.mts +2 -0
- package/dist/Rdfs.mjs +1 -0
- package/dist/Reasoner-BxYhx9s7.d.mts +94 -0
- package/dist/Reasoner-Cw90zrjv.mjs +798 -0
- package/dist/Reasoner-Cw90zrjv.mjs.map +1 -0
- package/dist/Reification-BmN4EfnM.d.mts +40 -0
- package/dist/Reification-dpqQvjDE.mjs +82 -0
- package/dist/Reification-dpqQvjDE.mjs.map +1 -0
- package/dist/Reification.d.mts +2 -0
- package/dist/Reification.mjs +1 -0
- package/dist/Report-XHs8htzK.mjs +121 -0
- package/dist/Report-XHs8htzK.mjs.map +1 -0
- package/dist/Report-hcXsc_19.d.mts +115 -0
- package/dist/Resource-B1cI8FyJ.d.mts +218 -0
- package/dist/Resource-sIEeNh15.mjs +374 -0
- package/dist/Resource-sIEeNh15.mjs.map +1 -0
- package/dist/Resource.d.mts +2 -0
- package/dist/Resource.mjs +1 -0
- package/dist/Results-BVNEC-Wt.d.mts +277 -0
- package/dist/Results-peJjGA2V.mjs +621 -0
- package/dist/Results-peJjGA2V.mjs.map +1 -0
- package/dist/ResultsStream-BhF0OcNn.mjs +639 -0
- package/dist/ResultsStream-BhF0OcNn.mjs.map +1 -0
- package/dist/ResultsStream-toYMXrOe.d.mts +100 -0
- package/dist/SemAct-CDchtk49.d.mts +96 -0
- package/dist/SemAct-CmyT4yI8.mjs +118 -0
- package/dist/SemAct-CmyT4yI8.mjs.map +1 -0
- package/dist/Serialization-DP9H5bYQ.mjs +514 -0
- package/dist/Serialization-DP9H5bYQ.mjs.map +1 -0
- package/dist/Serialization-Df8iVauT.d.mts +392 -0
- package/dist/Serialization.d.mts +2 -0
- package/dist/Serialization.mjs +1 -0
- package/dist/ServerFormats-CrRnjjf6.mjs +64 -0
- package/dist/ServerFormats-CrRnjjf6.mjs.map +1 -0
- package/dist/ServerFormats-DjC9NsO_.d.mts +36 -0
- package/dist/ServiceDescription-BERsvg-k.d.mts +54 -0
- package/dist/ServiceDescription-Dq5hxeGy.mjs +97 -0
- package/dist/ServiceDescription-Dq5hxeGy.mjs.map +1 -0
- package/dist/ShExC-Ctf-06CL.d.mts +67 -0
- package/dist/ShExC-DJbB19i3.mjs +1181 -0
- package/dist/ShExC-DJbB19i3.mjs.map +1 -0
- package/dist/ShExError-BeYFD9rv.d.mts +61 -0
- package/dist/ShExError-CVtq2NnM.mjs +64 -0
- package/dist/ShExError-CVtq2NnM.mjs.map +1 -0
- package/dist/ShExJ-C1u_wgyD.d.mts +531 -0
- package/dist/ShExJ-COiPd9Xw.mjs +532 -0
- package/dist/ShExJ-COiPd9Xw.mjs.map +1 -0
- package/dist/ShExR-ByR4mCh-.mjs +480 -0
- package/dist/ShExR-ByR4mCh-.mjs.map +1 -0
- package/dist/ShExR-CqONNNBz.d.mts +40 -0
- package/dist/ShapeMap-C422pxKl.d.mts +140 -0
- package/dist/ShapeMap-CsgKxB2G.mjs +181 -0
- package/dist/ShapeMap-CsgKxB2G.mjs.map +1 -0
- package/dist/Shapes-18GjfyBV.mjs +597 -0
- package/dist/Shapes-18GjfyBV.mjs.map +1 -0
- package/dist/Shapes-BQFDFc4Q.d.mts +306 -0
- package/dist/Sparql-BiYFMSpl.mjs +29 -0
- package/dist/Sparql-BiYFMSpl.mjs.map +1 -0
- package/dist/Sparql-DecpWTPh.d.mts +97 -0
- package/dist/SparqlClient-C_CjXbwj.mjs +333 -0
- package/dist/SparqlClient-C_CjXbwj.mjs.map +1 -0
- package/dist/SparqlClient-UPc88SHy.d.mts +290 -0
- package/dist/SparqlServer-CbUW-pVj.d.mts +71 -0
- package/dist/SparqlServer-Db7w7Cll.mjs +308 -0
- package/dist/SparqlServer-Db7w7Cll.mjs.map +1 -0
- package/dist/SqlStore-BBqFx-Wl.mjs +684 -0
- package/dist/SqlStore-BBqFx-Wl.mjs.map +1 -0
- package/dist/SqlStore-CCJo5I-e.d.mts +117 -0
- package/dist/Store-D0jmVfb3.d.mts +166 -0
- package/dist/Store-DH3Ow1GO.mjs +162 -0
- package/dist/Store-DH3Ow1GO.mjs.map +1 -0
- package/dist/Structure-BjMo4Bkc.mjs +334 -0
- package/dist/Structure-BjMo4Bkc.mjs.map +1 -0
- package/dist/Structure-n4CmDiab.d.mts +63 -0
- package/dist/Table-BGgm9nbM.mjs +538 -0
- package/dist/Table-BGgm9nbM.mjs.map +1 -0
- package/dist/Table-C3reiVrb.d.mts +261 -0
- package/dist/Term-B_4ezyXq.d.mts +619 -0
- package/dist/Term-CFLG1qu4.mjs +991 -0
- package/dist/Term-CFLG1qu4.mjs.map +1 -0
- package/dist/Term.d.mts +2 -0
- package/dist/Term.mjs +1 -0
- package/dist/TermCodec-CDZiEztW.mjs +397 -0
- package/dist/TermCodec-CDZiEztW.mjs.map +1 -0
- package/dist/TermCodec-_03bDXr0.d.mts +209 -0
- package/dist/TermCodec.d.mts +2 -0
- package/dist/TermCodec.mjs +1 -0
- package/dist/TermJson-BOPe0yve.d.mts +232 -0
- package/dist/TermJson-FAg3lvjl.mjs +142 -0
- package/dist/TermJson-FAg3lvjl.mjs.map +1 -0
- package/dist/TermJson.d.mts +2 -0
- package/dist/TermJson.mjs +1 -0
- package/dist/TermSchema-Bn9CoaYA.mjs +30 -0
- package/dist/TermSchema-Bn9CoaYA.mjs.map +1 -0
- package/dist/TermSchema-DBO6MroX.d.mts +6 -0
- package/dist/Testing-B-aPCpmu.mjs +63 -0
- package/dist/Testing-B-aPCpmu.mjs.map +1 -0
- package/dist/Testing-CF6s8P3O.d.mts +53 -0
- package/dist/Tiff-CR-2QeSI.d.mts +148 -0
- package/dist/Tiff-DlsOlZPM.mjs +169 -0
- package/dist/Tiff-DlsOlZPM.mjs.map +1 -0
- package/dist/Tools-7MdRKccr.d.mts +583 -0
- package/dist/Tools-ryxphZbI.mjs +329 -0
- package/dist/Tools-ryxphZbI.mjs.map +1 -0
- package/dist/Translate-B0YKKANS.d.mts +37 -0
- package/dist/Translate-gzWPq0Ia.mjs +308 -0
- package/dist/Translate-gzWPq0Ia.mjs.map +1 -0
- package/dist/Translation-DC9rLm2y.mjs +1535 -0
- package/dist/Translation-DC9rLm2y.mjs.map +1 -0
- package/dist/Translation-K4L9XBqX.d.mts +103 -0
- package/dist/TriG-BkqtqZ6Y.mjs +125 -0
- package/dist/TriG-BkqtqZ6Y.mjs.map +1 -0
- package/dist/TriG-xDjdDatp.d.mts +86 -0
- package/dist/Turtle-Bv1_bisW.d.mts +85 -0
- package/dist/Turtle-CZVUOtwl.mjs +133 -0
- package/dist/Turtle-CZVUOtwl.mjs.map +1 -0
- package/dist/ValidationReport-DBdJshW5.mjs +285 -0
- package/dist/ValidationReport-DBdJshW5.mjs.map +1 -0
- package/dist/ValidationReport-Dx3WxY0h.d.mts +192 -0
- package/dist/Validator-227ff9Rn.d.mts +179 -0
- package/dist/Validator-BzXMKDeJ.mjs +1162 -0
- package/dist/Validator-BzXMKDeJ.mjs.map +1 -0
- package/dist/Validator-Dl8cih5V.d.mts +207 -0
- package/dist/Validator-DmUfMbpL.mjs +568 -0
- package/dist/Validator-DmUfMbpL.mjs.map +1 -0
- package/dist/Vocab-DceKywpq.mjs +168 -0
- package/dist/Vocab-DceKywpq.mjs.map +1 -0
- package/dist/Vocab-Df-L-IwZ.d.mts +46 -0
- package/dist/Vocab-Do56UgBX.d.mts +81 -0
- package/dist/Vocab-TfpWG1Ne.mjs +118 -0
- package/dist/Vocab-TfpWG1Ne.mjs.map +1 -0
- package/dist/Vocab.d.mts +2 -0
- package/dist/Vocab.mjs +1 -0
- package/dist/Vocabulary-C6-GPOy4.d.mts +22 -0
- package/dist/Vocabulary-CnQl-_Z4.mjs +179 -0
- package/dist/Vocabulary-CnQl-_Z4.mjs.map +1 -0
- package/dist/Xml-B7iihYCS.mjs +976 -0
- package/dist/Xml-B7iihYCS.mjs.map +1 -0
- package/dist/Xml-CmfHS7SW.d.mts +267 -0
- package/dist/Xmp-D7CKA7MZ.d.mts +111 -0
- package/dist/Xmp-DCGN9pOD.mjs +307 -0
- package/dist/Xmp-DCGN9pOD.mjs.map +1 -0
- package/dist/XmpBasic-CP38jpR_.mjs +73 -0
- package/dist/XmpBasic-CP38jpR_.mjs.map +1 -0
- package/dist/XmpBasic-Cmbe53rQ.d.mts +64 -0
- package/dist/XmpMM-BfL_TgJF.mjs +73 -0
- package/dist/XmpMM-BfL_TgJF.mjs.map +1 -0
- package/dist/XmpMM-Dqm3IX8p.d.mts +63 -0
- package/dist/XmpRights-BKPtoI5L.mjs +73 -0
- package/dist/XmpRights-BKPtoI5L.mjs.map +1 -0
- package/dist/XmpRights-CaALZQz2.d.mts +63 -0
- package/dist/Xsd-Cdgx5zRB.mjs +405 -0
- package/dist/Xsd-Cdgx5zRB.mjs.map +1 -0
- package/dist/Xsd-D2elNhSm.d.mts +187 -0
- package/dist/Xsd.d.mts +2 -0
- package/dist/Xsd.mjs +1 -0
- package/dist/accessors-CEjaojuQ.mjs +28 -0
- package/dist/accessors-CEjaojuQ.mjs.map +1 -0
- package/dist/codec-Lb2T96rv.d.mts +20 -0
- package/dist/codec-QNo7IdJF.mjs +389 -0
- package/dist/codec-QNo7IdJF.mjs.map +1 -0
- package/dist/csvw/Csv2Json.d.mts +2 -0
- package/dist/csvw/Csv2Json.mjs +1 -0
- package/dist/csvw/Csv2Rdf.d.mts +2 -0
- package/dist/csvw/Csv2Rdf.mjs +1 -0
- package/dist/csvw/Datatype.d.mts +2 -0
- package/dist/csvw/Datatype.mjs +1 -0
- package/dist/csvw/Metadata.d.mts +2 -0
- package/dist/csvw/Metadata.mjs +1 -0
- package/dist/csvw/Processor.d.mts +2 -0
- package/dist/csvw/Processor.mjs +1 -0
- package/dist/csvw/Report.d.mts +2 -0
- package/dist/csvw/Report.mjs +1 -0
- package/dist/csvw/Table.d.mts +2 -0
- package/dist/csvw/Table.mjs +1 -0
- package/dist/csvw/index.d.mts +8 -0
- package/dist/csvw/index.mjs +8 -0
- package/dist/index-Cms2TYfC.d.mts +16 -0
- package/dist/index-Ct8xFmRs.d.mts +7 -0
- package/dist/index-D4QFwOjm.d.mts +28 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +17 -0
- package/dist/jsonld/DocumentLoader.d.mts +2 -0
- package/dist/jsonld/DocumentLoader.mjs +1 -0
- package/dist/jsonld/JsonLd.d.mts +2 -0
- package/dist/jsonld/JsonLd.mjs +1 -0
- package/dist/jsonld/JsonLdError.d.mts +2 -0
- package/dist/jsonld/JsonLdError.mjs +1 -0
- package/dist/jsonld/index.d.mts +4 -0
- package/dist/jsonld/index.mjs +4 -0
- package/dist/lists-D-OpQ0Ir.mjs +77 -0
- package/dist/lists-D-OpQ0Ir.mjs.map +1 -0
- package/dist/loop-D5-gNx9K.mjs +21 -0
- package/dist/loop-D5-gNx9K.mjs.map +1 -0
- package/dist/loop-DZ2hXlr_.mjs +21 -0
- package/dist/loop-DZ2hXlr_.mjs.map +1 -0
- package/dist/n3/Isomorphism.d.mts +2 -0
- package/dist/n3/Isomorphism.mjs +1 -0
- package/dist/n3/Mapping.d.mts +2 -0
- package/dist/n3/Mapping.mjs +1 -0
- package/dist/n3/Model.d.mts +2 -0
- package/dist/n3/Model.mjs +1 -0
- package/dist/n3/N3.d.mts +2 -0
- package/dist/n3/N3.mjs +1 -0
- package/dist/n3/Reasoner.d.mts +2 -0
- package/dist/n3/Reasoner.mjs +2 -0
- package/dist/n3/Vocab.d.mts +2 -0
- package/dist/n3/Vocab.mjs +1 -0
- package/dist/n3/index.d.mts +7 -0
- package/dist/n3/index.mjs +7 -0
- package/dist/ntriples/Grammar.d.mts +2 -0
- package/dist/ntriples/Grammar.mjs +1 -0
- package/dist/ntriples/Lexical.d.mts +2 -0
- package/dist/ntriples/Lexical.mjs +1 -0
- package/dist/ntriples/NQuads.d.mts +2 -0
- package/dist/ntriples/NQuads.mjs +1 -0
- package/dist/ntriples/NTriples.d.mts +2 -0
- package/dist/ntriples/NTriples.mjs +1 -0
- package/dist/ntriples/index.d.mts +5 -0
- package/dist/ntriples/index.mjs +5 -0
- package/dist/rdfjson/RdfJson.d.mts +2 -0
- package/dist/rdfjson/RdfJson.mjs +1 -0
- package/dist/rdfjson/index.d.mts +2 -0
- package/dist/rdfjson/index.mjs +1 -0
- package/dist/rdfxml/RdfXml.d.mts +2 -0
- package/dist/rdfxml/RdfXml.mjs +1 -0
- package/dist/rdfxml/Xml.d.mts +2 -0
- package/dist/rdfxml/Xml.mjs +1 -0
- package/dist/rdfxml/index.d.mts +3 -0
- package/dist/rdfxml/index.mjs +3 -0
- package/dist/rolldown-runtime-D8jQpDG7.mjs +12 -0
- package/dist/serialize-96KBvKaf.mjs +1463 -0
- package/dist/serialize-96KBvKaf.mjs.map +1 -0
- package/dist/serialize-DsoXdM6n.d.mts +37 -0
- package/dist/shacl/Message.d.mts +2 -0
- package/dist/shacl/Message.mjs +1 -0
- package/dist/shacl/Path.d.mts +2 -0
- package/dist/shacl/Path.mjs +1 -0
- package/dist/shacl/Shapes.d.mts +2 -0
- package/dist/shacl/Shapes.mjs +1 -0
- package/dist/shacl/Sparql.d.mts +2 -0
- package/dist/shacl/Sparql.mjs +1 -0
- package/dist/shacl/ValidationReport.d.mts +2 -0
- package/dist/shacl/ValidationReport.mjs +1 -0
- package/dist/shacl/Validator.d.mts +2 -0
- package/dist/shacl/Validator.mjs +1 -0
- package/dist/shacl/Vocabulary.d.mts +2 -0
- package/dist/shacl/Vocabulary.mjs +1 -0
- package/dist/shacl/index.d.mts +9 -0
- package/dist/shacl/index.mjs +8 -0
- package/dist/shex/SemAct.d.mts +2 -0
- package/dist/shex/SemAct.mjs +1 -0
- package/dist/shex/ShExC.d.mts +2 -0
- package/dist/shex/ShExC.mjs +1 -0
- package/dist/shex/ShExError.d.mts +2 -0
- package/dist/shex/ShExError.mjs +1 -0
- package/dist/shex/ShExJ.d.mts +2 -0
- package/dist/shex/ShExJ.mjs +2 -0
- package/dist/shex/ShExR.d.mts +2 -0
- package/dist/shex/ShExR.mjs +1 -0
- package/dist/shex/ShapeMap.d.mts +2 -0
- package/dist/shex/ShapeMap.mjs +1 -0
- package/dist/shex/Structure.d.mts +2 -0
- package/dist/shex/Structure.mjs +2 -0
- package/dist/shex/Validator.d.mts +2 -0
- package/dist/shex/Validator.mjs +4 -0
- package/dist/shex/index.d.mts +9 -0
- package/dist/shex/index.mjs +9 -0
- package/dist/sparql/Algebra.d.mts +2 -0
- package/dist/sparql/Algebra.mjs +1 -0
- package/dist/sparql/Ast.d.mts +2 -0
- package/dist/sparql/Ast.mjs +1 -0
- package/dist/sparql/Bindings.d.mts +2 -0
- package/dist/sparql/Bindings.mjs +1 -0
- package/dist/sparql/ClientErrors.d.mts +2 -0
- package/dist/sparql/ClientErrors.mjs +1 -0
- package/dist/sparql/ClientFormats.d.mts +2 -0
- package/dist/sparql/ClientFormats.mjs +1 -0
- package/dist/sparql/Engine.d.mts +2 -0
- package/dist/sparql/Engine.mjs +1 -0
- package/dist/sparql/Errors.d.mts +2 -0
- package/dist/sparql/Errors.mjs +1 -0
- package/dist/sparql/Expression.d.mts +2 -0
- package/dist/sparql/Expression.mjs +1 -0
- package/dist/sparql/Federation.d.mts +2 -0
- package/dist/sparql/Federation.mjs +1 -0
- package/dist/sparql/Functions.d.mts +2 -0
- package/dist/sparql/Functions.mjs +1 -0
- package/dist/sparql/Generator.d.mts +2 -0
- package/dist/sparql/Generator.mjs +1 -0
- package/dist/sparql/GraphStore.d.mts +2 -0
- package/dist/sparql/GraphStore.mjs +1 -0
- package/dist/sparql/Optimizer.d.mts +2 -0
- package/dist/sparql/Optimizer.mjs +1 -0
- package/dist/sparql/Options.d.mts +2 -0
- package/dist/sparql/Options.mjs +1 -0
- package/dist/sparql/Parser.d.mts +2 -0
- package/dist/sparql/Parser.mjs +1 -0
- package/dist/sparql/Protocol.d.mts +2 -0
- package/dist/sparql/Protocol.mjs +1 -0
- package/dist/sparql/ProtocolErrors.d.mts +2 -0
- package/dist/sparql/ProtocolErrors.mjs +1 -0
- package/dist/sparql/QueryBuilder.d.mts +2 -0
- package/dist/sparql/QueryBuilder.mjs +1 -0
- package/dist/sparql/Results.d.mts +2 -0
- package/dist/sparql/Results.mjs +1 -0
- package/dist/sparql/ResultsStream.d.mts +2 -0
- package/dist/sparql/ResultsStream.mjs +1 -0
- package/dist/sparql/ServerFormats.d.mts +2 -0
- package/dist/sparql/ServerFormats.mjs +1 -0
- package/dist/sparql/ServiceDescription.d.mts +2 -0
- package/dist/sparql/ServiceDescription.mjs +1 -0
- package/dist/sparql/SparqlClient.d.mts +2 -0
- package/dist/sparql/SparqlClient.mjs +1 -0
- package/dist/sparql/SparqlServer.d.mts +2 -0
- package/dist/sparql/SparqlServer.mjs +1 -0
- package/dist/sparql/Store.d.mts +2 -0
- package/dist/sparql/Store.mjs +1 -0
- package/dist/sparql/TermSchema.d.mts +3 -0
- package/dist/sparql/TermSchema.mjs +2 -0
- package/dist/sparql/Testing.d.mts +2 -0
- package/dist/sparql/Testing.mjs +1 -0
- package/dist/sparql/Translate.d.mts +2 -0
- package/dist/sparql/Translate.mjs +1 -0
- package/dist/sparql/ai/Mcp.d.mts +2 -0
- package/dist/sparql/ai/Mcp.mjs +1 -0
- package/dist/sparql/ai/Tools.d.mts +2 -0
- package/dist/sparql/ai/Tools.mjs +1 -0
- package/dist/sparql/ai/index.d.mts +3 -0
- package/dist/sparql/ai/index.mjs +3 -0
- package/dist/sparql/index.d.mts +30 -0
- package/dist/sparql/index.mjs +29 -0
- package/dist/sparql/shacl/Evaluator.d.mts +2 -0
- package/dist/sparql/shacl/Evaluator.mjs +1 -0
- package/dist/sparql/shacl/Query.d.mts +2 -0
- package/dist/sparql/shacl/Query.mjs +1 -0
- package/dist/sparql/shacl/index.d.mts +3 -0
- package/dist/sparql/shacl/index.mjs +3 -0
- package/dist/sparql/sql/Dialect.d.mts +2 -0
- package/dist/sparql/sql/Dialect.mjs +1 -0
- package/dist/sparql/sql/SqlStore.d.mts +2 -0
- package/dist/sparql/sql/SqlStore.mjs +1 -0
- package/dist/sparql/sql/Translation.d.mts +2 -0
- package/dist/sparql/sql/Translation.mjs +1 -0
- package/dist/sparql/sql/index.d.mts +4 -0
- package/dist/sparql/sql/index.mjs +4 -0
- package/dist/stringMap-D5YIpYtR.mjs +38 -0
- package/dist/stringMap-D5YIpYtR.mjs.map +1 -0
- package/dist/tokens-C6BzeodQ.mjs +24 -0
- package/dist/tokens-C6BzeodQ.mjs.map +1 -0
- package/dist/turtle/Grammar.d.mts +3 -0
- package/dist/turtle/Grammar.mjs +3 -0
- package/dist/turtle/Manifest.d.mts +2 -0
- package/dist/turtle/Manifest.mjs +1 -0
- package/dist/turtle/TriG.d.mts +2 -0
- package/dist/turtle/TriG.mjs +1 -0
- package/dist/turtle/Turtle.d.mts +2 -0
- package/dist/turtle/Turtle.mjs +1 -0
- package/dist/turtle/index.d.mts +5 -0
- package/dist/turtle/index.mjs +5 -0
- package/dist/xmp/DublinCore.d.mts +2 -0
- package/dist/xmp/DublinCore.mjs +1 -0
- package/dist/xmp/Exif.d.mts +2 -0
- package/dist/xmp/Exif.mjs +1 -0
- package/dist/xmp/Extract.d.mts +2 -0
- package/dist/xmp/Extract.mjs +1 -0
- package/dist/xmp/Metadata.d.mts +2 -0
- package/dist/xmp/Metadata.mjs +1 -0
- package/dist/xmp/Namespaces.d.mts +2 -0
- package/dist/xmp/Namespaces.mjs +1 -0
- package/dist/xmp/Packet.d.mts +2 -0
- package/dist/xmp/Packet.mjs +1 -0
- package/dist/xmp/Pdf.d.mts +2 -0
- package/dist/xmp/Pdf.mjs +1 -0
- package/dist/xmp/PdfA.d.mts +2 -0
- package/dist/xmp/PdfA.mjs +1 -0
- package/dist/xmp/Photoshop.d.mts +2 -0
- package/dist/xmp/Photoshop.mjs +1 -0
- package/dist/xmp/Tiff.d.mts +2 -0
- package/dist/xmp/Tiff.mjs +1 -0
- package/dist/xmp/Xmp.d.mts +2 -0
- package/dist/xmp/Xmp.mjs +3 -0
- package/dist/xmp/XmpBasic.d.mts +2 -0
- package/dist/xmp/XmpBasic.mjs +1 -0
- package/dist/xmp/XmpMM.d.mts +2 -0
- package/dist/xmp/XmpMM.mjs +1 -0
- package/dist/xmp/XmpRights.d.mts +2 -0
- package/dist/xmp/XmpRights.mjs +1 -0
- package/dist/xmp/index.d.mts +15 -0
- package/dist/xmp/index.mjs +15 -0
- package/package.json +187 -3
- package/src/Dataset.ts +1085 -0
- package/src/Iri.ts +322 -0
- package/src/Isomorphism.ts +319 -0
- package/src/LanguageTag.ts +98 -0
- package/src/Namespace.ts +100 -0
- package/src/PrefixMap.ts +117 -0
- package/src/RdfJs.ts +146 -0
- package/src/Rdfs.ts +241 -0
- package/src/Reification.ts +103 -0
- package/src/Resource.ts +873 -0
- package/src/Serialization.ts +775 -0
- package/src/Term.ts +1300 -0
- package/src/TermCodec.ts +505 -0
- package/src/TermJson.ts +313 -0
- package/src/Vocab.ts +161 -0
- package/src/Xsd.ts +573 -0
- package/src/csvw/Csv2Json.ts +265 -0
- package/src/csvw/Csv2Rdf.ts +268 -0
- package/src/csvw/Datatype.ts +589 -0
- package/src/csvw/Metadata.ts +1523 -0
- package/src/csvw/Processor.ts +276 -0
- package/src/csvw/Report.ts +135 -0
- package/src/csvw/Table.ts +759 -0
- package/src/csvw/index.ts +22 -0
- package/src/csvw/internal/dateFormat.ts +202 -0
- package/src/csvw/internal/json.ts +104 -0
- package/src/csvw/internal/numberFormat.ts +369 -0
- package/src/csvw/internal/object.ts +23 -0
- package/src/csvw/internal/uriTemplate.ts +130 -0
- package/src/csvw/internal/url.ts +93 -0
- package/src/csvw/internal/vocab.ts +282 -0
- package/src/index.ts +40 -0
- package/src/internal/arbitrary.ts +148 -0
- package/src/internal/loop.ts +24 -0
- package/src/internal/pending.ts +20 -0
- package/src/internal/textDecoder.ts +183 -0
- package/src/jsonld/DocumentLoader.ts +512 -0
- package/src/jsonld/JsonLd.ts +847 -0
- package/src/jsonld/JsonLdError.ts +105 -0
- package/src/jsonld/index.ts +13 -0
- package/src/jsonld/internal/compact.ts +852 -0
- package/src/jsonld/internal/context.ts +781 -0
- package/src/jsonld/internal/expand.ts +614 -0
- package/src/jsonld/internal/flatten.ts +243 -0
- package/src/jsonld/internal/frame.ts +559 -0
- package/src/jsonld/internal/iri.ts +52 -0
- package/src/jsonld/internal/json.ts +19 -0
- package/src/jsonld/internal/linkHeader.ts +60 -0
- package/src/jsonld/internal/rdf.ts +481 -0
- package/src/jsonld/internal/util.ts +367 -0
- package/src/n3/Isomorphism.ts +476 -0
- package/src/n3/Mapping.ts +332 -0
- package/src/n3/Model.ts +696 -0
- package/src/n3/N3.ts +237 -0
- package/src/n3/Reasoner.ts +568 -0
- package/src/n3/Vocab.ts +111 -0
- package/src/n3/index.ts +21 -0
- package/src/n3/internal/builtins.ts +668 -0
- package/src/n3/internal/guards.ts +23 -0
- package/src/n3/internal/lists.ts +106 -0
- package/src/n3/internal/loop.ts +28 -0
- package/src/n3/internal/parser.ts +1032 -0
- package/src/n3/internal/writer.ts +344 -0
- package/src/ntriples/Grammar.ts +317 -0
- package/src/ntriples/Lexical.ts +321 -0
- package/src/ntriples/NQuads.ts +140 -0
- package/src/ntriples/NTriples.ts +143 -0
- package/src/ntriples/index.ts +14 -0
- package/src/ntriples/internal/codec.ts +229 -0
- package/src/ntriples/internal/lineParser.ts +326 -0
- package/src/ntriples/internal/loop.ts +14 -0
- package/src/rdfjson/RdfJson.ts +806 -0
- package/src/rdfjson/index.ts +9 -0
- package/src/rdfjson/internal/json.ts +19 -0
- package/src/rdfxml/RdfXml.ts +1408 -0
- package/src/rdfxml/Xml.ts +419 -0
- package/src/rdfxml/index.ts +11 -0
- package/src/rdfxml/internal/chars.ts +73 -0
- package/src/rdfxml/internal/loop.ts +24 -0
- package/src/rdfxml/internal/parser.ts +1265 -0
- package/src/shacl/Message.ts +102 -0
- package/src/shacl/Path.ts +483 -0
- package/src/shacl/Shapes.ts +913 -0
- package/src/shacl/Sparql.ts +128 -0
- package/src/shacl/ValidationReport.ts +438 -0
- package/src/shacl/Validator.ts +1156 -0
- package/src/shacl/Vocabulary.ts +180 -0
- package/src/shacl/index.ts +22 -0
- package/src/shacl/internal/compare.ts +128 -0
- package/src/shacl/internal/regex.ts +56 -0
- package/src/shex/SemAct.ts +197 -0
- package/src/shex/ShExC.ts +415 -0
- package/src/shex/ShExError.ts +71 -0
- package/src/shex/ShExJ.ts +893 -0
- package/src/shex/ShExR.ts +640 -0
- package/src/shex/ShapeMap.ts +385 -0
- package/src/shex/Structure.ts +467 -0
- package/src/shex/Validator.ts +395 -0
- package/src/shex/index.ts +24 -0
- package/src/shex/internal/engine.ts +682 -0
- package/src/shex/internal/iterate.ts +14 -0
- package/src/shex/internal/json.ts +12 -0
- package/src/shex/internal/lexer.ts +56 -0
- package/src/shex/internal/nodeConstraint.ts +368 -0
- package/src/shex/internal/shexcLexer.ts +387 -0
- package/src/shex/internal/shexcParser.ts +1312 -0
- package/src/shex/internal/tokens.ts +41 -0
- package/src/shex/internal/xpathRegex.ts +290 -0
- package/src/sparql/Algebra.ts +914 -0
- package/src/sparql/Ast.ts +1344 -0
- package/src/sparql/Bindings.ts +272 -0
- package/src/sparql/ClientErrors.ts +156 -0
- package/src/sparql/ClientFormats.ts +70 -0
- package/src/sparql/Engine.ts +699 -0
- package/src/sparql/Errors.ts +30 -0
- package/src/sparql/Expression.ts +360 -0
- package/src/sparql/Federation.ts +187 -0
- package/src/sparql/Functions.ts +689 -0
- package/src/sparql/Generator.ts +426 -0
- package/src/sparql/GraphStore.ts +341 -0
- package/src/sparql/Optimizer.ts +230 -0
- package/src/sparql/Options.ts +191 -0
- package/src/sparql/Parser.ts +173 -0
- package/src/sparql/Protocol.ts +342 -0
- package/src/sparql/ProtocolErrors.ts +113 -0
- package/src/sparql/QueryBuilder.ts +953 -0
- package/src/sparql/Results.ts +844 -0
- package/src/sparql/ResultsStream.ts +771 -0
- package/src/sparql/ServerFormats.ts +75 -0
- package/src/sparql/ServiceDescription.ts +130 -0
- package/src/sparql/SparqlClient.ts +947 -0
- package/src/sparql/SparqlServer.ts +528 -0
- package/src/sparql/Store.ts +311 -0
- package/src/sparql/TermSchema.ts +20 -0
- package/src/sparql/Testing.ts +114 -0
- package/src/sparql/Translate.ts +407 -0
- package/src/sparql/ai/Mcp.ts +43 -0
- package/src/sparql/ai/Tools.ts +481 -0
- package/src/sparql/ai/index.ts +11 -0
- package/src/sparql/index.ts +64 -0
- package/src/sparql/internal/evaluator.ts +947 -0
- package/src/sparql/internal/hash.ts +418 -0
- package/src/sparql/internal/json.ts +12 -0
- package/src/sparql/internal/lexer.ts +488 -0
- package/src/sparql/internal/loop.ts +24 -0
- package/src/sparql/internal/parser.ts +2215 -0
- package/src/sparql/internal/prefetch.ts +46 -0
- package/src/sparql/internal/stringMap.ts +39 -0
- package/src/sparql/internal/textResults.ts +226 -0
- package/src/sparql/internal/values.ts +550 -0
- package/src/sparql/shacl/Evaluator.ts +478 -0
- package/src/sparql/shacl/Query.ts +574 -0
- package/src/sparql/shacl/index.ts +12 -0
- package/src/sparql/sql/Dialect.ts +246 -0
- package/src/sparql/sql/SqlStore.ts +1080 -0
- package/src/sparql/sql/Translation.ts +1898 -0
- package/src/sparql/sql/index.ts +17 -0
- package/src/sparql/sql/internal/encoding.ts +313 -0
- package/src/turtle/Grammar.ts +286 -0
- package/src/turtle/Manifest.ts +215 -0
- package/src/turtle/TriG.ts +158 -0
- package/src/turtle/Turtle.ts +166 -0
- package/src/turtle/index.ts +14 -0
- package/src/turtle/internal/loop.ts +23 -0
- package/src/turtle/internal/parse.ts +112 -0
- package/src/turtle/internal/parser.ts +1303 -0
- package/src/turtle/internal/serialize.ts +79 -0
- package/src/turtle/internal/streamWriter.ts +128 -0
- package/src/turtle/internal/writer.ts +898 -0
- package/src/xmp/DublinCore.ts +147 -0
- package/src/xmp/Exif.ts +109 -0
- package/src/xmp/Extract.ts +351 -0
- package/src/xmp/Metadata.ts +703 -0
- package/src/xmp/Namespaces.ts +228 -0
- package/src/xmp/Packet.ts +297 -0
- package/src/xmp/Pdf.ts +99 -0
- package/src/xmp/PdfA.ts +280 -0
- package/src/xmp/Photoshop.ts +275 -0
- package/src/xmp/Tiff.ts +196 -0
- package/src/xmp/Xmp.ts +430 -0
- package/src/xmp/XmpBasic.ts +90 -0
- package/src/xmp/XmpMM.ts +82 -0
- package/src/xmp/XmpRights.ts +83 -0
- package/src/xmp/index.ts +36 -0
- package/src/xmp/internal/accessors.ts +72 -0
- package/src/xmp/internal/xml.ts +63 -0
|
@@ -0,0 +1,1523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSVW metadata documents (Metadata Vocabulary for Tabular Data): the
|
|
3
|
+
* normalized description model as Effect `Schema`s (table groups, tables,
|
|
4
|
+
* schemas, columns, dialects, foreign keys, transformations), and decoding a
|
|
5
|
+
* JSON-LD metadata document with its fixed `http://www.w3.org/ns/csvw`
|
|
6
|
+
* context into that model — validating every property, warning about and
|
|
7
|
+
* dropping invalid values, failing on errors, and normalizing per §Normalization
|
|
8
|
+
* (absolute URLs, natural-language and common properties, referenced schemas
|
|
9
|
+
* and dialects fetched and inlined).
|
|
10
|
+
*
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
import { LanguageTag } from '../index.ts';
|
|
14
|
+
import * as Arr from 'effect/Array';
|
|
15
|
+
import * as Effect from 'effect/Effect';
|
|
16
|
+
import * as Option from 'effect/Option';
|
|
17
|
+
import * as Predicate from 'effect/Predicate';
|
|
18
|
+
import * as Record from 'effect/Record';
|
|
19
|
+
import * as Result from 'effect/Result';
|
|
20
|
+
import * as Schema from 'effect/Schema';
|
|
21
|
+
import * as Datatype from './Datatype.ts';
|
|
22
|
+
import * as Report from './Report.ts';
|
|
23
|
+
import * as Json from './internal/json.ts';
|
|
24
|
+
import { optional } from './internal/object.ts';
|
|
25
|
+
import * as Url from './internal/url.ts';
|
|
26
|
+
import * as Vocab from './internal/vocab.ts';
|
|
27
|
+
|
|
28
|
+
// -----------------------------------------------------------------------------
|
|
29
|
+
// Errors
|
|
30
|
+
// -----------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A metadata document that cannot be used: invalid JSON, an invalid
|
|
34
|
+
* `@context`, a missing required property, or a value the specification
|
|
35
|
+
* says is an error (processing stops).
|
|
36
|
+
*
|
|
37
|
+
* @since 0.1.0
|
|
38
|
+
* @category errors
|
|
39
|
+
*/
|
|
40
|
+
export class MetadataError extends Schema.TaggedError<MetadataError>()('MetadataError', {
|
|
41
|
+
message: Schema.String,
|
|
42
|
+
url: Schema.optional(Schema.String),
|
|
43
|
+
}) {}
|
|
44
|
+
|
|
45
|
+
// -----------------------------------------------------------------------------
|
|
46
|
+
// Model
|
|
47
|
+
// -----------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A natural-language property's value: language tags (`und` when unknown)
|
|
51
|
+
* mapped to strings.
|
|
52
|
+
*
|
|
53
|
+
* @since 0.1.0
|
|
54
|
+
* @category models
|
|
55
|
+
*/
|
|
56
|
+
export const LanguageMap = Schema.Record(Schema.String, Schema.Array(Schema.String));
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @since 0.1.0
|
|
60
|
+
* @category models
|
|
61
|
+
*/
|
|
62
|
+
export type LanguageMap = typeof LanguageMap.Type;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Common properties and notes in normalized form: prefixed names or absolute
|
|
66
|
+
* URLs mapped to JSON-LD values.
|
|
67
|
+
*
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
* @category models
|
|
70
|
+
*/
|
|
71
|
+
export const CommonProperties = Schema.Record(Schema.String, Schema.Json);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @since 0.1.0
|
|
75
|
+
* @category models
|
|
76
|
+
*/
|
|
77
|
+
export type CommonProperties = typeof CommonProperties.Type;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The text direction of cells.
|
|
81
|
+
*
|
|
82
|
+
* @since 0.1.0
|
|
83
|
+
* @category models
|
|
84
|
+
*/
|
|
85
|
+
export const TextDirection = Schema.Literals(['ltr', 'rtl', 'auto', 'inherit']);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @since 0.1.0
|
|
89
|
+
* @category models
|
|
90
|
+
*/
|
|
91
|
+
export type TextDirection = typeof TextDirection.Type;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The direction of a table's columns.
|
|
95
|
+
*
|
|
96
|
+
* @since 0.1.0
|
|
97
|
+
* @category models
|
|
98
|
+
*/
|
|
99
|
+
export const TableDirection = Schema.Literals(['ltr', 'rtl', 'auto']);
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @since 0.1.0
|
|
103
|
+
* @category models
|
|
104
|
+
*/
|
|
105
|
+
export type TableDirection = typeof TableDirection.Type;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The inherited properties of a description (§Inherited Properties), set
|
|
109
|
+
* where they were specified; a column inherits each unset one from its
|
|
110
|
+
* schema, table and table group.
|
|
111
|
+
*
|
|
112
|
+
* @since 0.1.0
|
|
113
|
+
* @category models
|
|
114
|
+
*/
|
|
115
|
+
export const Inherited = Schema.Struct({
|
|
116
|
+
aboutUrl: Schema.optional(Schema.String),
|
|
117
|
+
datatype: Schema.optional(Datatype.Datatype),
|
|
118
|
+
default: Schema.optional(Schema.String),
|
|
119
|
+
lang: Schema.optional(Schema.String),
|
|
120
|
+
null: Schema.optional(Schema.Array(Schema.String)),
|
|
121
|
+
ordered: Schema.optional(Schema.Boolean),
|
|
122
|
+
propertyUrl: Schema.optional(Schema.String),
|
|
123
|
+
required: Schema.optional(Schema.Boolean),
|
|
124
|
+
separator: Schema.optional(Schema.NullOr(Schema.String)),
|
|
125
|
+
textDirection: Schema.optional(TextDirection),
|
|
126
|
+
valueUrl: Schema.optional(Schema.String),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @since 0.1.0
|
|
131
|
+
* @category models
|
|
132
|
+
*/
|
|
133
|
+
export type Inherited = typeof Inherited.Type;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* A column description.
|
|
137
|
+
*
|
|
138
|
+
* @since 0.1.0
|
|
139
|
+
* @category models
|
|
140
|
+
*/
|
|
141
|
+
export const Column = Schema.Struct({
|
|
142
|
+
id: Schema.optional(Schema.String),
|
|
143
|
+
name: Schema.optional(Schema.String),
|
|
144
|
+
/** The name derived from the first title in the metadata's default language. */
|
|
145
|
+
titleName: Schema.optional(Schema.String),
|
|
146
|
+
titles: LanguageMap,
|
|
147
|
+
isVirtual: Schema.Boolean,
|
|
148
|
+
isSuppressed: Schema.Boolean,
|
|
149
|
+
inherited: Inherited,
|
|
150
|
+
common: CommonProperties,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @since 0.1.0
|
|
155
|
+
* @category models
|
|
156
|
+
*/
|
|
157
|
+
export type Column = typeof Column.Type;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The referenced side of a foreign key: a table by `resource` URL or by
|
|
161
|
+
* `schemaReference`, and its columns.
|
|
162
|
+
*
|
|
163
|
+
* @since 0.1.0
|
|
164
|
+
* @category models
|
|
165
|
+
*/
|
|
166
|
+
export const Reference = Schema.Struct({
|
|
167
|
+
resource: Schema.optional(Schema.String),
|
|
168
|
+
schemaReference: Schema.optional(Schema.String),
|
|
169
|
+
columnReference: Schema.Array(Schema.String),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @since 0.1.0
|
|
174
|
+
* @category models
|
|
175
|
+
*/
|
|
176
|
+
export type Reference = typeof Reference.Type;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A foreign key definition.
|
|
180
|
+
*
|
|
181
|
+
* @since 0.1.0
|
|
182
|
+
* @category models
|
|
183
|
+
*/
|
|
184
|
+
export const ForeignKey = Schema.Struct({
|
|
185
|
+
columnReference: Schema.Array(Schema.String),
|
|
186
|
+
reference: Reference,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @since 0.1.0
|
|
191
|
+
* @category models
|
|
192
|
+
*/
|
|
193
|
+
export type ForeignKey = typeof ForeignKey.Type;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* A schema description (`tableSchema`).
|
|
197
|
+
*
|
|
198
|
+
* @since 0.1.0
|
|
199
|
+
* @category models
|
|
200
|
+
*/
|
|
201
|
+
export const TableSchema = Schema.Struct({
|
|
202
|
+
id: Schema.optional(Schema.String),
|
|
203
|
+
columns: Schema.Array(Column),
|
|
204
|
+
primaryKey: Schema.optional(Schema.Array(Schema.String)),
|
|
205
|
+
rowTitles: Schema.optional(Schema.Array(Schema.String)),
|
|
206
|
+
foreignKeys: Schema.Array(ForeignKey),
|
|
207
|
+
inherited: Inherited,
|
|
208
|
+
common: CommonProperties,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @since 0.1.0
|
|
213
|
+
* @category models
|
|
214
|
+
*/
|
|
215
|
+
export type TableSchema = typeof TableSchema.Type;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The trim flag of a dialect.
|
|
219
|
+
*
|
|
220
|
+
* @since 0.1.0
|
|
221
|
+
* @category models
|
|
222
|
+
*/
|
|
223
|
+
export const Trim = Schema.Literals(['true', 'false', 'start', 'end']);
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @since 0.1.0
|
|
227
|
+
* @category models
|
|
228
|
+
*/
|
|
229
|
+
export type Trim = typeof Trim.Type;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A dialect description with every flag resolved (`header` folded into
|
|
233
|
+
* `headerRowCount`, `skipInitialSpace` into `trim`).
|
|
234
|
+
*
|
|
235
|
+
* @since 0.1.0
|
|
236
|
+
* @category models
|
|
237
|
+
*/
|
|
238
|
+
export const Dialect = Schema.Struct({
|
|
239
|
+
id: Schema.optional(Schema.String),
|
|
240
|
+
commentPrefix: Schema.optional(Schema.String),
|
|
241
|
+
delimiter: Schema.String,
|
|
242
|
+
isDoubleQuoted: Schema.Boolean,
|
|
243
|
+
encoding: Schema.String,
|
|
244
|
+
headerRowCount: Schema.Int,
|
|
245
|
+
lineTerminators: Schema.Array(Schema.String),
|
|
246
|
+
quoteChar: Schema.NullOr(Schema.String),
|
|
247
|
+
shouldSkipBlankRows: Schema.Boolean,
|
|
248
|
+
skipColumns: Schema.Int,
|
|
249
|
+
skipRows: Schema.Int,
|
|
250
|
+
trim: Trim,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @since 0.1.0
|
|
255
|
+
* @category models
|
|
256
|
+
*/
|
|
257
|
+
export type Dialect = typeof Dialect.Type;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The default dialect: UTF-8 CSV with one header row.
|
|
261
|
+
*
|
|
262
|
+
* @since 0.1.0
|
|
263
|
+
* @category constructors
|
|
264
|
+
*/
|
|
265
|
+
export const defaultDialect: Dialect = {
|
|
266
|
+
delimiter: ',',
|
|
267
|
+
isDoubleQuoted: true,
|
|
268
|
+
encoding: 'utf-8',
|
|
269
|
+
headerRowCount: 1,
|
|
270
|
+
lineTerminators: ['\r\n', '\n'],
|
|
271
|
+
quoteChar: '"',
|
|
272
|
+
shouldSkipBlankRows: false,
|
|
273
|
+
skipColumns: 0,
|
|
274
|
+
skipRows: 0,
|
|
275
|
+
trim: 'true',
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* A transformation definition.
|
|
280
|
+
*
|
|
281
|
+
* @since 0.1.0
|
|
282
|
+
* @category models
|
|
283
|
+
*/
|
|
284
|
+
export const Transformation = Schema.Struct({
|
|
285
|
+
id: Schema.optional(Schema.String),
|
|
286
|
+
url: Schema.String,
|
|
287
|
+
scriptFormat: Schema.String,
|
|
288
|
+
targetFormat: Schema.String,
|
|
289
|
+
source: Schema.optional(Schema.String),
|
|
290
|
+
titles: LanguageMap,
|
|
291
|
+
common: CommonProperties,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @since 0.1.0
|
|
296
|
+
* @category models
|
|
297
|
+
*/
|
|
298
|
+
export type Transformation = typeof Transformation.Type;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* A table description.
|
|
302
|
+
*
|
|
303
|
+
* @since 0.1.0
|
|
304
|
+
* @category models
|
|
305
|
+
*/
|
|
306
|
+
export const Table = Schema.Struct({
|
|
307
|
+
id: Schema.optional(Schema.String),
|
|
308
|
+
url: Schema.String,
|
|
309
|
+
dialect: Schema.optional(Dialect),
|
|
310
|
+
notes: Schema.Array(Schema.Json),
|
|
311
|
+
isSuppressed: Schema.Boolean,
|
|
312
|
+
tableDirection: Schema.optional(TableDirection),
|
|
313
|
+
tableSchema: Schema.optional(TableSchema),
|
|
314
|
+
transformations: Schema.Array(Transformation),
|
|
315
|
+
inherited: Inherited,
|
|
316
|
+
common: CommonProperties,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @since 0.1.0
|
|
321
|
+
* @category models
|
|
322
|
+
*/
|
|
323
|
+
export type Table = typeof Table.Type;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* A table group description: the normalized form of every metadata document
|
|
327
|
+
* (a table description is wrapped in a group of one).
|
|
328
|
+
*
|
|
329
|
+
* @since 0.1.0
|
|
330
|
+
* @category models
|
|
331
|
+
*/
|
|
332
|
+
export const TableGroup = Schema.Struct({
|
|
333
|
+
id: Schema.optional(Schema.String),
|
|
334
|
+
tables: Schema.Array(Table),
|
|
335
|
+
dialect: Schema.optional(Dialect),
|
|
336
|
+
notes: Schema.Array(Schema.Json),
|
|
337
|
+
tableDirection: Schema.optional(TableDirection),
|
|
338
|
+
tableSchema: Schema.optional(TableSchema),
|
|
339
|
+
transformations: Schema.Array(Transformation),
|
|
340
|
+
inherited: Inherited,
|
|
341
|
+
common: CommonProperties,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* @since 0.1.0
|
|
346
|
+
* @category models
|
|
347
|
+
*/
|
|
348
|
+
export type TableGroup = typeof TableGroup.Type;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A decoded metadata document and the warnings raised while decoding it.
|
|
352
|
+
*
|
|
353
|
+
* @since 0.1.0
|
|
354
|
+
* @category models
|
|
355
|
+
*/
|
|
356
|
+
export interface Decoded {
|
|
357
|
+
readonly group: TableGroup;
|
|
358
|
+
readonly warnings: ReadonlyArray<Report.Issue>;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Fetches the JSON document a `tableSchema` or `dialect` URL references.
|
|
363
|
+
*
|
|
364
|
+
* @since 0.1.0
|
|
365
|
+
* @category models
|
|
366
|
+
*/
|
|
367
|
+
export type Fetch = (url: string) => Effect.Effect<string, MetadataError>;
|
|
368
|
+
|
|
369
|
+
// -----------------------------------------------------------------------------
|
|
370
|
+
// Decoding context
|
|
371
|
+
// -----------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
type Obj = Schema.JsonObject;
|
|
374
|
+
|
|
375
|
+
interface Ctx {
|
|
376
|
+
readonly url: string;
|
|
377
|
+
readonly base: string;
|
|
378
|
+
readonly language: Option.Option<string>;
|
|
379
|
+
readonly issues: Array<Report.Issue>;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const warn = (ctx: Ctx, message: string): void => {
|
|
383
|
+
ctx.issues.push(Report.warning(message, { table: ctx.url }));
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const error = (ctx: Ctx, message: string): void => {
|
|
387
|
+
ctx.issues.push(Report.error(message, { table: ctx.url }));
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
const quote = Json.describe;
|
|
391
|
+
|
|
392
|
+
const CSVW_CONTEXT = 'http://www.w3.org/ns/csvw';
|
|
393
|
+
|
|
394
|
+
const inheritedKeys = [
|
|
395
|
+
'aboutUrl',
|
|
396
|
+
'datatype',
|
|
397
|
+
'default',
|
|
398
|
+
'lang',
|
|
399
|
+
'null',
|
|
400
|
+
'ordered',
|
|
401
|
+
'propertyUrl',
|
|
402
|
+
'required',
|
|
403
|
+
'separator',
|
|
404
|
+
'textDirection',
|
|
405
|
+
'valueUrl',
|
|
406
|
+
] as const;
|
|
407
|
+
|
|
408
|
+
type Kind =
|
|
409
|
+
| 'TableGroup'
|
|
410
|
+
| 'Table'
|
|
411
|
+
| 'Schema'
|
|
412
|
+
| 'Column'
|
|
413
|
+
| 'Dialect'
|
|
414
|
+
| 'Template'
|
|
415
|
+
| 'Datatype'
|
|
416
|
+
| 'ForeignKey'
|
|
417
|
+
| 'Reference';
|
|
418
|
+
|
|
419
|
+
const ownKeys: Readonly<Record<Kind, ReadonlyArray<string>>> = {
|
|
420
|
+
TableGroup: [
|
|
421
|
+
'tables',
|
|
422
|
+
'dialect',
|
|
423
|
+
'notes',
|
|
424
|
+
'tableDirection',
|
|
425
|
+
'tableSchema',
|
|
426
|
+
'transformations',
|
|
427
|
+
...inheritedKeys,
|
|
428
|
+
],
|
|
429
|
+
Table: [
|
|
430
|
+
'url',
|
|
431
|
+
'dialect',
|
|
432
|
+
'notes',
|
|
433
|
+
'suppressOutput',
|
|
434
|
+
'tableDirection',
|
|
435
|
+
'tableSchema',
|
|
436
|
+
'transformations',
|
|
437
|
+
...inheritedKeys,
|
|
438
|
+
],
|
|
439
|
+
Schema: ['columns', 'foreignKeys', 'primaryKey', 'rowTitles', ...inheritedKeys],
|
|
440
|
+
Column: ['name', 'suppressOutput', 'titles', 'virtual', ...inheritedKeys],
|
|
441
|
+
Dialect: [
|
|
442
|
+
'commentPrefix',
|
|
443
|
+
'delimiter',
|
|
444
|
+
'doubleQuote',
|
|
445
|
+
'encoding',
|
|
446
|
+
'header',
|
|
447
|
+
'headerRowCount',
|
|
448
|
+
'lineTerminators',
|
|
449
|
+
'quoteChar',
|
|
450
|
+
'skipBlankRows',
|
|
451
|
+
'skipColumns',
|
|
452
|
+
'skipInitialSpace',
|
|
453
|
+
'skipRows',
|
|
454
|
+
'trim',
|
|
455
|
+
],
|
|
456
|
+
Template: ['url', 'scriptFormat', 'targetFormat', 'source', 'titles'],
|
|
457
|
+
Datatype: [
|
|
458
|
+
'base',
|
|
459
|
+
'format',
|
|
460
|
+
'length',
|
|
461
|
+
'minLength',
|
|
462
|
+
'maxLength',
|
|
463
|
+
'minimum',
|
|
464
|
+
'maximum',
|
|
465
|
+
'minInclusive',
|
|
466
|
+
'maxInclusive',
|
|
467
|
+
'minExclusive',
|
|
468
|
+
'maxExclusive',
|
|
469
|
+
],
|
|
470
|
+
ForeignKey: ['columnReference', 'reference'],
|
|
471
|
+
Reference: ['resource', 'schemaReference', 'columnReference'],
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const isCommonPropertyName = (key: string): boolean => key.includes(':');
|
|
475
|
+
|
|
476
|
+
const get = (obj: Obj, key: string): Option.Option<Schema.Json> => Json.get(obj, key);
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Checks the keys of a description object: `@id` (a link that must not be a
|
|
480
|
+
* blank node), `@type` (must name the kind), warnings for properties that are
|
|
481
|
+
* not defined for this kind, and errors for unknown keywords.
|
|
482
|
+
*/
|
|
483
|
+
const checkKeys = (obj: Obj, kind: Kind, ctx: Ctx): void => {
|
|
484
|
+
const strict = kind === 'ForeignKey' || kind === 'Reference';
|
|
485
|
+
Arr.forEach(Json.keys(obj), (key) => {
|
|
486
|
+
if (key === '@id') {
|
|
487
|
+
const id = obj[key];
|
|
488
|
+
if (Predicate.isString(id) && id.startsWith('_:'))
|
|
489
|
+
error(ctx, `${kind} @id ${quote(id)} must not be a blank node`);
|
|
490
|
+
else if (!Predicate.isString(id)) warn(ctx, `${kind} @id must be a string`);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (key === '@type') {
|
|
494
|
+
if (obj[key] !== kind) error(ctx, `${kind} @type must be "${kind}"`);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (key === '@context') return;
|
|
498
|
+
if (key.startsWith('@')) {
|
|
499
|
+
error(ctx, `${kind} must not use the keyword ${key}`);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (Arr.contains(ownKeys[kind], key)) return;
|
|
503
|
+
if (isCommonPropertyName(key) && !strict) return;
|
|
504
|
+
if (strict) error(ctx, `${kind} must not have the property ${key}`);
|
|
505
|
+
else warn(ctx, `${kind} has an unknown property ${key}`);
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
const idOf = (obj: Obj, ctx: Ctx): Option.Option<string> =>
|
|
510
|
+
Option.flatMap(get(obj, '@id'), (id) =>
|
|
511
|
+
Predicate.isString(id)
|
|
512
|
+
? id.startsWith('_:')
|
|
513
|
+
? Option.none()
|
|
514
|
+
: Option.some(Url.resolve(Vocab.expand(id), ctx.base))
|
|
515
|
+
: Option.some(Url.resolve('', ctx.base)),
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
// -----------------------------------------------------------------------------
|
|
519
|
+
// Property value checks
|
|
520
|
+
// -----------------------------------------------------------------------------
|
|
521
|
+
|
|
522
|
+
const booleanProperty = (obj: Obj, key: string, ctx: Ctx): Option.Option<boolean> =>
|
|
523
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
524
|
+
if (Predicate.isBoolean(v)) return Option.some(v);
|
|
525
|
+
warn(ctx, `${key} must be a boolean, not ${quote(v)}`);
|
|
526
|
+
return Option.none();
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
const stringProperty = (obj: Obj, key: string, ctx: Ctx): Option.Option<string> =>
|
|
530
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
531
|
+
if (Predicate.isString(v)) return Option.some(v);
|
|
532
|
+
warn(ctx, `${key} must be a string, not ${quote(v)}`);
|
|
533
|
+
return Option.none();
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
const nonNegativeInteger = (obj: Obj, key: string, ctx: Ctx): Option.Option<number> =>
|
|
537
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
538
|
+
if (Predicate.isNumber(v) && Number.isInteger(v) && v >= 0) return Option.some(v);
|
|
539
|
+
warn(ctx, `${key} must be a non-negative integer, not ${quote(v)}`);
|
|
540
|
+
return Option.none();
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
const linkProperty = (obj: Obj, key: string, ctx: Ctx): Option.Option<string> =>
|
|
544
|
+
Option.map(get(obj, key), (v) => {
|
|
545
|
+
if (Predicate.isString(v)) return Url.resolve(v, ctx.base);
|
|
546
|
+
warn(ctx, `${key} must be a string, not ${quote(v)}`);
|
|
547
|
+
return Url.resolve('', ctx.base);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
const templateProperty = (obj: Obj, key: string, ctx: Ctx): Option.Option<string> =>
|
|
551
|
+
Option.map(get(obj, key), (v) => {
|
|
552
|
+
if (Predicate.isString(v)) return v;
|
|
553
|
+
warn(ctx, `${key} must be a URI template string, not ${quote(v)}`);
|
|
554
|
+
return '';
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const isLanguageTag = (tag: string): boolean => LanguageTag.isWellFormed(tag);
|
|
558
|
+
|
|
559
|
+
/** A natural-language property (§Natural Language Properties). */
|
|
560
|
+
const naturalLanguage = (value: Schema.Json, key: string, ctx: Ctx): LanguageMap => {
|
|
561
|
+
const lang = Option.getOrElse(ctx.language, () => 'und');
|
|
562
|
+
const strings = (vs: Schema.JsonArray): ReadonlyArray<string> =>
|
|
563
|
+
Arr.filter(vs, (v): v is string => {
|
|
564
|
+
if (Predicate.isString(v)) return true;
|
|
565
|
+
warn(ctx, `${key} values must be strings, not ${quote(v)}`);
|
|
566
|
+
return false;
|
|
567
|
+
});
|
|
568
|
+
if (Predicate.isString(value)) return { [lang]: [value] };
|
|
569
|
+
if (Json.isArray(value))
|
|
570
|
+
return Arr.isReadonlyArrayNonEmpty(value) ? { [lang]: strings(value) } : {};
|
|
571
|
+
if (Json.isObject(value))
|
|
572
|
+
return Record.fromEntries(
|
|
573
|
+
Arr.flatMap(Json.entries(value), ([tag, v]) => {
|
|
574
|
+
if (!isLanguageTag(tag)) {
|
|
575
|
+
warn(ctx, `${key} has an invalid language tag ${quote(tag)}`);
|
|
576
|
+
return [];
|
|
577
|
+
}
|
|
578
|
+
if (Predicate.isString(v)) return [[tag, [v]] as const];
|
|
579
|
+
if (Json.isArray(v)) return [[tag, strings(v)] as const];
|
|
580
|
+
warn(ctx, `${key} values must be strings, not ${quote(v)}`);
|
|
581
|
+
return [];
|
|
582
|
+
}),
|
|
583
|
+
);
|
|
584
|
+
warn(ctx, `${key} must be a string, array or language map, not ${quote(value)}`);
|
|
585
|
+
return {};
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
const columnReference = (
|
|
589
|
+
obj: Obj,
|
|
590
|
+
key: string,
|
|
591
|
+
ctx: Ctx,
|
|
592
|
+
required: boolean,
|
|
593
|
+
): Option.Option<ReadonlyArray<string>> =>
|
|
594
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
595
|
+
const refs = Predicate.isString(v)
|
|
596
|
+
? Option.some([v])
|
|
597
|
+
: Json.isArray(v) && Arr.isReadonlyArrayNonEmpty(v) && Arr.every(v, Predicate.isString)
|
|
598
|
+
? Option.some(Arr.filter(v, Predicate.isString))
|
|
599
|
+
: Option.none();
|
|
600
|
+
if (Option.isNone(refs)) {
|
|
601
|
+
if (required) error(ctx, `${key} must be a column name or a non-empty array of them`);
|
|
602
|
+
else warn(ctx, `${key} must be a column name or a non-empty array of them`);
|
|
603
|
+
}
|
|
604
|
+
return refs;
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// -----------------------------------------------------------------------------
|
|
608
|
+
// Common properties (§Values of Common Properties, §Normalization)
|
|
609
|
+
// -----------------------------------------------------------------------------
|
|
610
|
+
|
|
611
|
+
const legitimateTypes = [
|
|
612
|
+
'TableGroup',
|
|
613
|
+
'Table',
|
|
614
|
+
'Schema',
|
|
615
|
+
'Column',
|
|
616
|
+
'Dialect',
|
|
617
|
+
'Template',
|
|
618
|
+
'Datatype',
|
|
619
|
+
];
|
|
620
|
+
|
|
621
|
+
const isValidType = (t: string, valueType: boolean): boolean =>
|
|
622
|
+
!t.startsWith('_:') &&
|
|
623
|
+
((valueType ? Datatype.isBuiltIn(t) : Arr.contains(legitimateTypes, t)) ||
|
|
624
|
+
Record.has(Vocab.terms, t) ||
|
|
625
|
+
Option.isSome(Vocab.expandPrefixed(t)) ||
|
|
626
|
+
(Vocab.isAbsoluteUrl(t) && !t.includes(' ')));
|
|
627
|
+
|
|
628
|
+
const normalizeCommon = (value: Schema.Json, ctx: Ctx): Schema.Json => {
|
|
629
|
+
if (Json.isArray(value)) return Arr.map(value, (v) => normalizeCommon(v, ctx));
|
|
630
|
+
if (Predicate.isString(value))
|
|
631
|
+
return Option.match(ctx.language, {
|
|
632
|
+
onNone: () => ({ '@value': value }),
|
|
633
|
+
onSome: (language) => ({ '@value': value, '@language': language }),
|
|
634
|
+
});
|
|
635
|
+
if (!Json.isObject(value)) return value;
|
|
636
|
+
if (Json.has(value, '@value')) {
|
|
637
|
+
const v = value['@value'];
|
|
638
|
+
const extra = Arr.filter(
|
|
639
|
+
Json.keys(value),
|
|
640
|
+
(k) => !Arr.contains(['@value', '@type', '@language'], k),
|
|
641
|
+
);
|
|
642
|
+
if (Arr.isReadonlyArrayNonEmpty(extra))
|
|
643
|
+
error(ctx, `a value object must not have the properties ${Arr.join(extra, ', ')}`);
|
|
644
|
+
if (Json.has(value, '@type') && Json.has(value, '@language'))
|
|
645
|
+
error(ctx, 'a value object must not have both @type and @language');
|
|
646
|
+
if (!(Predicate.isString(v) || Predicate.isNumber(v) || Predicate.isBoolean(v)))
|
|
647
|
+
error(ctx, '@value must be a string, number or boolean');
|
|
648
|
+
Option.map(get(value, '@type'), (t) => {
|
|
649
|
+
if (!Predicate.isString(t) || !isValidType(t, true))
|
|
650
|
+
error(ctx, `invalid value @type ${quote(t)}`);
|
|
651
|
+
});
|
|
652
|
+
Option.map(get(value, '@language'), (l) => {
|
|
653
|
+
if (!(Predicate.isNull(l) || (Predicate.isString(l) && isLanguageTag(l))))
|
|
654
|
+
error(ctx, `invalid @language ${quote(l)}`);
|
|
655
|
+
});
|
|
656
|
+
return value;
|
|
657
|
+
}
|
|
658
|
+
return Record.fromEntries(
|
|
659
|
+
Arr.map(Json.entries(value), ([key, v]): readonly [string, Schema.Json] => {
|
|
660
|
+
if (key === '@id') {
|
|
661
|
+
if (!Predicate.isString(v)) {
|
|
662
|
+
error(ctx, '@id must be a string');
|
|
663
|
+
return [key, v];
|
|
664
|
+
}
|
|
665
|
+
if (v.startsWith('_:')) error(ctx, `@id ${quote(v)} must not be a blank node`);
|
|
666
|
+
return [key, Url.resolve(Vocab.expand(v), ctx.base)];
|
|
667
|
+
}
|
|
668
|
+
if (key === '@type') {
|
|
669
|
+
const types = Json.isArray(v) ? v : [v];
|
|
670
|
+
Arr.forEach(types, (t) => {
|
|
671
|
+
if (!Predicate.isString(t) || !isValidType(t, false))
|
|
672
|
+
error(ctx, `invalid node @type ${quote(t)}`);
|
|
673
|
+
});
|
|
674
|
+
return [key, v];
|
|
675
|
+
}
|
|
676
|
+
if (key === '@language') error(ctx, '@language must only be used with @value');
|
|
677
|
+
else if (key === '@context') error(ctx, 'a metadata document must not add a new @context');
|
|
678
|
+
else if (key === '@list' || key === '@set') error(ctx, `${key} must not be used`);
|
|
679
|
+
else if (key.startsWith('@')) error(ctx, `unknown keyword ${key}`);
|
|
680
|
+
return [key, normalizeCommon(v, ctx)];
|
|
681
|
+
}),
|
|
682
|
+
);
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
/** The common properties of a description object. */
|
|
686
|
+
const commonProperties = (obj: Obj, ctx: Ctx): CommonProperties =>
|
|
687
|
+
Record.fromEntries(
|
|
688
|
+
Arr.map(
|
|
689
|
+
Arr.filter(Json.entries(obj), ([key]) => isCommonPropertyName(key) && !key.startsWith('@')),
|
|
690
|
+
([key, value]) => [key, normalizeCommon(value, ctx)] as const,
|
|
691
|
+
),
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
const notesOf = (obj: Obj, ctx: Ctx): ReadonlyArray<Schema.Json> =>
|
|
695
|
+
Option.match(get(obj, 'notes'), {
|
|
696
|
+
onNone: () => [],
|
|
697
|
+
onSome: (v) => {
|
|
698
|
+
if (Json.isArray(v)) return Arr.map(v, (n) => normalizeCommon(n, ctx));
|
|
699
|
+
warn(ctx, 'notes must be an array');
|
|
700
|
+
return [];
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
// -----------------------------------------------------------------------------
|
|
705
|
+
// Datatypes
|
|
706
|
+
// -----------------------------------------------------------------------------
|
|
707
|
+
|
|
708
|
+
const bound = (obj: Obj, key: string, base: string, ctx: Ctx): Option.Option<Datatype.Bound> =>
|
|
709
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
710
|
+
if (Predicate.isNumber(v) || Predicate.isString(v)) {
|
|
711
|
+
if (Option.isNone(Datatype.boundKey(v, base)))
|
|
712
|
+
error(ctx, `${key} ${quote(v)} is not a valid ${base}`);
|
|
713
|
+
return Option.some(v);
|
|
714
|
+
}
|
|
715
|
+
warn(ctx, `${key} must be a number or string`);
|
|
716
|
+
return Option.none();
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const sameBound = (a: Datatype.Bound, b: Datatype.Bound, base: string): boolean =>
|
|
720
|
+
Option.makeEquivalence((x: number, y: number) => x === y)(
|
|
721
|
+
Datatype.boundKey(a, base),
|
|
722
|
+
Datatype.boundKey(b, base),
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
/** Whether both values are present and satisfy `f`. */
|
|
726
|
+
const both = <A>(a: Option.Option<A>, b: Option.Option<A>, f: (x: A, y: A) => boolean): boolean =>
|
|
727
|
+
Option.exists(Option.all([a, b]), ([x, y]) => f(x, y));
|
|
728
|
+
|
|
729
|
+
const of = Option.fromNullishOr;
|
|
730
|
+
|
|
731
|
+
/** Whether bound `a` is below bound `b` (`strict`) or at most `b`, in `base`'s value space. */
|
|
732
|
+
const below =
|
|
733
|
+
(base: string, strict: boolean) =>
|
|
734
|
+
(a: Datatype.Bound, b: Datatype.Bound): boolean =>
|
|
735
|
+
Option.exists(Option.all([Datatype.boundKey(a, base), Datatype.boundKey(b, base)]), ([x, y]) =>
|
|
736
|
+
strict ? x < y : x <= y,
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
const hasLength = (d: Datatype.Datatype): boolean =>
|
|
740
|
+
d.length !== undefined || d.minLength !== undefined || d.maxLength !== undefined;
|
|
741
|
+
|
|
742
|
+
const hasBounds = (d: Datatype.Datatype): boolean =>
|
|
743
|
+
d.minInclusive !== undefined ||
|
|
744
|
+
d.maxInclusive !== undefined ||
|
|
745
|
+
d.minExclusive !== undefined ||
|
|
746
|
+
d.maxExclusive !== undefined;
|
|
747
|
+
|
|
748
|
+
const lengthApplies = (base: string): boolean =>
|
|
749
|
+
Datatype.isString(base) || Datatype.isBinary(base) || base === 'anyAtomicType';
|
|
750
|
+
|
|
751
|
+
const boundsApply = (base: string): boolean =>
|
|
752
|
+
Datatype.isNumeric(base) || Datatype.isDateTime(base) || Datatype.isDuration(base);
|
|
753
|
+
|
|
754
|
+
/** The datatype constraint combinations that are errors (§Derived Datatypes). */
|
|
755
|
+
const datatypeRules: ReadonlyArray<
|
|
756
|
+
readonly [(d: Datatype.Datatype) => boolean, (d: Datatype.Datatype) => string]
|
|
757
|
+
> = [
|
|
758
|
+
[
|
|
759
|
+
(d) => both(of(d.length), of(d.minLength), (l, m) => l < m),
|
|
760
|
+
() => 'length is less than minLength',
|
|
761
|
+
],
|
|
762
|
+
[
|
|
763
|
+
(d) => both(of(d.length), of(d.maxLength), (l, m) => l > m),
|
|
764
|
+
() => 'length is greater than maxLength',
|
|
765
|
+
],
|
|
766
|
+
[
|
|
767
|
+
(d) => both(of(d.minLength), of(d.maxLength), (l, m) => l > m),
|
|
768
|
+
() => 'minLength is greater than maxLength',
|
|
769
|
+
],
|
|
770
|
+
[
|
|
771
|
+
(d) => hasLength(d) && !lengthApplies(d.base),
|
|
772
|
+
(d) => `length constraints do not apply to ${d.base}`,
|
|
773
|
+
],
|
|
774
|
+
[
|
|
775
|
+
(d) => hasBounds(d) && !boundsApply(d.base),
|
|
776
|
+
(d) => `value constraints do not apply to ${d.base}`,
|
|
777
|
+
],
|
|
778
|
+
[
|
|
779
|
+
(d) => both(of(d.minInclusive), of(d.minExclusive), () => true),
|
|
780
|
+
() => 'minInclusive and minExclusive must not both be specified',
|
|
781
|
+
],
|
|
782
|
+
[
|
|
783
|
+
(d) => both(of(d.maxInclusive), of(d.maxExclusive), () => true),
|
|
784
|
+
() => 'maxInclusive and maxExclusive must not both be specified',
|
|
785
|
+
],
|
|
786
|
+
[
|
|
787
|
+
(d) => both(of(d.maxInclusive), of(d.minInclusive), below(d.base, true)),
|
|
788
|
+
() => 'maxInclusive is less than minInclusive',
|
|
789
|
+
],
|
|
790
|
+
[
|
|
791
|
+
(d) => both(of(d.maxExclusive), of(d.minInclusive), below(d.base, false)),
|
|
792
|
+
() => 'maxExclusive is not greater than minInclusive',
|
|
793
|
+
],
|
|
794
|
+
[
|
|
795
|
+
(d) => both(of(d.maxExclusive), of(d.minExclusive), below(d.base, true)),
|
|
796
|
+
() => 'maxExclusive is less than minExclusive',
|
|
797
|
+
],
|
|
798
|
+
[
|
|
799
|
+
(d) => both(of(d.maxInclusive), of(d.minExclusive), below(d.base, false)),
|
|
800
|
+
() => 'maxInclusive is not greater than minExclusive',
|
|
801
|
+
],
|
|
802
|
+
];
|
|
803
|
+
|
|
804
|
+
const checkDatatype = (d: Datatype.Datatype, ctx: Ctx): void =>
|
|
805
|
+
Arr.forEach(datatypeRules, ([violated, message]) => {
|
|
806
|
+
if (violated(d)) error(ctx, message(d));
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
const datatypeObject = (obj: Obj, ctx: Ctx): Datatype.Datatype => {
|
|
810
|
+
checkKeys(obj, 'Datatype', ctx);
|
|
811
|
+
const id = idOf(obj, ctx);
|
|
812
|
+
if (Option.isSome(id) && Option.isSome(Datatype.fromIri(id.value))) {
|
|
813
|
+
if (Arr.some(Json.keys(obj), (k) => k !== '@id' && k !== '@type'))
|
|
814
|
+
error(ctx, `a datatype with the built-in @id ${id.value} must not have other properties`);
|
|
815
|
+
}
|
|
816
|
+
const base = Option.getOrElse(
|
|
817
|
+
Option.flatMap(stringProperty(obj, 'base', ctx), (b) => {
|
|
818
|
+
if (Datatype.isBuiltIn(b)) return Option.some(b);
|
|
819
|
+
warn(ctx, `base ${quote(b)} is not a built-in datatype`);
|
|
820
|
+
return Option.some('string');
|
|
821
|
+
}),
|
|
822
|
+
() => 'string',
|
|
823
|
+
);
|
|
824
|
+
const format = Option.flatMap(
|
|
825
|
+
get(obj, 'format'),
|
|
826
|
+
(f): Option.Option<string | Datatype.NumericFormat> => {
|
|
827
|
+
const candidate = Predicate.isString(f)
|
|
828
|
+
? Option.some<string | Datatype.NumericFormat>(f)
|
|
829
|
+
: Json.isObject(f) && Datatype.isNumeric(base)
|
|
830
|
+
? Option.some<string | Datatype.NumericFormat>({
|
|
831
|
+
...optional('decimalChar', stringProperty(f, 'decimalChar', ctx)),
|
|
832
|
+
...optional('groupChar', stringProperty(f, 'groupChar', ctx)),
|
|
833
|
+
...optional('pattern', stringProperty(f, 'pattern', ctx)),
|
|
834
|
+
})
|
|
835
|
+
: Option.none();
|
|
836
|
+
if (Option.isNone(candidate)) {
|
|
837
|
+
warn(ctx, `invalid format for a ${base} datatype`);
|
|
838
|
+
return Option.none();
|
|
839
|
+
}
|
|
840
|
+
return Option.match(Datatype.checkFormat(base, candidate.value), {
|
|
841
|
+
onNone: () => candidate,
|
|
842
|
+
onSome: (message) => {
|
|
843
|
+
warn(ctx, message);
|
|
844
|
+
return Option.none();
|
|
845
|
+
},
|
|
846
|
+
});
|
|
847
|
+
},
|
|
848
|
+
);
|
|
849
|
+
const minimum = bound(obj, 'minimum', base, ctx);
|
|
850
|
+
const maximum = bound(obj, 'maximum', base, ctx);
|
|
851
|
+
const minInclusive = bound(obj, 'minInclusive', base, ctx);
|
|
852
|
+
const maxInclusive = bound(obj, 'maxInclusive', base, ctx);
|
|
853
|
+
if (
|
|
854
|
+
Option.isSome(minimum) &&
|
|
855
|
+
Option.isSome(minInclusive) &&
|
|
856
|
+
!sameBound(minimum.value, minInclusive.value, base)
|
|
857
|
+
)
|
|
858
|
+
error(ctx, 'minimum and minInclusive differ');
|
|
859
|
+
if (
|
|
860
|
+
Option.isSome(maximum) &&
|
|
861
|
+
Option.isSome(maxInclusive) &&
|
|
862
|
+
!sameBound(maximum.value, maxInclusive.value, base)
|
|
863
|
+
)
|
|
864
|
+
error(ctx, 'maximum and maxInclusive differ');
|
|
865
|
+
const datatype: Datatype.Datatype = {
|
|
866
|
+
base,
|
|
867
|
+
...optional('id', id),
|
|
868
|
+
...optional('format', format),
|
|
869
|
+
...optional('length', nonNegativeInteger(obj, 'length', ctx)),
|
|
870
|
+
...optional('minLength', nonNegativeInteger(obj, 'minLength', ctx)),
|
|
871
|
+
...optional('maxLength', nonNegativeInteger(obj, 'maxLength', ctx)),
|
|
872
|
+
...optional(
|
|
873
|
+
'minInclusive',
|
|
874
|
+
Option.orElse(minInclusive, () => minimum),
|
|
875
|
+
),
|
|
876
|
+
...optional(
|
|
877
|
+
'maxInclusive',
|
|
878
|
+
Option.orElse(maxInclusive, () => maximum),
|
|
879
|
+
),
|
|
880
|
+
...optional('minExclusive', bound(obj, 'minExclusive', base, ctx)),
|
|
881
|
+
...optional('maxExclusive', bound(obj, 'maxExclusive', base, ctx)),
|
|
882
|
+
common: commonProperties(obj, ctx),
|
|
883
|
+
};
|
|
884
|
+
checkDatatype(datatype, ctx);
|
|
885
|
+
return datatype;
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
const datatypeProperty = (value: Schema.Json, ctx: Ctx): Option.Option<Datatype.Datatype> => {
|
|
889
|
+
if (Predicate.isString(value)) {
|
|
890
|
+
if (Datatype.isBuiltIn(value)) return Option.some({ base: value, common: {} });
|
|
891
|
+
warn(ctx, `datatype ${quote(value)} is not a built-in datatype`);
|
|
892
|
+
return Option.some(Datatype.string);
|
|
893
|
+
}
|
|
894
|
+
if (Json.isObject(value)) return Option.some(datatypeObject(value, ctx));
|
|
895
|
+
warn(ctx, `datatype must be a string or object, not ${quote(value)}`);
|
|
896
|
+
return Option.some(Datatype.string);
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
// -----------------------------------------------------------------------------
|
|
900
|
+
// Inherited properties
|
|
901
|
+
// -----------------------------------------------------------------------------
|
|
902
|
+
|
|
903
|
+
/** A `separator`: a string, or `null` for none (overriding an inherited one). */
|
|
904
|
+
type Separator = Exclude<Inherited['separator'], undefined>;
|
|
905
|
+
|
|
906
|
+
const inheritedOf = (obj: Obj, ctx: Ctx): Inherited => {
|
|
907
|
+
const nulls = Option.flatMap(get(obj, 'null'), (v): Option.Option<ReadonlyArray<string>> => {
|
|
908
|
+
if (Predicate.isString(v)) return Option.some([v]);
|
|
909
|
+
if (Json.isArray(v)) {
|
|
910
|
+
const strings = Arr.filter(v, Predicate.isString);
|
|
911
|
+
if (Arr.length(strings) !== Arr.length(v)) warn(ctx, 'null values must be strings');
|
|
912
|
+
return Option.some(strings);
|
|
913
|
+
}
|
|
914
|
+
warn(ctx, `null must be a string or array of strings, not ${quote(v)}`);
|
|
915
|
+
return Option.some(['']);
|
|
916
|
+
});
|
|
917
|
+
const lang = Option.flatMap(stringProperty(obj, 'lang', ctx), (l) => {
|
|
918
|
+
if (isLanguageTag(l)) return Option.some(l);
|
|
919
|
+
warn(ctx, `lang ${quote(l)} is not a valid language tag`);
|
|
920
|
+
return Option.some('und');
|
|
921
|
+
});
|
|
922
|
+
const separator = Option.flatMap(get(obj, 'separator'), (v): Option.Option<Separator> => {
|
|
923
|
+
if (Predicate.isString(v) || Predicate.isNull(v)) return Option.some(v);
|
|
924
|
+
warn(ctx, `separator must be a string or null, not ${quote(v)}`);
|
|
925
|
+
return Option.some(null);
|
|
926
|
+
});
|
|
927
|
+
const textDirection = Option.flatMap(
|
|
928
|
+
get(obj, 'textDirection'),
|
|
929
|
+
(v): Option.Option<TextDirection> => {
|
|
930
|
+
if (v === 'ltr' || v === 'rtl' || v === 'auto' || v === 'inherit') return Option.some(v);
|
|
931
|
+
warn(ctx, `textDirection must be "ltr", "rtl", "auto" or "inherit", not ${quote(v)}`);
|
|
932
|
+
return Option.some('inherit');
|
|
933
|
+
},
|
|
934
|
+
);
|
|
935
|
+
const defaultValue = Option.flatMap(get(obj, 'default'), (v) => {
|
|
936
|
+
if (Predicate.isString(v)) return Option.some(v);
|
|
937
|
+
warn(ctx, `default must be a string, not ${quote(v)}`);
|
|
938
|
+
return Option.some('');
|
|
939
|
+
});
|
|
940
|
+
const flag = (key: string) =>
|
|
941
|
+
Option.flatMap(get(obj, key), (v) => {
|
|
942
|
+
if (Predicate.isBoolean(v)) return Option.some(v);
|
|
943
|
+
warn(ctx, `${key} must be a boolean, not ${quote(v)}`);
|
|
944
|
+
return Option.some(false);
|
|
945
|
+
});
|
|
946
|
+
return {
|
|
947
|
+
...optional('aboutUrl', templateProperty(obj, 'aboutUrl', ctx)),
|
|
948
|
+
...optional(
|
|
949
|
+
'datatype',
|
|
950
|
+
Option.flatMap(get(obj, 'datatype'), (v) => datatypeProperty(v, ctx)),
|
|
951
|
+
),
|
|
952
|
+
...optional('default', defaultValue),
|
|
953
|
+
...optional('lang', lang),
|
|
954
|
+
...optional('null', nulls),
|
|
955
|
+
...optional('ordered', flag('ordered')),
|
|
956
|
+
...optional('propertyUrl', templateProperty(obj, 'propertyUrl', ctx)),
|
|
957
|
+
...optional('required', flag('required')),
|
|
958
|
+
...optional('separator', separator),
|
|
959
|
+
...optional('textDirection', textDirection),
|
|
960
|
+
...optional('valueUrl', templateProperty(obj, 'valueUrl', ctx)),
|
|
961
|
+
};
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
// -----------------------------------------------------------------------------
|
|
965
|
+
// Columns and schemas
|
|
966
|
+
// -----------------------------------------------------------------------------
|
|
967
|
+
|
|
968
|
+
const COLUMN_NAME = /^(?:[A-Za-z0-9]|%[0-9A-Fa-f]{2})(?:[A-Za-z0-9_.]|%[0-9A-Fa-f]{2})*$/;
|
|
969
|
+
|
|
970
|
+
const columnOf = (obj: Obj, ctx: Ctx): Column => {
|
|
971
|
+
checkKeys(obj, 'Column', ctx);
|
|
972
|
+
const titles = Option.match(get(obj, 'titles'), {
|
|
973
|
+
onNone: () => ({}),
|
|
974
|
+
onSome: (v) => naturalLanguage(v, 'titles', ctx),
|
|
975
|
+
});
|
|
976
|
+
const name = Option.flatMap(get(obj, 'name'), (v) => {
|
|
977
|
+
if (!Predicate.isString(v)) {
|
|
978
|
+
warn(ctx, `column name must be a string, not ${quote(v)}`);
|
|
979
|
+
return Option.none();
|
|
980
|
+
}
|
|
981
|
+
if (!COLUMN_NAME.test(v) || v.startsWith('_')) {
|
|
982
|
+
warn(ctx, `invalid column name ${quote(v)}`);
|
|
983
|
+
return Option.none();
|
|
984
|
+
}
|
|
985
|
+
return Option.some(v);
|
|
986
|
+
});
|
|
987
|
+
return {
|
|
988
|
+
...optional('id', idOf(obj, ctx)),
|
|
989
|
+
...optional('name', name),
|
|
990
|
+
...optional(
|
|
991
|
+
'titleName',
|
|
992
|
+
Option.flatMap(
|
|
993
|
+
Record.get(
|
|
994
|
+
titles,
|
|
995
|
+
Option.getOrElse(ctx.language, () => 'und'),
|
|
996
|
+
),
|
|
997
|
+
Arr.head,
|
|
998
|
+
),
|
|
999
|
+
),
|
|
1000
|
+
titles,
|
|
1001
|
+
isVirtual: Option.getOrElse(booleanProperty(obj, 'virtual', ctx), () => false),
|
|
1002
|
+
isSuppressed: Option.getOrElse(booleanProperty(obj, 'suppressOutput', ctx), () => false),
|
|
1003
|
+
inherited: inheritedOf(obj, ctx),
|
|
1004
|
+
common: commonProperties(obj, ctx),
|
|
1005
|
+
};
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
const arrayProperty = (obj: Obj, key: string, ctx: Ctx): ReadonlyArray<Obj> =>
|
|
1009
|
+
Option.match(get(obj, key), {
|
|
1010
|
+
onNone: () => [],
|
|
1011
|
+
onSome: (v) => {
|
|
1012
|
+
if (!Json.isArray(v)) {
|
|
1013
|
+
warn(ctx, `${key} must be an array`);
|
|
1014
|
+
return [];
|
|
1015
|
+
}
|
|
1016
|
+
return Arr.filter(v, (item): item is Obj => {
|
|
1017
|
+
if (Json.isObject(item)) return true;
|
|
1018
|
+
warn(ctx, `${key} items must be objects, not ${quote(item)}`);
|
|
1019
|
+
return false;
|
|
1020
|
+
});
|
|
1021
|
+
},
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
const foreignKeyOf = (obj: Obj, ctx: Ctx): Option.Option<ForeignKey> => {
|
|
1025
|
+
checkKeys(obj, 'ForeignKey', ctx);
|
|
1026
|
+
const columns = columnReference(obj, 'columnReference', ctx, true);
|
|
1027
|
+
const reference = Option.flatMap(get(obj, 'reference'), (r): Option.Option<Reference> => {
|
|
1028
|
+
if (!Json.isObject(r)) {
|
|
1029
|
+
error(ctx, 'foreign key reference must be an object');
|
|
1030
|
+
return Option.none();
|
|
1031
|
+
}
|
|
1032
|
+
checkKeys(r, 'Reference', ctx);
|
|
1033
|
+
const resource = linkProperty(r, 'resource', ctx);
|
|
1034
|
+
const schemaReference = linkProperty(r, 'schemaReference', ctx);
|
|
1035
|
+
if (Option.isSome(resource) === Option.isSome(schemaReference))
|
|
1036
|
+
error(ctx, 'foreign key reference needs exactly one of resource and schemaReference');
|
|
1037
|
+
return Option.map(columnReference(r, 'columnReference', ctx, true), (cols) => ({
|
|
1038
|
+
...optional('resource', resource),
|
|
1039
|
+
...optional('schemaReference', schemaReference),
|
|
1040
|
+
columnReference: cols,
|
|
1041
|
+
}));
|
|
1042
|
+
});
|
|
1043
|
+
if (Option.isNone(reference) && !Json.has(obj, 'reference'))
|
|
1044
|
+
error(ctx, 'foreign key needs a reference');
|
|
1045
|
+
return Option.map(Option.all([columns, reference]), ([from, to]) => ({
|
|
1046
|
+
columnReference: from,
|
|
1047
|
+
reference: to,
|
|
1048
|
+
}));
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
const schemaOf = (obj: Obj, ctx: Ctx): TableSchema => {
|
|
1052
|
+
checkKeys(obj, 'Schema', ctx);
|
|
1053
|
+
const columns = Arr.map(arrayProperty(obj, 'columns', ctx), (c) => columnOf(c, ctx));
|
|
1054
|
+
const names = Arr.getSomes(Arr.map(columns, (c) => Option.fromNullishOr(c.name)));
|
|
1055
|
+
if (Arr.length(Arr.dedupe(names)) !== Arr.length(names))
|
|
1056
|
+
error(ctx, 'column names must be unique');
|
|
1057
|
+
const firstVirtual = Arr.findFirstIndex(columns, (c) => c.isVirtual);
|
|
1058
|
+
if (Option.exists(firstVirtual, (i) => Arr.some(Arr.drop(columns, i), (c) => !c.isVirtual)))
|
|
1059
|
+
error(ctx, 'virtual columns must follow every non-virtual column');
|
|
1060
|
+
const references = (key: string) =>
|
|
1061
|
+
Option.flatMap(columnReference(obj, key, ctx, false), (refs) => {
|
|
1062
|
+
if (Arr.every(refs, (r) => Arr.contains(names, r))) return Option.some(refs);
|
|
1063
|
+
warn(ctx, `${key} references a column that does not exist`);
|
|
1064
|
+
return Option.none();
|
|
1065
|
+
});
|
|
1066
|
+
const foreignKeys = Arr.getSomes(
|
|
1067
|
+
Arr.map(arrayProperty(obj, 'foreignKeys', ctx), (fk) => foreignKeyOf(fk, ctx)),
|
|
1068
|
+
);
|
|
1069
|
+
Arr.forEach(foreignKeys, (fk) => {
|
|
1070
|
+
if (!Arr.every(fk.columnReference, (r) => Arr.contains(names, r)))
|
|
1071
|
+
error(ctx, 'foreign key columnReference references a column that does not exist');
|
|
1072
|
+
});
|
|
1073
|
+
return {
|
|
1074
|
+
...optional('id', idOf(obj, ctx)),
|
|
1075
|
+
columns,
|
|
1076
|
+
...optional('primaryKey', references('primaryKey')),
|
|
1077
|
+
...optional('rowTitles', references('rowTitles')),
|
|
1078
|
+
foreignKeys,
|
|
1079
|
+
inherited: inheritedOf(obj, ctx),
|
|
1080
|
+
common: commonProperties(obj, ctx),
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// -----------------------------------------------------------------------------
|
|
1085
|
+
// Dialects and transformations
|
|
1086
|
+
// -----------------------------------------------------------------------------
|
|
1087
|
+
|
|
1088
|
+
const isEncoding = (encoding: string): boolean =>
|
|
1089
|
+
Result.isSuccess(Result.try(() => new TextDecoder(encoding)));
|
|
1090
|
+
|
|
1091
|
+
const dialectOf = (obj: Obj, ctx: Ctx): Dialect => {
|
|
1092
|
+
checkKeys(obj, 'Dialect', ctx);
|
|
1093
|
+
const d = defaultDialect;
|
|
1094
|
+
const header = booleanProperty(obj, 'header', ctx);
|
|
1095
|
+
const headerRowCount = nonNegativeInteger(obj, 'headerRowCount', ctx);
|
|
1096
|
+
const skipInitialSpace = booleanProperty(obj, 'skipInitialSpace', ctx);
|
|
1097
|
+
const trim = Option.flatMap(get(obj, 'trim'), (v): Option.Option<Trim> => {
|
|
1098
|
+
if (Predicate.isBoolean(v)) return Option.some(v ? 'true' : 'false');
|
|
1099
|
+
if (v === 'true' || v === 'false' || v === 'start' || v === 'end') return Option.some(v);
|
|
1100
|
+
warn(ctx, `trim must be a boolean or "true", "false", "start" or "end", not ${quote(v)}`);
|
|
1101
|
+
return Option.none();
|
|
1102
|
+
});
|
|
1103
|
+
const quoteChar = Option.flatMap(
|
|
1104
|
+
get(obj, 'quoteChar'),
|
|
1105
|
+
(v): Option.Option<Dialect['quoteChar']> => {
|
|
1106
|
+
if (Predicate.isString(v) || Predicate.isNull(v)) return Option.some(v);
|
|
1107
|
+
warn(ctx, `quoteChar must be a string or null, not ${quote(v)}`);
|
|
1108
|
+
return Option.none();
|
|
1109
|
+
},
|
|
1110
|
+
);
|
|
1111
|
+
const lineTerminators = Option.flatMap(
|
|
1112
|
+
get(obj, 'lineTerminators'),
|
|
1113
|
+
(v): Option.Option<ReadonlyArray<string>> => {
|
|
1114
|
+
if (Predicate.isString(v)) return Option.some([v]);
|
|
1115
|
+
if (Json.isArray(v) && Arr.every(v, Predicate.isString))
|
|
1116
|
+
return Option.some(Arr.filter(v, Predicate.isString));
|
|
1117
|
+
warn(ctx, 'lineTerminators must be a string or an array of strings');
|
|
1118
|
+
return Option.none();
|
|
1119
|
+
},
|
|
1120
|
+
);
|
|
1121
|
+
const encoding = Option.flatMap(stringProperty(obj, 'encoding', ctx), (e) => {
|
|
1122
|
+
if (isEncoding(e)) return Option.some(e);
|
|
1123
|
+
warn(ctx, `unknown encoding ${quote(e)}`);
|
|
1124
|
+
return Option.none();
|
|
1125
|
+
});
|
|
1126
|
+
return {
|
|
1127
|
+
...optional('id', idOf(obj, ctx)),
|
|
1128
|
+
...optional('commentPrefix', stringProperty(obj, 'commentPrefix', ctx)),
|
|
1129
|
+
delimiter: Option.getOrElse(stringProperty(obj, 'delimiter', ctx), () => d.delimiter),
|
|
1130
|
+
isDoubleQuoted: Option.getOrElse(
|
|
1131
|
+
booleanProperty(obj, 'doubleQuote', ctx),
|
|
1132
|
+
() => d.isDoubleQuoted,
|
|
1133
|
+
),
|
|
1134
|
+
encoding: Option.getOrElse(encoding, () => d.encoding),
|
|
1135
|
+
headerRowCount: Option.getOrElse(headerRowCount, () =>
|
|
1136
|
+
Option.getOrElse(
|
|
1137
|
+
Option.map(header, (h) => (h ? 1 : 0)),
|
|
1138
|
+
() => d.headerRowCount,
|
|
1139
|
+
),
|
|
1140
|
+
),
|
|
1141
|
+
lineTerminators: Option.getOrElse(lineTerminators, () => d.lineTerminators),
|
|
1142
|
+
quoteChar: Option.getOrElse(quoteChar, () => d.quoteChar),
|
|
1143
|
+
shouldSkipBlankRows: Option.getOrElse(
|
|
1144
|
+
booleanProperty(obj, 'skipBlankRows', ctx),
|
|
1145
|
+
() => d.shouldSkipBlankRows,
|
|
1146
|
+
),
|
|
1147
|
+
skipColumns: Option.getOrElse(nonNegativeInteger(obj, 'skipColumns', ctx), () => d.skipColumns),
|
|
1148
|
+
skipRows: Option.getOrElse(nonNegativeInteger(obj, 'skipRows', ctx), () => d.skipRows),
|
|
1149
|
+
trim: Option.getOrElse(trim, () =>
|
|
1150
|
+
Option.getOrElse(
|
|
1151
|
+
Option.map(skipInitialSpace, (s): Trim => (s ? 'start' : 'false')),
|
|
1152
|
+
() => d.trim,
|
|
1153
|
+
),
|
|
1154
|
+
),
|
|
1155
|
+
};
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
const transformationOf = (obj: Obj, ctx: Ctx): Option.Option<Transformation> => {
|
|
1159
|
+
checkKeys(obj, 'Template', ctx);
|
|
1160
|
+
const required = (key: string) => {
|
|
1161
|
+
const v = linkProperty(obj, key, ctx);
|
|
1162
|
+
if (Option.isNone(v)) error(ctx, `transformation needs ${key}`);
|
|
1163
|
+
return v;
|
|
1164
|
+
};
|
|
1165
|
+
const url = required('url');
|
|
1166
|
+
const scriptFormat = required('scriptFormat');
|
|
1167
|
+
const targetFormat = required('targetFormat');
|
|
1168
|
+
const source = Option.flatMap(stringProperty(obj, 'source', ctx), (s) => {
|
|
1169
|
+
if (s === 'json' || s === 'rdf') return Option.some(s);
|
|
1170
|
+
warn(ctx, `transformation source must be "json" or "rdf", not ${quote(s)}`);
|
|
1171
|
+
return Option.none();
|
|
1172
|
+
});
|
|
1173
|
+
return Option.map(Option.all([url, scriptFormat, targetFormat]), ([u, sf, tf]) => ({
|
|
1174
|
+
...optional('id', idOf(obj, ctx)),
|
|
1175
|
+
url: u,
|
|
1176
|
+
scriptFormat: sf,
|
|
1177
|
+
targetFormat: tf,
|
|
1178
|
+
...optional('source', source),
|
|
1179
|
+
titles: Option.match(get(obj, 'titles'), {
|
|
1180
|
+
onNone: () => ({}),
|
|
1181
|
+
onSome: (v) => naturalLanguage(v, 'titles', ctx),
|
|
1182
|
+
}),
|
|
1183
|
+
common: commonProperties(obj, ctx),
|
|
1184
|
+
}));
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
const tableDirectionOf = (obj: Obj, ctx: Ctx): Option.Option<TableDirection> =>
|
|
1188
|
+
Option.flatMap(get(obj, 'tableDirection'), (v): Option.Option<TableDirection> => {
|
|
1189
|
+
if (v === 'ltr' || v === 'rtl' || v === 'auto') return Option.some(v);
|
|
1190
|
+
warn(ctx, `tableDirection must be "ltr", "rtl" or "auto", not ${quote(v)}`);
|
|
1191
|
+
return Option.some('auto');
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
// -----------------------------------------------------------------------------
|
|
1195
|
+
// Object properties referencing other documents
|
|
1196
|
+
// -----------------------------------------------------------------------------
|
|
1197
|
+
|
|
1198
|
+
interface Located {
|
|
1199
|
+
readonly obj: Obj;
|
|
1200
|
+
readonly ctx: Ctx;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
const contextOf = (
|
|
1204
|
+
doc: Obj,
|
|
1205
|
+
url: string,
|
|
1206
|
+
issues: Array<Report.Issue>,
|
|
1207
|
+
required: boolean,
|
|
1208
|
+
): Result.Result<Ctx, MetadataError> => {
|
|
1209
|
+
const fail = (message: string) => Result.fail(new MetadataError({ message, url }));
|
|
1210
|
+
const ctx: Ctx = { url, base: url, language: Option.none(), issues };
|
|
1211
|
+
return Option.match(get(doc, '@context'), {
|
|
1212
|
+
onNone: () =>
|
|
1213
|
+
required ? fail('a metadata document must have a @context') : Result.succeed(ctx),
|
|
1214
|
+
onSome: (c) => {
|
|
1215
|
+
if (c === CSVW_CONTEXT) return Result.succeed(ctx);
|
|
1216
|
+
if (!Json.isArray(c) || Arr.length(c) !== 2 || c[0] !== CSVW_CONTEXT)
|
|
1217
|
+
return fail(`@context must be "${CSVW_CONTEXT}" or ["${CSVW_CONTEXT}", {…}]`);
|
|
1218
|
+
const local = c[1];
|
|
1219
|
+
if (local === undefined || !Json.isObject(local))
|
|
1220
|
+
return fail('the local @context must be an object');
|
|
1221
|
+
const others = Arr.filter(Json.keys(local), (k) => k !== '@base' && k !== '@language');
|
|
1222
|
+
if (Arr.isReadonlyArrayNonEmpty(others))
|
|
1223
|
+
return fail(
|
|
1224
|
+
`the local @context must only define @base and @language, not ${Arr.join(others, ', ')}`,
|
|
1225
|
+
);
|
|
1226
|
+
const base = Option.match(get(local, '@base'), {
|
|
1227
|
+
onNone: () => url,
|
|
1228
|
+
onSome: (b) => {
|
|
1229
|
+
if (Predicate.isString(b)) return Url.resolve(b, url);
|
|
1230
|
+
issues.push(Report.warning('@base must be a string', { table: url }));
|
|
1231
|
+
return url;
|
|
1232
|
+
},
|
|
1233
|
+
});
|
|
1234
|
+
const language = Option.flatMap(get(local, '@language'), (l) => {
|
|
1235
|
+
if (Predicate.isString(l) && isLanguageTag(l)) return Option.some(l);
|
|
1236
|
+
issues.push(
|
|
1237
|
+
Report.warning(`@language ${quote(l)} is not a valid language tag`, { table: url }),
|
|
1238
|
+
);
|
|
1239
|
+
return Option.none();
|
|
1240
|
+
});
|
|
1241
|
+
return Result.succeed({ url, base, language, issues });
|
|
1242
|
+
},
|
|
1243
|
+
});
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
const parseDocument = (text: string, url: string): Result.Result<Schema.Json, MetadataError> =>
|
|
1247
|
+
Result.mapError(
|
|
1248
|
+
Json.parseJson(text),
|
|
1249
|
+
(message) => new MetadataError({ message: `invalid JSON: ${message}`, url }),
|
|
1250
|
+
);
|
|
1251
|
+
|
|
1252
|
+
const objectProperty = (
|
|
1253
|
+
obj: Obj,
|
|
1254
|
+
key: string,
|
|
1255
|
+
ctx: Ctx,
|
|
1256
|
+
load: Fetch,
|
|
1257
|
+
): Effect.Effect<Option.Option<Located>, MetadataError> =>
|
|
1258
|
+
Option.match(get(obj, key), {
|
|
1259
|
+
onNone: () => Effect.succeedNone,
|
|
1260
|
+
onSome: (v) => {
|
|
1261
|
+
if (Json.isObject(v)) {
|
|
1262
|
+
if (Json.has(v, '@context')) error(ctx, `${key} must not have a @context`);
|
|
1263
|
+
return Effect.succeedSome({ obj: v, ctx });
|
|
1264
|
+
}
|
|
1265
|
+
if (Predicate.isString(v)) {
|
|
1266
|
+
const url = Url.resolve(v, ctx.base);
|
|
1267
|
+
return Effect.flatMap(load(url), (text) =>
|
|
1268
|
+
Effect.fromResult(
|
|
1269
|
+
Result.flatMap(parseDocument(text, url), (doc) => {
|
|
1270
|
+
if (!Json.isObject(doc))
|
|
1271
|
+
return Result.fail(new MetadataError({ message: `${key} must be an object`, url }));
|
|
1272
|
+
return Result.map(contextOf(doc, url, ctx.issues, false), (sub) =>
|
|
1273
|
+
Option.some({
|
|
1274
|
+
obj: Json.has(doc, '@id') ? doc : Json.set(doc, '@id', url),
|
|
1275
|
+
ctx: sub,
|
|
1276
|
+
}),
|
|
1277
|
+
);
|
|
1278
|
+
}),
|
|
1279
|
+
),
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
warn(ctx, `${key} must be an object or a URL, not ${quote(v)}`);
|
|
1283
|
+
return Effect.succeedSome({ obj: {}, ctx });
|
|
1284
|
+
},
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
// -----------------------------------------------------------------------------
|
|
1288
|
+
// Tables and table groups
|
|
1289
|
+
// -----------------------------------------------------------------------------
|
|
1290
|
+
|
|
1291
|
+
/** The properties table and table group descriptions share. */
|
|
1292
|
+
const sharedProperties = Effect.fnUntraced(function* (obj: Obj, ctx: Ctx, load: Fetch) {
|
|
1293
|
+
const schema = yield* objectProperty(obj, 'tableSchema', ctx, load);
|
|
1294
|
+
const dialect = yield* objectProperty(obj, 'dialect', ctx, load);
|
|
1295
|
+
return {
|
|
1296
|
+
...optional('id', idOf(obj, ctx)),
|
|
1297
|
+
...optional(
|
|
1298
|
+
'dialect',
|
|
1299
|
+
Option.map(dialect, (d) => dialectOf(d.obj, d.ctx)),
|
|
1300
|
+
),
|
|
1301
|
+
notes: notesOf(obj, ctx),
|
|
1302
|
+
...optional('tableDirection', tableDirectionOf(obj, ctx)),
|
|
1303
|
+
...optional(
|
|
1304
|
+
'tableSchema',
|
|
1305
|
+
Option.map(schema, (s) => schemaOf(s.obj, s.ctx)),
|
|
1306
|
+
),
|
|
1307
|
+
transformations: Arr.getSomes(
|
|
1308
|
+
Arr.map(arrayProperty(obj, 'transformations', ctx), (t) => transformationOf(t, ctx)),
|
|
1309
|
+
),
|
|
1310
|
+
inherited: inheritedOf(obj, ctx),
|
|
1311
|
+
common: commonProperties(obj, ctx),
|
|
1312
|
+
};
|
|
1313
|
+
});
|
|
1314
|
+
|
|
1315
|
+
const describedTable = Effect.fnUntraced(function* (obj: Obj, ctx: Ctx, load: Fetch) {
|
|
1316
|
+
checkKeys(obj, 'Table', ctx);
|
|
1317
|
+
const url = linkProperty(obj, 'url', ctx);
|
|
1318
|
+
if (Option.isNone(url) || !Predicate.isString(obj['url'])) error(ctx, 'a table must have a url');
|
|
1319
|
+
const shared = yield* sharedProperties(obj, ctx, load);
|
|
1320
|
+
const table: Table = {
|
|
1321
|
+
...shared,
|
|
1322
|
+
url: Option.getOrElse(url, () => ctx.base),
|
|
1323
|
+
isSuppressed: Option.getOrElse(booleanProperty(obj, 'suppressOutput', ctx), () => false),
|
|
1324
|
+
};
|
|
1325
|
+
return table;
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
const describedGroup = Effect.fnUntraced(function* (obj: Obj, ctx: Ctx, load: Fetch) {
|
|
1329
|
+
checkKeys(obj, 'TableGroup', ctx);
|
|
1330
|
+
const tables = yield* Effect.forEach(
|
|
1331
|
+
arrayProperty(obj, 'tables', ctx),
|
|
1332
|
+
(t) => describedTable(t, ctx, load),
|
|
1333
|
+
{ concurrency: 1 },
|
|
1334
|
+
);
|
|
1335
|
+
if (!Arr.isReadonlyArrayNonEmpty(tables))
|
|
1336
|
+
error(ctx, 'a table group must have at least one table');
|
|
1337
|
+
const shared = yield* sharedProperties(obj, ctx, load);
|
|
1338
|
+
const group: TableGroup = { ...shared, tables };
|
|
1339
|
+
return group;
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
/**
|
|
1343
|
+
* Decodes a parsed metadata document found at `url` into a normalized table
|
|
1344
|
+
* group (a table description becomes a group of one), fetching the schemas
|
|
1345
|
+
* and dialects it references by URL with `load`. Warnings are returned with
|
|
1346
|
+
* the group; errors fail with `MetadataError`.
|
|
1347
|
+
*
|
|
1348
|
+
* @since 0.1.0
|
|
1349
|
+
* @category decoding
|
|
1350
|
+
*/
|
|
1351
|
+
export const decodeJson = Effect.fnUntraced(function* (
|
|
1352
|
+
document: Schema.Json,
|
|
1353
|
+
url: string,
|
|
1354
|
+
load: Fetch,
|
|
1355
|
+
): Effect.fn.Return<Decoded, MetadataError> {
|
|
1356
|
+
if (!Json.isObject(document))
|
|
1357
|
+
return yield* new MetadataError({ message: 'a metadata document must be an object', url });
|
|
1358
|
+
const issues: Array<Report.Issue> = [];
|
|
1359
|
+
const ctx = yield* Effect.fromResult(contextOf(document, url, issues, true));
|
|
1360
|
+
const isGroup = Json.has(document, 'tables');
|
|
1361
|
+
if (!isGroup && !Json.has(document, 'url')) {
|
|
1362
|
+
return yield* new MetadataError({
|
|
1363
|
+
message: 'a metadata document must describe a table group (tables) or a table (url)',
|
|
1364
|
+
url,
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
const group: TableGroup = isGroup
|
|
1368
|
+
? yield* describedGroup(document, ctx, load)
|
|
1369
|
+
: {
|
|
1370
|
+
tables: [yield* describedTable(document, ctx, load)],
|
|
1371
|
+
notes: [],
|
|
1372
|
+
transformations: [],
|
|
1373
|
+
inherited: {},
|
|
1374
|
+
common: {},
|
|
1375
|
+
};
|
|
1376
|
+
const first = Arr.findFirst(issues, (i) => i.level === 'error');
|
|
1377
|
+
if (Option.isSome(first)) return yield* new MetadataError({ message: first.value.message, url });
|
|
1378
|
+
return { group, warnings: issues };
|
|
1379
|
+
});
|
|
1380
|
+
|
|
1381
|
+
/**
|
|
1382
|
+
* Decodes metadata text found at `url` (see `decodeJson`); invalid JSON fails
|
|
1383
|
+
* with `MetadataError`.
|
|
1384
|
+
*
|
|
1385
|
+
* @since 0.1.0
|
|
1386
|
+
* @category decoding
|
|
1387
|
+
*/
|
|
1388
|
+
export const decode = (
|
|
1389
|
+
text: string,
|
|
1390
|
+
url: string,
|
|
1391
|
+
load: Fetch,
|
|
1392
|
+
): Effect.Effect<Decoded, MetadataError> =>
|
|
1393
|
+
Effect.flatMap(Effect.fromResult(parseDocument(text, url)), (doc) => decodeJson(doc, url, load));
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* A `Fetch` that fails for every URL: for metadata that references no other
|
|
1397
|
+
* document.
|
|
1398
|
+
*
|
|
1399
|
+
* @since 0.1.0
|
|
1400
|
+
* @category decoding
|
|
1401
|
+
*/
|
|
1402
|
+
export const noFetch: Fetch = (url) =>
|
|
1403
|
+
Effect.fail(new MetadataError({ message: `cannot fetch ${url}`, url }));
|
|
1404
|
+
|
|
1405
|
+
// -----------------------------------------------------------------------------
|
|
1406
|
+
// Inheritance, names and compatibility
|
|
1407
|
+
// -----------------------------------------------------------------------------
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* The effective inherited properties of a column: its own, then its schema's,
|
|
1411
|
+
* its table's and its group's.
|
|
1412
|
+
*
|
|
1413
|
+
* @since 0.1.0
|
|
1414
|
+
* @category inheritance
|
|
1415
|
+
*/
|
|
1416
|
+
export const inherit = (...levels: ReadonlyArray<Inherited>): Inherited =>
|
|
1417
|
+
Arr.reduceRight(levels, noInherited, (acc, level) => ({ ...acc, ...level }));
|
|
1418
|
+
|
|
1419
|
+
const noInherited: Inherited = {};
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* The table's effective schema: its own, or its group's.
|
|
1423
|
+
*
|
|
1424
|
+
* @since 0.1.0
|
|
1425
|
+
* @category inheritance
|
|
1426
|
+
*/
|
|
1427
|
+
export const schemaOfTable = (group: TableGroup, table: Table): Option.Option<TableSchema> =>
|
|
1428
|
+
Option.orElse(Option.fromNullishOr(table.tableSchema), () =>
|
|
1429
|
+
Option.fromNullishOr(group.tableSchema),
|
|
1430
|
+
);
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* The table's effective dialect: its own, its group's, or the default.
|
|
1434
|
+
*
|
|
1435
|
+
* @since 0.1.0
|
|
1436
|
+
* @category inheritance
|
|
1437
|
+
*/
|
|
1438
|
+
export const dialectOfTable = (group: TableGroup, table: Table): Dialect =>
|
|
1439
|
+
table.dialect ?? group.dialect ?? defaultDialect;
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* Whether two language tags match for title comparison: `und` matches any
|
|
1443
|
+
* language, and tags match when equal after truncation to the shorter one.
|
|
1444
|
+
*
|
|
1445
|
+
* @since 0.1.0
|
|
1446
|
+
* @category compatibility
|
|
1447
|
+
*/
|
|
1448
|
+
export const languagesMatch = (a: string, b: string): boolean => {
|
|
1449
|
+
if (a === 'und' || b === 'und') return true;
|
|
1450
|
+
const x = a.toLowerCase().split('-');
|
|
1451
|
+
const y = b.toLowerCase().split('-');
|
|
1452
|
+
const n = Math.min(Arr.length(x), Arr.length(y));
|
|
1453
|
+
return Arr.join(Arr.take(x, n), '-') === Arr.join(Arr.take(y, n), '-');
|
|
1454
|
+
};
|
|
1455
|
+
|
|
1456
|
+
const titleEntries = (titles: LanguageMap): ReadonlyArray<readonly [string, string]> =>
|
|
1457
|
+
Arr.flatMap(Record.toEntries(titles), ([lang, ts]) => Arr.map(ts, (t) => [lang, t] as const));
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Whether two column descriptions are compatible (§Schema Compatibility).
|
|
1461
|
+
*
|
|
1462
|
+
* @since 0.1.0
|
|
1463
|
+
* @category compatibility
|
|
1464
|
+
*/
|
|
1465
|
+
export const columnsCompatible = (a: Column, b: Column, validating: boolean): boolean => {
|
|
1466
|
+
const aTitles = titleEntries(a.titles);
|
|
1467
|
+
const bTitles = titleEntries(b.titles);
|
|
1468
|
+
const aEmpty = a.name === undefined && !Arr.isReadonlyArrayNonEmpty(aTitles);
|
|
1469
|
+
const bEmpty = b.name === undefined && !Arr.isReadonlyArrayNonEmpty(bTitles);
|
|
1470
|
+
if (aEmpty || bEmpty) return true;
|
|
1471
|
+
if (a.name !== undefined && a.name === b.name) return true;
|
|
1472
|
+
if (
|
|
1473
|
+
Arr.some(aTitles, ([la, ta]) =>
|
|
1474
|
+
Arr.some(bTitles, ([lb, tb]) => ta === tb && languagesMatch(la, lb)),
|
|
1475
|
+
)
|
|
1476
|
+
)
|
|
1477
|
+
return true;
|
|
1478
|
+
if (!validating) {
|
|
1479
|
+
const nameOnly = (c: Column, ts: ReadonlyArray<unknown>) =>
|
|
1480
|
+
c.name !== undefined && !Arr.isReadonlyArrayNonEmpty(ts);
|
|
1481
|
+
const titlesOnly = (c: Column, ts: ReadonlyArray<unknown>) =>
|
|
1482
|
+
c.name === undefined && Arr.isReadonlyArrayNonEmpty(ts);
|
|
1483
|
+
if (
|
|
1484
|
+
(nameOnly(a, aTitles) && titlesOnly(b, bTitles)) ||
|
|
1485
|
+
(titlesOnly(a, aTitles) && nameOnly(b, bTitles))
|
|
1486
|
+
)
|
|
1487
|
+
return true;
|
|
1488
|
+
}
|
|
1489
|
+
return false;
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* Checks a table's schema against the columns embedded in its data
|
|
1494
|
+
* (§Schema Compatibility), returning the reason they are incompatible.
|
|
1495
|
+
*
|
|
1496
|
+
* @since 0.1.0
|
|
1497
|
+
* @category compatibility
|
|
1498
|
+
*/
|
|
1499
|
+
export const checkCompatible = (
|
|
1500
|
+
schema: ReadonlyArray<Column>,
|
|
1501
|
+
embedded: ReadonlyArray<Column>,
|
|
1502
|
+
validating: boolean,
|
|
1503
|
+
): Option.Option<string> => {
|
|
1504
|
+
const real = Arr.filter(schema, (c) => !c.isVirtual);
|
|
1505
|
+
if (Arr.length(real) !== Arr.length(embedded))
|
|
1506
|
+
return Option.some(
|
|
1507
|
+
`the metadata describes ${Arr.length(real)} columns but the data has ${Arr.length(embedded)}`,
|
|
1508
|
+
);
|
|
1509
|
+
return Option.map(
|
|
1510
|
+
Arr.findFirstIndex(Arr.zip(real, embedded), ([a, b]) => !columnsCompatible(a, b, validating)),
|
|
1511
|
+
(i) => `column ${i + 1} of the metadata is not compatible with the data's header`,
|
|
1512
|
+
);
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
/**
|
|
1516
|
+
* Whether a table group describes the table at `url` (URLs compared after
|
|
1517
|
+
* normalization).
|
|
1518
|
+
*
|
|
1519
|
+
* @since 0.1.0
|
|
1520
|
+
* @category compatibility
|
|
1521
|
+
*/
|
|
1522
|
+
export const describes = (group: TableGroup, url: string): boolean =>
|
|
1523
|
+
Arr.some(group.tables, (t) => Url.normalize(t.url) === Url.normalize(url));
|