"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnknownType = exports.UnionType = exports.TypeOperatorType = exports.NamedTupleMember = exports.TupleType = exports.TemplateLiteralType = exports.RestType = exports.ReflectionType = exports.ReferenceType = exports.QueryType = exports.PredicateType = exports.OptionalType = exports.MappedType = exports.LiteralType = exports.IntrinsicType = exports.IntersectionType = exports.InferredType = exports.IndexedAccessType = exports.ConditionalType = exports.ArrayType = exports.TypeContext = exports.makeRecursiveVisitor = exports.Type = void 0;
const abstract_1 = require("./reflections/abstract");
/**
 * Base class of all type definitions.
 */
class Type {
    /**
     * Return a string representation of this type.
     */
    toString() {
        return this.stringify(exports.TypeContext.none);
    }
    visit(visitor) {
        var _a;
        return (_a = visitor[this.type]) === null || _a === void 0 ? void 0 : _a.call(visitor, this);
    }
    stringify(context) {
        if (this.needsParenthesis(context)) {
            return `(${this.getTypeString()})`;
        }
        return this.getTypeString();
    }
}
exports.Type = Type;
function makeRecursiveVisitor(visitor) {
    const recursiveVisitor = {
        "named-tuple-member"(type) {
            var _a;
            (_a = visitor["named-tuple-member"]) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.element.visit(recursiveVisitor);
        },
        "template-literal"(type) {
            var _a;
            (_a = visitor["template-literal"]) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            for (const [h] of type.tail) {
                h.visit(recursiveVisitor);
            }
        },
        array(type) {
            var _a;
            (_a = visitor.array) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.elementType.visit(recursiveVisitor);
        },
        conditional(type) {
            var _a;
            (_a = visitor.conditional) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.checkType.visit(recursiveVisitor);
            type.extendsType.visit(recursiveVisitor);
            type.trueType.visit(recursiveVisitor);
            type.falseType.visit(recursiveVisitor);
        },
        indexedAccess(type) {
            var _a;
            (_a = visitor.indexedAccess) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.indexType.visit(recursiveVisitor);
            type.objectType.visit(recursiveVisitor);
        },
        inferred(type) {
            var _a, _b;
            (_a = visitor.inferred) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            (_b = type.constraint) === null || _b === void 0 ? void 0 : _b.visit(recursiveVisitor);
        },
        intersection(type) {
            var _a;
            (_a = visitor.intersection) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.types.forEach((t) => t.visit(recursiveVisitor));
        },
        intrinsic(type) {
            var _a;
            (_a = visitor.intrinsic) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
        },
        literal(type) {
            var _a;
            (_a = visitor.literal) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
        },
        mapped(type) {
            var _a, _b;
            (_a = visitor.mapped) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            (_b = type.nameType) === null || _b === void 0 ? void 0 : _b.visit(recursiveVisitor);
            type.parameterType.visit(recursiveVisitor);
            type.templateType.visit(recursiveVisitor);
        },
        optional(type) {
            var _a;
            (_a = visitor.optional) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.elementType.visit(recursiveVisitor);
        },
        predicate(type) {
            var _a, _b;
            (_a = visitor.predicate) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            (_b = type.targetType) === null || _b === void 0 ? void 0 : _b.visit(recursiveVisitor);
        },
        query(type) {
            var _a;
            (_a = visitor.query) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.queryType.visit(recursiveVisitor);
        },
        reference(type) {
            var _a, _b;
            (_a = visitor.reference) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            (_b = type.typeArguments) === null || _b === void 0 ? void 0 : _b.forEach((t) => t.visit(recursiveVisitor));
        },
        reflection(type) {
            var _a;
            (_a = visitor.reflection) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            // Future: This should maybe recurse too?
            // See the validator in exports.ts for how to do it.
        },
        rest(type) {
            var _a;
            (_a = visitor.rest) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.elementType.visit(recursiveVisitor);
        },
        tuple(type) {
            var _a;
            (_a = visitor.tuple) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.elements.forEach((t) => t.visit(recursiveVisitor));
        },
        typeOperator(type) {
            var _a;
            (_a = visitor.typeOperator) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.target.visit(recursiveVisitor);
        },
        union(type) {
            var _a;
            (_a = visitor.union) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
            type.types.forEach((t) => t.visit(recursiveVisitor));
        },
        unknown(type) {
            var _a;
            (_a = visitor.unknown) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
        },
    };
    return recursiveVisitor;
}
exports.makeRecursiveVisitor = makeRecursiveVisitor;
/**
 * Enumeration that can be used when traversing types to track the location of recursion.
 * Used by TypeDoc internally to track when to output parenthesis when rendering.
 * @enum
 */
exports.TypeContext = {
    none: "none",
    templateLiteralElement: "templateLiteralElement",
    arrayElement: "arrayElement",
    indexedAccessElement: "indexedAccessElement",
    conditionalCheck: "conditionalCheck",
    conditionalExtends: "conditionalExtends",
    conditionalTrue: "conditionalTrue",
    conditionalFalse: "conditionalFalse",
    indexedIndex: "indexedIndex",
    indexedObject: "indexedObject",
    inferredConstraint: "inferredConstraint",
    intersectionElement: "intersectionElement",
    mappedName: "mappedName",
    mappedParameter: "mappedParameter",
    mappedTemplate: "mappedTemplate",
    optionalElement: "optionalElement",
    predicateTarget: "predicateTarget",
    queryTypeTarget: "queryTypeTarget",
    typeOperatorTarget: "typeOperatorTarget",
    referenceTypeArgument: "referenceTypeArgument",
    restElement: "restElement",
    tupleElement: "tupleElement",
    unionElement: "unionElement", // here | 1
};
/**
 * Represents an array type.
 *
 * ```ts
 * let value: string[];
 * ```
 */
class ArrayType extends Type {
    constructor(elementType) {
        super();
        this.type = "array";
        this.elementType = elementType;
    }
    getTypeString() {
        return this.elementType.stringify(exports.TypeContext.arrayElement) + "[]";
    }
    needsParenthesis() {
        return false;
    }
}
exports.ArrayType = ArrayType;
/**
 * Represents a conditional type.
 *
 * ```ts
 * let value: Check extends Extends ? True : False;
 * ```
 */
class ConditionalType extends Type {
    constructor(checkType, extendsType, trueType, falseType) {
        super();
        this.checkType = checkType;
        this.extendsType = extendsType;
        this.trueType = trueType;
        this.falseType = falseType;
        this.type = "conditional";
    }
    getTypeString() {
        return [
            this.checkType.stringify(exports.TypeContext.conditionalCheck),
            "extends",
            this.extendsType.stringify(exports.TypeContext.conditionalExtends),
            "?",
            this.trueType.stringify(exports.TypeContext.conditionalTrue),
            ":",
            this.falseType.stringify(exports.TypeContext.conditionalFalse),
        ].join(" ");
    }
    needsParenthesis(context) {
        const map = {
            none: false,
            templateLiteralElement: false,
            arrayElement: true,
            indexedAccessElement: false,
            conditionalCheck: true,
            conditionalExtends: true,
            conditionalTrue: false,
            conditionalFalse: false,
            indexedIndex: false,
            indexedObject: true,
            inferredConstraint: true,
            intersectionElement: true,
            mappedName: false,
            mappedParameter: false,
            mappedTemplate: false,
            optionalElement: true,
            predicateTarget: false,
            queryTypeTarget: false,
            typeOperatorTarget: true,
            referenceTypeArgument: false,
            restElement: true,
            tupleElement: false,
            unionElement: true,
        };
        return map[context];
    }
}
exports.ConditionalType = ConditionalType;
/**
 * Represents an indexed access type.
 */
class IndexedAccessType extends Type {
    constructor(objectType, indexType) {
        super();
        this.objectType = objectType;
        this.indexType = indexType;
        this.type = "indexedAccess";
    }
    getTypeString() {
        return [
            this.objectType.stringify(exports.TypeContext.indexedObject),
            "[",
            this.indexType.stringify(exports.TypeContext.indexedIndex),
            "]",
        ].join("");
    }
    needsParenthesis() {
        return false;
    }
}
exports.IndexedAccessType = IndexedAccessType;
/**
 * Represents an inferred type, U in the example below.
 *
 * ```ts
 * type Z = Promise<string> extends Promise<infer U> : never
 * ```
 */
class InferredType extends Type {
    constructor(name, constraint) {
        super();
        this.name = name;
        this.constraint = constraint;
        this.type = "inferred";
    }
    getTypeString() {
        if (this.constraint) {
            return `infer ${this.name} extends ${this.constraint.stringify(exports.TypeContext.inferredConstraint)}`;
        }
        return `infer ${this.name}`;
    }
    needsParenthesis(context) {
        const map = {
            none: false,
            templateLiteralElement: false,
            arrayElement: true,
            indexedAccessElement: false,
            conditionalCheck: false,
            conditionalExtends: false,
            conditionalTrue: false,
            conditionalFalse: false,
            indexedIndex: false,
            indexedObject: true,
            inferredConstraint: false,
            intersectionElement: false,
            mappedName: false,
            mappedParameter: false,
            mappedTemplate: false,
            optionalElement: true,
            predicateTarget: false,
            queryTypeTarget: false,
            typeOperatorTarget: false,
            referenceTypeArgument: false,
            restElement: true,
            tupleElement: false,
            unionElement: false,
        };
        return map[context];
    }
}
exports.InferredType = InferredType;
/**
 * Represents an intersection type.
 *
 * ```ts
 * let value: A & B;
 * ```
 */
class IntersectionType extends Type {
    constructor(types) {
        super();
        this.types = types;
        this.type = "intersection";
    }
    getTypeString() {
        return this.types
            .map((t) => t.stringify(exports.TypeContext.intersectionElement))
            .join(" & ");
    }
    needsParenthesis(context) {
        const map = {
            none: false,
            templateLiteralElement: false,
            arrayElement: true,
            indexedAccessElement: false,
            conditionalCheck: true,
            conditionalExtends: false,
            conditionalTrue: false,
            conditionalFalse: false,
            indexedIndex: false,
            indexedObject: true,
            inferredConstraint: false,
            intersectionElement: false,
            mappedName: false,
            mappedParameter: false,
            mappedTemplate: false,
            optionalElement: true,
            predicateTarget: false,
            queryTypeTarget: false,
            typeOperatorTarget: true,
            referenceTypeArgument: false,
            restElement: true,
            tupleElement: false,
            unionElement: false,
        };
        return map[context];
    }
}
exports.IntersectionType = IntersectionType;
/**
 * Represents an intrinsic type like `string` or `boolean`.
 *
 * ```ts
 * let value: number;
 * ```
 */
class IntrinsicType extends Type {
    constructor(name) {
        super();
        this.name = name;
        this.type = "intrinsic";
    }
    getTypeString() {
        return this.name;
    }
    needsParenthesis() {
        return false;
    }
}
exports.IntrinsicType = IntrinsicType;
/**
 * Represents a literal type.
 *
 * ```ts
 * type A = "A"
 * type B = 1
 * ```
 */
class LiteralType extends Type {
    constructor(value) {
        super();
        this.value = value;
        this.type = "literal";
    }
    /**
     * Return a string representation of this type.
     */
    getTypeString() {
        if (typeof this.value === "bigint") {
            return this.value.toString() + "n";
        }
        return JSON.stringify(this.value);
    }
    needsParenthesis() {
        return false;
    }
}
exports.LiteralType = LiteralType;
/**
 * Represents a mapped type.
 *
 * ```ts
 * { -readonly [K in Parameter as Name]?: Template }
 * ```
 */
class MappedType extends Type {
    constructor(parameter, parameterType, templateType, readonlyModifier, optionalModifier, nameType) {
        super();
        this.parameter = parameter;
        this.parameterType = parameterType;
        this.templateType = templateType;
        this.readonlyModifier = readonlyModifier;
        this.optionalModifier = optionalModifier;
        this.nameType = nameType;
        this.type = "mapped";
    }
    getTypeString() {
        var _a, _b;
        const read = {
            "+": "readonly ",
            "-": "-readonly ",
            "": "",
        }[(_a = this.readonlyModifier) !== null && _a !== void 0 ? _a : ""];
        const opt = {
            "+": "?",
            "-": "-?",
            "": "",
        }[(_b = this.optionalModifier) !== null && _b !== void 0 ? _b : ""];
        const parts = [
            "{ ",
            read,
            "[",
            this.parameter,
            " in ",
            this.parameterType.stringify(exports.TypeContext.mappedParameter),
        ];
        if (this.nameType) {
            parts.push(" as ", this.nameType.stringify(exports.TypeContext.mappedName));
        }
        parts.push("]", opt, ": ", this.templateType.stringify(exports.TypeContext.mappedTemplate), " }");
        return parts.join("");
    }
    needsParenthesis() {
        return false;
    }
}
exports.MappedType = MappedType;
/**
 * Represents an optional type
 * ```ts
 * type Z = [1, 2?]
 * //           ^^
 * ```
 */
class OptionalType extends Type {
    constructor(elementType) {
        super();
        this.type = "optional";
        this.elementType = elementType;
    }
    getTypeString() {
        return this.elementType.stringify(exports.TypeContext.optionalElement) + "?";
    }
    needsParenthesis() {
        return false;
    }
}
exports.OptionalType = OptionalType;
/**
 * Represents a type predicate.
 *
 * ```ts
 * function isString(anything: any): anything is string {}
 * function assert(condition: boolean): asserts condition {}
 * ```
 */
class PredicateType extends Type {
    /**
     * Create a new PredicateType instance.
     */
    constructor(name, asserts, targetType) {
        super();
        this.type = "predicate";
        this.name = name;
        this.asserts = asserts;
        this.targetType = targetType;
    }
    /**
     * Return a string representation of this type.
     */
    getTypeString() {
        const out = this.asserts ? ["asserts", this.name] : [this.name];
        if (this.targetType) {
            out.push("is", this.targetType.stringify(exports.TypeContext.predicateTarget));
        }
        return out.join(" ");
    }
    needsParenthesis() {
        return false;
    }
}
exports.PredicateType = PredicateType;
/**
 * Represents a type that is constructed by querying the type of a reflection.
 * ```ts
 * const x = 1
 * type Z = typeof x // query on reflection for x
 * ```
 */
class QueryType extends Type {
    constructor(reference) {
        super();
        this.type = "query";
        this.queryType = reference;
    }
    getTypeString() {
        return `typeof ${this.queryType.stringify(exports.TypeContext.queryTypeTarget)}`;
    }
    /**
     * @privateRemarks
     * An argument could be made that this ought to return true for indexedObject
     * since precedence is different than on the value side... if someone really cares
     * they can easily use a custom theme to change this.
     */
    needsParenthesis() {
        return false;
    }
}
exports.QueryType = QueryType;
/**
 * Represents a type that refers to another reflection like a class, interface or enum.
 *
 * ```ts
 * let value: MyClass<T>;
 * ```
 */
class ReferenceType extends Type {
    constructor(name, target, project) {
        super();
        this.type = "reference";
        this.name = name;
        this._target = target instanceof abstract_1.Reflection ? target.id : target;
        this._project = project;
    }
    /**
     * The resolved reflection.
     */
    get reflection() {
        var _a, _b;
        if (typeof this._target === "number") {
            return (_a = this._project) === null || _a === void 0 ? void 0 : _a.getReflectionById(this._target);
        }
        const resolved = (_b = this._project) === null || _b === void 0 ? void 0 : _b.getReflectionFromSymbol(this._target);
        if (resolved)
            this._target = resolved.id;
        return resolved;
    }
    /**
     * Don't use this if at all possible. It will eventually go away since models may not
     * retain information from the original TS objects to enable documentation generation from
     * previously generated JSON.
     * @internal
     */
    getSymbol() {
        if (typeof this._target === "number") {
            return;
        }
        return this._target;
    }
    static createResolvedReference(name, target, project) {
        return new ReferenceType(name, target, project);
    }
    static createSymbolReference(symbol, context, name) {
        var _a, _b;
        const ref = new ReferenceType(name !== null && name !== void 0 ? name : symbol.name, symbol, context.project);
        const symbolPath = (_b = (_a = symbol === null || symbol === void 0 ? void 0 : symbol.declarations) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.getSourceFile().fileName.replace(/\\/g, "/");
        if (!symbolPath)
            return ref;
        let startIndex = symbolPath.indexOf("node_modules/");
        if (startIndex === -1)
            return ref;
        startIndex += "node_modules/".length;
        let stopIndex = symbolPath.indexOf("/", startIndex);
        // Scoped package, e.g. `@types/node`
        if (symbolPath[startIndex] === "@") {
            stopIndex = symbolPath.indexOf("/", stopIndex + 1);
        }
        const packageName = symbolPath.substring(startIndex, stopIndex);
        ref.package = packageName;
        const qualifiedName = context.checker.getFullyQualifiedName(symbol);
        // I think this is less bad than depending on symbol.parent...
        // https://github.com/microsoft/TypeScript/issues/38344
        // It will break if someone names a directory with a quote in it, but so will lots
        // of other things including other parts of TypeDoc. Until it *actually* breaks someone...
        if (qualifiedName.startsWith('"')) {
            ref.qualifiedName = qualifiedName.substring(qualifiedName.indexOf('".', 1) + 2);
        }
        else {
            ref.qualifiedName = qualifiedName;
        }
        return ref;
    }
    /** @internal this is used for type parameters, which don't actually point to something */
    static createBrokenReference(name, project) {
        return new ReferenceType(name, -1, project);
    }
    getTypeString() {
        const name = this.reflection ? this.reflection.name : this.name;
        let typeArgs = "";
        if (this.typeArguments && this.typeArguments.length > 0) {
            typeArgs += "<";
            typeArgs += this.typeArguments
                .map((arg) => arg.stringify(exports.TypeContext.referenceTypeArgument))
                .join(", ");
            typeArgs += ">";
        }
        return name + typeArgs;
    }
    needsParenthesis() {
        return false;
    }
}
exports.ReferenceType = ReferenceType;
/**
 * Represents a type which has it's own reflection like literal types.
 * This type will likely go away at some point and be replaced by a dedicated
 * `ObjectType`. Allowing reflections to be nested within types causes much
 * pain in the rendering code.
 *
 * ```ts
 * let value: { a: string, b: number };
 * ```
 */
class ReflectionType extends Type {
    constructor(declaration) {
        super();
        this.type = "reflection";
        this.declaration = declaration;
    }
    // This really ought to do better, but I'm putting off investing effort here until
    // I'm fully convinced that keeping this is a good idea. Currently, I'd much rather
    // change object types to not create reflections.
    getTypeString() {
        if (!this.declaration.children && this.declaration.signatures) {
            return "Function";
        }
        else {
            return "Object";
        }
    }
    needsParenthesis() {
        return false;
    }
}
exports.ReflectionType = ReflectionType;
/**
 * Represents a rest type
 * ```ts
 * type Z = [1, ...2[]]
 * //           ^^^^^^
 * ```
 */
class RestType extends Type {
    constructor(elementType) {
        super();
        this.elementType = elementType;
        this.type = "rest";
    }
    getTypeString() {
        return `...${this.elementType.stringify(exports.TypeContext.restElement)}`;
    }
    needsParenthesis() {
        return false;
    }
}
exports.RestType = RestType;
/**
 * TS 4.1 template literal types
 * ```ts
 * type Z = `${'a' | 'b'}${'a' | 'b'}`
 * ```
 */
class TemplateLiteralType extends Type {
    constructor(head, tail) {
        super();
        this.head = head;
        this.tail = tail;
        this.type = "template-literal";
    }
    getTypeString() {
        return [
            "`",
            this.head,
            ...this.tail.map(([type, text]) => {
                return ("${" +
                    type.stringify(exports.TypeContext.templateLiteralElement) +
                    "}" +
                    text);
            }),
            "`",
        ].join("");
    }
    needsParenthesis() {
        return false;
    }
}
exports.TemplateLiteralType = TemplateLiteralType;
/**
 * Represents a tuple type.
 *
 * ```ts
 * let value: [string, boolean];
 * ```
 */
class TupleType extends Type {
    constructor(elements) {
        super();
        this.type = "tuple";
        this.elements = elements;
    }
    getTypeString() {
        return ("[" +
            this.elements
                .map((t) => t.stringify(exports.TypeContext.tupleElement))
                .join(", ") +
            "]");
    }
    needsParenthesis() {
        return false;
    }
}
exports.TupleType = TupleType;
/**
 * Represents a named member of a tuple type.
 *
 * ```ts
 * let value: [name: string];
 * ```
 */
class NamedTupleMember extends Type {
    constructor(name, isOptional, element) {
        super();
        this.name = name;
        this.isOptional = isOptional;
        this.element = element;
        this.type = "named-tuple-member";
    }
    /**
     * Return a string representation of this type.
     */
    getTypeString() {
        return `${this.name}${this.isOptional ? "?" : ""}: ${this.element.stringify(exports.TypeContext.tupleElement)}`;
    }
    needsParenthesis() {
        return false;
    }
}
exports.NamedTupleMember = NamedTupleMember;
/**
 * Represents a type operator type.
 *
 * ```ts
 * class A {}
 * class B<T extends keyof A> {}
 * ```
 */
class TypeOperatorType extends Type {
    constructor(target, operator) {
        super();
        this.target = target;
        this.operator = operator;
        this.type = "typeOperator";
    }
    getTypeString() {
        return `${this.operator} ${this.target.stringify(exports.TypeContext.typeOperatorTarget)}`;
    }
    needsParenthesis(context) {
        const map = {
            none: false,
            templateLiteralElement: false,
            arrayElement: true,
            indexedAccessElement: false,
            conditionalCheck: false,
            conditionalExtends: false,
            conditionalTrue: false,
            conditionalFalse: false,
            indexedIndex: false,
            indexedObject: true,
            inferredConstraint: false,
            intersectionElement: false,
            mappedName: false,
            mappedParameter: false,
            mappedTemplate: false,
            optionalElement: true,
            predicateTarget: false,
            queryTypeTarget: false,
            typeOperatorTarget: false,
            referenceTypeArgument: false,
            restElement: false,
            tupleElement: false,
            unionElement: false,
        };
        return map[context];
    }
}
exports.TypeOperatorType = TypeOperatorType;
/**
 * Represents an union type.
 *
 * ```ts
 * let value: string | string[];
 * ```
 */
class UnionType extends Type {
    constructor(types) {
        super();
        this.types = types;
        this.type = "union";
        this.normalize();
    }
    getTypeString() {
        return this.types
            .map((t) => t.stringify(exports.TypeContext.unionElement))
            .join(" | ");
    }
    needsParenthesis(context) {
        const map = {
            none: false,
            templateLiteralElement: false,
            arrayElement: true,
            indexedAccessElement: false,
            conditionalCheck: true,
            conditionalExtends: false,
            conditionalTrue: false,
            conditionalFalse: false,
            indexedIndex: false,
            indexedObject: true,
            inferredConstraint: false,
            intersectionElement: true,
            mappedName: false,
            mappedParameter: false,
            mappedTemplate: false,
            optionalElement: true,
            predicateTarget: false,
            queryTypeTarget: false,
            typeOperatorTarget: true,
            referenceTypeArgument: false,
            restElement: false,
            tupleElement: false,
            unionElement: false,
        };
        return map[context];
    }
    normalize() {
        let trueIndex = -1;
        let falseIndex = -1;
        for (let i = 0; i < this.types.length && (trueIndex === -1 || falseIndex === -1); i++) {
            const t = this.types[i];
            if (t instanceof LiteralType) {
                if (t.value === true) {
                    trueIndex = i;
                }
                if (t.value === false) {
                    falseIndex = i;
                }
            }
        }
        if (trueIndex !== -1 && falseIndex !== -1) {
            this.types.splice(Math.max(trueIndex, falseIndex), 1);
            this.types.splice(Math.min(trueIndex, falseIndex), 1, new IntrinsicType("boolean"));
        }
    }
}
exports.UnionType = UnionType;
/**
 * Represents all unknown types that cannot be converted by TypeDoc.
 */
class UnknownType extends Type {
    constructor(name) {
        super();
        this.type = "unknown";
        this.name = name;
    }
    getTypeString() {
        return this.name;
    }
    /**
     * Always returns true if not at the root level, we have no idea what's in here, so wrap it in parenthesis
     * to be extra safe.
     */
    needsParenthesis(context) {
        return context !== exports.TypeContext.none;
    }
}
exports.UnknownType = UnknownType;
