71 lines
2.8 KiB
TypeScript
71 lines
2.8 KiB
TypeScript
import gp, { JsonPath } from "@sagold/json-pointer";
|
|
import { JsonSchema, JsonPointer, isJsonError, JsonError } from "./types";
|
|
import { Draft } from "./draft";
|
|
|
|
const emptyObject = {} as const;
|
|
|
|
export type GetSchemaOptions = {
|
|
/* path to data location for the requested json-schema. Default to root-pointer '#' */
|
|
pointer?: JsonPointer;
|
|
/* the data object, which includes the json pointers value. This is optional,
|
|
as long as no oneOf, anyOf, etc statement is part of the pointers schema */
|
|
data?: unknown;
|
|
/* the json-schema to iterate. Defaults to draft.rootSchema */
|
|
schema?: JsonSchema;
|
|
/* returns an error `schema-warning` for valid properties missing a
|
|
json-schema definition. Default to false */
|
|
withSchemaWarning?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Returns the json-schema of a data-json-pointer.
|
|
*
|
|
* To resolve dynamic schema where the type of json-schema is evaluated by
|
|
* its value, a data object has to be passed in options.
|
|
*
|
|
* Per default this function will return `undefined` for valid properties that
|
|
* do not have a defined schema. Use the option `withSchemaWarning: true` to
|
|
* receive an error with `code: schema-warning` containing the location of its
|
|
* last evaluated json-schema.
|
|
*
|
|
* Notes
|
|
* - uses draft.step to walk through data and schema
|
|
*
|
|
* @param draft
|
|
* @param pointer - json pointer in data to get the json schema for
|
|
* @param [options.data] - the data object, which includes the json pointers value. This is optional, as
|
|
* long as no oneOf, anyOf, etc statement is part of the pointers schema
|
|
* @param [options.schema] - the json schema to iterate. Defaults to draft.rootSchema
|
|
* @param [options.withSchemaWarning] - if true returns an error instead of `undefined` for valid properties missing a schema definition
|
|
* @return resolved json-schema object of requested json-pointer location or json-error
|
|
*/
|
|
export default function getSchema(draft: Draft, options: GetSchemaOptions = emptyObject) {
|
|
const { pointer = "#", data, schema = draft.rootSchema, withSchemaWarning = false } = options;
|
|
const path = gp.split(pointer);
|
|
const result = _getSchema(draft, draft.resolveRef(schema), path, "#", data);
|
|
if (!withSchemaWarning && result?.code === "schema-warning") {
|
|
return undefined;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function _getSchema(
|
|
draft: Draft,
|
|
schema: JsonSchema,
|
|
path: JsonPath,
|
|
pointer: JsonPointer,
|
|
data: unknown = emptyObject
|
|
): JsonSchema | JsonError {
|
|
if (path.length === 0) {
|
|
return draft.resolveRef(schema);
|
|
}
|
|
|
|
const key = path.shift(); // step key
|
|
schema = draft.step(key, schema, data, pointer); // step schema
|
|
if (isJsonError(schema)) {
|
|
return schema;
|
|
}
|
|
// @ts-expect-error data
|
|
data = data[key]; // step data
|
|
return _getSchema(draft, schema, path, `${pointer}/${key}`, data);
|
|
}
|