cell-values.ts2.1 KBView on GitHub
/**
 * How a typed column's STRING value is read.
 *
 * Every cell is stored as a string, in the form the server's Excel writer already reads
 * (`apps/server/src/services/documents/table/table-excel.ts`). These coercions are the only
 * place that form is interpreted, because both the display (`CellDisplay`) and the editors
 * (`TypedCells`) have to agree about it — a checkbox that reads `✓` as unchecked while the
 * agent that wrote it meant checked is a disagreement no test of either half would catch.
 *
 * Kept in its own module rather than in `TypedCells` so the display can import it without
 * importing the editors, which import the display.
 */

import { readCellBoolean, readCellDate } from '@zero/server/table/sort';

/** The default `column.format` for a date column, matching the server-side schema default. */
export const DEFAULT_DATE_FORMAT = 'yyyy-MM-dd';

/** How a `multi_select` cell joins its selected options. One place, both directions. */
export const MULTI_SELECT_SEPARATOR = ', ';

/**
 * Checked, per the one vocabulary — `table-sort.ts`, which the Excel writer and the comparator
 * both read through as well.
 *
 * This used to be a local copy annotated "mirrors the server's truthy set", and the two had
 * already drifted. A cell that displays as unchecked while the sort ranks it as checked is a
 * disagreement no test of either half would catch, which is precisely the failure this module's
 * header claims not to have.
 */
export function isCheckedValue(value: string): boolean {
  return readCellBoolean(value) === true;
}

export function splitMultiSelect(value: string): string[] {
  return value
    .split(',')
    .map((part) => part.trim())
    .filter(Boolean);
}

/**
 * Tolerant parse: the column's own format first, then anything `Date` accepts.
 *
 * The same reader the comparator uses, so the day a cell DISPLAYS and the day it SORTS as
 * cannot differ — which they would for a `dd/MM/yyyy` column, where `new Date('03/04/2026')`
 * is the 4th of March and the column means the 3rd of April.
 */
export function parseCellDate(value: string, pattern: string): Date | null {
  return readCellDate(value, pattern);
}