text: "use strict";
  var __extends = (this && this.__extends) || (function () {
      var extendStatics = function (d, b) {
          extendStatics = Object.setPrototypeOf ||
              ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
              function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
          return extendStatics(d, b);
      }
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  Object.defineProperty(exports, "__esModule", { value: true });
  var ts = require("./typesystem");
  var messageRegistry = ts.messageRegistry;
  var tsInterfaces = require("./typesystem-interfaces");
  var rs = require("./restrictions");
  var typesystem_1 = require("./typesystem");
  var typeExpressions = require("./typeExpressions");
  var facetR = require("./facetRegistry");
  var meta = require("./metainfo");
  var metainfo_1 = require("./metainfo");
  var typesystem_2 = require("./typesystem");
  var restrictions_1 = require("./restrictions");
  var _ = require("underscore");
  var restrictions_2 = require("./restrictions");
  var NodeKind;
  (function (NodeKind) {
      NodeKind[NodeKind["SCALAR"] = 0] = "SCALAR";
      NodeKind[NodeKind["ARRAY"] = 1] = "ARRAY";
      NodeKind[NodeKind["MAP"] = 2] = "MAP";
  })(NodeKind = exports.NodeKind || (exports.NodeKind = {}));
  var JSObjectNode = /** @class */ (function () {
      function JSObjectNode(_key, obj, inArr, provider) {
          if (inArr === void 0) { inArr = false; }
          this._key = _key;
          this.obj = obj;
          this.inArr = inArr;
          this.provider = provider;
      }
      JSObjectNode.prototype.value = function () {
          return this.obj;
      };
      JSObjectNode.prototype.key = function () {
          if (!this._key) {
              if (this.kind() === NodeKind.MAP && this.inArr) {
                  var l = Object.keys(this.obj);
                  if (l.length === 1) {
                      return l[0];
                  }
              }
          }
          return this._key;
      };
      JSObjectNode.prototype.childWithKey = function (k) {
          if (this.obj == null) {
              return null;
          }
          if (this.obj.hasOwnProperty(k)) {
              return new JSObjectNode(k, this.obj[k], false, this.contentProvider());
          }
          return null;
      };
      JSObjectNode.prototype.children = function () {
          var _this = this;
          if (Array.isArray(this.obj)) {
              return this.obj.map(function (x) { return new JSObjectNode(null, x, true, _this.contentProvider()); });
          }
          else if (this.obj && typeof this.obj == "object") {
              return Object.keys(this.obj).map(function (x) { return new JSObjectNode(x, _this.obj[x], false, _this.provider); });
          }
          return [];
      };
      JSObjectNode.prototype.kind = function () {
          if (!this.obj) {
              return NodeKind.SCALAR;
          }
          if (Array.isArray(this.obj)) {
              return NodeKind.ARRAY;
          }
          else if (typeof this.obj === "object") {
              return NodeKind.MAP;
          }
          return NodeKind.SCALAR;
      };
      JSObjectNode.prototype.contentProvider = function () {
          return this.provider;
      };
      ;
      JSObjectNode.prototype.getMeta = function (key) {
          return null;
      };
      JSObjectNode.prototype.path = function () {
          return JSON.stringify(this.obj);
      };
      return JSObjectNode;
  }());
  function parseJSON(name, n, r, provider) {
      if (r === void 0) { r = ts.builtInRegistry(); }
      return parse(name, new JSObjectNode(null, n, false, provider), r, false, false, true, false, false, []);
  }
  exports.parseJSON = parseJSON;
  function parseJSONTypeCollection(n, r, provider) {
      if (r === void 0) { r = ts.builtInRegistry(); }
      return parseTypeCollection(new JSObjectNode(null, n, false, provider), r);
  }
  exports.parseJSONTypeCollection = parseJSONTypeCollection;
  function endsWithQuestionMark(p) {
      return p.charAt(p.length - 1) == '?';
  }
  var PropertyBean = /** @class */ (function () {
      function PropertyBean() {
      }
      PropertyBean.prototype.add = function (t, typePath) {
          // const p = typePath.concat(this.id).join(", ");
          // console.log(p);
          if (!this.optional && !this.additonal && !this.regExp && !this.type.isSubTypeOf(ts.NIL)) {
              t.addMeta(new rs.HasProperty(this.id));
          }
          var matchesPropertyFacet;
          if (this.additonal) {
              matchesPropertyFacet = new rs.AdditionalPropertyIs(this.type);
          }
          else if (this.regExp) {
              matchesPropertyFacet = new rs.MapPropertyIs(this.id, this.type, this.optional);
          }
          else {
              matchesPropertyFacet = new rs.PropertyIs(this.id, this.type, this.optional);
          }
          if (matchesPropertyFacet != null) {
              t.addMeta(matchesPropertyFacet);
              if (this.type instanceof ts.InheritedType && this.type.name() == null) {
                  //Linking anonymous types with properties declaring them
                  this.type.setContextMeta(matchesPropertyFacet);
              }
              if (this.annotations && this.annotations.length) {
                  for (var _i = 0, _a = this.annotations; _i < _a.length; _i++) {
                      var a = _a[_i];
                      var a1 = new meta.Annotation(a.name, a.value, a.key);
                      a1.setOwnerFacet(matchesPropertyFacet);
                      matchesPropertyFacet.addAnnotation(a1);
                  }
              }
          }
      };
      return PropertyBean;
  }());
  exports.PropertyBean = PropertyBean;
  var TypeCollection = /** @class */ (function () {
      function TypeCollection(_id) {
          this._id = _id;
          this._types = [];
          this._typeMap = {};
          this.uses = {};
          this._annotationTypes = [];
          this._annotationTypeMap = {};
      }
      TypeCollection.prototype.id = function () {
          return this._id;
      };
      TypeCollection.prototype.library = function (n) {
          return this.uses[n];
      };
      TypeCollection.prototype.addLibrary = function (n, t) {
          this.uses[n] = t;
      };
      TypeCollection.prototype.add = function (t) {
          this._types = this._types.filter(function (x) { return x.name() != t.name(); });
          this._types.push(t);
          this._typeMap[t.name()] = t;
      };
      TypeCollection.prototype.getType = function (name) {
          if (this._typeMap.hasOwnProperty(name)) {
              return this._typeMap[name];
          }
          return null;
      };
      TypeCollection.prototype.addAnnotationType = function (t) {
          this._annotationTypes.push(t);
          this._annotationTypeMap[t.name()] = t;
      };
      TypeCollection.prototype.getAnnotationType = function (name) {
          if (this._annotationTypeMap.hasOwnProperty(name)) {
              return this._annotationTypeMap[name];
          }
          return null;
      };
      TypeCollection.prototype.types = function () {
          return this._types;
      };
      TypeCollection.prototype.annotationTypes = function () {
          return this._annotationTypes;
      };
      TypeCollection.prototype.getAnnotationTypeRegistry = function () {
          var _this = this;
          var r = new typesystem_2.TypeRegistry(ts.builtInRegistry(), this, true);
          this.annotationTypes().forEach(function (x) { return r.addType(x); });
          Object.keys(this.uses).forEach(function (x) {
              _this.uses[x].annotationTypes().forEach(function (y) { return r.put(x + "." + y.name(), y); });
          });
          return r;
      };
      TypeCollection.prototype.getTypeRegistry = function () {
          var _this = this;
          var r = new typesystem_2.TypeRegistry(ts.builtInRegistry(), this);
          this.types().forEach(function (x) { return r.addType(x); });
          Object.keys(this.uses).forEach(function (x) {
              _this.uses[x].types().forEach(function (y) { return r.put(x + "." + y.name(), y); });
          });
          return r;
      };
      TypeCollection.prototype.libraries = function () {
          return this.uses;
      };
      return TypeCollection;
  }());
  exports.TypeCollection = TypeCollection;
  var AccumulatingRegistry = /** @class */ (function (_super) {
      __extends(AccumulatingRegistry, _super);
      function AccumulatingRegistry(toParse, schemas, ts, _c) {
          var _this = _super.call(this, ts, _c) || this;
          _this.toParse = toParse;
          _this.schemas = schemas;
          _this.parsing = {};
          return _this;
      }
      AccumulatingRegistry.prototype.getClassIdentifier = function () {
          var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
          return superIdentifiers.concat(AccumulatingRegistry.CLASS_IDENTIFIER_AccumulatingRegistry);
      };
      AccumulatingRegistry.isInstance = function (instance) {
          return instance != null && instance.getClassIdentifier
              && typeof (instance.getClassIdentifier) == "function"
              && _.contains(instance.getClassIdentifier(), AccumulatingRegistry.CLASS_IDENTIFIER_AccumulatingRegistry);
      };
      AccumulatingRegistry.prototype.get = function (name, isPropertyType) {
          if (isPropertyType === void 0) { isPropertyType = false; }
          var result = _super.prototype.get.call(this, name);
          if (isPropertyType && result && result.isSubTypeOf(ts.REFERENCE)) {
              return result;
          }
          if (!result || result.isSubTypeOf(ts.REFERENCE)) {
              var chld = this.toParse ? this.toParse.childWithKey(name) : null;
              if (!chld) {
                  chld = this.schemas ? this.schemas.childWithKey(name) : null;
              }
              if (chld) {
                  if (this.parsing[name]) {
                      var recurrent = ts.derive(name, [ts.RECURRENT]);
                      if (result && result.isSubTypeOf(ts.REFERENCE)) {
                          result.patch(recurrent);
                      }
                      else {
                          result = recurrent;
                      }
                      return result;
                  }
                  this.parsing[name] = true;
                  try {
                      var tp = parse(name, chld, this, false, false, true, false, false, []);
                  }
                  finally {
                      delete this.parsing[name];
                  }
                  return tp;
              }
              else {
                  var dt = name.indexOf('.');
                  if (dt != -1) {
                      var ln = name.substring(0, dt);
                      var tn = name.substr(dt + 1);
                      var lib = this._c.library(ln);
                      if (lib) {
                          var t = lib.getType(tn);
                          if (t) {
                              return t;
                          }
                      }
                  }
              }
          }
          return result;
      };
      AccumulatingRegistry.CLASS_IDENTIFIER_AccumulatingRegistry = "parse.AccumulatingRegistry";
      return AccumulatingRegistry;
  }(ts.TypeRegistry));
  exports.AccumulatingRegistry = AccumulatingRegistry;
  function parseTypes(n, tr) {
      if (tr === void 0) { tr = ts.builtInRegistry(); }
      var provider = n.provider && n.provider();
      return parseTypeCollection(new JSObjectNode(null, n, false, provider), tr);
  }
  exports.parseTypes = parseTypes;
  var WrapArrayNode = /** @class */ (function () {
      function WrapArrayNode(n) {
          this.n = n;
      }
      WrapArrayNode.prototype.key = function () {
          return null;
      };
      WrapArrayNode.prototype.value = function () {
          return null;
      };
      WrapArrayNode.prototype.childWithKey = function (k) {
          var r = this.children();
          for (var i = 0; i < r.length; i++) {
              if (r[i].key() == k) {
                  return r[i];
              }
          }
          return null;
      };
      WrapArrayNode.prototype.children = function () {
          return this.n.children().map(function (x) {
              var c = x.children();
              if (c.length == 1) {
                  return c[0];
              }
              return x;
          });
      };
      WrapArrayNode.prototype.kind = function () {
          return NodeKind.MAP;
      };
      WrapArrayNode.prototype.getMeta = function (key) {
          return null;
      };
      WrapArrayNode.prototype.path = function () {
          return this.n.path();
      };
      return WrapArrayNode;
  }());
  function transformToArray(n) {
      return new WrapArrayNode(n);
  }
  function parseTypeCollection(n, tr, ignoreUses) {
      if (ignoreUses === void 0) { ignoreUses = false; }
      var result = new TypeCollection(n.path());
      if (n.anchor) {
          if (n.anchor().__$$) {
              return n.anchor().__$$;
          }
          n.anchor().__$$ = result;
      }
      var tpes = n.childWithKey("types");
      if (tpes && tpes.kind() === NodeKind.ARRAY) {
          tpes = transformToArray(tpes);
      }
      var schemas = n.childWithKey("schemas");
      if (schemas && schemas.kind() === NodeKind.ARRAY) {
          schemas = transformToArray(schemas);
      }
      var reg = new AccumulatingRegistry(tpes, schemas, tr, result);
      if (tpes && tpes.kind() !== NodeKind.SCALAR) {
          tpes.children().filter(function (x) { return x.key() && true; }).forEach(function (x) {
              var t = ts.derive(x.key(), [ts.REFERENCE]);
              result.add(t);
              reg.addType(t);
          });
      }
      if (schemas && schemas.kind() !== NodeKind.SCALAR) {
          schemas.children().filter(function (x) { return x.key() && true; }).forEach(function (x) {
              var t = ts.derive(x.key(), [ts.REFERENCE]);
              result.add(t);
              reg.addType(t);
          });
      }
      if (!ignoreUses) {
          var uses = n.childWithKey("uses");
          if (uses && uses.kind() === NodeKind.ARRAY) {
              uses = transformToArray(uses);
          }
          if (uses && uses.kind() === NodeKind.MAP) {
              uses.children().forEach(function (c) {
                  result.addLibrary(c.key(), parseTypeCollection(c, tr));
              });
          }
      }
      if (tpes && tpes.kind() !== NodeKind.SCALAR) {
          tpes.children().filter(function (x) { return x.key() && true; }).forEach(function (x) {
              reg.get(x.key());
          });
      }
      if (schemas && schemas.kind() !== NodeKind.SCALAR) {
          schemas.children().filter(function (x) { return x.key() && true; }).forEach(function (x) {
              reg.get(x.key());
          });
      }
      reg.types().forEach(function (x) { return result.add(x); });
      var tpes = n.childWithKey("annotationTypes");
      if (tpes && tpes.kind() === NodeKind.ARRAY) {
          tpes = transformToArray(tpes);
      }
      if (tpes != null && tpes.kind() === NodeKind.MAP) {
          tpes.children().forEach(function (x) {
              result.addAnnotationType(parse(x.key(), x, reg, false, true, false, false, false, []));
          });
      }
      return result;
  }
  exports.parseTypeCollection = parseTypeCollection;
  function parsePropertyBean(n, tr, typePath) {
      var result = new PropertyBean();
      var hasRequiredFacet = false;
      var requiredNode = n.childWithKey("required");
      if (requiredNode) {
          var rsValue = requiredNode.value();
          if (typeof rsValue === "boolean") {
              hasRequiredFacet = true;
          }
          else if (rsValue && typeof (rsValue) === "object" && typeof rsValue.value === "boolean") {
              hasRequiredFacet = true;
              var annotations = Object.keys(rsValue).filter(function (x) {
                  x = x.trim();
                  return x.length > 1 && x.charAt(0) == "(" && x.charAt(x.length - 1) == ")";
              });
              if (annotations.length) {
                  result.annotations = annotations.map(function (x) {
                      x = x.trim();
                      return {
                          name: x.substring(1, x.length - 1).trim(),
                          key: x,
                          value: rsValue[x]
                      };
                  });
              }
          }
          if (rsValue === false) {
              result.optional = true;
              result.id = n.key();
          }
      }
      var name = n.key();
      if (!hasRequiredFacet && endsWithQuestionMark(n.key())) {
          name = name.substr(0, name.length - 1);
          result.optional = true;
      }
      if (name != null && name.length == 0 || name === '/.*/') {
          result.additonal = true;
      }
      else if (name.charAt(0) == '/' && name.charAt(name.length - 1) == '/') {
          name = name.substring(1, name.length - 1);
          result.regExp = true;
      }
      var tp1 = [].concat(typePath);
      tp1.push(name);
      result.type = parse(null, n, tr, false, false, false, false, true, tp1);
      var chainingData = n.getMeta("chaining");
      if (chainingData && chainingData.length > 0) {
          if (result.type.metaOfType(meta.ImportedByChain).length == 0) {
              var target = result.type;
              if (result.type.isArray()) {
                  var compMeta = result.type.metaOfType(rs.ComponentShouldBeOfType);
                  if (compMeta && compMeta.length > 0) {
                      var rt = compMeta[0].value();
                      target = ts.derive("", [rt]);
                      compMeta[0].type = target;
                  }
              }
              else if (result.type.isUnion()) {
                  var opts = result.type.allOptions();
                  if (opts.length > 0) {
                      target = ts.derive("", [opts[0]]);
                      opts[0] = target;
                  }
              }
              if (target.metaOfType(meta.ImportedByChain).length == 0) {
                  if (!target.isSubTypeOf(ts.UNKNOWN) && ts.InheritedType.isInstance(target)) {
                      target.addSuper(ts.UNKNOWN);
                  }
                  for (var _i = 0, chainingData_1 = chainingData; _i < chainingData_1.length; _i++) {
                      var cd = chainingData_1[_i];
                      target.addMeta(new meta.ImportedByChain(cd.value));
                  }
              }
              if (!target.isSubTypeOf(ts.UNKNOWN)) {
                  if (ts.InheritedType.isInstance(target)) {
                      target.addSuper(ts.UNKNOWN);
                  }
              }
              for (var _a = 0, chainingData_2 = chainingData; _a < chainingData_2.length; _a++) {
                  var cd = chainingData_2[_a];
                  target.addMeta(new meta.ImportedByChain(cd.value));
              }
          }
      }
      result.id = name;
      return result;
  }
  exports.parsePropertyBean = parsePropertyBean;
  var TypeProto = /** @class */ (function () {
      function TypeProto() {
      }
      TypeProto.prototype.toJSON = function () {
          var result = {};
          if (this.superTypes && this.superTypes.length > 0) {
              if (this.superTypes.length == 1) {
                  result['type'] = this.superTypes[0];
              }
              else {
                  result['type'] = this.superTypes;
              }
          }
          if (this.customFacets) {
              this.customFacets.forEach(function (x) { return result[x.facetName()] = x.value(); });
          }
          if (this.annotations) {
              this.annotations.forEach(function (x) { return result["(" + x.facetName() + ")"] = x.value(); });
          }
          if (this.facetDeclarations && this.facetDeclarations.length > 0) {
              var facets = {};
              this.facetDeclarations.forEach(function (x) {
                  var nm = x.facetName();
                  if (x.isOptional()) {
                      nm = nm + "?";
                  }
                  var vl = null;
                  if (x.type().isAnonymous()) {
                      if (x.type().isEmpty()) {
                          vl = typeToSignature(x.type());
                      }
                      else {
                          vl = toProto(x.type()).toJSON();
                      }
                  }
                  else {
                      vl = typeToSignature(x.type());
                  }
                  facets[nm] = vl;
              });
              result['facets'] = facets;
          }
          if (this.properties && this.properties.length > 0) {
              var properties = {};
              this.properties.forEach(function (x) {
                  var nm = x.id;
                  if (x.optional) {
                      nm = nm + "?";
                  }
                  if (x.additonal) {
                      nm = "/.*/";
                  }
                  if (x.regExp) {
                      nm = "/" + x.id + "/";
                  }
                  var vl = null;
                  if (x.type.isAnonymous()) {
                      if (x.type.isEmpty()) {
                          vl = typeToSignature(x.type);
                      }
                      else {
                          vl = toProto(x.type).toJSON();
                      }
                  }
                  else {
                      vl = typeToSignature(x.type);
                  }
                  properties[nm] = vl;
              });
              result['properties'] = properties;
          }
          if (this.basicFacets) {
              this.basicFacets.forEach(function (x) {
                  result[x.facetName()] = x.value();
              });
          }
          if (Object.keys(result).length == 1 && !this.notAScalar) {
              if (result['type']) {
                  return result['type'];
              }
          }
          if (this.additionalProperties !== undefined) {
              result["additionalProperties"] = this.additionalProperties;
          }
          return result;
      };
      return TypeProto;
  }());
  exports.TypeProto = TypeProto;
  function toProto(type) {
      var result = new TypeProto();
      result.name = type.name();
      result.superTypes = type.superTypes().map(function (x) { return typeToSignature(x); });
      result.annotations = [];
      result.customFacets = [];
      result.facetDeclarations = [];
      result.basicFacets = [];
      result.properties = [];
      var pmap = {};
      type.declaredMeta().forEach(function (x) {
          if (x instanceof meta.Annotation) {
              result.annotations.push(x);
          }
          else if (x instanceof meta.CustomFacet) {
              result.customFacets.push(x);
          }
          else if (x instanceof meta.NotScalar) {
              result.notAScalar = true;
          }
          else if (x instanceof metainfo_1.FacetDeclaration) {
              result.facetDeclarations.push(x);
          }
          else {
              if (x instanceof rs.HasProperty) {
                  if (pmap.hasOwnProperty(x.value())) {
                      pmap[x.value()].optional = false;
                  }
                  else {
                      var pbean = new PropertyBean();
                      pbean.optional = false;
                      pbean.id = x.value();
                      pbean.type = ts.ANY;
                      pmap[x.value()] = pbean;
                  }
              }
              else if (x instanceof rs.AdditionalPropertyIs) {
                  var pbean = new PropertyBean();
                  pbean.optional = false;
                  pbean.id = ".*";
                  pbean.additonal = true;
                  pbean.type = x.value();
                  pbean.optional = x.isOptional();
                  pbean.regExp = true;
                  pmap['/.*/'] = pbean;
              }
              else if (rs.MapPropertyIs.isInstance(x)) {
                  var pbean = new PropertyBean();
                  pbean.optional = false;
                  pbean.id = x.regexpValue();
                  pbean.regExp = true;
                  pbean.type = x.value();
                  pbean.optional = x.isOptional();
                  pmap[x.regexpValue()] = pbean;
              }
              else if (rs.PropertyIs.isInstance(x)) {
                  if (pmap.hasOwnProperty(x.propertyName())) {
                      pmap[x.propertyName()].type = x.value();
                  }
                  else {
                      var pbean = new PropertyBean();
                      pbean.optional = true;
                      pbean.id = x.propertyName();
                      pbean.type = x.value();
                      pmap[x.propertyName()] = pbean;
                  }
              }
              else if (rs.KnownPropertyRestriction.isInstance(x)) {
                  result.additionalProperties = x.value();
              }
              else if (meta.DiscriminatorValue.isInstance(x)) {
                  if (x.isStrict()) {
                      result.basicFacets.push(x);
                  }
              }
              else if (!meta.HasPropertiesFacet.isInstance(x)) {
                  result.basicFacets.push(x);
              }
          }
      });
      Object.keys(pmap).forEach(function (x) { return result.properties.push(pmap[x]); });
      return result;
  }
  exports.toProto = toProto;
  /***
   * stores a type to JSON structure
   * @param ts
   */
  function storeAsJSON(ts) {
      if (ts instanceof typesystem_1.AbstractType) {
          return toProto(ts).toJSON();
      }
      else {
          return storeTypeCollection(ts);
      }
  }
  exports.storeAsJSON = storeAsJSON;
  function storeTypeCollection(tc) {
      var res = {};
      var types = {};
      tc.types().forEach(function (x) {
          types[x.name()] = storeAsJSON(x);
      });
      if (Object.keys(types).length > 0) {
          res["types"] = types;
      }
      var types = {};
      tc.annotationTypes().forEach(function (x) {
          types[x.name()] = storeAsJSON(x);
      });
      if (Object.keys(types).length > 0) {
          res["annotationTypes"] = types;
      }
      return res;
  }
  function typeToSignature(t) {
      if (t.isAnonymous()) {
          if (t.isArray()) {
              var ci = t.oneMeta(rs.ComponentShouldBeOfType);
              if (ci) {
                  var vl = ci.value();
                  if (vl.isAnonymous() && vl.isUnion()) {
                      return "(" + typeToSignature(vl) + ")" + "[]";
                  }
                  return typeToSignature(vl) + "[]";
              }
          }
          if (t.isUnion()) {
              return t.options().map(function (x) { return typeToSignature(x); }).join(" | ");
          }
          return t.superTypes().map(function (x) { return typeToSignature(x); }).join(" , ");
      }
      return t.name();
  }
  /**
   * Analogue of type.isSubTypeOf(), but also checks through unions
   * @param potentialSubtype
   * @param potentialSupertype
   */
  function isSubtypeOf(potentialSubtype, potentialSupertype) {
      //TODO this algorithm should be moved to type.isSubTypeOf() after release (now leaving it here for safety)
      if (potentialSupertype === ts.ANY ||
          potentialSubtype === potentialSupertype ||
          potentialSubtype.superTypes().some(function (currentSuperType) { return isSubtypeOf(currentSuperType, potentialSupertype); })) {
          return true;
      }
      if (potentialSubtype.isUnion() && potentialSubtype.options) {
          var options = potentialSubtype.options();
          if (options.some(function (option) { return isSubtypeOf(option, potentialSupertype); }))
              return true;
      }
      if (potentialSupertype.isUnion() && potentialSupertype.options) {
          var options = potentialSupertype.options();
          if (options.some(function (option) { return potentialSubtype == option; }))
              return true;
      }
      return false;
  }
  function testFacetAgainstType(facet, type) {
      var requiredType = facet.requiredType();
      var requiredTypes = facet.requiredTypes();
      if (requiredTypes && requiredTypes.length > 0) {
          return requiredTypes.some(function (currentRType) { return isSubtypeOf(type, currentRType); });
      }
      else {
          return isSubtypeOf(type, requiredType);
      }
  }
  function appendAnnotations(appendedInfo, childNode) {
      var arr = childNode.kind() == NodeKind.ARRAY ? childNode.children() : [childNode];
      for (var i = 0; i < arr.length; i++) {
          var children = arr[i].children();
          for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
              var ch = children_1[_i];
              var key = ch.key();
              if (key && key.charAt(0) == "(" && key.charAt(key.length - 1) == ")") {
                  var aName = key.substring(1, key.length - 1);
                  var aInstance = new meta.Annotation(aName, ch.value(), key, false, i);
                  aInstance.setOwnerFacet(appendedInfo);
                  aInstance._owner = appendedInfo._owner;
                  appendedInfo.addAnnotation(aInstance);
              }
          }
      }
  }
  var checkIfSkipValidation = function (sp, n) {
      if (n.getMeta("skipValidation")) {
          sp.addMeta(new meta.SkipValidation());
      }
  };
  /**
   * parses a type from a JSON structure
   * @param name
   * @param n
   * @param r
   * @returns {any}
   */
  function parse(name, n, r, defaultsToAny, annotation, global, ignoreTypeAttr, isPropertyType, typePath) {
      if (r === void 0) { r = ts.builtInRegistry(); }
      if (typePath.length == 0) {
          typePath = [name];
      }
      //mentioning fragment' uses
      var uses = n.childWithKey("uses");
      if (uses) {
          if (uses.kind() === NodeKind.ARRAY) {
              uses = transformToArray(uses);
          }
          if (uses.kind() === NodeKind.MAP) {
              var col = new TypeCollection(n.path());
              uses.children().forEach(function (c) {
                  col.addLibrary(c.key(), parseTypeCollection(c, ts.builtInRegistry()));
              });
              r = new AccumulatingRegistry(null, null, r, col);
          }
      }
      if (n.kind() == NodeKind.SCALAR) {
          var valString = n.value();
          var sp;
          if (valString == null || valString == "Null" || valString == "NULL") {
              sp = ts.STRING;
          }
          else {
              sp = typeExpressions.parseToType("" + valString, r, n, null, isPropertyType);
          }
          if (name == null) {
              checkIfSkipValidation(sp, n);
              return sp;
          }
          var res = ts.derive(name, [sp]);
          var chainingData = n.getMeta("chaining");
          if (sp && chainingData && chainingData.length > 0) {
              var target = res;
              if (sp.isArray()) {
                  var compMeta = sp.metaOfType(rs.ComponentShouldBeOfType);
                  if (compMeta && compMeta.length > 0) {
                      var rt = compMeta[0].value();
                      target = ts.derive("", [rt]);
                      compMeta[0].type = target;
                  }
              }
              else if (sp.isUnion()) {
                  var opts = sp.allOptions();
                  if (opts.length > 0) {
                      target = ts.derive("", [opts[0]]);
                      opts[0] = target;
                  }
              }
              if (target.metaOfType(meta.ImportedByChain).length == 0) {
                  if (!target.isSubTypeOf(ts.UNKNOWN)) {
                      target.addSuper(ts.UNKNOWN);
                  }
                  for (var _i = 0, chainingData_3 = chainingData; _i < chainingData_3.length; _i++) {
                      var cd = chainingData_3[_i];
                      target.addMeta(new meta.ImportedByChain(cd.value));
                  }
              }
          }
          if (AccumulatingRegistry.isInstance(r)) {
              res = contributeToAccumulatingRegistry(res, r);
          }
          checkIfSkipValidation(res, n);
          return res;
      }
      if (n.kind() == NodeKind.ARRAY) {
          var supers = [];
          n.children().forEach(function (x) {
              supers.push(typeExpressions.parseToType("" + x.value(), r, n, null, isPropertyType));
          });
          var res = ts.derive(name, supers);
          if (AccumulatingRegistry.isInstance(r)) {
              res = contributeToAccumulatingRegistry(res, r);
          }
          checkIfSkipValidation(res, n);
          return res;
      }
      var superTypes = [];
      var tp = n.childWithKey("type");
      var shAndType = false;
      if (!tp) {
          tp = n.childWithKey("schema");
      }
      else {
          if (n.childWithKey("schema")) {
              shAndType = true;
          }
      }
      var typePropAnnotations = [];
      if (!tp || (!tp.children().length && !tp.value()) || ignoreTypeAttr) {
          if (defaultsToAny) {
              if (n.childWithKey("properties")) {
                  superTypes = [ts.OBJECT];
              }
              else {
                  superTypes = [ts.ANY];
              }
          }
          else {
              if (n.childWithKey("properties")) {
                  superTypes = [ts.OBJECT];
              }
              else {
                  superTypes = [ts.STRING];
              }
          }
      }
      else {
          var sAnnotations = [];
          var actual = tp.childWithKey("value");
          if (actual && (actual.kind() == NodeKind.SCALAR || actual.kind() == NodeKind.ARRAY)) {
              sAnnotations = [tp.children().filter(function (x) {
                      var key = x.key();
                      if (!key) {
                          return false;
                      }
                      return key.charAt(0) == "(" && key.charAt(key.length - 1) == ")";
                  })];
              tp = actual;
          }
          if (tp.kind() == NodeKind.SCALAR) {
              var valString = tp.value();
              if (valString == null || valString == "Null" || valString == "NULL") {
                  superTypes = [ts.STRING];
              }
              else {
                  var typeAttributeContentProvider = tp.contentProvider ? tp.contentProvider() : null;
                  var st = typeExpressions.parseToType("" + valString, r, n, typeAttributeContentProvider, isPropertyType);
                  superTypes = [st];
              }
          }
          else if (tp.kind() == NodeKind.ARRAY) {
              superTypes = tp.children().map(function (x) {
                  var actual = x.childWithKey("value");
                  if (actual && (actual.kind() == NodeKind.SCALAR || actual.kind() == NodeKind.ARRAY)) {
                      sAnnotations.push(x.children().filter(function (x) {
                          var key = x.key();
                          if (!key) {
                              return false;
                          }
                          return key.charAt(0) == "(" && key.charAt(key.length - 1) == ")";
                      }));
                      x = actual;
                  }
                  else {
                      sAnnotations.push([]);
                  }
                  return x.value();
              }).map(function (y) { return typeExpressions.parseToType("" + y, r, n, null, isPropertyType); });
          }
          else if (tp.kind() == NodeKind.MAP) {
              var tp1 = [].concat(typePath);
              tp1.push("#super");
              superTypes = [parse("", tp, r, false, false, false, false, false, tp1)];
          }
          if (sAnnotations.length > 0 && sAnnotations.filter(function (x) { return x.length > 0; }).length > 0) {
              for (var _a = 0, sAnnotations_1 = sAnnotations; _a < sAnnotations_1.length; _a++) {
                  var aArr = sAnnotations_1[_a];
                  var aiArr = [];
                  typePropAnnotations.push(aiArr);
                  for (var _b = 0, aArr_1 = aArr; _b < aArr_1.length; _b++) {
                      var ann = aArr_1[_b];
                      var key = ann.key();
                      var aName = key.substring(1, key.length - 1);
                      var aInstance = new meta.Annotation(aName, ann.value(), key);
                      aInstance.setNode(ann);
                      aiArr.push(aInstance);
                  }
              }
          }
      }
      for (var _d = 0, superTypes_1 = superTypes; _d < superTypes_1.length; _d++) {
          var st = superTypes_1[_d];
          if (st.superTypes().indexOf(ts.REFERENCE) >= 0) {
              r.get(st.name());
          }
      }
      var result = ts.derive(name, superTypes);
      if (ignoreTypeAttr && tp) {
          result.addMeta(new meta.TypeAttributeValue(tp.value()));
      }
      for (var i = 0; i < typePropAnnotations.length; i++) {
          var aArr1 = typePropAnnotations[i];
          result.addSupertypeAnnotation(aArr1, i);
      }
      if (name != null && name.length > 0 && AccumulatingRegistry.isInstance(r)) {
          result = contributeToAccumulatingRegistry(result, r);
      }
      var actualResult = result;
      var hasfacetsOrOtherStuffDoesNotAllowedInExternals = null;
      n.children().forEach(function (childNode) {
          var key = childNode.key();
          var actual = childNode.childWithKey("value");
          var x = childNode;
          if (key != "example" && key != "discriminatorValue" && actual) {
              x = actual;
          }
          if (!key) {
              return;
          }
          if (key === "type") {
              return;
          }
          if (key === "uses") {
              //FIXME this should be handled depending from parse level
              return;
          }
          if (key === "schema") {
              return;
          }
          if (key == "properties" || key == "additionalProperties") {
              if (result.isSubTypeOf(ts.OBJECT)) {
                  return;
              }
          }
          var appendedInfo;
          if (key == "items") {
              if (result.isSubTypeOf(ts.ARRAY)) {
                  var componentTypes = [];
                  var arr = [x];
                  if (x.kind() == NodeKind.ARRAY) {
                      arr = x.children();
                      var err_1 = ts.error(messageRegistry.ITEMS_SHOULD_BE_REFERENCE_OR_INLINE_TYPE, actualResult);
                      err_1.setValidationPath({ name: "items" });
                      result.putExtra(tsInterfaces.PARSE_ERROR, err_1);
                  }
                  var componentTypes = arr.map(function (y) {
                      var actual = y.childWithKey("value");
                      if (actual && (actual.kind() == NodeKind.SCALAR || actual.kind() == NodeKind.MAP)) {
                          y = actual;
                      }
                      if (y.kind() == NodeKind.SCALAR) {
                          var valString = y.value();
                          if (valString == null || valString == "Null" || valString == "NULL") {
                              return ts.STRING;
                          }
                          else {
                              var res_1 = typeExpressions.parseToType("" + valString, r, n);
                              checkIfSkipValidation(res_1, x);
                              return res_1;
                          }
                      }
                      else if (y.kind() == NodeKind.MAP) {
                          var tp1 = [].concat(typePath);
                          tp1.push("#super");
                          return parse("", y, r, false, false, false, false, false, tp1);
                      }
                  });
                  var tp = componentTypes.length == 1 ? componentTypes[0] :
                      ts.derive("", componentTypes);
                  appendedInfo = new restrictions_1.ComponentShouldBeOfType(tp);
                  actualResult.addMeta(appendedInfo);
                  actualResult.putExtra(tsInterfaces.HAS_ITEMS, true);
                  appendAnnotations(appendedInfo, childNode);
                  return appendedInfo;
              }
              else if (!ignoreTypeAttr) {
                  var err_2 = ts.error(messageRegistry.ITEMS_DEFINED_FOR_NON_ARRAY, actualResult);
                  err_2.setValidationPath({ name: "items" });
                  result.putExtra(tsInterfaces.PARSE_ERROR, err_2);
              }
          }
          else {
              if (key == "required" && !isPropertyType) {
                  return;
              }
              if (key === "facets") {
                  hasfacetsOrOtherStuffDoesNotAllowedInExternals = [key];
                  return;
              }
              else if (key == "default" || key == "xml" || key == "required") {
                  hasfacetsOrOtherStuffDoesNotAllowedInExternals =
                      hasfacetsOrOtherStuffDoesNotAllowedInExternals ?
                          hasfacetsOrOtherStuffDoesNotAllowedInExternals.concat(key) : [key];
              }
              else if (key.charAt(0) == '(' && key.charAt(key.length - 1) == ')') {
                  var a = new meta.Annotation(key.substr(1, key.length - 2), x.value(), key);
                  a.setNode(x);
                  result.addMeta(a);
                  return;
              }
              appendedInfo = facetR.getInstance().buildFacet(key, x.value());
              //TODO remove "format" condition and use this check for all facets
              if (appendedInfo && (key != "format" || testFacetAgainstType(appendedInfo, result))) {
                  appendedInfo.setNode(x);
                  result.addMeta(appendedInfo);
              }
              else {
                  // if (annotation && key === "allowedTargets") {
                  //     result.addMeta(new meta.AllowedTargets(x.value()));
                  // }
                  { //else {
                      var customFacet = new meta.CustomFacet(key, x.value());
                      customFacet.setNode(x);
                      result.addMeta(customFacet);
                  }
              }
          }
          if (appendedInfo) {
              appendAnnotations(appendedInfo, childNode);
          }
      });
      if (result.metaOfType(meta.DiscriminatorValue).length == 0 && global) {
          result.addMeta(new meta.DiscriminatorValue(result.name(), false));
      }
      if (result.isSubTypeOf(ts.OBJECT)) {
          var props = n.childWithKey("properties");
          var hasProps = false;
          if (props) {
              result.addMeta(new meta.HasPropertiesFacet());
              if (props.kind() == NodeKind.MAP) {
                  props.children().forEach(function (x) {
                      hasProps = true;
                      var tp1 = [].concat(typePath);
                      tp1.push("#props");
                      parsePropertyBean(x, r, tp1).add(result, tp1);
                  });
              }
              else {
                  var err = ts.error(messageRegistry.PROPERTIES_MAP, actualResult);
                  err.setValidationPath({ name: "properties" });
                  result.putExtra(tsInterfaces.PARSE_ERROR, err);
              }
          }
          var ap = n.childWithKey("additionalProperties");
          if (ap) {
              var actual = ap.childWithKey("value");
              if (actual) {
                  ap = actual;
              }
              if (typeof (ap.value()) == "boolean") {
                  result.addMeta(new restrictions_2.KnownPropertyRestriction(ap.value()));
              }
              else {
                  var err = ts.error(messageRegistry.ADDITIONAL_PROPERTIES_BOOLEAN, actualResult);
                  err.setValidationPath({ name: "additionalProperties" });
                  result.putExtra(tsInterfaces.PARSE_ERROR, err);
              }
          }
      }
      var props = n.childWithKey("facets");
      if (props) {
          if (props.kind() == NodeKind.MAP) {
              props.children().forEach(function (x) {
                  var tp1 = [].concat(typePath);
                  tp1.push("#facets");
                  var bean = parsePropertyBean(x, r, tp1);
                  result.addMeta(new meta.FacetDeclaration(bean.id, bean.type, bean.optional));
              });
          }
          else {
              var err = ts.error(messageRegistry.FACETS_MAP, actualResult);
              err.setValidationPath({ name: "facets" });
              result.putExtra(tsInterfaces.PARSE_ERROR, err);
          }
      }
      if (result.isAnonymous() && result.isEmpty()) {
          if (result.superTypes().length == 1) {
              var res_2 = result.superTypes()[0];
              checkIfSkipValidation(res_2, n);
              return res_2;
          }
      }
      if (n.kind() != NodeKind.SCALAR) {
          result.addMeta(new meta.NotScalar());
      }
      if (shAndType) {
          actualResult.putExtra(ts.SCHEMA_AND_TYPE, true);
      }
      actualResult.putExtra(ts.GLOBAL, global);
      actualResult.putExtra(ts.SOURCE_EXTRA, n);
      if (hasfacetsOrOtherStuffDoesNotAllowedInExternals) {
          actualResult.putExtra(tsInterfaces.HAS_FACETS, hasfacetsOrOtherStuffDoesNotAllowedInExternals);
      }
      checkIfSkipValidation(actualResult, n);
      if (n.getMeta("acceptAllScalarsAsStrings")) {
          actualResult.addMeta(new meta.AcceptAllScalarsAsStrings());
      }
      return actualResult;
  }
  exports.parse = parse;
  function contributeToAccumulatingRegistry(result, r) {
      var existing;
      var _r = r;
      while (_r) {
          existing = _r.typeMap()[result.name()];
          if (existing) {
              break;
          }
          _r = _r.parent();
      }
      if (existing == null || !existing.isSubTypeOf(ts.REFERENCE)) {
          r.addType(result);
      }
      else if (existing != null && existing.isSubTypeOf(ts.REFERENCE)) {
          existing.patch(result);
          result = existing;
      }
      result.putExtra(tsInterfaces.TOP_LEVEL_EXTRA, true);
      return result;
  }
  ;
  //# sourceMappingURL=parse.js.map