import { type U } from "../utils";
import { type MutGraph } from ".";
import { type Id } from "./utils";
/**
 * The interface for getting the parent ids from data. This must return an
 * array of the ids of every parent of this node. `i` will increment in the
 * order nodes are processed.
 *
 * This can be modified with the {@link Stratify#parentIds} method.
 */
export type ParentIds<in NodeDatum = never> = (datum: NodeDatum, index: number) => Iterable<string> | undefined;
/**
 * The interface for getting the parent ids and link data from the current node
 * data. This must return an array of parent ids coupled with data (i.e. an
 * array of two element arrays of the form ["Parent Id", data]) for the link
 * between this node and the parent id.
 *
 * This can be modified with the {@link Stratify#parentData} method.
 */
export type ParentData<in NodeDatum = never, out LinkDatum = unknown> = (datum: NodeDatum, index: number) => Iterable<readonly [string, LinkDatum]> | undefined;
type StratifyNodeDatum<Ops extends StratifyOps> = Ops extends StratifyOps<infer N> ? N : never;
/**
 * What gets returned by {@link Stratify#parentData}() when {@link Stratify#parentIds} is set.
 */
export interface WrappedParentIds<ParIds extends ParentIds> extends ParentData<ParIds extends ParentIds<infer N> ? N : never, undefined> {
    /** the wrapped parent ids operator */
    wrapped: ParIds;
}
/**
 * What gets returned by {@link Stratify#parentIds}() when {@link Stratify#parentData} is set.
 */
export interface WrappedParentData<ParData extends ParentData> extends ParentIds<ParData extends ParentData<infer N> ? N : never> {
    /** the wrapped parent data operator */
    wrapped: ParData;
}
/** the operators for the stratify operator */
export interface StratifyOps<in NodeDatum = never, out LinkDatum = unknown> {
    /** the id operator */
    id: Id<NodeDatum>;
    /** the parent ids operator */
    parentIds: ParentIds<NodeDatum>;
    /** the parent data operator */
    parentData: ParentData<NodeDatum, LinkDatum>;
}
/**
 * The operator that constructs a {@link MutGraph} from stratified tabularesque
 * data.
 *
 * Create a default operator with {@link graphStratify}. The accessors for a node's
 * {@link id} or {@link parentIds | parents' ids} can be altered, or
 * {@link parentData} can be specified to specify parent ids and attach data
 * to the edge for that parent.
 */
export interface Stratify<LinkDatum, Ops extends StratifyOps<never, LinkDatum>> {
    /**
     * create a graph from stratify data
     *
     * @param data - the node data to create a graph from
     * @returns graph - the graph representation of the data
     */
    <N extends StratifyNodeDatum<Ops>>(data: readonly N[]): MutGraph<N, LinkDatum>;
    /**
     * Sets the id accessor to the given {@link Id} and returns a
     * Stratify. The default operator is:
     *
     * ```js
     * function id(d) {
     *   return d.id;
     * }
     * ```
     */
    id<NewId extends Id>(id: NewId): Stratify<LinkDatum, U<Ops, "id", NewId>>;
    /**
     * Gets the current id accessor.
     */
    id(): Ops["id"];
    /**
     * Sets the parentIds accessor to the given {@link ParentIds}
     * and returns an update operator. The default operator is:
     *
     * ```js
     * function parentIds(d) {
     *   return d.parentIds;
     * }
     * ```
     */
    parentIds<NewParentIds extends ParentIds>(ids: NewParentIds): Stratify<undefined, {
        /** current id operator */
        id: Ops["id"];
        /** new parent ids */
        parentIds: NewParentIds;
        /** new parent data */
        parentData: WrappedParentIds<NewParentIds>;
    }>;
    /**
     * Gets the current parent ids accessor.  If {@link parentData} was passed, the
     * returned function will {@link WrappedParentData | wrap} that to
     * just return the ids.
     */
    parentIds(): Ops["parentIds"];
    /**
     * Sets the parentData accessor to the given {@link ParentData} and
     * returns an updated operator.
     */
    parentData<NewLinkDatum, NewParentData extends ParentData<never, NewLinkDatum>>(data: NewParentData & ParentData<never, NewLinkDatum>): Stratify<NewLinkDatum, {
        /** current id operator */
        id: Ops["id"];
        /** new parent data */
        parentData: NewParentData;
        /** new parent ids */
        parentIds: WrappedParentData<NewParentData>;
    }>;
    /**
     * Gets the current parentData accessor. If {@link parentIds} was passed, this
     * will {@link WrappedParentIds | wrap} that to just return the ids
     * with `undefined` data.
     */
    parentData(): Ops["parentData"];
}
/** default interface for types with an id */
export interface HasId {
    /** the id */
    readonly id: string;
}
/** default interface for data types with parent ids */
export interface HasParentIds {
    /** the parent ids */
    readonly parentIds?: Iterable<string> | undefined;
}
/** the default stratify operator */
export type DefaultStratify = Stratify<undefined, {
    /** the id operator */
    id: Id<HasId>;
    /** the parent id operator */
    parentIds: ParentIds<HasParentIds>;
    /** the parent data operator */
    parentData: WrappedParentIds<ParentIds<HasParentIds>>;
}>;
/**
 * create a new {@link Stratify} with default settings
 *
 * Stratify operators create graphs from data that are in a tabular format,
 * with references to ids of their parents.  By default it expects node data to
 * have a string `id` property and `parentIds` property with an iterable of
 * parent ids.
 *
 * @example
 *
 * If you want to use the default operator:
 *
 * ```ts
 * data = [
 *   { "id": "Euler" },
 *   {
 *     "id": "Lagrange",
 *     "parentIds": ["Euler"]
 *   },
 *   {
 *     "id": "Fourier",
 *     "parentIds": ["Lagrange"]
 *   },
 *   {
 *     "id": "Poisson",
 *     "parentIds": ["Lagrange", "Laplace"]
 *   },
 *   {
 *     "id": "Dirichlet",
 *     "parentIds": ["Fourier", "Poisson"]
 *   },
 *   { "id": "Laplace" }
 * ] as const;
 *
 * const builder = stratify();
 * const grf = builder(data);
 * ```
 *
 * @example
 *
 * If you want to include custom link data:
 *
 * ```ts
 * data = [
 *   { "id": "Euler" },
 *   {
 *     "id": "Lagrange",
 *     "parentData": [["Euler", 1]]
 *   },
 * ] as const;
 *
 * const builder = stratify()
 *   .parentData(({ parentData = [] }) => parentData;
 * const grf = builder(data);
 * ```
 */
export declare function graphStratify(...args: never[]): DefaultStratify;
export {};
