From 5815ac0cbc86193d966b62e32d489c000b487358 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Mon, 26 May 2025 17:23:08 +0100 Subject: [PATCH] feat: add shacl support --- package-lock.json | 360 +++++++++++++++++++++++++- packages/cli/package.json | 3 + packages/cli/src/util/forAllShapes.ts | 53 +++- 3 files changed, 414 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1cacd0a..c900258 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5782,6 +5782,97 @@ "fsevents": "^2.3.2" } }, + "node_modules/@jeswr/shacl2shex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jeswr/shacl2shex/-/shacl2shex-1.1.0.tgz", + "integrity": "sha512-1lcPUqavU+Q1wCM+aF2JbHjTKoBZTNbA6n4P+EfmXDzNKK8UPJ6qRlyx6ICpHEw2wxoXhcFAYdtBUpQc/cxHnw==", + "license": "MIT", + "dependencies": { + "@ldo/ldo": "^0.0.1-alpha.24", + "@on2ts/ontologies-sh": "^1.0.51", + "@rdfjs/term-set": "^1.1.0", + "@rdfjs/types": "^1.1.0", + "@shexjs/neighborhood-rdfjs": "^1.0.0-alpha.29", + "@shexjs/validator": "^1.0.0-alpha.29", + "@shexjs/writer": "^1.0.0-alpha.27", + "event-emitter-promisify": "^1.1.0", + "n3": "^1.17.3", + "rdf-dereference": "^2.2.0", + "rdf-namespaces": "^1.12.0" + }, + "bin": { + "shacl2shex": "dist/bin/index.js" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@ldo/dataset": { + "version": "0.0.1-alpha.24", + "resolved": "https://registry.npmjs.org/@ldo/dataset/-/dataset-0.0.1-alpha.24.tgz", + "integrity": "sha512-Jlh6DjvLN4gOOT8SYCKQaHZB8taeHvoriQRbF3s5CtYFf8Ne20job+02cToE1kVcBCinBrjZ/qnZ777wje+Z7A==", + "license": "MIT", + "dependencies": { + "@ldo/rdf-utils": "^0.0.1-alpha.24", + "@rdfjs/dataset": "^1.1.0", + "buffer": "^6.0.3", + "readable-stream": "^4.2.0" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@ldo/jsonld-dataset-proxy": { + "version": "0.0.1-alpha.29", + "resolved": "https://registry.npmjs.org/@ldo/jsonld-dataset-proxy/-/jsonld-dataset-proxy-0.0.1-alpha.29.tgz", + "integrity": "sha512-6r1tn/t82aJ6vjxEGyNSJTzQJgz1Z4Pu875o4EolXXJZCu7TiXBdsW6HyAuloqiIV5b6A2b+M6G0mOuObndooA==", + "license": "MIT", + "dependencies": { + "@ldo/rdf-utils": "^0.0.1-alpha.24", + "@ldo/subscribable-dataset": "^0.0.1-alpha.24", + "@rdfjs/data-model": "^1.2.0", + "@rdfjs/dataset": "^1.1.0", + "jsonld2graphobject": "^0.0.4" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@ldo/ldo": { + "version": "0.0.1-alpha.29", + "resolved": "https://registry.npmjs.org/@ldo/ldo/-/ldo-0.0.1-alpha.29.tgz", + "integrity": "sha512-eci3e2FlaSoOWN5vzLQaJhrmznuuK89yTr/ZLvmWIK2bvsY8QOArAx8EiGgwvvrzvHpG7ezaoW1ThS/53QFiqQ==", + "license": "MIT", + "dependencies": { + "@ldo/dataset": "^0.0.1-alpha.24", + "@ldo/jsonld-dataset-proxy": "^0.0.1-alpha.29", + "@ldo/subscribable-dataset": "^0.0.1-alpha.24", + "@rdfjs/data-model": "^1.2.0", + "buffer": "^6.0.3", + "readable-stream": "^4.3.0" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@ldo/rdf-utils": { + "version": "0.0.1-alpha.24", + "resolved": "https://registry.npmjs.org/@ldo/rdf-utils/-/rdf-utils-0.0.1-alpha.24.tgz", + "integrity": "sha512-L6gV/pS7107ODinnvvD4sUBb9VM/7IuVeFWZnN0Jmyk7XBiviPLVUvReO18UB7mambXweLS7efl+Z0W2NnsH1A==", + "license": "MIT", + "dependencies": { + "@rdfjs/data-model": "^1.2.0", + "n3": "^1.17.1", + "rdf-string": "^1.6.3" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@ldo/subscribable-dataset": { + "version": "0.0.1-alpha.24", + "resolved": "https://registry.npmjs.org/@ldo/subscribable-dataset/-/subscribable-dataset-0.0.1-alpha.24.tgz", + "integrity": "sha512-grQ0/pzdx4euBOTxMHqQqebOYBqrBbNS9Jk8sYFR4u/dEg8e6nIGz0E4beI83dHp/hT8fT18gs/gV4UxZzmphQ==", + "license": "MIT", + "dependencies": { + "@ldo/dataset": "^0.0.1-alpha.24", + "@ldo/rdf-utils": "^0.0.1-alpha.24" + } + }, + "node_modules/@jeswr/shacl2shex/node_modules/@rdfjs/types": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.1.2.tgz", + "integrity": "sha512-wqpOJK1QCbmsGNtyzYnojPU8gRDPid2JO0Q0kMtb4j65xhCK880cnKAfEOwC+dX85VJcCByQx5zOwyyfCjDJsg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -7289,6 +7380,46 @@ "@octokit/openapi-types": "^18.0.0" } }, + "node_modules/@on2ts/ontologies-sh": { + "version": "1.0.51", + "resolved": "https://registry.npmjs.org/@on2ts/ontologies-sh/-/ontologies-sh-1.0.51.tgz", + "integrity": "sha512-V0k+ZKupMjCQajCGkMVmILsxLq1uqHLY6V2xTmBJ0Y34q4dLZF6r1dX2NW1PZofekxLvx8VNNDsvynyPTDFp7g==", + "license": "MIT", + "dependencies": { + "@on2ts/ontologies-utils": "^1.0.51" + } + }, + "node_modules/@on2ts/ontologies-utils": { + "version": "1.0.51", + "resolved": "https://registry.npmjs.org/@on2ts/ontologies-utils/-/ontologies-utils-1.0.51.tgz", + "integrity": "sha512-xM4052l0OKxk73ERuWY+IObEIVgXxkwDOFZU3rlLK6GBDbReaGXSYK9DAJyqwk0R1FcyLZxjNdIDYN4WbMzpuA==", + "license": "MIT", + "dependencies": { + "@types/rdf-js": "^4.0.1", + "jsonld-streaming-parser": "^2.2.1" + } + }, + "node_modules/@on2ts/ontologies-utils/node_modules/canonicalize": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/canonicalize/-/canonicalize-1.0.8.tgz", + "integrity": "sha512-0CNTVCLZggSh7bc5VkX5WWPWO+cyZbNd07IHIsSXLia/eAq+r836hgk+8BKoEh7949Mda87VUOitx5OddVj64A==", + "license": "Apache-2.0" + }, + "node_modules/@on2ts/ontologies-utils/node_modules/jsonld-streaming-parser": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/jsonld-streaming-parser/-/jsonld-streaming-parser-2.4.3.tgz", + "integrity": "sha512-ysuevJ+l8+Y4W3J/yQW3pa9VCBNDHo2tZkKmPAnfhfsmFMyxuueAeXMmTbpJZdrpagzeeDVr3A8EZVuHliQJ9A==", + "license": "MIT", + "dependencies": { + "@rdfjs/types": "*", + "@types/http-link-header": "^1.0.1", + "canonicalize": "^1.0.1", + "http-link-header": "^1.0.2", + "jsonld-context-parser": "^2.1.3", + "jsonparse": "^1.3.1", + "rdf-data-factory": "^1.1.0" + } + }, "node_modules/@parcel/watcher": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", @@ -7873,6 +8004,69 @@ "string-argv": "~0.3.1" } }, + "node_modules/@shexjs/eval-simple-1err": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/@shexjs/eval-simple-1err/-/eval-simple-1err-1.0.0-alpha.29.tgz", + "integrity": "sha512-qizKDp+FPoOL9140VJglIbf9brgQdoPDrZ0t0vmTEdRQvY5+rF+H20nStAiPPK6XxC/AbIglv6/dImQWAMKuSw==", + "license": "MIT", + "dependencies": { + "@shexjs/eval-validator-api": "^1.0.0-alpha.29", + "@shexjs/term": "^1.0.0-alpha.27" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@shexjs/eval-threaded-nerr": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/@shexjs/eval-threaded-nerr/-/eval-threaded-nerr-1.0.0-alpha.29.tgz", + "integrity": "sha512-/RFl7SzEaiofdLd1qNidvpU4Yy4TZuMdO5DMPznHkIICjyJeKgg8Kx166VznZPVIa66Sxr/hG4ngkaWsHxWYwQ==", + "license": "MIT", + "dependencies": { + "@shexjs/eval-validator-api": "^1.0.0-alpha.29", + "@shexjs/term": "^1.0.0-alpha.27" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@shexjs/eval-validator-api": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/@shexjs/eval-validator-api/-/eval-validator-api-1.0.0-alpha.29.tgz", + "integrity": "sha512-5QCd6DvgBMOZvWZtixdsH/d4uXPzxYr4yv7C0wzVeBKRkB15KQd7Ccg8Bz9QbsIV1O9asxG1xoxGgYDkhZeBPg==", + "license": "MIT", + "dependencies": { + "@shexjs/term": "^1.0.0-alpha.27" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@shexjs/neighborhood-api": { + "version": "1.0.0-alpha.28", + "resolved": "https://registry.npmjs.org/@shexjs/neighborhood-api/-/neighborhood-api-1.0.0-alpha.28.tgz", + "integrity": "sha512-rkIIt39z3z1gt+8xc3CJAKLBJ/OUE+8sP24Iqs9uZYuRvJitavd+L8oX5XcdpMduwJUqE6s+Rf/YUuN0VYn7Qw==", + "license": "MIT", + "dependencies": { + "@shexjs/term": "^1.0.0-alpha.27" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@shexjs/neighborhood-rdfjs": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/@shexjs/neighborhood-rdfjs/-/neighborhood-rdfjs-1.0.0-alpha.29.tgz", + "integrity": "sha512-6B4LMfTyQA5L42QI3+rlGxQEPywqLe4CFJDUm/bn6V3ldakajh/ZbPHod3DPjSLsJ7tYLZsRi9GPIPTgYgmZUw==", + "license": "MIT", + "dependencies": { + "@shexjs/eval-validator-api": "^1.0.0-alpha.29", + "@shexjs/term": "^1.0.0-alpha.27" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@shexjs/parser": { "version": "1.0.0-alpha.28", "resolved": "https://registry.npmjs.org/@shexjs/parser/-/parser-1.0.0-alpha.28.tgz", @@ -7916,6 +8110,35 @@ "node": ">=0.10.0" } }, + "node_modules/@shexjs/validator": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/@shexjs/validator/-/validator-1.0.0-alpha.29.tgz", + "integrity": "sha512-KO9Sf9ICpnoFFutiX59vx7o9eRnOPuKngKxfeyOzM3mKmKQXad0SOIbqRxRBaMgV/eXwhnIERhzvCK66EZMrFQ==", + "license": "MIT", + "dependencies": { + "@rdfjs/data-model": "^2.0.1", + "@shexjs/eval-simple-1err": "^1.0.0-alpha.29", + "@shexjs/eval-threaded-nerr": "^1.0.0-alpha.29", + "@shexjs/eval-validator-api": "^1.0.0-alpha.29", + "@shexjs/neighborhood-api": "^1.0.0-alpha.28", + "@shexjs/term": "^1.0.0-alpha.27", + "@shexjs/visitor": "^1.0.0-alpha.27", + "@types/shexj": "^2.1.6", + "hierarchy-closure": "^1.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@shexjs/validator/node_modules/@rdfjs/data-model": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@rdfjs/data-model/-/data-model-2.1.0.tgz", + "integrity": "sha512-pnjwSqDCXxxJQPm3TyDaqoWynYYQBl1pZC7rIPhdck7RbcEVF8hIBg5vXXosUbNcW3qwyAEBtYGojoWRnxBPew==", + "license": "MIT", + "bin": { + "rdfjs-data-model-test": "bin/test.js" + } + }, "node_modules/@shexjs/visitor": { "version": "1.0.0-alpha.27", "resolved": "https://registry.npmjs.org/@shexjs/visitor/-/visitor-1.0.0-alpha.27.tgz", @@ -7925,6 +8148,18 @@ "node": ">=0.10.0" } }, + "node_modules/@shexjs/writer": { + "version": "1.0.0-alpha.27", + "resolved": "https://registry.npmjs.org/@shexjs/writer/-/writer-1.0.0-alpha.27.tgz", + "integrity": "sha512-VK4gIQdIuhlU2vU8HiZAvffj4zPzLrDjLaBS0uKiLS0VTSpee4rejLJs4HiXCfPXFY7xOdW+As9dBH7kKpXWew==", + "license": "MIT", + "dependencies": { + "relativize-url": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -9377,6 +9612,15 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, + "node_modules/@types/rdf-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/rdf-js/-/rdf-js-4.0.1.tgz", + "integrity": "sha512-S+28+3RoFI+3arls7dS813gYnhb2HiyLX+gs00rgIvCzHU93DaYajhx4tyT+XEO8SjtzZw90OF4OVdYXBwbvkQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/rdf-validate-shacl": { "version": "0.4.9", "resolved": "https://registry.npmjs.org/@types/rdf-validate-shacl/-/rdf-validate-shacl-0.4.9.tgz", @@ -14111,6 +14355,12 @@ "url": "https://github.com/eta-dev/eta?sponsor=1" } }, + "node_modules/event-emitter-promisify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/event-emitter-promisify/-/event-emitter-promisify-1.1.0.tgz", + "integrity": "sha512-uyHG8gjwYGDlKoo0Txtx/u1HI1ubj0FK0rVqI4O0s1EymQm4iAEMbrS5B+XFlSaS8SZ3xzoKX+YHRZk8Nk/bXg==", + "license": "MIT" + }, "node_modules/event-stream": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", @@ -18803,7 +19053,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, "engines": [ "node >= 0.2.0" ], @@ -23535,6 +23784,106 @@ "rdf-dereference": "bin/Runner.js" } }, + "node_modules/rdf-dereference-store": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rdf-dereference-store/-/rdf-dereference-store-1.3.2.tgz", + "integrity": "sha512-T9lYzCjd3IF4NWzmL4nN/DOQMqghNv/mFrxg3/V0ADAsNVjqy/EU1W9HAgmR6jczLcZWxbp9ZEHMEXoIANVEuQ==", + "license": "MIT", + "dependencies": { + "@rdfjs/types": "^1.1.0", + "@types/n3": "^1.16.4", + "asynciterator": "^3.9.0", + "event-emitter-promisify": "^1.1.0", + "n3": "^1.17.3", + "rdf-dereference": "^3.0.0", + "rdf-parse": "^3.0.0", + "readable-stream": "^4.5.2" + } + }, + "node_modules/rdf-dereference-store/node_modules/@rdfjs/types": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rdfjs/types/-/types-1.1.2.tgz", + "integrity": "sha512-wqpOJK1QCbmsGNtyzYnojPU8gRDPid2JO0Q0kMtb4j65xhCK880cnKAfEOwC+dX85VJcCByQx5zOwyyfCjDJsg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rdf-dereference-store/node_modules/rdf-dereference": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rdf-dereference/-/rdf-dereference-3.0.0.tgz", + "integrity": "sha512-LxB1dP357S/NuivEfNa2YMbnY+k+hPNrvAx/p6CUaHhKv5wuqJHtfmbm8ahqbo/98CizjoFew5xT4WlqedXWYA==", + "license": "MIT", + "dependencies": { + "@comunica/actor-dereference-fallback": "^2.0.2", + "@comunica/actor-dereference-file": "^2.0.2", + "@comunica/actor-dereference-http": "^2.0.2", + "@comunica/actor-dereference-rdf-parse": "^2.6.0", + "@comunica/actor-http-fetch": "^2.0.1", + "@comunica/actor-http-proxy": "^2.0.1", + "@comunica/actor-rdf-parse-html": "^2.0.1", + "@comunica/actor-rdf-parse-html-microdata": "^2.0.1", + "@comunica/actor-rdf-parse-html-rdfa": "^2.0.1", + "@comunica/actor-rdf-parse-html-script": "^2.0.1", + "@comunica/actor-rdf-parse-jsonld": "^2.0.1", + "@comunica/actor-rdf-parse-n3": "^2.0.1", + "@comunica/actor-rdf-parse-rdfxml": "^2.0.1", + "@comunica/actor-rdf-parse-shaclc": "^2.6.0", + "@comunica/actor-rdf-parse-xml-rdfa": "^2.0.1", + "@comunica/bus-dereference": "^2.0.2", + "@comunica/bus-dereference-rdf": "^2.0.2", + "@comunica/bus-http": "^2.0.1", + "@comunica/bus-init": "^2.0.1", + "@comunica/bus-rdf-parse": "^2.0.1", + "@comunica/bus-rdf-parse-html": "^2.0.1", + "@comunica/config-query-sparql": "^2.0.1", + "@comunica/context-entries": "^2.8.1", + "@comunica/core": "^2.0.1", + "@comunica/mediator-combine-pipeline": "^2.0.1", + "@comunica/mediator-combine-union": "^2.0.1", + "@comunica/mediator-number": "^2.0.1", + "@comunica/mediator-race": "^2.0.1", + "@rdfjs/types": "*", + "process": "^0.11.10", + "rdf-string": "^1.6.0", + "stream-to-string": "^1.2.0" + }, + "bin": { + "rdf-dereference": "bin/Runner.js" + } + }, + "node_modules/rdf-dereference-store/node_modules/rdf-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rdf-parse/-/rdf-parse-3.0.0.tgz", + "integrity": "sha512-W+h4cEL299Va9XXmtbM6Cl3Mh6dMUgFC2a3q7nyohEOPjp/ZOxFS9zNfnJY1/5wnmaLXbydnJhahwkcnQ8kD/g==", + "license": "MIT", + "dependencies": { + "@comunica/actor-http-fetch": "^2.0.1", + "@comunica/actor-http-proxy": "^2.0.1", + "@comunica/actor-rdf-parse-html": "^2.0.1", + "@comunica/actor-rdf-parse-html-microdata": "^2.0.1", + "@comunica/actor-rdf-parse-html-rdfa": "^2.0.1", + "@comunica/actor-rdf-parse-html-script": "^2.0.1", + "@comunica/actor-rdf-parse-jsonld": "^2.0.1", + "@comunica/actor-rdf-parse-n3": "^2.0.1", + "@comunica/actor-rdf-parse-rdfxml": "^2.0.1", + "@comunica/actor-rdf-parse-shaclc": "^2.6.2", + "@comunica/actor-rdf-parse-xml-rdfa": "^2.0.1", + "@comunica/bus-http": "^2.0.1", + "@comunica/bus-init": "^2.0.1", + "@comunica/bus-rdf-parse": "^2.0.1", + "@comunica/bus-rdf-parse-html": "^2.0.1", + "@comunica/config-query-sparql": "^2.0.1", + "@comunica/core": "^2.0.1", + "@comunica/mediator-combine-pipeline": "^2.0.1", + "@comunica/mediator-combine-union": "^2.0.1", + "@comunica/mediator-number": "^2.0.1", + "@comunica/mediator-race": "^2.0.1", + "@rdfjs/types": "*", + "readable-stream": "^4.3.0", + "stream-to-string": "^1.2.0" + } + }, "node_modules/rdf-isomorphic": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.3.1.tgz", @@ -23568,6 +23917,12 @@ "rdf-data-factory": "^1.1.0" } }, + "node_modules/rdf-namespaces": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/rdf-namespaces/-/rdf-namespaces-1.12.0.tgz", + "integrity": "sha512-Fk48ltssXTmyXeoLqC0y85CEAhhWH+wvu7bkr9WxsKUyFDcKwWSHOK7CvRq3XRampy1qhSrOsIQ8U1gQDCh5MA==", + "license": "MIT" + }, "node_modules/rdf-object": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/rdf-object/-/rdf-object-1.14.0.tgz", @@ -30340,6 +30695,7 @@ "version": "1.0.0-alpha.21", "license": "MIT", "dependencies": { + "@jeswr/shacl2shex": "^1.1.0", "@ldo/ldo": "^1.0.0-alpha.21", "@ldo/schema-converter-shex": "^1.0.0-alpha.21", "@shexjs/parser": "^1.0.0-alpha.24", @@ -30350,6 +30706,8 @@ "loading-cli": "^1.1.0", "prettier": "^3.0.3", "prompts": "^2.4.2", + "rdf-dereference-store": "^1.3.2", + "rdf-namespaces": "^1.12.0", "ts-morph": "^24.0.0", "type-fest": "^2.19.0" }, diff --git a/packages/cli/package.json b/packages/cli/package.json index 29d1f48..b6687c5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -40,6 +40,7 @@ "rimraf": "^3.0.2" }, "dependencies": { + "@jeswr/shacl2shex": "^1.1.0", "@ldo/ldo": "^1.0.0-alpha.21", "@ldo/schema-converter-shex": "^1.0.0-alpha.21", "@shexjs/parser": "^1.0.0-alpha.24", @@ -50,6 +51,8 @@ "loading-cli": "^1.1.0", "prettier": "^3.0.3", "prompts": "^2.4.2", + "rdf-dereference-store": "^1.3.2", + "rdf-namespaces": "^1.12.0", "ts-morph": "^24.0.0", "type-fest": "^2.19.0" }, diff --git a/packages/cli/src/util/forAllShapes.ts b/packages/cli/src/util/forAllShapes.ts index 7897b35..e84da86 100644 --- a/packages/cli/src/util/forAllShapes.ts +++ b/packages/cli/src/util/forAllShapes.ts @@ -1,5 +1,22 @@ import fs from "fs"; import path from "path"; +import { shaclStoreToShexSchema, writeShexSchema } from "@jeswr/shacl2shex"; +import derefStore from "rdf-dereference-store"; +import type { Store } from "n3"; +import { DataFactory as DF } from "n3"; +import { rdf } from "rdf-namespaces"; + +function hasMatch(store: Store, predicate: string, object: string) { + for (const _ in store.match( + null, + DF.namedNode(predicate), + DF.namedNode(object), + DF.defaultGraph(), + )) { + return true; + } + return false; +} export async function forAllShapes( shapePath: string, @@ -12,7 +29,7 @@ export async function forAllShapes( const shexFiles = shapeDir.filter( (file) => file.isFile() && file.name.endsWith(".shex"), ); - await Promise.all( + const shexPromise = Promise.all( shexFiles.map(async (file) => { const fileName = path.parse(file.name).name; // Get the content of each document @@ -23,4 +40,38 @@ export async function forAllShapes( await callback(fileName, shexC); }), ); + // See if any of the RDF files contain a SHACL shape + const shaclPromise = Promise.all( + shapeDir.map(async (file) => { + if (file.isFile()) { + try { + const store = await derefStore(path.join(shapePath, file.name), { + localFiles: true, + }); + // Make sure the RDF file contains a SHACL shape + if ( + hasMatch( + store.store, + rdf.type, + "http://www.w3.org/ns/shacl#NodeShape", + ) || + hasMatch( + store.store, + rdf.type, + "http://www.w3.org/ns/shacl#PropertyShape", + ) + ) { + const shex = await writeShexSchema( + await shaclStoreToShexSchema(store.store), + store.prefixes, + ); + await callback(shex, path.parse(file.name).name); + } + } catch (e) { + // no-op ignore invalid RDF file + } + } + }), + ); + await Promise.all([shexPromise, shaclPromise]); }