diff --git a/package-lock.json b/package-lock.json index 61fcac0369..78b27c881b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,13 +16,28 @@ "yargs": "^18.0.0" }, "devDependencies": { - "@hyperjump/json-schema": "^1.16.1", + "@hyperjump/json-schema-coverage": "^1.1.0", + "@vitest/coverage-v8": "^3.2.4", "c8": "^10.1.3", "markdownlint-cli2": "^0.18.1", "vitest": "^3.2.4", "yaml": "^2.8.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -37,6 +52,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", @@ -46,6 +71,36 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@bcoe/v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", @@ -482,12 +537,11 @@ } }, "node_modules/@hyperjump/browser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@hyperjump/browser/-/browser-1.3.0.tgz", - "integrity": "sha512-bf2ZTqpjfvcEq3DAZSg1h0FuliNUddR6nDPuaPb9qNoPPBQQzD1ldtuXX0QggXKQZl0OgsI3eovGCR3Dl5kToA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@hyperjump/browser/-/browser-1.3.1.tgz", + "integrity": "sha512-Le5XZUjnVqVjkgLYv6yyWgALat/0HpB1XaCPuCZ+GCFki9NvXloSZITIJ0H+wRW7mb9At1SxvohKBbNQbrr/cw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@hyperjump/json-pointer": "^1.1.0", "@hyperjump/uri": "^1.2.0", @@ -536,6 +590,47 @@ "@hyperjump/browser": "^1.1.0" } }, + "node_modules/@hyperjump/json-schema-coverage": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@hyperjump/json-schema-coverage/-/json-schema-coverage-1.1.0.tgz", + "integrity": "sha512-E9pwHoalb1enSVMR14iM7x0gIqdG0DzpFVHDfYGOi08DMpbhfj5q59Q5V9X8Z2PlrPn/r74ufvxkbkAOEH5djQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hyperjump/browser": "^1.3.1", + "@hyperjump/json-schema": "^1.16.0", + "@hyperjump/uri": "^1.3.1", + "content-type": "^1.0.5", + "ignore": "^7.0.5", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.7", + "moo": "^0.5.2", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "tinyglobby": "^0.2.14", + "vfile": "^6.0.3", + "yaml": "^2.8.0", + "yaml-unist-parser": "^2.0.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jdesrosiers" + } + }, + "node_modules/@hyperjump/json-schema-coverage/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@hyperjump/pact": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@hyperjump/pact/-/pact-1.4.0.tgz", @@ -586,6 +681,17 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -1170,6 +1276,40 @@ "@types/node": "*" } }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", @@ -1346,6 +1486,25 @@ "node": ">=4" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz", + "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/b4a": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", @@ -2686,9 +2845,9 @@ } }, "node_modules/ignore": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz", - "integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { @@ -2858,6 +3017,21 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", @@ -3016,6 +3190,18 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -3741,6 +3927,13 @@ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "license": "MIT" }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -4941,6 +5134,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -4970,6 +5184,50 @@ "node": ">=10.12.0" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/vfile/node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -5383,6 +5641,29 @@ "node": ">= 14.6" } }, + "node_modules/yaml-unist-parser": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/yaml-unist-parser/-/yaml-unist-parser-2.0.5.tgz", + "integrity": "sha512-CirHjIkYcQxbG9wgYmzjJlMaBFuj788zLOgT0A2FAzdsw2dD4vnq4cx+kij/fXImG09ARnlODtS38JM1EottOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-unist-parser/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", diff --git a/package.json b/package.json index 1e9d0cfc5c..016c26a213 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "build": "bash ./scripts/md2html/build.sh", "build-src": "npm run validate-markdown && bash ./scripts/md2html/build.sh src && bash ./scripts/schema-publish.sh src", - "test": "c8 --100 vitest --watch=false && bash scripts/schema-test-coverage.sh", + "test": "c8 --100 vitest run --coverage", "format-markdown": "npx markdownlint-cli2 --config spec.markdownlint.yaml --fix src/oas.md && npx markdownlint-cli2 --fix *.md", "validate-markdown": "npx markdownlint-cli2 --config spec.markdownlint.yaml src/oas.md && npx markdownlint-cli2 *.md" }, @@ -27,7 +27,8 @@ "yargs": "^18.0.0" }, "devDependencies": { - "@hyperjump/json-schema": "^1.16.1", + "@hyperjump/json-schema-coverage": "^1.1.0", + "@vitest/coverage-v8": "^3.2.4", "c8": "^10.1.3", "markdownlint-cli2": "^0.18.1", "vitest": "^3.2.4", diff --git a/scripts/adjust-release-branch.sh b/scripts/adjust-release-branch.sh index bbf0288602..15a5de8a82 100755 --- a/scripts/adjust-release-branch.sh +++ b/scripts/adjust-release-branch.sh @@ -17,5 +17,6 @@ echo Prepare release of $version cp EDITORS.md versions/$version-editors.md mv src/oas.md versions/$version.md -rm -r src/schemas -rm -r tests/schema +rm -r src +rm -r tests/schema/pass tests/schema/fail +rm tests/schema/schema.test.mjs diff --git a/scripts/schema-test-coverage.mjs b/scripts/schema-test-coverage.mjs deleted file mode 100644 index 5ebaad8d22..0000000000 --- a/scripts/schema-test-coverage.mjs +++ /dev/null @@ -1,161 +0,0 @@ -import { readFileSync } from "node:fs"; -import { readdir, readFile } from "node:fs/promises"; -import YAML from "yaml"; -import { join } from "node:path"; -import { argv } from "node:process"; -import { registerSchema, validate } from "@hyperjump/json-schema/openapi-3-1"; -import "@hyperjump/json-schema/draft-04"; -import { BASIC, defineVocabulary } from "@hyperjump/json-schema/experimental"; - -/** - * @import { EvaluationPlugin } from "@hyperjump/json-schema/experimental" - * @import { Json } from "@hyperjump/json-pointer" - */ - -import contentTypeParser from "content-type"; -import { addMediaTypePlugin } from "@hyperjump/browser"; -import { buildSchemaDocument } from "@hyperjump/json-schema/experimental"; - -addMediaTypePlugin("application/schema+yaml", { - parse: async (response) => { - const contentType = contentTypeParser.parse( - response.headers.get("content-type") ?? "", - ); - const contextDialectId = - contentType.parameters.schema ?? contentType.parameters.profile; - - const foo = YAML.parse(await response.text()); - return buildSchemaDocument(foo, response.url, contextDialectId); - }, - fileMatcher: (path) => path.endsWith(".yaml"), -}); - -/** @implements EvaluationPlugin */ -class TestCoveragePlugin { - constructor() { - /** @type Set */ - this.visitedLocations = new Set(); - } - - beforeSchema(_schemaUri, _instance, context) { - if (this.allLocations) { - return; - } - - /** @type Set */ - this.allLocations = []; - - for (const schemaLocation in context.ast) { - if ( - schemaLocation === "metaData" || - // Do not require coverage of standard JSON Schema - schemaLocation.includes("json-schema.org") || - // Do not require coverage of default $dynamicAnchor - // schemas, as they are not expected to be reached - schemaLocation.endsWith("/schema/WORK-IN-PROGRESS#/$defs/schema") - ) { - continue; - } - - if (Array.isArray(context.ast[schemaLocation])) { - for (const keyword of context.ast[schemaLocation]) { - if (Array.isArray(keyword)) { - this.allLocations.push(keyword[1]); - } - } - } - } - } - - beforeKeyword([, schemaUri]) { - this.visitedLocations.add(schemaUri); - } -} - -/** @type (testDirectory: string) => AsyncGenerator<[string,Json]> */ -const tests = async function* (testDirectory) { - for (const file of await readdir(testDirectory, { - recursive: true, - withFileTypes: true, - })) { - if (!file.isFile() || !file.name.endsWith(".yaml")) { - continue; - } - - const testPath = join(file.parentPath, file.name); - const testJson = await readFile(testPath, "utf8"); - - yield [testPath, YAML.parse(testJson)]; - } -}; - -/** - * @typedef {{ - * allLocations: string[]; - * visitedLocations: Set; - * }} Coverage - */ - -/** @type (schemaUri: string, testDirectory: string) => Promise */ -const runTests = async (schemaUri, testDirectory) => { - const testCoveragePlugin = new TestCoveragePlugin(); - const validateOpenApi = await validate(schemaUri); - - for await (const [name, test] of tests(testDirectory)) { - const result = validateOpenApi(test, { - outputFormat: BASIC, - plugins: [testCoveragePlugin], - }); - - if (!result.valid) { - console.log("Failed:", name, result.errors); - } - } - - return { - allLocations: testCoveragePlugin.allLocations ?? new Set(), - visitedLocations: testCoveragePlugin.visitedLocations - }; -}; - -const parseYamlFromFile = (filePath) => { - const schemaYaml = readFileSync(filePath, "utf8"); - return YAML.parse(schemaYaml, { prettyErrors: true }); -}; - -const meta = parseYamlFromFile("./src/schemas/validation/meta.yaml"); -const oasBaseVocab = Object.keys(meta.$vocabulary)[0]; - -defineVocabulary(oasBaseVocab, { - "discriminator": "https://spec.openapis.org/oas/3.0/keyword/discriminator", - "example": "https://spec.openapis.org/oas/3.0/keyword/example", - "externalDocs": "https://spec.openapis.org/oas/3.0/keyword/externalDocs", - "xml": "https://spec.openapis.org/oas/3.0/keyword/xml" -}); - -registerSchema(meta); -registerSchema(parseYamlFromFile("./src/schemas/validation/dialect.yaml")); -registerSchema(parseYamlFromFile("./src/schemas/validation/schema.yaml")); - -/////////////////////////////////////////////////////////////////////////////// - -const { allLocations, visitedLocations } = await runTests(argv[2], argv[3]); -const notCovered = allLocations.filter( - (location) => !visitedLocations.has(location), -); -if (notCovered.length > 0) { - console.log("NOT Covered:", notCovered.length, "of", allLocations.length); - const maxNotCovered = 20; - const firstNotCovered = notCovered.slice(0, maxNotCovered); - if (notCovered.length > maxNotCovered) firstNotCovered.push("..."); - console.log(firstNotCovered); - process.exitCode = 1; -} - -console.log( - "Covered:", - (allLocations.length - notCovered.length), - "of", - allLocations.length, - "(" + Math.floor(((allLocations.length - notCovered.length) / allLocations.length) * 100) + "%)", -); diff --git a/scripts/schema-test-coverage.sh b/scripts/schema-test-coverage.sh deleted file mode 100755 index 600199b907..0000000000 --- a/scripts/schema-test-coverage.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -# Author: @ralfhandl - -# Run this script from the root of the repo - -[[ ! -e src/schemas ]] && exit 0 - -echo -echo "Schema Test Coverage" -echo - -node scripts/schema-test-coverage.mjs src/schemas/validation/schema-base.yaml tests/schema/pass -rc=$? - -[[ "$BASE" == "dev" ]] || exit $rc diff --git a/tests/schema/oas-schema.mjs b/tests/schema/oas-schema.mjs new file mode 100644 index 0000000000..720d3879f4 --- /dev/null +++ b/tests/schema/oas-schema.mjs @@ -0,0 +1,27 @@ +import { registerSchema } from "@hyperjump/json-schema/draft-2020-12"; +import { defineVocabulary } from "@hyperjump/json-schema/experimental"; +import { readFile } from "node:fs/promises"; +import YAML from "yaml"; + +const parseYamlFromFile = async (filePath) => { + const schemaYaml = await readFile(filePath, "utf8"); + return YAML.parse(schemaYaml, { prettyErrors: true }); +}; + +export default async () => { + try { + const dialect = await parseYamlFromFile("./src/schemas/validation/dialect.yaml"); + const meta = await parseYamlFromFile("./src/schemas/validation/meta.yaml"); + const oasBaseVocab = Object.keys(meta.$vocabulary)[0]; + + defineVocabulary(oasBaseVocab, { + "discriminator": "https://spec.openapis.org/oas/3.0/keyword/discriminator", + "example": "https://spec.openapis.org/oas/3.0/keyword/example", + "externalDocs": "https://spec.openapis.org/oas/3.0/keyword/externalDocs", + "xml": "https://spec.openapis.org/oas/3.0/keyword/xml" + }); + + registerSchema(meta); + registerSchema(dialect); + } catch (error) {} +}; diff --git a/vitest.config.mjs b/vitest.config.mjs index 4268028a0d..f5c7665b70 100644 --- a/vitest.config.mjs +++ b/vitest.config.mjs @@ -1,8 +1,17 @@ import { defineConfig } from 'vitest/config' +import { jsonSchemaCoveragePlugin } from "@hyperjump/json-schema-coverage/vitest" export default defineConfig({ + plugins: [jsonSchemaCoveragePlugin()], test: { + globalSetup: ["tests/schema/oas-schema.mjs"], + coverage: { + include: ["src/schemas/validation/**/*.yaml"], + thresholds: process.env.BASE !== "dev" ? { + 100: true + } : {} + }, forceRerunTriggers: ['**/scripts/**', '**/tests/**'], testTimeout: 10000, // 10 seconds }, -}) \ No newline at end of file +})