import type { Identity } from './identity';
import type { PathType } from './path';
import { Path } from './path';
export type Lens<TState, TPath extends PathType> = LensContext<TState, TPath>['target'];
export type LensContext<TState, TPath extends PathType> = LensWithSlash<TState, TPath, object>;
/**
 * The arguments from the lens
 */
export type LensArgs<TState, TPath extends PathType> = Omit<LensContext<TState, TPath>, 'target' | 'path'>;
type LensWithSlash<TChildState, TPath extends PathType, TProps extends NonNullable<unknown>> = TPath extends `/${infer TTail}` ? LensWithoutSlash<TChildState, TPath, TTail, TProps> : TProps & {
    path: Path<TPath>;
    target: unknown;
};
type LensWithoutSlash<TChildState, TPath extends PathType, TSubPath extends PathType, TProps extends NonNullable<unknown>> = TSubPath extends `${infer THead}/${infer TTail}` ? LensOnCompoundPathWithParameter<TChildState, TPath, THead, TTail, TProps> : LensOnSinglePathWithParameter<TChildState, TPath, TSubPath, TProps>;
type LensOnSinglePathWithParameter<TChildState, TPath extends PathType, TParam extends string, TProps extends NonNullable<unknown>> = TParam extends `:${infer Arg}` ? TChildState extends any[] ? LensOnSinglePath<TChildState, TPath, number, TProps & {
    [key in Arg]: number;
}> : LensOnSinglePath<TChildState, TPath, keyof TChildState, TProps & {
    [key in Arg]: keyof TChildState;
}> : LensOnSinglePath<TChildState, TPath, TParam, TProps>;
type LensOnSinglePath<TChildState, TPath extends PathType, TKey, TProps extends NonNullable<unknown>> = TKey extends '' ? LensOnEmptyPath<TChildState, TPath, TProps> : TKey extends keyof TChildState ? LensOnEmptyPath<TChildState[TKey], TPath, TProps> : never;
type LensOnEmptyPath<TChildState, TPath extends PathType, TProps extends NonNullable<unknown>> = Identity<TProps & {
    path: Path<TPath>;
    target: TChildState;
}>;
type LensOnCompoundPathWithParameter<TChildState, TPath extends PathType, THead extends string, TTail extends PathType, TProps extends NonNullable<unknown>> = THead extends `:${infer Arg}` ? TChildState extends Array<infer U> ? LensWithoutSlash<U, TPath, TTail, TProps & {
    [K in Arg]: number;
}> : LensOnCompoundPath<TChildState, TPath, keyof TChildState, TTail, TProps & {
    [K in Arg]: keyof TChildState;
}> : LensOnCompoundPath<TChildState, TPath, THead, TTail, TProps>;
type LensOnCompoundPath<TChildState, TPath extends PathType, THead, TTail extends PathType, TProps extends NonNullable<unknown>> = THead extends keyof TChildState ? LensWithoutSlash<TChildState[THead], TPath, TTail, TProps> : LensOnArray<TChildState, TPath, THead, TTail, TProps>;
type LensOnArray<TChildState, TPath extends PathType, THead, TTail extends PathType, TProps extends NonNullable<unknown>> = TChildState extends Array<infer U> ? THead extends `${number}` ? LensWithoutSlash<U, TPath, TTail, TProps> : never : never;
declare function params(template: Path, path: Path): {
    [k: string]: any;
};
declare function context<TState, TPath extends PathType>(lens: Path<TPath>, path: Path, target: Lens<TState, TPath>): LensContext<TState, TPath>;
declare function createLens<TState, TPath extends PathType>(s: TState, p: Path<TPath>): Lens<TState, TPath> | undefined;
/**
 * Test if a lens given as first argument starts
 * with the path given as second argument
 */
declare function startsWith<TPath extends PathType>(lens: Path<TPath>, path: Path): boolean;
/**
 * Find all elements of the given state object that match
 * the lens, starting at `initialPath`
 *
 * This function never throws, if the lens does not
 * start with the initial path or there are no matches
 * the function will return an empty array
 */
declare function findAll<TState, TPath extends PathType, TStartPath extends PathType = '/'>(state: TState, lens: Path<TPath>, initialPath?: Path<TStartPath>): Path[];
export declare const Lens: {
    context: typeof context;
    args: typeof params;
    from: typeof createLens;
    findAll: typeof findAll;
    startsWith: typeof startsWith;
};
export {};
