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 { INopeDescriptor } from "../types/nope";
|
||||
import { flattenObject, rgetattr, rsetattr, SPLITCHAR } from "./objectMethods";
|
||||
|
||||
/**
|
||||
@ -59,3 +60,91 @@ export function flattenSchema(schema: IJsonSchema) {
|
||||
export function schemaGetDefinition(schema: IJsonSchema, reference: string) {
|
||||
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