{"version":3,"sources":["../../src/date/orgFormat.ts"],"names":["validateDateFormat","validateTimeFormat","formatDateSafe","MS_PER_MINUTE","relativeTimePhrase"],"mappings":"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","file":"org-format.cjs","sourcesContent":["/**\n * Organisation-driven date/time DISPLAY formatting.\n *\n * Plugin (and host) surfaces render dates in the organisation's configured\n * format. This module holds the module-level format refs, the org-aware display\n * formatters, and the MUI X (dayjs) input-mask derivations. It is pure — no React,\n * no dayjs — so it lives in core-utils behind the\n * `@ethisyscore/core-utils/date/org-format` sub-path rather than the main barrel,\n * whose `formatDate` is the ISO `(date: Date) => string` helper, a different\n * contract from the org-aware `formatDate` exported here.\n *\n * The formatters do NOT re-implement parse/format/fallback: they resolve the\n * effective format (the org ref when grammar-valid, else the UK fallback) and\n * delegate to the shared `formatDateSafe` primitive. The refs are stamped by the\n * surface sync hook — the SDK `useOrgFormatSync` reads the\n * `ethisys:organisation-settings` reserved resource and calls `setOrgFormats`.\n * When no org format is set (or a stored value fails the shared token grammar)\n * formatters fall back to the deterministic UK default, NOT the OS locale, so\n * output is machine-stable regardless of the host.\n *\n * Consolidated from the per-plugin `adapter/shared/{orgFormatContextValue,dates}`\n * copies and the monolith's `dateUtils` mask helpers, which re-export from here\n * so every existing import path keeps working.\n */\nimport { MS_PER_MINUTE } from \"./constants\";\nimport { formatDateSafe, relativeTimePhrase } from \"./format\";\nimport { validateDateFormat, validateTimeFormat } from \"./formatValidation\";\n\n/** UK display fallback (date-fns tokens) — numeric `dd/MM/yyyy`. */\nexport const ORG_DATE_FALLBACK_FORMAT = \"dd/MM/yyyy\";\n/** UK time display fallback (date-fns tokens) — 24-hour `HH:mm`. */\nexport const ORG_TIME_FALLBACK_FORMAT = \"HH:mm\";\n\nconst EM_DASH = \"—\";\n\n// ---------------------------------------------------------------------------\n// Module-level format refs\n// ---------------------------------------------------------------------------\n\nlet orgDateFormatRef: string | null = null;\nlet orgTimeFormatRef: string | null = null;\n\n/** The org's preferred date-fns date format, or null to fall back to the UK default. */\nexport function getOrgDateFormat(): string | null {\n  return orgDateFormatRef;\n}\n\n/** The org's preferred date-fns time format, or null to fall back to the UK default. */\nexport function getOrgTimeFormat(): string | null {\n  return orgTimeFormatRef;\n}\n\n/**\n * Stamps the module-level date/time format refs. Called by the surface sync hook\n * each time organisation settings resolve. Pass `null` for either argument to\n * clear that format and fall back to the deterministic UK default.\n */\nexport function setOrgFormats(dateFormat: string | null, timeFormat: string | null): void {\n  orgDateFormatRef = dateFormat;\n  orgTimeFormatRef = timeFormat;\n}\n\n// ---------------------------------------------------------------------------\n// Effective format resolution\n//\n// The grammar gate (validateDateFormat/validateTimeFormat) is what catches the\n// `tt` gotcha — `tt` is date-fns's seconds-timestamp token, not .NET AM/PM, so it\n// renders garbage rather than throwing — before a bad stored format reaches\n// date-fns. A non-grammar (legacy .NET) token therefore degrades to the UK default.\n// ---------------------------------------------------------------------------\n\n/** The org's effective date format: the configured override when grammar-valid, else the UK `dd/MM/yyyy` fallback. */\nexport function resolveOrgDateFormat(): string {\n  const fmt = getOrgDateFormat();\n  return fmt && validateDateFormat(fmt).valid ? fmt : ORG_DATE_FALLBACK_FORMAT;\n}\n\n/** The org's effective time format: the configured override when grammar-valid, else the UK `HH:mm` fallback. */\nexport function resolveOrgTimeFormat(): string {\n  const fmt = getOrgTimeFormat();\n  return fmt && validateTimeFormat(fmt).valid ? fmt : ORG_TIME_FALLBACK_FORMAT;\n}\n\n// ---------------------------------------------------------------------------\n// Org-aware display formatters (delegate to formatDateSafe)\n// ---------------------------------------------------------------------------\n\n/**\n * Formats a date/ISO string for display in the org's dateFormat (UK `dd/MM/yyyy`\n * fallback) — never the OS locale. Returns em-dash for falsy/invalid.\n */\nexport function formatDate(dateStr?: string | null): string {\n  return formatDateSafe(dateStr, resolveOrgDateFormat(), EM_DASH);\n}\n\n/**\n * Formats a date/ISO string with time in the org's date+time formats (UK\n * `dd/MM/yyyy HH:mm` fallback). Returns em-dash for falsy/invalid.\n */\nexport function formatDateTime(dateStr?: string | null): string {\n  const datePart = formatDateSafe(dateStr, resolveOrgDateFormat(), EM_DASH);\n  if (datePart === EM_DASH) return EM_DASH;\n  return `${datePart} ${formatDateSafe(dateStr, resolveOrgTimeFormat(), EM_DASH)}`;\n}\n\n/**\n * Extracts the time portion from an ISO datetime string in the org's timeFormat\n * (UK `HH:mm` fallback). A bare `HH:mm`/`HH:mm:ss` value (no date component) is\n * anchored to a fixed date and rendered in the org's time format too — a 12-hour\n * org turns `14:30` into `2:30 PM`, it is NOT passed straight through. Returns\n * em-dash for falsy values, and the original string for anything that is neither\n * ISO nor a bare `HH:mm(:ss)`.\n */\nexport function formatTime(timeStr?: string | null): string {\n  if (!timeStr) return EM_DASH;\n  if (timeStr.includes(\"T\")) {\n    return formatDateSafe(timeStr, resolveOrgTimeFormat(), EM_DASH);\n  }\n  // A bare \"HH:mm\" / \"HH:mm:ss\" carries no date, so anchor it to a fixed date and\n  // render it in the org's time format — a 12-hour org format must still turn\n  // \"14:30\" into \"2:30 PM\", not pass the 24-hour value straight through. Match,\n  // anchor and fall back on ONE trimmed value so a padded input (\" 14:30 \") is\n  // converted too rather than building an invalid anchored string that silently\n  // bypasses the org conversion.\n  const trimmed = timeStr.trim();\n  const parts = /^(\\d{2}):(\\d{2})(:\\d{2})?$/.exec(trimmed);\n  if (!parts) return timeStr;\n  const anchored = `2000-01-01T${parts[3] ? trimmed : `${trimmed}:00`}`;\n  return formatDateSafe(anchored, resolveOrgTimeFormat(), trimmed);\n}\n\n/**\n * Formats a date/ISO string in the org's dateFormat (UK fallback), or returns\n * `\"Present\"` for falsy/invalid values. Use for open-ended ranges where a missing\n * end date means \"still active\" — distinct from {@link formatDate} which returns em-dash.\n */\nexport function formatDateOrPresent(dateStr?: string | null): string {\n  if (!dateStr) return \"Present\";\n  return formatDateSafe(dateStr, resolveOrgDateFormat(), \"Present\");\n}\n\n/**\n * Returns a short relative-time phrase — \"Just now\", \"5m ago\", \"3h ago\", \"2d ago\" —\n * or the absolute org-formatted datetime for anything older than a week. Returns\n * em-dash for falsy/unparseable values. `now` is injectable for tests.\n *\n * The org-aware sibling of core-utils `formatTimeAgo`, which shares the tier ladder\n * but falls back to the ISO date (not the org format) and returns \"\" for empty.\n */\nexport function formatRelativeTime(dateStr?: string | null, now: Date = new Date()): string {\n  if (!dateStr) return EM_DASH;\n  const then = new Date(dateStr).getTime();\n  if (Number.isNaN(then)) return EM_DASH;\n  const diffMinutes = Math.floor((now.getTime() - then) / MS_PER_MINUTE);\n  // Shares the tier ladder with core-utils `formatTimeAgo`; the only difference is\n  // the older-than-a-week fallback (org datetime here vs the plain ISO date there).\n  return relativeTimePhrase(diffMinutes) ?? formatDateTime(dateStr);\n}\n\n// ---------------------------------------------------------------------------\n// MUI X (dayjs) input-mask derivations\n// ---------------------------------------------------------------------------\n\n/** Converts one letter-run token from date-fns to dayjs (families that differ; others pass through). */\nfunction convertTokenRun(run: string): string {\n  switch (run[0]) {\n    case \"y\":\n      return \"Y\".repeat(run.length); // yyyy -> YYYY, yy -> YY\n    case \"d\":\n      return \"D\".repeat(run.length); // dd -> DD, d -> D\n    case \"a\":\n      return \"A\"; // date-fns AM/PM -> dayjs AM/PM\n    case \"E\":\n      // date-fns weekday widths -> dayjs: full (EEEE) -> dddd, short (E-EEE) -> ddd.\n      return run.length >= 4 ? \"dddd\" : \"ddd\";\n    default:\n      return run; // M, H, h, m, s and any other letter run are identical\n  }\n}\n\n/**\n * Converts a date-fns format string to the equivalent dayjs tokens. Only four token\n * families differ — year (`y`->`Y`), day-of-month (`d`->`D`), weekday (`E`->`d…`)\n * and meridiem (`a`->`A`); month, hour, minute and second are identical.\n *\n * Quoted literals are handled properly rather than blindly regex-replaced: date-fns\n * escapes literal text with single quotes (`dd 'day' MMM` renders a literal \"day\"),\n * which must NOT have its letters rewritten and must become a dayjs bracket literal\n * (`[day]`); `''` is a literal apostrophe.\n */\nexport function dateFnsToDayjsFormat(fmt: string): string {\n  let out = \"\";\n  let i = 0;\n  while (i < fmt.length) {\n    const ch = fmt[i];\n    if (ch === \"'\") {\n      // Consume a quoted literal span; '' inside it is an escaped apostrophe.\n      i++;\n      let literal = \"\";\n      while (i < fmt.length) {\n        if (fmt[i] === \"'\") {\n          if (fmt[i + 1] === \"'\") {\n            literal += \"'\";\n            i += 2;\n            continue;\n          }\n          i++;\n          break;\n        }\n        literal += fmt[i];\n        i++;\n      }\n      out += literal === \"\" ? \"[']\" : `[${literal}]`;\n      continue;\n    }\n    if (/[a-zA-Z]/.test(ch)) {\n      let run = ch;\n      while (i + 1 < fmt.length && fmt[i + 1] === ch) {\n        run += fmt[i + 1];\n        i++;\n      }\n      out += convertTokenRun(run);\n      i++;\n      continue;\n    }\n    out += ch;\n    i++;\n  }\n  return out;\n}\n\n/**\n * The org's date mask as dayjs tokens for a MUI X date picker — the effective\n * date format converted to dayjs tokens, so the UK fallback yields `DD/MM/YYYY`.\n * Mirrors {@link formatDate} so an editable input shows the read-only format.\n */\nexport function getOrgDateInputFormat(): string {\n  return dateFnsToDayjsFormat(resolveOrgDateFormat());\n}\n\n/**\n * The org's date+time mask as dayjs tokens for a datetime picker, combining\n * {@link getOrgDateInputFormat} with the effective time format (UK fallback yields `HH:mm`).\n */\nexport function getOrgDateTimeInputFormat(): string {\n  return `${getOrgDateInputFormat()} ${dateFnsToDayjsFormat(resolveOrgTimeFormat())}`;\n}\n"]}