diff --git a/.github/workflows/validate-examples.yaml b/.github/workflows/validate-examples.yaml new file mode 100644 index 0000000000..dc13c37ffb --- /dev/null +++ b/.github/workflows/validate-examples.yaml @@ -0,0 +1,27 @@ +name: validate-examples + +# Author: @MikeRalphson +# Issue: https://github.com/OAI/OpenAPI-Specification/issues/1739 + +# +# This workflow validates files in the examples/v2 and /v3 directories +# + +# run this on push to any branch and creation of pull-requests +on: [push, pull_request] + +jobs: + validate-examples: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 # checkout repo content + - uses: actions/setup-node@v1 # setup Node.js + with: + node-version: '12.x' + - name: Install dependencies + run: npm i + - name: Validate examples + run: node scripts/validateExamples/index.js + diff --git a/.github/workflows/validate-schemas.yaml b/.github/workflows/validate-schemas.yaml new file mode 100644 index 0000000000..f89490c214 --- /dev/null +++ b/.github/workflows/validate-schemas.yaml @@ -0,0 +1,31 @@ +name: validate-schemas + +# Author: @MikeRalphson +# Issue: https://github.com/OAI/OpenAPI-Specification/issues/1739 + +# +# This workflow validates files in the schemas directory against their +# appropriate meta-schemas +# + +# run this on push to any branch and creation of pull-requests +on: [push, pull_request] + +jobs: + mdv: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 # checkout repo content + - uses: actions/setup-node@v1 # setup Node.js + with: + node-version: '12.x' + - name: Install dependencies + run: npm i + - name: Validate schemas + run: | + node scripts/validateSchema/index.js schemas/v1.2/apiDeclaration.json schemas/jsonSchema/draft-04/metaschema.json + node scripts/validateSchema/index.js schemas/v2.0/schema.json schemas/jsonSchema/draft-04/metaschema.json + node scripts/validateSchema/index.js schemas/v3.0/schema.yaml schemas/jsonSchema/draft-04/metaschema.json + diff --git a/package.json b/package.json index 2b7d19e525..36416c42b6 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,10 @@ ], "dependencies": {}, "devDependencies": { - "mdv": "^1.0.7" + "jsonschema": "^1.2.4", + "mdv": "^1.0.7", + "node-readfiles": "^0.2.0", + "yaml": "^1.7.2" }, "keywords": [ "OpenAPI", diff --git a/schemas/jsonSchema/draft-04/metaschema.json b/schemas/jsonSchema/draft-04/metaschema.json new file mode 100644 index 0000000000..bcbb84743e --- /dev/null +++ b/schemas/jsonSchema/draft-04/metaschema.json @@ -0,0 +1,149 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/scripts/validateExamples/index.js b/scripts/validateExamples/index.js new file mode 100644 index 0000000000..bee923dab5 --- /dev/null +++ b/scripts/validateExamples/index.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const util = require('util'); + +const yaml = require('yaml'); +const rf = require('node-readfiles'); +const jsonschema = require('jsonschema').Validator; +const options = { }; +const validator = new jsonschema(options); + +const schema = {}; +schema["v2.0"] = yaml.parse(fs.readFileSync('./schemas/v2.0/schema.json','utf8')); +schema.draft4 = yaml.parse(fs.readFileSync('./schemas/jsonSchema/draft-04/metaschema.json','utf8')); +schema["v3.0"] = yaml.parse(fs.readFileSync('./schemas/v3.0/schema.yaml','utf8')); + +validator.addSchema(schema.draft4); + +async function main(path,schema,propName) { + return new Promise(async function(resolve,reject){ + let files = await rf(path, { readContents: false, filenameFormat: rf.FULL_PATH }); + files = files.sort(); + for (let file of files) { + const contentStr = fs.readFileSync(file,'utf8'); + let contentObj; + try { + contentObj = yaml.parse(contentStr,{prettyErrors:true}); + } + catch (ex) { + process.exitCode = 1; + console.warn(file,ex.message); + } + if (contentObj && contentObj[propName]) { + console.log('Validating',file); + try { + const result = await validator.validate(contentObj,schema); + if (result.errors && result.errors.length) { + process.exitCode = 1; + console.warn(file,util.inspect(result.errors)); + } + } + catch (ex) { + process.exitCode = 1; + console.warn(file,ex.message); + } + } + } + resolve(files); + }); +} + +async function validateExamples(){ + await main('./examples/v2.0/',schema["v2.0"],'swagger'); + await main('./examples/v3.0/',schema["v3.0"],'openapi'); +} + +validateExamples(); diff --git a/scripts/validateSchema/index.js b/scripts/validateSchema/index.js new file mode 100644 index 0000000000..391223223e --- /dev/null +++ b/scripts/validateSchema/index.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node +'use strict'; + +const fs = require('fs'); +const util = require('util'); + +const yaml = require('yaml'); +const jsonschema = require('jsonschema').Validator; +const options = { base: process.argv[2] }; +const validator = new jsonschema(options); + +const schema = yaml.parse(fs.readFileSync(process.argv[2],'utf8')); +const metaSchema = yaml.parse(fs.readFileSync(process.argv[3],'utf8')); + +console.log('Checking',process.argv[2]); + +const result = validator.validate(schema, metaSchema); + +if (result.errors.length) { + console.warn(util.inspect(result.errors)); + process.exit(1); +} +else { + console.log('OK'); +} +