diff --git a/.changeset/brave-papayas-obey.md b/.changeset/brave-papayas-obey.md new file mode 100644 index 00000000..0d74290d --- /dev/null +++ b/.changeset/brave-papayas-obey.md @@ -0,0 +1,5 @@ +--- +"barnard59-formats": patch +--- + +Added type declarations diff --git a/.changeset/eighty-melons-boil.md b/.changeset/eighty-melons-boil.md new file mode 100644 index 00000000..97fc1f9a --- /dev/null +++ b/.changeset/eighty-melons-boil.md @@ -0,0 +1,5 @@ +--- +"barnard59-env": patch +--- + +Update `@zazuko/env-node` diff --git a/.changeset/young-turkeys-sit.md b/.changeset/young-turkeys-sit.md new file mode 100644 index 00000000..a70304e5 --- /dev/null +++ b/.changeset/young-turkeys-sit.md @@ -0,0 +1,5 @@ +--- +"barnard59-formats": patch +--- + +Ensures that the RDF/JS environment is used with parser streams diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 22e6d670..26c94dd3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -81,14 +81,20 @@ jobs: strategy: fail-fast: false matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest - runs-on: ${{ matrix.os }} + env: + - os: ubuntu-latest + node: 20 + - os: macos-latest + node: 20 + - os: windows-latest + node: 20.12.1 # Pinned, because of https://github.com/approvals/Approvals.NodeJS/issues/176 + runs-on: ${{ matrix.env.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.env.node }} + cache: npm - run: npm ci - run: npx barnard59 run test/e2e/definitions/file-loader.ttl - run: npx barnard59 run test/e2e/definitions/foreach/with-handler.ttl @@ -103,25 +109,31 @@ jobs: strategy: fail-fast: false matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest - runs-on: ${{ matrix.os }} + env: + - os: ubuntu-latest + node: 20 + - os: macos-latest + node: 20 + - os: windows-latest + node: 20.12.1 # Pinned, because of https://github.com/approvals/Approvals.NodeJS/issues/176 + runs-on: ${{ matrix.env.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.env.node }} + cache: npm - run: npm ci - name: pack all run: npm pack -ws - run: npm install -g barnard59-*.tgz - if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' + if: matrix.env.os == 'ubuntu-latest' || matrix.env.os == 'macos-latest' - run: cmd /c npm install -g (Get-ChildItem -Filter barnard59-*.tgz).FullName - if: matrix.os == 'windows-latest' + if: matrix.env.os == 'windows-latest' - run: which barnard59 - run: barnard59 --help - run: barnard59 shacl validate --shapes test/support/pipeline-shapes.ttl < test/e2e/definitions/file-loader.ttl - if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' + if: matrix.env.os == 'ubuntu-latest' || matrix.os == 'macos-latest' - run: barnard59 shacl validate --shapes test/support/pipeline-shapes.ttl < test/e2e/definitions/file-loader.ttl - if: matrix.os == 'windows-latest' + if: matrix.env.os == 'windows-latest' shell: cmd diff --git a/package-lock.json b/package-lock.json index d5c42df2..8e56163e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,8 +26,7 @@ "mocha": "^10.2.0", "sinon-chai": "^3.7.0", "ts-node": "^10.9.2", - "tsm": "^2.3.0", - "typescript": "^5.3.2", + "typescript": "^5.4.5", "wsrun": "^5.2.4" }, "engines": { @@ -6457,6 +6456,24 @@ "rdf-js": "^4.0.2" } }, + "node_modules/@types/rdf-parser-csvw": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@types/rdf-parser-csvw/-/rdf-parser-csvw-0.15.0.tgz", + "integrity": "sha512-m8YYxA9KIpEUucOONwLPlCb/X4OFwociBBhkK280uqhDNowZhpnQpDx3OtE7qE9u+1uAzUSfnH5rhL17Rah7oA==", + "dev": true, + "dependencies": { + "@rdfjs/types": "*" + } + }, + "node_modules/@types/rdf-parser-csvw-xlsx": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@types/rdf-parser-csvw-xlsx/-/rdf-parser-csvw-xlsx-0.1.0.tgz", + "integrity": "sha512-TrgN5yDVKKWD8Reks+RI/GsHrNvLgU+vFcXVmic+MeIRHKSNOGCbulCk3l+YzhKhUvCiHyDX+k8Pqr9PMuJw7Q==", + "dev": true, + "dependencies": { + "@rdfjs/types": "*" + } + }, "node_modules/@types/rdf-transform-triple-to-quad": { "version": "2.0.5", "dev": true, @@ -6616,18 +6633,20 @@ } }, "node_modules/@types/rdfjs__parser-jsonld": { - "version": "2.1.1", - "license": "MIT", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/rdfjs__parser-jsonld/-/rdfjs__parser-jsonld-2.1.7.tgz", + "integrity": "sha512-n35K+c1Y95580N202Jxly6xjFE953FF+Y2mwxok6zLfMo4rgIfgMBElnNwpja0IeYXTuzGm1tEz7va3lItGrTg==", "dependencies": { - "@types/jsonld": "*", - "rdf-js": "^4.0.2" + "@rdfjs/types": ">=1.0.0", + "@types/jsonld": "*" } }, "node_modules/@types/rdfjs__parser-n3": { - "version": "2.0.1", - "license": "MIT", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/rdfjs__parser-n3/-/rdfjs__parser-n3-2.0.6.tgz", + "integrity": "sha512-VHfdq7BDV6iMCtHkzTFSOuUWnqGlMUmEF0UZyK4+g9SzLWvc6TMcU5TYwQPQIz/e0s7dZ+xomxx6mVtIzsRQ/A==", "dependencies": { - "rdf-js": "^4.0.2" + "@rdfjs/types": ">=1.0.0" } }, "node_modules/@types/rdfjs__prefix-map": { @@ -6679,6 +6698,16 @@ "@rdfjs/types": "*" } }, + "node_modules/@types/rdfjs__sink-to-duplex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/rdfjs__sink-to-duplex/-/rdfjs__sink-to-duplex-1.0.0.tgz", + "integrity": "sha512-hUqFFuTbFvNBcBL/gfHG2+RwvV9T6wEcDUOA1rBQLsq/y+CgPygzFRT8AOuS5MSy0nzR4igajYn0wfkEasVZRw==", + "dev": true, + "dependencies": { + "@rdfjs/types": "*", + "@types/duplexify": "^3.6.4" + } + }, "node_modules/@types/rdfjs__term-map": { "version": "2.0.9", "license": "MIT", @@ -6719,6 +6748,15 @@ "@types/node": "*" } }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/semver": { "version": "6.2.3", "dev": true, @@ -12007,57 +12045,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.15.18", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.18", - "@esbuild/linux-loong64": "0.15.18", - "esbuild-android-64": "0.15.18", - "esbuild-android-arm64": "0.15.18", - "esbuild-darwin-64": "0.15.18", - "esbuild-darwin-arm64": "0.15.18", - "esbuild-freebsd-64": "0.15.18", - "esbuild-freebsd-arm64": "0.15.18", - "esbuild-linux-32": "0.15.18", - "esbuild-linux-64": "0.15.18", - "esbuild-linux-arm": "0.15.18", - "esbuild-linux-arm64": "0.15.18", - "esbuild-linux-mips64le": "0.15.18", - "esbuild-linux-ppc64le": "0.15.18", - "esbuild-linux-riscv64": "0.15.18", - "esbuild-linux-s390x": "0.15.18", - "esbuild-netbsd-64": "0.15.18", - "esbuild-openbsd-64": "0.15.18", - "esbuild-sunos-64": "0.15.18", - "esbuild-windows-32": "0.15.18", - "esbuild-windows-64": "0.15.18", - "esbuild-windows-arm64": "0.15.18" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.18", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/escalade": { "version": "3.1.1", "license": "MIT", @@ -25736,20 +25723,6 @@ "version": "2.5.3", "license": "0BSD" }, - "node_modules/tsm": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.15.16" - }, - "bin": { - "tsm": "bin.js" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/tty-table": { "version": "4.2.1", "dev": true, @@ -25968,9 +25941,10 @@ } }, "node_modules/typescript": { - "version": "5.3.3", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -27449,11 +27423,17 @@ "@rdfjs/serializer-ntriples": "^2.0.0", "@rdfjs/sink-to-duplex": "^1.0.0", "barnard59-base": "^2.0.1", + "is-stream": "^3.0.0", "rdf-parser-csvw": "^0.15.0", "rdf-parser-csvw-xlsx": "^0.1.0", "rdfxml-streaming-parser": "^1.2.0" }, "devDependencies": { + "@types/rdf-parser-csvw": "^0.15.0", + "@types/rdf-parser-csvw-xlsx": "^0.1.0", + "@types/rdfjs__parser-jsonld": "^2.1.7", + "@types/rdfjs__sink-to-duplex": "^1.0.0", + "@types/sax": "^1.2.7", "@zazuko/env-core": "^1.1.2", "barnard59-env": "^1.2.5", "chai": "^4.3.7" diff --git a/package.json b/package.json index aaee31de..048c2d70 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "mocha": "^10.2.0", "sinon-chai": "^3.7.0", "ts-node": "^10.9.2", - "typescript": "^5.3.2", + "typescript": "^5.4.5", "wsrun": "^5.2.4" }, "lint-staged": { diff --git a/packages/formats/csvw.js b/packages/formats/csvw.js index 330daacf..148ba105 100644 --- a/packages/formats/csvw.js +++ b/packages/formats/csvw.js @@ -3,13 +3,41 @@ import CsvwParser from 'rdf-parser-csvw' import tracer from './lib/tracer.js' import { toDataset } from './lib/stream.js' +/** + * @typedef {{ + * metadata: import('@rdfjs/types').DatasetCore + * timezone?: string + * relaxColumnCount?: boolean + * skipLinesWithError?: boolean + * }} Options + */ + +/** + * @overload + * @param {Options} args + * @return {import('duplexify').Duplexify} + */ + +/** + * @overload + * @param {import('@rdfjs/types').DatasetCore} metadata + * @return {import('duplexify').Duplexify} + */ + +/** + * @this {import('barnard59-core').Context} + * @param {Options | import('@rdfjs/types').DatasetCore} args + */ function parse(args) { + /** + * @type {import('@rdfjs/types').DatasetCore} + */ let metadata let relaxColumnCount = false let skipLinesWithError = false let timezone = 'local' - if (args.metadata) { + if ('metadata' in args) { metadata = args.metadata if (typeof args.relaxColumnCount !== 'undefined') { diff --git a/packages/formats/jsonld.js b/packages/formats/jsonld.js index 3f308490..97d92d87 100644 --- a/packages/formats/jsonld.js +++ b/packages/formats/jsonld.js @@ -6,20 +6,28 @@ import sinkToDuplex from '@rdfjs/sink-to-duplex' import { combine, jsonStringify } from 'barnard59-base' import tracer from './lib/tracer.js' +/** + * @this {import('barnard59-core').Context} + * @param {Object} [options] + * @param {string | Record} [options.localContext] + */ function parse({ localContext } = {}) { - let documentLoader = null + /** + * @type {import('@rdfjs/parser-jsonld').DocumentLoader | undefined} + */ + let documentLoader if (localContext) { if (typeof localContext === 'string') { - localContext = JSON.parse(localContext) + documentLoader = new FsDocumentLoader(JSON.parse(localContext)) + } else { + documentLoader = new FsDocumentLoader(localContext) } - - documentLoader = new FsDocumentLoader(localContext) } return tracer.startActiveSpan('jsonld:parse', span => { const stream = sinkToDuplex(new Parser({ factory: this.env, documentLoader }), { objectMode: true }) - stream.on('error', err => { + stream.on('error', /** @type {any} */ err => { span.recordException(err) span.setStatus({ code: SpanStatusCode.ERROR, message: err.message }) span.end() @@ -29,10 +37,13 @@ function parse({ localContext } = {}) { }) } +/** + * @this {import('barnard59-core').Context} + */ const parseObject = function () { return tracer.startActiveSpan('jsonld:parse.object', span => { const stream = combine([jsonStringify(), parse.call(this)], { objectMode: true }) - stream.on('error', err => { + stream.on('error', (/** @type Error */ err) => { span.recordException(err) span.setStatus({ code: SpanStatusCode.ERROR, message: err.message }) span.end() diff --git a/packages/formats/lib/stream.js b/packages/formats/lib/stream.js index 094793e6..a74d915d 100644 --- a/packages/formats/lib/stream.js +++ b/packages/formats/lib/stream.js @@ -1,5 +1,12 @@ +import { isReadableStream } from 'is-stream' + +/** + * @param {import('@rdfjs/environment/Environment.js').Environment>} rdf + * @param {(import('@rdfjs/types').Stream & import('stream').Readable) | import('@rdfjs/types').DatasetCore} streamOrDataset + * @return {Promise} + */ export function toDataset(rdf, streamOrDataset) { - if (!streamOrDataset.readable) { + if (!isReadableStream(streamOrDataset)) { return Promise.resolve(streamOrDataset) } diff --git a/packages/formats/n3.js b/packages/formats/n3.js index 031cfb1f..6bc72d30 100644 --- a/packages/formats/n3.js +++ b/packages/formats/n3.js @@ -1,6 +1,10 @@ import Parser from '@rdfjs/parser-n3' import sinkToDuplex from '@rdfjs/sink-to-duplex' +/** + * @this {import('barnard59-core').Context} + * @param {import('@rdfjs/parser-n3').ParserOptions} args + */ function parse(args) { return sinkToDuplex(new Parser({ factory: this.env, ...args }), { readableObjectMode: true, diff --git a/packages/formats/package.json b/packages/formats/package.json index d6fa4612..d48d7f43 100644 --- a/packages/formats/package.json +++ b/packages/formats/package.json @@ -5,7 +5,10 @@ "main": "index.js", "type": "module", "scripts": { - "test": "mocha" + "test": "mocha", + "prebuild": "rimraf -g *.d.ts lib/*.d.ts", + "build": "tsc", + "prepack": "npm run build" }, "repository": { "type": "git", @@ -27,11 +30,17 @@ "@rdfjs/serializer-ntriples": "^2.0.0", "@rdfjs/sink-to-duplex": "^1.0.0", "barnard59-base": "^2.0.1", + "is-stream": "^3.0.0", "rdf-parser-csvw": "^0.15.0", "rdf-parser-csvw-xlsx": "^0.1.0", "rdfxml-streaming-parser": "^1.2.0" }, "devDependencies": { + "@types/rdfjs__sink-to-duplex": "^1.0.0", + "@types/rdf-parser-csvw": "^0.15.0", + "@types/rdf-parser-csvw-xlsx": "^0.1.0", + "@types/rdfjs__parser-jsonld": "^2.1.7", + "@types/sax": "^1.2.7", "@zazuko/env-core": "^1.1.2", "barnard59-env": "^1.2.5", "chai": "^4.3.7" @@ -40,6 +49,6 @@ "node": ">= 14.0.0" }, "mocha": { - "loader": "ts-node/esm" + "loader": "ts-node/esm/transpile-only" } } diff --git a/packages/formats/rdf-xml.js b/packages/formats/rdf-xml.js index 361b5b12..aac02a7e 100644 --- a/packages/formats/rdf-xml.js +++ b/packages/formats/rdf-xml.js @@ -1,6 +1,9 @@ import sinkToDuplex from '@rdfjs/sink-to-duplex' import { RdfXmlParser } from 'rdfxml-streaming-parser' +/** + * @this {import('barnard59-core').Context} + */ function parse() { return sinkToDuplex(new RdfXmlParser({ dataFactory: this.env, diff --git a/packages/formats/tsconfig.json b/packages/formats/tsconfig.json new file mode 100644 index 00000000..2f57222f --- /dev/null +++ b/packages/formats/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "emitDeclarationOnly": true + }, + "files": [ + "./index.js" + ] +} diff --git a/packages/formats/xlsx.js b/packages/formats/xlsx.js index 2518b3f9..d69031b8 100644 --- a/packages/formats/xlsx.js +++ b/packages/formats/xlsx.js @@ -3,11 +3,37 @@ import CsvwXlsxParser from 'rdf-parser-csvw-xlsx' import tracer from './lib/tracer.js' import { toDataset } from './lib/stream.js' +/** + * @typedef {{ + * metadata: import('@rdfjs/types').DatasetCore + * timezone?: string + * }} Options + */ + +/** + * @overload + * @param {Options} args + * @return {import('duplexify').Duplexify} + */ + +/** + * @overload + * @param {import('@rdfjs/types').DatasetCore} metadata + * @return {import('duplexify').Duplexify} + */ + +/** + * @this {import('barnard59-core').Context} + * @param {Options | import('@rdfjs/types').DatasetCore} args + */ function parse(args) { + /** + * @type {import('rdf-js').DatasetCore} + */ let metadata let timezone = 'local' - if (args.metadata) { + if ('metadata' in args) { metadata = args.metadata if (typeof args.timezone !== 'undefined') {