/// <reference lib="es2015.iterable" />
/// <reference lib="es2018.asynciterable" />

// Form manager ================================================================

/**
 * Form manager validation mode.
 * - `auto`: Automatic validations. A background process is launched that runs
 * validations as needed.
 * - `manual`: Manual validations. Validations only run when
 * {@link FormManager.validate} (or {@link FormManager.isValid}) is called.
 */
export type ValidationMode = "auto" | "manual";

/**
 * Class responsible for managing the data and state of a form.
 *
 * The form manager stores, provides access, and allows manipulating the content
 * of a form with a provided schema in a concurrent and controlled manner. It
 * further manages state associated with the different fields of the form such
 * as keeping track of validation issues, "dirty" and "touched" states, and
 * others.
 *
 * All form value/state accesses and manipulations should go through an instance
 * of the form manager, to make sure that changes are tracked and no "dangerous"
 * concurrent operations are performed. As such, storing non-copied form values
 * outside the form manager is highly discouraged. Certain methods like
 * {@link valueInfo}, {@link get}, and {@link validate} take callbacks as
 * arguments to guarantee that data access only happens within a "controlled
 * environment", i.e. during the lifetime of the callback.
 */
export declare class FormManager {
  /**
   * Constructs a new instance of a form manager.
   * @param formSchema Schema of the form.
   * @param initialValue Initial form value.
   * @param externalContexts External contexts available to validations.
   * @param validationMode Validation mode (defaults to `"auto"`).
   * @param autoInit Whether to automatically initialise the form manager
   * (defaults to `true`). When set to `false`, {@link init} should be called
   * before interacting with the form manager instance.
   */
  constructor(
    formSchema: Schema | SchemaKt,
    initialValue?: unknown,
    externalContexts?: Record<string, unknown>,
    validationMode?: ValidationMode,
    autoInit?: boolean,
  );

  /**
   * Initialises the form manager.
   *
   * This method is automatically called when constructing a new form manager
   * instance when `autoInit` is set to `true` (the default). Calling
   * {@link init} on an already initted form manager has no effect.
   * @param externalContexts External contexts available to validations.
   * @param validationMode Validation mode (defaults to `"auto"`).
   */
  init(
    externalContexts?: Record<string, unknown>,
    validationMode?: ValidationMode,
  ): CancellablePromise<void>;

  /**
   * Destroys this form manager instance by cancelling its coroutine scope.
   *
   * Destroying an already destroyed form manager has no effect.
   */
  destroy(): CancellablePromise<void>;

  /**
   * Status of the automatic validations.
   */
  get autoValidationStatus(): AutoValidationStatus;

  /**
   * Method used to subscribe to changes on the status of the automatic
   * validations. Returns a function that should be used to unsubscribe from
   * change notifications. Note that the subscription itself is asynchronous.
   *
   * An {@link onSubscription} function may be provided, which is guaranteed to
   * run after the subscription has completed, but before changes are emitted to
   * {@link statusChangeHandler}
   * @param statusChangeHandler Function called with the new status of the
   * automatic validations whenever the status changes.
   * @param onSubscription Function called after the subscription completes but
   * before any events are emitted to
   * {@link statusChangeHandler}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the subscription has been registered with another
   * [cancellable promise]{@link CancellablePromise} that can be used to
   * unsubscribe from change notifications.
   */
  onAutoValidationStatusChange(
    statusChangeHandler: (
      status: AutoValidationStatus,
    ) => void | PromiseLike<void>,
    onSubscription?: () => void | PromiseLike<void>,
  ): CancellablePromise<() => CancellablePromise<void>>;

  /**
   * Sets the validation mode (automatic or manual). Note that this action is
   * asynchronous.
   * @param validationMode New validation mode.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the mode has been set.
   */
  setValidationMode(validationMode: ValidationMode): CancellablePromise<void>;

  /**
   * Returns whether there exists at least one schema at a path matching
   * {@link path}.
   *
   * Paths that match no schema paths are deemed invalid by the form manager and
   * most methods called with them will throw.
   * @param path Path to check if valid.
   * @returns Whether {@link path} is valid according to the manager's schema.
   */
  isValidPath(path?: Path | string): boolean;

  /**
   * Returns an iterable over schema-information about the schemas at paths
   * matching {@link path}.
   * @param path Path matching path of schemas from which to get information
   * (defaults to `/**`).
   * @returns Iterable over schema-information of schemas at paths mathing
   * {@link path}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  schemaInfo<T = unknown>(path?: Path | string): Iterable<SchemaInfo<T>>;

  /**
   * Runs the {@link infoHandler} callback with the value-information of values
   * at paths matching {@link path}. Returns the result of {@link infoHandler}.
   *
   * This method receives a callback to ensure that no conflicting concurrent
   * operations occur during the lifetime of said callback.
   * @param path Path matching path of values from which to get information
   * (defaults to `/**`).
   * @param infoHandler Function that receives an async iterable over the
   * value-information of values matching {@link path}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the result of {@link infoHandler}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  valueInfo<T = unknown, TResult = unknown>(
    path: Path | string | undefined,
    infoHandler: (
      infoIterable: AsyncIterable<ValueInfo<T>>,
    ) => TResult | PromiseLike<TResult>,
  ): CancellablePromise<TResult>;

  /**
   * Runs the {@link infoHandler} callback with all information of values at
   * paths matching {@link path}. Returns the result of {@link infoHandler}.
   *
   * This method receives a callback to ensure that no conflicting concurrent
   * operations occur during the lifetime of said callback.
   * @param path Path matching path of values from which to get information
   * (defaults to `/**`).
   * @param infoHandler Function that receives an async iterable over all the
   * information of values matching {@link path}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the result of {@link infoHandler}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  info<T = unknown, TResult = unknown>(
    path: Path | string | undefined,
    infoHandler: (
      infoIterable: AsyncIterable<Info<T>>,
    ) => TResult | PromiseLike<TResult>,
  ): CancellablePromise<TResult>;

  /**
   * Returns the single schema matching {@link path}.
   *
   * To get information about all schemas at paths matching a given path use
   * {@link schemaInfo} instead.
   * @param path Path of the schema to get (defaults to `/`).
   * @returns Schema at {@link path}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths or
   * more than one schema path.
   */
  schema<T = unknown>(path?: Path | string): Schema<T>;

  /**
   * Returns whether there exists at least one value at a path matching
   * {@link path}.
   * @param path Path to check.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether there exists at least one value at a path matching
   * {@link path}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  has(path: Path | string): CancellablePromise<boolean>;

  /**
   * Runs the provided {@link valueHandler} with the single value at
   * {@link path}. Returns the result of {@link valueHandler}.
   *
   * Because this method is meant to return a single value, paths with wildcards
   * are not accepted. To get all values at paths matching a path containing
   * wildcards, use {@link valueInfo} instead.
   *
   * This method receives a callback to ensure that no conflicting concurrent
   * operations occur during the lifetime of said callback.
   * @param path Path of the value to get (defaults to `/`).
   * @param valueHandler Function called with the value at {@link path}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the result of {@link valueHandler}.
   * @throws {InvalidPathException} If {@link path} contains wildcards, matches
   * no schemas, or matches more than one value.
   * @throws {IllegalStateException} If {@link path} matches more than one
   * value.
   * @throws {NoSuchElementException} If no value matches {@link path}.
   */
  get<T = unknown, TResult = unknown>(
    path: Path | string | undefined,
    valueHandler: (value: T) => TResult | PromiseLike<TResult>,
  ): CancellablePromise<TResult>;

  /**
   * Returns a clone (deep copy) of the single value at {@link path}. Equivalent
   * to:
   * ```typescript
   * formManager.get(path, (value) => formManager.schema(path).clone(value))
   * ```
   * @param path Path of the value to get (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with a clone of the value at {@link path}.
   * @throws {InvalidPathException} If {@link path} contains wildcards or
   * matches no schemas.
   * @throws {IllegalStateException} If {@link path} matches more than one
   * value.
   * @throws {NoSuchElementException} If no value matches {@link path}.
   */
  getClone<T = unknown>(path?: Path | string): CancellablePromise<T>;

  /**
   * Sets values at {@link path} with {@link toSet}.
   *
   * If the path has a trailing non-recursive wildcard, then all existing
   * children of its parent value are set to {@link toSet}. E.g. assume that the
   * list `[1, 2, 3]` exists at `"/list"`; setting the value `5` at `"/list/∗"`
   * will cause `"/list"` to end up with `[5, 5, 5]`.
   *
   * Setting a value on a path with a trailing recursive wildcard is considered
   * equivalent to setting the value on said path without such wildcard. E.g.
   * setting the value at `"/x/∗∗"` is equivalent to setting the same value at
   * `"/x"`.
   * @param path Path of values to set (defaults to `/`).
   * @param toSet Value to set at {@link path}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  set(
    path: Path | string | undefined,
    toSet: unknown,
  ): CancellablePromise<void>;

  /**
   * Resets the values at {@link path} to their initial value.
   *
   * If the path has a trailing non-recursive wildcard, then all existing
   * children of its parent value will have their value reset. E.g. assume that
   * the list `[1, 2, 3]` exists at `"/list"` and that the schema of `"/list/∗"`
   * has an initial value of `0`; resetting `"/list/∗"` will thus cause
   * `"/list"` to end up with `[0, 0, 0]`.
   *
   * Resetting the value on a path with a trailing recursive wildcard is
   * considered equivalent to resetting the value on said path without such
   * wildcard. E.g. resetting the value at `"/x/∗∗"` is equivalent to resetting
   * the value at `"/x"`.
   * @param path Path of values to reset (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  reset(path?: Path | string): CancellablePromise<void>;

  /**
   * Removes the values matching {@link path} from their parent collection(s).
   *
   * It is possible to clear a collection by providing a path with a trailing
   * wildcard.
   *
   * Removing the value on a path with a trailing recursive wildcard is
   * considered equivalent to removing the value on said path without such
   * wildcard. E.g. removing the value at `"/x/∗∗"` is equivalent to removing
   * the value at `"/x"`.
   * @param path Path of values to remove.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths,
   * when attempting to remove the root value, or when a parent of {@link path}
   * is not a collection.
   */
  remove(path: Path | string): CancellablePromise<void>;

  /**
   * Runs {@link externalContextHandler} with the external context named
   * {@link externalContextName} currently available to validations.
   *
   * This method receives a callback to ensure that no conflicting concurrent
   * operations occur during the lifetime of said callback.
   * @param externalContextName Name of the external context to get.
   * @param externalContextHandler Function called with the external context
   * named {@link externalContextName} currently available to validations.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the result of {@link externalContextHandler}.
   */
  getExternalContext<T = unknown, TResult = unknown>(
    externalContextName: string,
    externalContextHandler: (
      externalContext: T,
    ) => TResult | PromiseLike<TResult>,
  ): CancellablePromise<TResult>;

  /**
   * Sets an [external context]{@link externalContext} with name
   * {@link externalContextName} to be available to validations and returns the
   * previous external context associated with the same name if one existed.
   * @param externalContextName Name of the external context to set.
   * @param externalContext Value of the external context to set.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the previous external context associated with
   * {@link externalContextName} if one existed.
   */
  setExternalContext<T = unknown>(
    externalContextName: string,
    externalContext: T,
  ): CancellablePromise<T | null>;

  /**
   * Removes the external context with name {@link externalContextName}
   * available to validations and returns it if it existed.
   * @param externalContextName Name of the external context to remove.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the removed external context associated with
   * {@link externalContextName} if it existed.
   */
  removeExternalContext<T = unknown>(
    externalContextName: string,
  ): CancellablePromise<T | null>;

  /**
   * Validates all values at paths matching {@link path} by running a function
   * {@link issuesHandler} with an async interable over all found
   * [validation issues]{@link LocatedValidationIssue}. Returns the result of
   * {@link issuesHandler}.
   *
   * This method receives a callback to ensure that no conflicting concurrent
   * operations occur during the lifetime of said callback.
   * @param path Path of values to validate (defaults to `/**`).
   * @param issuesHandler Function that receives an async iterable over all
   * found [validation issues]{@link LocatedValidationIssue} at {@link path}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the result of {@link issuesHandler}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  validate<T = unknown>(
    path: Path | string | undefined,
    issuesHandler: (
      issuesIterable: AsyncIterable<SealedLocatedValidationIssue>,
    ) => T | PromiseLike<T>,
  ): CancellablePromise<T>;
  /**
   * Validates all values at paths matching {@link path}. Returns the list of
   * all found [validation issues]{@link LocatedValidationIssue}.
   * @param path Path of values to validate (defaults to `/**`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the list all found [validation issues]{@link LocatedValidationIssue}.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  validate(
    path?: Path | string,
  ): CancellablePromise<SealedLocatedValidationIssue[]>;

  /**
   * Returns whether the values at paths matching {@link path} are valid
   * according to their schemas.
   *
   * Values are said to be valid if they contain no validation errors.
   * @param path Path of values to check if valid (defaults to `/**`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether all values at {@link path} are valid.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  isValid(path?: Path | string): CancellablePromise<boolean>;

  /**
   * Adds external issues to the form manager. Once added, each issue can be
   * removed either manually via {@link removeExternalIssues} or automatically
   * when the value referenced by the issue or one of the values referenced by
   * the issue's dependencies change.
   * @param issues External issues to add to the form manager.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If any of the issue's paths or dependencies
   * match no schema paths.
   */
  addExternalIssues(
    issues:
      | (SealedLocatedValidationIssue | LocatedValidationIssueKt)[]
      | KtList<SealedLocatedValidationIssue | LocatedValidationIssueKt>,
  ): CancellablePromise<void>;

  /**
   * Removes all external issues currently added to the form manager with paths
   * matching {@link path}. If a {@link code} is provided, only the issues with
   * the provided code are removed.
   * @param path Path of values with external issues to remove.
   * @param code Code of issues to remove.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws InvalidPathException If [path] matches no schema paths.
   */
  removeExternalIssues(
    path?: Path | string,
    code?: string | null,
  ): CancellablePromise<void>;

  /**
   * Returns whether at least one value at a path matching {@link path} is
   * dirty.
   * @param path Path of values to check if dirty (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether at least one value at a path matching {@link path} is
   * dirty.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  isDirty(path?: Path | string): CancellablePromise<boolean>;

  /**
   * Returns whether all values at a path matching {@link path} are pristine
   * (i.e. are not dirty).
   * @param path Path of values to check if pristine (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether all values at a path matching {@link path} are pristine.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  isPristine(path?: Path | string): CancellablePromise<boolean>;

  /**
   * Sets all values at a path matching {@link path} as dirty, as well as their
   * parents.
   * @param path Path of values to set as dirty (defaults to `/**`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  setDirty(path?: Path | string): CancellablePromise<void>;

  /**
   * Sets all values at a path matching {@link path} as pristine (i.e. as not
   * dirty), as well as their descendents.
   * @param path Path of values to set as pristine (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  setPristine(path?: Path | string): CancellablePromise<void>;

  /**
   * Returns whether at least one value at a path matching {@link path} has been
   * touched.
   * @param path Path of values to check if touched (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether at least one value at a path matching {@link path} has been
   * touched.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  isTouched(path?: Path | string): CancellablePromise<boolean>;

  /**
   * Returns whether all values at a path matching {@link path} are untouched
   * (i.e. are not touched).
   * @param path Path of values to check if untouched (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with whether all values at a path matching {@link path} are untouched.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  isUntouched(path?: Path | string): CancellablePromise<boolean>;

  /**
   * Sets all values at a path matching {@link path} as touched, as well as
   * their parents.
   * @param path Path of values to set as touched (defaults to `/**`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  setTouched(path?: Path | string): CancellablePromise<void>;

  /**
   * Sets all values at a path matching {@link path} as untouched (i.e. as not
   * touched), as well as their descendents.
   * @param path Path of values to set as untouched (defaults to `/`).
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the operation completes.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  setUntouched(path?: Path | string): CancellablePromise<void>;

  /**
   * Subscribes to all events with paths matching {@link path} by running
   * {@link eventHandler} for each event. Returns a function that should be
   * called to unsubscribe from the subscription. Note that the subscription
   * itself is asynchronous.
   *
   * An {@link onSubscription} function may be provided, which is guaranteed to
   * run after the subscription has completed but before any events are emitted
   * to the {@link eventHandler}.
   *
   * All subscriptions are automatically cancelled when the form manager is
   * [destroyed]{@link destroy}.
   * @param path Path of events to subscribe to (defaults to `/**`).
   * @param eventHandler Function called whenever an event occurs at a path
   * matching {@link path}. It receives the event in question as argument.
   * @param onSubscription Function called after the subscription completes, but
   * before any event are emitted to {@link eventHandler}.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * once the subscription has been registered with another
   * [cancellable promise]{@link CancellablePromise} that can be used to
   * unsubscribe from new event notifications.
   * @throws {InvalidPathException} If {@link path} matches no schema paths.
   */
  subscribe<T = unknown, TChildren = unknown>(
    path: Path | string | undefined,
    eventHandler: (
      event: SealedFormManagerEvent<T, TChildren>,
    ) => void | PromiseLike<void>,
    onSubscription?: () => void | PromiseLike<void>,
  ): CancellablePromise<() => CancellablePromise<void>>;
}

// Form util ===================================================================

/**
 * Validates that the provided {@link path} points to a schema of
 * {@link formSchema}.
 * @param formSchema Schema of the form.
 * @param path Path to validate against {@link formSchema}.
 * @throws {InvalidPathException} If the {@link path} is invalid.
 */
export function validatePath(
  formSchema: Schema | SchemaKt,
  path: Path | string,
): void;

/**
 * Validates all validations of the provided {@link formSchema} by checking that
 * all validation dependencies are valid (i.e. that they point to valid
 * locations and have valid types).
 * @param formSchema Schema of the form.
 * @throws {InvalidDependencyPathException} If a validation has an invalid
 * dependency path.
 * @throws {InvalidDependencyTypeException} If a validation has an invalid
 * dependency type.
 */
export function validateSchemaValidations(formSchema: Schema | SchemaKt): void;

/**
 * Validates the provided [external validations]{@link externalValidations} in
 * the context of the given {@link formSchema} by checking that all validation
 * dependencies are valid (i.e. that they point to valid locations and have
 * valid types).
 * @param formSchema Schema of the form.
 * @param externalValidations External validations to validate.
 * @throws {InvalidPathException} If an external validation path is invalid.
 * @throws {InvalidDependencyPathException} If a validation has an invalid
 * dependency path.
 * @throws {InvalidDependencyTypeException} If a validation has an invalid
 * dependency type.
 */
export function validateExternalValidations(
  formSchema: Schema | SchemaKt,
  externalValidations: Record<string, Validation[]>,
): void;

/**
 * Returns whether there exists at least one schema within {@link formSchema}
 * matching {@link path}.
 *
 * Paths that match no schemas are deemed invalid, and most functions called
 * with them will throw.
 * @param formSchema Schema of the form.
 * @param path Path to check if valid.
 * @returns Whether {@link path} is valid according to {@link formSchema}.
 */
export function isValidPath(
  formSchema: Schema | SchemaKt,
  path: Path | string,
): boolean;

/**
 * Returns a sequence of information about the schemas within {@link formSchema}
 * matching {@link path}.
 * @param formSchema Schema of the form.
 * @param path Path matching path of schemas from which to get information
 * (defaults to `/**`).
 * @returns Iterable over schema-information of schemas at paths mathing
 * {@link path}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function schemaInfo<T = unknown>(
  formSchema: Schema | SchemaKt,
  path?: Path | string,
): Iterable<SchemaInfo<T>>;

/**
 * Returns the single schema within {@link formSchema} matching {@link path}.
 *
 * To get information about all schemas matching a path use {@link schemaInfo}
 * instead.
 * @param formSchema Schema of the form.
 * @param path Path of the schema to get.
 * @returns Schema at {@link path}.
 * @throws {InvalidPathException} If {@link path} matches no schemas or more
 * than one schema.
 */
export function schema<T = unknown>(
  formSchema: Schema | SchemaKt,
  path: Path | string,
): Schema<T>;

/**
 * Returns information about the parts of the form value {@link formValue}
 * (with schema {@link formSchema}) matching {@link path}.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path matching path of values from which to get information
 * (defaults to `/**`).
 * @returns An async iterable over the information about the parts of the form
 * value {@link formValue} matching {@link path}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function valueInfo<T = unknown, TInfo = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path?: Path | string,
): AsyncIterable<ValueInfo<TInfo>>;

/**
 * Returns whether there exists a part of the form value {@link formValue} (with
 * schema {@link formSchema}) matching {@link path}.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path to check.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * with whether there exists at least one value at a path matching {@link path}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function has<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
): CancellablePromise<boolean>;

/**
 * Returns the single part of the form value {@link formValue} (with schema
 * {@link formSchema}) matching {@link path}.
 *
 * To get information about multiple parts of a form value at once, use
 * {@link valueInfo} instead.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of the value to get.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * with the single part of the form value {@link formValue} matching
 * {@link path}.
 * @throws {InvalidPathException} If {@link path} contains wildcards or matches
 * no schemas.
 * @throws {IllegalStateException} If {@link path} matches more than one value.
 * @throws {NoSuchElementException} If no part of {@link formValue} matches
 * {@link path}.
 */
export function get<T = unknown, TValue = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
): CancellablePromise<TValue>;

/**
 * Returns a clone (deep copy) of the single part of the form value
 * {@link formValue} (with schema {@link formSchema}) matching {@link path}.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of the value to get.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * with a clone of the value at {@link path}.
 * @throws {InvalidPathException} If {@link path} contains wildcards or matches
 * no schemas.
 * @throws {IllegalStateException} If {@link path} matches more than one value.
 * @throws {NoSuchElementException} If no part of {@link formValue} matches
 * {@link path}.
 */
export function getClone<T = unknown, TValue = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
): CancellablePromise<TValue>;

/**
 * Sets values at {@link path} that are part of the form value {@link formValue}
 * (with schema {@link formSchema}) with {@link toSet}.
 *
 * If the path has a trailing non-recursive wildcard, then all existing
 * children of its parent value are set to {@link toSet}. E.g. assume that the
 * list `[1, 2, 3]` exists at `"/list"`; setting the value `5` at `"/list/∗"`
 * will cause `"/list"` to end up with `[5, 5, 5]`.
 *
 * Setting a value on a path with a trailing recursive wildcard is considered
 * equivalent to setting the value on said path without such wildcard. E.g.
 * setting the value at `"/x/∗∗"` is equivalent to setting the same value at
 * `"/x"`.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to set (defaults to `/`).
 * @param toSet Value to set at {@link path}.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * once the operation completes.
 * @throws {InvalidPathException} If {@link path} matches no schema paths, or
 * when attempting to set the root value.
 */
export function set<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
  toSet: unknown,
): CancellablePromise<void>;

/**
 * Resets the values at {@link path} that are part of the form value
 * {@link formValue} (with schema {@link formSchema}) to their initial value.
 *
 * If the path has a trailing non-recursive wildcard, then all existing
 * children of its parent value will have their value reset. E.g. assume that
 * the list `[1, 2, 3]` exists at `"/list"` and that the schema of `"/list/∗"`
 * has an initial value of `0`; resetting `"/list/∗"` will thus cause
 * `"/list"` to end up with `[0, 0, 0]`.
 *
 * Resetting the value on a path with a trailing recursive wildcard is
 * considered equivalent to resetting the value on said path without such
 * wildcard. E.g. resetting the value at `"/x/∗∗"` is equivalent to resetting
 * the value at `"/x"`.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to reset.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * once the operation completes.
 * @throws {InvalidPathException} If {@link path} matches no schema paths, or
 * when attempting to reset the root value.
 */
export function reset<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
): CancellablePromise<void>;

/**
 * Removes the values matching {@link path} that are part of the form value
 * {@link formValue} (with schema {@link formSchema}) from their parent
 * collection(s).
 *
 * It is possible to clear a collection by providing a path with a trailing
 * wildcard.
 *
 * Removing the value on a path with a trailing recursive wildcard is
 * considered equivalent to removing the value on said path without such
 * wildcard. E.g. removing the value at `"/x/∗∗"` is equivalent to removing
 * the value at `"/x"`.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to remove.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * once the operation completes.
 * @throws {InvalidPathException} If {@link path} matches no schema paths,
 * when attempting to remove the root value, or when a parent of {@link path}
 * is not a collection.
 */
export function remove<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
): CancellablePromise<void>;

/**
 * Validates the parts of the form value {@link formValue} matching {@link path}
 * against {@link formSchema}. Returns an async iterable over all found
 * [validation issues]{@link LocatedValidationIssue}.
 *
 * A map of external contexts may be provided for validations that depend on
 * them.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to validate (defaults to `/**`).
 * @param externalContexts External contexts used by validations.
 * @returns Async iterable over all found
 * [validation issues]{@link LocatedValidationIssue}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function validate<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
  externalContexts?: Record<string, unknown>,
): AsyncIterable<LocatedValidationIssue>;
export function validate<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  externalContexts?: Record<string, unknown>,
): AsyncIterable<LocatedValidationIssue>;

/**
 * Validates the parts of the form value {@link formValue} matching {@link path}
 * with schema {@link formSchema} against the provided
 * [external validations]{@link externalValidations}. Returns an async iterable
 * over all found [validation issues]{@link LocatedValidationIssue}.
 *
 * A map of external contexts may be provided for validations that depend on
 * them.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to validate (defaults to `/**`).
 * @param externalValidations External validations to validate the form value
 * against.
 * @param externalContexts External contexts used by validations.
 * @returns Async iterable over all found
 * [validation issues]{@link LocatedValidationIssue}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function validateExternally<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
  externalValidations: Record<string, Validation[]>,
  externalContexts?: Record<string, unknown>,
): AsyncIterable<LocatedValidationIssue>;
export function validateExternally<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  externalValidations: Record<string, Validation[]>,
  externalContexts?: Record<string, unknown>,
): AsyncIterable<LocatedValidationIssue>;

/**
 * Returns whether the parts of the form value {@link formValue} (with schema
 * {@link formSchema}) matching {@link path} are valid according to their
 * schemas. These parts are said to be valid if they contain no validation
 * errors.
 *
 * A map of external contexts may be provided for validations that depend on
 * them.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to check if valid (defaults to `/**`).
 * @param externalContexts External contexts used by validations.
 * @returns A [cancellable promise]{@link CancellablePromise} that resolves
 * with whether all values at {@link path} are valid.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function isValid<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path?: Path | string,
  externalContexts?: Record<string, unknown>,
): CancellablePromise<boolean>;
export function isValid<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  externalContexts?: Record<string, unknown>,
): CancellablePromise<boolean>;

/**
 * Returns whether the parts of the form value {@link formValue} (with schema
 * {@link formSchema}) matching {@link path} are valid according to the provided
 * [external validations]{@link externalValidations}. These parts are said to be
 * valid if they contain no validation errors.
 *
 * A map of external contexts may be provided for validations that depend on
 * them.
 * @param formSchema Schema of the form.
 * @param formValue Value of the form.
 * @param path Path of values to validate (defaults to `/**`).
 * @param externalValidations External validations to validate the form value
 * against.
 * @param externalContexts External contexts used by validations.
 * @returns Async iterable over all found
 * [validation issues]{@link LocatedValidationIssue}.
 * @throws {InvalidPathException} If {@link path} matches no schemas.
 */
export function isValidExternally<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  path: Path | string,
  externalValidations: Record<string, Validation[]>,
  externalContexts?: Record<string, unknown>,
): CancellablePromise<boolean>;
export function isValidExternally<T = unknown>(
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
  externalValidations: Record<string, Validation[]>,
  externalContexts?: Record<string, unknown>,
): CancellablePromise<boolean>;

// Cancellable promise =========================================================

/**
 * A [promise-like]{@link PromiseLike} object that represents the eventual
 * completion (or failure) of an asynchronous cancellable operation and its
 * resulting value.
 *
 * It differs from a regular {@link Promise} in that it exposes a {@link cancel}
 * method that, when called, possibly cancels the asynchronous operation. When
 * cancelled, the promise will fail with a {@link PromiseCancellationException}.
 */
export declare class CancellablePromise<T> implements PromiseLike<T> {
  private constructor();

  then<TResult1 = T, TResult2 = never>(
    onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
    onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
  ): CancellablePromise<TResult1 | TResult2>;

  catch<TResult = never>(
    onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null,
  ): CancellablePromise<T | TResult>;

  finally(onFinally?: (() => void) | null): CancellablePromise<T>;

  /**
   * Method used to (possibly) cancel an ongoing asynchronous operation.
   * @param causeMessage Reason for the cancellation.
   */
  cancel(causeMessage?: string): void;
}

/**
 * Exception emitted when a {@link CancellablePromise} has been successfully
 * cancelled.
 */
export declare class PromiseCancellationException {
  constructor(message?: string);

  get message(): string;
}

// Schemas =====================================================================

/**
 * Type of value represented by a schema.
 */
export declare class TypeInfo {
  private constructor();

  /**
   * Name of the type.
   */
  get name(): string;

  /**
   * Whether the type is nullable.
   */
  get nullable(): boolean;

  /**
   * Type arguments.
   */
  get arguments(): TypeInfo[];

  /**
   * Type and validation related "simple" restrictions, e.g. ("required", "min",
   * "max", etc.).
   */
  get restrictions(): Record<string, unknown>;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

/**
 * Kotlin representation of a [schema]{@link Schema}.
 */
export declare abstract class SchemaKt {}

/**
 * Schema representing metadata on values of type `T`.
 *
 * The schema of a form is responsible for specifying which validations to run
 * on it, as well as how to "manage" the form data. If a certain form contains a
 * field of, for example, type `number`, then there should be a schema of type
 * `Schema<number>` that holds the metadata required for knowing how to, for
 * example, initialise said field and validate it.
 *
 * The [form manager]{@link FormManager} uses schemas extensively to, amongst
 * others, initialise data, set data, and validate data; the schema is
 * responsible for specifying **how** each different type of data is initialised
 * or set.
 */
export declare abstract class Schema<T = unknown> {
  private constructor();

  /**
   * Information about the type of value represented by this schema.
   */
  get typeInfo(): TypeInfo;

  /**
   * List of validations used to validate this schema.
   */
  get validations(): Validation<T>[];

  /**
   * Initial value for a value of this schema.
   *
   * New values of this schema will hold this value by default. Moreover, when a
   * value of this schema is [reset]{@link FormManager.reset} by the
   * [form manager]{@link FormManager}, it is set to this value.
   */
  get initialValue(): T;

  /**
   * Returns a clone (deep copy) of {@link value}.
   * @param value Value to clone.
   * @returns A [cancellable promise]{@link CancellablePromise} that resolves
   * with the cloned value.
   */
  clone(value: T): CancellablePromise<T>;
}

/**
 * Schema representing metadata on parent values of type `T`.
 *
 * "Parent" values, in this context, simply means values with children (children
 * themselves also represented by their own schemas).
 */
export declare abstract class ParentSchema<T = unknown> extends Schema<T> {
  private constructor();
}

/**
 * Schema representing metadata on collections of type `T`.
 *
 * "Collections", in this context, simply means data structures that hold
 * children of the same type and that support the addition and removal of
 * values.
 */
export declare abstract class CollectionSchema<
  T = unknown,
> extends ParentSchema<T> {
  private constructor();
}

// Schema constructor functions:

export interface SchemaOptions<T = unknown> {
  validations?: Validation<T>[];
  initialValue?: T;
}

export declare function arraySchema<T = unknown>(
  options: SchemaOptions<T[]>,
  elementsSchema: Schema<T>,
): CollectionSchema<T[]>;
export declare function arraySchema<T = unknown>(
  elementsSchema: Schema<T>,
): CollectionSchema<T[]>;

export declare function booleanSchema(
  options?: SchemaOptions<boolean>,
): Schema<boolean>;

export declare function dateSchema(options?: SchemaOptions<Date>): Schema<Date>;

export declare function fileSchema(options?: SchemaOptions<File>): Schema<File>;

export declare function nullableSchema<T = unknown>(
  options: SchemaOptions<T | null>,
  childSchema: CollectionSchema<T>,
): CollectionSchema<T | null>;
export declare function nullableSchema<T = unknown>(
  options: SchemaOptions<T | null>,
  childSchema: ParentSchema<T>,
): ParentSchema<T | null>;
export declare function nullableSchema<T = unknown>(
  options: SchemaOptions<T | null>,
  childSchema: Schema<T>,
): Schema<T | null>;
export declare function nullableSchema<T = unknown>(
  childSchema: CollectionSchema<T>,
): CollectionSchema<T | null>;
export declare function nullableSchema<T = unknown>(
  childSchema: ParentSchema<T>,
): ParentSchema<T | null>;
export declare function nullableSchema<T = unknown>(
  childSchema: Schema<T>,
): Schema<T | null>;

export declare function numberSchema(
  options?: SchemaOptions<number>,
): Schema<number>;
export declare function bigIntegerSchema(
  options?: SchemaOptions<BigInteger>,
): Schema<BigInteger>;
export declare function bigDecimalSchema(
  options?: SchemaOptions<BigDecimal>,
): Schema<BigDecimal>;

export declare function objectSchema<
  T extends Record<keyof T, unknown> = Record<string, unknown>,
  TSchema extends { [TKey in keyof T]: Schema<T[TKey]> } = {
    [TKey in keyof T]: Schema<T[TKey]>;
  },
>(options: SchemaOptions<T>, fieldsSchemas: TSchema): ParentSchema<T>;
export declare function objectSchema<
  T extends Record<keyof T, unknown> = Record<string, unknown>,
  TSchema extends { [TKey in keyof T]: Schema<T[TKey]> } = {
    [TKey in keyof T]: Schema<T[TKey]>;
  },
>(fieldsSchemas: TSchema): ParentSchema<T>;

export declare function stringSchema(
  options?: SchemaOptions<string>,
): Schema<string>;

export declare function tableSchema<T = unknown>(
  options: SchemaOptions<Table<T>>,
  elementsSchema: Schema<T>,
): CollectionSchema<Table<T>>;
export declare function tableSchema<T = unknown>(
  elementsSchema: Schema<T>,
): CollectionSchema<Table<T>>;

// Paths =======================================================================

/**
 * Possible path fragments.
 */
export type SealedPathFragment =
  | typeof PathFragment.Root
  | typeof PathFragment.CurrentPath
  | typeof PathFragment.ParentPath
  | SealedAbsolutePathFragment;

/**
 * Fragment of a path.
 */
export declare abstract class PathFragment {
  protected constructor();

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  /**
   * Path fragment representing the root path.
   */
  static get Root(): PathFragment & { toString(): "Root" };

  /**
   * Path fragment representing the current path (`"."` in string notation).
   */
  static get CurrentPath(): PathFragment & { toString(): "CurrentPath" };

  /**
   * Path fragment representing the parent path (`".."` in string notation).
   */
  static get ParentPath(): PathFragment & { toString(): "ParentPath" };
}

/**
 * Possible absolute path fragments.
 */
export type SealedAbsolutePathFragment =
  | AbsolutePathFragment.Id
  | typeof AbsolutePathFragment.CollectionEnd
  | typeof AbsolutePathFragment.Wildcard
  | typeof AbsolutePathFragment.RecursiveWildcard;

/**
 * Fragment of an absolute path.
 */
export declare abstract class AbsolutePathFragment extends PathFragment {
  protected constructor();

  /**
   * Path fragment representing the "end" of a collection (`"-"` in string
   * notation).
   *
   * This fragment represents the fictional element after the last element of a
   * collection.
   */
  static get CollectionEnd(): AbsolutePathFragment & {
    toString(): "CollectionEnd";
  };

  /**
   * Wildcard fragment (`"*"` in string notation).
   *
   * Wildcard fragments match against any other fragments.
   */
  static get Wildcard(): AbsolutePathFragment & { toString(): "Wildcard" };

  /**
   * Recursive wildcard fragment (`"**"` in string notation).
   *
   * Recursive wildcard fragments match against zero or more any other fragments.
   */
  static get RecursiveWildcard(): AbsolutePathFragment & {
    toString(): "RecursiveWildcard";
  };
}

export declare namespace AbsolutePathFragment {
  /**
   * Path fragment representing an identifier. In string notation, the id
   * fragment `new AbsolutePathFragment.Id("x")` would be represented as `x`; if
   * the string version of the fragment conflicts with a different fragment,
   * then the fragment is escaped, e.g. the id fragment declared as
   * `new AbsolutePathFragment.Id("*")` would be represented as `~*` in string
   * notation.
   */
  class Id extends AbsolutePathFragment {
    constructor(id: NonNullable<unknown>);

    /**
     * Path fragment identifier.
     */
    get id(): string;
  }
}

/**
 * Representation of a path as a list of path fragments.
 *
 * Paths represent locations of data, possibly relatively to other locations:
 * e.g. the location of a value relative to the location of another value. They
 * can also represent locations of data from the root when they contain a root
 * fragment.
 */
export declare class Path {
  constructor(path?: Path | string | SealedPathFragment[]);

  /**
   * List of fragments representing this path.
   */
  get fragments(): SealedPathFragment[];

  /**
   * Returns the fragment of this path with index {@link index}.
   * @param index Index of fragment to get.
   * @throws {IndexOutOfBoundsException} When an out of bounds {@link index} is
   * provided.
   * @returns Fragment of this path with index {@link index}.
   */
  fragment(index: number): SealedPathFragment;

  /**
   * Returns a new path representing the parent of this path.
   *
   * Note that the parent of the root path is the root path itself.
   * @returns New path representing the parent of this path.
   */
  parent(): Path;

  /**
   * Returns the path resulting from appending {@link fragments} to this path.
   * @param fragments Fragments to append to this path.
   * @returns Path resulting from appending {@link fragments} to this path.
   */
  append(...fragments: SealedPathFragment[]): Path;

  /**
   * Returns the path resulting from joining {@link paths} together with this
   * path.
   * @param paths Paths to join with this path.
   * @returns Path resulting from joining {@link paths} together with this path.
   */
  join(...paths: (Path | string)[]): Path;

  /**
   * Returns the path resulting from resolving a list of {@link paths} against
   * this path.
   * @param paths Paths to resolve against this path.
   * @returns Path resulting from resolving {@link paths} against this path.
   */
  resolve(...paths: (Path | string)[]): Path;

  /**
   * Returns whether this path equals {@link other}.
   *
   * Two paths are equal when they both resolve to paths with the exact same
   * fragments.
   * @param other Value to compare against.
   * @returns Whether {@link other} is considered equal to this path.
   */
  equals(other: unknown): boolean;

  hashCode(): number;

  /**
   * String representation of this path.
   * @returns The string representation of this path.
   */
  toString(): string;

  /**
   * Path representing the current path (`"."`).
   */
  static get CURRENT(): Path;

  /**
   * Path representing the current path and all of its descendants (`"./∗∗"`).
   */
  static get CURRENT_DEEP(): Path;

  /**
   * Path representing the parent path (`".."`).
   */
  static get PARENT(): Path;

  /**
   * Path representing the children of a path (`"./∗"`).
   */
  static get CHILDREN(): Path;

  /**
   * Path representing the descendants of a path (`"./∗/∗∗"`).
   */
  static get DESCENDANTS(): Path;
}

/**
 * Representation of an absolute path as a subtype of {@link Path} and as a list
 * of absolute path fragments. Absolute paths are always "resolved" (i.e. they
 * contain no unnecessary fragments such as current path fragments or
 * consecutive recursive wildcard fragments).
 *
 * Absolute paths represent locations of data from a root location: e.g. the
 * location of a value within a value where the outer value is seen as the
 * "root" value.
 *
 * Unlike regular paths, the root fragment is always implicit in absolute paths
 * and is not visible in the list of fragments.
 */
export declare class AbsolutePath extends Path {
  constructor(path?: Path | string | SealedAbsolutePathFragment[]);

  /**
   * List of fragments representing this path.
   */
  get fragments(): SealedAbsolutePathFragment[];

  /**
   * Size of the path (number of fragments it has).
   */
  get size(): number;

  /**
   * Whether this path represents the root path.
   */
  get isRoot(): boolean;

  /**
   * Last fragment of this path or `null` for the root path.
   */
  get lastFragment(): SealedAbsolutePathFragment | null;

  /**
   * Returns the fragment of this path with index {@link index}.
   * @param index Index of fragment to get.
   * @throws {IndexOutOfBoundsException} When an out of bounds {@link index} is
   * provided.
   * @returns Fragment of this path with index {@link index}.
   */
  fragment(index: number): SealedAbsolutePathFragment;

  /**
   * Returns whether this path has at least one non-recursive wildcard.
   * @returns Whether this path has at least one non-recursive wildcard.
   */
  hasWildcard(): boolean;

  /**
   * Returns whether this path has at least one recursive wildcard.
   * @returns Whether this path has at least one recursive wildcard.
   */
  hasRecursiveWildcard(): boolean;

  /**
   * Returns whether this path has at least one wildcard (either recursive or
   * not).
   * @returns Whether this path has at least one wildcard (either recursive or
   * not).
   */
  hasAnyWildcard(): boolean;

  /**
   * Returns an absolute path representing the parent of this path. Equivalent to
   * `resolve("..")`.
   *
   * Note that the parent of the root path is the root path itself.
   * @returns Absolute path representing the parent of this path.
   */
  parent(): AbsolutePath;

  /**
   * Returns the absolute path resulting from appending {@link fragments} to
   * this path.
   * @param fragments Fragments to append to this path.
   * @returns Absolute path resulting from appending {@link fragments} to this
   * path.
   */
  append(...fragments: SealedAbsolutePathFragment[]): AbsolutePath;
  /**
   * Returns the path resulting from appending {@link fragments} to this path.
   * @param fragments Fragments to append to this path.
   * @returns Path resulting from appending {@link fragments} to this path.
   */
  append(...fragments: SealedAbsolutePathFragment[]): Path;

  /**
   * Returns the absolute path resulting from resolving a list of {@link paths}
   * against this path.
   * @param paths Paths to resolve against this path.
   * @returns Absolute path resulting from resolving {@link paths} against this
   * path.
   */
  resolve(...paths: (Path | string)[]): AbsolutePath;

  /**
   * Returns whether this path matches with {@link path}. Note that {@link path}
   * will be converted to an [absolute path]{@link AbsolutePath} when it isn't
   * one.
   *
   * For the purpose of matching, a
   * [wildcard fragment]{@link AbsolutePathFragment.Wildcard}
   * matches against any other fragment and a
   * [recursive wildcard fragment]{@link AbsolutePathFragment.RecursiveWildcard}
   * matches against zero or more any other fragments. Non-wildcard fragments
   * match against each other on a basis of equality.
   * @param path Path to check if this path matches with.
   * @returns Whether this path matches with {@link path}.
   */
  matches(path: Path | string): boolean;

  /**
   * Returns whether this path contains {@link path}. Note that {@link path}
   * will be converted to an [absolute path]{@link AbsolutePath} when it isn't
   * one.
   *
   * We say that a path `p1` contains a path `p2` when all paths that
   * [match]{@link matches} against `p2` also [match]{@link matches} against
   * `p1`. I.e. `p1.contains(p2) === true` iff there does **not** exist a path
   * `p3` such that `p3.matches(p2) === true` and `p3.matches(p1) === false`.
   * @param path Path to check if contained by this path.
   * @returns Whether this path contains {@link path}.
   */
  contains(path: Path | string): boolean;

  /**
   * Returns a relative path representing this path, but relative to
   * {@link path}. Note that {@link path} will be converted to an
   * [absolute path]{@link AbsolutePath} when it isn't one.
   *
   * In other words, if `relPath1 = path1.relativeTo(path2)`, then
   * `path2.resolve(relPath1).equals(path1) === true`.
   * @param path Path from which to create a relative path.
   * @returns Relative path representing this path, but relative to
   * {@link path}.
   */
  relativeTo(path: Path | string): Path;

  /**
   * Absolute root path (`"/"`).
   */
  static get ROOT(): AbsolutePath;

  /**
   * Absolute path that matches all other paths (`"/∗∗"`).
   */
  static get MATCH_ALL(): AbsolutePath;
}

// Validations =================================================================

export declare class ValidationContext<
  T = unknown,
  TDependencyKey extends string = string,
  TContextName extends string = string,
> {
  private constructor();

  get schema(): Schema<T>;

  get value(): T;

  dependencyInfoOrNull<TDependency = unknown>(
    dependencyKey: TDependencyKey,
  ): ValueInfo<TDependency> | null;

  dependencyInfo<TDependency = unknown>(
    dependencyKey: TDependencyKey,
  ): ValueInfo<TDependency>;

  dependencyPathOrNull(dependencyKey: TDependencyKey): AbsolutePath | null;

  dependencyPath(dependencyKey: TDependencyKey): AbsolutePath;

  dependencySchemaOrNull<TDependency = unknown>(
    dependencyKey: TDependencyKey,
  ): Schema<TDependency> | null;

  dependencySchema<TDependency = unknown>(
    dependencyKey: TDependencyKey,
  ): Schema<TDependency>;

  dependencyOrNull<TDependency = unknown>(
    dependencyKey: TDependencyKey,
  ): TDependency | null;

  dependency<TDependency = unknown>(dependencyKey: TDependencyKey): TDependency;

  externalContextOrNull<TContext = unknown>(
    externalContextName: TContextName,
  ): TContext | null;

  externalContext<TContext = unknown>(
    externalContextName: TContextName,
  ): TContext;
}

export interface ValidationOptions<
  TDependencyKey extends string = string,
  TContextName extends string = string,
> {
  name?: string;
  dependencies?: Record<TDependencyKey, Path | string>;
  dependsOnDescendants?: boolean;
  externalContextDependencies?: readonly TContextName[];
}

export type ValidationFunction<
  T = unknown,
  TDependencyKey extends string = string,
  TContextName extends string = string,
> = (
  context: ValidationContext<T, TDependencyKey, TContextName>,
) =>
  | SealedValidationIssue[]
  | PromiseLike<SealedValidationIssue[]>
  | Iterator<SealedValidationIssue>
  | AsyncIterator<SealedValidationIssue>;

export declare class Validation<
  T = unknown,
  TDependencyKey extends string = string,
  TContextName extends string = string,
> {
  constructor(
    validationOptions: ValidationOptions<TDependencyKey, TContextName>,
    validate: ValidationFunction<T, TDependencyKey, TContextName>,
  );
  constructor(validate: ValidationFunction<T, never, never>);

  get dependencies(): Record<string, Path>;

  get dependsOnDescendants(): boolean;

  get externalContextDependencies(): string[];

  toString(): string;
}

// Missing values:
export declare function required<T = unknown>(
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function notEmpty<T extends string | unknown[] | Table>(
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function notBlank(
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<string>;

// Allowed values:
export declare function mustEqual<T = unknown>(
  requiredValue: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function mustNotEqual<T = unknown>(
  forbiddenValue: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function oneOf<T = unknown>(
  allowedValues: readonly T[],
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function notOneOf<T = unknown>(
  disallowedValues: readonly T[],
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

// Accepted files:
export declare function accepts(
  accepts: readonly string[],
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<File>;

// Size bounds:
export declare function size<T = unknown>(
  requiredSize: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T[]>;

export declare function minSize<T = unknown>(
  minSize: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T[]>;

export declare function maxSize<T = unknown>(
  maxSize: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T[]>;

// Comparable bounds:
export declare function min<T = unknown>(
  min: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function max<T = unknown>(
  max: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function exclusiveMin<T = unknown>(
  exclusiveMin: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

export declare function exclusiveMax<T = unknown>(
  exclusiveMax: T,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T>;

// Length bounds:
export declare function length(
  requiredLength: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<string>;

export declare function minLength(
  minLength: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<string>;

export declare function maxLength(
  maxLength: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<string>;

// Patterns:
export declare function matches(
  regex: RegExp,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<string>;

export declare function matchesEmail(
  code?: string,
  severity?: ValidationIssueSeverity,
  regex?: RegExp,
): Validation<string>;

// Unique items:
export declare function uniqueItemsBy<T = unknown, TKey = unknown>(
  selector: (selector: T) => TKey | null,
  emitAllRepetitions?: boolean,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T[] | Table<T>>;

export declare function uniqueItems<T = unknown>(
  emitAllRepetitions?: boolean,
  treatNullAsUnique?: boolean,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<T[] | Table<T>>;

// Scale:
export declare function scale(
  requiredScale: number,
  code?: string,
  severity?: ValidationIssueSeverity,
): Validation<BigDecimal>;

// Validation issues ===========================================================

export type ValidationIssueData = Record<string, string | null>;

export type ValidationIssueSeverity = "error" | "warning";

export type SealedValidationIssue =
  | ValidationError
  | ValidationWarning
  | ValidationExceptionError;

export declare abstract class ValidationIssue {
  protected constructor();

  get code(): string;

  get data(): ValidationIssueData;

  get severity(): ValidationIssueSeverity;

  contains(issue: SealedValidationIssue): boolean;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

export declare class ValidationError extends ValidationIssue {
  constructor(code: string, data?: ValidationIssueData);

  get severity(): "error";
}

export declare class ValidationWarning extends ValidationIssue {
  constructor(code: string, data?: ValidationIssueData);

  get severity(): "warning";
}

export declare class ValidationExceptionError extends ValidationIssue {
  private constructor();

  get severity(): "error";
}

export type SealedLocatedValidationIssue =
  | LocatedValidationError
  | LocatedValidationWarning
  | LocatedValidationExceptionError;

export declare abstract class LocatedValidationIssue {
  protected constructor();

  get path(): AbsolutePath;

  get code(): string;

  get dependencies(): AbsolutePath[];

  get dependsOnDescendants(): boolean;

  get externalContextDependencies(): string[];

  get data(): ValidationIssueData;

  get severity(): ValidationIssueSeverity;

  contains(issue: SealedLocatedValidationIssue): boolean;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

export interface LocatedValidationIssueOptions {
  dependencies?: (Path | string)[];
  dependsOnDescendants?: boolean;
  externalContextDependencies?: string[];
  data?: ValidationIssueData;
}

export declare class LocatedValidationError extends LocatedValidationIssue {
  constructor(
    path: Path | string,
    code: string,
    options?: LocatedValidationIssueOptions,
  );

  get severity(): "error";
}

export declare class LocatedValidationWarning extends LocatedValidationIssue {
  constructor(
    path: Path | string,
    code: string,
    options?: LocatedValidationIssueOptions,
  );

  get severity(): "warning";
}

export declare class LocatedValidationExceptionError extends LocatedValidationIssue {
  private constructor();

  get severity(): "error";
}

// Info ========================================================================

export declare class SchemaInfo<T = unknown> {
  private constructor();

  get schema(): Schema<T>;

  get path(): AbsolutePath;

  get queriedPath(): AbsolutePath;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

export declare class ValueInfo<T = unknown> {
  private constructor();

  get value(): T;

  get schema(): Schema<T>;

  get path(): AbsolutePath;

  get schemaPath(): AbsolutePath;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

export declare class Info<T = unknown> {
  private constructor();

  get value(): T;

  get schema(): Schema<T>;

  get path(): AbsolutePath;

  get schemaPath(): AbsolutePath;

  get dirty(): boolean;

  get touched(): boolean;

  get issues(): SealedValidationIssue[];

  get validationStatus(): ValidationStatus;

  get displayStatus(): DisplayStatus;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;
}

/**
 * Validation status of a value.
 * - `unvalidated`: Validation status representing that the value hasn't been
 * validated.
 * - `validating`: Validation status representing that the value is currently
 * being validated.
 * - `validated`: Validation status representing that the value has been
 * validated successfully.
 * - `validatedExceptionally`: Validation status representing that the value has
 * been validated, but an exception occurred during the validation.
 */
export type ValidationStatus =
  | "unvalidated"
  | "validating"
  | "validated"
  | "validatedExceptionally";

/**
 * Display status of a value.
 * - `valid`: Display status representing that the value is either
 * "unvalidated", "untouched", or that itself and all of its descendants are
 * valid.
 * - `error`: Display status representing that the value is "touched" and that
 * either itself of one of its descendants has an error.
 * - `warning`: Display status representing that the value is "touched", that
 * either itself of one of its descendants has a warning, and that neither
 * itself nor any of its descendants has an error.
 */
export type DisplayStatus = "valid" | "error" | "warning";

/**
 * Status of the automatic validations.
 * - `inactive`: Automatic validations are inactive
 * ([validation mode]{@link ValidationMode} is set to `"manual"`).
 * - `activeIdle`: Automatic validations are active but idle
 * ([validation mode]{@link ValidationMode} is set to `"auto"` but there is
 * nothing to validate).
 * - `activeRunning`: Automatic validations are active and running
 * ([validation mode]{@link ValidationMode} is set to `"auto"` and values are
 * currently being validated).
 */
export type AutoValidationStatus = "inactive" | "activeIdle" | "activeRunning";

// Events ======================================================================

export type SealedFormManagerEvent<T = unknown, TChildren = unknown> =
  | SealedValueEvent<T, TChildren>
  | SealedStateEvent<T>;

export abstract class FormManagerEvent<T = unknown> {
  protected constructor();

  get path(): AbsolutePath;

  get schema(): Schema<T>;

  toString(): string;
}

export type SealedValueEvent<T = unknown, TChildren = unknown> =
  | ValueEvent.Init<T>
  | ValueEvent.Change<T>
  | ValueEvent.Destroy<T>
  | ValueEvent.Add<T, TChildren>
  | ValueEvent.Remove<T, TChildren>;

export declare abstract class ValueEvent<
  T = unknown,
> extends FormManagerEvent<T> {
  protected constructor();

  get value(): T | undefined;

  get oldValue(): T | undefined;

  get path(): AbsolutePath;

  get schema(): Schema<T>;

  toString(): string;
}

export declare namespace ValueEvent {
  class Init<T = unknown> extends ValueEvent<T> {
    private constructor();

    get value(): T;

    get oldValue(): undefined;
  }

  class Change<T = unknown> extends ValueEvent<T> {
    private constructor();

    get value(): T;

    get oldValue(): T;
  }

  class Destroy<T = unknown> extends ValueEvent<T> {
    private constructor();

    get value(): undefined;

    get oldValue(): T;
  }

  class Add<T = unknown, TChildren = unknown> extends ValueEvent<T> {
    private constructor();

    get value(): T;

    get oldValue(): undefined;

    get addedValue(): TChildren;

    get id(): AbsolutePathFragment.Id;
  }

  class Remove<T = unknown, TChildren = unknown> extends ValueEvent<T> {
    private constructor();

    get value(): T;

    get oldValue(): undefined;

    get removedValue(): TChildren;

    get id(): AbsolutePathFragment.Id;
  }
}

export type SealedStateEvent<T = unknown> =
  | StateEvent.ValidationChange<T>
  | StateEvent.DisplayChange<T>
  | StateEvent.DirtyChange<T>
  | StateEvent.TouchedChange<T>;

export declare abstract class StateEvent<
  T = unknown,
> extends FormManagerEvent<T> {
  protected constructor();

  get path(): AbsolutePath;

  get schema(): Schema<T>;

  toString(): string;
}

export declare namespace StateEvent {
  class ValidationChange<T = unknown> extends StateEvent<T> {
    private constructor();

    get status(): ValidationStatus;

    get issues(): SealedValidationIssue[];
  }

  class DisplayChange<T = unknown> extends StateEvent<T> {
    private constructor();

    get status(): DisplayStatus;
  }

  class DirtyChange<T = unknown> extends StateEvent<T> {
    private constructor();

    get status(): boolean;
  }

  class TouchedChange<T = unknown> extends StateEvent<T> {
    private constructor();

    get status(): boolean;
  }
}

// Logging =====================================================================

/**
 * Log level.
 */
export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "off";

/**
 * Sets the logging level associated with the form manager.
 * @param level Log level to set.
 */
export declare function setLogLevel(level: LogLevel): void;

// Path multimap ===============================================================

/**
 * Identifier of an entry in a path multimap.
 */
export type PathMultimapEntryId = number;

/** An entry of the path multimap with values of type `T`. */
export class PathMultimapEntry<T = unknown> {
  private constructor();

  /**
   * Path of the multimap entry.
   */
  get path(): AbsolutePath;

  /**
   * Value of the multimap entry.
   */
  get value(): T;

  /**
   * Unique identified of the entry in the multimap.
   */
  get id(): PathMultimapEntryId;
}

/**
 * Multimap implementation mapping paths to values of type `T`.
 *
 * It is a multimap in the sense that multiple values may be associated with the
 * same path. However, each entry in the multimap is represented by an id
 * {@link PathMultimapEntryId} and the multimap allows operations on said ids.
 *
 * Operations on the multimap that receive paths follow the path semantics of
 * {@link AbsolutePath.matches matching} (for
 * {@link PathMultimap.contains contains}, {@link PathMultimap.get get}, and
 * {@link PathMultimap.entries entries}). This allows us to, for example, ge
 * all values matching a certain path that contains wildcards; or to have
 * entries containing paths with wildcards in the multimap whose value will be
 * returned when getting a path without wildcards that matches it.
 */
export class PathMultimap<T = unknown> {
  constructor(pairs?: [Path | string, T][]);

  /**
   * Number of entries in the multimap.
   */
  get size(): number;

  /**
   * Returns whether there exists at least one entry with a path matching
   * {@link path} (following the semantics of
   * {@link AbsolutePath.matches path matching}).
   * @param path Path to check.
   * @returns Whether there exists at least one entry with a path matching
   * {@link path}.
   */
  containsPath(path: Path | string): boolean;

  /**
   * Returns whether there exists an entry identified by {@link entryId} in the
   * multimap.
   * @param entryId Entry id to check.
   * @returns Whether there exists an entry identified by {@link entryId} in the
   * multimap.
   */
  containsEntry(entryId: PathMultimapEntryId): boolean;

  /**
   * Returns whether there exists at least one value equal to {@link value} in
   * the multimap.
   * @param value Value to check.
   * @returns Whether the exists at least one value equal to {@link value} in
   * the multimap.
   */
  containsValue(value: T): boolean;

  /**
   * Returns an iterable over all values with a path matching {@link path}
   * (following the semantics of
   * {@link AbsolutePath.matches path matching}).
   * @param path Path for which to get values.
   * @returns Iterable over values with a path matching {@link path}.
   */
  get(path: Path | string): Iterable<T>;

  /**
   * Returns the entry identified by {@link entryId} or `null` when no such
   * entry exists.
   * @param entryId Entry id of entry to get.
   * @returns Entry identified by {@link entryId} or `null`.
   */
  getEntry(entryId: PathMultimapEntryId): PathMultimapEntry<T> | null;

  /**
   * Inserts a new entry in the multimap with the given {@link path} and
   * {@link value} and returns an identifier that identifies the inserted entry
   * in the multimap.
   *
   * The returned identifier can be used to remove the inserted entry from the
   * multimap.
   * @param path Path of entry to insert.
   * @param value Value of entry to insert.
   * @returns Identifier that identifies the inserted entry in the multimap.
   */
  put(path: Path | string, value: T): PathMultimapEntryId;

  /**
   * Removes all entries with a path contained by {@link path} (following the
   * semantics of {@link AbsolutePath.contains path containment}) and returns an
   * array with said entries.
   * @param path Path containing entries to remove.
   * @returns Array of removed entries.
   */
  remove(path: Path | string): PathMultimapEntry<T>[];

  /**
   * Removes the entry identified by {@link entryId} and returns it or `null`
   * when no such entry exists.
   * @param entryId Id of entry to remove.
   * @returns Removed entry or `null`.
   */
  removeEntry(entryId: PathMultimapEntryId): PathMultimapEntry<T> | null;

  /**
   * Removes all entries from the path multimap.
   */
  clear();

  /**
   * Returns an iterable over all entries with a path matching {@link path}
   * (following the semantics of {@link AbsolutePath.matches path matching}).
   * @param path Path for which to get entries.
   * @returns Iterable over all entries with a path matching {@link path}.
   */
  entries(path?: Path | string): Iterable<PathMultimapEntry<T>>;

  toString(): string;
}

// Schema util =================================================================

/**
 * Returns the inner schema of a nullable schema.
 * @param schema Nullable schema from which to obtain the inner schema.
 * @returns Inner schema of a nullable schema.
 */
export function nullableSchemaInnerSchema<T = unknown>(
  schema: Schema<T | null>,
): Schema<T>;

/**
 * Returns whether the provided schema is computed.
 * @param schema Schema to check if it is computed.
 * @returns Whether the provided schema is computed.
 */
export function isComputedSchema(schema: Schema): boolean;

/**
 * Returns the inner schema of a computed schema.
 * @param schema Computed schema from which to obtain the inner schema.
 * @returns Inner schema of a computed schema.
 */
export function computedSchemaInnerSchema<T = unknown>(
  schema: Schema<T>,
): Schema<T>;

// Char util ===================================================================

/**
 * Kotlin `Char`.
 */
export interface Char {
  constructor: { $metadata$: { simpleName: "Char" } };

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Returns whether a given {@link value} is a Kotlin {@link Char}.
 * @param value Value to check.
 * @returns Whether a given {@link value} is a Kotlin {@link Char}.
 */
export declare function isChar(value: unknown): value is Char;

export declare function charToCode(value: Char): number;

export declare function codeToChar(code: number): Char;

// Numeric util ================================================================

/**
 * Kotlin `Long`.
 */
export interface Long {
  constructor: { $metadata$: { simpleName: "Long" } };

  valueOf(): number;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Returns whether a given {@link value} is a Kotlin {@link Long}.
 * @param value Value to check.
 * @returns Whether a given {@link value} is a Kotlin {@link Long}.
 */
export declare function isLong(value: unknown): value is Long;

/**
 * Converts a string to a {@link Long}.
 * @param string String to convert into a {@link Long}.
 * @returns {@link Long} representation of the string.
 */
export declare function stringToLong(string: string): Long;

/**
 * `kt-math` big integer.
 */
export declare interface BigInteger {
  /* extends Comparable<BigInteger> */
  readonly absoluteValue: BigInteger;
  readonly signum: number;
  readonly bitLength: number;
  readonly bitCount: number;

  rangeTo(endInclusive: BigInteger): any;

  rangeToInt(endInclusive: number): any;

  rangeToLong(endInclusive: Long): any;

  nextProbablePrime(): BigInteger;

  plus(other: BigInteger): BigInteger;

  plusInt(other: number): BigInteger;

  plusLong(other: Long): BigInteger;

  minus(other: BigInteger): BigInteger;

  minusInt(other: number): BigInteger;

  minusLong(other: Long): BigInteger;

  times(other: BigInteger): BigInteger;

  timesInt(other: number): BigInteger;

  timesLong(other: Long): BigInteger;

  div(other: BigInteger): BigInteger;

  divInt(other: number): BigInteger;

  divLong(other: Long): BigInteger;

  divideAndRemainder(other: BigInteger): BigInteger[];

  divideAndRemainderInt(other: number): BigInteger[];

  divideAndRemainderLong(other: Long): BigInteger[];

  reminder(other: BigInteger): BigInteger;

  reminderInt(other: number): BigInteger;

  reminderLong(other: Long): BigInteger;

  pow(exponent: number): BigInteger;

  sqrt(): BigInteger;

  sqrtAndRemainder(): BigInteger[];

  gcd(other: BigInteger): BigInteger;

  gcdInt(other: number): BigInteger;

  gcdLong(other: Long): BigInteger;

  unaryMinus(): BigInteger;

  unaryPlus(): BigInteger;

  rem(modulus: BigInteger): BigInteger;

  remInt(modulus: number): BigInteger;

  remLong(modulus: Long): BigInteger;

  modPow(exponent: BigInteger, modulus: BigInteger): BigInteger;

  modInverse(modulus: BigInteger): BigInteger;

  modInverseInt(modulus: number): BigInteger;

  modInverseLong(modulus: Long): BigInteger;

  shl(n: number): BigInteger;

  shr(n: number): BigInteger;

  and(other: BigInteger): BigInteger;

  andInt(other: number): BigInteger;

  andLong(other: Long): BigInteger;

  or(other: BigInteger): BigInteger;

  orInt(other: number): BigInteger;

  orLong(other: Long): BigInteger;

  xor(other: BigInteger): BigInteger;

  xorInt(other: number): BigInteger;

  xorLong(other: Long): BigInteger;

  not(): BigInteger;

  andNot(other: BigInteger): BigInteger;

  andNotInt(other: number): BigInteger;

  andNotLong(other: Long): BigInteger;

  testBit(n: number): boolean;

  get(n: number): boolean;

  set(n: number, b: boolean): BigInteger;

  setBit(n: number): BigInteger;

  clearBit(n: number): BigInteger;

  flipBit(n: number): BigInteger;

  isProbablePrime(certainty: number): boolean;

  equals(other: unknown): boolean;

  min(other: BigInteger): BigInteger;

  max(other: BigInteger): BigInteger;

  hashCode(): number;

  toStringWithRadix(radix: number): string;

  toString(): string;

  toByteArray(): Int8Array;

  toInt(): number;

  toLong(): Long;

  toByte(): number;

  toChar(): any /* Char */;

  toShort(): number;

  toFloat(): number;

  toDouble(): number;

  toLongExact(): Long;

  toIntExact(): number;

  toShortExact(): number;

  toByteExact(): number;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Returns whether a given {@link value} is a `kt-math` {@link BigInteger}.
 * @param value Value to check.
 * @returns Whether a given {@link value} is a `kt-math` {@link BigInteger}.
 */
export declare function isBigInteger(value: unknown): value is BigInteger;

/**
 * Converts a string to a {@link BigInteger}.
 * @param string String to convert into a {@link BigInteger}.
 * @returns {@link BigInteger} representation of the string.
 */
export declare function stringToBigInteger(string: string): BigInteger;

/**
 * `kt-math` big decimal.
 */
export declare interface BigDecimal {
  /* extends Comparable<BigDecimal> */
  readonly absoluteValue: BigDecimal;
  readonly signum: number;
  readonly scale: number;
  readonly precision: number;
  readonly unscaledValue: BigInteger;

  plus(augend?: BigDecimal | null): BigDecimal;

  plusWithContext(augend: BigDecimal | null, mc: any): BigDecimal;

  minus(subtrahend: BigDecimal): BigDecimal;

  minusWithContext(subtrahend: BigDecimal, mc: any): BigDecimal;

  times(multiplicand: BigDecimal | null): BigDecimal;

  timesWithContext(multiplicand: BigDecimal, mc: any): BigDecimal;

  div(divisor: BigDecimal): BigDecimal;

  divWithContext(divisor: BigDecimal, mc: any): BigDecimal | null | undefined;

  divideToIntegralValue(divisor: BigDecimal): BigDecimal;

  divideToIntegralValueWithContext(divisor: BigDecimal, mc: any): BigDecimal;

  rem(divisor: BigDecimal): BigDecimal;

  remWithContext(divisor: BigDecimal, mc: any): BigDecimal;

  divideAndRemainder(
    divisor: BigDecimal,
  ): any /* Pair<BigDecimal, BigDecimal> */;

  divideAndRemainderWithContext(
    divisor: BigDecimal,
    mc: any,
  ): any /* Pair<BigDecimal, BigDecimal> */;

  sqrt(mc?: MathContext): BigDecimal;

  pow(n: number): BigDecimal;

  powWithContext(n: number, mc: any): BigDecimal | null | undefined;

  absoluteValueWithContext(mc: any): BigDecimal | null | undefined;

  unaryMinus(): BigDecimal;

  unaryMinusWithContext(mc: any): BigDecimal | null | undefined;

  unaryPlus(): BigDecimal;

  unaryPlusWithContext(mc: any): BigDecimal | null | undefined;

  round(mc: any): BigDecimal | null | undefined;

  setScaleRounding(newScale: number, roundingMode: any): BigDecimal;

  /**
   * @deprecated The method {@link setScaleRounding} should be used in
   * preference to this legacy method.
   */
  setScaleInt(newScale: number, roundingMode: number): BigDecimal;

  setScale(newScale: number): BigDecimal;

  movePointLeft(n: number): BigDecimal;

  movePointRight(n: number): BigDecimal;

  scaleByPowerOfTen(n: number): BigDecimal;

  stripTrailingZeros(): BigDecimal;

  min(val: BigDecimal): BigDecimal;

  max(val: BigDecimal): BigDecimal;

  toEngineeringString(): string;

  toPlainString(): string;

  toBigInteger(): BigInteger;

  toBigIntegerExact(): BigInteger;

  toLong(): Long;

  toLongExact(): Long;

  toInt(): number;

  toByte(): number;

  toChar(): any /* Char */;

  toShort(): number;

  toIntExact(): number;

  toShortExact(): number;

  toByteExact(): number;

  toFloat(): number;

  toDouble(): number;

  ulp(): BigDecimal;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Returns whether a given {@link value} is a `kt-math` {@link BigDecimal}.
 * @param value Value to check.
 * @returns Whether a given {@link value} is a `kt-math` {@link BigDecimal}.
 */
export declare function isBigDecimal(value: unknown): value is BigDecimal;

/**
 * Converts a string to a {@link BigDecimal}.
 * @param string String to convert into a {@link BigDecimal}.
 * @returns {@link BigDecimal} representation of the string.
 */
export declare function stringToBigDecimal(string: string): BigDecimal;

// Temporal util ===============================================================

/**
 * `Instant` from `kotlinx-datetime`.
 */
export interface Instant {
  constructor: { $metadata$: { simpleName: "Instant" } };

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * `LocalDate` from `kotlinx-datetime`.
 */
export interface LocalDate {
  constructor: { $metadata$: { simpleName: "LocalDate" } };

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * `LocalDateTime` from `kotlinx-datetime`.
 */
export interface LocalDateTime {
  constructor: { $metadata$: { simpleName: "LocalDateTime" } };

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Returns whether `value` is an instance of a `kotlinx-datetime` `Instant`.
 * @param value Value to check.
 * @returns Wether `value` is a `kotlinx-datetime` `Instant`.
 */
export declare function isInstant(value: unknown): value is Instant;

/**
 * Returns whether `value` is an instance of a `kotlinx-datetime` `LocalDate`.
 * @param value Value to check.
 * @returns Wether `value` is a `kotlinx-datetime` `LocalDate`.
 */
export declare function isLocalDate(value: unknown): value is LocalDate;

/**
 * Returns whether `value` is an instance of a `kotlinx-datetime`
 * `LocalDateTime`.
 * @param value Value to check.
 * @returns Wether `value` is a `kotlinx-datetime` `LocalDateTime`.
 */
export declare function isLocalDateTime(value: unknown): value is LocalDateTime;

/**
 * Transforms an ISO string into a `kotlinx-datetime` `Instant`.
 * @param isoString String to transform.
 * @returns `kotlinx-datetime` `Instant`.
 */
export declare function stringToInstant(isoString: string): Instant;

/**
 * Transforms an ISO string into a `kotlinx-datetime` `LocalDate`.
 * @param isoString String to transform.
 * @returns `kotlinx-datetime` `LocalDate`.
 */
export declare function stringToLocalDate(isoString: string): LocalDate;

/**
 * Transforms an ISO string into a `kotlinx-datetime` `LocalDateTime`.
 * @param isoString String to transform.
 * @returns `kotlinx-datetime` `LocalDateTime`.
 */
export declare function stringToLocalDateTime(isoString: string): LocalDateTime;

// Listable util ===============================================================

/**
 * Kotlin `List`.
 */
export declare interface KtList<T = unknown> {
  asJsReadonlyArrayView(): readonly T[];

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Type of the identifier of a table row.
 */
export type TableRowId = number;

/**
 * KForm core's `Table`.
 */
export declare interface Table<
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  T = unknown,
> {
  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Size of a listable.
 * @param value Instance of a listable.
 * @returns Size of the listable.
 */
export declare function listableSize(
  value: readonly unknown[] | KtList | Table,
): number;

export declare function listableToArray<T = unknown>(
  value: readonly T[] | KtList<T> | Table<T>,
): T[];

export declare function isList(value: unknown): value is KtList;

export declare function isTable(value: unknown): value is Table;

export declare function sliceList<T = unknown>(
  value: KtList<T>,
  fromIndex?: number,
  toIndex?: number,
): T[];

export declare function sliceTable<T = unknown>(
  value: Table<T>,
  fromIndex?: number,
  toIndex?: number,
): [TableRowId, T][];

export declare function arrayToList<T = unknown>(
  value: readonly T[],
): KtList<T>;

export declare function arrayToTable<T = unknown>(
  value: readonly T[],
): Table<T>;

export declare function indexOfTableRowId(table: Table, id: TableRowId): number;

export declare function nextTableRowId(table: Table): TableRowId;

// Map util ====================================================================

/**
 * Kotlin `Map`.
 */
export declare interface KtMap<K = unknown, V = unknown> {
  asJsReadonlyMapView(): ReadonlyMap<K, V>;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Transforms a JavaScript object into a Kotlin map with string keys, optionally
 * mapping each value.
 * @param object JavaScript object to transform.
 * @param valueMapper Optional function that, when provided, maps each value of
 * the JavaScript to be set on the Kotlin map.
 * @returns Kotlin map representation of the provided JavaScript object, with
 * optionally mapped values.
 */
export function objectToKtMap<T = unknown>(
  object: Record<string, T>,
  valueMapper?: null,
): KtMap<string, T>;
export function objectToKtMap<T = unknown>(
  object: Record<string, T> | null | undefined,
  valueMapper?: null,
): KtMap<string, T> | null;
export function objectToKtMap<T = unknown, TMapped = unknown>(
  object: Record<string, T>,
  valueMapper: (value: T) => TMapped,
): KtMap<string, TMapped>;
export function objectToKtMap<T = unknown, TMapped = unknown>(
  object: Record<string, T> | null | undefined,
  valueMapper: (value: T) => TMapped,
): KtMap<string, TMapped> | null;
export function objectToKtMap<T = unknown, TMapped = unknown>(
  object: Record<string, T>,
  valueMapper?: ((value: T) => TMapped) | null,
): KtMap<string, T | TMapped>;
export function objectToKtMap<T = unknown, TMapped = unknown>(
  object: Record<string, T> | null | undefined,
  valueMapper?: ((value: T) => TMapped) | null,
): KtMap<string, T | TMapped> | null;

/**
 * Transforms a Kotlin into a JavaScript object, optionally mapping each value.
 * @param ktMap Kotlin map to transform.
 * @param valueMapper Optional function that, when provided, maps each value of
 * the Kotlin map to be set on the JavaScript object.
 * @returns JavaScript object representation of the provided Kotlin map, with
 * optionally mapped values.
 */
export function ktMapToObject<T = unknown>(
  ktMap: KtMap<unknown, T>,
  valueMapper?: null,
): Record<string, T>;
export function ktMapToObject<T = unknown>(
  ktMap: KtMap<unknown, T> | null | undefined,
  valueMapper?: null,
): Record<string, T> | null;
export function ktMapToObject<T = unknown, TMapped = unknown>(
  ktMap: KtMap<unknown, T>,
  valueMapper: (value: T) => TMapped,
): Record<string, TMapped>;
export function ktMapToObject<T = unknown, TMapped = unknown>(
  ktMap: KtMap<unknown, T> | null | undefined,
  valueMapper: (value: T) => TMapped,
): Record<string, TMapped> | null;
export function ktMapToObject<T = unknown, TMapped = unknown>(
  ktMap: KtMap<unknown, T>,
  valueMapper?: ((value: T) => TMapped) | null,
): Record<string, T | TMapped>;
export function ktMapToObject<T = unknown, TMapped = unknown>(
  ktMap: KtMap<unknown, T> | null | undefined,
  valueMapper?: ((value: T) => TMapped) | null,
): Record<string, T | TMapped> | null;

// Schema path util ============================================================

export function compareSchemaPaths(
  formSchema: Schema<T> | SchemaKt,
  path1: Path | string,
  path2: Path | string,
): number;

// Table path util =============================================================

export function convertPathTableRowIndicesToIds<T = unknown>(
  path: Path | string,
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
): CancellablePromise<AbsolutePath>;

export function convertPathTableRowIdsToIndices<T = unknown>(
  path: Path | string,
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
): CancellablePromise<AbsolutePath>;

export function convertIssueTableRowIndicesToIds<T = unknown>(
  issue: SealedLocatedValidationIssue | LocatedValidationIssueKt,
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
): CancellablePromise<SealedLocatedValidationIssue>;

export function convertIssuesTableRowIndicesToIds<T = unknown>(
  issues:
    | (SealedLocatedValidationIssue | LocatedValidationIssueKt)[]
    | KtList<SealedLocatedValidationIssue | LocatedValidationIssueKt>,
  formSchema: Schema<T> | SchemaKt,
  formValue: T,
): CancellablePromise<SealedLocatedValidationIssue[]>;

// File util ===================================================================

/**
 * Representation of a file to be used in a form.
 */
export interface File {
  constructor: { $metadata$: { simpleName: "File" } };

  /**
   * Name of the file.
   */
  get name(): string;

  /**
   * File content.
   */
  get data(): Int8Array;

  /**
   * File MIME type.
   */
  get type(): string | null;

  /**
   * Size of the file's data, in bytes.
   */
  get size(): number;

  equals(other: unknown): boolean;

  hashCode(): number;

  toString(): string;

  readonly __doNotUseOrImplementIt: any;
}

/**
 * Transforms a KForm file into its JavaScript file representation.
 * @param file KForm file to transform.
 * @returns JavaScript file representing the provided KForm file.
 */
export declare function kFormFileToJsFile(file: File): globalThis.File;

/**
 * Transforms a JavaScript file into its KForm file representation.
 * @param file JavaScript file to transform.
 * @returns Promise that resolves with a KForm file representing the given
 * JavaScript file.
 */
export declare function jsFileToKFormFile(file: globalThis.File): Promise<File>;

/**
 * Returns an empty placeholder KForm file.
 * @returns Empty placeholder KForm file.
 */
export declare function emptyPlaceholderKFormFile(): File;

// Validation issue util =======================================================

/**
 * Kotlin representation of a
 * [located validation issue]{@link LocatedValidationIssue}.
 */
export declare abstract class LocatedValidationIssueKt {}

/**
 * Checks whether a given value is a Kotlin representation of a located
 * validation issue.
 * @param value Value to check.
 * @returns Whether the provided value is a Kotlin representation of a located
 * validation issue.
 */
export declare function isLocatedValidationIssueKt(
  value: unknown,
): value is LocatedValidationIssueKt;

/**
 * Transforms a Kotlin representation of a located validation issue into its
 * JavaScript representation.
 * @param issue Kotlin representation of a located validation issue to
 * transform.
 * @returns JavaScript representation of the located validation issue.
 */
export declare function locatedValidationIssueKtToJs(
  issue: LocatedValidationIssueKt,
): SealedLocatedValidationIssue;
