/// <reference types="node" />
import { enforce } from 'n4s';
import { DynamicValue, OneOrMoreOf, Maybe, Nullable, CB, ValueOf } from "vest-utils";
import { InjectionToken } from "@angular/core";
import { TIsolate, IsolateKey } from "vestjs-runtime";
declare enum Severity {
    WARNINGS = "warnings",
    ERRORS = "errors"
}
declare enum TestSeverity {
    Error = "error",
    Warning = "warning"
}
declare const TestStatus: {
    [x: string]: string;
    CANCELED: string;
    FAILED: string;
    OMITTED: string;
    PASSING: string;
    SKIPPED: string;
    UNTESTED: string;
    WARNING: string;
};
type TestStatus = ValueOf<typeof TestStatus>;
type TestFnPayload = {
    signal: AbortSignal;
};
type TestFn = (payload: TestFnPayload) => TestResult;
type AsyncTest = Promise<void>;
type TestResult = Maybe<AsyncTest | boolean> | void;
type WithFieldName<F extends TFieldName = TFieldName> = {
    fieldName: F;
};
type TIsolateTest<F extends TFieldName = TFieldName, G extends TGroupName = TGroupName> = TIsolate<CommonTestFields<F, G> & IsolateTestPayload>;
type IsolateTestPayload<F extends TFieldName = TFieldName, G extends TGroupName = TGroupName> = CommonTestFields<F, G> & {
    severity: TestSeverity;
    status: TestStatus;
    asyncTest?: AsyncTest;
};
type CommonTestFields<F extends TFieldName = TFieldName, G extends TGroupName = TGroupName> = {
    message?: Maybe<string>;
    groupName?: G;
    fieldName: F;
    testFn: TestFn;
};
/**
 * Injection token for accessing the current test context in Angular environments.
 * Used internally by runSyncTest to provide the test object to the test function.
 */
declare const VEST_TEST_CONTEXT: InjectionToken<TIsolateTest<string, string>>;
declare class SummaryFailure<F extends TFieldName, G extends TGroupName> implements WithFieldName<F> {
    fieldName: F;
    message: string | undefined;
    groupName: G | undefined;
    constructor(fieldName: F, message: string | undefined, groupName: G | undefined);
    static fromTestObject<F extends TFieldName, G extends TGroupName>(testObject: TIsolateTest<F, G>): SummaryFailure<F & string, G & string>;
}
interface Done<F extends TFieldName, G extends TGroupName> {
    (...args: [
        cb: (res: SuiteResult<F, G>) => void
    ]): SuiteRunResult<F, G>;
    (...args: [
        fieldName: F,
        cb: (res: SuiteResult<F, G>) => void
    ]): SuiteRunResult<F, G>;
}
// eslint-disable-next-line max-lines-per-function, max-statements
declare function suiteSelectors<F extends TFieldName, G extends TGroupName>(summary: SuiteSummary<F, G>): SuiteSelectors<F, G>;
interface SuiteSelectors<F extends TFieldName, G extends TGroupName> {
    getWarning(): SummaryFailure<F, G> | undefined;
    getWarning(fieldName: F): string | undefined;
    getWarning(fieldName?: F): SummaryFailure<F, G> | string | undefined;
    getError(): SummaryFailure<F, G> | undefined;
    getError(fieldName: F): string | undefined;
    getError(fieldName?: F): SummaryFailure<F, G> | string | undefined;
    getMessage(fieldName: F): string | undefined;
    getErrors(): FailureMessages;
    getErrors(fieldName: F): string[];
    getErrors(fieldName?: F): string[] | FailureMessages;
    getWarnings(): FailureMessages;
    getWarnings(fieldName: F): string[];
    getWarnings(fieldName?: F): string[] | FailureMessages;
    getErrorsByGroup(groupName: G): FailureMessages;
    getErrorsByGroup(groupName: G, fieldName: F): string[];
    getErrorsByGroup(groupName: G, fieldName?: F): string[] | FailureMessages;
    getWarningsByGroup(groupName: G): FailureMessages;
    getWarningsByGroup(groupName: G, fieldName: F): string[];
    getWarningsByGroup(groupName: G, fieldName?: F): string[] | FailureMessages;
    hasErrors(fieldName?: F): boolean;
    hasWarnings(fieldName?: F): boolean;
    hasErrorsByGroup(groupName: G, fieldName?: F): boolean;
    hasWarningsByGroup(groupName: G, fieldName?: F): boolean;
    isTested(fieldName: F): boolean;
    isPending(fieldName?: F): boolean;
    isValid(fieldName?: F): boolean;
    isValidByGroup(groupName: G, fieldName?: F): boolean;
}
declare class SummaryBase {
    errorCount: number;
    warnCount: number;
    testCount: number;
    pendingCount: number;
}
declare class SuiteSummary<F extends TFieldName, G extends TGroupName> extends SummaryBase {
    [Severity.ERRORS]: SummaryFailure<F, G>[];
    [Severity.WARNINGS]: SummaryFailure<F, G>[];
    groups: Groups<G, F>;
    tests: Tests<F>;
    valid: Nullable<boolean>;
}
type GroupTestSummary = SingleTestSummary;
type Groups<G extends TGroupName, F extends TFieldName> = Record<G, Group<F>>;
type Group<F extends TFieldName> = Record<F, GroupTestSummary>;
type Tests<F extends TFieldName> = Record<F, SingleTestSummary>;
type SingleTestSummary = SummaryBase & {
    errors: string[];
    warnings: string[];
    valid: Nullable<boolean>;
    pendingCount: number;
};
type FailureMessages = Record<string, string[]>;
type SuiteResult<F extends TFieldName, G extends TGroupName> = SuiteSummary<F, G> & SuiteSelectors<F, G> & {
    suiteName: SuiteName;
};
type SuiteRunResult<F extends TFieldName, G extends TGroupName> = SuiteResult<F, G> & {
    done: Done<F, G>;
};
type SuiteName = Maybe<string>;
type TFieldName<T extends string = string> = T;
type TGroupName<G extends string = string> = G;
type OptionalFields = Record<string, OptionalFieldDeclaration>;
type OptionalsInput<F extends TFieldName> = OneOrMoreOf<F> | OptionalsObject<F>;
type OptionalsObject<F extends TFieldName> = Record<F, TOptionalRule | any>;
type ImmediateOptionalFieldDeclaration = {
    type: OptionalFieldTypes.CUSTOM_LOGIC;
    rule: TOptionalRule;
    applied: boolean;
};
type DelayedOptionalFieldDeclaration = {
    type: OptionalFieldTypes.AUTO;
    applied: boolean;
    rule: null;
};
type TOptionalRule = DynamicValue<boolean>;
type OptionalFieldDeclaration = ImmediateOptionalFieldDeclaration | DelayedOptionalFieldDeclaration;
declare enum OptionalFieldTypes {
    CUSTOM_LOGIC = 0,
    AUTO = 1
}
// @vx-allow use-use
declare function optional<F extends TFieldName>(optionals: OptionalsInput<F>): void;
declare enum Modes {
    EAGER = "EAGER",
    ALL = "ALL",
    ONE = "ONE"
}
type TIsolateSuite = TIsolate<{
    optional: OptionalFields;
}>;
type Events = "TEST_RUN_STARTED" | "TEST_COMPLETED" | "ALL_RUNNING_TESTS_FINISHED" | "REMOVE_FIELD" | "RESET_FIELD" | "RESET_SUITE" | "SUITE_RUN_STARTED" | "SUITE_CALLBACK_RUN_FINISHED" | "DONE_TEST_OMISSION_PASS";
type Subscribe = {
    (event: Events, cb: CB): CB<void>;
    (cb: CB): CB<void>;
};
declare enum FocusModes {
    ONLY = 0,
    SKIP = 1
}
type FieldExclusion<F extends TFieldName> = Maybe<OneOrMoreOf<F>>;
type TIsolateFocused = TIsolate<IsolateFocusedPayload>;
type IsolateFocusedPayload = {
    focusMode: FocusModes;
    match: FieldExclusion<TFieldName>;
    matchAll: boolean;
};
/**
 * Adds a field or a list of fields into the inclusion list
 *
 * @example
 *
 * only('username');
 */
// @vx-allow use-use
declare function only(match: FieldExclusion<TFieldName> | false): TIsolateFocused;
/**
 * Adds a field or a list of fields into the exclusion list
 *
 * @example
 *
 * skip('username');
 */
// @vx-allow use-use
declare function skip(match: FieldExclusion<TFieldName> | boolean): TIsolateFocused;
declare function vestTest<F extends TFieldName>(fieldName: F, message: string, cb: TestFn): TIsolateTest;
declare function vestTest<F extends TFieldName>(fieldName: F, cb: TestFn): TIsolateTest;
declare function vestTest<F extends TFieldName>(fieldName: F, message: string, cb: TestFn, key: IsolateKey): TIsolateTest;
declare function vestTest<F extends TFieldName>(fieldName: F, cb: TestFn, key: IsolateKey): TIsolateTest;
declare const test: typeof vestTest & {
    memo: TestMemo<string>;
};
type TestMemo<F extends TFieldName> = {
    (fieldName: F, ...args: ParametersWithoutMessage): TIsolateTest;
    (fieldName: F, ...args: ParametersWithMessage): TIsolateTest;
};
type ParametersWithoutMessage = [
    test: TestFn,
    dependencies: unknown[]
];
type ParametersWithMessage = [
    message: string,
    test: TestFn,
    dependencies: unknown[]
];
type TTypedMethods<F extends TFieldName, G extends TGroupName> = {
    include: (fieldName: F) => {
        when: (condition: F | TDraftCondition<F, G>) => void;
    };
    omitWhen: (conditional: TDraftCondition<F, G>, callback: CB) => void;
    only: {
        (item: FieldExclusion<F>): void;
    };
    optional: (optionals: OptionalsInput<F>) => void;
    skip: {
        (item: FieldExclusion<F>): void;
    };
    skipWhen: (condition: TDraftCondition<F, G>, callback: CB) => void;
    test: {
        (fieldName: F, message: string, cb: TestFn): TIsolateTest;
        (fieldName: F, cb: TestFn): TIsolateTest;
        (fieldName: F, message: string, cb: TestFn, key: IsolateKey): TIsolateTest;
        (fieldName: F, cb: TestFn, key: IsolateKey): TIsolateTest;
    } & {
        memo: TestMemo<F>;
    };
    group: {
        (callback: () => void): TIsolate;
        (groupName: G, callback: () => void): TIsolate;
    };
};
type TDraftCondition<F extends TFieldName, G extends TGroupName> = DynamicValue<boolean, [
    draft: SuiteResult<F, G>
]>;
declare function createSuite<F extends TFieldName = string, G extends TGroupName = string, T extends CB = CB>(suiteName: SuiteName, suiteCallback: T): Suite<F, G, T>;
declare function createSuite<F extends TFieldName = string, G extends TGroupName = string, T extends CB = CB>(suiteCallback: T): Suite<F, G, T>;
/**
 * Creates a static suite for server-side validation.
 *
 * @param {Function} validationFn - The validation function that defines the suite's tests.
 * @returns {Function} - A function that runs the validations defined in the suite.
 *
 * @example
 * import { staticSuite, test, enforce } from 'vest';
 *
 * const suite = staticSuite(data => {
 *   test('username', 'username is required', () => {
 *     enforce(data.username).isNotEmpty();
 *   });
 * });
 *
 * suite(data);
 */
declare function staticSuite<F extends TFieldName = string, G extends TGroupName = string, T extends CB = CB>(suiteName: SuiteName, suiteCallback: T): StaticSuite<F, G, T>;
declare function staticSuite<F extends TFieldName = string, G extends TGroupName = string, T extends CB = CB>(suiteCallback: T): StaticSuite<F, G, T>;
type StaticSuite<F extends TFieldName = string, G extends TGroupName = string, T extends CB = CB> = (...args: Parameters<T>) => StaticSuiteRunResult<F, G>;
type StaticSuiteRunResult<F extends TFieldName = string, G extends TGroupName = string> = Promise<SuiteWithDump<F, G>> & WithDump<SuiteRunResult<F, G> & TTypedMethods<F, G>>;
type WithDump<T> = T & {
    dump: CB<TIsolateSuite>;
};
type SuiteWithDump<F extends TFieldName, G extends TGroupName> = WithDump<SuiteResult<F, G>>;
type Suite<F extends TFieldName, G extends TGroupName, T extends CB = CB> = ((...args: Parameters<T>) => SuiteRunResult<F, G>) & SuiteMethods<F, G, T>;
type SuiteMethods<F extends TFieldName, G extends TGroupName, T extends CB> = {
    dump: CB<TIsolateSuite>;
    get: CB<SuiteResult<F, G>>;
    resume: CB<void, [
        TIsolateSuite
    ]>;
    reset: CB<void>;
    remove: CB<void, [
        fieldName: F
    ]>;
    resetField: CB<void, [
        fieldName: F
    ]>;
    runStatic: CB<StaticSuiteRunResult<F, G>, Parameters<T>>;
    subscribe: Subscribe;
} & TTypedMethods<F, G> & SuiteSelectors<F, G>;
declare function registerReconciler(reconciler: IsolateReconciler): void;
type IsolateReconciler = {
    match(currentNode: TIsolate, historyNode: TIsolate): boolean;
    reconcile(elecurrentNode: TIsolate, historyNode: TIsolate): TIsolate;
};
/**
 * Iterates over an array of items, allowing to run tests individually per item.
 *
 * Requires setting a "key" property on each item tested.
 *
 * @example
 *
 * each(itemsArray, (item) => {
 *  test(item.name, 'Item value must not be empty', () => {
 *    enforce(item.value).isNotEmpty();
 *  }, item.id)
 * })
 */
declare function each<T>(list: T[], callback: (arg: T, index: number) => void): void;
declare function group<G extends TGroupName>(groupName: G, callback: CB<void>): TIsolate;
declare function group(callback: CB<void>): TIsolate;
/**
 * Conditionally includes a field for testing, based on specified criteria.
 *
 * @param {string} fieldName - The name of the field to include for testing.
 *
 * @example
 * include('confirm').when('password');
 * // Includes the "confirm" field for testing when the "password" field is included
 *
 * include('confirm').when(someValue);
 * // Includes the "confirm" field for testing when the value of `someValue` is true
 *
 * include('confirm').when(() => someValue);
 * // Includes the "confirm" field for testing when the callback function returns true
 *
 * include('username').when(result => result.hasErrors('username'));
 * // Includes the "username" field for testing when there are errors associated with it in the current suite result
 */
// @vx-allow use-use
declare function include<F extends TFieldName, G extends TGroupName>(fieldName: F): {
    when: (condition: F | TFieldName | TDraftCondition<F, G>) => void;
};
/**
 * Sets the current execution mode for the current suite.
 *
 * Supported modes:
 * - `EAGER` - (default) Runs all tests, but stops on first failure for each given field.
 * - `ALL` - Runs all tests, regardless of failures.
 * - `ONE` - Stops suite execution on first failure of any field.
 *
 * @example
 * ```js
 * import {Modes, create} from 'vest';
 *
 * const suite = create('suite_name', () => {
 *  vest.mode(Modes.ALL);
 *
 *  // ...
 * });
 * ```
 * @param 'ALL' | 'EAGER' | 'ONE' mode - The mode to set.
 */
// @vx-allow use-use
declare function mode(mode: Modes): void;
/**
 * Conditionally omits tests from the suite.
 *
 * @example
 *
 * omitWhen(res => res.hasErrors('username'), () => {
 *  test('username', 'User already taken', async () => await doesUserExist(username)
 * });
 */
// @vx-allow use-use
declare function omitWhen<F extends TFieldName, G extends TGroupName>(conditional: TDraftCondition<F, G>, callback: CB): void;
/**
 * Conditionally skips running tests within the callback.
 *
 * @example
 *
 * skipWhen(res => res.hasErrors('username'), () => {
 *  test('username', 'User already taken', async () => await doesUserExist(username)
 * });
 */
// @vx-allow use-use
declare function skipWhen<F extends TFieldName, G extends TGroupName>(condition: TDraftCondition<F, G>, callback: CB): void;
/**
 * Sets the severity level of a test to `warn`, allowing it to fail without marking the suite as invalid.
 * Use this function within the body of a test to create warn-only tests.
 *
 * @returns {void}
 *
 * @example
 *   test('password', 'Your password strength is: WEAK', () => {
 *     warn();
 *
 *     enforce(data.password).matches(/0-9/);
 *   });
 *
 * @limitations
 * - The `warn` function should only be used within the body of a `test` function.
 * - When using `warn()` in an async test, it should be called in the synchronous portion of the test, not after an `await` call or in the Promise body.
 * - It is recommended to call `warn()` at the top of the test function.
 */
// @vx-allow use-use
declare function warn(): void;
export { createSuite as create, test, group, optional, enforce, skip, skipWhen, omitWhen, only, warn, include, suiteSelectors, each, mode, staticSuite, Modes, registerReconciler, VEST_TEST_CONTEXT };
export type { SuiteResult, SuiteRunResult, SuiteSummary, Suite, StaticSuite };
//# sourceMappingURL=vest.d.ts.map