Adding a Helper to idenfitify valid json-schemas.
This commit is contained in:
parent
39c50061dc
commit
d81eddd7a6
264
lib/helpers/jsonSchemaMethods.spec.ts
Normal file
264
lib/helpers/jsonSchemaMethods.spec.ts
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
/**
|
||||||
|
* @author Martin Karkowski
|
||||||
|
* @email m.karkowski@zema.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { assert } from "chai";
|
||||||
|
import { describe, it } from "mocha";
|
||||||
|
import { INopeDescriptor } from "../index.browser";
|
||||||
|
import { isJsonSchema } from "./jsonSchemaMethods";
|
||||||
|
|
||||||
|
describe("jsonSchemaMethods", function () {
|
||||||
|
// Describe the required Test:
|
||||||
|
|
||||||
|
const tests: [string, INopeDescriptor, boolean][] = [
|
||||||
|
[
|
||||||
|
"function",
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
name: "parameter",
|
||||||
|
schema: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"nested-function",
|
||||||
|
{
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
function: {
|
||||||
|
type: "function",
|
||||||
|
inputs: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"array => items",
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vegetables: {
|
||||||
|
type: "array",
|
||||||
|
items: { $ref: "#/$defs/veggie" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"array => additionalItems",
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
additionalItems: {
|
||||||
|
type: "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vegetables: {
|
||||||
|
type: "array",
|
||||||
|
items: { $ref: "#/$defs/veggie" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"anyOf",
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
anyOf: [
|
||||||
|
{
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"allOf",
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
allOf: [
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"oneOf",
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
oneOf: [
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
describe("isJsonSchema", function () {
|
||||||
|
for (const [name, test, expectedResult] of tests) {
|
||||||
|
it(name, function () {
|
||||||
|
const result = isJsonSchema(test);
|
||||||
|
assert.isTrue(result == expectedResult, "Test Failed");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it("detect-nope-schema -> true", function () {
|
||||||
|
const shouldFalse: INopeDescriptor[] = [
|
||||||
|
{
|
||||||
|
$id: "https://example.com/person.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
title: "Person",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
firstName: {
|
||||||
|
type: "string",
|
||||||
|
description: "The person's first name.",
|
||||||
|
},
|
||||||
|
lastName: {
|
||||||
|
type: "string",
|
||||||
|
description: "The person's last name.",
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
description:
|
||||||
|
"Age in years which must be equal to or greater than zero.",
|
||||||
|
type: "integer",
|
||||||
|
minimum: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$id: "https://example.com/geographical-location.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
title: "Longitude and Latitude Values",
|
||||||
|
description: "A geographical coordinate.",
|
||||||
|
required: ["latitude", "longitude"],
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
latitude: {
|
||||||
|
type: "number",
|
||||||
|
minimum: -90,
|
||||||
|
maximum: 90,
|
||||||
|
},
|
||||||
|
longitude: {
|
||||||
|
type: "number",
|
||||||
|
minimum: -180,
|
||||||
|
maximum: 180,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$id: "https://example.com/arrays.schema.json",
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
description:
|
||||||
|
"A representation of a person, company, organization, or place",
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fruits: {
|
||||||
|
type: "array",
|
||||||
|
items: {
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vegetables: {
|
||||||
|
type: "array",
|
||||||
|
items: { $ref: "#/$defs/veggie" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
definitions: {
|
||||||
|
veggie: {
|
||||||
|
type: "object",
|
||||||
|
required: ["veggieName", "veggieLike"],
|
||||||
|
properties: {
|
||||||
|
veggieName: {
|
||||||
|
type: "string",
|
||||||
|
description: "The name of the vegetable.",
|
||||||
|
},
|
||||||
|
veggieLike: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Do I like this vegetable?",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const test of shouldFalse) {
|
||||||
|
const result = isJsonSchema(test);
|
||||||
|
assert.isTrue(result, "Test should be true");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IJsonSchema } from "../types/IJSONSchema";
|
import { IJsonSchema } from "../types/IJSONSchema";
|
||||||
|
import { INopeDescriptor } from "../types/nope";
|
||||||
import { flattenObject, rgetattr, rsetattr, SPLITCHAR } from "./objectMethods";
|
import { flattenObject, rgetattr, rsetattr, SPLITCHAR } from "./objectMethods";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,3 +60,91 @@ export function flattenSchema(schema: IJsonSchema) {
|
|||||||
export function schemaGetDefinition(schema: IJsonSchema, reference: string) {
|
export function schemaGetDefinition(schema: IJsonSchema, reference: string) {
|
||||||
return rgetattr(schema, reference.replace("#/", ""), null, "/");
|
return rgetattr(schema, reference.replace("#/", ""), null, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const _isNopeDescriptor: Array<
|
||||||
|
[keyof INopeDescriptor, (value: any) => boolean]
|
||||||
|
> = [
|
||||||
|
["type", (value) => value === "function"],
|
||||||
|
["inputs", (value) => typeof value === "object"],
|
||||||
|
["outputs", (value) => typeof value === "object"],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Helper Function, to test, if the given schema is a JSON Schema or whether it contains a method description
|
||||||
|
*
|
||||||
|
* @param { INopeDescriptor | IJsonSchema } schema The Schema to Test
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isJsonSchema(schema: INopeDescriptor | IJsonSchema): boolean {
|
||||||
|
for (const [attr, test] of _isNopeDescriptor) {
|
||||||
|
if (test(schema[attr])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object-Related Test-Cases.
|
||||||
|
if (
|
||||||
|
schema.type == "object" ||
|
||||||
|
(Array.isArray(schema.type) && schema.type.includes("object"))
|
||||||
|
) {
|
||||||
|
if (schema.properties) {
|
||||||
|
for (const key in schema.properties) {
|
||||||
|
if (!isJsonSchema(schema.properties[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (schema.patternProperties) {
|
||||||
|
for (const key in schema.patternProperties) {
|
||||||
|
if (!isJsonSchema(schema.patternProperties[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (schema.dependencies) {
|
||||||
|
for (const key in schema.dependencies) {
|
||||||
|
if (
|
||||||
|
typeof schema.dependencies[key] !== "string" &&
|
||||||
|
!isJsonSchema(schema.dependencies[key] as INopeDescriptor)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
for (const key of ["allOf", "anyOf", "oneOf"]) {
|
||||||
|
if (schema[key]) {
|
||||||
|
for (const subSchema of schema[key]) {
|
||||||
|
if (!isJsonSchema(subSchema)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
schema.type == "array" ||
|
||||||
|
(Array.isArray(schema.type) && schema.type.includes("array"))
|
||||||
|
) {
|
||||||
|
if (Array.isArray(schema.items)) {
|
||||||
|
for (const key in schema.items) {
|
||||||
|
if (!isJsonSchema(schema.items[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!isJsonSchema(schema.items)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the Additional Items.
|
||||||
|
if (typeof schema.additionalItems === "object") {
|
||||||
|
if (!isJsonSchema(schema.additionalItems)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user