constructor (options) {
    /**
     * @prop {object}
     *  Options of the schema. @see readme.
     */
    this.options = options || {}

    /**
     * @prop {object}
     *  The orginial schema to load
     */
    this.schema = {}

    /**
     * @prop {object}
     *  Storage of External ref. Exemple :
     *  refs = {
     *    "fully/realized/path/to/schema.json": { ... }
     *    "mylocalschema.json": { ... }
     *  }
     */
    this.refs = this.options.refs || {}

    /**
     * @prop {object}
     *  Mapping between the schema and ref. Exemple:
     *  refs_with_info = {
     *   "#/counter/1": "fully/realized/path/to/schema.json"
     *   "#/counter/2": "mylocalschema.json"
     *  }
     */
    this.refs_with_info = {}

    /**
     * @prop {string}
     *  String to eewrite external ref with.
     */
    this.refs_prefix = '#/counter/'

    /**
     * @prop {int}
     *  Counter of ref
     */
    this.refs_counter = 1

    this._subSchema1 = {
      /* Version 3 `type` */
      type (schema) {
        if (typeof schema.type === 'object') {
          schema.type = this._expandSubSchema(schema.type)
        }
      },
      /* Version 3 `disallow` */
      disallow (schema) {
        if (typeof schema.disallow === 'object') {
          schema.disallow = this._expandSubSchema(schema.disallow)
        }
      },
      /* Version 4 `anyOf` */
      anyOf (schema) {
        Object.entries(schema.anyOf).forEach(([key, value]) => {
          schema.anyOf[key] = this.expandSchema(value)
        })
      },
      /* Version 4 `dependencies` (schema dependencies) */
      dependencies (schema) {
        Object.entries(schema.dependencies).forEach(([key, value]) => {
          if (typeof value === 'object' && !(Array.isArray(value))) {
            schema.dependencies[key] = this.expandSchema(value)
          }
        })
      },
      /* Version 4 `not` */
      not (schema) {
        schema.not = this.expandSchema(schema.not)
      }
    }

    this._subSchema2 = {
      /* allOf schemas should be merged into the parent */
      allOf (schema, extended) {
        let _extended = extend({}, extended)
        Object.entries(schema.allOf).forEach(([key, value]) => {
          schema.allOf[key] = this.expandRefs(value, true)
          _extended = this.extendSchemas(_extended, this.expandSchema(value))
        })
        delete _extended.allOf
        return _extended
      },
      /* extends schemas should be merged into parent */
      extends (schema, extended) {
        let _extended
        /* If extends is a schema */
        if (!(Array.isArray(schema.extends))) {
          _extended = this.extendSchemas(extended, this.expandSchema(schema.extends))
        } else {
          /* If extends is an array of schemas */
          _extended = schema.extends.reduce((e, s, i) => {
            return this.extendSchemas(e, this.expandSchema(s))
          }, extended)
        }
        delete _extended.extends
        return _extended
      },
      /* parent should be merged into oneOf schemas */
      oneOf (schema, extended) {
        const tmp = extend({}, extended)
        delete tmp.oneOf
        schema.oneOf.reduce((e, s, i) => {
          e.oneOf[i] = this.extendSchemas(this.expandSchema(s), tmp)
          return e
        }, extended)
        return extended
      }
    }
  }
Handles loading Schema and tracking references.