import { type Maybe, type SortCompareFunction, type ArrayOrValue, type UniqueModel, type IndexNumber, type FactoryWithRequiredInput, type DateRelativeState } from '@dereekb/util'; import { type DateCell, type DateOrDateCellIndex, type DateCellIndex } from './date.cell'; import { type DateRange } from './date.range'; /** * Represents a range of DateCell values. */ export interface DateCellRange extends DateCell { /** * Index this block ends at, inclusive. A block with i=0 and to=0 encompases only the block 0. * * If not provided, assumes this has no range and starts/ends at the same index, i. */ to?: Maybe; } /** * Returns true if the input is a DateCellRange. * * Does not check validity. Use {@link isValidDateCellRange} for that. * * @param input - Value to check. * @returns True if the input is a DateCellRange. */ export declare function isDateCellRange(input: unknown): input is DateCellRange; /** * A DateCellIndex, DateCell, or DateCellRange */ export type DateCellOrDateCellIndexOrDateCellRange = DateCellIndex | DateCell | DateCellRange; /** * Returns true if the input is a valid DateCellRange. * * A valid range has a non-negative integer `i`, and if `to` is defined it must also be a valid index * that is greater than or equal to `i`. * * @param input - Range to validate. * @returns True if the range has valid non-negative indexes and `to` (when defined) is greater than or equal to `i` */ export declare function isValidDateCellRange(input: DateCellRange): boolean; /** * Returns true if the input is a sorted DateCellRange array and there are no repeat indexes. * * Validates that each range is individually valid and that no ranges overlap or appear out of order. * * @param input - Array of ranges to validate as a non-overlapping ascending series. * @returns True if the array is sorted in ascending order with no overlapping or duplicate indexes. */ export declare function isValidDateCellRangeSeries(input: DateCellRange[]): boolean; /** * Returns the lowest index between all the input date block ranges. Returns 0 by default if there is no minimum or input blocks. * * The input range is not expected to be sorted. * * @param input - Unsorted array of date cell ranges to scan. * @returns The smallest starting index found, or 0 if the input is empty. */ export declare function getLeastDateCellIndexInDateCellRanges(input: (DateCell | DateCellRange)[]): DateCellIndex; /** * Returns the largest index between all the input date block ranges. Returns 0 by default. * * The input range is not expected to be sorted. * * @param input - Unsorted array of date cell ranges to scan. * @returns The largest ending index found, or 0 if the input is empty. */ export declare function getGreatestDateCellIndexInDateCellRanges(input: (DateCell | DateCellRange)[]): DateCellIndex; /** * Result containing both the smallest and largest indexes found across a set of date cell ranges, * along with references to the items that contain those extreme indexes. */ export interface LeastAndGreatestDateCellIndexResult { /** * Smallest starting index found. */ leastIndex: number; /** * The item containing the smallest starting index. */ leastIndexItem: T; /** * Largest ending index found (considers `to` values). */ greatestIndex: number; /** * The item containing the largest ending index. */ greatestIndexItem: T; } /** * Returns both the least and greatest indexes across all input date cell ranges, or null if the input is empty. * * The input range is not expected to be sorted. * * @param input - Unsorted array of date cell ranges to scan. * @returns An object with the least and greatest indexes and their source items, or null if the input is empty. */ export declare function getLeastAndGreatestDateCellIndexInDateCellRanges(input: T[]): Maybe>; /** * Input type used for cases where a DateRange or a DateCellRange are allowed as input but used the start/end parameters in DateRange. */ export interface DateCellRangeOrDateRange { start?: Maybe; end?: Maybe; } /** * Union type allowing a Date, DateCellIndex, or DateCellRange as input. */ export type DateOrDateCellIndexOrDateCellRange = DateOrDateCellIndex | DateCellRange; /** * Union type extending {@link DateOrDateCellIndexOrDateCellRange} to also accept a {@link DateRange}. */ export type DateOrDateRangeOrDateCellIndexOrDateCellRange = DateRange | DateOrDateCellIndexOrDateCellRange; /** * Creates a {@link DateCellRangeWithRange} with the given start and optional end index. * If `to` is omitted the range covers a single cell at index `i`. * * @param i - Starting cell index. * @param to - Ending cell index (inclusive); defaults to `i` * @returns A DateCellRangeWithRange spanning from `i` to `to` */ export declare function dateCellRange(i: number, to?: Maybe): DateCellRangeWithRange; /** * Creates a single-cell {@link DateCellRangeWithRange} where both `i` and `to` equal the given index. * * @param dateCellIndex - The index for both start and end of the range. * @returns A DateCellRangeWithRange where `i` and `to` both equal the given index. */ export declare function dateCellRangeWithRangeFromIndex(dateCellIndex: DateCellIndex): DateCellRangeWithRange; /** * Normalizes any {@link DateCellOrDateCellIndexOrDateCellRange} into a {@link DateCellRangeWithRange}, * ensuring the result always has an explicit `to` value. * * @param input - Index, cell, or range to normalize. * @returns A DateCellRangeWithRange with an explicit `to` value. */ export declare function dateCellRangeWithRange(input: DateCellOrDateCellIndexOrDateCellRange): DateCellRangeWithRange; /** * Function that returns true if the input range covers the full range of the configured DateCellRange. */ export type DateCellRangeIncludedByRangeFunction = (range: DateCellOrDateCellIndexOrDateCellRange) => boolean; /** * Creates a {@link DateCellRangeIncludedByRangeFunction} that checks whether a given range * fully contains the configured `inputRange`. * * @param inputRange - Range that must be fully included by candidate ranges. * @returns Predicate that reports true when its argument fully contains `inputRange`. * * @__NO_SIDE_EFFECTS__ */ export declare function dateCellRangeIncludedByRangeFunction(inputRange: DateCellOrDateCellIndexOrDateCellRange): DateCellRangeIncludedByRangeFunction; /** * Function that returns true if the input range overlaps the range of the configured DateCellRange. */ export type DateCellRangeOverlapsRangeFunction = (range: DateCellOrDateCellIndexOrDateCellRange) => boolean; /** * Creates a {@link DateCellRangeOverlapsRangeFunction} that checks whether a given range * has any overlap with the configured `inputRange`. * * @param inputRange - Range to compare candidate ranges against. * @returns Predicate that reports true when its argument overlaps with `inputRange`. * * @__NO_SIDE_EFFECTS__ */ export declare function dateCellRangeOverlapsRangeFunction(inputRange: DateCellOrDateCellIndexOrDateCellRange): DateCellRangeOverlapsRangeFunction; /** * Returns true if the two ranges share at least one common index. * * @param rangeA - First range to compare. * @param rangeB - Second range to compare. * @returns True if the two ranges share at least one common index. */ export declare function dateCellRangeOverlapsRange(rangeA: DateCellOrDateCellIndexOrDateCellRange, rangeB: DateCellOrDateCellIndexOrDateCellRange): boolean; /** * Returns a sort comparator that orders ranges first by starting index (`i`), then by ending index (`to`). * * In many cases {@link sortAscendingIndexNumberRefFunction} may be preferential when `to` ordering is not needed. * * @returns A comparator function that sorts ranges by `i` then by `to` * * @__NO_SIDE_EFFECTS__ */ export declare function sortDateCellRangeAndSizeFunction(): SortCompareFunction; /** * Sorts the input date ranges in-place by ascending index using {@link sortAscendingIndexNumberRefFunction}. * * @param input - Array of ranges to sort (mutated in place) * @returns The same array, sorted in ascending index order. */ export declare function sortDateCellRanges(input: T[]): T[]; /** * DateCellRange that is known to have a to value. */ export type DateCellRangeWithRange = Omit & { to: DateCellIndex; }; /** * Merges an array of {@link DateCell} or {@link DateCellRange} values into the smallest set of * contiguous {@link DateCellRangeWithRange} values. Adjacent or overlapping ranges are combined. * * The input is sorted internally before grouping. * * @param input - Cells or ranges to merge into contiguous groups. * @returns Contiguous, non-overlapping range groups covering the input. * * @example * ```ts * // Three adjacent cells collapse into one range * groupToDateCellRanges([{ i: 0 }, { i: 1 }, { i: 2 }]); * // => [{ i: 0, to: 2 }] * * // Non-adjacent cells produce separate ranges * groupToDateCellRanges([{ i: 0 }, { i: 5 }]); * // => [{ i: 0, to: 0 }, { i: 5, to: 5 }] * ``` */ export declare function groupToDateCellRanges(input: (DateCell | DateCellRange)[]): DateCellRangeWithRange[]; /** * Returns an array containing every individual index in the given date cell range (inclusive of both `i` and `to`). * * @param input - Range to expand into individual indexes. * @returns Every DateCellIndex covered by the range, inclusive on both ends. */ export declare function allIndexesInDateCellRange(input: DateCellRange): DateCellIndex[]; /** * Flattens an array of indexes and/or ranges into a single array of individual {@link DateCellIndex} values. * * @param input - Mix of raw indexes and ranges to flatten. * @returns A flat array of all individual DateCellIndex values. */ export declare function allIndexesInDateCellRangesToArray(input: (DateCellIndex | DateCellRange)[]): DateCellIndex[]; /** * Returns a deduplicated {@link Set} of all indexes within the input ranges. * * @param input - Mix of raw indexes and ranges to collect. * @returns Deduplicated DateCellIndex values covered by the inputs. */ export declare function allIndexesInDateCellRanges(input: (DateCellIndex | DateCellRange)[]): Set; /** * Filters the input blocks, returning only those that fall entirely within the given range. * * @param blocks - Cells or ranges to filter. * @param range - Bounding range that blocks must fall within. * @returns Only the blocks that fall entirely within the given range. */ export declare function filterDateCellsInDateCellRange(blocks: T[], range: DateCellRangeWithRange): T[]; /** * Accepted input types for range-containment checks: a raw index, a {@link DateCell}, or a {@link DateCellRange}. */ export type IsDateCellWithinDateCellRangeInput = DateCellOrDateCellIndexOrDateCellRange; /** * Function that returns true if the input range is equal or falls within the configured DateCellRange. */ export type IsDateCellWithinDateCellRangeFunction = (input: IsDateCellWithinDateCellRangeInput) => boolean; /** * Creates an {@link IsDateCellWithinDateCellRangeFunction} that tests whether a given cell or range * is fully contained within `inputRange`. * * @param inputRange - Bounding range candidates are compared against. * @returns Predicate that reports true when its argument fits entirely inside `inputRange`. * * @__NO_SIDE_EFFECTS__ */ export declare function isDateCellWithinDateCellRangeFunction(inputRange: IsDateCellWithinDateCellRangeInput): IsDateCellWithinDateCellRangeFunction; /** * Returns true if `contains` is fully within `range`. * * @param range - The outer bounding range. * @param contains - The cell or range to test for containment. * @returns True if `contains` is fully within `range` */ export declare function isDateCellWithinDateCellRange(range: IsDateCellWithinDateCellRangeInput, contains: IsDateCellWithinDateCellRangeInput): boolean; /** * Statistical information about the blocks in a set of date cell ranges. */ export interface DateCellRangeBlockCountInfo { /** * Total number of individual cell indexes across all ranges. */ readonly count: number; /** * Sum of all individual indexes. Used for calculating the average. */ readonly total: number; /** * The average block index (total / count), or 0 if count is 0. */ readonly average: number; } /** * Computes {@link DateCellRangeBlockCountInfo} (count, total, average) for the given date cell ranges. * * Internally groups overlapping ranges before counting so each index is counted only once. * * @param inputDateCellRange - One or more cells/ranges to analyze. * @returns Count, total, and average statistics for the given ranges. */ export declare function dateCellRangeBlocksCountInfo(inputDateCellRange: ArrayOrValue): DateCellRangeBlockCountInfo; /** * Counts the total number of individual cell indexes across the given date cell ranges. * * Shorthand for `dateCellRangeBlocksCountInfo(input).count`. * * @param inputDateCellRange - One or more cells/ranges to count. * @returns The total number of individual cell indexes. * * @example * ```ts * dateCellRangeBlocksCount({ i: 0, to: 4 }); // => 5 * dateCellRangeBlocksCount([{ i: 0, to: 2 }, { i: 10, to: 12 }]); // => 6 * ``` */ export declare function dateCellRangeBlocksCount(inputDateCellRange: ArrayOrValue): number; /** * Checks whether or not the input range is fully included by the configured ranges. */ export type DateCellRangesFullyCoverDateCellRangeFunction = (range: DateCellRange) => boolean; /** * Creates a {@link DateCellRangesFullyCoverDateCellRangeFunction} that checks whether any single * grouped range from `ranges` fully covers a given input range. * * @param ranges - Covering ranges to evaluate candidates against. * @returns Predicate that reports true when any single grouped range fully covers the input range. * * @__NO_SIDE_EFFECTS__ */ export declare function dateCellRangesFullyCoverDateCellRangeFunction(ranges: ArrayOrValue): DateCellRangesFullyCoverDateCellRangeFunction; /** * Input configuration for {@link getNextDateCellTimingIndex}. */ export interface GetNextDateCellTimingIndexInput { /** * The "current" index to evaluate against (typically represents "now"). */ readonly currentIndex: DateCellIndex; /** * All possible ranges to classify as past, present, or future relative to `currentIndex`. */ readonly ranges: ArrayOrValue; } /** * Result of {@link getNextDateCellTimingIndex}, classifying ranges relative to a current index * and identifying the next upcoming index/range. */ export interface GetNextDateCellTimingIndexResult { /** * The first range that contains the current index, if any. */ readonly currentResult: Maybe; /** * The next index after `currentIndex` that is covered by a range, or undefined if no future ranges exist. */ readonly nextIndex: Maybe; /** * The range that contains {@link nextIndex}, if available. */ readonly nextResult: Maybe; /** * All ranges that contain the current index (i.e., the index falls within their `i..to` span). */ readonly presentResults: T[]; /** * All ranges whose `to` is before the current index. */ readonly pastResults: T[]; /** * All ranges whose `i` is after the current index. */ readonly futureResults: T[]; } /** * Classifies the given ranges as past, present, or future relative to `currentIndex`, and determines * the next upcoming index. Useful for "what comes next" scheduling logic against date cell timings. * * If a present range continues past `currentIndex`, its next index is preferred. Otherwise the * nearest future range's starting index is used. * * @param input - The current index and ranges to evaluate. * @returns Classification of ranges as past/present/future and the next upcoming index. * * @example * ```ts * const result = getNextDateCellTimingIndex({ * currentIndex: 5, * ranges: [ * { i: 0, to: 3 }, // past * { i: 4, to: 7 }, // present (contains 5) * { i: 10, to: 12 } // future * ] * }); * // result.currentResult => { i: 4, to: 7 } * // result.nextIndex => 6 * // result.pastResults.length => 1 * ``` */ export declare function getNextDateCellTimingIndex(input: GetNextDateCellTimingIndexInput): GetNextDateCellTimingIndexResult; /** * Determines whether a range is in the past, present, or future relative to a given index. * * @param range - Range to classify. * @param nowIndex - Reference index representing "now". * @returns 'past', 'present', or 'future' depending on the range's position relative to `nowIndex`. */ export declare function dateRelativeStateForDateCellRangeComparedToIndex(range: DateCellRange, nowIndex: DateCellIndex): DateRelativeState; /** * Expands a {@link DateCellRange} into an array of individual single-cell copies, one per index * from `i` to `to` (inclusive). Each copy retains all properties of the original block. * * @param block - Range to expand into individual single-cell copies. * @returns One copy per index covered by the range, preserving the original payload. * * @example * ```ts * expandDateCellRange({ i: 2, to: 4, data: 'x' }); * // => [{ i: 2, to: 2, data: 'x' }, { i: 3, to: 3, data: 'x' }, { i: 4, to: 4, data: 'x' }] * ``` */ export declare function expandDateCellRange(block: B): B[]; /** * A DateCell that also has the potential for a unique identifier. */ export interface UniqueDateCell extends DateCell, UniqueModel { } /** * Represents a range of UniqueDateCell values keyed by a similar identifier (or lack of identifier). */ export interface UniqueDateCellRange extends UniqueDateCell, DateCellRange { } /** * Returns true if the input spans more than one cell (i.e., has a `to` value strictly greater than `i`). * * @param input - Range or cell to check. * @returns True if `to` is defined and strictly greater than `i` */ export declare function dateCellRangeHasRange(input: DateCellRange | UniqueDateCell): input is DateCellRangeWithRange; /** * Returns the effective ending index of a range: `to` if defined, otherwise `i`. * * @param input - Range or cell to read. * @returns The `to` index if defined, otherwise `i` */ export declare function dateCellEndIndex(input: DateCellRange | UniqueDateCell): IndexNumber; /** * A grouping of UniqueDateCell values, sorted by date range. */ export interface UniqueDateCellRangeGroup extends DateCellRange { /** * Blocks are sorted by index. */ blocks: B[]; } /** * Groups all input {@link DateCellRange} or {@link UniqueDateCell} values into a single * {@link UniqueDateCellRangeGroup}, sorting them by index. The group's `i` is always 0 * and `to` is the maximum ending index across all blocks. * * @param input - Cells or ranges to group. * @returns A UniqueDateCellRangeGroup containing the sorted blocks with `i` at 0. */ export declare function groupUniqueDateCells(input: B[]): UniqueDateCellRangeGroup; /** * Determines how to "fill" a DateRange when an empty range is detected. * - extend: extends the previous block to fill the range. * - fill: creates a new value using a factory. * - empty: skips the space */ export type ExpandUniqueDateCellsFillOption = 'extend' | 'fill' | 'empty'; /** * Determines how overwrite block values that are completely overlapping eachother. * - current: keeps the "current" value * - next: the next/new value overwrites the previous one */ export type ExpandUniqueDateCellsRetainOverlapOption = 'current' | 'next'; export interface ExpandUniqueDateCellsConfig { /** * The expected start index. * * If provided, will expand the first block to start at this index, and filter out any blocks that end before this index. */ readonly startAtIndex?: number; /** * The expected end index, inclusive. * * If provided, will expand the final block to end at this index, and filter out any blocks that start past this index. */ readonly endAtIndex?: number; /** * Determines how to fill empty ranges. */ readonly fillOption: ExpandUniqueDateCellsFillOption; /** * (Optional) Determines how to handle overwrites. * * - next: will retain the latest value (next) and overwrite the current value. * - current: will retain the current value and ignore any future values at that index. * * Defaults to next */ readonly retainOnOverlap?: ExpandUniqueDateCellsRetainOverlapOption; /** * Used to create new items to fill empty block sets. Required when mode is set to "fill". */ readonly fillFactory?: FactoryWithRequiredInput; } /** * Result of {@link ExpandUniqueDateCellsFunction}, containing the merged/expanded blocks * and any blocks that were fully discarded during the merge process. */ export interface ExpandUniqueDateCellsResult extends UniqueDateCellRangeGroup { /** * Blocks that were completely removed due to overlap resolution. Some blocks may be partially retained * (with adjusted `i`/`to`) and appear in `blocks` instead. */ discarded: B[]; } /** * Expansion function used to sort/merge/replace DateCellRange values by block. * * Can optionally specify a second array/group of blocks that are treated as "next" blocks which can take priority or not depending on the retain options. */ export type ExpandUniqueDateCellsFunction = (input: B[] | UniqueDateCellRangeGroup, newBlocks?: B[] | UniqueDateCellRangeGroup) => ExpandUniqueDateCellsResult; /** * Creates an {@link ExpandUniqueDateCellsFunction} that sorts, merges, and fills date cell ranges * according to the provided configuration. Handles overlap resolution, gap filling, and boundary clamping. * * @param config - Controls start/end bounds, fill strategy, and overlap retention behavior. * @returns Configured expander that merges, fills, and resolves overlaps in cell-range arrays. * @throws {Error} When `fillOption` is `'fill'` but no `fillFactory` is supplied. * * @example * ```ts * const expand = expandUniqueDateCellsFunction({ * fillOption: 'empty', * startAtIndex: 0, * endAtIndex: 10 * }); * * const result = expand([{ i: 2, to: 5 }, { i: 8, to: 10 }]); * // result.blocks => [{ i: 2, to: 5 }, { i: 8, to: 10 }] * ``` * * @__NO_SIDE_EFFECTS__ */ export declare function expandUniqueDateCellsFunction(config: ExpandUniqueDateCellsConfig): ExpandUniqueDateCellsFunction;