@seriousme/openapi-schema-validator
Advanced tools
Comparing version 1.7.1 to 2.0.0
#!/usr/bin/env node | ||
const Validator = require("../index.js"); | ||
import Validator from "../index.js"; | ||
const validator = new Validator(); | ||
const { argv, exit } = require("process"); | ||
import { argv, exit } from "process"; | ||
@@ -7,0 +7,0 @@ const filename = argv[2]; |
@@ -6,2 +6,7 @@ # Changelog | ||
## [v2.0.0] | ||
### Changed 25-04-2022 | ||
- Removed Node 10/12 support from code | ||
- Migrated to ESM, see UPGRADING.md for details | ||
## [v1.7.1] | ||
@@ -8,0 +13,0 @@ ### Changed 22-04-2022 |
import {Options, ErrorObject} from "ajv" | ||
export default class Validator { | ||
export class Validator { | ||
static supportedVersions: Set<string>; | ||
@@ -4,0 +4,0 @@ constructor(ajvOptions?: Options); |
44
index.js
@@ -1,9 +0,8 @@ | ||
const Ajv04 = require("ajv-draft-04"); | ||
const Ajv2020 = require("ajv/dist/2020.js"); | ||
const addFormats = require("ajv-formats"); | ||
const JSYaml = require("js-yaml"); | ||
const util = require("util"); | ||
const fs = require("fs"); | ||
const readFile = util.promisify(fs.readFile); | ||
const { resolve } = require("./resolve.js"); | ||
import Ajv04 from "ajv-draft-04"; | ||
import Ajv2020 from "ajv/dist/2020.js"; | ||
import addFormats from "ajv-formats"; | ||
import { JSON_SCHEMA, load } from "js-yaml"; | ||
import { readFileSync } from "fs"; | ||
import { readFile } from "fs/promises"; | ||
import { resolve } from "./resolve.js"; | ||
@@ -17,2 +16,10 @@ const openApiVersions = new Set(["2.0", "3.0", "3.1"]); | ||
function localFile(fileName) { | ||
return new URL(fileName, import.meta.url).pathname; | ||
} | ||
function importJSON(file) { | ||
return JSON.parse(readFileSync(localFile(file))); | ||
} | ||
function getOpenApiVersion(specification) { | ||
@@ -29,3 +36,3 @@ for (const version of openApiVersions) { | ||
async function getSpecFromData(data) { | ||
const yamlOpts = { schema: JSYaml.JSON_SCHEMA }; | ||
const yamlOpts = { schema: JSON_SCHEMA }; | ||
if (typeof data === "object") { | ||
@@ -37,3 +44,3 @@ return data; | ||
try { | ||
return JSYaml.load(data, yamlOpts); | ||
return load(data, yamlOpts); | ||
} catch (_) { | ||
@@ -45,3 +52,3 @@ return undefined; | ||
const fileData = await readFile(data, "utf-8"); | ||
return JSYaml.load(fileData, yamlOpts); | ||
return load(fileData, yamlOpts); | ||
} catch (_) { | ||
@@ -54,3 +61,3 @@ return undefined; | ||
class Validator { | ||
export class Validator { | ||
constructor(ajvOptions = {}) { | ||
@@ -68,2 +75,4 @@ // AJV is a bit too strict in its strict validation of openAPI schemas | ||
static supportedVersions = openApiVersions; | ||
resolveRefs(opts = {}) { | ||
@@ -78,4 +87,4 @@ return resolve(this.specification || opts.specification); | ||
} | ||
if (uri === undefined){ | ||
if (spec['$id'] === undefined){ | ||
if (uri === undefined) { | ||
if (spec['$id'] === undefined) { | ||
throw new Error("uri parameter or $id attribute must be present"); | ||
@@ -126,3 +135,3 @@ } | ||
if (!this.ajvValidators[version]) { | ||
const schema = require(`./schemas/v${version}/schema.json`); | ||
const schema = importJSON(`./schemas/v${version}/schema.json`); | ||
const schemaVersion = schema.$schema; | ||
@@ -137,5 +146,2 @@ const AjvClass = ajvVersions[schemaVersion]; | ||
} | ||
} | ||
Validator.supportedVersions = openApiVersions; | ||
module.exports = Validator; | ||
} |
{ | ||
"name": "@seriousme/openapi-schema-validator", | ||
"version": "1.7.1", | ||
"version": "2.0.0", | ||
"description": "Validate OpenApi specifications against their JSON schema", | ||
"main": "index.js", | ||
"type": "commonjs", | ||
"type": "module", | ||
"bin": { | ||
@@ -17,4 +17,5 @@ "validate-api": "./bin/validate-api-cli.js" | ||
"scripts": { | ||
"test": "tap test/test-*.js", | ||
"covtest": "tap --coverage-report=html test/test-*.js", | ||
"test": "c8 tap test/test-*.js", | ||
"posttest": "c8 check-coverage --lines 100 --functions 100 --branches 100", | ||
"covtest": "c8 --reporter=lcov npm test", | ||
"cloneOas": "rm -rf OpenAPI-Specification && git clone --branch 'gh-pages' --single-branch https://github.com/OAI/OpenAPI-Specification.git", | ||
@@ -28,6 +29,6 @@ "checkOasVersions": "tap --no-coverage test/check-versions.js", | ||
"postversion": "git push && git push --tags", | ||
"realWorldTest": "node test/realworld/realworld.mjs", | ||
"realWorldTestAll": "node test/realworld/realworld.mjs --all", | ||
"realWorldTestFailed": "node test/realworld/realworld.mjs --failedOnly", | ||
"realWorldTestCI": "node test/realworld/realworld.mjs --ci" | ||
"realWorldTest": "node test/realworld/realworld.js", | ||
"realWorldTestAll": "node test/realworld/realworld.js --all", | ||
"realWorldTestFailed": "node test/realworld/realworld.js --failedOnly", | ||
"realWorldTestCI": "node test/realworld/realworld.js --ci" | ||
}, | ||
@@ -37,2 +38,3 @@ "author": "Hans Klunder", | ||
"devDependencies": { | ||
"c8": "^7.11.2", | ||
"node-fetch": "^3.2.3", | ||
@@ -39,0 +41,0 @@ "tap": "^16.0.1" |
@@ -32,7 +32,7 @@ # OpenAPI schema validator | ||
This module is ESM only, if you need to use commonJS please see below. | ||
```javascript | ||
// ESM | ||
import Validator from "@seriousme/openapi-schema-validator"; | ||
// CommonJS | ||
const Validator = require("@seriousme/openapi-schema-validator"); | ||
import { Validator } from "@seriousme/openapi-schema-validator"; | ||
@@ -56,2 +56,11 @@ console.log(Validator.supportedVersions.has("3.1")); | ||
This module can be used in CommonJS code via: | ||
```javascript | ||
// CommonJS | ||
const { Validator } = await (import("@seriousme/openapi-schema-validator")); | ||
``` | ||
See also the [upgrading guide](UPGRADING.md) if you come from a previous major version. | ||
<a name="CLI"></a> | ||
@@ -58,0 +67,0 @@ |
@@ -10,2 +10,3 @@ function escapeJsonPointer(str) { | ||
const isObject = (obj) => typeof obj === "object" && obj !== null; | ||
const pointerWords = new Set([ | ||
@@ -20,17 +21,13 @@ "$ref", | ||
function fromEntries(iterable) { | ||
return [...iterable].reduce((obj, [key, val]) => { | ||
obj[key] = val; | ||
return obj; | ||
}, {}); | ||
// remove pointerWords from object | ||
function filtered(obj) { | ||
return Object.fromEntries(Object.entries(obj).filter(([key, _]) => !pointerWords.has(key))); | ||
} | ||
const filtered = (raw) => | ||
fromEntries(Object.entries(raw).filter(([key, _]) => !pointerWords.has(key))); | ||
function resolveUri(uri, anchors) { | ||
const [prefix, path] = uri.split("#", 2); | ||
const hashPresent = !!path; | ||
const err = new Error(`Can't resolve ${uri}, only internal refs are supported.`); | ||
if (path && path.length && path[0] !== "/") { | ||
if (hashPresent && (path[0]!=='/')) { | ||
if (anchors[uri]) { | ||
@@ -46,3 +43,3 @@ return anchors[uri]; | ||
if (path === undefined){ | ||
if (!hashPresent){ | ||
return anchors[prefix]; | ||
@@ -68,3 +65,3 @@ } | ||
function resolve(tree) { | ||
export function resolve(tree) { | ||
if (!isObject(tree)) { | ||
@@ -142,4 +139,2 @@ return undefined; | ||
return tree; | ||
} | ||
module.exports = { resolve }; | ||
} |
@@ -1,17 +0,16 @@ | ||
const tap = require("tap"); | ||
const test = tap.test; | ||
import tap from "tap"; | ||
import { URL } from 'url'; | ||
import { readdir } from "fs/promises"; | ||
import { readFileSync } from "fs"; | ||
import { Validator } from "../index.js"; | ||
import { createHash } from "crypto"; | ||
const util = require("util"); | ||
const fs = require("fs"); | ||
const { createHash } = require("crypto"); | ||
const Validator = require("../index.js"); | ||
const readDir = util.promisify(fs.readdir); | ||
const supportedVersions = Validator.supportedVersions; | ||
const openApiDir = `${__dirname}/../schemas.orig`; | ||
function readJSON(file) { | ||
return JSON.parse(fs.readFileSync(file)); | ||
function localPath(path){ | ||
return new URL(path, import.meta.url).pathname; | ||
} | ||
const openApiDir = localPath('../schemas.orig'); | ||
const test = tap.test; | ||
tap.formatSnapshot = (object) => { | ||
@@ -23,4 +22,8 @@ const hash = createHash("sha256"); | ||
function readJSON(file) { | ||
return JSON.parse(readFileSync(file)); | ||
} | ||
async function getOpenApiSchemasVersions(oasdir) { | ||
const dirs = (await readDir(oasdir)).filter((d) => !d.endsWith(".html")); | ||
const dirs = (await readdir(oasdir)).filter((d) => !d.endsWith(".html")); | ||
return dirs; | ||
@@ -32,3 +35,3 @@ } | ||
t.plan(1); | ||
const schemaList = (await readDir(`${openApiDir}/${version}/schema/`)); | ||
const schemaList = (await readdir(`${openApiDir}/${version}/schema/`)); | ||
const lastSchema = schemaList.pop(); | ||
@@ -35,0 +38,0 @@ const schema = readJSON(`${openApiDir}/${version}/schema/${lastSchema}`); |
@@ -1,10 +0,13 @@ | ||
const { Console } = require("console"); | ||
const fs = require("fs"); | ||
const openApiSrcDir = `${__dirname}/../schemas.orig`; | ||
const openApiDestDir = `${__dirname}/../schemas`; | ||
import { readFileSync, readdirSync, writeFileSync } from "fs"; | ||
function localPath(path){ | ||
return new URL(path, import.meta.url).pathname; | ||
} | ||
const openApiSrcDir = localPath('../schemas.orig'); | ||
const openApiDestDir = localPath('../schemas'); | ||
const version = "3.1"; | ||
const destFilePath = `${openApiDestDir}/v${version}/schema.json`; | ||
function readJSON(file) { | ||
return JSON.parse(fs.readFileSync(file)); | ||
function importJSON(file) { | ||
return JSON.parse(readFileSync(file)); | ||
} | ||
@@ -14,5 +17,5 @@ | ||
const srcPath = `${openApiSrcDir}/${version}/schema/` | ||
const schemaList = fs.readdirSync(srcPath); | ||
const schemaList = readdirSync(srcPath); | ||
const lastSchema = schemaList.pop(); | ||
const schema = readJSON(`${srcPath}/${lastSchema}`); | ||
const schema = importJSON(`${srcPath}/${lastSchema}`); | ||
return schema; | ||
@@ -25,6 +28,2 @@ } | ||
function unescapeJsonPointer(str) { | ||
return str.replace(/~1/g, "/").replace(/~0/g, "~"); | ||
} | ||
const isObject = (obj) => typeof obj === "object" && obj !== null; | ||
@@ -70,3 +69,3 @@ | ||
fs.writeFileSync( | ||
writeFileSync( | ||
`${destFilePath}`, | ||
@@ -73,0 +72,0 @@ JSON.stringify(schema, null, 2), |
@@ -58,4 +58,3 @@ function escapeMarkDown(string){ | ||
function createReport(results) { | ||
export function createReport(results) { | ||
return `# Results of real world testing | ||
@@ -83,3 +82,1 @@ Report generated at: ${new Date(Date.parse(results.testDate))} | ||
module.exports = { createReport }; | ||
@@ -1,4 +0,3 @@ | ||
const { test } = require("tap"); | ||
const Validator = require("../index.js"); | ||
import { test } from "tap"; | ||
import { Validator } from "../index.js"; | ||
const validator = new Validator(); | ||
@@ -5,0 +4,0 @@ const resolve = (specification) => validator.resolveRefs({ specification }); |
@@ -1,13 +0,16 @@ | ||
const { test } = require("tap"); | ||
import { test } from "tap"; | ||
import { Validator } from "../index.js"; | ||
import { readFileSync } from "fs"; | ||
import { readFile } from "fs/promises"; | ||
const Validator = require("../index.js"); | ||
function localFile(fileName) { | ||
return new URL(fileName, import.meta.url).pathname; | ||
} | ||
const util = require("util"); | ||
const fs = require("fs"); | ||
const readFile = util.promisify(fs.readFile); | ||
function importJSON(file) { | ||
return JSON.parse(readFileSync(localFile(file))); | ||
} | ||
const localFile = (fileName) => | ||
new URL(fileName, `file://${__dirname}/`).pathname; | ||
const emptySpec = require(`./validation/empty.json`); | ||
const invalidSpec = require(`./validation/invalid-spec.json`); | ||
const emptySpec = importJSON(`./validation/empty.json`); | ||
const invalidSpec = importJSON(`./validation/invalid-spec.json`); | ||
const yamlFileName = localFile(`./validation/petstore-openapi.v3.yaml`); | ||
@@ -24,3 +27,3 @@ const mainSpecYamlFileName = localFile(`./validation/main-spec.v3.yaml`); | ||
t.plan(2); | ||
const petStoreSpec = require(`./v${version}/petstore.json`); | ||
const petStoreSpec = importJSON(`./v${version}/petstore.json`); | ||
const validator = new Validator(); | ||
@@ -128,3 +131,3 @@ | ||
const validator = new Validator(); | ||
const petStoreSpec = require(`./validation/petstore-swagger.v2.json`); | ||
const petStoreSpec = importJSON(`./validation/petstore-swagger.v2.json`); | ||
const res = await validator.validate(petStoreSpec); | ||
@@ -149,6 +152,6 @@ t.equal(res.valid, true, "original petstore spec is valid"); | ||
let logcount = 0; | ||
const log = warn = error = () => logcount++; | ||
const logger = { log, warn, error }; | ||
const log = () => logcount++; | ||
const logger = { log, warn: log, error: log }; | ||
const validator = new Validator({ strict: "log", logger }); | ||
const petStoreSpec = require(`./validation/petstore-swagger.v2.json`); | ||
const petStoreSpec = importJSON(`./validation/petstore-swagger.v2.json`); | ||
const res = await validator.validate(petStoreSpec); | ||
@@ -155,0 +158,0 @@ t.equal(res.valid, true, "original petstore spec is valid"); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
376158
41
9677
238
9
Yes
3