CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
1'use strict'2 3const { dequal: deepEqual } = require('dequal')4 5const jsonSchemaRefSymbol = Symbol.for('json-schema-ref')6 7class RefResolver {8  #schemas9  #derefSchemas10  #insertRefSymbol11  #allowEqualDuplicates12  #cloneSchemaWithoutRefs13 14  constructor (opts = {}) {15    this.#schemas = {}16    this.#derefSchemas = {}17    this.#insertRefSymbol = opts.insertRefSymbol ?? false18    this.#allowEqualDuplicates = opts.allowEqualDuplicates ?? true19    this.#cloneSchemaWithoutRefs = opts.cloneSchemaWithoutRefs ?? false20  }21 22  addSchema (schema, rootSchemaId, isRootSchema = true) {23    if (isRootSchema) {24      if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {25        // Schema has an $id that is not an anchor26        rootSchemaId = schema.$id27      } else {28        // Schema has no $id or $id is an anchor29        this.#insertSchemaBySchemaId(schema, rootSchemaId)30      }31    }32 33    const schemaId = schema.$id34    if (schemaId !== undefined && typeof schemaId === 'string') {35      if (schemaId.charAt(0) === '#') {36        this.#insertSchemaByAnchor(schema, rootSchemaId, schemaId)37      } else {38        this.#insertSchemaBySchemaId(schema, schemaId)39        rootSchemaId = schemaId40      }41    }42 43    const ref = schema.$ref44    if (ref !== undefined && typeof ref === 'string') {45      const { refSchemaId, refJsonPointer } = this.#parseSchemaRef(ref, rootSchemaId)46      this.#schemas[rootSchemaId].refs.push({47        schemaId: refSchemaId,48        jsonPointer: refJsonPointer49      })50    }51 52    for (const key in schema) {53      if (typeof schema[key] === 'object' && schema[key] !== null) {54        this.addSchema(schema[key], rootSchemaId, false)55      }56    }57  }58 59  getSchema (schemaId, jsonPointer = '#') {60    const schema = this.#schemas[schemaId]61    if (schema === undefined) {62      throw new Error(63        `Cannot resolve ref "${schemaId}${jsonPointer}". Schema with id "${schemaId}" is not found.`64      )65    }66    if (schema.anchors[jsonPointer] !== undefined) {67      return schema.anchors[jsonPointer]68    }69    return getDataByJSONPointer(schema.schema, jsonPointer)70  }71 72  hasSchema (schemaId) {73    return this.#schemas[schemaId] !== undefined74  }75 76  getSchemaRefs (schemaId) {77    const schema = this.#schemas[schemaId]78    if (schema === undefined) {79      throw new Error(`Schema with id "${schemaId}" is not found.`)80    }81    return schema.refs82  }83 84  getSchemaDependencies (schemaId, dependencies = {}) {85    const schema = this.#schemas[schemaId]86 87    for (const ref of schema.refs) {88      const dependencySchemaId = ref.schemaId89      if (90        dependencySchemaId === schemaId ||91        dependencies[dependencySchemaId] !== undefined92      ) continue93 94      dependencies[dependencySchemaId] = this.getSchema(dependencySchemaId)95      this.getSchemaDependencies(dependencySchemaId, dependencies)96    }97 98    return dependencies99  }100 101  derefSchema (schemaId) {102    if (this.#derefSchemas[schemaId] !== undefined) return103 104    const schema = this.#schemas[schemaId]105    if (schema === undefined) {106      throw new Error(`Schema with id "${schemaId}" is not found.`)107    }108 109    if (!this.#cloneSchemaWithoutRefs && schema.refs.length === 0) {110      this.#derefSchemas[schemaId] = {111        schema: schema.schema,112        anchors: schema.anchors113      }114    }115 116    const refs = []117    this.#addDerefSchema(schema.schema, schemaId, true, refs)118 119    const dependencies = this.getSchemaDependencies(schemaId)120    for (const schemaId in dependencies) {121      const schema = dependencies[schemaId]122      this.#addDerefSchema(schema, schemaId, true, refs)123    }124 125    for (const ref of refs) {126      const {127        refSchemaId,128        refJsonPointer129      } = this.#parseSchemaRef(ref.ref, ref.sourceSchemaId)130 131      const targetSchema = this.getDerefSchema(refSchemaId, refJsonPointer)132      if (targetSchema === null) {133        throw new Error(134          `Cannot resolve ref "${ref.ref}". Ref "${refJsonPointer}" is not found in schema "${refSchemaId}".`135        )136      }137 138      ref.targetSchema = targetSchema139      ref.targetSchemaId = refSchemaId140    }141 142    for (const ref of refs) {143      this.#resolveRef(ref, refs)144    }145  }146 147  getDerefSchema (schemaId, jsonPointer = '#') {148    let derefSchema = this.#derefSchemas[schemaId]149    if (derefSchema === undefined) {150      this.derefSchema(schemaId)151      derefSchema = this.#derefSchemas[schemaId]152    }153    if (derefSchema.anchors[jsonPointer] !== undefined) {154      return derefSchema.anchors[jsonPointer]155    }156    return getDataByJSONPointer(derefSchema.schema, jsonPointer)157  }158 159  #parseSchemaRef (ref, schemaId) {160    const sharpIndex = ref.indexOf('#')161    if (sharpIndex === -1) {162      return { refSchemaId: ref, refJsonPointer: '#' }163    }164    if (sharpIndex === 0) {165      return { refSchemaId: schemaId, refJsonPointer: ref }166    }167    return {168      refSchemaId: ref.slice(0, sharpIndex),169      refJsonPointer: ref.slice(sharpIndex)170    }171  }172 173  #addDerefSchema (schema, rootSchemaId, isRootSchema, refs = []) {174    const derefSchema = Array.isArray(schema) ? [...schema] : { ...schema }175 176    if (isRootSchema) {177      if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {178        // Schema has an $id that is not an anchor179        rootSchemaId = schema.$id180      } else {181        // Schema has no $id or $id is an anchor182        this.#insertDerefSchemaBySchemaId(derefSchema, rootSchemaId)183      }184    }185 186    const schemaId = derefSchema.$id187    if (schemaId !== undefined && typeof schemaId === 'string') {188      if (schemaId.charAt(0) === '#') {189        this.#insertDerefSchemaByAnchor(derefSchema, rootSchemaId, schemaId)190      } else {191        this.#insertDerefSchemaBySchemaId(derefSchema, schemaId)192        rootSchemaId = schemaId193      }194    }195 196    if (derefSchema.$ref !== undefined) {197      refs.push({198        ref: derefSchema.$ref,199        sourceSchemaId: rootSchemaId,200        sourceSchema: derefSchema201      })202    }203 204    for (const key in derefSchema) {205      const value = derefSchema[key]206      if (typeof value === 'object' && value !== null) {207        derefSchema[key] = this.#addDerefSchema(value, rootSchemaId, false, refs)208      }209    }210 211    return derefSchema212  }213 214  #resolveRef (ref, refs) {215    const { sourceSchema, targetSchema } = ref216 217    if (!sourceSchema.$ref) return218    if (this.#insertRefSymbol) {219      sourceSchema[jsonSchemaRefSymbol] = sourceSchema.$ref220    }221 222    delete sourceSchema.$ref223 224    if (targetSchema.$ref) {225      const targetSchemaRef = refs.find(ref => ref.sourceSchema === targetSchema)226      this.#resolveRef(targetSchemaRef, refs)227    }228    for (const key in targetSchema) {229      if (key === '$id') continue230      if (sourceSchema[key] !== undefined) {231        if (deepEqual(sourceSchema[key], targetSchema[key])) continue232        throw new Error(233          `Cannot resolve ref "${ref.ref}". Property "${key}" already exists in schema "${ref.sourceSchemaId}".`234        )235      }236      sourceSchema[key] = targetSchema[key]237    }238    ref.isResolved = true239  }240 241  #insertSchemaBySchemaId (schema, schemaId) {242    const foundSchema = this.#schemas[schemaId]243    if (foundSchema !== undefined) {244      if (this.#allowEqualDuplicates && deepEqual(schema, foundSchema.schema)) return245      throw new Error(`There is already another schema with id "${schemaId}".`)246    }247    this.#schemas[schemaId] = { schema, anchors: {}, refs: [] }248  }249 250  #insertSchemaByAnchor (schema, schemaId, anchor) {251    const { anchors } = this.#schemas[schemaId]252    if (anchors[anchor] !== undefined) {253      throw new Error(`There is already another anchor "${anchor}" in schema "${schemaId}".`)254    }255    anchors[anchor] = schema256  }257 258  #insertDerefSchemaBySchemaId (schema, schemaId) {259    const foundSchema = this.#derefSchemas[schemaId]260    if (foundSchema !== undefined) return261 262    this.#derefSchemas[schemaId] = { schema, anchors: {} }263  }264 265  #insertDerefSchemaByAnchor (schema, schemaId, anchor) {266    const { anchors } = this.#derefSchemas[schemaId]267    anchors[anchor] = schema268  }269}270 271function getDataByJSONPointer (data, jsonPointer) {272  const parts = jsonPointer.split('/')273  let current = data274  for (const part of parts) {275    if (part === '' || part === '#') continue276    if (typeof current !== 'object' || current === null) {277      return null278    }279    current = current[part]280  }281  return current ?? null282}283 284module.exports = { RefResolver }285