From ec60131eddf6f51ed0c737fdcd28616ae1a0e564 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 17 Jun 2024 19:58:52 -0700 Subject: [PATCH] feat: support draft-2020-12 (#15) --- __tests__/main.test.ts | 32 +++++++ dist/index.js | 201 ++++++++++++++++++++++++++++++++++++++++- src/main.ts | 21 +++-- 3 files changed, 246 insertions(+), 8 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 811d3a3..a9da4cc 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -524,6 +524,38 @@ describe('action', () => { expect(core.setOutput).toHaveBeenLastCalledWith('valid', true); }); + it('using JSON Schema draft-2019-09', async () => { + vi.mocked(fs.readFile).mockResolvedValueOnce( + schemaContents.replace( + 'http://json-schema.org/draft-07/schema#', + 'https://json-schema.org/draft/2019-09/schema' + ) + ); + + await main.run(); + expect(runSpy).toHaveReturned(); + expect(process.exitCode).not.toBeDefined(); + + expect(core.setOutput).toHaveBeenCalledTimes(1); + expect(core.setOutput).toHaveBeenLastCalledWith('valid', true); + }); + + it('using JSON Schema draft-2020-12', async () => { + vi.mocked(fs.readFile).mockResolvedValueOnce( + schemaContents.replace( + 'http://json-schema.org/draft-07/schema#', + 'https://json-schema.org/draft/2020-12/schema' + ) + ); + + await main.run(); + expect(runSpy).toHaveReturned(); + expect(process.exitCode).not.toBeDefined(); + + expect(core.setOutput).toHaveBeenCalledTimes(1); + expect(core.setOutput).toHaveBeenLastCalledWith('valid', true); + }); + it('but fails if $schema key is missing', async () => { vi.mocked(fs.readFile).mockResolvedValueOnce( schemaContents.replace('$schema', '_schema') diff --git a/dist/index.js b/dist/index.js index 0d288a6..4f48b25 100644 --- a/dist/index.js +++ b/dist/index.js @@ -45811,6 +45811,66 @@ Object.defineProperty(exports, "MissingRefError", ({ enumerable: true, get: func /***/ }), +/***/ 6121: +/***/ ((module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MissingRefError = exports.ValidationError = exports.CodeGen = exports.Name = exports.nil = exports.stringify = exports.str = exports._ = exports.KeywordCxt = void 0; +const core_1 = __nccwpck_require__(2685); +const draft2020_1 = __nccwpck_require__(6098); +const discriminator_1 = __nccwpck_require__(4025); +const json_schema_2020_12_1 = __nccwpck_require__(9246); +const META_SCHEMA_ID = "https://json-schema.org/draft/2020-12/schema"; +class Ajv2020 extends core_1.default { + constructor(opts = {}) { + super({ + ...opts, + dynamicRef: true, + next: true, + unevaluated: true, + }); + } + _addVocabularies() { + super._addVocabularies(); + draft2020_1.default.forEach((v) => this.addVocabulary(v)); + if (this.opts.discriminator) + this.addKeyword(discriminator_1.default); + } + _addDefaultMetaSchema() { + super._addDefaultMetaSchema(); + const { $data, meta } = this.opts; + if (!meta) + return; + json_schema_2020_12_1.default.call(this, $data); + this.refs["http://json-schema.org/schema"] = META_SCHEMA_ID; + } + defaultMeta() { + return (this.opts.defaultMeta = + super.defaultMeta() || (this.getSchema(META_SCHEMA_ID) ? META_SCHEMA_ID : undefined)); + } +} +module.exports = exports = Ajv2020; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports["default"] = Ajv2020; +var validate_1 = __nccwpck_require__(8955); +Object.defineProperty(exports, "KeywordCxt", ({ enumerable: true, get: function () { return validate_1.KeywordCxt; } })); +var codegen_1 = __nccwpck_require__(9179); +Object.defineProperty(exports, "_", ({ enumerable: true, get: function () { return codegen_1._; } })); +Object.defineProperty(exports, "str", ({ enumerable: true, get: function () { return codegen_1.str; } })); +Object.defineProperty(exports, "stringify", ({ enumerable: true, get: function () { return codegen_1.stringify; } })); +Object.defineProperty(exports, "nil", ({ enumerable: true, get: function () { return codegen_1.nil; } })); +Object.defineProperty(exports, "Name", ({ enumerable: true, get: function () { return codegen_1.Name; } })); +Object.defineProperty(exports, "CodeGen", ({ enumerable: true, get: function () { return codegen_1.CodeGen; } })); +var validation_error_1 = __nccwpck_require__(7616); +Object.defineProperty(exports, "ValidationError", ({ enumerable: true, get: function () { return validation_error_1.default; } })); +var ref_error_1 = __nccwpck_require__(8190); +Object.defineProperty(exports, "MissingRefError", ({ enumerable: true, get: function () { return ref_error_1.default; } })); +//# sourceMappingURL=2020.js.map + +/***/ }), + /***/ 2426: /***/ ((module, exports, __nccwpck_require__) => { @@ -49434,6 +49494,43 @@ exports["default"] = addMetaSchema2019; /***/ }), +/***/ 9246: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +const metaSchema = __nccwpck_require__(2577); +const applicator = __nccwpck_require__(996); +const unevaluated = __nccwpck_require__(5568); +const content = __nccwpck_require__(6795); +const core = __nccwpck_require__(235); +const format = __nccwpck_require__(2567); +const metadata = __nccwpck_require__(1233); +const validation = __nccwpck_require__(1968); +const META_SUPPORT_DATA = ["/properties"]; +function addMetaSchema2020($data) { + ; + [ + metaSchema, + applicator, + unevaluated, + content, + core, + with$data(this, format), + metadata, + with$data(this, validation), + ].forEach((sch) => this.addMetaSchema(sch, undefined, false)); + return this; + function with$data(ajv, sch) { + return $data ? ajv.$dataMetaSchema(sch, META_SUPPORT_DATA) : sch; + } +} +exports["default"] = addMetaSchema2020; +//# sourceMappingURL=index.js.map + +/***/ }), + /***/ 3809: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -50917,6 +51014,36 @@ var DiscrError; /***/ }), +/***/ 6098: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +const core_1 = __nccwpck_require__(3707); +const validation_1 = __nccwpck_require__(9805); +const applicator_1 = __nccwpck_require__(3048); +const dynamic_1 = __nccwpck_require__(9774); +const next_1 = __nccwpck_require__(6405); +const unevaluated_1 = __nccwpck_require__(3357); +const format_1 = __nccwpck_require__(9841); +const metadata_1 = __nccwpck_require__(5799); +const draft2020Vocabularies = [ + dynamic_1.default, + core_1.default, + validation_1.default, + (0, applicator_1.default)(true), + format_1.default, + metadata_1.metadataVocabulary, + metadata_1.contentVocabulary, + next_1.default, + unevaluated_1.default, +]; +exports["default"] = draft2020Vocabularies; +//# sourceMappingURL=draft2020.js.map + +/***/ }), + /***/ 691: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -89837,13 +89964,19 @@ const core = __importStar(__nccwpck_require__(2186)); const glob = __importStar(__nccwpck_require__(8090)); const http = __importStar(__nccwpck_require__(6255)); const _2019_1 = __importDefault(__nccwpck_require__(5988)); +const _2020_1 = __importDefault(__nccwpck_require__(6121)); const ajv_draft_04_1 = __importDefault(__nccwpck_require__(7023)); const ajv_formats_1 = __importDefault(__nccwpck_require__(567)); const yaml = __importStar(__nccwpck_require__(4083)); function newAjv(schema) { const draft04Schema = schema.$schema === 'http://json-schema.org/draft-04/schema#'; - const ajv = (0, ajv_formats_1.default)(draft04Schema ? new ajv_draft_04_1.default() : new _2019_1.default()); - if (!draft04Schema) { + const draft2020Schema = schema.$schema === 'https://json-schema.org/draft/2020-12/schema'; + const ajv = (0, ajv_formats_1.default)(draft04Schema + ? new ajv_draft_04_1.default() + : draft2020Schema + ? new _2020_1.default() + : new _2019_1.default()); + if (!draft04Schema && !draft2020Schema) { /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ ajv.addMetaSchema(__nccwpck_require__(18)); ajv.addMetaSchema(__nccwpck_require__(98)); @@ -100373,6 +100506,70 @@ module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2019-09/s /***/ }), +/***/ 996: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/applicator","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/applicator":true},"$dynamicAnchor":"meta","title":"Applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"prefixItems":{"$ref":"#/$defs/schemaArray"},"items":{"$dynamicRef":"#meta"},"contains":{"$dynamicRef":"#meta"},"additionalProperties":{"$dynamicRef":"#meta"},"properties":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"default":{}},"patternProperties":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"propertyNames":{"format":"regex"},"default":{}},"dependentSchemas":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"},"default":{}},"propertyNames":{"$dynamicRef":"#meta"},"if":{"$dynamicRef":"#meta"},"then":{"$dynamicRef":"#meta"},"else":{"$dynamicRef":"#meta"},"allOf":{"$ref":"#/$defs/schemaArray"},"anyOf":{"$ref":"#/$defs/schemaArray"},"oneOf":{"$ref":"#/$defs/schemaArray"},"not":{"$dynamicRef":"#meta"}},"$defs":{"schemaArray":{"type":"array","minItems":1,"items":{"$dynamicRef":"#meta"}}}}'); + +/***/ }), + +/***/ 6795: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/content","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/content":true},"$dynamicAnchor":"meta","title":"Content vocabulary meta-schema","type":["object","boolean"],"properties":{"contentEncoding":{"type":"string"},"contentMediaType":{"type":"string"},"contentSchema":{"$dynamicRef":"#meta"}}}'); + +/***/ }), + +/***/ 235: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/core","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/core":true},"$dynamicAnchor":"meta","title":"Core vocabulary meta-schema","type":["object","boolean"],"properties":{"$id":{"$ref":"#/$defs/uriReferenceString","$comment":"Non-empty fragments not allowed.","pattern":"^[^#]*#?$"},"$schema":{"$ref":"#/$defs/uriString"},"$ref":{"$ref":"#/$defs/uriReferenceString"},"$anchor":{"$ref":"#/$defs/anchorString"},"$dynamicRef":{"$ref":"#/$defs/uriReferenceString"},"$dynamicAnchor":{"$ref":"#/$defs/anchorString"},"$vocabulary":{"type":"object","propertyNames":{"$ref":"#/$defs/uriString"},"additionalProperties":{"type":"boolean"}},"$comment":{"type":"string"},"$defs":{"type":"object","additionalProperties":{"$dynamicRef":"#meta"}}},"$defs":{"anchorString":{"type":"string","pattern":"^[A-Za-z_][-A-Za-z0-9._]*$"},"uriString":{"type":"string","format":"uri"},"uriReferenceString":{"type":"string","format":"uri-reference"}}}'); + +/***/ }), + +/***/ 2567: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/format-annotation","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/format-annotation":true},"$dynamicAnchor":"meta","title":"Format vocabulary meta-schema for annotation results","type":["object","boolean"],"properties":{"format":{"type":"string"}}}'); + +/***/ }), + +/***/ 1233: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/meta-data","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/meta-data":true},"$dynamicAnchor":"meta","title":"Meta-data vocabulary meta-schema","type":["object","boolean"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"default":true,"deprecated":{"type":"boolean","default":false},"readOnly":{"type":"boolean","default":false},"writeOnly":{"type":"boolean","default":false},"examples":{"type":"array","items":true}}}'); + +/***/ }), + +/***/ 5568: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/unevaluated","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/unevaluated":true},"$dynamicAnchor":"meta","title":"Unevaluated applicator vocabulary meta-schema","type":["object","boolean"],"properties":{"unevaluatedItems":{"$dynamicRef":"#meta"},"unevaluatedProperties":{"$dynamicRef":"#meta"}}}'); + +/***/ }), + +/***/ 1968: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/meta/validation","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/validation":true},"$dynamicAnchor":"meta","title":"Validation vocabulary meta-schema","type":["object","boolean"],"properties":{"type":{"anyOf":[{"$ref":"#/$defs/simpleTypes"},{"type":"array","items":{"$ref":"#/$defs/simpleTypes"},"minItems":1,"uniqueItems":true}]},"const":true,"enum":{"type":"array","items":true},"multipleOf":{"type":"number","exclusiveMinimum":0},"maximum":{"type":"number"},"exclusiveMaximum":{"type":"number"},"minimum":{"type":"number"},"exclusiveMinimum":{"type":"number"},"maxLength":{"$ref":"#/$defs/nonNegativeInteger"},"minLength":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"pattern":{"type":"string","format":"regex"},"maxItems":{"$ref":"#/$defs/nonNegativeInteger"},"minItems":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"uniqueItems":{"type":"boolean","default":false},"maxContains":{"$ref":"#/$defs/nonNegativeInteger"},"minContains":{"$ref":"#/$defs/nonNegativeInteger","default":1},"maxProperties":{"$ref":"#/$defs/nonNegativeInteger"},"minProperties":{"$ref":"#/$defs/nonNegativeIntegerDefault0"},"required":{"$ref":"#/$defs/stringArray"},"dependentRequired":{"type":"object","additionalProperties":{"$ref":"#/$defs/stringArray"}}},"$defs":{"nonNegativeInteger":{"type":"integer","minimum":0},"nonNegativeIntegerDefault0":{"$ref":"#/$defs/nonNegativeInteger","default":0},"simpleTypes":{"enum":["array","boolean","integer","null","number","object","string"]},"stringArray":{"type":"array","items":{"type":"string"},"uniqueItems":true,"default":[]}}}'); + +/***/ }), + +/***/ 2577: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://json-schema.org/draft/2020-12/schema","$vocabulary":{"https://json-schema.org/draft/2020-12/vocab/core":true,"https://json-schema.org/draft/2020-12/vocab/applicator":true,"https://json-schema.org/draft/2020-12/vocab/unevaluated":true,"https://json-schema.org/draft/2020-12/vocab/validation":true,"https://json-schema.org/draft/2020-12/vocab/meta-data":true,"https://json-schema.org/draft/2020-12/vocab/format-annotation":true,"https://json-schema.org/draft/2020-12/vocab/content":true},"$dynamicAnchor":"meta","title":"Core and Validation specifications meta-schema","allOf":[{"$ref":"meta/core"},{"$ref":"meta/applicator"},{"$ref":"meta/unevaluated"},{"$ref":"meta/validation"},{"$ref":"meta/meta-data"},{"$ref":"meta/format-annotation"},{"$ref":"meta/content"}],"type":["object","boolean"],"$comment":"This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.","properties":{"definitions":{"$comment":"\\"definitions\\" has been replaced by \\"$defs\\".","type":"object","additionalProperties":{"$dynamicRef":"#meta"},"deprecated":true,"default":{}},"dependencies":{"$comment":"\\"dependencies\\" has been split and replaced by \\"dependentSchemas\\" and \\"dependentRequired\\" in order to serve their differing semantics.","type":"object","additionalProperties":{"anyOf":[{"$dynamicRef":"#meta"},{"$ref":"meta/validation#/$defs/stringArray"}]},"deprecated":true,"default":{}},"$recursiveAnchor":{"$comment":"\\"$recursiveAnchor\\" has been replaced by \\"$dynamicAnchor\\".","$ref":"meta/core#/$defs/anchorString","deprecated":true},"$recursiveRef":{"$comment":"\\"$recursiveRef\\" has been replaced by \\"$dynamicRef\\".","$ref":"meta/core#/$defs/uriReferenceString","deprecated":true}}}'); + +/***/ }), + /***/ 18: /***/ ((module) => { diff --git a/src/main.ts b/src/main.ts index 94a0b8a..0228c99 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,8 +7,9 @@ import * as core from '@actions/core'; import * as glob from '@actions/glob'; import * as http from '@actions/http-client'; -import type { default as Ajv } from 'ajv'; -import { default as Ajv2019, ErrorObject } from 'ajv/dist/2019'; +import type { default as Ajv, ErrorObject } from 'ajv'; +import { default as Ajv2019 } from 'ajv/dist/2019'; +import { default as Ajv2020 } from 'ajv/dist/2020'; import AjvDraft04 from 'ajv-draft-04'; import AjvFormats from 'ajv-formats'; import * as yaml from 'yaml'; @@ -16,10 +17,18 @@ import * as yaml from 'yaml'; function newAjv(schema: Record): Ajv { const draft04Schema = schema.$schema === 'http://json-schema.org/draft-04/schema#'; - - const ajv = AjvFormats(draft04Schema ? new AjvDraft04() : new Ajv2019()); - - if (!draft04Schema) { + const draft2020Schema = + schema.$schema === 'https://json-schema.org/draft/2020-12/schema'; + + const ajv = AjvFormats( + draft04Schema + ? new AjvDraft04() + : draft2020Schema + ? new Ajv2020() + : new Ajv2019() + ); + + if (!draft04Schema && !draft2020Schema) { /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */ ajv.addMetaSchema(require('ajv/dist/refs/json-schema-draft-06.json')); ajv.addMetaSchema(require('ajv/dist/refs/json-schema-draft-07.json'));