/** * Worksheet sort state (`CT_SortState` / `CT_SortCondition`). * * Citations: * - ECMA-376-1 5th ed. §18.3.1.91 `sortCondition`, §18.3.1.92 `sortState` * - transitional sml.xsd `CT_SortState` ~L151–160, `CT_SortCondition` * ~L161–171, `ST_SortBy` ~L172–179, `ST_SortMethod` ~L181–187 * - `CT_Worksheet` sequence: `autoFilter` → **`sortState`** → * `dataConsolidate` (~L2182–2186) * - docs/requirements/sort-state.md; docs/specs/sort-state.md; * docs/ooxml-mapping/sort-state.md * * This feature is the **state record** Excel persists after a user sort. * It never sorts, moves, or rewrites cell data. Unsupported content * (unknown attributes/children, `extLst`, unparsable refs, `sortCondition` * overflow beyond the schema's `maxOccurs="64"`) round-trips opaquely in * relative order; invalid lexical forms stay untouched on no-op saves. */ import { CellRange } from '../address/cell-address'; import { IconSetType } from './conditional-formatting'; /** * Specifies what a sort level compares — cell values, cell colors, font * colors, or icons. */ export declare type SortBy = 'value' | 'cellColor' | 'fontColor' | 'icon'; /** Specifies the collation method used when sorting East-Asian text. */ export declare type SortMethod = 'stroke' | 'pinYin' | 'none'; /** * Represents one sort level in a recorded sort, letting you set its * direction and what it compares, such as cell values or colors. * * Mutating setters mark the sheet dirty. Authoring keeps at most one * modeled condition (each {@link DataSorter.add} replaces prior entries); * loaded multi-condition records keep file order (§18.3.1.91). */ export interface SortCondition { /** * The part of the data the condition sorts, written as an A1-style * reference (e.g. `'A1:C10'`). Authored conditions always match the parent * {@link DataSorter.range}; on load, foreign files may use a narrower key * column inside that range. */ readonly range: string; /** * Whether the sort goes from highest to lowest instead of lowest to * highest. Default `false`. */ isDescending: boolean; /** * What the sort compares when ordering entries — normal cell values * (`'value'`, the default) or their formatting (`'cellColor'`, * `'fontColor'`, `'icon'`). */ sortBy: SortBy; /** * A custom order to sort by, given as a comma-separated list — for * example `'Low,Medium,High'` — or `undefined` for none. Stored as * text and never evaluated. */ customList: string | undefined; /** * Raw `dxfId` read from the file when `sortBy` is a color sort; * `undefined` when absent. Data only — this feature never allocates or * renumbers stylesheet `dxfs`. * @private Preserved OOXML metadata; not part of the application-facing * sorting API. */ readonly dxfId: number | undefined; /** * Icon set family when `@iconSet` is present (`CT_SortCondition/@iconSet`, * schema default `3Arrows`); `undefined` when the attribute is absent. * @private Preserved OOXML metadata; not part of the application-facing * sorting API. */ readonly iconSet: IconSetType | undefined; /** * Zero-based icon index (`@iconId`) or `undefined` when absent. * @private Preserved OOXML metadata; not part of the application-facing * sorting API. */ readonly iconId: number | undefined; } /** * Represents the sort settings recorded for a range of cells, letting you * define how its rows or columns should be ordered. */ export interface DataSorter { /** * The range of data to sort, written as an A1-style reference * (e.g. `'A1:C10'`). The sort conditions defined on this sorter apply to * this same range. */ readonly range: string; /** * Whether the sort rearranges columns (left to right) instead of rows * (top to bottom). Default `false`. */ isColumnSort: boolean; /** * Whether the sort treats uppercase and lowercase letters as different * when comparing text. Default `false`. */ isCaseSensitive: boolean; /** * Internal OOXML collation method (`CT_SortState/@sortMethod`). Preserved * during load/save but not part of the application-facing sorting API. * @private */ sortMethod: SortMethod; /** * The number of sort conditions currently defined on this sorter, in the * order they apply. */ readonly count: number; /** * Get all current sort conditions as a list, in the order they apply. * * @returns the current sort conditions. */ list(): ReadonlyArray; /** * Define the sort condition for this sorter, which sorts the given cell * range. Any previously defined conditions are removed first, so the new * condition is the only one that applies. * * @param range - The range of data to sort, as an A1-style reference * (e.g. `'A1:C10'`). * @returns the newly created sort condition — set its direction, * comparison, and custom order on the returned handle. * @throws InvalidArgumentError when `range` is empty or not a string * @throws InvalidSortStateError when `range` is not a valid A1 range */ add(range: string): SortCondition; /** * Get the sort condition at a zero-based position, in the order the * conditions apply. * * @param index - The zero-based position of the sort condition. * @returns the sort condition at `index`. * @throws InvalidArgumentError when the index is out of range */ get(index: number): SortCondition; /** * Remove a sort condition previously returned by this sorter. * * @param condition - The sort condition to remove. * @throws InvalidArgumentError when the condition was not created by this * sorter, or no longer belongs to it (for example after its state was * replaced or the workbook reloaded) */ remove(condition: SortCondition): void; /** * Remove the sort condition at a zero-based position. * * @param index - The zero-based position of the sort condition to remove. * @throws InvalidArgumentError when the index is out of range */ removeAt(index: number): void; /** * Remove every sort condition from this sorter. The sorter itself and its * settings are kept. */ clear(): void; } /** * Internal modeled `CT_SortCondition` entry. * * Tri-state booleans: `undefined` = attribute absent (XSD default); * explicit `true`/`false` round-trip their lexical form. * @private */ export interface SortConditionEntry { readonly range: CellRange; readonly descending: boolean | undefined; readonly sortBy: SortBy | undefined; readonly customList: string | undefined; readonly dxfId: number | undefined; readonly iconSet: IconSetType | undefined; readonly iconId: number | undefined; /** Extra attributes (unknown, plus invalid lexicals excluded from model). */ readonly extraAttrsXml: string; /** * Whole-element backup for an unparsable-but-preserved condition: emits * verbatim, never exposed in the public list. Modeled entries have * `undefined` (they own their fields + `extraAttrsXml`). */ readonly xml: string | undefined; } /** * Wire model for the worksheet-level `sortState` element. * @private */ export interface SortStateModel { readonly present: boolean; /** Parsed `CT_SortState/@ref` (required attr). */ readonly range: CellRange | undefined; readonly columnSort: boolean | undefined; readonly caseSensitive: boolean | undefined; readonly sortMethod: SortMethod | undefined; /** Modeled conditions (≤ 64 on load; application/file order). */ readonly conditions: ReadonlyArray; /** * Opaque children in relative order: `extLst`, unknown children, the * modeled-overflow `sortCondition` count beyond `maxOccurs="64"`, and * unparsable conditions kept verbatim. */ readonly extraChildrenXml: ReadonlyArray; /** Extra attributes (unknown, plus invalid lexicals excluded from model). */ readonly extraAttrsXml: string; /** * Whole-element backup when the root `ref` is unparsable-but-preserved: * emits verbatim; public `dataSorter` reads as `undefined`. Modeled states * have `undefined`. */ readonly xml: string | undefined; } /** * Host notifications for sort-state mutations. * @private */ export interface SortStateHost { markDirty(): void; } /** * Mutable sort-state store owning the modeled conditions and flags. * Live handles stay valid across index shifts (the owner re-points them on * removal) and die on model replacement (`addDataSorter` on the same sheet, * reload, whole-state removal) via a generation token. * @private */ export declare class SortStateImpl implements DataSorter { private model; private host; /** * Generation token bumped on every model replacement (`authorState`, * `replaceFromParse`, `clearState`, `set authorState`-equivalent paths). * Handles minted against an older generation refuse to mutate — a replaced * or reloaded state must never accept writes through stale handles. */ private generation; constructor(initial?: SortStateModel); /** @private */ bindHost(host: SortStateHost): void; /** @private */ readonly isPresent: boolean; /** * Current generation for handle-minting (internal). * @private */ readonly currentGeneration: number; readonly range: string; isColumnSort: boolean; isCaseSensitive: boolean; /** @private Preserved OOXML collation metadata. */ /** @private Preserved OOXML collation metadata. */ sortMethod: SortMethod; readonly count: number; list(): ReadonlyArray; add(range: string): SortCondition; get(index: number): SortCondition; remove(condition: SortCondition): void; removeAt(index: number): void; clear(): void; /** * Replace contents from parse (does not mark dirty). Kills live handles: * the reloaded model is a different record set. * @private */ replaceFromParse(model: SortStateModel | undefined): void; /** * Author a fresh state, replacing any existing record (the schema allows * at most one `sortState` per worksheet). Kills live handles from the * replaced record. * @private */ authorState(rangeText: string): void; /** * Remove the state entirely; the element stops being emitted on save. * Kills live handles. * @private */ clearState(): void; /** * Snapshot for serialize. * @private */ toModel(): SortStateModel; /** * Mutate one modeled condition by index (host handle writer). * @private */ writeConditionMutation(index: number, mutate: (entry: SortConditionEntry) => SortConditionEntry, isNoOp: boolean): void; private assertPresent; /** Live handles minted against the current generation, by index. */ private readonly handles; private mintHandle; /** Drop every live handle (called on model replacement). */ private detachLiveHandles; /** * After removal at `removedIndex`, shift still-live handles above it * down one and detach the removed index's handles. */ private retargetHandlesAfterRemoval; /** * Remove a live handle from the registry (its own `remove` completed). * @private */ unregisterHandle(handle: SortConditionHandle): void; private modelRange; } /** * CT_Worksheet locals that appear **before** `sortState` after `sheetData` * (schema sequence order; `autoFilter` is the nearest predecessor). */ export declare const SORT_STATE_PREDECESSORS: ReadonlyArray; /** * CT_Worksheet locals that appear **after** `sortState`. */ export declare const SORT_STATE_SUCCESSORS: ReadonlyArray; /** * Index at which to insert the serialized `sortState` among after-sheetData * siblings. Prefer: after the last known predecessor present; else before * the first known successor; else append. Unknown elements keep relative order. */ export declare function findSortStateInsertIndex(afterSheetDataLocals: ReadonlyArray): number; /** * Parse a worksheet-level `sortState` element. * Unparsable root ref → whole-element opaque backup (`present: false`, * `xml` set) so a no-op save preserves it. Invalid modeled-attribute * lexicals stay in `extraAttrsXml` verbatim. * * @private */ export declare function parseSortStateXml(sortStateXml: string): SortStateModel; /** * Serialize a sort-state model, or `undefined` when absent and no backup. * Attribute order follows the XSD declaration order; children are modeled * conditions then opaque preserves in relative order. * * @private */ export declare function serializeSortStateXml(model: SortStateModel): string | undefined; /** * Live per-condition handle bound to its owning {@link SortStateImpl} by * index and generation. Route mutations through the owning state so model * snapshots stay the single source of truth. Handles survive index shifts * (the owning state re-points them) and die on model replacement / removal. * @private */ declare class SortConditionHandle implements SortCondition { /** Owning state token for cross-state `remove` rejection. */ readonly state: SortStateImpl; private readonly owner; /** Generation this handle was minted against. */ private readonly generation; private index; private detached; constructor(owner: SortStateImpl, index: number, generation: number); readonly range: string; isDescending: boolean; sortBy: SortBy; customList: string | undefined; /** * Preserved OOXML metadata (`CT_SortCondition/@dxfId`). Read-only load * data; not part of the application-facing sorting API. * @private */ readonly dxfId: number | undefined; /** * Preserved OOXML metadata (`CT_SortCondition/@iconSet`). Read-only load * data; not part of the application-facing sorting API. * @private */ readonly iconSet: IconSetType | undefined; /** * Preserved OOXML metadata (`CT_SortCondition/@iconId`). Read-only load * data; not part of the application-facing sorting API. * @private */ readonly iconId: number | undefined; /** * Detach this handle from the owning state and remove its condition. * @private */ remove(): void; /** * Generation/attachment check used by {@link SortStateImpl.remove} before * delegating: rejects handles from a replaced or reloaded state. * @private */ assertSameGeneration(): void; /** * Owner callback after a removal at `removedIndex`: shift this handle's * index down when it sat above the removal; detach when it WAS the removal * target (detached handles are filtered from the registry lazily). * @private */ shiftForRemovalAt(removedIndex: number): void; private assertNotDetached; } export {};