Befor generating

This commit is contained in:
marys
2026-06-01 13:17:37 +02:00
parent 3383f4bf4a
commit 1aa1b5f625
6756 changed files with 649946 additions and 1 deletions
+42
View File
@@ -0,0 +1,42 @@
const path = require('path');
const fs = require('fs');
const definitionsDirectory = path.resolve(__dirname, '../../definitions');
const outputDirectory = path.resolve(__dirname, '../../schemas');
console.log(`Looking for separate definitions in the following directory: ${definitionsDirectory}`);
console.log(`Using the following output directory: ${outputDirectory}`);
/**
* When run, go through all versions that have split definitions and bundles them together.
*/
(async () => {
const versions = await fs.promises.readdir(definitionsDirectory);
console.log(`Ensuring output directory is present ${outputDirectory}`);
if (!fs.existsSync(outputDirectory)) {
await fs.promises.mkdir(outputDirectory);
}
console.log(`The following versions have separate definitions: ${versions.join(',')}`);
for (const version of versions) {
const Bundler = require("@hyperjump/json-schema-bundle");
try{
console.log(`Bundling the following version together: ${version}`);
const versionDir = path.resolve(definitionsDirectory, version);
const definitions = await fs.promises.readdir(versionDir);
const definitionFiles = definitions.filter((value) => {return !value.includes('asyncapi')}).map((file) => fs.readFileSync(path.resolve(versionDir, file)));
const definitionJson = definitionFiles.map((file) => JSON.parse(file));
for (const jsonFile of definitionJson) {
Bundler.add(jsonFile);
}
const filePathToBundle = `file://${versionDir}/asyncapi.json`;
const fileToBundle = await Bundler.get(filePathToBundle);
const bundledSchema = await Bundler.bundle(fileToBundle);
bundledSchema.description = `!!Auto generated!! \n Do not manually edit. ${bundledSchema.description ?? ''}`;
const outputFile = path.resolve(outputDirectory, `${version}.json`);
console.log(`Writing the bundled file to: ${outputFile}`);
await fs.promises.writeFile(outputFile, JSON.stringify(bundledSchema, null, 4));
}catch(e) {
console.log(e);
}
}
console.log('done');
})();
@@ -0,0 +1,149 @@
{
"name": "bundler",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/@hyperjump/json-pointer": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@hyperjump/json-pointer/-/json-pointer-0.9.1.tgz",
"integrity": "sha512-tiDl/9MOkkiUQ5t+wq4PhtPghgWmFyBwU9Q6xRkXksg2s/6GNxNPcO/MzOjJoDAeCY1XXajNUIkco7wvhNmlOA==",
"dependencies": {
"just-curry-it": "^3.2.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
}
},
"node_modules/@hyperjump/json-schema": {
"version": "0.18.3",
"resolved": "https://registry.npmjs.org/@hyperjump/json-schema/-/json-schema-0.18.3.tgz",
"integrity": "sha512-HKrrsuJOlYdqpHEr/eRU99LCiAe8ZH4LUkQOQOMa/P8pNSgs4FQHMKy3sgkmgLSgdmQbRX2/hA+yn2Ts/gS0lA==",
"dependencies": {
"@hyperjump/json-schema-core": "^0.23.4",
"fastest-stable-stringify": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
}
},
"node_modules/@hyperjump/json-schema-bundle": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@hyperjump/json-schema-bundle/-/json-schema-bundle-0.1.3.tgz",
"integrity": "sha512-UjmmtyIgaMXRXKmkJDQhvGAQFSfaPYBRue4tk3qeISrD468vziCWI2Km0RgfeXVxgy5xgqEPyi9DLXUqD4KWDQ==",
"dependencies": {
"@hyperjump/json-schema": "^0.18.3",
"uuid": "^8.3.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
}
},
"node_modules/@hyperjump/json-schema-core": {
"version": "0.23.4",
"resolved": "https://registry.npmjs.org/@hyperjump/json-schema-core/-/json-schema-core-0.23.4.tgz",
"integrity": "sha512-rHORA3qPk2JKOJOgwgXzGkMnad0neoPiHK8tPrITNxCcVM+AwPkTK+ABogNhbFG4lipWVF4gB3XHJ2qxfQuSAw==",
"dependencies": {
"@hyperjump/json-pointer": "^0.9.1",
"@hyperjump/pact": "^0.2.0",
"content-type": "^1.0.4",
"node-fetch": "^2.6.5",
"pubsub-js": "^1.9.1",
"url-resolve-browser": "^1.2.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
}
},
"node_modules/@hyperjump/pact": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@hyperjump/pact/-/pact-0.2.0.tgz",
"integrity": "sha512-RHt0XRFsADXbqopurGZfCUNL7mPc0695TD2HNDqs4RCK5Db/1lDU2Bhk9EsyFmCBE9N1/boyvdKWjT1UYHIebg==",
"dependencies": {
"just-curry-it": "^3.1.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
}
},
"node_modules/content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fastest-stable-stringify": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz",
"integrity": "sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q=="
},
"node_modules/just-curry-it": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.2.1.tgz",
"integrity": "sha512-Q8206k8pTY7krW32cdmPsP+DqqLgWx/hYPSj9/+7SYqSqz7UuwPbfSe07lQtvuuaVyiSJveXk0E5RydOuWwsEg=="
},
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/pubsub-js": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/pubsub-js/-/pubsub-js-1.9.4.tgz",
"integrity": "sha512-hJYpaDvPH4w8ZX/0Fdf9ma1AwRgU353GfbaVfPjfJQf1KxZ2iHaHl3fAUw1qlJIR5dr4F3RzjGaWohYUEyoh7A=="
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"node_modules/url-resolve-browser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/url-resolve-browser/-/url-resolve-browser-1.2.0.tgz",
"integrity": "sha512-L9PBPnlKNDFzt9ElK4br8I8Tufdm1xgv1GhMeiP7ZC87x0b7mr+4vSh13kmPq5km80JKX+UD2BeEFTCrFZ6xDA=="
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Jason Desrosiers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,73 @@
JSON Pointer
============
This is an implementation of RFC-6901 JSON Pointer. JSON Pointer is designed for
referring to data values within a JSON document. It's designed to be URL
friendly so it can be used as a URL fragment that points to a specific part of
the JSON document.
Installation
------------
Includes support for node.js JavaScript (CommonJS and ES Modules), TypeScript,
and browsers.
```bash
npm install @hyperjump/json-pointer
```
Usage
-----
```javascript
const JsonPointer = require("@hyperjump/json-pointer");
const value = {
"foo": {
"bar": 42
}
};
// Construct pointers
const fooPointer = JsonPointer.append(JsonPointer.nil, "foo"); // "/foo"
const fooBarPointer = JsonPointer.append(fooPointer, "bar"); // "/foo/bar"
// Get a value from a pointer
const getFooBar = JsonPointer.get(fooBarPointer);
getFooBar(value); // 42
// Set a value from a pointer
// New value is returned without modifying the original
const setFooBar = JsonPointer.set(fooBarPointer);
setFooBar(value, 33); // { "foo": { "bar": 33 } }
// Assign a value from a pointer
// The original value is changed and no value is returned
const assignFooBar = JsonPointer.assign(fooBarPointer);
assignFooBar(value, 33); // { "foo": { "bar": 33 } }
// Unset a value from a pointer
// New value is returned without modifying the original
const unsetFooBar = JsonPointer.unset(fooBarPointer);
setFooBar(value); // { "foo": {} }
// Delete a value from a pointer
// The original value is changed and no value is returned
const deleteFooBar = JsonPointer.remove(fooBarPointer);
deleteFooBar(value); // { "foo": {} }
```
Contributing
------------
### Tests
Run the tests
```bash
npm test
```
Run the tests with a continuous test runner
```bash
npm test -- --watch
```
@@ -0,0 +1,181 @@
define(function () { 'use strict';
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = { nil, append, get, set, assign, unset, remove };
return lib;
});
//# sourceMappingURL=json-pointer-amd.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
define((function(){"use strict";const e=function(e,t){return function r(){null==t&&(t=e.length);var n=[].slice.call(arguments);return n.length>=t?e.apply(this,n):function(){return r.apply(this,n.concat([].slice.call(arguments)))}}},t=e=>{if(e.length>0&&"/"!==e[0])throw Error("Invalid JSON Pointer");return e.split("/").slice(1).map(u)},r=(e,t,n,i)=>{if(0===e.length)return n;if(e.length>1){const o=e.shift();return{...t,[o]:r(e,c(t,o,i),n,l(o,i))}}if(Array.isArray(t)){const r=[...t];return r[a(t,e[0])]=n,r}return"object"==typeof t&&null!==t?{...t,[e[0]]:n}:c(t,e[0],i)},n=(e,t,r,i)=>{if(0!==e.length)if(1!==e.length||f(t)){const o=e.shift();n(e,c(t,o,i),r,l(o,i))}else{t[a(t,e[0])]=r}},i=(e,t,r)=>{if(0!=e.length){if(e.length>1){const n=e.shift(),o=c(t,n,r);return{...t,[n]:i(e,o,l(n,r))}}if(Array.isArray(t))return t.filter(((t,r)=>r!=e[0]));if("object"==typeof t&&null!==t){const{[e[0]]:r,...n}=t;return n}return c(t,e[0],r)}},o=(e,t,r)=>{if(0!==e.length)if(e.length>1){const n=e.shift(),i=c(t,n,r);o(e,i,l(n,r))}else Array.isArray(t)?t.splice(e[0],1):"object"==typeof t&&null!==t?delete t[e[0]]:c(t,e[0],r)},l=e(((e,t)=>t+"/"+s(e))),s=e=>e.toString().replace(/~/g,"~0").replace(/\//g,"~1"),u=e=>e.toString().replace(/~1/g,"/").replace(/~0/g,"~"),a=(e,t)=>Array.isArray(e)&&"-"===t?e.length:t,c=(e,t,r="")=>{if(void 0===e)throw TypeError(`Value at '${r}' is undefined and does not have property '${t}'`);if(null===e)throw TypeError(`Value at '${r}' is null and does not have property '${t}'`);if(f(e))throw TypeError(`Value at '${r}' is a ${typeof e} and does not have property '${t}'`);return e[a(e,t)]},f=e=>null===e||"object"!=typeof e;return{nil:"",append:l,get:(e,r)=>{const n=t(e),i=e=>n.reduce((([e,t],r)=>[c(e,r,t),l(r,t)]),[e,""])[0];return void 0===r?i:i(r)},set:(n,i,o)=>{const l=t(n),s=e(((e,t)=>r(l,e,t,"")));return void 0===i?s:s(i,o)},assign:(r,i,o)=>{const l=t(r),s=e(((e,t)=>n(l,e,t,"")));return void 0===i?s:s(i,o)},unset:(e,r)=>{const n=t(e),o=e=>i(n,e,"");return void 0===r?o:o(r)},remove:(e,r)=>{const n=t(e),i=e=>o(n,e,"");return void 0===r?i:i(r)}}}));
//# sourceMappingURL=json-pointer-amd.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,179 @@
'use strict';
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = { nil, append, get, set, assign, unset, remove };
module.exports = lib;
//# sourceMappingURL=json-pointer-cjs.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
"use strict";const e=function(e,r){return function t(){null==r&&(r=e.length);var n=[].slice.call(arguments);return n.length>=r?e.apply(this,n):function(){return t.apply(this,n.concat([].slice.call(arguments)))}}},r=e=>{if(e.length>0&&"/"!==e[0])throw Error("Invalid JSON Pointer");return e.split("/").slice(1).map(a)},t=(e,r,n,o)=>{if(0===e.length)return n;if(e.length>1){const i=e.shift();return{...r,[i]:t(e,c(r,i,o),n,l(i,o))}}if(Array.isArray(r)){const t=[...r];return t[u(r,e[0])]=n,t}return"object"==typeof r&&null!==r?{...r,[e[0]]:n}:c(r,e[0],o)},n=(e,r,t,o)=>{if(0!==e.length)if(1!==e.length||f(r)){const i=e.shift();n(e,c(r,i,o),t,l(i,o))}else{r[u(r,e[0])]=t}},o=(e,r,t)=>{if(0!=e.length){if(e.length>1){const n=e.shift(),i=c(r,n,t);return{...r,[n]:o(e,i,l(n,t))}}if(Array.isArray(r))return r.filter(((r,t)=>t!=e[0]));if("object"==typeof r&&null!==r){const{[e[0]]:t,...n}=r;return n}return c(r,e[0],t)}},i=(e,r,t)=>{if(0!==e.length)if(e.length>1){const n=e.shift(),o=c(r,n,t);i(e,o,l(n,t))}else Array.isArray(r)?r.splice(e[0],1):"object"==typeof r&&null!==r?delete r[e[0]]:c(r,e[0],t)},l=e(((e,r)=>r+"/"+s(e))),s=e=>e.toString().replace(/~/g,"~0").replace(/\//g,"~1"),a=e=>e.toString().replace(/~1/g,"/").replace(/~0/g,"~"),u=(e,r)=>Array.isArray(e)&&"-"===r?e.length:r,c=(e,r,t="")=>{if(void 0===e)throw TypeError(`Value at '${t}' is undefined and does not have property '${r}'`);if(null===e)throw TypeError(`Value at '${t}' is null and does not have property '${r}'`);if(f(e))throw TypeError(`Value at '${t}' is a ${typeof e} and does not have property '${r}'`);return e[u(e,r)]},f=e=>null===e||"object"!=typeof e;var p={nil:"",append:l,get:(e,t)=>{const n=r(e),o=e=>n.reduce((([e,r],t)=>[c(e,t,r),l(t,r)]),[e,""])[0];return void 0===t?o:o(t)},set:(n,o,i)=>{const l=r(n),s=e(((e,r)=>t(l,e,r,"")));return void 0===o?s:s(o,i)},assign:(t,o,i)=>{const l=r(t),s=e(((e,r)=>n(l,e,r,"")));return void 0===o?s:s(o,i)},unset:(e,t)=>{const n=r(e),i=e=>o(n,e,"");return void 0===t?i:i(t)},remove:(e,t)=>{const n=r(e),o=e=>i(n,e,"");return void 0===t?o:o(t)}};module.exports=p;
//# sourceMappingURL=json-pointer-cjs.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,177 @@
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = { nil, append, get, set, assign, unset, remove };
export { lib as default };
//# sourceMappingURL=json-pointer-esm.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
const e=function(e,r){return function t(){null==r&&(r=e.length);var n=[].slice.call(arguments);return n.length>=r?e.apply(this,n):function(){return t.apply(this,n.concat([].slice.call(arguments)))}}},r=e=>{if(e.length>0&&"/"!==e[0])throw Error("Invalid JSON Pointer");return e.split("/").slice(1).map(a)},t=(e,r,n,o)=>{if(0===e.length)return n;if(e.length>1){const l=e.shift();return{...r,[l]:t(e,c(r,l,o),n,i(l,o))}}if(Array.isArray(r)){const t=[...r];return t[u(r,e[0])]=n,t}return"object"==typeof r&&null!==r?{...r,[e[0]]:n}:c(r,e[0],o)},n=(e,r,t,o)=>{if(0!==e.length)if(1!==e.length||f(r)){const l=e.shift();n(e,c(r,l,o),t,i(l,o))}else{r[u(r,e[0])]=t}},o=(e,r,t)=>{if(0!=e.length){if(e.length>1){const n=e.shift(),l=c(r,n,t);return{...r,[n]:o(e,l,i(n,t))}}if(Array.isArray(r))return r.filter(((r,t)=>t!=e[0]));if("object"==typeof r&&null!==r){const{[e[0]]:t,...n}=r;return n}return c(r,e[0],t)}},l=(e,r,t)=>{if(0!==e.length)if(e.length>1){const n=e.shift(),o=c(r,n,t);l(e,o,i(n,t))}else Array.isArray(r)?r.splice(e[0],1):"object"==typeof r&&null!==r?delete r[e[0]]:c(r,e[0],t)},i=e(((e,r)=>r+"/"+s(e))),s=e=>e.toString().replace(/~/g,"~0").replace(/\//g,"~1"),a=e=>e.toString().replace(/~1/g,"/").replace(/~0/g,"~"),u=(e,r)=>Array.isArray(e)&&"-"===r?e.length:r,c=(e,r,t="")=>{if(void 0===e)throw TypeError(`Value at '${t}' is undefined and does not have property '${r}'`);if(null===e)throw TypeError(`Value at '${t}' is null and does not have property '${r}'`);if(f(e))throw TypeError(`Value at '${t}' is a ${typeof e} and does not have property '${r}'`);return e[u(e,r)]},f=e=>null===e||"object"!=typeof e;var p={nil:"",append:i,get:(e,t)=>{const n=r(e),o=e=>n.reduce((([e,r],t)=>[c(e,t,r),i(t,r)]),[e,""])[0];return void 0===t?o:o(t)},set:(n,o,l)=>{const i=r(n),s=e(((e,r)=>t(i,e,r,"")));return void 0===o?s:s(o,l)},assign:(t,o,l)=>{const i=r(t),s=e(((e,r)=>n(i,e,r,"")));return void 0===o?s:s(o,l)},unset:(e,t)=>{const n=r(e),l=e=>o(n,e,"");return void 0===t?l:l(t)},remove:(e,t)=>{const n=r(e),o=e=>l(n,e,"");return void 0===t?o:o(t)}};export{p as default};
//# sourceMappingURL=json-pointer-esm.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,182 @@
var JsonPointer = (function () {
'use strict';
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = { nil, append, get, set, assign, unset, remove };
return lib;
}());
//# sourceMappingURL=json-pointer-iife.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
var JsonPointer=function(){"use strict";const r=function(r,t){return function e(){null==t&&(t=r.length);var n=[].slice.call(arguments);return n.length>=t?r.apply(this,n):function(){return e.apply(this,n.concat([].slice.call(arguments)))}}},t=r=>{if(r.length>0&&"/"!==r[0])throw Error("Invalid JSON Pointer");return r.split("/").slice(1).map(u)},e=(r,t,n,o)=>{if(0===r.length)return n;if(r.length>1){const i=r.shift();return{...t,[i]:e(r,c(t,i,o),n,l(i,o))}}if(Array.isArray(t)){const e=[...t];return e[a(t,r[0])]=n,e}return"object"==typeof t&&null!==t?{...t,[r[0]]:n}:c(t,r[0],o)},n=(r,t,e,o)=>{if(0!==r.length)if(1!==r.length||f(t)){const i=r.shift();n(r,c(t,i,o),e,l(i,o))}else{t[a(t,r[0])]=e}},o=(r,t,e)=>{if(0!=r.length){if(r.length>1){const n=r.shift(),i=c(t,n,e);return{...t,[n]:o(r,i,l(n,e))}}if(Array.isArray(t))return t.filter(((t,e)=>e!=r[0]));if("object"==typeof t&&null!==t){const{[r[0]]:e,...n}=t;return n}return c(t,r[0],e)}},i=(r,t,e)=>{if(0!==r.length)if(r.length>1){const n=r.shift(),o=c(t,n,e);i(r,o,l(n,e))}else Array.isArray(t)?t.splice(r[0],1):"object"==typeof t&&null!==t?delete t[r[0]]:c(t,r[0],e)},l=r(((r,t)=>t+"/"+s(r))),s=r=>r.toString().replace(/~/g,"~0").replace(/\//g,"~1"),u=r=>r.toString().replace(/~1/g,"/").replace(/~0/g,"~"),a=(r,t)=>Array.isArray(r)&&"-"===t?r.length:t,c=(r,t,e="")=>{if(void 0===r)throw TypeError(`Value at '${e}' is undefined and does not have property '${t}'`);if(null===r)throw TypeError(`Value at '${e}' is null and does not have property '${t}'`);if(f(r))throw TypeError(`Value at '${e}' is a ${typeof r} and does not have property '${t}'`);return r[a(r,t)]},f=r=>null===r||"object"!=typeof r;return{nil:"",append:l,get:(r,e)=>{const n=t(r),o=r=>n.reduce((([r,t],e)=>[c(r,e,t),l(e,t)]),[r,""])[0];return void 0===e?o:o(e)},set:(n,o,i)=>{const l=t(n),s=r(((r,t)=>e(l,r,t,"")));return void 0===o?s:s(o,i)},assign:(e,o,i)=>{const l=t(e),s=r(((r,t)=>n(l,r,t,"")));return void 0===o?s:s(o,i)},unset:(r,e)=>{const n=t(r),i=r=>o(n,r,"");return void 0===e?i:i(e)},remove:(r,e)=>{const n=t(r),o=r=>i(n,r,"");return void 0===e?o:o(e)}}}();
//# sourceMappingURL=json-pointer-iife.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,184 @@
System.register('JsonPointer', [], function (exports) {
'use strict';
return {
execute: function () {
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = exports('default', { nil, append, get, set, assign, unset, remove });
}
};
});
//# sourceMappingURL=json-pointer-system.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
System.register("JsonPointer",[],(function(e){"use strict";return{execute:function(){const t=function(e,t){return function r(){null==t&&(t=e.length);var n=[].slice.call(arguments);return n.length>=t?e.apply(this,n):function(){return r.apply(this,n.concat([].slice.call(arguments)))}}},r=e=>{if(e.length>0&&"/"!==e[0])throw Error("Invalid JSON Pointer");return e.split("/").slice(1).map(a)},n=(e,t,r,o)=>{if(0===e.length)return r;if(e.length>1){const i=e.shift();return{...t,[i]:n(e,f(t,i,o),r,s(i,o))}}if(Array.isArray(t)){const n=[...t];return n[c(t,e[0])]=r,n}return"object"==typeof t&&null!==t?{...t,[e[0]]:r}:f(t,e[0],o)},o=(e,t,r,n)=>{if(0!==e.length)if(1!==e.length||p(t)){const i=e.shift();o(e,f(t,i,n),r,s(i,n))}else{t[c(t,e[0])]=r}},i=(e,t,r)=>{if(0!=e.length){if(e.length>1){const n=e.shift(),o=f(t,n,r);return{...t,[n]:i(e,o,s(n,r))}}if(Array.isArray(t))return t.filter(((t,r)=>r!=e[0]));if("object"==typeof t&&null!==t){const{[e[0]]:r,...n}=t;return n}return f(t,e[0],r)}},l=(e,t,r)=>{if(0!==e.length)if(e.length>1){const n=e.shift(),o=f(t,n,r);l(e,o,s(n,r))}else Array.isArray(t)?t.splice(e[0],1):"object"==typeof t&&null!==t?delete t[e[0]]:f(t,e[0],r)},s=t(((e,t)=>t+"/"+u(e))),u=e=>e.toString().replace(/~/g,"~0").replace(/\//g,"~1"),a=e=>e.toString().replace(/~1/g,"/").replace(/~0/g,"~"),c=(e,t)=>Array.isArray(e)&&"-"===t?e.length:t,f=(e,t,r="")=>{if(void 0===e)throw TypeError(`Value at '${r}' is undefined and does not have property '${t}'`);if(null===e)throw TypeError(`Value at '${r}' is null and does not have property '${t}'`);if(p(e))throw TypeError(`Value at '${r}' is a ${typeof e} and does not have property '${t}'`);return e[c(e,t)]},p=e=>null===e||"object"!=typeof e;e("default",{nil:"",append:s,get:(e,t)=>{const n=r(e),o=e=>n.reduce((([e,t],r)=>[f(e,r,t),s(r,t)]),[e,""])[0];return void 0===t?o:o(t)},set:(e,o,i)=>{const l=r(e),s=t(((e,t)=>n(l,e,t,"")));return void 0===o?s:s(o,i)},assign:(e,n,i)=>{const l=r(e),s=t(((e,t)=>o(l,e,t,"")));return void 0===n?s:s(n,i)},unset:(e,t)=>{const n=r(e),o=e=>i(n,e,"");return void 0===t?o:o(t)},remove:(e,t)=>{const n=r(e),o=e=>l(n,e,"");return void 0===t?o:o(t)}})}}}));
//# sourceMappingURL=json-pointer-system.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,185 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JsonPointer = factory());
}(this, (function () { 'use strict';
var justCurryIt = curry$1;
/*
function add(a, b, c) {
return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9
function add(...args) {
return args.reduce((sum, n) => sum + n, 0)
}
var curryAdd4 = curry(add, 4)
curryAdd4(1)(2, 3)(4); // 10
function converter(ratio, input) {
return (input*ratio).toFixed(1);
}
const curriedConverter = curry(converter)
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2
*/
function curry$1(fn, arity) {
return function curried() {
if (arity == null) {
arity = fn.length;
}
var args = [].slice.call(arguments);
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function() {
return curried.apply(this, args.concat([].slice.call(arguments)));
};
}
};
}
const curry = justCurryIt;
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
var lib = { nil, append, get, set, assign, unset, remove };
return lib;
})));
//# sourceMappingURL=json-pointer-umd.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).JsonPointer=t()}(this,(function(){"use strict";const e=function(e,t){return function r(){null==t&&(t=e.length);var n=[].slice.call(arguments);return n.length>=t?e.apply(this,n):function(){return r.apply(this,n.concat([].slice.call(arguments)))}}},t=e=>{if(e.length>0&&"/"!==e[0])throw Error("Invalid JSON Pointer");return e.split("/").slice(1).map(u)},r=(e,t,n,o)=>{if(0===e.length)return n;if(e.length>1){const i=e.shift();return{...t,[i]:r(e,a(t,i,o),n,l(i,o))}}if(Array.isArray(t)){const r=[...t];return r[f(t,e[0])]=n,r}return"object"==typeof t&&null!==t?{...t,[e[0]]:n}:a(t,e[0],o)},n=(e,t,r,o)=>{if(0!==e.length)if(1!==e.length||c(t)){const i=e.shift();n(e,a(t,i,o),r,l(i,o))}else{t[f(t,e[0])]=r}},o=(e,t,r)=>{if(0!=e.length){if(e.length>1){const n=e.shift(),i=a(t,n,r);return{...t,[n]:o(e,i,l(n,r))}}if(Array.isArray(t))return t.filter(((t,r)=>r!=e[0]));if("object"==typeof t&&null!==t){const{[e[0]]:r,...n}=t;return n}return a(t,e[0],r)}},i=(e,t,r)=>{if(0!==e.length)if(e.length>1){const n=e.shift(),o=a(t,n,r);i(e,o,l(n,r))}else Array.isArray(t)?t.splice(e[0],1):"object"==typeof t&&null!==t?delete t[e[0]]:a(t,e[0],r)},l=e(((e,t)=>t+"/"+s(e))),s=e=>e.toString().replace(/~/g,"~0").replace(/\//g,"~1"),u=e=>e.toString().replace(/~1/g,"/").replace(/~0/g,"~"),f=(e,t)=>Array.isArray(e)&&"-"===t?e.length:t,a=(e,t,r="")=>{if(void 0===e)throw TypeError(`Value at '${r}' is undefined and does not have property '${t}'`);if(null===e)throw TypeError(`Value at '${r}' is null and does not have property '${t}'`);if(c(e))throw TypeError(`Value at '${r}' is a ${typeof e} and does not have property '${t}'`);return e[f(e,t)]},c=e=>null===e||"object"!=typeof e;return{nil:"",append:l,get:(e,r)=>{const n=t(e),o=e=>n.reduce((([e,t],r)=>[a(e,r,t),l(r,t)]),[e,""])[0];return void 0===r?o:o(r)},set:(n,o,i)=>{const l=t(n),s=e(((e,t)=>r(l,e,t,"")));return void 0===o?s:s(o,i)},assign:(r,o,i)=>{const l=t(r),s=e(((e,t)=>n(l,e,t,"")));return void 0===o?s:s(o,i)},unset:(e,r)=>{const n=t(e),i=e=>o(n,e,"");return void 0===r?i:i(r)},remove:(e,r)=>{const n=t(e),o=e=>i(n,e,"");return void 0===r?o:o(r)}}}));
//# sourceMappingURL=json-pointer-umd.min.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,65 @@
export type JsonPointer = {
nil: "";
append: (
(segment: string, pointer: string) => string
) & (
(segment: string) => (pointer: string) => string
);
get: (
(pointer: string, subject: Pointable) => unknown
) & (
(pointer: string) => Getter
);
set: (
<A extends Pointable>(pointer: string, subject: A, value: unknown) => A
) & (
(pointer: string) => Setter
);
assign: (
<A extends Pointable>(pointer: string, subject: A, value: unknown) => void
) & (
(pointer: string) => Assigner
);
unset: (
<A extends Pointable>(pointer: string, subject: A) => A
) & (
(pointer: string) => Unsetter
);
remove: (
(pointer: string, subject: Pointable) => void
) & (
(pointer: string) => Remover
);
}
export type Getter = (subject: Pointable) => unknown;
export type Setter = (
<A extends Pointable>(subject: A, value: unknown) => A
) & (
<A extends Pointable>(subject: A) => (value: unknown) => A
);
export type Assigner = (
<A extends Pointable>(subject: A, value: unknown) => void
) & (
<A extends Pointable>(subject: A) => (value: unknown) => void
);
export type Unsetter = <A extends Pointable>(subject: A) => A;
export type Remover = (subject: Pointable) => void;
export type Json = string | number | boolean | null | JsonObject | Json[];
export type JsonObject = {
[property: string]: Json;
};
export type Pointable = JsonObject | Json[];
declare const JsonPointer: JsonPointer;
export const nil: JsonPointer["nil"];
export const append: JsonPointer["append"];
export const get: JsonPointer["get"];
export const set: JsonPointer["set"];
export const assign: JsonPointer["assign"];
export const unset: JsonPointer["unset"];
export const remove: JsonPointer["remove"];
export default JsonPointer;
@@ -0,0 +1,133 @@
const curry = require("just-curry-it");
const nil = "";
const compile = (pointer) => {
if (pointer.length > 0 && pointer[0] !== "/") {
throw Error("Invalid JSON Pointer");
}
return pointer.split("/").slice(1).map(unescape);
};
const get = (pointer, value = undefined) => {
const ptr = compile(pointer);
const fn = (value) => ptr.reduce(([value, pointer], segment) => {
return [applySegment(value, segment, pointer), append(segment, pointer)];
}, [value, ""])[0];
return value === undefined ? fn : fn(value);
};
const set = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _set(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _set = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return value;
} else if (pointer.length > 1) {
const segment = pointer.shift();
return { ...subject, [segment]: _set(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
const clonedSubject = [...subject];
const segment = computeSegment(subject, pointer[0]);
clonedSubject[segment] = value;
return clonedSubject;
} else if (typeof subject === "object" && subject !== null) {
return { ...subject, [pointer[0]]: value };
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const assign = (pointer, subject = undefined, value = undefined) => {
const ptr = compile(pointer);
const fn = curry((subject, value) => _assign(ptr, subject, value, nil));
return subject === undefined ? fn : fn(subject, value);
};
const _assign = (pointer, subject, value, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length === 1 && !isScalar(subject)) {
const segment = computeSegment(subject, pointer[0]);
subject[segment] = value;
} else {
const segment = pointer.shift();
_assign(pointer, applySegment(subject, segment, cursor), value, append(segment, cursor));
}
};
const unset = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _unset(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _unset = (pointer, subject, cursor) => {
if (pointer.length == 0) {
return undefined;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
return { ...subject, [segment]: _unset(pointer, value, append(segment, cursor)) };
} else if (Array.isArray(subject)) {
return subject.filter((_, ndx) => ndx != pointer[0]);
} else if (typeof subject === "object" && subject !== null) {
// eslint-disable-next-line no-unused-vars
const { [pointer[0]]: _, ...result } = subject;
return result;
} else {
return applySegment(subject, pointer[0], cursor);
}
};
const remove = (pointer, subject = undefined) => {
const ptr = compile(pointer);
const fn = (subject) => _remove(ptr, subject, nil);
return subject === undefined ? fn : fn(subject);
};
const _remove = (pointer, subject, cursor) => {
if (pointer.length === 0) {
return;
} else if (pointer.length > 1) {
const segment = pointer.shift();
const value = applySegment(subject, segment, cursor);
_remove(pointer, value, append(segment, cursor));
} else if (Array.isArray(subject)) {
subject.splice(pointer[0], 1);
} else if (typeof subject === "object" && subject !== null) {
delete subject[pointer[0]];
} else {
applySegment(subject, pointer[0], cursor);
}
};
const append = curry((segment, pointer) => pointer + "/" + escape(segment));
const escape = (segment) => segment.toString().replace(/~/g, "~0").replace(/\//g, "~1");
const unescape = (segment) => segment.toString().replace(/~1/g, "/").replace(/~0/g, "~");
const computeSegment = (value, segment) => Array.isArray(value) && segment === "-" ? value.length : segment;
const applySegment = (value, segment, cursor = "") => {
if (value === undefined) {
throw TypeError(`Value at '${cursor}' is undefined and does not have property '${segment}'`);
} else if (value === null) {
throw TypeError(`Value at '${cursor}' is null and does not have property '${segment}'`);
} else if (isScalar(value)) {
throw TypeError(`Value at '${cursor}' is a ${typeof value} and does not have property '${segment}'`);
} else {
const computedSegment = computeSegment(value, segment);
return value[computedSegment];
}
};
const isScalar = (value) => value === null || typeof value !== "object";
module.exports = { nil, append, get, set, assign, unset, remove };
@@ -0,0 +1,9 @@
import JsonPointer from "./index.js";
export const append = JsonPointer.append;
export const assign = JsonPointer.assign;
export const remove = JsonPointer.remove;
export const get = JsonPointer.get;
export const set = JsonPointer.set;
export const unset = JsonPointer.unset;
@@ -0,0 +1,88 @@
{
"_args": [
[
"@hyperjump/json-pointer@0.9.1",
"/Users/wookiee/sources/asyncapi-node/tools/bundler"
]
],
"_from": "@hyperjump/json-pointer@0.9.1",
"_id": "@hyperjump/json-pointer@0.9.1",
"_inBundle": false,
"_integrity": "sha512-tiDl/9MOkkiUQ5t+wq4PhtPghgWmFyBwU9Q6xRkXksg2s/6GNxNPcO/MzOjJoDAeCY1XXajNUIkco7wvhNmlOA==",
"_location": "/@hyperjump/json-pointer",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@hyperjump/json-pointer@0.9.1",
"name": "@hyperjump/json-pointer",
"escapedName": "@hyperjump%2fjson-pointer",
"scope": "@hyperjump",
"rawSpec": "0.9.1",
"saveSpec": null,
"fetchSpec": "0.9.1"
},
"_requiredBy": [
"/@hyperjump/json-schema-core"
],
"_resolved": "https://registry.npmjs.org/@hyperjump/json-pointer/-/json-pointer-0.9.1.tgz",
"_spec": "0.9.1",
"_where": "/Users/wookiee/sources/asyncapi-node/tools/bundler",
"author": {
"name": "Jason Desrosiers",
"email": "jdesrosi@gmail.com"
},
"bugs": {
"url": "https://github.com/hyperjump-io/json-pointer/issues"
},
"dependencies": {
"just-curry-it": "^3.2.1"
},
"description": "An RFC-6901 JSON Pointer implementation",
"devDependencies": {
"@rollup/plugin-commonjs": "^20.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@types/chai": "^4.2.21",
"@types/mocha": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^4.29.3",
"@typescript-eslint/parser": "^4.29.3",
"chai": "^4.3.4",
"eslint": "^7.32.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.24.2",
"mocha": "^9.1.1",
"rollup": "^2.56.3",
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.2.1",
"typescript": "^4.4.2"
},
"exports": {
"require": "./lib/index.js",
"import": "./lib/index.mjs"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
},
"homepage": "https://github.com/hyperjump-io/json-pointer#readme",
"keywords": [
"JSON Pointer",
"RFC-6901"
],
"license": "MIT",
"main": "lib/index.js",
"name": "@hyperjump/json-pointer",
"repository": {
"type": "git",
"url": "git+https://github.com/hyperjump-io/json-pointer.git"
},
"scripts": {
"build": "rollup --config rollup.config.js",
"clean": "xargs -a .gitignore rm -rf",
"lint": "eslint lib",
"prepublishOnly": "npm run build",
"test": "mocha --require ts-node/register 'lib/**/*.spec.ts'"
},
"version": "0.9.1"
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Jason Desrosiers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,159 @@
# Hyperjump - JSON Schema Bundle
JSON Schema Bundle (JSB) is an implementation of the official JSON Schema
bundling process introduced in the Draft 2020-12 specification. Given a schema
with external references, any external schemas will be embedded in the schema
resulting in a Compound Schema Document with all the schemas necessary to
evaluate the given schema.
The bundling process allows schemas to be embedded without needing to modify any
references which means you get the same output details whether you validate the
bundle or the original unbundled schemas.
JSON Schema Bundle (JSB) is built on [JSON Schema Core](https://github.com/hyperjump-io/json-schema-core).
* Supported JSON Schema Dialects
* draft-04 | draft-06 | draft-07 | Draft 2019-09 | Draft 2020-12
* Support for custom dialects can be configured
* Schemas can reference other schemas using a different draft
* Load schemas from filesystem (file://), network (http(s)://), or JavaScript
## Install
JSB includes support for node.js JavaScript (CommonJS and ES Modules),
TypeScript, and browsers.
### Node.js
```bash
npm install @hyperjump/json-schema-bundle
```
### Browser
When in a browser context, JSB is designed to use the browser's `fetch`
implementation instead of a node.js fetch clone. The Webpack bundler does this
properly without any extra configuration, but if you are using the Rollup
bundler you will need to include the `browser: true` option in your Rollup
configuration.
```javascript
plugins: [
resolve({
browser: true
}),
commonjs()
]
```
### Versioning
This project is in beta and there may be breaking changes at any time. When it's
stable enough, I'll publish v1.0.0 and follow semantic versioning from there on
out.
## Usage
```javascript
const Bundler = require("@hyperjump/json-schema-bundle");
// Optionally load schema manually
Bundler.add({
"$id": "https://json-schema.hyperjump.io/schemas/string",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
});
// Get the initial schema to pass to the bundler
const main = await Bundler.get(`file://${__dirname}/schemas/main.schema.json`);
// The bundler will fetch from the file system, network, or internal schemas as
// needed to build to bundle.
const bundle = await Bundler.bundle(main);
```
## TypeScript
Although the package is written in JavaScript, type definitions are included for
TypeScript support. The following example shows the types you might want to
know.
```typescript
import Bundler from "@hyperjump/json-schema-bundle";
import type { SchemaDocument, Draft202012Schema, InvalidSchemaError } from "@hyperjump/json-schema-bundle";
(async function () {
const schemaJson: Draft202012Schema = {
"$id": "https://json-schema.hyperjump.io/schemas/string",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
};
Bundler.add(schemaJson);
try {
const main: SchemaDocument = await Bundler.get(`file://${__dirname}/schemas/main.schema.json`);
const bundle: Draft202012Schema = await Bundler.bundle(main);
console.log(JSON.stringify(bundle, null, " "));
} catch (error: unknown) {
if (error instanceof InvalidSchemaError) {
console.log(error.output);
} else {
console.log(error);
}
}
}());
```
## API
* **add**: (schema: object, url?: URI, schemaVersion?: string) => SDoc
Load a schema. See [JSC - $id](https://github.com/hyperjump-io/json-schema-core#id)
and [JSC - $schema](https://github.com/hyperjump-io/json-schema-core#schema-1)
for more information.
* **get**: (url: URI, contextDoc?: SDoc, recursive: boolean = false) => Promise\<SDoc>
Fetch a schema. Schemas can come from an HTTP request, a file, or a schema
that was added with `add`.
* **bundle**: (schema: SDoc, options: Options) => Promise\<SchemaObject>
Create a bundled schema starting with the given schema. External schemas
will be fetched from the filesystem, the network, or internally as needed.
Options:
* alwaysIncludeDialect: boolean (default: false) -- Include dialect even
when it isn't strictly needed
* bundleMode: "flat" | "full" (default: "flat") -- When bundling schemas
that already contain bundled schemas, "flat" mode with remove nested
embedded schemas and put them all in the top level `$defs`. When using
"full" mode, it will keep the already embedded schemas around, which will
result in some embedded schema duplication.
* definitionNamingStrategy: "uri" | "uuid" (default: "uri") -- By default
the name used in definitions for embedded schemas will match the
identifier of the embedded schema. This naming is unlikely to collide
with actual definitions, but if you want to be sure, you can use the
"uuid" strategy instead to be sure you get a unique name.
* **setMetaOutputFormat**: (outputFormat: OutputFormat = DETAILED) => undefined
Set the output format for meta-validation. Meta-validation output is only
returned if meta-validation results in an error.
* **setShouldMetaValidate**: (isEnabled: boolean) => undefined
Enable or disable meta-validation.
* **OutputFormat**: [**FLAG** | **BASIC** | **DETAILED** | **VERBOSE**]
See [JSC - Output](https://github.com/hyperjump-io/json-schema-core#output)
for more information on output formats.
## Contributing
### Tests
Run the tests
```bash
npm test
```
Run the tests with a continuous test runner
```bash
npm test -- --watch
```
@@ -0,0 +1,10 @@
const splitUri = (url) => {
const indexOfHash = url.indexOf("#");
const ndx = indexOfHash === -1 ? url.length : indexOfHash;
const urlReference = url.slice(0, ndx);
const urlFragment = url.slice(ndx + 1);
return [decodeURI(urlReference), decodeURI(urlFragment)];
};
module.exports = { splitUri };
@@ -0,0 +1,11 @@
const { Core } = require("@hyperjump/json-schema-core");
const { splitUri } = require("./common");
const collectExternalIds = (schemaUri, externalIds, ast, dynamicAnchors) => {
const keywordId = ast[schemaUri][0];
const id = splitUri(schemaUri)[0];
Core.getKeyword(keywordId).collectExternalIds(schemaUri, externalIds, ast, { ...ast.metaData[id].dynamicAnchors, ...dynamicAnchors });
};
module.exports = { collectExternalIds };
@@ -0,0 +1,39 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core, Schema } = require("@hyperjump/json-schema-core");
const Keywords = require("./keywords");
Schema.setConfig("http://json-schema.org/draft-04/schema", "bundlingLocation", "/definitions");
Core.defineVocabulary("http://json-schema.org/draft-04/schema", {
"validate": Keywords.validate,
"additionalItems": Keywords.additionalItems,
"additionalProperties": Keywords.additionalProperties,
"allOf": Keywords.allOf,
"anyOf": Keywords.anyOf,
"default": JsonSchema.Keywords.metaData,
"definitions": JsonSchema.Keywords.definitions,
"dependencies": Keywords.dependencies,
"description": JsonSchema.Keywords.metaData,
"enum": JsonSchema.Keywords.enum,
"format": JsonSchema.Keywords.metaData,
"items": Keywords.items,
"maxItems": JsonSchema.Keywords.maxItems,
"maxLength": JsonSchema.Keywords.maxLength,
"maxProperties": JsonSchema.Keywords.maxProperties,
"maximum": JsonSchema.Keywords.maximumExclusiveMaximum,
"minItems": JsonSchema.Keywords.minItems,
"minLength": JsonSchema.Keywords.minLength,
"minProperties": JsonSchema.Keywords.minProperties,
"minimum": JsonSchema.Keywords.minimumExclusiveMinimum,
"multipleOf": JsonSchema.Keywords.multipleOf,
"not": Keywords.not,
"oneOf": Keywords.oneOf,
"pattern": JsonSchema.Keywords.pattern,
"patternProperties": Keywords.patternProperties,
"properties": Keywords.properties,
"required": JsonSchema.Keywords.required,
"title": JsonSchema.Keywords.metaData,
"type": JsonSchema.Keywords.type,
"uniqueItems": JsonSchema.Keywords.uniqueItems
});
@@ -0,0 +1,45 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core, Schema } = require("@hyperjump/json-schema-core");
const Keywords = require("./keywords");
Schema.setConfig("http://json-schema.org/draft-06/schema", "bundlingLocation", "/definitions");
Core.defineVocabulary("http://json-schema.org/draft-06/schema", {
"validate": Keywords.validate,
"additionalItems": Keywords.additionalItems6,
"additionalProperties": Keywords.additionalProperties6,
"allOf": Keywords.allOf,
"anyOf": Keywords.anyOf,
"const": JsonSchema.Keywords.const,
"contains": Keywords.contains,
"default": JsonSchema.Keywords.metaData,
"definitions": JsonSchema.Keywords.definitions,
"dependencies": Keywords.dependencies,
"description": JsonSchema.Keywords.metaData,
"enum": JsonSchema.Keywords.enum,
"examples": JsonSchema.Keywords.metaData,
"exclusiveMaximum": JsonSchema.Keywords.exclusiveMaximum,
"exclusiveMinimum": JsonSchema.Keywords.exclusiveMinimum,
"format": JsonSchema.Keywords.metaData,
"items": Keywords.items,
"maxItems": JsonSchema.Keywords.maxItems,
"maxLength": JsonSchema.Keywords.maxLength6,
"maxProperties": JsonSchema.Keywords.maxProperties,
"maximum": JsonSchema.Keywords.maximum,
"minItems": JsonSchema.Keywords.minItems,
"minLength": JsonSchema.Keywords.minLength6,
"minProperties": JsonSchema.Keywords.minProperties,
"minimum": JsonSchema.Keywords.minimum,
"multipleOf": JsonSchema.Keywords.multipleOf,
"not": Keywords.not,
"oneOf": Keywords.oneOf,
"pattern": JsonSchema.Keywords.pattern,
"patternProperties": Keywords.patternProperties,
"properties": Keywords.properties,
"propertyNames": Keywords.propertyNames,
"required": JsonSchema.Keywords.required,
"title": JsonSchema.Keywords.metaData,
"type": JsonSchema.Keywords.type,
"uniqueItems": JsonSchema.Keywords.uniqueItems
});
@@ -0,0 +1,49 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core, Schema } = require("@hyperjump/json-schema-core");
const Keywords = require("./keywords");
Schema.setConfig("http://json-schema.org/draft-07/schema", "bundlingLocation", "/definitions");
Core.defineVocabulary("http://json-schema.org/draft-07/schema", {
"validate": Keywords.validate,
"additionalItems": Keywords.additionalItems6,
"additionalProperties": Keywords.additionalProperties6,
"allOf": Keywords.allOf,
"anyOf": Keywords.anyOf,
"const": JsonSchema.Keywords.const,
"contains": Keywords.contains,
"default": JsonSchema.Keywords.metaData,
"definitions": JsonSchema.Keywords.definitions,
"dependencies": Keywords.dependencies,
"description": JsonSchema.Keywords.metaData,
"enum": JsonSchema.Keywords.enum,
"exclusiveMaximum": JsonSchema.Keywords.exclusiveMaximum,
"exclusiveMinimum": JsonSchema.Keywords.exclusiveMinimum,
"format": JsonSchema.Keywords.metaData,
"if": Keywords.if,
"then": Keywords.then,
"else": Keywords.else,
"items": Keywords.items,
"maxItems": JsonSchema.Keywords.maxItems,
"maxLength": JsonSchema.Keywords.maxLength6,
"maxProperties": JsonSchema.Keywords.maxProperties,
"maximum": JsonSchema.Keywords.maximum,
"minItems": JsonSchema.Keywords.minItems,
"minLength": JsonSchema.Keywords.minLength6,
"minProperties": JsonSchema.Keywords.minProperties,
"minimum": JsonSchema.Keywords.minimum,
"multipleOf": JsonSchema.Keywords.multipleOf,
"not": Keywords.not,
"oneOf": Keywords.oneOf,
"pattern": JsonSchema.Keywords.pattern,
"patternProperties": Keywords.patternProperties,
"properties": Keywords.properties,
"propertyNames": Keywords.propertyNames,
"readOnly": JsonSchema.Keywords.metaData,
"required": JsonSchema.Keywords.required,
"title": JsonSchema.Keywords.metaData,
"type": JsonSchema.Keywords.type,
"uniqueItems": JsonSchema.Keywords.uniqueItems,
"writeOnly": JsonSchema.Keywords.metaData
});
@@ -0,0 +1,33 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core, Schema } = require("@hyperjump/json-schema-core");
const Keywords = require("./keywords");
Schema.setConfig("https://json-schema.org/draft/2019-09/schema", "bundlingLocation", "/$defs");
Core.defineVocabulary("https://json-schema.org/draft/2019-09/vocab/core", {
"validate": Keywords.validate,
"$defs": JsonSchema.Keywords.definitions,
"$recursiveRef": JsonSchema.Keywords.dynamicRef,
"$ref": Keywords.ref
});
Core.defineVocabulary("https://json-schema.org/draft/2019-09/vocab/applicator", {
"additionalItems": Keywords.additionalItems6,
"additionalProperties": Keywords.additionalProperties6,
"allOf": Keywords.allOf,
"anyOf": Keywords.anyOf,
"contains": Keywords.containsMinContainsMaxContains,
"dependentSchemas": Keywords.dependentSchemas,
"if": Keywords.if,
"then": Keywords.then,
"else": Keywords.else,
"items": Keywords.items,
"not": Keywords.not,
"oneOf": Keywords.oneOf,
"patternProperties": Keywords.patternProperties,
"properties": Keywords.properties,
"propertyNames": Keywords.propertyNames,
"unevaluatedItems": Keywords.unevaluatedItems,
"unevaluatedProperties": Keywords.unevaluatedProperties
});
@@ -0,0 +1,36 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core, Schema } = require("@hyperjump/json-schema-core");
const Keywords = require("./keywords");
Schema.setConfig("https://json-schema.org/draft/2020-12/schema", "bundlingLocation", "/$defs");
Core.defineVocabulary("https://json-schema.org/draft/2020-12/vocab/core", {
"validate": Keywords.validate,
"$defs": JsonSchema.Keywords.definitions,
"$dynamicRef": JsonSchema.Keywords.dynamicRef,
"$ref": Keywords.ref
});
Core.defineVocabulary("https://json-schema.org/draft/2020-12/vocab/applicator", {
"additionalProperties": Keywords.additionalProperties6,
"allOf": Keywords.allOf,
"anyOf": Keywords.anyOf,
"contains": Keywords.containsMinContainsMaxContains,
"dependentSchemas": Keywords.dependentSchemas,
"if": Keywords.if,
"then": Keywords.then,
"else": Keywords.else,
"items": Keywords.items202012,
"not": Keywords.not,
"oneOf": Keywords.oneOf,
"patternProperties": Keywords.patternProperties,
"prefixItems": Keywords.tupleItems,
"properties": Keywords.properties,
"propertyNames": Keywords.propertyNames
});
Core.defineVocabulary("https://json-schema.org/draft/2020-12/vocab/unevaluated", {
"unevaluatedItems": Keywords.unevaluatedItems,
"unevaluatedProperties": Keywords.unevaluatedProperties
});
@@ -0,0 +1,47 @@
import type { Core, Schema, SchemaDocument, SchemaObject, InvalidSchemaError } from "@hyperjump/json-schema-core";
export type JsonSchemaBundler = {
add: typeof Schema.add;
get: typeof Schema.get;
bundle: (schemaDoc: SchemaDocument, options?: BundleOptions) => Promise<SchemaObject>;
FULL: "full";
FLAT: "flat";
URI: "uri";
UUID: "uuid";
setMetaOutputFormat: typeof Core.setMetaOutputFormat;
setShouldMetaValidate: typeof Core.setShouldMetaValidate;
FLAG: typeof Core.FLAG;
BASIC: typeof Core.BASIC;
DETAILED: typeof Core.DETAILED;
VERBOSE: typeof Core.VERBOSE;
InvalidSchemaError: typeof InvalidSchemaError;
};
export type BundleOptions = {
alwaysIncludeDialect?: boolean;
bundleMode?: BundleMode;
definitionNamingStrategy: DefinitionNamingStrategy;
};
export type BundleMode = JsonSchemaBundler["FULL"] | JsonSchemaBundler["FLAT"];
export type DefinitionNamingStrategy = JsonSchemaBundler["URI"] | JsonSchemaBundler["UUID"];
export const add: JsonSchemaBundler["add"];
export const get: JsonSchemaBundler["get"];
export const bundle: JsonSchemaBundler["bundle"];
export const FULL: JsonSchemaBundler["FULL"];
export const FLAT: JsonSchemaBundler["FLAT"];
export const URI: JsonSchemaBundler["URI"];
export const UUID: JsonSchemaBundler["UUID"];
export const setMetaOutputFormat: JsonSchemaBundler["setMetaOutputFormat"];
export const setShouldMetaValidate: JsonSchemaBundler["setShouldMetaValidate"];
export const FLAG: JsonSchemaBundler["FLAG"];
export const BASIC: JsonSchemaBundler["BASIC"];
export const DETAILED: JsonSchemaBundler["DETAILED"];
export const VERBOSE: JsonSchemaBundler["VERBOSE"];
export * from "@hyperjump/json-schema";
declare const jsonSchemaBundler: JsonSchemaBundler;
export default jsonSchemaBundler;
@@ -0,0 +1,82 @@
const { v4: uuid } = require("uuid");
const JsonSchema = require("@hyperjump/json-schema");
const JsonPointer = require("@hyperjump/json-pointer");
const { Core, Schema, InvalidSchemaError } = require("@hyperjump/json-schema-core");
const Bundle = require("./core");
const { splitUri } = require("./common");
require("./draft-04");
require("./draft-06");
require("./draft-07");
require("./draft-2019-09");
require("./draft-2020-12");
const FULL = "full";
const FLAT = "flat";
const URI = "uri";
const UUID = "uuid";
const defaultOptions = {
alwaysIncludeDialect: false,
bundleMode: FLAT,
definitionNamingStrategy: URI
};
const bundle = async (schemaDoc, options = {}) => {
const fullOptions = { ...defaultOptions, ...options };
const { ast, schemaUri } = await Core.compile(schemaDoc);
const subSchemaUris = new Set();
Bundle.collectExternalIds(schemaUri, subSchemaUris, ast, {});
const externalIds = new Set([...subSchemaUris].map((uri) => splitUri(uri)[0]));
externalIds.delete(schemaDoc.id);
const bundled = Schema.toSchema(schemaDoc, {
includeEmbedded: fullOptions.bundleMode === FULL
});
const bundlingLocation = Schema.getConfig(schemaDoc.schemaVersion, "bundlingLocation");
if (JsonPointer.get(bundlingLocation, bundled) === undefined && externalIds.size > 0) {
JsonPointer.assign(bundlingLocation, bundled, {});
}
for (const uri of externalIds.values()) {
const externalSchema = await JsonSchema.get(uri);
const embeddedSchema = Schema.toSchema(externalSchema, {
parentId: schemaDoc.id,
parentDialect: fullOptions.alwaysIncludeDialect ? "" : schemaDoc.schemaVersion,
includeEmbedded: fullOptions.bundleMode === FULL
});
let id;
if (fullOptions.definitionNamingStrategy === URI) {
const embeddedToken = Schema.getConfig(externalSchema.schemaVersion, "embeddedToken");
id = embeddedSchema[embeddedToken];
} else if (fullOptions.definitionNamingStrategy === UUID) {
id = uuid();
} else {
throw Error(`Unknown definition naming stragety: ${fullOptions.definitionNamingStrategy}`);
}
const pointer = JsonPointer.append(id, bundlingLocation);
JsonPointer.assign(pointer, bundled, embeddedSchema);
}
return bundled;
};
module.exports = {
add: JsonSchema.add,
get: Schema.get,
bundle: bundle,
FULL: FULL,
FLAT: FLAT,
URI: URI,
UUID: UUID,
setMetaOutputFormat: Core.setMetaOutputFormat,
setShouldMetaValidate: Core.setShouldMetaValidate,
FLAG: Core.FLAG,
BASIC: Core.BASIC,
DETAILED: Core.DETAILED,
VERBOSE: Core.VERBOSE,
InvalidSchemaError: InvalidSchemaError
};
@@ -0,0 +1,17 @@
import Bundler from "./index.js";
export const add = Bundler.add;
export const get = Bundler.get;
export const bundle = Bundler.bundle;
export const FULL = Bundler.FULL;
export const FLAT = Bundler.FLAT;
export const URI = Bundler.URI;
export const UUID = Bundler.UUID;
export const setMetaOutputFormat = Bundler.setMetaOutputFormat;
export const setShouldMetaValidate = Bundler.setShouldMetaValidate;
export const FLAG = Bundler.FLAG;
export const BASIC = Bundler.BASIC;
export const DETAILED = Bundler.DETAILED;
export const VERBOSE = Bundler.VERBOSE;
export const InvalidSchemaError = Bundler.InvalidSchemaError;
@@ -0,0 +1,221 @@
const JsonSchema = require("@hyperjump/json-schema");
const { Core } = require("@hyperjump/json-schema-core");
const Bundle = require("./core");
const validate = {
...JsonSchema.Keywords.validate,
collectExternalIds: (schemaUri, externalIds, ast, dynamicAnchors) => {
const nodes = ast[schemaUri][2];
if (externalIds.has(schemaUri) || typeof nodes === "boolean") {
return;
}
externalIds.add(schemaUri);
for (const [keywordId, , keywordValue] of nodes) {
const keyword = Core.getKeyword(keywordId);
if (keyword.collectExternalIds) {
keyword.collectExternalIds(keywordValue, externalIds, ast, dynamicAnchors);
}
}
}
};
const ref = {
...JsonSchema.Keywords.ref,
collectExternalIds: Bundle.collectExternalIds
};
const additionalItems = {
...JsonSchema.Keywords.additionalItems,
collectExternalIds: ([, additionalItems], externalIds, ast, dynamicAnchors) => {
if (typeof additionalItems === "string") {
Bundle.collectExternalIds(additionalItems, externalIds, ast, dynamicAnchors);
}
}
};
const additionalProperties = {
...JsonSchema.Keywords.additionalProperties,
collectExternalIds: ([, , additionalProperties], externalIds, ast, dynamicAnchors) => {
if (typeof additionalProperties === "string") {
Bundle.collectExternalIds(additionalProperties, externalIds, ast, dynamicAnchors);
}
}
};
const additionalItems6 = {
...JsonSchema.Keywords.additionalItems6,
collectExternalIds: ([, additionalItems], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(additionalItems, externalIds, ast, dynamicAnchors);
}
};
const additionalProperties6 = {
...JsonSchema.Keywords.additionalProperties6,
collectExternalIds: ([, , additionalProperties], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(additionalProperties, externalIds, ast, dynamicAnchors);
}
};
const allOf = {
...JsonSchema.Keywords.allOf,
collectExternalIds: (allOf, externalIds, ast, dynamicAnchors) => {
allOf.forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const anyOf = {
...JsonSchema.Keywords.anyOf,
collectExternalIds: (anyOf, externalIds, ast, dynamicAnchors) => {
anyOf.forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const contains = {
...JsonSchema.Keywords.contains,
collectExternalIds: Bundle.collectExternalIds
};
const containsMinContainsMaxContains = {
...JsonSchema.Keywords.containsMinContainsMaxContains,
collectExternalIds: ({ contains }, externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(contains, externalIds, ast, dynamicAnchors);
}
};
const dependencies = {
...JsonSchema.Keywords.dependencies,
collectExternalIds: (dependentSchemas, externalIds, ast, dynamicAnchors) => {
Object.values(dependentSchemas).forEach(([, dependency]) => {
if (typeof dependency === "string") {
Bundle.collectExternalIds(dependency, externalIds, ast, dynamicAnchors);
}
});
}
};
const dependentSchemas = {
...JsonSchema.Keywords.dependentSchemas,
collectExternalIds: (dependentSchemas, externalIds, ast, dynamicAnchors) => {
Object.values(dependentSchemas).forEach(([, schemaUri]) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const if_ = {
...JsonSchema.Keywords.if,
collectExternalIds: Bundle.collectExternalIds
};
const then = {
...JsonSchema.Keywords.then,
collectExternalIds: ([, then], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(then, externalIds, ast, dynamicAnchors);
}
};
const else_ = {
...JsonSchema.Keywords.else,
collectExternalIds: ([, elseSchema], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(elseSchema, externalIds, ast, dynamicAnchors);
}
};
const items = {
...JsonSchema.Keywords.items,
collectExternalIds: (items, externalIds, ast, dynamicAnchors) => {
if (typeof items === "string") {
Bundle.collectExternalIds(items, externalIds, ast, dynamicAnchors);
} else {
items.forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
}
};
const items202012 = {
...JsonSchema.Keywords.items202012,
collectExternalIds: ([, items], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(items, externalIds, ast, dynamicAnchors);
}
};
const not = {
...JsonSchema.Keywords.not,
collectExternalIds: Bundle.collectExternalIds
};
const oneOf = {
...JsonSchema.Keywords.oneOf,
collectExternalIds: (oneOf, externalIds, ast, dynamicAnchors) => {
oneOf.forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const patternProperties = {
...JsonSchema.Keywords.patternProperties,
collectExternalIds: (patternProperties, externalIds, ast, dynamicAnchors) => {
patternProperties.forEach(([, schemaUri]) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const tupleItems = {
...JsonSchema.Keywords.tupleItems,
collectExternalIds: (tupleItems, externalIds, ast, dynamicAnchors) => {
tupleItems.forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const properties = {
...JsonSchema.Keywords.properties,
collectExternalIds: (properties, externalIds, ast, dynamicAnchors) => {
Object.values(properties).forEach((schemaUri) => Bundle.collectExternalIds(schemaUri, externalIds, ast, dynamicAnchors));
}
};
const propertyNames = {
...JsonSchema.Keywords.propertyNames,
collectExternalIds: Bundle.collectExternalIds
};
const unevaluatedItems = {
...JsonSchema.Keywords.unevaluatedItems,
collectExternalIds: ([, unevaluatedItems], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(unevaluatedItems, externalIds, ast, dynamicAnchors);
}
};
const unevaluatedProperties = {
...JsonSchema.Keywords.unevaluatedProperties,
collectExternalIds: ([, unevaluatedProperties], externalIds, ast, dynamicAnchors) => {
Bundle.collectExternalIds(unevaluatedProperties, externalIds, ast, dynamicAnchors);
}
};
module.exports = {
validate,
ref,
additionalItems,
additionalItems6,
additionalProperties,
additionalProperties6,
allOf,
anyOf,
contains,
containsMinContainsMaxContains,
dependencies,
dependentSchemas,
if: if_,
then,
else: else_,
items,
items202012,
not,
oneOf,
patternProperties,
tupleItems,
properties,
propertyNames,
unevaluatedItems,
unevaluatedProperties
};
@@ -0,0 +1,99 @@
{
"_args": [
[
"@hyperjump/json-schema-bundle@0.1.3",
"/Users/wookiee/sources/asyncapi-node/tools/bundler"
]
],
"_from": "@hyperjump/json-schema-bundle@0.1.3",
"_id": "@hyperjump/json-schema-bundle@0.1.3",
"_inBundle": false,
"_integrity": "sha512-UjmmtyIgaMXRXKmkJDQhvGAQFSfaPYBRue4tk3qeISrD468vziCWI2Km0RgfeXVxgy5xgqEPyi9DLXUqD4KWDQ==",
"_location": "/@hyperjump/json-schema-bundle",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "@hyperjump/json-schema-bundle@0.1.3",
"name": "@hyperjump/json-schema-bundle",
"escapedName": "@hyperjump%2fjson-schema-bundle",
"scope": "@hyperjump",
"rawSpec": "0.1.3",
"saveSpec": null,
"fetchSpec": "0.1.3"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/@hyperjump/json-schema-bundle/-/json-schema-bundle-0.1.3.tgz",
"_spec": "0.1.3",
"_where": "/Users/wookiee/sources/asyncapi-node/tools/bundler",
"author": {
"name": "Jason Desrosiers",
"email": "jdesrosi@gmail.com"
},
"bugs": {
"url": "https://github.com/hyperjump-io/json-schema-bundle/issues"
},
"dependencies": {
"@hyperjump/json-schema": "^0.18.3",
"uuid": "^8.3.2"
},
"description": "A tool for bundling JSON Schema documents",
"devDependencies": {
"@rollup/plugin-commonjs": "^21.0.1",
"@rollup/plugin-node-resolve": "^13.0.6",
"@types/chai": "^4.2.22",
"@types/mocha": "^9.0.0",
"@types/uuid": "^8.3.3",
"@typescript-eslint/eslint-plugin": "^5.3.1",
"@typescript-eslint/parser": "^5.3.1",
"chai": "^4.3.4",
"eslint": "^8.2.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.2",
"mocha": "^9.1.3",
"rollup": "^2.59.0",
"rollup-plugin-terser": "^7.0.2",
"ts-node": "^10.4.0",
"typescript": "^4.4.4"
},
"exports": {
"require": "./lib/index.js",
"import": "./lib/index.mjs"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jdesrosiers"
},
"homepage": "https://github.com/hyperjump-io/json-schema-bundle#readme",
"keywords": [
"JSON Schema",
"json-schema",
"jsonschema",
"schema",
"bundle",
"bundler",
"$ref",
"external",
"reference",
"Compound Schema Document",
"embedded"
],
"license": "MIT",
"main": "lib/index.js",
"name": "@hyperjump/json-schema-bundle",
"repository": {
"type": "git",
"url": "git+https://github.com/hyperjump-io/json-schema-bundle.git"
},
"scripts": {
"build": "rollup --config rollup.config.js",
"clean": "xargs -a .gitignore rm -rf",
"lint": "eslint lib",
"prepublishOnly": "npm run build",
"test": "mocha --require ts-node/register 'lib/**/*.spec.ts'"
},
"version": "0.1.3"
}
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Jason Desrosiers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,753 @@
# Hyperjump - JSON Schema Core
JSON Schema Core (JSC) is a framework for building JSON Schema based validators
and other tools.
It includes tools for:
* Working with schemas (`$id`, `$schema`, `$ref`, etc)
* Working with instances
* Building custom keywords
* Building custom vocabularies
* Standard output formats
* Custom output formats
* Compiling schemas for validating multiple instances
## Install
JSC is designed to run in a vanilla node.js environment, but has no dependencies
on node.js specific libraries so it can be bundled for the browser. No
compilers, preprocessors, or bundlers are used.
JSC includes support for node.js JavaScript (CommonJS and ES Modules),
TypeScript, and browsers.
### Node.js
```bash
npm install @hyperjump/json-schema-core
```
### Browser
When in a browser context, JSC is designed to use the browser's `fetch`
implementation instead of a node.js fetch clone. The Webpack bundler does this
properly without any extra configuration, but if you are using the Rollup
bundler you will need to include the `browser: true` option in your Rollup
configuration.
```javascript
plugins: [
resolve({
browser: true
}),
commonjs()
]
```
## Schema
A Schema Document (SDoc) is a structure that includes the schema, the id, and a
JSON Pointer. The "value" of an SDoc is the portion of the schema that the JSON
pointer points to. This allows an SDoc to represent any value in the schema
while maintaining enough context to follow `$ref`s and track the position in the
document.
* **Schema.add**: (schema: object, url?: URI, schemaVersion?: string) => URI
Load a schema. Returns the identifier for the schema. See the "$id" and
"$schema" sections for more details.
* **Schema.get**: (url: URI, contextDoc?: SDoc) => Promise<SDoc>
Fetch a schema. Schemas can come from an HTTP request, a file, or a schema
that was added with `Schema.add`.
* **Schema.uri**: (doc: SDoc) => URI
Returns a URI including the id and JSON Pointer that represents a value
within the schema.
* **Schema.getAnchorPointer**: (doc: SDoc, anchor: string) => any
Get a JSON Pointer for the location in the schema that the anchor refers to.
* **Schema.value**: (doc: SDoc) => any
The portion of the schema the document's JSON Pointer points to.
* **Schema.typeOf**: (doc: SDoc, type: string) => boolean
Determines if the JSON type of the given doc matches the given type
* **Schema.has**: (key: string, doc: SDoc) => Promise<SDoc>
Similar to `key in schema`.
* **Schema.step**: (key: string, doc: SDoc) => Promise<SDoc>
Similar to `schema[key]`, but returns an SDoc.
* **Schema.entries**: (doc: SDoc) => Promise<[[string, SDoc]]>
Similar to `Object.entries`, but returns SDocs for values.
* **Schema.keys**: (doc: SDoc) => [string]
Similar to `Object.keys`.
* **Schema.map**: (fn: (item: Promise<SDoc>, index: integer) => T, doc: SDoc) => Promise<[T]>
A `map` function for an SDoc whose value is an array.
* **Schema.length**: (doc: SDoc) => number
Similar to `Array.prototype.length`.
* **Schema.toSchema**: (doc: SDoc, options: ToSchemaOptions) => object
Get a raw schema from a Schema Document.
* **ToSchemaOptions**: object
* parentId: string (default: "") -- `file://` URIs will be generated
relative to this path.
* parentDialect: string (default: "") -- If the dialect of the schema
* matches this value, the `$schema` keyword will be omitted.
* includeEmbedded: boolean (default: true) -- If false, embedded schemas
will be unbundled from the schema.
### Schema Identification
JSC requires that all schemas are identified by at least one URI. There are two
types of schema identifiers, internal and external. An internal identifier is an
identifier that is specified within the schema using `$id`. An external
identifier is an identifier that is specified outside of the schema. In JSC, an
external identifier can be either the URL a schema is retrieved with, or the
identifier specified when using `Schema.add` to load a schema.
JSC can fetch schemas from the web or from the file system, but when fetching
from the file system, there are limitations for security reasons. If
your schema has an identifier with an http scheme (**http**://example.com), it's
not allowed to reference schemas with a file scheme
(**file**:///path/to/my/schemas).
Internal identifiers (`$id`s) are resolved against the external identifier of
the schema (if one exists) and the resulting URI is used to identify the schema.
All identifiers must be absolute URIs. External identifiers are required to be
absolute URIs and internal identifiers must resolve to absolute URIs.
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
// Example: Inline schema with external identifier
const schemaJson = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
}
Schema.add(schemaJson, "http://example.com/schemas/string");
const schema = await Schema.get("http://example.com/schemas/string");
// Example: Inline schema with internal identifier
const schemaJson = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/schemas/string",
"type": "string"
}
Schema.add(schemaJson);
const schema = await Schema.get("http://example.com/schemas/string");
// Example: Inline schema with no identifier
const schemaJson = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
}
Schema.add(schemaJson); // Error: Couldn't determine an identifier for the schema
// Given the following schema at http://example.com/schemas/foo
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "$id": "http://example.com/schemas/string",
// "type": "string"
// }
// Example: Fetch schema from external HTTP identifier
const schema = await Schema.get("http://example.com/schemas/string");
// Example: Fetch schema from internal identifier
const schema = await Schema.get("http://example.com/schemas/foo");
// Given the following schema at http://example.com/schemas/bar
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "$id": "string",
// "type": "string"
// }
// Example: Fetch schema from internal identifier resolved against external identifier
const schema = await Schema.get("http://example.com/schemas/string");
// Given the following schema at /path/to/my/schemas/string.schema.json
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "type": "string"
// }
// Example: Fetch schema from external FILE identifier
const schema = await Schema.get("file:///path/to/my/schemas/string.schema.json");
// Given the following schema at /path/to/my/schemas/string.schema.json
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "type": "string"
// }
//
// Given the following schema at http://example.com/schemas/baz
// {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
// "$ref": "file:///path/to/my/schemas/string.schema.json"
// }
// Example: Reference file from network context
const schema = await Schema.get("http://example.com/schemas/baz");
await Core.validate(schema); // Error: Can't access file resource from network context
```
### $schema
JSC is designed to support multiple drafts of JSON Schema and it makes no
assumption about what draft your schema uses. You need to specify it in some
way. The preferred way is to the use `$schema` in all of your schemas, but you
can also specify what draft to use when adding a schema using `Schema.add`. If a
draft is specified in `Schema.add` and the schema has a `$schema`, the
`$schema` will be used. If no draft is specified, you will get an error.
```javascript
// Example: Internal schema version
const schemaJSON = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/schemas/string",
"type": "string"
};
Schema.add(schemaJSON);
// Example: External schema version
const schemaJSON = {
"type": "string"
};
Schema.add(schemaJSON, "http://example.com/schemas/string", "https://json-schema.org/draft/2020-12/schema");
// Example: No schema version
const schemaJSON = {
"$id": "http://example.com/schemas/string",
"type": "string"
};
Schema.add(schemaJSON); // Error: Couldn't determine schema version
// Given the following schema at http://example.com/schemas/foo
// {
// "type": "string"
// }
// Example: No schema version external
const schema = Schema.get("http://example.com/schemas/string"); // Error: Couldn't determine schema version
```
## Instance
An Instance Document (IDoc) is like a Schema Document (SDoc) except with much
more limited functionality.
* **Instance.cons**: (instance: any) => IDoc
Construct a IDoc from a value.
* **Instance.get**: (url: URI, contextDoc: IDoc) => IDoc
Apply a same-resource reference to a IDoc.
* **Instance.uri**: (doc: IDoc) => URI
Returns a URI including the id and JSON Pointer that represents a value
within the instance.
* **Instance.value**: (doc: IDoc) => any
The portion of the instance that the document's JSON Pointer points to.
* **Instance.has**: (key: string, doc: IDoc) => any
Similar to `key in instance`.
* **Instance.typeOf**: (doc: IDoc, type: string) => boolean
Determines if the JSON type of the given doc matches the given type.
* **Instance.step**: (key: string, doc: IDoc) => IDoc
Similar to `schema[key]`, but returns a IDoc.
* **Instance.entries**: (doc: IDoc) => [string, IDoc]
Similar to `Object.entries`, but returns IDocs for values.
* **Instance.keys**: (doc: IDoc) => [string]
Similar to `Object.keys`.
* **Instance.map**: (fn: (item: IDoc, index: integer) => T, doc: IDoc) => [T]
A `map` function for a IDoc whose value is an array.
* **Instance.reduce**: (fn: (accumulator: T, item: IDoc, index: integer) => T, initial: T, doc: IDoc) => T
A `reduce` function for a IDoc whose value is an array.
* **Instance.every**: (fn: (doc: IDoc, index: integer) => boolean, doc: IDoc) => boolean
An `every` function for a IDoc whose value is an array.
* **Instance.some**: (fn: (doc: IDoc, index: integer) => boolean, doc: IDoc) => boolean
A `some` function for a IDoc whose value is an array.
* **Instance.length**: (doc: IDoc) => number
Similar to `Array.prototype.length`.
## Validation
Some helper functions are provided to assist in building validation functions.
* **Core.validate**: (schema: SDoc, value: any, outputFormat: OutputFormat = Core.FLAG) => Promise<Output>
A curried function that validates a JavaScript value against a schema.
* **Core.compile**: (schema: SDoc) => Promise<CompiledSchema>
Compile a schema to be used interpreted later. A compiled schema is a JSON
serializable structure that can be serialized an restored for later use.
* **Core.interpret**: (schema: CompiledSchema, instance: Instance, outputFormat = Core.FLAG) => <Output>
A curried function for validating an instance against a compiled schema.
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
// Example: Inline schema with external identifier
Schema.add({
"$id": "http://example.com/schemas/string",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
});
const schema = await Schema.get("http://example.com/schemas/string");
// Generate a validation function from a Schema Document
const isString = await Core.validate(schema);
// Validate a value from a Schema Document in one step
const result = await Core.validate(schema, "foo");
// Compile a Schema Document for use later
const compiledSchema = await Core.compile(schema);
// Generate a validation function from a compiled schema
const isString = Core.interpret(compiledSchema);
// Validate an instance from a compiled schema
const result = Core.interpret(compiledSchema, Instance.cons("foo"));
```
## Output
JSC supports all of the standard output formats specified for JSON Schema
draft 2019-09 and 2020-12 and is separately configurable for instance validation
and meta-validtion.
This implementation does not include the suggested `keywordLocation` property in
the output unit. I think `absoluteKeywordLocation`+`instanceLocation` is
sufficient for debugging and it's awkward for the output to produce JSON
Pointers that potentially won't resolve because they cross schema boundaries.
This implementation includes an extra property in the output unit called
`keyword`. This is an identifier (URI) for the keyword that was validated. With
the standard output unit fields, we can see what keyword was validated by
inspecting the last segment of the `absoluteKeywordLocation` property. But,
since JSC can support multiple JSON Schema versions, we would have to pull up
the actual schema to find what draft was used. The `schema` property gives us
enough information to not have to go back to the schema to know what draft is
being used.
By default JSC will validate all schemas against their meta-schema. However, the
only time you really need this is when developing schemas. When JSC is running
in a production environment or you are working with third-party schemas that you
trust to be correct, you can turn off meta-validation to boost performance.
* **Core.setMetaOutputFormat**: (outputFormat: OutputFormat) => undefined
Set the output format used for schema validation. Default Core.DETAILED
* **Core.setShouldMetaValidate**: (shouldMetaValidate: boolean) => undefined
Turn schema validation on or off. Default true
* **OutputFormat**: An enum of available output formats
* Core.FLAG - Default for instance validation
* Core.BASIC
* Core.DETAILED - Default for meta-validation
* Core.VERBOSE
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
// Example: Specify instance validation output format
Schema.add({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/schemas/string",
"type": "string"
});
const schema = await Schema.get("http://example.com/schemas/string");
const isString = await Core.validate(schema);
const output = isString(42, Core.BASIC); // => {
// "keyword": "https://json-schema.org/draft/2020-12/schema",
// "absoluteKeywordLocation": "http://example.com/schemas/string#",
// "instanceLocation": "#",
// "valid": false,
// "errors": [
// {
// "keyword": "https://json-schema.org/draft/2020-12/schema#type",
// "absoluteKeywordLocation": "http://example.com/schemas/string#/type",
// "instanceLocation": "#",
// "valid": false
// }
// ]
// }
// Example: Specify meta-validation output format
Schema.add({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/schemas/foo",
"type": "this-is-not-a-valid-type"
});
Core.setMetaOutputFormat(Core.BASIC);
const schema = await Schema.get("http://example.com/schemas/foo");
const isString = await Core.validate(schema); // InvalidSchemaError: {
// "keyword": "https://json-schema.org/draft/2020-12/schema",
// "absoluteKeywordLocation": "https://json-schema.org/draft/2020-12/schema#",
// "instanceLocation": "#",
// "valid": false,
// "errors": [
// {
// "keyword": "https://json-schema.org/draft/2020-12/schema#allOf",
// "absoluteKeywordLocation": "https://json-schema.org/draft/2020-12/schema#/allOf",
// "instanceLocation": "#",
// "valid": false
// }
// ...
// ]
// }
// Example: Turn off schema validation
Core.setShouldMetaValidate(false);
const schema = await Schema.get("http://example.com/schemas/foo"); // Load invalid schema
const isString = await Core.validate(schema); // Schema compilation succeeds even though schema is invalid
```
## PubSub
JSC emits events that you can subscribe to and work with however your
application needs. For now, the only event is the `"result"` event that emits
output units every time a keyword is validated. Internally, JSC uses these
events to build standard output formats. Other events can be added when
use-cases are identified for them.
```javascript
const PubSub = require("pubsub-js");
const { Core, Schema } = require("@hyperjump/json-schema-core");
Schema.add({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "http://example.com/schemas/string",
"type": "string"
});
const schema = await Schema.get("http://example.com/schemas/string");
const isString = await Core.validate(schema);
const results = [];
const subscriptionToken = PubSub.subscribe("result", (message, result) => {
results.push(result);
});
isString(42);
PubSub.unsubscribe(subscriptionToken);
results; // => [
// {
// "keyword": "https://json-schema.org/draft/2020-12/schema",
// "absoluteKeywordLocation": "http://example.com/schemas/string#",
// "instanceLocation": "#",
// "valid": false
// },
// {
// "keyword": "https://json-schema.org/draft/2020-12/schema#type",
// "absoluteKeywordLocation": "http://example.com/schemas/string#/type",
// "instanceLocation": "#",
// "valid": false
// }
// ]
```
## Customize
JSC uses a micro-kernel architecture, so it's highly customizable. Everything
is a plugin, even the validation logic. This allows you to use JSC as a
framework for building other types of JSON Schema based tools such as code
generators or form generators.
In addition to this documentation you should be able to look at the
[JSV](https://github.com/hyperjump-io/json-schema-validator) code to see an
example of how to add your custom plugins because it's all implemented the same
way.
* **Schema.setConfig**: (schemaVersion: string, configName: string, configValue: string) => undefined
Set a configuration value for a schemaVersion.
* **Schema.getConfig**: (schemaVersion: string, configName: string) => any
Get a configuration value for a schemaVersion.
### References
The `$ref` keyword has changed a couple times over the last several drafts. JSC
allows you to configure which version(s) of `$ref`s you want to support. There
are several types of references.
* **JSON Reference**: *(draft-04/06/07)* In draft-04, references were defined in
a separate spec from JSON Schema. The JSON Schema spec only constrained `$ref`
in how URIs are resolved with respect to `id`. Then in draft-06/07, JSON
Schema absorbed the JSON Reference spec and further constrained `$ref` to only
be allowed where schemas are allowed. JSC doesn't support this constraint
because it can't be done in a keyword agnostic way.
* **JSON Schema Reference**: *(draft-2019-09+)* In draft 2019-09, a reference
was changed from being an object with a `$ref` property to the value of a
`$ref` keyword. This allowed `$ref` to behave more like a keyword.
* **Dynamic JSON Schema Reference**: *(draft-2019-09+)* In draft 2019-09, the
concept of a dynamic scope reference was added to make it easier to extend
recursive schemas. This was added to support building custom meta-schemas.
Draft-04/6/7 style references are configured via dialect configuration using
`Schema.setConfig`. Draft-2019-09+ style references are just keywords and can be
added as part of a vocabulary.
```javascript
const { Schema } = require("@hyperjump/json-schema-core");
// Configure draft-04/6/7 style references
Schema.setConfig("http://json-schema.org/draft-04/schema", "jrefToken", "$ref");
// Configure draft-2019-09+ style references
Core.defineVocabulary("https://example.com/draft/custom/vocab/core", {
"$ref": Keywords.ref,
"$dynamicRef": Keywords.dynamicRef,
...
});
```
### Identifiers
The `$id` keyword has seen it's fair share of churn as well. Although the spec
around this keyword was rewritten and clarified many times, the vast majority of
changes have simply been name changes. JSC allows you to configure which version
you want to support.
* **id**: *(draft-04)* A base URI used to resolve reference URIs.
* **$id**: *(draft-06/07)* Same as `id`, just a different name.
* **$id**: *(draft-2019-09+)* Same as `$id` except with same-document reference
support split out into `$anchor`.
* **$anchor**: *(draft-2019-09+)* Same-document reference.
* **$recursiveAnchor**: *(draft-2019-09)* Dynamic scope same-document reference.
Value is a boolean that is only allowed at the root of a schema.
* **$dynamicAnchor**: *(draft-2020-12)* Dynamic scope same-document reference.
Value is a string and works like `$anchor`.
In draft-2019-09, `$id` was redefined from being a resolution scope modifier to
being an inlined reference. This means that JSON Pointers can not cross into
schemas with `$id`s. So far, JSC only supports these bounded `$id`s. If I come
up with a way to relax this constraint for old draft implementations, I will,
but since there is no sensible reason to want such a thing, it's a low priority.
In JSON Schema, properties called `$id` are only considered identifiers if they
appear in a schema. JSC is keyword agnostic, so it doesn't know what is a schema
and what isn't. Therefore, an `$id` might be treated as an identifier in places
it's not expected to. This is unlikely, but not impossible.
```javascript
const { Schema } = require("@hyperjump/json-schema-core");
// Configure draft-2019-09+ style identifiers
Schema.setConfig("https://json-schema.org/draft/2020-12/schema", "baseToken", "$id");
Schema.setConfig("https://json-schema.org/draft/2002-12/schema", "embeddedToken", "$id");
Schema.setConfig("https://json-schema.org/draft/2020-12/schema", "anchorToken", "$anchor");
Schema.setConfig("https://json-schema.org/draft/2020-12/schema", "recursiveAnchorToken", "$recursiveAnchor");
// Configure draft-06/7 style references
Schema.setConfig("http://json-schema.org/draft-04/schema", "baseToken", "$id");
Schema.setConfig("http://json-schema.org/draft-04/schema", "embeddedToken", "$id");
Schema.setConfig("http://json-schema.org/draft-04/schema", "anchorToken", "$id");
// Configure draft-04 style references
Schema.setConfig("http://json-schema.org/draft-04/schema", "baseToken", "id");
Schema.setConfig("http://json-schema.org/draft-04/schema", "embeddedToken", "id");
Schema.setConfig("http://json-schema.org/draft-04/schema", "anchorToken", "id");
```
### Custom Meta-Schemas
Let's say you want to use a custom meta-schema that does stricter validation
than the standard meta-schema. Once you have your custom meta-schema ready, it's
just a couple lines of code to start using it.
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
// Optional: Load your meta-schema. If you don't do this, JSC will fetch it
// using it's identifier when it's needed.
Schema.add({
"$id": "https://example.com/draft/2020-12-strict/schema",
"$schema": "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/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
},
...
});
// Use the URI you chose for your meta-schema for the `$schema` in you schemas.
Schema.add({
"$id": "http://example.com/schemas/string",
"$schema": "http://example.com/draft/2020-12-strict/schema",
"type": "string"
});
const schema = await Schema.get("http://example.com/schemas/string");
await Core.validate(schema, "foo");
```
### Keywords
A keyword implementation is a module with at least the functions: `compile` and
`interpret`. In the `compile` step, you can do any processing steps necessary to
do the actual validation in the `interpret` step. The most common things to do
in the `compile` step is to follow references and compile sub-schemas. The
`interpret` step takes the result of the `compile` step and returns a boolean
value indicating whether validation has passed or failed.
If your custom keyword is an applicator and your dialect supports
`unevaluatedProperties` and `unevaluatedItems`, you'll also need to provide the
`collectEvaluatedProperties` and `collectEvaluatedItems` functions.
You can Use the [JSV](https://github.com/hyperjump-io/json-schema-validator)
keyword implementations as examples when creating your own keywords.
* **Core.getKeyword**: (keywordId: string) => Keyword
Retreive a keyword by it's identifier.
* **Core.hasKeyword**: (keywordId: string) => boolean
Query whether a keyword implementation exists.
* **Core.compileSchema**: (schema: SDoc, ast: AST) => undefined
Compile a schema.
* **Core.interpretSchmea**: (schemaUri: string, instance: Instance, ast: AST, dynamicAnchors: Map[anchor: String, uri: String]) => boolean
Finds the compiled schema in the ast for the schemaUri and validates the
instance against the it. The result is a boolean indicating if the keyword
passes validation.
* **Core.collectEvaluatedProperties**: (schemaUri: string, instance: Instance, ast: AST, dynamicAnchors: Map[anchor: String, uri: String]) => string[]
Walk a schema and collect any property names that are evaluated by the
schemas it finds. A property is not considered evaluated if the schema
containing it is not valid.
* **Core.collectEvaluatedItems**: (schemaUri: string, instance: Instance, ast: AST, dynamicAnchors: Map[anchor: String, uri: String]) => number
Walk a schema and collect maximum number of items that are evaluated by the
schemas it finds. An item is not considered evaluated if the schema
containing it is not valid.
This example implements an `if`/`then`/`else`-like keyword called `cond`.
`cond` is an array of schemas where the first is the `if` schema, the second is
the `then` schema, and the third is the `else` schema.
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
module.exports = {
compile: async (schema, ast) => {
const schemas = await Schema.map((schema) => Core.compileSchema(schema, ast), schema);
return Promise.all(schemas);
},
interpret: (cond, instance, ast, dynamicAnchors) => {
return Core.interpretSchema(cond[0], instance, ast, dynamicAnchors)
? (cond[1] ? Core.interpretSchema(cond[1], instance, ast, dynamicAnchors) : true)
: (cond[2] ? Core.interpretSchema(cond[2], instance, ast, dynamicAnchors) : true);
},
collectEvaluatedProperties: (cond, instance, ast, dynamicAnchors) => {
const propertyNames = Core.collectEvaluatedProperties(cond[0], instance, ast, dynamicAnchors);
const branch = propertyNames ? 1 : 2;
if (cond[branch]) {
const branchPropertyNames = Core.collectEvaluatedProperties(cond[branch], instance, ast, dynamicAnchors);
return branchPropertyNames && (propertyNames || []).concat(branchPropertyNames);
} else {
return propertyNames || [];
}
},
collectEvaluatedItems: (cond, instance, ast, dynamicAnchors) => {
const evaluatedIndexes = Core.collectEvaluatedItems(cond[0], instance, ast, dynamicAnchors);
const branch = evaluatedIndexes !== false ? 1 : 2;
if (cond[branch]) {
const branchEvaluatedIndexes = Core.collectEvaluatedItems(cond[branch], instance, ast, dynamicAnchors);
return branchEvaluatedIndexes !== false && new Set([...evaluatedIndexes || new Set(), ...branchEvaluatedIndexes]);
} else {
return evaluatedIndexes || new Set();
}
}
};
```
In order to use an keyword in an implementation, you need to add it to a
vocabulary.
### Vocabularies
A vocabulary is just a named collection of keywords.
* **Core.defineVocabulary**: (vocabularyId: string, keywords: { [keywordId]: Keyword }) => undefined
Define a vocabulary giving it an identifier and an object that maps keyword
identifiers to keyword implementations.
```javascript
const { Core, Schema } = require("@hyperjump/json-schema-core");
const cond = require("./keywords/cond");
// Choose a URI for your vocabulary and add keywords
Core.defineVocabulary("https://example.com/draft/custom/vocab/conditionals", {
cond: cond
});
// Create a new meta-schema an add your vocabulary to `$vocabulary`
Schema.add({
"$id": "https://example.com/draft/custom/schema",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
...
"https://example.com/draft/custom/vocab/conditionals": true
},
...
});
// Try it out
Schema.add({
"$id": "http://example.com/schemas/cond-example",
"$schema": "https://example.com/draft/custom/schema",
"type": "integer",
"cond": [
{ "minimum": 10 },
{ "multipleOf": 3 },
{ "multipleOf": 2 }
]
});
const schema = await Schema.get("http://example.com/schemas/cond-example");
await Core.validate(schema, 42);
```
## Contributing
### Tests
Run the tests
```bash
npm test
```
Run the tests with a continuous test runner
```bash
npm test -- --watch
```
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
export type JsonType = "null" | "boolean" | "object" | "array" | "number" | "integer" | "string";
export const pathRelative: (from: string, to: string) => string;
@@ -0,0 +1,102 @@
const resolveUrl = require("url-resolve-browser");
const isObject = (value) => typeof value === "object" && !Array.isArray(value) && value !== null;
const isType = {
null: (value) => value === null,
boolean: (value) => typeof value === "boolean",
object: isObject,
array: (value) => Array.isArray(value),
number: (value) => typeof value === "number",
integer: (value) => Number.isInteger(value),
string: (value) => typeof value === "string"
};
const jsonTypeOf = (value, type) => isType[type](value);
const splitUrl = (url) => {
const indexOfHash = url.indexOf("#");
const ndx = indexOfHash === -1 ? url.length : indexOfHash;
const urlReference = url.slice(0, ndx);
const urlFragment = url.slice(ndx + 1);
return [decodeURI(urlReference), decodeURI(urlFragment)];
};
const getScheme = (url) => {
const matches = RegExp(/^(.+):\/\//).exec(url);
return matches ? matches[1] : "";
};
const safeResolveUrl = (contextUrl, url) => {
const resolvedUrl = resolveUrl(contextUrl, url);
const contextId = splitUrl(contextUrl)[0];
if (contextId && getScheme(resolvedUrl) === "file" && getScheme(contextId) !== "file") {
throw Error(`Can't access file '${resolvedUrl}' resource from network context '${contextUrl}'`);
}
return resolvedUrl;
};
const CHAR_BACKWARD_SLASH = 47;
const pathRelative = (from, to) => {
if (from === to) {
return "";
}
let toStart = 1;
const fromLen = from.length - 1;
const toLen = to.length - toStart;
// Compare paths to find the longest common path from root
const length = fromLen < toLen ? fromLen : toLen;
let lastCommonSep = -1;
let i = 0;
for (; i < length; i++) {
const fromCode = from.charCodeAt(i + 1);
if (fromCode !== to.charCodeAt(toStart + i)) {
break;
} else if (fromCode === CHAR_BACKWARD_SLASH) {
lastCommonSep = i;
}
}
if (toLen > length) {
if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {
return to.slice(toStart + i + 1);
}
if (i === 0) {
return to.slice(toStart + i);
}
}
if (fromLen > length) {
if (from.charCodeAt(i + 1) === CHAR_BACKWARD_SLASH) {
lastCommonSep = i;
} else if (length === 0) {
lastCommonSep = 0;
}
}
let out = "";
// Generate the relative path based on the path difference between `to` and `from`
for (i = lastCommonSep + 2; i <= from.length; ++i) {
if (i === from.length || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {
out += out.length === 0 ? ".." : "/..";
}
}
toStart += lastCommonSep;
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts
if (out.length > 0) {
return `${out}${to.slice(toStart, to.length)}`;
}
if (to.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {
++toStart;
}
return to.slice(toStart, to.length);
};
module.exports = { jsonTypeOf, splitUrl, safeResolveUrl, pathRelative };
@@ -0,0 +1,68 @@
import type { Schema, SchemaDocument, SchemaObject, Anchors } from "./schema";
import type { Vocabulary, Compile, Interpret, CollectEvaluatedProperties, CollectEvaluatedItems } from "./keywords";
export type Core = {
validate: (
(schema: SchemaDocument, value: unknown, outputFormat?: OutputFormat) => Promise<Result>
) & (
(schema: SchemaDocument) => Promise<Validator>
);
compile: (schema: SchemaDocument<SchemaObject>) => Promise<CompiledSchema>;
interpret: (
(compiledSchema: CompiledSchema, value: unknown, outputFormat?: OutputFormat) => Result
) & (
(compiledSchema: CompiledSchema) => Validator
);
setMetaOutputFormat: (format: OutputFormat) => void;
setShouldMetaValidate: (isEnabled: boolean) => void;
FLAG: "FLAG";
BASIC: "BASIC";
DETAILED: "DETAILED";
VERBOSE: "VERBOSE";
add: Schema["add"];
getKeyword: <A>(id: string) => {
compile: Compile<A>;
interpret: Interpret<A>;
collectEvaluatedProperties: CollectEvaluatedProperties<A>;
collectEvaluatedItems: CollectEvaluatedItems<A>;
};
hasKeyword: (id: string) => boolean;
defineVocabulary: (id: string, keywords: Vocabulary) => void;
compileSchema: Compile<string>;
interpretSchema: Interpret<string>;
collectEvaluatedProperties: CollectEvaluatedProperties<string>;
collectEvaluatedItems: CollectEvaluatedItems<string>;
};
export type Validator = (value: unknown, outputFormat?: OutputFormat) => Result;
export type OutputFormat = "FLAG" | "BASIC" | "DETAILED" | "VERBOSE" | string;
export type CompiledSchema = {
schemaUri: string;
ast: AST;
};
export type AST = {
metaData: Record<string, MetaData>;
} & Record<string, Node<Node<unknown>[] | boolean>>;
export type Node<A> = [keywordId: string, schemaUri: string, keywordValue: A];
export type MetaData = {
id: string;
dynamicAnchors: Anchors;
anchors: Anchors;
};
export type Result = {
keyword: string;
absoluteKeywordLocation: string;
instanceLocation: string;
valid: boolean;
errors?: Result[];
};
declare const core: Core;
export default core;

Some files were not shown because too many files have changed in this diff Show More