kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
191 wiersze
5.2 KiB
TypeScript
191 wiersze
5.2 KiB
TypeScript
/* eslint-disable unicorn/no-thenable */
|
|
import type { Schema } from './types'
|
|
import { encodePointer } from './pointer'
|
|
|
|
export const schemaKeyword: Record<string, boolean> = {
|
|
additionalItems: true,
|
|
unevaluatedItems: true,
|
|
items: true,
|
|
contains: true,
|
|
additionalProperties: true,
|
|
unevaluatedProperties: true,
|
|
propertyNames: true,
|
|
not: true,
|
|
if: true,
|
|
then: true,
|
|
else: true
|
|
}
|
|
|
|
export const schemaArrayKeyword: Record<string, boolean> = {
|
|
prefixItems: true,
|
|
items: true,
|
|
allOf: true,
|
|
anyOf: true,
|
|
oneOf: true
|
|
}
|
|
|
|
export const schemaMapKeyword: Record<string, boolean> = {
|
|
$defs: true,
|
|
definitions: true,
|
|
properties: true,
|
|
patternProperties: true,
|
|
dependentSchemas: true
|
|
}
|
|
|
|
export const ignoredKeyword: Record<string, boolean> = {
|
|
id: true,
|
|
$id: true,
|
|
$ref: true,
|
|
$schema: true,
|
|
$anchor: true,
|
|
$vocabulary: true,
|
|
$comment: true,
|
|
default: true,
|
|
enum: true,
|
|
const: true,
|
|
required: true,
|
|
type: true,
|
|
maximum: true,
|
|
minimum: true,
|
|
exclusiveMaximum: true,
|
|
exclusiveMinimum: true,
|
|
multipleOf: true,
|
|
maxLength: true,
|
|
minLength: true,
|
|
pattern: true,
|
|
format: true,
|
|
maxItems: true,
|
|
minItems: true,
|
|
uniqueItems: true,
|
|
maxProperties: true,
|
|
minProperties: true
|
|
}
|
|
|
|
/**
|
|
* Default base URI for schemas without an $id.
|
|
* https://json-schema.org/draft/2019-09/json-schema-core.html#initial-base
|
|
* https://tools.ietf.org/html/rfc3986#section-5.1
|
|
*/
|
|
export const initialBaseURI: URL = (globalThis as any)?.self?.location?.origin
|
|
? new URL(
|
|
(globalThis as any).self.location.origin +
|
|
(globalThis as any).self.location.pathname +
|
|
(globalThis as any).self.location.search
|
|
)
|
|
: new URL('https://github.com/transitive-bullshit/agentic')
|
|
|
|
export function dereference(
|
|
schema: Schema | boolean,
|
|
lookup: Record<string, Schema | boolean> = Object.create(null),
|
|
baseURI: URL = initialBaseURI,
|
|
basePointer = ''
|
|
): Record<string, Schema | boolean> {
|
|
if (schema && typeof schema === 'object' && !Array.isArray(schema)) {
|
|
const id: string = schema.$id || schema.id
|
|
if (id) {
|
|
const url = new URL(id, baseURI.href)
|
|
if (url.hash.length > 1) {
|
|
lookup[url.href] = schema
|
|
} else {
|
|
url.hash = '' // normalize hash https://url.spec.whatwg.org/#dom-url-hash
|
|
if (basePointer === '') {
|
|
baseURI = url
|
|
} else {
|
|
dereference(schema, lookup, baseURI)
|
|
}
|
|
}
|
|
}
|
|
} else if (schema !== true && schema !== false) {
|
|
return lookup
|
|
}
|
|
|
|
// compute the schema's URI and add it to the mapping.
|
|
const schemaURI = baseURI.href + (basePointer ? '#' + basePointer : '')
|
|
if (lookup[schemaURI] !== undefined) {
|
|
throw new Error(`Duplicate schema URI "${schemaURI}".`)
|
|
}
|
|
lookup[schemaURI] = schema
|
|
|
|
// exit early if this is a boolean schema.
|
|
if (schema === true || schema === false) {
|
|
return lookup
|
|
}
|
|
|
|
// set the schema's absolute URI.
|
|
if (schema.__absolute_uri__ === undefined) {
|
|
Object.defineProperty(schema, '__absolute_uri__', {
|
|
enumerable: false,
|
|
value: schemaURI
|
|
})
|
|
}
|
|
|
|
// if a $ref is found, resolve it's absolute URI.
|
|
if (schema.$ref && schema.__absolute_ref__ === undefined) {
|
|
const url = new URL(schema.$ref, baseURI.href)
|
|
// eslint-disable-next-line no-self-assign
|
|
url.hash = url.hash // normalize hash https://url.spec.whatwg.org/#dom-url-hash
|
|
Object.defineProperty(schema, '__absolute_ref__', {
|
|
enumerable: false,
|
|
value: url.href
|
|
})
|
|
}
|
|
|
|
// if a $recursiveRef is found, resolve it's absolute URI.
|
|
if (schema.$recursiveRef && schema.__absolute_recursive_ref__ === undefined) {
|
|
const url = new URL(schema.$recursiveRef, baseURI.href)
|
|
// eslint-disable-next-line no-self-assign
|
|
url.hash = url.hash // normalize hash https://url.spec.whatwg.org/#dom-url-hash
|
|
Object.defineProperty(schema, '__absolute_recursive_ref__', {
|
|
enumerable: false,
|
|
value: url.href
|
|
})
|
|
}
|
|
|
|
// if an $anchor is found, compute it's URI and add it to the mapping.
|
|
if (schema.$anchor) {
|
|
const url = new URL('#' + schema.$anchor, baseURI.href)
|
|
lookup[url.href] = schema
|
|
}
|
|
|
|
// process subschemas.
|
|
for (const key in schema) {
|
|
if (ignoredKeyword[key]) {
|
|
continue
|
|
}
|
|
const keyBase = `${basePointer}/${encodePointer(key)}`
|
|
const subSchema = schema[key]
|
|
if (Array.isArray(subSchema)) {
|
|
if (schemaArrayKeyword[key]) {
|
|
const length = subSchema.length
|
|
for (let i = 0; i < length; i++) {
|
|
dereference(subSchema[i]!, lookup, baseURI, `${keyBase}/${i}`)
|
|
}
|
|
}
|
|
} else if (schemaMapKeyword[key]) {
|
|
for (const subKey in subSchema) {
|
|
dereference(
|
|
subSchema[subKey]!,
|
|
lookup,
|
|
baseURI,
|
|
`${keyBase}/${encodePointer(subKey)}`
|
|
)
|
|
}
|
|
} else {
|
|
dereference(subSchema, lookup, baseURI, keyBase)
|
|
}
|
|
}
|
|
|
|
return lookup
|
|
}
|
|
|
|
// schema identification examples
|
|
// https://json-schema.org/draft/2019-09/json-schema-core.html#rfc.appendix.A
|
|
// $ref delegation
|
|
// https://github.com/json-schema-org/json-schema-spec/issues/514
|
|
// output format
|
|
// https://json-schema.org/draft/2019-09/json-schema-core.html#output
|
|
// JSON pointer
|
|
// https://tools.ietf.org/html/rfc6901
|
|
// JSON relative pointer
|
|
// https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01
|