"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 _ = require("underscore");
var su = require("./schemaUtil");
var tsInterfaces = require("./typesystem-interfaces");
exports.messageRegistry = require("../../resources/errorMessages");
var Status = /** @class */ (function () {
    function Status(severity, code, message, source, takeNodeFromSource) {
        if (takeNodeFromSource === void 0) { takeNodeFromSource = false; }
        this.takeNodeFromSource = takeNodeFromSource;
        this.subStatus = [];
        this.severity = severity;
        this.code = code;
        this.message = message;
        this.source = source;
    }
    Status.prototype.getValidationPath = function () {
        return this.vp;
    };
    Status.prototype.getValidationPathAsString = function () {
        if (!this.vp) {
            return "";
        }
        var s = "";
        var c = this.vp;
        while (c) {
            s += c.name;
            if (c.child) {
                s += '/';
            }
            c = c.child;
        }
        return s;
    };
    Status.prototype.setValidationPath = function (_c) {
        this.vp = _c;
    };
    Status.prototype.addSubStatus = function (st, pathName) {
        if (pathName === void 0) { pathName = null; }
        if (!st) {
            return;
        }
        if (pathName) {
            setValidationPath(st, { name: pathName });
        }
        this.subStatus.push(st);
        var otherSeverity = Status.OK;
        if (!st.isOk()) {
            if (st.isError()) {
                otherSeverity = Status.ERROR;
            }
            else if (st.isWarning()) {
                otherSeverity = Status.WARNING;
            }
            else if (st.isInfo()) {
                otherSeverity = Status.INFO;
            }
        }
        if (this.severity < otherSeverity) {
            this.severity = otherSeverity;
            this.message = st.getMessage();
        }
    };
    Status.prototype.getErrors = function () {
        if (this.isError() || this.isWarning()) {
            if (this.subStatus.length > 0) {
                var rs = [];
                this.subStatus.forEach(function (x) { return rs = rs.concat(x.getErrors()); });
                return rs;
            }
            return [this];
        }
        return [];
    };
    Status.prototype.getSubStatuses = function () {
        return this.subStatus;
    };
    Status.prototype.getSeverity = function () {
        return this.severity;
    };
    Status.prototype.getMessage = function () {
        return this.message;
    };
    Status.prototype.setMessage = function (message) {
        this.message = message;
    };
    Status.prototype.getSource = function () {
        return this.source;
    };
    Status.prototype.getCode = function () {
        return this.code;
    };
    Status.prototype.setCode = function (code) {
        this.code = code;
    };
    Status.prototype.isWarning = function () {
        return this.severity == Status.WARNING;
    };
    Status.prototype.isError = function () {
        return this.severity == Status.ERROR;
    };
    Status.prototype.isOk = function () {
        return this.severity === Status.OK;
    };
    Status.prototype.isInfo = function () {
        return this.severity === Status.INFO;
    };
    Status.prototype.setSource = function (s) {
        this.source = s;
    };
    Status.prototype.toString = function () {
        if (this.isOk()) {
            return "OK";
        }
        return this.message;
    };
    Status.prototype.getExtra = function (name) {
        if (this.takeNodeFromSource && name == tsInterfaces.SOURCE_EXTRA) {
            if (this.source instanceof TypeInformation) {
                return this.source.node();
            }
        }
        return null;
    };
    Status.prototype.putExtra = function (name, value) { };
    Status.prototype.setInternalRange = function (range) {
        this.internalRange = range;
    };
    Status.prototype.getInternalRange = function () { return this.internalRange; };
    Status.prototype.getInternalPath = function () {
        return this.internalPath;
    };
    Status.prototype.setInternalPath = function (ip) {
        this.internalPath = ip;
    };
    Status.prototype.getFilePath = function () {
        return this.filePath;
    };
    Status.prototype.setFilePath = function (filePath) {
        this.filePath = filePath;
    };
    Status.CODE_CONFLICTING_TYPE_KIND = 4;
    Status.CODE_INCORRECT_DISCRIMINATOR = exports.messageRegistry.INCORRECT_DISCRIMINATOR;
    Status.CODE_MISSING_DISCRIMINATOR = exports.messageRegistry.MISSING_DISCRIMINATOR;
    Status.ERROR = 3;
    Status.INFO = 1;
    Status.OK = 0;
    Status.WARNING = 2;
    return Status;
}());
exports.Status = Status;
function ok() { return new Status(Status.OK, "", "", null); }
exports.ok = ok;
;
exports.SCHEMA_AND_TYPE = tsInterfaces.SCHEMA_AND_TYPE_EXTRA;
exports.GLOBAL = tsInterfaces.GLOBAL_EXTRA;
exports.TOPLEVEL = tsInterfaces.TOP_LEVEL_EXTRA;
exports.SOURCE_EXTRA = tsInterfaces.SOURCE_EXTRA;
var messageText = function (messageEntry, params) {
    var result = "";
    var msg = messageEntry.message;
    var prev = 0;
    for (var ind = msg.indexOf("{{"); ind >= 0; ind = msg.indexOf("{{", prev)) {
        result += msg.substring(prev, ind);
        prev = msg.indexOf("}}", ind);
        if (prev < 0) {
            prev = ind;
            break;
        }
        ind += "{{".length;
        var paramName = msg.substring(ind, prev);
        prev += "}}".length;
        var paramValue = params[paramName];
        if (paramValue === undefined) {
            throw new Error(messageText(exports.messageRegistry.MESSAGE_PARAMETER_NO_VALUE, { paramName: paramName }));
        }
        result += paramValue;
    }
    result += msg.substring(prev, msg.length);
    return result;
};
function error(messageEntry, source, params, severity, takeNodeFromSource) {
    if (params === void 0) { params = {}; }
    if (severity === void 0) { severity = Status.ERROR; }
    if (takeNodeFromSource === void 0) { takeNodeFromSource = false; }
    var message = messageText(messageEntry, params);
    return new Status(severity, messageEntry.code, message, source, takeNodeFromSource);
}
exports.error = error;
var TypeInformation = /** @class */ (function () {
    function TypeInformation(_inheritable) {
        this._inheritable = _inheritable;
        this._annotations = [];
    }
    TypeInformation.prototype.getClassIdentifier = function () {
        var superIdentifiers = [];
        return superIdentifiers.concat(TypeInformation.CLASS_IDENTIFIER_TypeInformation);
    };
    TypeInformation.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), TypeInformation.CLASS_IDENTIFIER_TypeInformation);
    };
    TypeInformation.prototype.node = function () {
        return this._node;
    };
    TypeInformation.prototype.setNode = function (node) {
        this._node = node;
    };
    TypeInformation.prototype.owner = function () {
        return this._owner;
    };
    TypeInformation.prototype.isInheritable = function () {
        return this._inheritable;
    };
    TypeInformation.prototype.validateSelf = function (registry) {
        var result = ok();
        if (this.node() && this.node().getMeta("skipValidation")) {
            return result;
        }
        for (var _i = 0, _a = this._annotations; _i < _a.length; _i++) {
            var a = _a[_i];
            var aStatus = a.validateSelf(registry);
            if (!aStatus.isOk()) {
                result.addSubStatus(aStatus);
            }
        }
        var facetEntry = new AnnotatedFacet(this, registry);
        var aPluginStatuses = applyAnnotationValidationPlugins(facetEntry);
        for (var _b = 0, aPluginStatuses_1 = aPluginStatuses; _b < aPluginStatuses_1.length; _b++) {
            var ps = aPluginStatuses_1[_b];
            if (!ps.isOk()) {
                result.addSubStatus(ps);
            }
        }
        setValidationPath(result, { name: this.facetName() });
        return this.validateSelfIndividual(result, registry);
    };
    TypeInformation.prototype.validateSelfIndividual = function (parentStatus, registry) {
        return parentStatus;
    };
    /**
     * Extension of requiredType() method for the case when there are more than a single type
     * hierarchy roots to cover.
     * requiredType() should return the common superclass for the list.
     *
     * @returns {Array} of types or empty list of there is only a single type set by requiredType() method
     */
    TypeInformation.prototype.requiredTypes = function () {
        return [];
    };
    TypeInformation.prototype.annotations = function () {
        return this._annotations;
    };
    TypeInformation.prototype.addAnnotation = function (a) {
        this._annotations.push(a);
    };
    TypeInformation.prototype.isConstraint = function () {
        return false;
    };
    TypeInformation.CLASS_IDENTIFIER_TypeInformation = "typesystem.TypeInformation";
    return TypeInformation;
}());
exports.TypeInformation = TypeInformation;
var stack = null;
var Constraint = /** @class */ (function (_super) {
    __extends(Constraint, _super);
    function Constraint(_inheritable) {
        if (_inheritable === void 0) { _inheritable = true; }
        return _super.call(this, _inheritable) || this;
    }
    Constraint.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(Constraint.CLASS_IDENTIFIER_Constraint);
    };
    Constraint.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), Constraint.CLASS_IDENTIFIER_Constraint);
    };
    Constraint.prototype.intersect = function (t0, t1) {
        var nm = t0.id() + "" + t1.id();
        if (Constraint.intersections.hasOwnProperty(nm)) {
            return Constraint.intersections[nm];
        }
        var is = intersect(nm, [t0, t1]);
        Constraint.intersections[nm] = is;
        return is;
    };
    Constraint.prototype.release = function (t) {
        delete Constraint.intersections[t.name()];
    };
    Constraint.prototype.nothing = function (c, message) {
        if (message === void 0) { message = "Conflicting restrictions"; }
        return new NothingRestrictionWithLocation(stack, message, c);
    };
    /**
     * inner implementation of  compute composed restriction from this and parameter restriction
     * @param restriction
     * @return  composed restriction or null;
     */
    Constraint.prototype.composeWith = function (r) { return null; };
    /**
     * returns optimized restiction or this
     * @returns {Constraint}
     */
    Constraint.prototype.preoptimize = function () {
        if (stack === null) {
            stack = new RestrictionStackEntry(null, null, "top");
        }
        stack = stack.push(this);
        try {
            return this.innerOptimize();
        }
        finally {
            stack = stack.pop();
        }
    };
    Constraint.prototype.innerOptimize = function () {
        return this;
    };
    /**
     * performs attempt to compute composed restriction from this and parameter restriction
     * @param restriction
     * @return  composed restriction or null;
     */
    Constraint.prototype.tryCompose = function (r) {
        if (stack === null) {
            stack = new RestrictionStackEntry(null, null, "top");
        }
        stack = stack.push(this);
        try {
            return this.composeWith(r);
        }
        finally {
            stack = stack.pop();
        }
    };
    Constraint.prototype.kind = function () {
        return tsInterfaces.MetaInformationKind.Constraint;
    };
    Constraint.prototype.conflictMessage = function (otherPath, otherValue) { return null; };
    Constraint.prototype.isConstraint = function () {
        return true;
    };
    Constraint.CLASS_IDENTIFIER_Constraint = "typesystem.TypeInformation";
    Constraint.intersections = {};
    return Constraint;
}(TypeInformation));
exports.Constraint = Constraint;
var restr = require("./restrictions");
var metaInfo = require("./metainfo");
var fr = require("./facetRegistry");
var restrictions_1 = require("./restrictions");
var metainfo_1 = require("./metainfo");
var metainfo_2 = require("./metainfo");
var restrictions_2 = require("./restrictions");
var restrictions_3 = require("./restrictions");
var exO = require("./exampleBuilder");
var metainfo_3 = require("./metainfo");
var restrictions_4 = require("./restrictions");
exports.autoCloseFlag = false;
/**
 * Registry of the types
 */
var TypeRegistry = /** @class */ (function () {
    function TypeRegistry(_parent, _c, isAnnotationsReg) {
        if (_parent === void 0) { _parent = null; }
        if (isAnnotationsReg === void 0) { isAnnotationsReg = false; }
        this._parent = _parent;
        this._c = _c;
        this.isAnnotationsReg = isAnnotationsReg;
        this._types = {};
        this.typeList = [];
        this.chainedTypes = {};
    }
    TypeRegistry.prototype.getClassIdentifier = function () {
        var superIdentifiers = [];
        return superIdentifiers.concat(TypeRegistry.CLASS_IDENTIFIER_TypeRegistry);
    };
    TypeRegistry.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), TypeRegistry.CLASS_IDENTIFIER_TypeRegistry);
    };
    TypeRegistry.prototype.put = function (alias, t) {
        this._types[alias] = t;
    };
    TypeRegistry.prototype.addType = function (t) {
        if (t.isAnonymous()) {
            return;
        }
        this._types[t.name()] = t;
        this.typeList.push(t);
    };
    TypeRegistry.prototype.get = function (name) {
        if (this._types.hasOwnProperty(name)) {
            return this._types[name];
        }
        if (this._parent != null) {
            return this._parent.get(name);
        }
        return null;
    };
    TypeRegistry.prototype.getByChain = function (name) {
        var result = this.get(name);
        if (!result) {
            result = this.chainedTypes[name];
        }
        if (result) {
            return result;
        }
        result = this.getTypeByChainFromCollection(name, this._c);
        if (result) {
            this.chainedTypes[name] = result;
        }
        return result;
    };
    TypeRegistry.prototype.getTypeByChainFromCollection = function (name, collection) {
        var result = this.isAnnotationsReg ? collection.getAnnotationType(name) : collection.getType(name);
        if (result) {
            return result;
        }
        for (var dt_1 = name.indexOf('.'); dt_1 >= 0; dt_1 = name.indexOf('.', dt_1 + 1)) {
            var namespace = name.substring(0, dt_1);
            var typeName = name.substr(dt_1 + 1);
            var lib = collection.library(namespace);
            if (lib) {
                result = this.getTypeByChainFromCollection(typeName, lib);
                if (result) {
                    return result;
                }
            }
        }
        return null;
    };
    TypeRegistry.prototype.types = function () {
        return this.typeList;
    };
    TypeRegistry.prototype.typeMap = function () {
        return this._types;
    };
    TypeRegistry.prototype.parent = function () {
        return this._parent;
    };
    TypeRegistry.CLASS_IDENTIFIER_TypeRegistry = "typesystem.TypeRegistry";
    return TypeRegistry;
}());
exports.TypeRegistry = TypeRegistry;
var PropertyCyclesValidator = /** @class */ (function () {
    function PropertyCyclesValidator() {
    }
    PropertyCyclesValidator.prototype.getInfos = function (t) {
        if (t.getExtra("PInfos")) {
            return t.getExtra("PInfos");
        }
        var m = {};
        t.meta().forEach(function (x) {
            if (x instanceof restr.HasProperty) {
                var id = x.value();
                m[id] = { name: id, type: null };
            }
        });
        t.meta().forEach(function (x) {
            if (x instanceof restr.PropertyIs) {
                var id = x.propertyName();
                if (m[id]) {
                    m[id].type = x.value();
                }
            }
        });
        t.putExtra("PInfos", m);
        return m;
    };
    PropertyCyclesValidator.prototype.validate = function (t, visited) {
        var _this = this;
        var i = this.getInfos(t);
        var result = false;
        Object.keys(i).forEach(function (x) {
            result = result || _this.validateInfo(i[x], visited);
        });
        return result;
    };
    PropertyCyclesValidator.prototype.validateInfo = function (t, visited) {
        var _this = this;
        if (visited.some(function (y) { return y == t; })) {
            return true;
        }
        else {
            if (t.type instanceof UnionType) {
                var ut = t.type;
                var passing = true;
                ut.options().forEach(function (o) {
                    if (!_this.validate(o, [t].concat(visited))) {
                        passing = false;
                    }
                });
                return passing;
            }
            if (t.type.isArray()) {
            }
            else {
                return this.validate(t.type, [t].concat(visited));
            }
        }
    };
    PropertyCyclesValidator.prototype.validateType = function (t) {
        var _this = this;
        var i = this.getInfos(t);
        var result = [];
        Object.keys(i).forEach(function (x) {
            if (_this.validateInfo(i[x], [])) {
                result.push(x);
            }
        });
        return result;
    };
    return PropertyCyclesValidator;
}());
var RestrictionsConflict = /** @class */ (function (_super) {
    __extends(RestrictionsConflict, _super);
    function RestrictionsConflict(_conflicting, _stack, source) {
        var _this = _super.call(this, Status.ERROR, exports.messageRegistry.RESTRICTIONS_CONFLICT.code, null, source) || this;
        _this._conflicting = _conflicting;
        _this._stack = _stack;
        _this.source = source;
        _this.computeMessage();
        return _this;
    }
    RestrictionsConflict.prototype.computeMessage = function () {
        var conflictingMessage = null;
        if (this._stack != null) {
            if (this._stack.getRestriction() instanceof restr.MinMaxRestriction) {
                var mmr = this._stack.getRestriction();
                conflictingMessage = this._conflicting.conflictMessage(mmr.facetPath(), mmr.value());
            }
        }
        if (conflictingMessage == null) {
            conflictingMessage = this._conflicting + " and " + (this._stack != null ? this._stack.getRestriction().toString() : "");
        }
        var typeInfo = "";
        if (this.source instanceof AbstractType) {
            var path = [];
            var rse = this._stack;
            while (rse) {
                var restri = rse.getRestriction();
                if (restri instanceof restrictions_2.PropertyIs) {
                    var vp = { name: restri.propId() };
                    if (path.length > 0) {
                        vp.child = path[path.length - 1];
                    }
                    path.push(vp);
                }
                rse = rse.pop();
            }
            setValidationPath(this, path.pop());
            var arc = restr.anotherRestrictionComponent();
            if (arc) {
                typeInfo = " between types '" + typePath(this.source) + "' and '" + typePath(arc) + "'";
            }
            else {
                typeInfo = " in type '" + typePath(this.source) + "'";
            }
        }
        this.message = "Restrictions conflict" + typeInfo + ": " + conflictingMessage;
    };
    RestrictionsConflict.prototype.getConflictDescription = function () {
        var rs = "";
        rs += "Restrictions coflict:\n";
        rs += this._stack.getRestriction() + " conflicts with " + this._conflicting + "\n";
        rs += "at\n";
        rs += this._stack.pop();
        return rs;
    };
    RestrictionsConflict.prototype.getConflicting = function () {
        return this._conflicting;
    };
    RestrictionsConflict.prototype.getStack = function () {
        return this._stack;
    };
    RestrictionsConflict.prototype.toRestriction = function () {
        return new NothingRestrictionWithLocation(this._stack, this.message, this._conflicting);
    };
    return RestrictionsConflict;
}(Status));
exports.RestrictionsConflict = RestrictionsConflict;
var globalId = 0;
exports.VALIDATED_TYPE = null;
var PropertyInfo = /** @class */ (function () {
    function PropertyInfo(obj) {
        if (restr.MatchesProperty.isInstance(obj)) {
            this._matches = obj;
            var fn = this._matches.facetName();
            if (fn == "propertyIs") {
                this.isProp = true;
            }
            else if (fn == "mapPropertyIs") {
                this.isMap = true;
            }
            else if (fn == "additionalProperties") {
                this.isAdditionalProp = true;
            }
        }
        else {
            this.isFacet = true;
            this._facetDecl = obj;
        }
    }
    PropertyInfo.prototype.name = function () {
        return this.isFacet ? this._facetDecl.actualName() : this._matches.path();
    };
    PropertyInfo.prototype.isPattern = function () {
        return this.isMap;
    };
    PropertyInfo.prototype.isAdditional = function () {
        return this.isAdditionalProp;
    };
    PropertyInfo.prototype.declaredAt = function () {
        return this.isFacet ? this._facetDecl.owner() : this._matches.owner();
    };
    PropertyInfo.prototype.range = function () {
        return this.isFacet ? this._facetDecl.type() : this._matches.range();
    };
    PropertyInfo.prototype.required = function () {
        if (this._required !== undefined) {
            return this._required;
        }
        if (this.isProp) {
            return !this.property().isOptional();
        }
        else if (this.isMap) {
            return !this.mapProperty().isOptional();
        }
        else if (this.isAdditionalProp) {
            return !this.additionalProperty().isOptional();
        }
        return false;
    };
    PropertyInfo.prototype.setRequired = function (val) {
        this._required = val;
    };
    PropertyInfo.prototype.property = function () {
        return this.isProp ? this._matches : null;
    };
    PropertyInfo.prototype.mapProperty = function () {
        return this.isMap ? this._matches : null;
    };
    PropertyInfo.prototype.additionalProperty = function () {
        return this.isAdditionalProp ? this._matches : null;
    };
    PropertyInfo.prototype.annotations = function () {
        return this._matches ? this._matches.annotations() : [];
    };
    return PropertyInfo;
}());
exports.PropertyInfo = PropertyInfo;
var AbstractType = /** @class */ (function () {
    function AbstractType(_name) {
        this._name = _name;
        this.metaInfo = [];
        this._subTypes = [];
        this.innerid = globalId++;
        this.extras = {};
        this._locked = false;
    }
    AbstractType.prototype.getClassIdentifier = function () {
        var superIdentifiers = [];
        return superIdentifiers.concat(AbstractType.CLASS_IDENTIFIER_AbstractType);
    };
    AbstractType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), AbstractType.CLASS_IDENTIFIER_AbstractType);
    };
    AbstractType.prototype.annotation = function (name) {
        var res = null;
        for (var _i = 0, _a = this.annotations(); _i < _a.length; _i++) {
            var x = _a[_i];
            if (x.name() == name) {
                return x.value();
            }
        }
        return null;
    };
    AbstractType.prototype.isAssignableFrom = function (t) {
        if (t.allSuperTypes().indexOf(this) != -1) {
            return true;
        }
        //TODO make it better
        var ms = this.restrictions().filter(function (x) { return !metaInfo.DiscriminatorValue.isInstance(x); });
        var another = t.restrictions();
        var all = true;
        ms.forEach(function (x) {
            var found = false;
            another.forEach(function (y) {
                var vm = x.composeWith(y);
                if (vm == y) {
                    found = true;
                }
                if (GenericTypeOf.isInstance(y) && vm != null) {
                    if (vm == x) {
                        found = true;
                    }
                }
            });
            all = all && found;
        });
        return all;
    };
    AbstractType.prototype.registry = function () {
        return this._collection;
    };
    AbstractType.prototype.cloneWithFilter = function (x, f) {
        var c = this.clone();
        var ms = [];
        this.metaInfo.forEach(function (f) {
            var rs = x(f, c);
            if (typeof rs == "boolean") {
                if (rs) {
                    ms.push(f);
                }
            }
            else {
                if (rs) {
                    ms.push(rs);
                }
            }
        });
        c.metaInfo = ms;
        return c;
    };
    AbstractType.prototype.options = function () {
        if (this.isUnion()) {
            var res = [];
            this.allSuperTypes().forEach(function (x) {
                if (UnionType.isInstance(x)) {
                    var opts = x.options();
                    res = res.concat(opts);
                }
            });
            return _.unique(res);
        }
        return [this];
    };
    AbstractType.prototype.allOptions = function () {
        if (this.isUnion()) {
            var res = [];
            this.allSuperTypes().forEach(function (x) {
                if (UnionType.isInstance(x)) {
                    var opts = x.allOptions();
                    res = res.concat(opts);
                }
            });
            return _.unique(res);
        }
        return [this];
    };
    AbstractType.prototype.examples = function () {
        return exO.exampleFromInheritedType2(this);
    };
    AbstractType.prototype.collection = function () {
        if (!this._collection) {
            if (this._contextMeta) {
                var cm = this._contextMeta;
                if (cm) {
                    return cm.owner().collection();
                }
            }
        }
        return this._collection;
    };
    AbstractType.prototype.getExtra = function (name) {
        return this.extras[name];
    };
    AbstractType.prototype.putExtra = function (name, v) {
        this.extras[name] = v;
    };
    AbstractType.prototype.id = function () {
        return this.innerid;
    };
    AbstractType.prototype.knownProperties = function () {
        return this.metaOfType(restrictions_4.MatchesProperty);
    };
    AbstractType.prototype.lock = function () {
        this._locked = true;
    };
    AbstractType.prototype.isLocked = function () {
        return this._locked;
    };
    AbstractType.prototype.patchName = function (name) {
        this._name = name;
    };
    AbstractType.prototype.allFacets = function () {
        return this.meta().filter(function (x) {
            if (!metaInfo.DiscriminatorValue.isInstance(x)) {
                return true;
            }
            return x.isStrict();
        });
    };
    AbstractType.prototype.declaredFacets = function () {
        return this.declaredMeta();
    };
    AbstractType.prototype.isSubTypeOf = function (t) {
        return t === exports.ANY || this === t || this.superTypes().some(function (x) { return x.isSubTypeOf(t); });
    };
    AbstractType.prototype.isSuperTypeOf = function (t) {
        return this === t || this.allSubTypes().indexOf(t) != -1;
    };
    AbstractType.prototype.addMeta = function (info) {
        this.metaInfo.push(info);
        info._owner = this;
        this.propertyInfos = null;
        this.propertiesMap = null;
        this.definedFacetInfos = null;
        this.definedFacetInfosMap = null;
    };
    AbstractType.prototype.name = function () {
        return this._name;
    };
    AbstractType.prototype.label = function () {
        return this._name;
    };
    /**
     * @return directly known sub types of a given type
     */
    AbstractType.prototype.subTypes = function () {
        return this._subTypes;
    };
    /**
     * @return directly known super types of a given type
     */
    AbstractType.prototype.superTypes = function () {
        return [];
    };
    AbstractType.prototype.addSupertypeAnnotation = function (arr, ind) {
        if (!arr || arr.length == 0) {
            return;
        }
        if (!this.supertypeAnnotations) {
            this.supertypeAnnotations = [];
        }
        var aMap = this.supertypeAnnotations[ind];
        if (!aMap) {
            aMap = {};
            this.supertypeAnnotations[ind] = aMap;
        }
        for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) {
            var a = arr_1[_i];
            aMap[a.facetName()] = a;
        }
    };
    AbstractType.prototype.validateType = function (tr) {
        var _this = this;
        if (tr === void 0) { tr = builtInRegistry(); }
        var rs = new Status(Status.OK, "", "", this);
        this.validateHierarchy(rs);
        if (this.getExtra(tsInterfaces.PARSE_ERROR)) {
            rs.addSubStatus(this.getExtra(tsInterfaces.PARSE_ERROR));
        }
        if (rs.isOk()) {
            rs.addSubStatus(this.checkConfluent());
            if (this.isExternal() && this.kind() == "external") {
                var extType = this;
                if (extType.isJSON()) {
                    try {
                        var sch = su.getJSONSchema(extType.schema(), extType.getContentProvider && extType.getContentProvider());
                        if (sch) {
                            sch.validateSelf();
                        }
                    }
                    catch (e) {
                        if (e.message == "Maximum call stack size exceeded") {
                            return error(exports.messageRegistry.CIRCULAR_REFS_IN_JSON_SCHEMA, this);
                        }
                        else if (ValidationError.isInstance(e)) {
                            var ve = e;
                            var errorStatus = error(ve.messageEntry, this, ve.parameters, ve.isWarning ? Status.WARNING : Status.ERROR);
                            errorStatus.setInternalRange(ve.internalRange);
                            errorStatus.setInternalPath(toValidationPath(ve.internalPath));
                            errorStatus.setFilePath(ve.filePath);
                            rs.addSubStatus(errorStatus);
                        }
                        else {
                            rs.addSubStatus(error(exports.messageRegistry.JSON_SCHEMA_VALIDATION_EXCEPTION, this, { msg: e.message }));
                        }
                    }
                }
            }
            if (rs.isOk()) {
                this.superTypes().forEach(function (x) {
                    if (x.isAnonymous()) {
                        var superStatus = x.validateType(tr);
                        if (!superStatus.isOk()) {
                            setValidationPath(superStatus, { name: "type" });
                            rs.addSubStatus(superStatus);
                        }
                    }
                });
            }
        }
        if (this.getExtra(exports.SCHEMA_AND_TYPE)) {
            rs.addSubStatus(error(exports.messageRegistry.SCHEMA_AND_TYPE, this));
        }
        if (rs.isOk()) {
            this.validateMeta(tr).getErrors().forEach(function (x) { return rs.addSubStatus(x); });
        }
        //if (this.isPolymorphic()||(this.isUnion())) {
        //    rs.addSubStatus(this.canDoAc());
        //}
        if (this.isObject()) {
            var required = {};
            this.restrictions().forEach(function (x) {
                if (x.owner() != _this) {
                    if (x instanceof restr.HasProperty) {
                        required[x.value()] = true;
                    }
                }
            });
            this.declaredMeta().forEach(function (x) {
                if (x instanceof restr.HasProperty) {
                    delete required[x.value()];
                }
            });
            this.declaredMeta().forEach(function (x) {
                if (x instanceof restr.PropertyIs) {
                    var pr = x;
                    if (required.hasOwnProperty(pr.propertyName())) {
                        rs.addSubStatus(error(exports.messageRegistry.REQUIRED_OVERRIDE_OPTIONAL, _this, { propertyName: pr.propertyName() }));
                    }
                }
            });
            var propertyCycles = new PropertyCyclesValidator().validateType(this);
            if (propertyCycles.length > 0) {
                propertyCycles.forEach(function (p) {
                    var st = error(exports.messageRegistry.CYCLIC_DEPENDENCY, _this, { typeName: p });
                    setValidationPath(st, { name: p });
                    rs.addSubStatus(st);
                });
            }
        }
        if (this.supertypeAnnotations) {
            for (var i = 0; i < this.supertypeAnnotations.length; i++) {
                var aMap = this.supertypeAnnotations[i];
                for (var _i = 0, _a = Object.keys(aMap); _i < _a.length; _i++) {
                    var aName = _a[_i];
                    var a = aMap[aName];
                    var aStatus = a.validateSelf(tr);
                    if (!aStatus.isOk()) {
                        setValidationPath(aStatus, { name: "type", child: { name: i } });
                        rs.addSubStatus(aStatus);
                    }
                }
            }
        }
        var pluginStatuses = applyTypeValidationPlugins(this, tr);
        for (var _b = 0, pluginStatuses_1 = pluginStatuses; _b < pluginStatuses_1.length; _b++) {
            var ps = pluginStatuses_1[_b];
            rs.addSubStatus(ps);
        }
        var typeEntry = new AnnotatedType(this, tr);
        var aPluginStatuses = applyAnnotationValidationPlugins(typeEntry);
        for (var _d = 0, aPluginStatuses_2 = aPluginStatuses; _d < aPluginStatuses_2.length; _d++) {
            var ps = aPluginStatuses_2[_d];
            rs.addSubStatus(ps);
        }
        return rs;
    };
    AbstractType.prototype.validateHierarchy = function (rs) {
        var _this = this;
        if (!this.isAnonymous()) {
            if (this.getExtra(tsInterfaces.TOP_LEVEL_EXTRA) && builtInRegistry().get(this.name())) {
                rs.addSubStatus(error(exports.messageRegistry.REDEFINIG_BUILDTIN, this, { typeName: this.name() }));
            }
        }
        if (this.isSubTypeOf(exports.RECURRENT)) {
            rs.addSubStatus(error(exports.messageRegistry.RECURRENT_DEFINITION, this), "type");
        }
        if (isUnknown(this)) {
            var chained = this.metaOfType(metaInfo.ImportedByChain);
            if (chained.length > 0) {
                var issues_1 = [];
                chained.forEach(function (x) {
                    issues_1.push(error(exports.messageRegistry.INHERITING_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN, _this, {
                        typeName: x.value()
                    }));
                });
                issues_1.forEach(function (x) { return rs.addSubStatus(x, "type"); });
            }
            else {
                rs.addSubStatus(error(exports.messageRegistry.INHERITING_UNKNOWN_TYPE, this), "type");
            }
        }
        if (this.isUnion()) {
            var tf = this.typeFamily();
            var chained_1 = [];
            var isRecurent = false;
            var isUnknown_1 = false;
            for (var _i = 0, tf_1 = tf; _i < tf_1.length; _i++) {
                var t = tf_1[_i];
                if (t.isSubTypeOf(exports.RECURRENT)) {
                    isRecurent = true;
                }
                else if (t.isSubTypeOf(exports.UNKNOWN)) {
                    isUnknown_1 = true;
                }
                t.metaOfType(metaInfo.ImportedByChain).forEach(function (x) { return chained_1.push(x); });
            }
            if (isRecurent) {
                rs.addSubStatus(error(exports.messageRegistry.RECURRENT_UNION_OPTION, this), "type");
            }
            if (isUnknown_1) {
                if (chained_1.length > 0) {
                    chained_1 = _.unique(chained_1);
                    if (chained_1.length > 0) {
                        chained_1.forEach(function (x) {
                            var typeName = x.value();
                            var messageEntry = exports.messageRegistry.UNION_OPTION_TYPE_DEPENDS_ON_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN;
                            if (_this.options().some(function (y) { return y.name() == typeName; })) {
                                messageEntry = exports.messageRegistry.UNION_OPTION_TYPE_OPTION_IMPORTED_THROUGH_LIBRARY_CHAIN;
                            }
                            rs.addSubStatus(error(messageEntry, _this, { typeName: typeName }), "type");
                        });
                    }
                }
                else {
                    rs.addSubStatus(error(exports.messageRegistry.UNKNOWN_UNION_OPTION, this), "type");
                }
            }
        }
        if (this.isArray()) {
            var fs_2 = this.familyWithArray();
            var ps = this.getExtra(tsInterfaces.HAS_ITEMS) ? "items" : "type";
            var chained_2 = [];
            var isRecurent = false;
            var isUnknown_2 = false;
            for (var _a = 0, fs_1 = fs_2; _a < fs_1.length; _a++) {
                var t = fs_1[_a];
                if (t == this || t === exports.RECURRENT) {
                    isRecurent = true;
                }
                else if (t == exports.UNKNOWN) {
                    isUnknown_2 = true;
                }
                t.metaOfType(metaInfo.ImportedByChain).forEach(function (x) { return chained_2.push(x); });
            }
            if (isRecurent) {
                rs.addSubStatus(error(exports.messageRegistry.RECURRENT_ARRAY_DEFINITION, this), ps);
            }
            else if (isUnknown_2) {
                var componentTypeName = this.oneMeta(restrictions_3.ComponentShouldBeOfType).value().name();
                if (chained_2.length > 0) {
                    chained_2 = _.unique(chained_2);
                    chained_2.forEach(function (x) {
                        var typeName = componentTypeName;
                        var messageEntry = exports.messageRegistry.ARRAY_COMPONENT_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN;
                        if (!typeName) {
                            componentTypeName = x.value();
                        }
                        else if (x.value() != typeName) {
                            messageEntry = exports.messageRegistry.ARRAY_COMPONENT_TYPE_DEPENDES_ON_TYPE_IMPORTED_THROUGH_LIBRARY_CHAIN;
                            typeName = x.value();
                        }
                        rs.addSubStatus(error(messageEntry, _this, { componentTypeName: componentTypeName, typeName: typeName }), ps);
                    });
                }
                else {
                    rs.addSubStatus(error(exports.messageRegistry.UNKNOWN_ARRAY_COMPONENT_TYPE, this, { componentTypeName: componentTypeName }), ps);
                }
            }
        }
        var supers = this.superTypes();
        var hasExternal = false;
        var hasNotExternal = false;
        if (supers.length > 1) {
            supers.forEach(function (x) {
                if (x.isExternal()) {
                    hasExternal = true;
                }
                else {
                    hasNotExternal = true;
                }
            });
        }
        if (hasExternal && hasNotExternal) {
            rs.addSubStatus(error(exports.messageRegistry.EXTERNALS_MIX, this));
        }
        if (this instanceof UnionType) {
            var ut = this;
            ut.options().forEach(function (x) {
                if (x.isExternal()) {
                    rs.addSubStatus(error(exports.messageRegistry.EXTERNALS_MIX, _this));
                }
            });
        }
        if (this.isExternal()) {
            if (this.getExtra(tsInterfaces.HAS_FACETS)) {
                var fArr = this.getExtra(tsInterfaces.HAS_FACETS);
                if (fArr.length) {
                    var f = fArr[fArr.length - 1];
                    var fs = error(exports.messageRegistry.EXTERNAL_FACET, this, { name: f });
                    setValidationPath(fs, { name: f });
                    rs.addSubStatus(fs);
                }
            }
        }
    };
    ;
    AbstractType.prototype.familyWithArray = function () {
        if (this.oneMeta(metaInfo.SkipValidation)) {
            return [];
        }
        var ts = [];
        this.fillSuperTypes(ts, true);
        var mn = this.oneMeta(restrictions_3.ComponentShouldBeOfType);
        if (mn) {
            var at = mn.value();
            if (!at.oneMeta(metaInfo.SkipValidation)) {
                ts = ts.concat(at.familyWithArray().concat(at));
            }
        }
        return ts;
    };
    AbstractType.prototype.validateMeta = function (tr) {
        var rs = new Status(Status.OK, "", "", this);
        this.declaredMeta().forEach(function (x) {
            x.validateSelf(tr).getErrors().forEach(function (y) { return rs.addSubStatus(y); });
        });
        this.validateFacets(rs);
        return rs;
    };
    AbstractType.prototype.validateFacets = function (rs) {
        var _this = this;
        var fds = {};
        var super_facets = {};
        var rfds = {};
        this.meta().forEach(function (x) {
            if (x instanceof metainfo_1.FacetDeclaration) {
                var fd = x;
                fds[fd.actualName()] = fd;
                if (!fd.isOptional()) {
                    if (fd.owner() !== _this) {
                        rfds[fd.actualName()] = fd;
                    }
                }
                if (fd.owner() != _this) {
                    super_facets[fd.actualName()] = fd;
                }
            }
        });
        this.declaredMeta().forEach(function (x) {
            if (x instanceof metainfo_1.FacetDeclaration) {
                var fd = x;
                if (fd.owner() == _this) {
                    var an = fd.actualName();
                    if (super_facets.hasOwnProperty(an)) {
                        rs.addSubStatus(error(exports.messageRegistry.OVERRIDE_FACET, _this, { name: an }));
                    }
                    var fp = fr.getInstance().facetPrototypeWithName(an);
                    if (fp && fp.isApplicable(_this) || an == "type" ||
                        fd.facetName() == "properties" || an == "schema" || an == "facets" || an == "uses") {
                        rs.addSubStatus(error(exports.messageRegistry.OVERRIDE_BUILTIN_FACET, _this, { name: an }));
                    }
                    if (an.charAt(0) == '(') {
                        rs.addSubStatus(error(exports.messageRegistry.FACET_START_BRACKET, _this, { name: an }));
                    }
                }
            }
        });
        var knownPropertySet = {};
        this.meta().forEach(function (x) {
            if (x instanceof restrictions_2.PropertyIs) {
                knownPropertySet[x.propId()] = true;
            }
        });
        for (var _i = 0, _a = this.meta(); _i < _a.length; _i++) {
            var x = _a[_i];
            if (x instanceof metainfo_2.CustomFacet) {
                var cd = x;
                if (cd.node() && cd.node().getMeta("skipValidation")) {
                    continue;
                }
                var facetName = cd.facetName();
                if (fds.hasOwnProperty(facetName)) {
                    var facet = fds[facetName];
                    var ft = facet.value();
                    if (facet.owner() == this && cd.owner() == this) {
                        var err_1 = error(exports.messageRegistry.FACET_CAN_NOT_BE_FIXED_BY_THE_DECLARING_TYPE, cd);
                        err_1.setValidationPath({ name: facetName });
                        rs.addSubStatus(err_1);
                    }
                    else {
                        var st = ft.validateDirect(cd.value(), false, false);
                        for (var _b = 0, _d = st.getErrors(); _b < _d.length; _b++) {
                            var err = _d[_b];
                            setValidationPath(err, { name: facetName });
                            rs.addSubStatus(err);
                        }
                        ;
                        delete rfds[facetName];
                    }
                }
                else {
                    if (this.isExternal()) {
                        rs.addSubStatus(error(exports.messageRegistry.FACET_PROHIBITED_FOR_EXTERNALS, cd, { facetName: facetName }, Status.ERROR, true));
                    }
                    else {
                        rs.addSubStatus(error(exports.messageRegistry.UNKNOWN_FACET, cd, { facetName: facetName }, Status.ERROR, true));
                    }
                }
            }
            // if (x instanceof MapPropertyIs){
            //     var mm:MapPropertyIs=x;
            //     Object.keys(knownPropertySet).forEach(c=>{
            //         try {
            //             if (c.match(mm.regexpValue())) {
            //                 var regexpText = '/' + mm.regexpValue().toString() + '/';
            //                
            //                 rs.addSubStatus(new Status(Status.WARNING, 0, `Pattern property '${regexpText}' conflicts with property: '${c}'`, this));
            //             }
            //         } catch (e){
            //             //ignore incorrect regexps here
            //         }
            //     })
            // }
        }
        if (Object.getOwnPropertyNames(rfds).length > 0) {
            rs.addSubStatus(error(exports.messageRegistry.MISSING_REQUIRED_FACETS, this, { facetsList: Object.keys(rfds).map(function (x) { return "'" + x + "'"; }).join(",") }));
        }
    };
    ;
    AbstractType.prototype.allSuperTypes = function () {
        var rs = [];
        this.fillSuperTypes(rs);
        return rs;
    };
    AbstractType.prototype.fillSuperTypes = function (r, forValidation) {
        if (forValidation === void 0) { forValidation = false; }
        for (var _i = 0, _a = this.superTypes(); _i < _a.length; _i++) {
            var x = _a[_i];
            if (forValidation && x.oneMeta(metaInfo.SkipValidation)) {
                continue;
            }
            if (!_.contains(r, x)) {
                r.push(x);
                x.fillSuperTypes(r);
            }
        }
    };
    AbstractType.prototype.allSubTypes = function () {
        var rs = [];
        this.fillSubTypes(rs);
        return rs;
    };
    AbstractType.prototype.fillSubTypes = function (r) {
        this.subTypes().forEach(function (x) {
            if (!_.contains(r, x)) {
                r.push(x);
                x.fillSubTypes(r);
            }
        });
    };
    AbstractType.prototype.inherit = function (name) {
        var rs = new InheritedType(name);
        rs.addSuper(this);
        return rs;
    };
    /**
     *
     * @return true if type is an inplace type and has no name
     */
    AbstractType.prototype.isAnonymous = function () {
        return (!this._name) || this._name.length === 0;
    };
    /**
     *
     * @return true if type has no associated meta information of restrictions
     */
    AbstractType.prototype.isEmpty = function () {
        if (this.extras != null && this.extras.hasOwnProperty(tsInterfaces.PARSE_ERROR)) {
            return false;
        }
        if (this.metaInfo.length > 2) {
            return false;
        }
        return this.metaInfo.filter(function (x) {
            if (metainfo_3.NotScalar.isInstance(x)) {
                return false;
            }
            else if (metaInfo.DiscriminatorValue.isInstance(x)) {
                return x.isStrict();
            }
            else if (metaInfo.SourceMap.isInstance(x)) {
                return false;
            }
            else if (metaInfo.ImportedByChain.isInstance(x)) {
                return false;
            }
            return true;
        }).length == 0;
    };
    /**
     *
     * @return true if type is an array or extends from an array
     */
    AbstractType.prototype.isArray = function () {
        return this === exports.ARRAY || this.allSuperTypes().indexOf(exports.ARRAY) != -1;
    };
    AbstractType.prototype.propertySet = function () {
        var rs = [];
        this.meta().forEach(function (x) {
            if (x instanceof restrictions_2.PropertyIs) {
                var p = x;
                rs.push(p.propertyName());
            }
        });
        return _.uniq(rs);
    };
    AbstractType.prototype.checkConfluent = function () {
        if (this.oneMeta(metaInfo.SkipValidation)) {
            return ok();
        }
        if (this.computeConfluent) {
            return ok();
        }
        this.computeConfluent = true;
        var arcc = restr.anotherRestrictionComponentsCount();
        try {
            var os = restr.optimize(this.restrictions());
            var ns = _.find(os, function (x) { return x instanceof NothingRestriction; });
            if (ns) {
                var lstack = null;
                var another = null;
                if (ns instanceof NothingRestrictionWithLocation) {
                    var nswl = ns;
                    lstack = nswl.getStack();
                    another = nswl.another();
                }
                var status = new RestrictionsConflict(another, lstack, this);
                return status;
            }
            return ok();
        }
        finally {
            this.computeConfluent = false;
            restr.releaseAnotherRestrictionComponent(arcc);
        }
    };
    /**
     *
     * @return true if type is object or inherited from object
     */
    AbstractType.prototype.isObject = function () {
        return this == exports.OBJECT || _.some(this.allSuperTypes(), function (x) { return x.isObject(); });
    };
    /**
     *
     * @return true if type is object or inherited from object
     */
    AbstractType.prototype.isExternal = function () {
        return this == exports.EXTERNAL || this.allSuperTypes().indexOf(exports.EXTERNAL) != -1;
    };
    /**
     *
     * @return true if type is an boolean type or extends from boolean
     */
    AbstractType.prototype.isBoolean = function () {
        return this == exports.BOOLEAN || this.allSuperTypes().indexOf(exports.BOOLEAN) != -1;
    };
    /**
     *
     * @return true if type is string or inherited from string
     */
    AbstractType.prototype.isString = function () {
        return this == exports.STRING || this.allSuperTypes().indexOf(exports.STRING) != -1;
    };
    /**
     *
     * @return true if type is number or inherited from number
     */
    AbstractType.prototype.isNumber = function () {
        return this == exports.NUMBER || this.allSuperTypes().indexOf(exports.NUMBER) != -1;
    };
    /**
     *
     * @return true if type is number or inherited from number
     */
    AbstractType.prototype.isFile = function () {
        return this == exports.FILE || this.allSuperTypes().indexOf(exports.FILE) != -1;
    };
    /**
     *
     * @return true if type is scalar or inherited from scalar
     */
    AbstractType.prototype.isScalar = function () {
        return this == exports.SCALAR || this.allSuperTypes().indexOf(exports.SCALAR) != -1;
    };
    /**
     * returns true if this type inherits from one of date related types
     */
    AbstractType.prototype.isDateTime = function () {
        return this == exports.DATETIME || this.allSuperTypes().indexOf(exports.DATETIME) != -1;
    };
    /**
     * returns true if this type inherits from one of date related types
     */
    AbstractType.prototype.isDateOnly = function () {
        return this == exports.DATE_ONLY || this.allSuperTypes().indexOf(exports.DATE_ONLY) != -1;
    };
    /**
     * returns true if this type inherits from one of date related types
     */
    AbstractType.prototype.isTimeOnly = function () {
        return this == exports.TIME_ONLY || this.allSuperTypes().indexOf(exports.TIME_ONLY) != -1;
    };
    /**
     * returns true if this type inherits from one of date related types
     */
    AbstractType.prototype.isInteger = function () {
        return this == exports.INTEGER || this.allSuperTypes().indexOf(exports.INTEGER) != -1;
    };
    /**
     * returns true if this type inherits from one of date related types
     */
    AbstractType.prototype.isDateTimeOnly = function () {
        return this == exports.DATETIME_ONLY || this.allSuperTypes().indexOf(exports.DATETIME_ONLY) != -1;
    };
    /**
     *
     * @return true if type is scalar or inherited from scalar
     */
    AbstractType.prototype.isUnknown = function () {
        return this == exports.UNKNOWN || this.allSuperTypes().indexOf(exports.UNKNOWN) != -1;
    };
    /**
     *
     * @return true if type is scalar or inherited from scalar
     */
    AbstractType.prototype.isRecurrent = function () {
        return this == exports.RECURRENT || this.allSuperTypes().indexOf(exports.RECURRENT) != -1;
    };
    /**
     *
     * @return true if type is an built-in type
     */
    AbstractType.prototype.isBuiltin = function () {
        return this.metaInfo.indexOf(BUILT_IN) != -1;
    };
    AbstractType.prototype.exampleObject = function () {
        return exO.example(this);
    };
    /**
     *
     * @return true if type is an polymorphic type
     */
    AbstractType.prototype.isPolymorphic = function () {
        return this.meta().some(function (x) { return x instanceof Polymorphic; });
    };
    /**
     * @return all restrictions associated with type
     */
    AbstractType.prototype.restrictions = function (forValidation) {
        if (forValidation === void 0) { forValidation = false; }
        if (this.isUnion()) {
            var rs = [];
            this.superTypes().forEach(function (x) {
                rs = rs.concat(x.restrictions());
            });
            rs = rs.concat(this.meta().filter(function (x) { return x instanceof Constraint; }));
            return rs;
        }
        var result = [];
        var generic = null;
        this.meta().forEach(function (x) {
            if (x instanceof Constraint) {
                if (x instanceof GenericTypeOf && forValidation) {
                    if (generic) {
                        return;
                    }
                    generic = x;
                }
                result.push(x);
            }
        });
        return result;
    };
    AbstractType.prototype.customFacets = function () {
        return this.declaredMeta().filter(function (x) { return x instanceof metaInfo.CustomFacet; });
    };
    AbstractType.prototype.allCustomFacets = function () {
        return this.meta().filter(function (x) { return x instanceof metaInfo.CustomFacet; });
    };
    AbstractType.prototype.isUnion = function () {
        var rs = false;
        if (this.isBuiltin()) {
            return false;
        }
        this.allSuperTypes().forEach(function (x) { return rs = rs || x instanceof UnionType; });
        return rs;
    };
    AbstractType.prototype.isIntersection = function () {
        var rs = false;
        if (this.isBuiltin()) {
            return false;
        }
        this.allSuperTypes().forEach(function (x) { return rs = rs || x instanceof IntersectionType; });
        return rs;
    };
    /**
     * return all type information associated with type
     */
    AbstractType.prototype.meta = function () {
        return [].concat(this.metaInfo);
    };
    /**
     * validates object against this type without performing AC
     */
    AbstractType.prototype.validateDirect = function (i, autoClose, nullAllowed, path) {
        var _this = this;
        if (autoClose === void 0) { autoClose = false; }
        if (nullAllowed === void 0) { nullAllowed = true; }
        if (path === void 0) { path = null; }
        var prevValidated = exports.VALIDATED_TYPE;
        try {
            var g = exports.autoCloseFlag;
            if (autoClose) {
                exports.autoCloseFlag = true;
            }
            exports.VALIDATED_TYPE = this;
            var result = new Status(Status.OK, "", "", this);
            if (!nullAllowed && (i === null || i === undefined)) {
                if (!this.nullable) {
                    var typeRestriction = null;
                    this.restrictions(true).forEach(function (restriction) {
                        if (restriction instanceof TypeOfRestriction) {
                            if (typeRestriction) {
                                return;
                            }
                            typeRestriction = restriction;
                        }
                    });
                    if (typeRestriction) {
                        return error(exports.messageRegistry.TYPE_EXPECTED, typeRestriction, {
                            expectedType: typeRestriction.value(),
                            actualType: 'null'
                        });
                    }
                    return error(exports.messageRegistry.OBJECT_EXPECTED, this);
                }
            }
            this.restrictions(true).forEach(function (x) { return result.addSubStatus(x.check(i, path)); });
            if ((autoClose || exports.autoCloseFlag) && this.isObject() && (!this.oneMeta(restrictions_1.KnownPropertyRestriction))) {
                var cp = new restrictions_1.KnownPropertyRestriction(false);
                cp.patchOwner(this);
                cp.check(i).getErrors().forEach(function (x) {
                    var rs = new Status(Status.WARNING, x.getCode(), x.getMessage(), _this);
                    setValidationPath(rs, x.getValidationPath());
                    result.addSubStatus(rs);
                });
            }
        }
        finally {
            exports.autoCloseFlag = g;
            exports.VALIDATED_TYPE = prevValidated;
        }
        return result;
    };
    AbstractType.prototype.validate = function (i, autoClose, nullAllowed) {
        if (autoClose === void 0) { autoClose = false; }
        if (nullAllowed === void 0) { nullAllowed = true; }
        var g = exports.autoCloseFlag;
        if (!nullAllowed && (i === null || i === undefined)) {
            if (!this.nullable) {
                return error(exports.messageRegistry.NULL_NOT_ALLOWED, this);
            }
        }
        if (autoClose) {
            exports.autoCloseFlag = true;
        }
        try {
            // for( var subType of this.subTypes()){
            //     var vr = subType.validateDirect(i,autoClose||g);
            //     if(vr.isOk()){
            //         return vr;
            //     }
            // }
            // return this.validateDirect(i, autoClose||g);
            var statuses = [];
            var global = _.find([this].concat(this.allSuperTypes()), function (x) { return x.getExtra(exports.GLOBAL); });
            var queue = this.allSubTypes().concat(this);
            if (global && global != this) {
                queue = queue.concat(global.allSubTypes());
                queue.push(global);
            }
            var lastStatus;
            for (var _i = 0, queue_1 = queue; _i < queue_1.length; _i++) {
                var subType = queue_1[_i];
                var dStatus = checkDescriminator(i, subType);
                var vr = subType.validateDirect(i, autoClose || g);
                if (dStatus) {
                    if (dStatus.isOk()) {
                        return vr;
                    }
                    else {
                        statuses.push(dStatus);
                    }
                }
                else if (vr.isOk()) {
                    return vr;
                }
                lastStatus = vr;
            }
            if (statuses.length == 0) {
                return lastStatus;
            }
            var result = ok();
            statuses.forEach(function (x) { return result.addSubStatus(x); });
            return statuses.pop(); //result;
        }
        finally {
            exports.autoCloseFlag = g;
        }
    };
    /**
     * declares a pattern property on this type,
     * note if type is not inherited from an object type this will move
     * type to inconsistent state
     * @param name - regexp
     * @param type - type of the property
     * @return
     */
    AbstractType.prototype.declareMapProperty = function (name, type) {
        if (type != null) {
            this.addMeta(new restr.MapPropertyIs(name, type));
        }
        return type;
    };
    /**
     * make this type closed type (no unknown properties any more)
     */
    AbstractType.prototype.closeUnknownProperties = function () {
        this.addMeta(new restrictions_1.KnownPropertyRestriction(false));
    };
    AbstractType.prototype.annotations = function () {
        return this.metaOfType(metaInfo.Annotation);
    };
    AbstractType.prototype.declaredAnnotations = function () {
        return this.declaredMeta().filter(function (x) { return metaInfo.Annotation.isInstance(x); });
    };
    AbstractType.prototype.scalarsAnnotations = function () {
        return this.sAnnotations(this.meta());
    };
    AbstractType.prototype.declaredScalarsAnnotations = function () {
        return this.sAnnotations(this.declaredFacets());
    };
    AbstractType.prototype.sAnnotations = function (facets) {
        facets = facets.filter(function (x) {
            return x.kind() != tsInterfaces.MetaInformationKind.FacetDeclaration
                && x.kind() != tsInterfaces.MetaInformationKind.Example
                && x.kind() != tsInterfaces.MetaInformationKind.Examples
                && x.facetName() != "propertyIs";
        });
        var result = {};
        var _loop_1 = function (f) {
            var annotations = f.annotations();
            if (!annotations || !annotations.length) {
                return "continue";
            }
            result[f.facetName()] = [annotations.map(function (x) {
                    var a = new metaInfo.Annotation(x.name(), x.value(), x.getPath());
                    a.setOwnerFacet(f);
                    return a;
                })];
        };
        for (var _i = 0, facets_1 = facets; _i < facets_1.length; _i++) {
            var f = facets_1[_i];
            _loop_1(f);
        }
        if (this.supertypeAnnotations && this.supertypeAnnotations.length) {
            result['type'] = this.supertypeAnnotations.map(function (x) {
                return Object.keys(x).map(function (y) { return new metaInfo.Annotation(x[y].name(), x[y].value(), x[y].getPath()); });
            });
        }
        return result;
    };
    AbstractType.prototype.componentType = function () {
        var components = this.metaOfType(restrictions_3.ComponentShouldBeOfType);
        if (components.length == 0) {
            return null;
        }
        else if (components.length == 1) {
            return components[0].value();
        }
        else {
            var componentTypes = components.map(function (x) { return x.value(); });
            var componentTypes1 = [].concat(componentTypes);
            var _loop_2 = function (x) {
                var toRemove = [];
                for (var _i = 0, componentTypes_1 = componentTypes; _i < componentTypes_1.length; _i++) {
                    var y = componentTypes_1[_i];
                    if (x == y) {
                        continue;
                    }
                    if (y.isAssignableFrom(x)) {
                        toRemove.push(y);
                    }
                }
                componentTypes = componentTypes.filter(function (y) { return toRemove.indexOf(y) < 0; });
            };
            for (var _i = 0, componentTypes1_1 = componentTypes1; _i < componentTypes1_1.length; _i++) {
                var x = componentTypes1_1[_i];
                _loop_2(x);
            }
            var ct = derive(null, componentTypes);
            return ct;
        }
    };
    AbstractType.prototype.canDoAc = function () {
        var tf = _.uniq(this.typeFamily());
        var s = new Status(Status.OK, "", "", this);
        for (var i = 0; i < tf.length; i++) {
            for (var j = 0; j < tf.length; j++) {
                if (i != j) {
                    var t0 = tf[i];
                    var t1 = tf[j];
                    var ed = this.emptyIntersectionOrDiscriminator(t0, t1);
                    s.addSubStatus(ed);
                }
            }
        }
        return s;
    };
    AbstractType.prototype.emptyIntersectionOrDiscriminator = function (t0, t1) {
        if (t1 === t0) {
            return ok();
        }
        if (t1.isScalar() && t0.isScalar()) {
            return ok();
        }
        var it = intersect("", [t0, t1]);
        var innerCheckConfluent = it.checkConfluent();
        if (innerCheckConfluent.isOk()) {
            return this.checkDiscriminator(t0, t1);
        }
        return ok();
    };
    AbstractType.prototype.properties = function () {
        if (this.propertyInfos == null) {
            this.propertiesMap = {};
            this.propertyInfos = [];
            var meta = this.meta();
            for (var _i = 0, meta_1 = meta; _i < meta_1.length; _i++) {
                var m = meta_1[_i];
                if (restr.MatchesProperty.isInstance(m)) {
                    var p = new PropertyInfo(m);
                    var name_1 = p.name();
                    if (!this.propertiesMap[name_1]) {
                        this.propertiesMap[name_1] = p;
                    }
                    this.propertyInfos.push(p);
                }
            }
        }
        return this.propertyInfos;
    };
    AbstractType.prototype.declaredProperties = function () {
        var _this = this;
        return this.properties().filter(function (x) { return x.declaredAt() == _this; });
    };
    AbstractType.prototype.allDefinedFacets = function () {
        if (this.definedFacetInfos == null) {
            this.definedFacetInfosMap = {};
            this.definedFacetInfos = [];
            var m = this.meta();
            for (var _i = 0, m_1 = m; _i < m_1.length; _i++) {
                var f = m_1[_i];
                if (metaInfo.FacetDeclaration.isInstance(f) && !f.isBuiltIn()) {
                    var p = new PropertyInfo(f);
                    if (!this.definedFacetInfosMap[f.facetName()]) {
                        this.definedFacetInfosMap[p.name()] = p;
                    }
                    this.definedFacetInfos.push(p);
                }
            }
        }
        return this.definedFacetInfos;
    };
    AbstractType.prototype.definedFacets = function () {
        var _this = this;
        return this.allDefinedFacets().filter(function (x) { return x.declaredAt() == _this; });
    };
    AbstractType.prototype.property = function (name) {
        if (!this.propertyInfos) {
            this.properties();
        }
        return this.propertiesMap[name];
    };
    AbstractType.prototype.checkDiscriminator = function (t1, t2) {
        var found = error(exports.messageRegistry.DISCRIMINATOR_NEEDED, this, { name1: t1.name(), name2: t2.name() });
        var oneMeta = t1.oneMeta(metaInfo.Discriminator);
        var anotherMeta = t2.oneMeta(metaInfo.Discriminator);
        if (oneMeta != null && anotherMeta != null && oneMeta.value() === (anotherMeta.value())) {
            var d1 = t1.name();
            var d2 = t2.name();
            var dv1 = t1.oneMeta(metaInfo.DiscriminatorValue);
            if (dv1 != null) {
                d1 = dv1.value();
            }
            var dv2 = t2.oneMeta(metaInfo.DiscriminatorValue);
            if (dv2 != null) {
                d2 = dv2.value();
            }
            if (d1 !== d2) {
                return ok();
            }
            found = error(exports.messageRegistry.SAME_DISCRIMINATOR_VALUE, this, { name1: t1.name(), name2: t2.name() });
        }
        return found;
    };
    /**
     * performs automatic classification of the instance
     * @param obj
     * @returns {AbstractType}
     */
    AbstractType.prototype.ac = function (obj) {
        if (!this.isPolymorphic() && !this.isUnion()) {
            return this;
        }
        if (this.isBuiltin()) {
            return this;
        }
        var tf = _.uniq(this.typeFamily());
        if (tf.length == 0) {
            return exports.NOTHING;
        }
        if (this.isScalar()) {
            if (this.isNumber()) {
                if (typeof obj == "number") {
                    return this;
                }
                return exports.NOTHING;
            }
            if (this.isString()) {
                if (typeof obj == "string") {
                    return this;
                }
                return exports.NOTHING;
            }
            if (this.isBoolean()) {
                if (typeof obj == "boolean") {
                    return this;
                }
                return exports.NOTHING;
            }
            return this;
        }
        if (tf.length === 1) {
            return tf[0];
        }
        var options = [];
        tf.forEach(function (x) {
            var ds = x.validateDirect(obj, true);
            if (ds.isOk()) {
                options.push(x);
            }
        });
        var t = this.discriminate(obj, options);
        if (!t) {
            return exports.NOTHING;
        }
        return t;
    };
    /**
     * adds new property declaration to this type, note if type is not inherited from an object type this will move
     * type to inconsistent state
     * @param name - name of the property
     * @param type - type of the property
     * @param optional true if property is optinal
     * @return the type with property (this)
     */
    AbstractType.prototype.declareProperty = function (name, t, optional) {
        if (!optional) {
            this.addMeta(new restr.HasProperty(name));
        }
        if (t != null) {
            this.addMeta(new restr.PropertyIs(name, t));
        }
        return this;
    };
    AbstractType.prototype.discriminate = function (obj, opt) {
        var newOpts = [].concat(opt);
        var opts = [].concat(opt);
        while (newOpts.length > 1) {
            var found = false;
            l2: for (var i = 0; i < opts.length; i++) {
                for (var j = 0; j < opts.length; j++) {
                    var t0 = opts[i];
                    var t1 = opts[j];
                    if (t0 != t1) {
                        var nt = select(obj, t0, t1);
                        if (nt === t0) {
                            opts = opts.filter(function (x) { return x != t1; });
                            found = true;
                            break l2;
                        }
                        else if (nt === t1) {
                            opts = opts.filter(function (x) { return x != t0; });
                            found = true;
                            break l2;
                        }
                        else {
                            opts = opts.filter(function (x) { return x != t0 && x != t1; });
                            found = true;
                            break l2;
                        }
                    }
                }
            }
            newOpts = opts;
        }
        if (newOpts.length == 1) {
            return newOpts[0];
        }
        return null;
    };
    /**
     * return instance of type information of particular class
     * @param clazz
     * @returns {any}
     */
    AbstractType.prototype.oneMeta = function (clazz) {
        return _.find(this.meta(), function (x) { return x instanceof clazz; });
    };
    /**
     * return all instances of meta information of particular class
     * @param clazz
     * @returns {any}
     */
    AbstractType.prototype.metaOfType = function (clazz) {
        return this.meta().filter(function (x) { return x instanceof clazz; });
    };
    AbstractType.prototype.declaredMeta = function () {
        return this.metaInfo;
    };
    AbstractType.prototype.descValue = function () {
        var dv = this.oneMeta(metaInfo.DiscriminatorValue);
        if (dv) {
            return dv.value();
        }
        return this.name();
    };
    AbstractType.prototype.isAbstractOrInternal = function () {
        return this.metaInfo.some(function (x) { return x instanceof Abstract || x instanceof Internal; });
    };
    AbstractType.prototype.typeFamily = function () {
        if (this.isUnion()) {
            var res = [];
            this.allSuperTypes().forEach(function (x) {
                if (x instanceof UnionType) {
                    var opts = x.allOptions();
                    for (var i = 0; i < opts.length; i++) {
                        res = res.concat(opts[i].typeFamily());
                    }
                }
            });
            return _.unique(res);
        }
        var rs = [];
        if (!this.isAbstractOrInternal()) {
            rs.push(this);
        }
        this.allSubTypes().forEach(function (x) {
            if (!x.isAbstractOrInternal()) {
                rs.push(x);
            }
        });
        return _.unique(rs);
    };
    AbstractType.prototype.hasPropertiesFacet = function () {
        return this.metaInfo.some(function (x) { return x instanceof metaInfo.HasPropertiesFacet; });
    };
    AbstractType.prototype.sourceMap = function () {
        return null;
    };
    AbstractType.CLASS_IDENTIFIER_AbstractType = "typesystem.AbstractType";
    return AbstractType;
}());
exports.AbstractType = AbstractType;
var Modifier = /** @class */ (function (_super) {
    __extends(Modifier, _super);
    function Modifier() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Modifier.prototype.requiredType = function () {
        return exports.ANY;
    };
    Modifier.prototype.kind = function () {
        return tsInterfaces.MetaInformationKind.Modifier;
    };
    return Modifier;
}(TypeInformation));
exports.Modifier = Modifier;
var Polymorphic = /** @class */ (function (_super) {
    __extends(Polymorphic, _super);
    function Polymorphic() {
        return _super.call(this, true) || this;
    }
    Polymorphic.prototype.facetName = function () {
        return "polymorphic";
    };
    Polymorphic.prototype.value = function () {
        return true;
    };
    return Polymorphic;
}(Modifier));
exports.Polymorphic = Polymorphic;
var Abstract = /** @class */ (function (_super) {
    __extends(Abstract, _super);
    function Abstract() {
        return _super.call(this, false) || this;
    }
    Abstract.prototype.value = function () {
        return true;
    };
    Abstract.prototype.facetName = function () {
        return "abstract";
    };
    return Abstract;
}(Modifier));
exports.Abstract = Abstract;
var Internal = /** @class */ (function (_super) {
    __extends(Internal, _super);
    function Internal() {
        return _super.call(this, false) || this;
    }
    Internal.prototype.facetName = function () {
        return "abstract";
    };
    Internal.prototype.value = function () {
        return true;
    };
    return Internal;
}(Modifier));
exports.Internal = Internal;
var BuiltIn = /** @class */ (function (_super) {
    __extends(BuiltIn, _super);
    function BuiltIn() {
        return _super.call(this, false) || this;
    }
    BuiltIn.prototype.facetName = function () {
        return "builtIn";
    };
    BuiltIn.prototype.value = function () {
        return true;
    };
    return BuiltIn;
}(Modifier));
var BUILT_IN = new BuiltIn();
var RootType = /** @class */ (function (_super) {
    __extends(RootType, _super);
    function RootType() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    RootType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(RootType.CLASS_IDENTIFIER_RootType);
    };
    RootType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), RootType.CLASS_IDENTIFIER_RootType);
    };
    RootType.prototype.kind = function () {
        return "root";
    };
    RootType.prototype.clone = function () {
        return this;
    };
    RootType.CLASS_IDENTIFIER_RootType = "typesystem.RootType";
    return RootType;
}(AbstractType));
exports.RootType = RootType;
var InheritedType = /** @class */ (function (_super) {
    __extends(InheritedType, _super);
    function InheritedType() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this._superTypes = [];
        return _this;
    }
    InheritedType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(InheritedType.CLASS_IDENTIFIER_InheritedType);
    };
    InheritedType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), InheritedType.CLASS_IDENTIFIER_InheritedType);
    };
    InheritedType.prototype.superTypes = function () {
        return this._superTypes;
    };
    InheritedType.prototype.clone = function () {
        if (this.isBuiltin()) {
            return this;
        }
        var v = new InheritedType(this._name);
        v._superTypes = this._superTypes;
        return v;
    };
    InheritedType.prototype.knownProperties = function () {
        var vs = this.metaOfType(restrictions_4.MatchesProperty);
        this.superTypes().forEach(function (x) {
            vs = vs.concat(x.knownProperties());
        });
        return vs;
    };
    InheritedType.prototype.kind = function () {
        return "inherited";
    };
    InheritedType.prototype.meta = function () {
        var _this = this;
        var rs = _super.prototype.meta.call(this);
        var hasKp = false;
        this.superTypes().forEach(function (x) {
            x.meta().forEach(function (m) {
                if (m instanceof restrictions_1.KnownPropertyRestriction) {
                    if (hasKp) {
                        return;
                    }
                    var kp = new restrictions_1.KnownPropertyRestriction(false);
                    kp.patchOwner(_this);
                    rs.push(kp);
                    return;
                }
                if (m.isInheritable()) {
                    rs.push(m);
                }
            });
        });
        return rs;
    };
    InheritedType.prototype.addSuper = function (t) {
        this._superTypes.push(t);
        if (!t.isLocked()) {
            t._subTypes.push(this);
        }
        if (t.nullable) {
            this.nullable = true;
        }
    };
    InheritedType.prototype.label = function () {
        var cmp = this.metaOfType(restrictions_3.ComponentShouldBeOfType);
        if (cmp.length > 0) {
            return cmp[0].value().label() + "[]";
        }
        return _super.prototype.label.call(this);
    };
    InheritedType.prototype.contextMeta = function () {
        return this._contextMeta;
    };
    InheritedType.prototype.setContextMeta = function (contextMeta) {
        this._contextMeta = contextMeta;
    };
    InheritedType.prototype.patch = function (another) {
        var _this = this;
        for (var prop in another) {
            if (another.hasOwnProperty(prop)) {
                this[prop] = another[prop];
            }
        }
        this.metaInfo.filter(function (m) { return m._owner === another; }).forEach(function (m) { return m._owner = _this; });
        for (var i = 0; i < this._superTypes.length; i++) {
            var st = this._superTypes[i];
            if (st == this || st.allSuperTypes().indexOf(this) >= 0) {
                this._superTypes[i] = exports.RECURRENT;
            }
        }
    };
    InheritedType.CLASS_IDENTIFIER_InheritedType = "typesystem.InheritedType";
    return InheritedType;
}(AbstractType));
exports.InheritedType = InheritedType;
var DerivedType = /** @class */ (function (_super) {
    __extends(DerivedType, _super);
    function DerivedType(name, _options) {
        var _this = _super.call(this, name) || this;
        _this._options = _options;
        return _this;
    }
    DerivedType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(DerivedType.CLASS_IDENTIFIER_DerivedType);
    };
    DerivedType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), DerivedType.CLASS_IDENTIFIER_DerivedType);
    };
    DerivedType.prototype.cloneWithFilter = function (x, f) {
        var c = this.clone();
        var ms = [];
        if (f) {
            c._options = this.options().map(function (t) { return f(t); });
        }
        this.metaInfo.forEach(function (f) {
            var rs = x(f, c);
            if (typeof rs == "boolean") {
                if (rs) {
                    ms.push(f);
                }
            }
            else {
                if (rs) {
                    ms.push(rs);
                }
            }
        });
        c.metaInfo = ms;
        return c;
    };
    /**
     *
     * @returns all possible options
     */
    DerivedType.prototype.allOptions = function () {
        var _this = this;
        var rs = [];
        this._options.forEach(function (x) {
            if (x.kind() == _this.kind()) {
                rs = rs.concat(x.allOptions());
            }
            else {
                rs.push(x);
            }
        });
        return _.unique(rs);
    };
    DerivedType.prototype.options = function () {
        return this._options;
    };
    DerivedType.CLASS_IDENTIFIER_DerivedType = "typesystem.DerivedType";
    return DerivedType;
}(AbstractType));
exports.DerivedType = DerivedType;
var UnionType = /** @class */ (function (_super) {
    __extends(UnionType, _super);
    function UnionType(name, _options) {
        var _this = _super.call(this, name, _options) || this;
        _this.options().forEach(function (x) {
            if (x.nullable) {
                _this.nullable = true;
            }
        });
        return _this;
    }
    UnionType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(UnionType.CLASS_IDENTIFIER_UnionType);
    };
    UnionType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), UnionType.CLASS_IDENTIFIER_UnionType);
    };
    UnionType.prototype.kind = function () {
        return "union";
    };
    UnionType.prototype.clone = function () {
        return new UnionType(this.name(), this.options());
    };
    UnionType.prototype.isSubTypeOf = function (t) {
        var isSubType = true;
        this.allOptions().forEach(function (x) {
            if (!x.isSubTypeOf(t)) {
                isSubType = false;
            }
        });
        return isSubType;
        //return t===ANY||this===t|| this.superTypes().some(x=>x.isSubTypeOf(t));
    };
    UnionType.prototype.validate = function (i) {
        return this.validateDirect(i);
    };
    UnionType.prototype.typeFamily = function () {
        var res = [];
        this.allOptions().forEach(function (x) {
            res = res.concat(x.typeFamily());
        });
        return res;
    };
    UnionType.prototype.knownProperties = function () {
        var vs = this.metaOfType(restrictions_4.MatchesProperty);
        this.options().forEach(function (x) {
            vs = vs.concat(x.knownProperties());
        });
        return vs;
    };
    UnionType.prototype.validateDirect = function (i, autoClose) {
        if (autoClose === void 0) { autoClose = false; }
        var result = new Status(Status.OK, "", "", this);
        this.restrictions().forEach(function (x) { return result.addSubStatus(x.check(i, null)); });
        return result;
    };
    UnionType.prototype.isUnion = function () {
        return true;
    };
    UnionType.prototype.isObject = function () {
        return _.all(this.allOptions(), function (x) { return x.isObject(); });
    };
    UnionType.prototype.restrictions = function () {
        return [new OrRestriction(this.allOptions().map(function (x) { return new AndRestriction(x.restrictions()); }), exports.messageRegistry.UNION_TYPE_FAILURE, exports.messageRegistry.UNION_TYPE_FAILURE_DETAILS)];
    };
    UnionType.prototype.label = function () {
        return this.options().map(function (x) { return x.label(); }).join("|");
    };
    UnionType.CLASS_IDENTIFIER_UnionType = "typesystem.UnionType";
    return UnionType;
}(DerivedType));
exports.UnionType = UnionType;
var IntersectionType = /** @class */ (function (_super) {
    __extends(IntersectionType, _super);
    function IntersectionType() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    IntersectionType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(IntersectionType.CLASS_IDENTIFIER_IntersectionType);
    };
    IntersectionType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), IntersectionType.CLASS_IDENTIFIER_IntersectionType);
    };
    IntersectionType.prototype.kind = function () {
        return "intersection";
    };
    IntersectionType.prototype.clone = function () {
        return new IntersectionType(this.name(), this.options());
    };
    IntersectionType.prototype.restrictions = function () {
        var rs = [];
        this.allOptions().forEach(function (x) {
            if (!x.oneMeta(metaInfo.SkipValidation)) {
                rs = rs.concat(x.restrictions());
            }
        });
        return [new AndRestriction(rs)];
    };
    IntersectionType.prototype.label = function () {
        return this.options().map(function (x) { return x.label(); }).join("&");
    };
    IntersectionType.prototype.isIntersection = function () {
        return true;
    };
    IntersectionType.CLASS_IDENTIFIER_IntersectionType = "typesystem.IntersectionType";
    return IntersectionType;
}(DerivedType));
exports.IntersectionType = IntersectionType;
var registry = new TypeRegistry();
function builtInRegistry() {
    return registry;
}
exports.builtInRegistry = builtInRegistry;
function union(name, t) {
    return new UnionType(name, t);
}
exports.union = union;
function intersect(name, t) {
    return new IntersectionType(name, t);
}
exports.intersect = intersect;
/**
 * allows you to extend a type from other types
 * @param name
 * @param t
 * @returns {InheritedType}
 */
function derive(name, t) {
    var r = new InheritedType(name);
    t.forEach(function (x) { return r.addSuper(x); });
    if (r.isSubTypeOf(exports.NIL)) {
        r.nullable = true;
    }
    else if (t.length == 1 && t[0] == exports.ANY) {
        r.nullable = true;
    }
    return r;
}
exports.derive = derive;
/**
 * this function allows you to quickly derive a new type from object;
 * @param name
 * @returns {InheritedType}
 */
function deriveObjectType(name) {
    return derive(name, [exports.OBJECT]);
}
exports.deriveObjectType = deriveObjectType;
function select(obj, t0, t1) {
    if (t0.isScalar() && t1.isScalar()) {
        if (t0.allSubTypes().indexOf(t1) != -1) {
            return t0;
        }
        if (t1.allSubTypes().indexOf(t0) != -1) {
            return t1;
        }
    }
    var d0 = t0.oneMeta(metaInfo.Discriminator);
    var d1 = t1.oneMeta(metaInfo.Discriminator);
    if (d0 && d1) {
        if (d0.property === d1.property) {
            var v0 = t0.descValue();
            var v1 = t1.descValue();
            if (v0 !== v1) {
                var val = obj[d0.property];
                if (val === v0) {
                    return t0;
                }
                if (val === v1) {
                    return t1;
                }
            }
        }
    }
    return null;
}
var NothingRestriction = /** @class */ (function (_super) {
    __extends(NothingRestriction, _super);
    function NothingRestriction() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    NothingRestriction.prototype.check = function (i) {
        if (i === null || i === undefined) {
            return ok();
        }
        return error(exports.messageRegistry.NOTHING, this);
    };
    NothingRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    NothingRestriction.prototype.facetName = function () {
        return "nothing";
    };
    NothingRestriction.prototype.value = function () {
        return "!!!";
    };
    return NothingRestriction;
}(Constraint));
exports.NothingRestriction = NothingRestriction;
var RestrictionStackEntry = /** @class */ (function () {
    function RestrictionStackEntry(_previous, _restriction, id) {
        this._previous = _previous;
        this._restriction = _restriction;
        this.id = id;
    }
    RestrictionStackEntry.prototype.getRestriction = function () { return this._restriction; };
    RestrictionStackEntry.prototype.pop = function () { return this._previous; };
    RestrictionStackEntry.prototype.push = function (r) {
        return new RestrictionStackEntry(this, r, r.toString());
    };
    return RestrictionStackEntry;
}());
exports.RestrictionStackEntry = RestrictionStackEntry;
var NothingRestrictionWithLocation = /** @class */ (function (_super) {
    __extends(NothingRestrictionWithLocation, _super);
    function NothingRestrictionWithLocation(_entry, _message, _another) {
        var _this = _super.call(this) || this;
        _this._entry = _entry;
        _this._message = _message;
        _this._another = _another;
        return _this;
    }
    NothingRestrictionWithLocation.prototype.getMessage = function () { return this._message; };
    NothingRestrictionWithLocation.prototype.getStack = function () { return this._entry; };
    NothingRestrictionWithLocation.prototype.another = function () { return this._another; };
    return NothingRestrictionWithLocation;
}(NothingRestriction));
exports.NothingRestrictionWithLocation = NothingRestrictionWithLocation;
var GenericTypeOf = /** @class */ (function (_super) {
    __extends(GenericTypeOf, _super);
    function GenericTypeOf() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    GenericTypeOf.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(GenericTypeOf.CLASS_IDENTIFIER_GenericTypeOf);
    };
    GenericTypeOf.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), GenericTypeOf.CLASS_IDENTIFIER_GenericTypeOf);
    };
    GenericTypeOf.CLASS_IDENTIFIER_GenericTypeOf = "typesystem.GenericTypeOf";
    return GenericTypeOf;
}(Constraint));
exports.GenericTypeOf = GenericTypeOf;
var TypeOfRestriction = /** @class */ (function (_super) {
    __extends(TypeOfRestriction, _super);
    function TypeOfRestriction(val) {
        var _this = _super.call(this) || this;
        _this.val = val;
        return _this;
    }
    TypeOfRestriction.prototype.check = function (i) {
        var to = typeof i;
        if (i === null || i === undefined) {
            return ok();
        }
        if (Array.isArray(i)) {
            to = "array";
        }
        if (to === this.val) {
            return ok();
        }
        return error(exports.messageRegistry.TYPE_EXPECTED, this, {
            expectedType: this.val,
            actualType: to
        });
    };
    TypeOfRestriction.prototype.value = function () {
        return this.val;
    };
    TypeOfRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    TypeOfRestriction.prototype.facetName = function () {
        return "typeOf";
    };
    TypeOfRestriction.prototype.composeWith = function (r) {
        if (r instanceof TypeOfRestriction) {
            var to = r;
            if (to.val == this.val) {
                return this;
            }
            return this.nothing(r);
        }
        return null;
    };
    TypeOfRestriction.prototype.toString = function () {
        return "should be of type " + this.val;
    };
    return TypeOfRestriction;
}(GenericTypeOf));
exports.TypeOfRestriction = TypeOfRestriction;
function is_int(value) {
    if ((parseFloat(value) == parseInt(value)) && !isNaN(value)) {
        return true;
    }
    else {
        return false;
    }
}
var IntegerRestriction = /** @class */ (function (_super) {
    __extends(IntegerRestriction, _super);
    function IntegerRestriction() {
        return _super.call(this) || this;
    }
    IntegerRestriction.prototype.check = function (i) {
        if (typeof i == "number" && is_int(i)) {
            return ok();
        }
        return error(exports.messageRegistry.INTEGER_EXPECTED, this);
    };
    IntegerRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    IntegerRestriction.prototype.value = function () {
        return true;
    };
    IntegerRestriction.prototype.facetName = function () {
        return "should be integer";
    };
    return IntegerRestriction;
}(GenericTypeOf));
exports.IntegerRestriction = IntegerRestriction;
var NullRestriction = /** @class */ (function (_super) {
    __extends(NullRestriction, _super);
    function NullRestriction() {
        return _super.call(this, "nil") || this;
    }
    NullRestriction.prototype.check = function (i) {
        if (i === null || i == undefined || i === "null") {
            return ok();
        }
        return error(exports.messageRegistry.NULL_EXPECTED, this);
    };
    NullRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    NullRestriction.prototype.facetName = function () {
        return "should be nil";
    };
    return NullRestriction;
}(TypeOfRestriction));
exports.NullRestriction = NullRestriction;
var ScalarRestriction = /** @class */ (function (_super) {
    __extends(ScalarRestriction, _super);
    function ScalarRestriction() {
        return _super.call(this) || this;
    }
    ScalarRestriction.prototype.check = function (i) {
        if (!i) {
            return ok();
        }
        if (typeof i === 'number' || typeof i === 'boolean' || typeof i === 'string') {
            return ok();
        }
        return error(exports.messageRegistry.SCALAR_EXPECTED, this);
    };
    ScalarRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    ScalarRestriction.prototype.facetName = function () {
        return exports.messageRegistry.SHOULD_BE_SCALAR.message;
    };
    ScalarRestriction.prototype.value = function () {
        return true;
    };
    return ScalarRestriction;
}(GenericTypeOf));
exports.ScalarRestriction = ScalarRestriction;
var OrRestriction = /** @class */ (function (_super) {
    __extends(OrRestriction, _super);
    function OrRestriction(val, _extraMessage, _extraOptionMessage) {
        var _this = _super.call(this) || this;
        _this.val = val;
        _this._extraMessage = _extraMessage;
        _this._extraOptionMessage = _extraOptionMessage;
        return _this;
    }
    OrRestriction.prototype.check = function (i, p) {
        var _this = this;
        var cs = new Status(Status.OK, "", "", this);
        var results = [];
        for (var j = 0; j < this.val.length; j++) {
            var m = this.val[j].check(i, p);
            if (m.isOk()) {
                return ok();
            }
            results.push(m);
        }
        if (results.length > 0) {
            for (var _i = 0, results_1 = results; _i < results_1.length; _i++) {
                var r = results_1[_i];
                var ownerName = null;
                var src = r.getSource();
                if (src instanceof TypeInformation) {
                    var owner = src.owner();
                    if (owner) {
                        ownerName = owner.label();
                    }
                }
                r.getErrors().forEach(function (x) {
                    var msg = x.getMessage();
                    var code = x.getCode();
                    if (ownerName) {
                        msg = ownerName + ": " + msg;
                    }
                    if (_this._extraOptionMessage) {
                        var st = error(_this._extraOptionMessage, _this, { msg: msg });
                        msg = st.getMessage();
                        code = st.getCode();
                    }
                    x.setMessage(msg);
                    x.setCode(code);
                    cs.addSubStatus(x);
                });
            }
            if (this._extraMessage) {
                var severity = 0;
                results.forEach(function (x) { return severity = Math.max(severity, x.getSeverity()); });
                cs.addSubStatus(new Status(severity, this._extraMessage.code, this._extraMessage.message, this));
            }
        }
        return cs;
    };
    OrRestriction.prototype.value = function () {
        return this.val.map(function (x) { return x.value(); });
    };
    OrRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    OrRestriction.prototype.facetName = function () {
        return "or";
    };
    return OrRestriction;
}(Constraint));
exports.OrRestriction = OrRestriction;
var AndRestriction = /** @class */ (function (_super) {
    __extends(AndRestriction, _super);
    function AndRestriction(val) {
        var _this = _super.call(this) || this;
        _this.val = val;
        return _this;
    }
    AndRestriction.prototype.value = function () {
        return this.val.map(function (x) { return x.value(); });
    };
    AndRestriction.prototype.options = function () {
        return this.val;
    };
    AndRestriction.prototype.check = function (i, p) {
        for (var j = 0; j < this.val.length; j++) {
            var st = this.val[j].check(i, p);
            if (!st.isOk()) {
                return st;
            }
        }
        return ok();
    };
    AndRestriction.prototype.requiredType = function () {
        return exports.ANY;
    };
    AndRestriction.prototype.facetName = function () {
        return "and";
    };
    return AndRestriction;
}(Constraint));
exports.AndRestriction = AndRestriction;
/***
 *
 * lets declare built in types
 */
exports.ANY = new RootType("any");
exports.SCALAR = exports.ANY.inherit("scalar");
exports.OBJECT = exports.ANY.inherit("object");
//export const POLYMORPHIC=OBJECT.inherit("polymorphic");
exports.ARRAY = exports.ANY.inherit("array");
exports.EXTERNAL = exports.ANY.inherit("external");
exports.NUMBER = exports.SCALAR.inherit("number");
exports.INTEGER = exports.NUMBER.inherit("integer");
exports.BOOLEAN = exports.SCALAR.inherit("boolean");
exports.STRING = exports.SCALAR.inherit("string");
exports.NIL = exports.SCALAR.inherit("nil");
//export const DATE=SCALAR.inherit("date");
exports.DATE_ONLY = exports.SCALAR.inherit("date-only");
exports.TIME_ONLY = exports.SCALAR.inherit("time-only");
exports.DATETIME_ONLY = exports.SCALAR.inherit("datetime-only");
exports.DATETIME = exports.SCALAR.inherit("datetime");
exports.FILE = exports.SCALAR.inherit("file");
exports.NOTHING = new RootType("nothing");
exports.UNION = exports.ANY.inherit("union");
exports.UNKNOWN = exports.NOTHING.inherit("unknown");
exports.REFERENCE = exports.NOTHING.inherit("reference");
exports.RECURRENT = exports.NOTHING.inherit("recurrent");
///
//POLYMORPHIC.addMeta(new Polymorphic())
exports.ANY.addMeta(BUILT_IN);
exports.NIL.addMeta(BUILT_IN);
exports.UNION.addMeta(BUILT_IN);
exports.SCALAR.addMeta(BUILT_IN);
exports.OBJECT.addMeta(BUILT_IN);
exports.ARRAY.addMeta(BUILT_IN);
exports.NUMBER.addMeta(BUILT_IN);
exports.INTEGER.addMeta(BUILT_IN);
exports.BOOLEAN.addMeta(BUILT_IN);
exports.STRING.addMeta(BUILT_IN);
exports.EXTERNAL.addMeta(BUILT_IN);
exports.UNKNOWN.addMeta(BUILT_IN);
exports.RECURRENT.addMeta(BUILT_IN);
exports.DATE_ONLY.addMeta(BUILT_IN);
exports.TIME_ONLY.addMeta(BUILT_IN);
exports.DATETIME_ONLY.addMeta(BUILT_IN);
exports.DATETIME.addMeta(BUILT_IN);
exports.FILE.addMeta(BUILT_IN);
//POLYMORPHIC.addMeta(BUILT_IN);
exports.UNKNOWN.addMeta(BUILT_IN);
exports.UNKNOWN.lock();
exports.RECURRENT.addMeta(BUILT_IN);
exports.RECURRENT.lock();
exports.EXTERNAL.lock();
exports.UNION.lock();
exports.REFERENCE.lock();
///lets register all types in registry
registry.addType(exports.ANY);
registry.addType(exports.SCALAR);
registry.addType(exports.OBJECT);
registry.addType(exports.ARRAY);
registry.addType(exports.NUMBER);
registry.addType(exports.INTEGER);
registry.addType(exports.BOOLEAN);
registry.addType(exports.NIL);
registry.addType(exports.STRING);
registry.addType(exports.DATE_ONLY);
registry.addType(exports.TIME_ONLY);
registry.addType(exports.DATETIME_ONLY);
registry.addType(exports.DATETIME);
registry.addType(exports.FILE);
//registry.addType(POLYMORPHIC);
exports.NOTHING.addMeta(new NothingRestriction());
exports.NUMBER.addMeta(new TypeOfRestriction("number"));
exports.NUMBER.addMeta(new metainfo_1.FacetDeclaration("format", exports.STRING, true, true));
exports.BOOLEAN.addMeta(new TypeOfRestriction("boolean"));
exports.OBJECT.addMeta(new TypeOfRestriction("object"));
exports.ARRAY.addMeta(new TypeOfRestriction("array"));
exports.STRING.addMeta(new TypeOfRestriction("string"));
exports.INTEGER.addMeta(new IntegerRestriction());
exports.NIL.addMeta(new NullRestriction());
var dt = require("./datetime");
exports.DATE_ONLY.addMeta(new dt.DateOnlyR());
exports.TIME_ONLY.addMeta(new dt.TimeOnlyR());
exports.DATETIME_ONLY.addMeta(new dt.DateTimeOnlyR());
exports.DATETIME.addMeta(new dt.DateTimeR());
exports.FILE.addMeta(new TypeOfRestriction("string"));
var arrayOfString = exports.ARRAY.inherit("");
arrayOfString.addMeta(new restrictions_3.ComponentShouldBeOfType(exports.STRING));
exports.FILE.addMeta(new metainfo_1.FacetDeclaration("fileTypes", arrayOfString, true, true));
exports.FILE.addMeta(new metainfo_1.FacetDeclaration("minLength", exports.INTEGER, true, true));
exports.FILE.addMeta(new metainfo_1.FacetDeclaration("maxLength", exports.INTEGER, true, true));
exports.DATETIME.addMeta(new metainfo_1.FacetDeclaration("format", exports.STRING, true, true));
exports.NIL.nullable = true;
exports.SCALAR.addMeta(new ScalarRestriction());
registry.types().forEach(function (x) { return x.lock(); });
var ExternalType = /** @class */ (function (_super) {
    __extends(ExternalType, _super);
    function ExternalType(name, _content, json, provider, typeAttributeProvider) {
        if (typeAttributeProvider === void 0) { typeAttributeProvider = null; }
        var _this = _super.call(this, name) || this;
        _this._content = _content;
        _this.json = json;
        _this.provider = provider;
        _this.addMeta(new restr.MatchToSchema(_content, typeAttributeProvider ? typeAttributeProvider : provider));
        _this.addSuper(exports.EXTERNAL);
        return _this;
    }
    ExternalType.prototype.getClassIdentifier = function () {
        var superIdentifiers = _super.prototype.getClassIdentifier.call(this);
        return superIdentifiers.concat(ExternalType.CLASS_IDENTIFIER_ExternalType);
    };
    ExternalType.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), ExternalType.CLASS_IDENTIFIER_ExternalType);
    };
    ExternalType.prototype.getContentProvider = function () {
        return this.provider;
    };
    ExternalType.prototype.setContentProvider = function (provider) {
        this.provider = provider;
    };
    ExternalType.prototype.kind = function () {
        return "external";
    };
    ExternalType.prototype.isJSON = function () {
        return this.json;
    };
    ExternalType.prototype.schema = function () {
        return this._content;
    };
    ExternalType.CLASS_IDENTIFIER_ExternalType = "typesystem.ExternalType";
    return ExternalType;
}(InheritedType));
exports.ExternalType = ExternalType;
function typePath(t) {
    var arr = [];
    while (t != null) {
        if (t.name() == null) {
            if (t instanceof InheritedType) {
                var contextMeta = t.contextMeta();
                if (contextMeta != null) {
                    arr.push(contextMeta.path());
                    t = contextMeta._owner;
                }
                else {
                    break;
                }
            }
            else {
                break;
            }
        }
        else {
            arr.push(t.name());
            break;
        }
    }
    return arr.reverse();
}
exports.typePath = typePath;
function checkDescriminator(i, t, path) {
    var discriminator = t.metaOfType(metaInfo.Discriminator);
    if (discriminator.length != 0) {
        var dName = discriminator[0].value();
        var owner = _.find([t].concat(t.allSuperTypes()), function (x) { return x.getExtra(exports.GLOBAL); });
        if (!owner) {
            return null;
        }
        var dVal = owner.name();
        var discriminatorValue = t.metaOfType(metaInfo.DiscriminatorValue);
        if (discriminatorValue.length != 0) {
            dVal = discriminatorValue[0].value();
        }
        if (dVal) {
            if (i.hasOwnProperty(dName)) {
                var adVal = i[dName];
                if (adVal != dVal) {
                    var wrng = error(Status.CODE_INCORRECT_DISCRIMINATOR, this, {
                        rootType: owner.name(),
                        value: adVal,
                        propName: dName
                    }, Status.WARNING);
                    //var wrng = new Status(Status.WARNING, Status.CODE_INCORRECT_DISCRIMINATOR, dVal, this);
                    setValidationPath(wrng, { name: dName, child: path });
                    return wrng;
                }
                return ok();
            }
            else {
                var err = error(Status.CODE_MISSING_DISCRIMINATOR, this, {
                    rootType: owner.name(),
                    propName: dName
                });
                //var err = new Status(Status.ERROR, Status.CODE_MISSING_DISCRIMINATOR, dVal, this);
                setValidationPath(err, path);
                return err;
            }
        }
    }
    else {
        return null;
    }
}
var ValidationError = /** @class */ (function (_super) {
    __extends(ValidationError, _super);
    function ValidationError(messageEntry, parameters) {
        if (parameters === void 0) { parameters = {}; }
        var _this = _super.call(this) || this;
        _this.messageEntry = messageEntry;
        _this.parameters = parameters;
        _this.isWarning = false;
        _this.message = messageText(messageEntry, parameters);
        _this.getClassIdentifier = ValidationError.prototype.getClassIdentifier;
        return _this;
    }
    ValidationError.prototype.getClassIdentifier = function () {
        var superIdentifiers = [];
        return superIdentifiers.concat(ValidationError.CLASS_IDENTIFIER_ValidationError);
    };
    ValidationError.isInstance = function (instance) {
        return instance != null && instance.getClassIdentifier
            && typeof (instance.getClassIdentifier) == "function"
            && _.contains(instance.getClassIdentifier(), ValidationError.CLASS_IDENTIFIER_ValidationError);
    };
    ValidationError.CLASS_IDENTIFIER_ValidationError = "linter.ValidationError";
    return ValidationError;
}(Error));
exports.ValidationError = ValidationError;
function setValidationPath(_s, _c) {
    if (_s.getValidationPath()) {
        var c = patchPath(_c);
        var m = c;
        while (m.child) {
            m = m.child;
        }
        m.child = _s.getValidationPath();
        _s.setValidationPath(c);
    }
    else {
        _s.setValidationPath(_c);
    }
    _s.getSubStatuses().forEach(function (x) {
        setValidationPath(x, _c);
    });
}
exports.setValidationPath = setValidationPath;
function patchPath(p) {
    if (!p) {
        return null;
    }
    else {
        var c = p;
        var r = null;
        var cp = null;
        while (c) {
            if (!r) {
                r = { name: c.name };
                cp = r;
                c = c.child;
                cp = r;
            }
            else {
                var news = { name: c.name };
                cp.child = news;
                c = c.child;
                cp = news;
            }
        }
        return r;
    }
}
exports.patchPath = patchPath;
/**
 * A model of annotated RAML type facet
 */
var AnnotatedFacet = /** @class */ (function () {
    function AnnotatedFacet(_facet, reg) {
        this._facet = _facet;
        this.reg = reg;
    }
    AnnotatedFacet.prototype.kind = function () { return "AnnotatedFacet"; };
    AnnotatedFacet.prototype.annotationsMap = function () {
        var _this = this;
        if (!this._annotationsMap) {
            this._annotationsMap = {};
            this.annotations().forEach(function (x) { return _this._annotationsMap[x.name()] = x; });
        }
        return this._annotationsMap;
    };
    AnnotatedFacet.prototype.annotations = function () {
        var _this = this;
        if (!this._annotations) {
            this._annotations = this._facet.annotations().map(function (x) { return new AnnotationInstance(x, _this.reg); });
        }
        return this._annotations;
    };
    /**
     * Value of the facet serialized to JSON
     */
    AnnotatedFacet.prototype.value = function () { return this._facet.value(); };
    /**
     * Facet name
     */
    AnnotatedFacet.prototype.name = function () { return this._facet.facetName(); };
    /**
     * The facet itself
     */
    AnnotatedFacet.prototype.entry = function () { return this._facet; };
    return AnnotatedFacet;
}());
exports.AnnotatedFacet = AnnotatedFacet;
var parse = require("./parse");
/**
 * A model of annotated RAML type
 */
var AnnotatedType = /** @class */ (function () {
    function AnnotatedType(_type, reg) {
        this._type = _type;
        this.reg = reg;
    }
    AnnotatedType.prototype.kind = function () { return "AnnotatedType"; };
    AnnotatedType.prototype.annotationsMap = function () {
        var _this = this;
        if (!this._annotationsMap) {
            this._annotationsMap = {};
            this.annotations().forEach(function (x) {
                var n = x.name();
                var ind = n.lastIndexOf(".");
                if (ind >= 0) {
                    n = n.substring(ind + 1);
                }
                _this._annotationsMap[n] = x;
            });
        }
        return this._annotationsMap;
    };
    AnnotatedType.prototype.annotations = function () {
        var _this = this;
        if (!this._annotations) {
            this._annotations = this._type.meta().filter(function (x) {
                return x.kind() == tsInterfaces.MetaInformationKind.Annotation;
            }).map(function (x) { return new AnnotationInstance(x, _this.reg); });
        }
        return this._annotations;
    };
    /**
     * JSON representation of the type
     */
    AnnotatedType.prototype.value = function () { return parse.storeAsJSON(this._type); };
    /**
     * Type name
     */
    AnnotatedType.prototype.name = function () { return this._type.name(); };
    /**
     * The type itself
     * @returns {IParsedType}
     */
    AnnotatedType.prototype.entry = function () { return this._type; };
    return AnnotatedType;
}());
exports.AnnotatedType = AnnotatedType;
var AnnotationInstance = /** @class */ (function () {
    function AnnotationInstance(actual, reg) {
        this.actual = actual;
    }
    AnnotationInstance.prototype.name = function () {
        return this.actual.facetName();
    };
    /**
     * Annotation value
     */
    AnnotationInstance.prototype.value = function () {
        return this.actual.value();
    };
    /**
     * Annotation definition type
     */
    AnnotationInstance.prototype.definition = function () {
        var tp = registry.get(this.actual.facetName());
        return tp;
    };
    /**
     * Actual annotation model
     */
    AnnotationInstance.prototype.annotation = function () {
        return this.actual;
    };
    return AnnotationInstance;
}());
exports.AnnotationInstance = AnnotationInstance;
/**
 * Apply registered type validation plugins to the type
 * @param t type to be validated
 * @param reg context type registry
 * @param skipOk whether to omit OK issues
 * @returns an array of {tsInterfaces.IStatus}
 */
function applyAnnotationValidationPlugins(e) {
    var plugins = tsInterfaces.getAnnotationValidationPlugins();
    var result = [];
    for (var _i = 0, plugins_1 = plugins; _i < plugins_1.length; _i++) {
        var tv = plugins_1[_i];
        var issues = tv.process(e);
        if (issues) {
            issues.forEach(function (x) {
                result.push(toStatus(x, tv.id(), e.entry()));
            });
        }
    }
    return result;
}
exports.applyAnnotationValidationPlugins = applyAnnotationValidationPlugins;
/**
 * Apply registered type validation plugins to the type
 * @param t type to be validated
 * @param reg context type registry
 * @param skipOk whether to omit OK issues
 * @returns an array of {tsInterfaces.IStatus}
 */
function applyTypeValidationPlugins(t, reg) {
    var plugins = tsInterfaces.getTypeValidationPlugins();
    var result = [];
    for (var _i = 0, plugins_2 = plugins; _i < plugins_2.length; _i++) {
        var tv = plugins_2[_i];
        var issues = tv.process(t, reg);
        if (issues) {
            issues.forEach(function (x) {
                result.push(toStatus(x, tv.id(), t));
            });
        }
    }
    return result;
}
exports.applyTypeValidationPlugins = applyTypeValidationPlugins;
function toStatus(pvi, pluginId, src) {
    var severity = pvi.isWarning ? Status.WARNING : Status.ERROR;
    var issueCode = pvi.issueCode || pluginId;
    var message = pvi.message || messageText(exports.messageRegistry.PLUGIN_REPORTS_AN_ERROR, { pluginId: pluginId });
    var status = new Status(severity, issueCode, message, src);
    status.setValidationPath(pvi.path);
    return status;
}
function toValidationPath(p) {
    if (!p) {
        return null;
    }
    p = p.trim();
    if (p.length == 0) {
        return null;
    }
    if (p.charAt(0) == "#") {
        p = p.substring(1);
    }
    if (p.charAt(0) == "/") {
        p = p.substring(1);
    }
    if (p.length == 0) {
        return null;
    }
    var arr = p.split("/");
    var result = {
        name: arr[0]
    };
    var prev = result;
    for (var i = 1; i < arr.length; i++) {
        var vp = {
            name: arr[i]
        };
        prev.child = vp;
        prev = vp;
    }
    return result;
}
exports.toValidationPath = toValidationPath;
function isUnknown(t) {
    return !t || (t.isSubTypeOf(exports.UNKNOWN) && !t.oneMeta(metaInfo.SkipValidation));
}
exports.isUnknown = isUnknown;
//# sourceMappingURL=typesystem.js.map