schema-finder
Version:
A simple React component for viewing and exploring a JSONSchema
96 lines (82 loc) • 2.43 kB
text/typescript
import {JSONSchema7} from "json-schema";
import {DerefBuilder, DerefOptions} from "./internal";
export const buildDeref: DerefBuilder = (root, options) => async (ref) => {
if (ref === undefined) return [{}];
// if (ref in idDict) return [idDict[ref]];
const [address, jp] = ref.split(/\/?#\/?/);
let refschema = root;
if (address.length && options?.unsafeAllowRemoteUriResolution) {
const [val, err] = await resolveAddress(address);
if (err !== undefined) {
return [{}, err];
}
refschema = val;
}
return evaljp(refschema, parseJsonPointer(jp));
};
/**
* Resolves $ref
* @param options Additional options
* @param idDict Dictionary of schemas with $id
* @param rootSchema Fallback schema so use if ref doesn't specify an id
* or an address or remote address resolution is not enabled.
* @param ref [JSON pointer] to referenced schema
*
* [JSON pointer]: https://datatracker.ietf.org/doc/html/rfc6901
*/
export async function deref(
options: DerefOptions,
idDict: Record<string, JSONSchema7>,
rootSchema: JSONSchema7,
ref?: string
): Promise<[unknown, Error?]> {
if (ref === undefined) return [{}];
if (ref in idDict) return [idDict[ref]];
const [address, jp] = ref.split(/\/?#\/?/);
if (address.length && options.unsafeAllowRemoteUriResolution) {
const [val, err] = await resolveAddress(address);
if (err !== undefined) {
return [{}, err];
}
rootSchema = val;
}
return evaljp(rootSchema, parseJsonPointer(jp));
}
async function resolveAddress(
address: string
): Promise<[Record<string, unknown>, Error?]> {
try {
const r = await fetch(address);
if (!r.ok) {
return [{}, new Error(`${r.status}: ${r.statusText}`)];
}
return [await r.json()];
} catch (e) {
return [{}, e as Error];
}
}
/**
* Returns whatever the JSONPointer is pointing to in a schema
*/
function evaljp(j: JSONSchema7, keys: string[]): [unknown, Error?] {
for (const key of keys) {
if (!(key in j)) {
return [
j,
new Error(
`No key "${key}" in given object: ${JSON.stringify(
j,
undefined,
"\t"
)}`
),
];
}
// @ts-expect-error Indexing with {string}
j = j[key];
}
return [j];
}
function parseJsonPointer(jp: string): string[] {
return jp.split("/").map((key) => key.replace("~1", "/").replace("~0", "~"));
}