code: function derefSchema (schema, options, state) {
    const check = checkLocalCircular(schema)
    if (check instanceof Error) {
      return check
    }
  
    if (state.circular) {
      return new Error(`circular references found: ${state.circularRefs.toString()}`)
    } else if (state.error) {
      return state.error
    }
  
    return traverse(schema).forEach(function (node) {
      if (!_.isNull(node) && !_.isUndefined(null) && typeof node.$ref === 'string') {
        const refType = utils.getRefType(node)
        const refVal = utils.getRefValue(node)
  
        const addOk = addToHistory(state, refType, refVal)
        if (!addOk) {
          state.circular = true
          state.circularRefs.push(refVal)
          state.error = new Error(`circular references found: ${state.circularRefs.toString()}`)
          this.update(node, true)
        } else {
          setCurrent(state, refType, refVal)
          let newValue = getRefSchema(refVal, refType, schema, options, state)
          state.history.pop()
          if (newValue === undefined) {
            if (state.missing.indexOf(refVal) === -1) {
              state.missing.push(refVal)
            }
            if (options.failOnMissing) {
              state.error = new Error(`Missing $ref: ${refVal}`)
            }
            this.update(node, options.failOnMissing)
          } else {
            if (options.mergeAdditionalProperties) {
              delete node.$ref
              newValue = _.merge(newValue, node)
            }
            if (options.removeIds && newValue.hasOwnProperty('$id')) {
              delete newValue.$id
            }
            this.update(newValue)
            if (state.missing.indexOf(refVal) !== -1) {
              state.missing.splice(state.missing.indexOf(refVal), 1)
            }
          }
        }
      }
    })
  }
docs: Derefs $ref types in a schema
  @param schema
  @param options
  @param state
  @param type
  @private