text: "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.makeRecursiveVisitor = exports.Type = void 0;
  const abstract_1 = require("./reflections/abstract");
  /**
   * Base class of all type definitions.
   */
  class Type {
      /**
       * Visit this type, returning the value returned by the visitor.
       */
      visit(visitor) {
          return visitor[this.type](this);
      }
  }
  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;
              (_a = visitor.inferred) === null || _a === void 0 ? void 0 : _a.call(visitor, type);
          },
          intersection(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;
  // A lower binding power means that if contained within a type
  // with a higher binding power the type must be parenthesized.
  // 999 = never have parenthesis
  // -1 = always have parenthesis
  const BINDING_POWERS = {
      array: 999,
      conditional: 70,
      conditionalCheckType: 150,
      indexedAccess: 999,
      inferred: 999,
      intersection: 120,
      intrinsic: 999,
      literal: 999,
      mapped: 999,
      optional: 999,
      predicate: 999,
      query: 900,
      reference: 999,
      reflection: 999,
      rest: 999,
      "template-literal": 999,
      tuple: 999,
      "named-tuple-member": 999,
      typeOperator: 900,
      union: 100,
      // We should always wrap these in parenthesis since we don't know what they contain.
      unknown: -1,
  };
  function wrap(type, bp) {
      if (BINDING_POWERS[type.type] < bp) {
          return `(${type})`;
      }
      return type.toString();
  }
  /**
   * Represents an array type.
   *
   * ```ts
   * let value: string[];
   * ```
   */
  class ArrayType extends Type {
      constructor(elementType) {
          super();
          this.type = "array";
          this.elementType = elementType;
      }
      toString() {
          return wrap(this.elementType, BINDING_POWERS.array) + "[]";
      }
  }
  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";
      }
      toString() {
          return [
              wrap(this.checkType, BINDING_POWERS.conditionalCheckType),
              "extends",
              this.extendsType,
              "?",
              this.trueType,
              ":",
              this.falseType, // no need to wrap
          ].join(" ");
      }
  }
  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";
      }
      toString() {
          return `${this.objectType}[${this.indexType}]`;
      }
  }
  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) {
          super();
          this.name = name;
          this.type = "inferred";
      }
      toString() {
          return `infer ${this.name}`;
      }
  }
  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";
      }
      toString() {
          return this.types
              .map((t) => wrap(t, BINDING_POWERS.intersection))
              .join(" & ");
      }
  }
  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";
      }
      toString() {
          return this.name;
      }
  }
  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.
       */
      toString() {
          if (typeof this.value === "bigint") {
              return this.value.toString() + "n";
          }
          return JSON.stringify(this.value);
      }
  }
  exports.LiteralType = LiteralType;
  /**
   * Represents a mapped type.
   *
   * ```ts
   * { -readonly [K in keyof U & string as `a${K}`]?: Foo }
   * ```
   */
  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";
      }
      toString() {
          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 name = this.nameType ? ` as ${this.nameType}` : "";
          return `{ ${read}[${this.parameter} in ${this.parameterType}${name}]${opt}: ${this.templateType} }`;
      }
  }
  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;
      }
      toString() {
          return wrap(this.elementType, BINDING_POWERS.optional) + "?";
      }
  }
  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.
       */
      toString() {
          const out = this.asserts ? ["asserts", this.name] : [this.name];
          if (this.targetType) {
              out.push("is", this.targetType.toString());
          }
          return out.join(" ");
      }
  }
  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;
      }
      toString() {
          return `typeof ${this.queryType.toString()}`;
      }
  }
  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;
      }
      getSymbol() {
          if (typeof this._target === "number") {
              return;
          }
          return this._target;
      }
      /** @internal this is used for type parameters, which don't actually point to something */
      static createBrokenReference(name, project) {
          return new ReferenceType(name, -1, project);
      }
      toString() {
          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.toString())
                  .join(", ");
              typeArgs += ">";
          }
          return name + typeArgs;
      }
  }
  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;
      }
      toString() {
          if (!this.declaration.children && this.declaration.signatures) {
              return "Function";
          }
          else {
              return "Object";
          }
      }
  }
  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";
      }
      toString() {
          return `...${wrap(this.elementType, BINDING_POWERS.rest)}`;
      }
  }
  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";
      }
      toString() {
          return [
              "`",
              this.head,
              ...this.tail.map(([type, text]) => {
                  return "${" + type + "}" + text;
              }),
              "`",
          ].join("");
      }
  }
  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;
      }
      toString() {
          return "[" + this.elements.join(", ") + "]";
      }
  }
  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.
       */
      toString() {
          return `${this.name}${this.isOptional ? "?" : ""}: ${this.element}`;
      }
  }
  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";
      }
      toString() {
          return `${this.operator} ${this.target.toString()}`;
      }
  }
  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();
      }
      toString() {
          return this.types.map((t) => wrap(t, BINDING_POWERS.union)).join(" | ");
      }
      normalize() {
          const trueIndex = this.types.findIndex((t) => t instanceof LiteralType && t.value === true);
          const falseIndex = this.types.findIndex((t) => t instanceof LiteralType && t.value === false);
          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;
      }
      toString() {
          return this.name;
      }
  }
  exports.UnknownType = UnknownType;
  