@datakable/core 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +3 -2
  2. package/dist/{codes-B9bCK73-.d.cts → codes-4sYQv_7J.d.cts} +42 -12
  3. package/dist/{codes-B9bCK73-.d.ts → codes-4sYQv_7J.d.ts} +42 -12
  4. package/dist/column-filters.d.cts +2 -2
  5. package/dist/column-filters.d.ts +2 -2
  6. package/dist/diagnostics/build.cjs +1 -1
  7. package/dist/diagnostics/build.cjs.map +1 -1
  8. package/dist/diagnostics/build.js +2 -2
  9. package/dist/diagnostics/build.js.map +1 -1
  10. package/dist/diagnostics/console.cjs +15 -4
  11. package/dist/diagnostics/console.cjs.map +1 -1
  12. package/dist/diagnostics/console.js +15 -4
  13. package/dist/diagnostics/console.js.map +1 -1
  14. package/dist/diagnostics/explain.cjs.map +1 -1
  15. package/dist/diagnostics/explain.js.map +1 -1
  16. package/dist/diagnostics/hub.cjs +7 -1
  17. package/dist/diagnostics/hub.cjs.map +1 -1
  18. package/dist/diagnostics/hub.js +7 -1
  19. package/dist/diagnostics/hub.js.map +1 -1
  20. package/dist/diagnostics/prose.cjs +10 -1
  21. package/dist/diagnostics/prose.cjs.map +1 -1
  22. package/dist/diagnostics/prose.js +9 -1
  23. package/dist/diagnostics/prose.js.map +1 -1
  24. package/dist/diagnostics/redact.cjs +1 -1
  25. package/dist/diagnostics/redact.cjs.map +1 -1
  26. package/dist/diagnostics/redact.js +1 -1
  27. package/dist/diagnostics/redact.js.map +1 -1
  28. package/dist/diagnostics/types.cjs.map +1 -1
  29. package/dist/{explain-i0OATi_W.d.ts → explain-DmwN_RG9.d.cts} +13 -6
  30. package/dist/{explain-Q8Cg0cZy.d.cts → explain-Dr3SmMNY.d.ts} +13 -6
  31. package/dist/feature/install.cjs +2 -1
  32. package/dist/feature/install.cjs.map +1 -1
  33. package/dist/feature/install.js +2 -1
  34. package/dist/feature/install.js.map +1 -1
  35. package/dist/feature/slice-guard.cjs +76 -0
  36. package/dist/feature/slice-guard.cjs.map +1 -0
  37. package/dist/feature/slice-guard.js +50 -0
  38. package/dist/feature/slice-guard.js.map +1 -0
  39. package/dist/features/column-filters/codes.cjs +2 -19
  40. package/dist/features/column-filters/codes.cjs.map +1 -1
  41. package/dist/features/column-filters/codes.js +2 -19
  42. package/dist/features/column-filters/codes.js.map +1 -1
  43. package/dist/features/column-filters/column-filters.cjs +37 -22
  44. package/dist/features/column-filters/column-filters.cjs.map +1 -1
  45. package/dist/features/column-filters/column-filters.js +37 -22
  46. package/dist/features/column-filters/column-filters.js.map +1 -1
  47. package/dist/features/column-filters/match.cjs +6 -2
  48. package/dist/features/column-filters/match.cjs.map +1 -1
  49. package/dist/features/column-filters/match.js +6 -2
  50. package/dist/features/column-filters/match.js.map +1 -1
  51. package/dist/features/pagination/pagination.cjs +2 -2
  52. package/dist/features/pagination/pagination.cjs.map +1 -1
  53. package/dist/features/pagination/pagination.js +2 -2
  54. package/dist/features/pagination/pagination.js.map +1 -1
  55. package/dist/features/search/codes.cjs +18 -2
  56. package/dist/features/search/codes.cjs.map +1 -1
  57. package/dist/features/search/codes.js +16 -1
  58. package/dist/features/search/codes.js.map +1 -1
  59. package/dist/features/search/search-engine.cjs +24 -5
  60. package/dist/features/search/search-engine.cjs.map +1 -1
  61. package/dist/features/search/search-engine.js +25 -6
  62. package/dist/features/search/search-engine.js.map +1 -1
  63. package/dist/features/sorting/sorting.cjs +55 -24
  64. package/dist/features/sorting/sorting.cjs.map +1 -1
  65. package/dist/features/sorting/sorting.js +55 -24
  66. package/dist/features/sorting/sorting.js.map +1 -1
  67. package/dist/index.d.cts +26 -17
  68. package/dist/index.d.ts +26 -17
  69. package/dist/intercept/runtime.cjs +3 -2
  70. package/dist/intercept/runtime.cjs.map +1 -1
  71. package/dist/intercept/runtime.js +3 -2
  72. package/dist/intercept/runtime.js.map +1 -1
  73. package/dist/messages/index.cjs +2 -0
  74. package/dist/messages/index.cjs.map +1 -1
  75. package/dist/messages/index.js +2 -0
  76. package/dist/messages/index.js.map +1 -1
  77. package/dist/pagination.d.cts +2 -2
  78. package/dist/pagination.d.ts +2 -2
  79. package/dist/schema.d.cts +2 -2
  80. package/dist/schema.d.ts +2 -2
  81. package/dist/{search-async-entry-CuLYPfY_.d.cts → search-async-entry-BiemO3JT.d.cts} +2 -2
  82. package/dist/{search-async-entry-Cx7xpuVZ.d.ts → search-async-entry-GRj0E06n.d.ts} +2 -2
  83. package/dist/search-async.d.cts +3 -3
  84. package/dist/search-async.d.ts +3 -3
  85. package/dist/search.d.cts +4 -4
  86. package/dist/search.d.ts +4 -4
  87. package/dist/server.d.cts +3 -3
  88. package/dist/server.d.ts +3 -3
  89. package/dist/sorting.d.cts +2 -2
  90. package/dist/sorting.d.ts +2 -2
  91. package/dist/source/async-control.cjs +2 -1
  92. package/dist/source/async-control.cjs.map +1 -1
  93. package/dist/source/async-control.js +2 -1
  94. package/dist/source/async-control.js.map +1 -1
  95. package/dist/source/fetcher.cjs.map +1 -1
  96. package/dist/source/fetcher.js.map +1 -1
  97. package/dist/source/server.cjs +58 -5
  98. package/dist/source/server.cjs.map +1 -1
  99. package/dist/source/server.js +58 -5
  100. package/dist/source/server.js.map +1 -1
  101. package/dist/table/create-table.cjs +30 -20
  102. package/dist/table/create-table.cjs.map +1 -1
  103. package/dist/table/create-table.js +30 -20
  104. package/dist/table/create-table.js.map +1 -1
  105. package/dist/table/index.cjs +3 -0
  106. package/dist/table/index.cjs.map +1 -1
  107. package/dist/table/index.js +5 -1
  108. package/dist/table/index.js.map +1 -1
  109. package/dist/table/state-codes.cjs +72 -0
  110. package/dist/table/state-codes.cjs.map +1 -0
  111. package/dist/table/state-codes.js +45 -0
  112. package/dist/table/state-codes.js.map +1 -0
  113. package/dist/table/types.cjs.map +1 -1
  114. package/dist/table/types.js.map +1 -1
  115. package/dist/validity.d.cts +2 -2
  116. package/dist/validity.d.ts +2 -2
  117. package/dist/version.cjs +1 -1
  118. package/dist/version.cjs.map +1 -1
  119. package/dist/version.js +1 -1
  120. package/dist/version.js.map +1 -1
  121. package/package.json +1 -1
  122. package/dist/ingest/test-schemas.cjs +0 -73
  123. package/dist/ingest/test-schemas.cjs.map +0 -1
  124. package/dist/ingest/test-schemas.js +0 -46
  125. package/dist/ingest/test-schemas.js.map +0 -1
@@ -1,20 +1,23 @@
1
1
  // src/features/search/search-engine.ts
2
2
  import { keepDiagnostics } from "../../diagnostics/catalog.js";
3
+ import "../../diagnostics/process-guard.js";
3
4
  import { describeValue } from "../../diagnostics/redact.js";
4
5
  import { resolveRowKeys } from "../../ingest/row-key.js";
5
6
  import { errorName } from "../../intercept/classify.js";
6
7
  import { requestsOf } from "../../source/requests.js";
7
8
  import { getTableInternals } from "../../table/internals.js";
8
- import { searchDiagnostics } from "./codes.js";
9
+ import { searchDiagnostics, unknownKeysDiagnostics } from "./codes.js";
9
10
  import {
10
11
  APPLIED,
11
12
  SUPERSEDED
12
13
  } from "./search-fn-brand.js";
13
14
  keepDiagnostics(searchDiagnostics);
15
+ keepDiagnostics(unknownKeysDiagnostics);
14
16
  var EMPTY = [];
15
17
  var ERROR = Object.freeze({ status: "error" });
16
18
  var NO_KEYS = () => {
17
19
  };
20
+ var SAMPLE = 5;
18
21
  var SearchFailure = class {
19
22
  constructor(error) {
20
23
  this.error = error;
@@ -40,34 +43,43 @@ function createSearchEngine(fn) {
40
43
  function indicesOf(a, data, rowKey) {
41
44
  const c = a.cache;
42
45
  if (c && c.data === data && c.rowKey === rowKey) return c.indices;
43
- let map;
46
+ let find;
44
47
  let list;
45
48
  if ("rows" in a.hits) {
46
49
  list = a.hits.rows;
47
- map = positions.get(data) ?? /* @__PURE__ */ new Map();
50
+ const map = positions.get(data) ?? /* @__PURE__ */ new Map();
48
51
  if (!positions.has(data)) {
49
52
  for (let i = 0; i < data.length; i++) if (!map.has(data[i])) map.set(data[i], i);
50
53
  positions.set(data, map);
51
54
  }
55
+ find = (v) => map.get(v);
52
56
  } else {
53
57
  list = a.hits.keys;
54
58
  if (!keyIndex || keyIndex.data !== data || keyIndex.rowKey !== rowKey) {
55
59
  const keyOf = resolveRowKeys(data, rowKey, NO_KEYS, NO_KEYS);
56
60
  const m = /* @__PURE__ */ new Map();
57
61
  for (let i = 0; i < data.length; i++) {
58
- const k = keyOf(data[i], i);
62
+ const k = String(keyOf(data[i], i));
59
63
  if (!m.has(k)) m.set(k, i);
60
64
  }
61
65
  keyIndex = { data, rowKey, map: m };
62
66
  }
63
- map = keyIndex.map;
67
+ const map = keyIndex.map;
68
+ find = (v) => map.get(String(v));
64
69
  }
65
70
  const out = new Uint32Array(list.length);
66
71
  let n = 0;
72
+ let unknown;
67
73
  for (const v of list) {
68
- const i = map.get(v);
74
+ const i = find(v);
69
75
  if (i !== void 0) out[n++] = i;
76
+ else if (process.env.NODE_ENV !== "production" && "keys" in a.hits) {
77
+ unknown ??= { count: 0, returned: list.length, keys: [] };
78
+ unknown.count++;
79
+ if (unknown.keys.length < SAMPLE) unknown.keys.push(v);
80
+ }
70
81
  }
82
+ if (process.env.NODE_ENV !== "production") a.unknown = unknown;
71
83
  const indices = out.subarray(0, n);
72
84
  a.cache = { data, rowKey, indices };
73
85
  return indices;
@@ -185,6 +197,13 @@ function createSearchEngine(fn) {
185
197
  }
186
198
  };
187
199
  checks.set(table, () => {
200
+ if (process.env.NODE_ENV !== "production") {
201
+ const u = results.get(table);
202
+ if (u?.unknown && !dead) {
203
+ ctx.emit("DK_SEARCH_UNKNOWN_KEYS", u.unknown);
204
+ u.unknown = void 0;
205
+ }
206
+ }
188
207
  if (scheduled || dead) return;
189
208
  const query = applied();
190
209
  if (query.trim() === "") return;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/features/search/search-engine.ts"],"sourcesContent":["import { keepDiagnostics } from '../../diagnostics/catalog'\nimport { describeValue } from '../../diagnostics/redact'\nimport type { RowModelContext } from '../../feature/types'\nimport { resolveRowKeys } from '../../ingest/row-key'\nimport { errorName } from '../../intercept/classify'\nimport type { RowKey } from '../../pipeline/row'\nimport type { AsyncStatus } from '../../source/async-control'\nimport { requestsOf } from '../../source/requests'\nimport { getTableInternals } from '../../table/internals'\nimport { searchDiagnostics } from './codes'\nimport {\n APPLIED,\n type SearchEngine,\n type SearchFn,\n type SearchFnContext,\n type SearchHost,\n type SearchOutcome,\n type SearchSession,\n SUPERSEDED,\n type Waiter,\n} from './search-fn-brand'\n\nkeepDiagnostics(searchDiagnostics)\n\nconst EMPTY: readonly never[] = []\nconst ERROR: SearchOutcome = Object.freeze({ status: 'error' })\nconst NO_KEYS = () => {}\n\n/** A `searchFn` that rejected or threw: resolved as a value so asyncControl reports 'applied'. */\nclass SearchFailure {\n constructor(readonly error: unknown) {}\n}\n\nconst isAbortError = (e: unknown) =>\n e != null && typeof e === 'object' && (e as { name?: unknown }).name === 'AbortError'\n\nasync function callSearch(fn: SearchFn<unknown>, c: SearchFnContext<unknown>): Promise<unknown> {\n try {\n return await fn(c)\n } catch (e) {\n if (c.signal.aborted || isAbortError(e)) throw e\n return new SearchFailure(e)\n }\n}\n\n/** A `searchFn` result in one of its two shapes, or `undefined` when malformed. */\ntype Hits = { rows: readonly unknown[] } | { keys: readonly RowKey[] }\nconst toHits = (v: unknown): Hits | undefined =>\n Array.isArray(v)\n ? { rows: v }\n : v !== null && typeof v === 'object' && Array.isArray((v as { keys?: unknown }).keys)\n ? { keys: (v as { keys: readonly RowKey[] }).keys }\n : undefined\n\n/** The applied `searchFn` result of a table, and its data indices per (data, rowKey). */\ninterface Applied {\n query: string\n /** The data `searchFn` searched. */\n data: readonly unknown[]\n hits: Hits\n cache?: { data: readonly unknown[]; rowKey: unknown; indices: Uint32Array }\n}\n\n/**\n * The async search engine of one `search({ searchFn: withSearchFn(fn) })` feature instance (§6.3):\n * each applied non-blank query runs `fn` through `async:request` (latest wins, abort, `timeout`);\n * while it runs `status` is `'searching'` and the previous results stay; a failure keeps them too\n * (`DK_SEARCH_FAILED`, `status: 'error'`); new data runs it again for the applied query.\n */\nexport function createSearchEngine(fn: SearchFn<unknown>): SearchEngine {\n /** Per table: the applied `searchFn` result (the previous results while searching / on error). */\n const results = new WeakMap<object, Applied>()\n /** Per table: `check` after a pipeline run. */\n const checks = new WeakMap<object, () => void>()\n /** The table whose `pipeline:run` is in progress (`rowModel` has no table reference). */\n let active: object | undefined\n /** Data → row index, to map result rows back (rows are compared by identity). */\n const positions = new WeakMap<readonly unknown[], Map<unknown, number>>()\n let keyIndex: { data: readonly unknown[]; rowKey: unknown; map: Map<unknown, number> } | undefined\n /** The last step: same input and hits → same output (no per-run allocation). */\n let last: { input: Uint32Array; hits: Uint32Array; output: Uint32Array } | undefined\n\n /** The data indices of an applied result over `data`, in result order (memoised). */\n function indicesOf(a: Applied, data: readonly unknown[], rowKey: unknown): Uint32Array {\n const c = a.cache\n if (c && c.data === data && c.rowKey === rowKey) return c.indices\n let map: Map<unknown, number>\n let list: readonly unknown[]\n if ('rows' in a.hits) {\n list = a.hits.rows\n map = positions.get(data) ?? new Map()\n if (!positions.has(data)) {\n for (let i = 0; i < data.length; i++) if (!map.has(data[i])) map.set(data[i], i)\n positions.set(data, map)\n }\n } else {\n list = a.hits.keys\n if (!keyIndex || keyIndex.data !== data || keyIndex.rowKey !== rowKey) {\n // Diagnostics about the keys are the pipeline's (it resolves the same keys).\n const keyOf = resolveRowKeys(data, rowKey, NO_KEYS, NO_KEYS)\n const m = new Map<unknown, number>()\n for (let i = 0; i < data.length; i++) {\n const k = keyOf(data[i], i)\n if (!m.has(k)) m.set(k, i)\n }\n keyIndex = { data, rowKey, map: m }\n }\n map = keyIndex.map\n }\n const out = new Uint32Array(list.length)\n let n = 0\n for (const v of list) {\n const i = map.get(v)\n if (i !== undefined) out[n++] = i\n }\n const indices = out.subarray(0, n)\n a.cache = { data, rowKey, indices }\n return indices\n }\n\n function step(input: Uint32Array, ctx: RowModelContext): Uint32Array {\n const a = active && results.get(active)\n // Nothing applied yet (the first search is in flight or failed): the rows stay unsearched.\n if (!a) return input\n const rowKey = (active as { getOptions(): { rowKey?: unknown } }).getOptions().rowKey\n const hits = indicesOf(a, ctx.data, rowKey)\n if (last && last.input === input && last.hits === hits) return last.output\n const take = new Uint8Array(ctx.data.length)\n for (let k = 0; k < input.length; k++) take[input[k] as number] = 1\n const out = new Uint32Array(Math.min(hits.length, input.length))\n let n = 0\n for (let k = 0; k < hits.length; k++) {\n const i = hits[k] as number\n if (take[i] === 1) {\n take[i] = 0\n out[n++] = i\n }\n }\n const output = out.subarray(0, n)\n last = { input, hits, output }\n return output\n }\n\n function run<R>(table: object, next: () => R): R {\n // `step` reads the table's applied searchFn result through `active`.\n const prev = active\n active = table\n try {\n return next()\n } finally {\n active = prev\n checks.get(table)?.()\n }\n }\n\n function session(host: SearchHost): SearchSession {\n const { ctx, write, applied, input, claim } = host\n const table = ctx.table as unknown as object\n let dead = false\n /** The in-flight search: its query, data, waiters and abort handle. */\n let attempt:\n | { query: string; data: readonly unknown[]; waiters: Waiter[]; ctl: AbortController }\n | undefined\n /** (query, data) last handed to searchFn: `check()` never retries it in a loop. */\n let tried: { query: string; data: readonly unknown[] } | undefined\n let scheduled = false\n /**\n * SSR (§7.2): the initial query whose result is `initialData` (no searchFn call for it). Without\n * initialData, a deferred table (`createDeferred`) waits for `startTable` to search it.\n */\n let seeded: string | undefined\n if (applied().trim() !== '') {\n const opts = ctx.table.getOptions()\n if (opts.initialData !== undefined && opts.data === undefined) seeded = applied()\n else requestsOf(table).defer('searchFn')\n }\n\n /** Ends the in-flight search without its result (its waiters: `'superseded'`). */\n const abort = () => {\n const a = attempt\n if (!a) return\n attempt = undefined\n a.ctl.abort()\n for (const w of a.waiters) w.resolve(SUPERSEDED)\n }\n\n const startSearch = (query: string, inp: string) => {\n const data = ctx.table.getData() as readonly unknown[]\n const waiters: Waiter[] = []\n const prev = attempt\n if (prev) {\n attempt = undefined\n // Same query (new data): its waiters follow the new request; else they are replaced.\n if (prev.query === query) waiters.push(...prev.waiters)\n else for (const w of prev.waiters) w.resolve(SUPERSEDED)\n prev.ctl.abort()\n }\n waiters.push(...claim(query))\n const a = { query, data, waiters, ctl: new AbortController() }\n attempt = a\n tried = { query, data }\n write(inp, applied(), 'searching')\n const c = {\n query: query.trim(),\n rows: data,\n columns: ctx.table.getOptions().columns ?? EMPTY,\n }\n requestsOf(table)\n .request('searchFn', (signal) => callSearch(fn, { ...c, signal }), {\n signal: a.ctl.signal,\n onSettle: (value, status) => settle(a, value, status),\n })\n // strict: the DatakableError went to the hub; the outcome was settled in onSettle.\n .catch(() => settle(a, undefined, 'error'))\n }\n\n const settle = (a: NonNullable<typeof attempt>, value: unknown, status: AsyncStatus) => {\n // Replaced, cancelled or destroyed: its waiters were resolved then.\n if (attempt !== a || dead) return\n attempt = undefined\n const hits = status === 'applied' && !(value instanceof SearchFailure) && toHits(value)\n if (hits) {\n results.set(table, { query: a.query, data: a.data, hits })\n write(input(), a.query, 'idle')\n for (const w of a.waiters) w.resolve(APPLIED)\n return\n }\n if (status === 'superseded' || status === 'aborted') {\n // An AbortError from searchFn (not ours): not an error (§6.3).\n write(input(), applied(), 'idle')\n for (const w of a.waiters) w.resolve(SUPERSEDED)\n return\n }\n const failure = value instanceof SearchFailure ? value : undefined\n const error =\n status === 'timeout'\n ? new DOMException('searchFn timed out.', 'TimeoutError')\n : failure?.error\n write(input(), applied(), 'error', error)\n for (const w of a.waiters) w.resolve(ERROR)\n // 'error' / 'timeout': already reported by the errorBoundary / asyncControl.\n if (status !== 'applied') return\n const hadResults = results.has(table)\n if (failure) {\n const name = errorName(failure.error)\n ctx.emit(\n 'DK_SEARCH_FAILED',\n { ...(name === undefined ? {} : { errorName: name }), hadResults },\n { cause: failure.error },\n )\n } else {\n ctx.emit('DK_SEARCH_FAILED', {\n problem: 'bad-result',\n received: describeValue(value),\n hadResults,\n })\n }\n }\n\n /** After a pipeline run: new data or an outside query without a result → search again. */\n checks.set(table, () => {\n if (scheduled || dead) return\n const query = applied()\n if (query.trim() === '') return\n const data = ctx.table.getData()\n const r = results.get(table)\n if (r && r.query === query && r.data === data) return\n if (tried && tried.query === query && tried.data === data) return\n if (seeded !== undefined) {\n const initial = seeded === query && getTableInternals(table).initialRows() === data\n seeded = undefined\n if (initial) {\n results.set(table, { query, data, hits: { rows: data } })\n return\n }\n }\n if (requestsOf(table).defer('searchFn')) return\n scheduled = true\n queueMicrotask(() => {\n scheduled = false\n const q = applied()\n const d = ctx.table.getData()\n if (dead || q.trim() === '' || (tried && tried.query === q && tried.data === d)) return\n const cur = results.get(table)\n if (cur && cur.query === q && cur.data === d) return\n startSearch(q, input())\n })\n })\n\n return {\n apply(query, inp) {\n const data = ctx.table.getData()\n const r = results.get(table)\n if (query.trim() === '' || (query === applied() && r?.query === query && r.data === data)) {\n abort()\n if (query.trim() === '') results.delete(table)\n return false\n }\n if (attempt && attempt.query === query && attempt.data === data) {\n attempt.waiters.push(...claim(query))\n write(inp, applied(), 'searching')\n return true\n }\n startSearch(query, inp)\n return true\n },\n busy: () => attempt !== undefined,\n abort,\n destroy() {\n dead = true\n abort()\n },\n }\n }\n\n return { step, run, session }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/features/search/search-engine.ts"],"sourcesContent":["import { keepDiagnostics } from '../../diagnostics/catalog'\nimport '../../diagnostics/process-guard'\nimport { describeValue } from '../../diagnostics/redact'\nimport type { RowModelContext } from '../../feature/types'\nimport { resolveRowKeys } from '../../ingest/row-key'\nimport { errorName } from '../../intercept/classify'\nimport type { RowKey } from '../../pipeline/row'\nimport type { AsyncStatus } from '../../source/async-control'\nimport { requestsOf } from '../../source/requests'\nimport { getTableInternals } from '../../table/internals'\nimport { searchDiagnostics, unknownKeysDiagnostics } from './codes'\nimport {\n APPLIED,\n type SearchEngine,\n type SearchFn,\n type SearchFnContext,\n type SearchHost,\n type SearchOutcome,\n type SearchSession,\n SUPERSEDED,\n type Waiter,\n} from './search-fn-brand'\n\nkeepDiagnostics(searchDiagnostics)\nkeepDiagnostics(unknownKeysDiagnostics)\n\nconst EMPTY: readonly never[] = []\nconst ERROR: SearchOutcome = Object.freeze({ status: 'error' })\nconst NO_KEYS = () => {}\n/** Unmatched `{ keys }` listed in a `DK_SEARCH_UNKNOWN_KEYS` sample. */\nconst SAMPLE = 5\n\n/** A `searchFn` that rejected or threw: resolved as a value so asyncControl reports 'applied'. */\nclass SearchFailure {\n constructor(readonly error: unknown) {}\n}\n\nconst isAbortError = (e: unknown) =>\n e != null && typeof e === 'object' && (e as { name?: unknown }).name === 'AbortError'\n\nasync function callSearch(fn: SearchFn<unknown>, c: SearchFnContext<unknown>): Promise<unknown> {\n try {\n return await fn(c)\n } catch (e) {\n if (c.signal.aborted || isAbortError(e)) throw e\n return new SearchFailure(e)\n }\n}\n\n/** A `searchFn` result in one of its two shapes, or `undefined` when malformed. */\ntype Hits = { rows: readonly unknown[] } | { keys: readonly RowKey[] }\nconst toHits = (v: unknown): Hits | undefined =>\n Array.isArray(v)\n ? { rows: v }\n : v !== null && typeof v === 'object' && Array.isArray((v as { keys?: unknown }).keys)\n ? { keys: (v as { keys: readonly RowKey[] }).keys }\n : undefined\n\n/** The applied `searchFn` result of a table, and its data indices per (data, rowKey). */\ninterface Applied {\n query: string\n /** The data `searchFn` searched. */\n data: readonly unknown[]\n hits: Hits\n cache?: { data: readonly unknown[]; rowKey: unknown; indices: Uint32Array }\n /** Development: returned `{ keys }` that match no row, until reported (`DK_SEARCH_UNKNOWN_KEYS`). */\n unknown?: { count: number; returned: number; keys: unknown[] } | undefined\n}\n\n/**\n * The async search engine of one `search({ searchFn: withSearchFn(fn) })` feature instance (§6.3):\n * each applied non-blank query runs `fn` through `async:request` (latest wins, abort, `timeout`);\n * while it runs `status` is `'searching'` and the previous results stay; a failure keeps them too\n * (`DK_SEARCH_FAILED`, `status: 'error'`); new data runs it again for the applied query.\n */\nexport function createSearchEngine(fn: SearchFn<unknown>): SearchEngine {\n /** Per table: the applied `searchFn` result (the previous results while searching / on error). */\n const results = new WeakMap<object, Applied>()\n /** Per table: `check` after a pipeline run. */\n const checks = new WeakMap<object, () => void>()\n /** The table whose `pipeline:run` is in progress (`rowModel` has no table reference). */\n let active: object | undefined\n /** Data → row index, to map result rows back (rows are compared by identity). */\n const positions = new WeakMap<readonly unknown[], Map<unknown, number>>()\n /** Row key, as a string → data index: keys compare as strings (`2` matches `'2'`), as in row-key.ts. */\n let keyIndex: { data: readonly unknown[]; rowKey: unknown; map: Map<string, number> } | undefined\n /** The last step: same input and hits → same output (no per-run allocation). */\n let last: { input: Uint32Array; hits: Uint32Array; output: Uint32Array } | undefined\n\n /** The data indices of an applied result over `data`, in result order (memoised). */\n function indicesOf(a: Applied, data: readonly unknown[], rowKey: unknown): Uint32Array {\n const c = a.cache\n if (c && c.data === data && c.rowKey === rowKey) return c.indices\n let find: (v: unknown) => number | undefined\n let list: readonly unknown[]\n if ('rows' in a.hits) {\n list = a.hits.rows\n const map = positions.get(data) ?? new Map<unknown, number>()\n if (!positions.has(data)) {\n for (let i = 0; i < data.length; i++) if (!map.has(data[i])) map.set(data[i], i)\n positions.set(data, map)\n }\n find = (v) => map.get(v)\n } else {\n list = a.hits.keys\n if (!keyIndex || keyIndex.data !== data || keyIndex.rowKey !== rowKey) {\n // Diagnostics about the keys are the pipeline's (it resolves the same keys).\n const keyOf = resolveRowKeys(data, rowKey, NO_KEYS, NO_KEYS)\n const m = new Map<string, number>()\n for (let i = 0; i < data.length; i++) {\n // Repeated keys are already unique here: later rows carry `key#1`, `key#2`, … (row.key).\n const k = String(keyOf(data[i], i))\n if (!m.has(k)) m.set(k, i)\n }\n keyIndex = { data, rowKey, map: m }\n }\n const map = keyIndex.map\n find = (v) => map.get(String(v))\n }\n const out = new Uint32Array(list.length)\n let n = 0\n let unknown: Applied['unknown']\n for (const v of list) {\n const i = find(v)\n if (i !== undefined) out[n++] = i\n else if ((process.env.NODE_ENV !== \"production\") && 'keys' in a.hits) {\n unknown ??= { count: 0, returned: list.length, keys: [] }\n unknown.count++\n if (unknown.keys.length < SAMPLE) unknown.keys.push(v)\n }\n }\n if ((process.env.NODE_ENV !== \"production\")) a.unknown = unknown\n const indices = out.subarray(0, n)\n a.cache = { data, rowKey, indices }\n return indices\n }\n\n function step(input: Uint32Array, ctx: RowModelContext): Uint32Array {\n const a = active && results.get(active)\n // Nothing applied yet (the first search is in flight or failed): the rows stay unsearched.\n if (!a) return input\n const rowKey = (active as { getOptions(): { rowKey?: unknown } }).getOptions().rowKey\n const hits = indicesOf(a, ctx.data, rowKey)\n if (last && last.input === input && last.hits === hits) return last.output\n const take = new Uint8Array(ctx.data.length)\n for (let k = 0; k < input.length; k++) take[input[k] as number] = 1\n const out = new Uint32Array(Math.min(hits.length, input.length))\n let n = 0\n for (let k = 0; k < hits.length; k++) {\n const i = hits[k] as number\n if (take[i] === 1) {\n take[i] = 0\n out[n++] = i\n }\n }\n const output = out.subarray(0, n)\n last = { input, hits, output }\n return output\n }\n\n function run<R>(table: object, next: () => R): R {\n // `step` reads the table's applied searchFn result through `active`.\n const prev = active\n active = table\n try {\n return next()\n } finally {\n active = prev\n checks.get(table)?.()\n }\n }\n\n function session(host: SearchHost): SearchSession {\n const { ctx, write, applied, input, claim } = host\n const table = ctx.table as unknown as object\n let dead = false\n /** The in-flight search: its query, data, waiters and abort handle. */\n let attempt:\n | { query: string; data: readonly unknown[]; waiters: Waiter[]; ctl: AbortController }\n | undefined\n /** (query, data) last handed to searchFn: `check()` never retries it in a loop. */\n let tried: { query: string; data: readonly unknown[] } | undefined\n let scheduled = false\n /**\n * SSR (§7.2): the initial query whose result is `initialData` (no searchFn call for it). Without\n * initialData, a deferred table (`createDeferred`) waits for `startTable` to search it.\n */\n let seeded: string | undefined\n if (applied().trim() !== '') {\n const opts = ctx.table.getOptions()\n if (opts.initialData !== undefined && opts.data === undefined) seeded = applied()\n else requestsOf(table).defer('searchFn')\n }\n\n /** Ends the in-flight search without its result (its waiters: `'superseded'`). */\n const abort = () => {\n const a = attempt\n if (!a) return\n attempt = undefined\n a.ctl.abort()\n for (const w of a.waiters) w.resolve(SUPERSEDED)\n }\n\n const startSearch = (query: string, inp: string) => {\n const data = ctx.table.getData() as readonly unknown[]\n const waiters: Waiter[] = []\n const prev = attempt\n if (prev) {\n attempt = undefined\n // Same query (new data): its waiters follow the new request; else they are replaced.\n if (prev.query === query) waiters.push(...prev.waiters)\n else for (const w of prev.waiters) w.resolve(SUPERSEDED)\n prev.ctl.abort()\n }\n waiters.push(...claim(query))\n const a = { query, data, waiters, ctl: new AbortController() }\n attempt = a\n tried = { query, data }\n write(inp, applied(), 'searching')\n const c = {\n query: query.trim(),\n rows: data,\n columns: ctx.table.getOptions().columns ?? EMPTY,\n }\n requestsOf(table)\n .request('searchFn', (signal) => callSearch(fn, { ...c, signal }), {\n signal: a.ctl.signal,\n onSettle: (value, status) => settle(a, value, status),\n })\n // strict: the DatakableError went to the hub; the outcome was settled in onSettle.\n .catch(() => settle(a, undefined, 'error'))\n }\n\n const settle = (a: NonNullable<typeof attempt>, value: unknown, status: AsyncStatus) => {\n // Replaced, cancelled or destroyed: its waiters were resolved then.\n if (attempt !== a || dead) return\n attempt = undefined\n const hits = status === 'applied' && !(value instanceof SearchFailure) && toHits(value)\n if (hits) {\n results.set(table, { query: a.query, data: a.data, hits })\n write(input(), a.query, 'idle')\n for (const w of a.waiters) w.resolve(APPLIED)\n return\n }\n if (status === 'superseded' || status === 'aborted') {\n // An AbortError from searchFn (not ours): not an error (§6.3).\n write(input(), applied(), 'idle')\n for (const w of a.waiters) w.resolve(SUPERSEDED)\n return\n }\n const failure = value instanceof SearchFailure ? value : undefined\n const error =\n status === 'timeout'\n ? new DOMException('searchFn timed out.', 'TimeoutError')\n : failure?.error\n write(input(), applied(), 'error', error)\n for (const w of a.waiters) w.resolve(ERROR)\n // 'error' / 'timeout': already reported by the errorBoundary / asyncControl.\n if (status !== 'applied') return\n const hadResults = results.has(table)\n if (failure) {\n const name = errorName(failure.error)\n ctx.emit(\n 'DK_SEARCH_FAILED',\n { ...(name === undefined ? {} : { errorName: name }), hadResults },\n { cause: failure.error },\n )\n } else {\n ctx.emit('DK_SEARCH_FAILED', {\n problem: 'bad-result',\n received: describeValue(value),\n hadResults,\n })\n }\n }\n\n /** After a pipeline run: new data or an outside query without a result → search again. */\n checks.set(table, () => {\n if ((process.env.NODE_ENV !== \"production\")) {\n const u = results.get(table)\n if (u?.unknown && !dead) {\n ctx.emit('DK_SEARCH_UNKNOWN_KEYS', u.unknown)\n u.unknown = undefined\n }\n }\n if (scheduled || dead) return\n const query = applied()\n if (query.trim() === '') return\n const data = ctx.table.getData()\n const r = results.get(table)\n if (r && r.query === query && r.data === data) return\n if (tried && tried.query === query && tried.data === data) return\n if (seeded !== undefined) {\n const initial = seeded === query && getTableInternals(table).initialRows() === data\n seeded = undefined\n if (initial) {\n results.set(table, { query, data, hits: { rows: data } })\n return\n }\n }\n if (requestsOf(table).defer('searchFn')) return\n scheduled = true\n queueMicrotask(() => {\n scheduled = false\n const q = applied()\n const d = ctx.table.getData()\n if (dead || q.trim() === '' || (tried && tried.query === q && tried.data === d)) return\n const cur = results.get(table)\n if (cur && cur.query === q && cur.data === d) return\n startSearch(q, input())\n })\n })\n\n return {\n apply(query, inp) {\n const data = ctx.table.getData()\n const r = results.get(table)\n if (query.trim() === '' || (query === applied() && r?.query === query && r.data === data)) {\n abort()\n if (query.trim() === '') results.delete(table)\n return false\n }\n if (attempt && attempt.query === query && attempt.data === data) {\n attempt.waiters.push(...claim(query))\n write(inp, applied(), 'searching')\n return true\n }\n startSearch(query, inp)\n return true\n },\n busy: () => attempt !== undefined,\n abort,\n destroy() {\n dead = true\n abort()\n },\n }\n }\n\n return { step, run, session }\n}\n"],"mappings":"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","names":[]}
@@ -29,7 +29,10 @@ var import_slots = require("../../catalog/slots.cjs");
29
29
  var import_get_value = require("../../column/get-value.cjs");
30
30
  var import_catalog = require("../../diagnostics/catalog.cjs");
31
31
  var import_process_guard = require("../../diagnostics/process-guard.cjs");
32
+ var import_prose = require("../../diagnostics/prose.cjs");
33
+ var import_redact = require("../../diagnostics/redact.cjs");
32
34
  var import_define = require("../../feature/define.cjs");
35
+ var import_slice_guard = require("../../feature/slice-guard.cjs");
33
36
  var import_cell_batch = require("../../intercept/cell-batch.cjs");
34
37
  var import_classify = require("../../intercept/classify.cjs");
35
38
  var import_codes2 = require("../../intercept/codes.cjs");
@@ -50,7 +53,30 @@ var import_strategy = require("./strategy.cjs");
50
53
  import_codes.optionDiagnostics,
51
54
  import_env_codes.envDiagnostics
52
55
  );
53
- var setSort = (ctx, by) => ctx.setState((s) => JSON.stringify(s.by) === JSON.stringify(by) ? s : { by: by.slice() });
56
+ var isEntry = (e) => e?.id != null;
57
+ var byOf = (s) => s?.by;
58
+ var entriesOf = (s) => {
59
+ const by = byOf(s);
60
+ return Array.isArray(by) ? by.filter(isEntry) : [];
61
+ };
62
+ function fixSlice(s) {
63
+ const raw = byOf(s);
64
+ const by = entriesOf(s);
65
+ if (Array.isArray(raw) && raw.length === by.length) return void 0;
66
+ const bad = Array.isArray(raw) ? raw.findIndex((e) => !isEntry(e)) : -1;
67
+ return [
68
+ { by },
69
+ bad < 0 ? (0, import_redact.describeValue)(raw ?? s) : `by[${bad}]: ${(0, import_redact.describeValue)(raw[bad])}`,
70
+ `{ by: [${by.length} valid] }`
71
+ ];
72
+ }
73
+ var setSort = (ctx, by) => {
74
+ try {
75
+ if (JSON.stringify(byOf(ctx.getState())) === JSON.stringify(by)) return;
76
+ } catch {
77
+ }
78
+ ctx.setState({ by: Array.isArray(by) ? by.slice() : by });
79
+ };
54
80
  var validLocale = (v) => {
55
81
  try {
56
82
  Intl.getCanonicalLocales(v);
@@ -113,6 +139,7 @@ var SortFnFailed = class {
113
139
  }
114
140
  };
115
141
  var sorting = (opts = {}) => {
142
+ const guard = process.env.NODE_ENV !== "production" ? (0, import_slice_guard.sliceGuard)("sorting", fixSlice) : void 0;
116
143
  let collator;
117
144
  const getCollator = (emit) => {
118
145
  if (collator) return collator;
@@ -202,32 +229,36 @@ var sorting = (opts = {}) => {
202
229
  process.env.NODE_ENV !== "production" ? sortingOptions : {},
203
230
  opts
204
231
  ),
232
+ ...guard ? { interceptors: [guard.interceptor] } : void 0,
205
233
  initialState: () => ({ by: [] }),
206
234
  // After destroy(): still a declared value (`aria-sort` reads it during teardown renders).
207
235
  destroyedResult: { getSortDirection: () => false },
208
- createApi: (ctx) => ({
209
- toggleSort: (id, options) => ctx.setState((s) => {
210
- const by = s.by;
211
- const i = by.findIndex((e) => e.id === id);
212
- const cur = by[i];
213
- const next = !cur ? { id, desc: false } : cur.desc ? void 0 : { id, desc: true };
214
- if (!options?.multi) return { by: next ? [next] : [] };
215
- if (!cur) return { by: [...by, next] };
216
- const out = by.slice();
217
- if (next) out[i] = next;
218
- else out.splice(i, 1);
219
- return { by: out };
220
- }),
221
- setSorting: (by) => setSort(ctx, by),
222
- clearSorting: () => setSort(ctx, []),
223
- getSortDirection: (id) => {
224
- const e = ctx.getState().by.find((x) => x.id === id);
225
- return e ? e.desc ? "desc" : "asc" : false;
226
- }
227
- }),
236
+ createApi: (ctx) => {
237
+ guard?.install(ctx);
238
+ return {
239
+ toggleSort: (id, options) => {
240
+ const by = entriesOf(ctx.getState());
241
+ const i = by.findIndex((e) => e.id === id);
242
+ const cur = by[i];
243
+ const next = !cur ? { id, desc: false } : cur.desc ? void 0 : { id, desc: true };
244
+ if (!options?.multi) return ctx.setState({ by: next ? [next] : [] });
245
+ if (!cur) return ctx.setState({ by: [...by, next] });
246
+ const out = by.slice();
247
+ if (next) out[i] = next;
248
+ else out.splice(i, 1);
249
+ ctx.setState({ by: out });
250
+ },
251
+ setSorting: (by) => setSort(ctx, by),
252
+ clearSorting: () => setSort(ctx, []),
253
+ getSortDirection: (id) => {
254
+ const e = entriesOf(ctx.getState()).find((x) => x.id === id);
255
+ return e ? e.desc ? "desc" : "asc" : false;
256
+ }
257
+ };
258
+ },
228
259
  rowModel: (indices, state, ctx) => {
229
- const by = state?.by;
230
- if (!by || by.length === 0 || indices.length < 2) {
260
+ const by = entriesOf(state);
261
+ if (by.length === 0 || indices.length < 2) {
231
262
  shown = void 0;
232
263
  return indices;
233
264
  }
@@ -260,7 +291,7 @@ var sorting = (opts = {}) => {
260
291
  fromColumn ? { path: `columns[${primary.col?.index}].sortAlgorithm`, reason: reason2, once: false } : { path: "algorithm", feature: "sorting", reason: reason2, once: false }
261
292
  );
262
293
  if (typeof requested !== "function" && !ALGORITHMS.includes(requested)) {
263
- noEffect(`not-algorithm|${JSON.stringify(requested)}`);
294
+ noEffect(`not-algorithm|${(0, import_prose.proseArg)(JSON.stringify(requested))}`);
264
295
  requested = "auto";
265
296
  }
266
297
  if (requested !== "native" && exsorted === void 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/features/sorting/sorting.ts"],"sourcesContent":["import { optionDiagnostics } from '../../catalog/codes'\nimport { defineOptions } from '../../catalog/options'\nimport { describeReturn } from '../../catalog/slots'\nimport type { SortAlgorithm } from '../../column/column-def'\nimport { compilePath, getValue } from '../../column/get-value'\nimport type { Path } from '../../column/path'\nimport { keepDiagnostics } from '../../diagnostics/catalog'\nimport '../../diagnostics/process-guard'\nimport type { Emit } from '../../diagnostics/types'\nimport { defineFeature } from '../../feature/define'\nimport type { FeatureTypes, RowModelContext } from '../../feature/types'\nimport { CellFailures } from '../../intercept/cell-batch'\nimport { errorName } from '../../intercept/classify'\nimport { boundaryDiagnostics } from '../../intercept/codes'\nimport { type ResolvedColumn, resolveColumns } from '../../pipeline/columns'\nimport { envDiagnostics } from '../../pipeline/env-codes'\nimport { allRows } from '../../pipeline/indices'\nimport { sliced } from '../../pipeline/slice'\nimport type { ColumnValues } from '../../pipeline/types'\nimport { type DataMode, modeOption } from '../../source/mode'\nimport { detectCapability, hasCapability } from '../../versioning/capability'\nimport { comparatorDiagnostics, sortingDiagnostics } from './codes'\nimport {\n defaultIndexComparator,\n type IndexComparator,\n RANK,\n sortFnIndexComparator,\n typeRank,\n} from './compare'\nimport { collationRanks } from './ranks'\nimport {\n chooseAuto,\n hasExsorted,\n intKeys,\n needsIntKeys,\n sortIntKeys,\n sortWithComparator,\n} from './strategy'\n\nkeepDiagnostics(\n sortingDiagnostics,\n comparatorDiagnostics,\n boundaryDiagnostics,\n optionDiagnostics,\n envDiagnostics,\n)\n\n/** One sort key: a column id (a path of the row type) and its direction. */\nexport type SortEntry<T> = { id: Path<T>; desc: boolean }\n\n/** The `sorting` slice (§6.4): multi-column, earlier entries first. Empty = unsorted. */\nexport type SortingState<T> = { by: readonly SortEntry<T>[] }\n\nexport type SortDirection = 'asc' | 'desc'\n\n/** Replaces the sort; an equal one keeps the slice (same reference, no notification, #21). */\nconst setSort = (\n ctx: { setState(u: (s: SortingState<unknown>) => SortingState<unknown>): void },\n by: readonly SortEntry<unknown>[],\n) => ctx.setState((s) => (JSON.stringify(s.by) === JSON.stringify(by) ? s : { by: by.slice() }))\n\nexport type SortingApi<T> = {\n /**\n * Cycles `id` asc → desc → none. Without `multi` the result is a single-column sort; with `multi`\n * (Shift+click) `id` is appended, cycled in place or removed and the other entries are kept.\n */\n toggleSort(id: Path<T>, options?: { multi?: boolean }): void\n /** Replaces the whole sort. */\n setSorting(by: readonly SortEntry<T>[]): void\n /** Removes every sort entry (input order). */\n clearSorting(): void\n /** `id`'s direction in the current sort, or `false` (for `aria-sort`). */\n getSortDirection(id: Path<T>): SortDirection | false\n}\n\nexport interface SortingTypes extends FeatureTypes {\n state: SortingState<this['T']>\n api: SortingApi<this['T']>\n}\n\n/**\n * How rows are sorted (§6.4): `'auto'` (default) picks per sort from one O(n) scan — exsorted\n * tim / counting / radix for a single column of safe-integer keys (numbers, `Date`s), native\n * `Array.prototype.sort` otherwise. A built-in name forces that algorithm (radix / counting only\n * apply to safe-integer keys); a function sorts the row indices itself.\n */\nexport type SortAlgorithmOption = SortAlgorithm\n\nexport interface SortingOptions {\n /**\n * Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`). Default `'en'`,\n * not the runtime's: the server and the browser must sort alike (SSR hydration, #12).\n */\n locale?: string | readonly string[]\n /** The sort algorithm (default `'auto'`); a column's `sortAlgorithm` takes precedence. */\n algorithm?: SortAlgorithmOption\n /** Reports the algorithm chosen for each sort, why, n and the time taken (`DK_SORT_STRATEGY`). */\n debug?: boolean\n /**\n * `'server'`: the server sorts (its state goes to `options.fetcher`, or the app fetches); core\n * skips this step (§7.1). Default `'client'`.\n */\n mode?: DataMode\n}\n\nconst validLocale = (v: unknown) => {\n try {\n Intl.getCanonicalLocales(v as string | string[])\n return true\n } catch {\n return false\n }\n}\n\nconst ALGORITHMS = ['auto', 'tim', 'radix', 'counting', 'native'] as const\n\nconst sortingOptions = {\n locale: {\n type: ['string', 'array'],\n check: validLocale,\n expected: 'a BCP 47 locale tag or a list of them, e.g. \"th\" or [\"th\", \"en\"]',\n },\n algorithm: {\n type: ['string', 'function'],\n oneOf: ALGORITHMS,\n // A literal (not built from ALGORITHMS): a module-level call would keep the schema in production.\n expected:\n \"one of 'auto', 'tim', 'radix', 'counting', 'native', or (indices, compare) => indices\",\n },\n debug: { type: 'boolean' },\n mode: modeOption,\n} as const\n\ntype CustomAlgorithm = Extract<SortAlgorithm, (...args: never[]) => unknown>\n\nconst now = () => (typeof performance === 'undefined' ? Date.now() : performance.now())\n\n/**\n * From this many rows, `auto` sorts a string column by precomputed collation ranks (§9.1): one\n * time-sliced job per column values, then integer-key sorts (a few ms at 100k rows) instead of a\n * collator call per comparison (~100–200 ms at 100k, one long task).\n */\nconst RANKS_MIN = 10_000\n\nconst missing = (v: unknown) => typeRank(v) === RANK.missing\n\n/**\n * Dev check of a column's `sortFn` (§8.3 `DK_SORT_COMPARATOR_INVALID`), sampled: up to 8 present\n * values spread over the input, every pair both ways. A throw gives no verdict (the sort reports\n * it as `DK_CALLBACK_FAILED`).\n */\nfunction checkSortFn(\n fn: SortFn,\n values: ColumnValues,\n indices: Uint32Array,\n): { reason: 'nan' | 'not-number' | 'inconsistent'; received?: string } | undefined {\n const sample: unknown[] = []\n const step = Math.max(1, Math.floor(indices.length / 8))\n for (let i = 0; i < indices.length && sample.length < 8; i += step) {\n const v = values[indices[i] as number]\n if (!missing(v)) sample.push(v)\n }\n try {\n for (let i = 0; i < sample.length; i++) {\n for (let j = i; j < sample.length; j++) {\n const x = fn(sample[i], sample[j])\n const y = fn(sample[j], sample[i])\n for (const r of [x, y]) {\n if (typeof r !== 'number') return { reason: 'not-number', received: describeReturn(r) }\n if (Number.isNaN(r)) return { reason: 'nan' }\n }\n if (Math.sign(x) !== -Math.sign(y)) return { reason: 'inconsistent' }\n }\n }\n } catch {\n return undefined\n }\n return undefined\n}\n\ntype SortFn = (a: unknown, b: unknown) => number\ntype SortBy = (row: unknown) => unknown\n\nconst fnField = (def: object, field: 'sortFn' | 'sortBy') => {\n const f = (def as Record<string, unknown>)[field]\n return typeof f === 'function' ? f : undefined\n}\n\n/** Aborts a native sort when a column's `sortFn` throws (the entry then falls back). */\nclass SortFnFailed {\n constructor(\n readonly entry: number,\n readonly error: unknown,\n ) {}\n}\n\n/**\n * Sorting (§6.4): `toggleSort` (asc → desc → none, `multi`), stable sort of the row indices with\n * the default comparator — missing values (`null`, `undefined`, `NaN`, invalid `Date`) last in both\n * directions, mixed types by type rank, strings with one `Intl.Collator(locale, { numeric: true })`\n * — or a column's `sortFn` / `sortBy`. Never touches the data: a copy of the index array is sorted.\n *\n * `algorithm: 'auto'` (default) picks per sort from one O(n) scan (§6.4): exsorted tim / counting /\n * radix for a single column of safe-integer keys (numbers, `Date`s), native `Array.prototype.sort`\n * (stable) for strings, floats, multi-column and `sortFn`. Every choice gives the same stable order.\n * `sorting({ algorithm })` or a column's `sortAlgorithm` overrides it; `debug: true` reports each\n * choice (`DK_SORT_STRATEGY`).\n */\nexport const sorting = (opts: SortingOptions = {}) => {\n let collator: Intl.Collator | undefined\n /** The collator; `DK_ENV_FALLBACK` when the runtime supports none of the requested locales. */\n const getCollator = (emit: Emit) => {\n if (collator) return collator\n const locale = (opts.locale ?? 'en') as string | string[]\n let supported = true\n try {\n collator = new Intl.Collator(locale, { numeric: true })\n supported = Intl.Collator.supportedLocalesOf(locale).length > 0\n } catch {\n collator = new Intl.Collator(undefined, { numeric: true })\n supported = false\n }\n if (!supported) {\n emit('DK_ENV_FALLBACK', {\n api: 'Intl.Collator',\n feature: 'sorting',\n requested: ([] as string[]).concat(locale).join(', '),\n fallback: `collation|${collator.resolvedOptions().locale}`,\n })\n }\n return collator\n }\n\n /** Values array → the key of its collation-ranks job (`ctx.slice`); released with the values. */\n const rankKeys = new WeakMap<object, object>()\n function ranksFor(ctx: RowModelContext, values: readonly unknown[]) {\n let key = rankKeys.get(values)\n if (!key) {\n key = {}\n rankKeys.set(values, key)\n }\n const c = getCollator(ctx.emit)\n return sliced(ctx, key, () => collationRanks(values, c))\n }\n /** The last sorted output and its input: the stand-in while ranks are computed (§9.1). */\n let shown: { input: Uint32Array; output: Uint32Array } | undefined\n\n // Values that the column cache does not hold, per data reference (released with it).\n const sortByCache = new WeakMap<readonly unknown[], WeakMap<object, unknown[]>>()\n const pathCache = new WeakMap<readonly unknown[], Map<string, unknown[]>>()\n /** exsorted feature detection (§8.5), once per feature instance, on the first sort needing it. */\n let exsorted: boolean | undefined\n\n /** `sortBy` failures (§3.4): numbers only; text is built only when a cell failed. */\n const sortByFailures = new CellFailures()\n\n /**\n * `sortBy` is a cell slot: one `column:batch` per column per data reference, an inline\n * `try/catch` per row. A failed row (or a batch an interceptor skipped) keys as `undefined`,\n * which sorts last.\n */\n function sortByValues(ctx: RowModelContext, col: ResolvedColumn, sortBy: SortBy): unknown[] {\n const data = ctx.data\n let byDef = sortByCache.get(data)\n if (!byDef) {\n byDef = new WeakMap()\n sortByCache.set(data, byDef)\n }\n let out = byDef.get(col.def)\n if (out) return out\n const values: unknown[] = new Array(data.length).fill(undefined)\n const rows = allRows(data)\n sortByFailures.reset()\n ctx.batch(col.id, 'sortBy', rows, () => {\n for (let i = 0; i < rows.length; i++) {\n const r = rows[i] as number\n try {\n values[r] = sortBy(data[r])\n } catch (e) {\n sortByFailures.add(r, e)\n }\n }\n sortByFailures.report(ctx.emit, col.index, col.id, 'sortBy')\n })\n sortByFailures.reset()\n out = values\n byDef.set(col.def, out)\n return out\n }\n\n function pathValues(ctx: RowModelContext, id: string): unknown[] {\n const data = ctx.data\n let byId = pathCache.get(data)\n if (!byId) {\n byId = new Map()\n pathCache.set(data, byId)\n }\n let out = byId.get(id)\n if (out) return out\n const path = compilePath(id)\n out = new Array(data.length)\n for (let r = 0; r < data.length; r++) out[r] = getValue(data[r], path)\n byId.set(id, out)\n return out\n }\n\n return defineFeature<'sorting', SortingTypes>({\n name: 'sorting',\n stage: 'sort',\n mode: opts.mode ?? 'client',\n options: defineOptions(\n // The option validator runs in development only (§9.3): production drops the schema.\n (process.env.NODE_ENV !== \"production\") ? sortingOptions : ({} as typeof sortingOptions),\n opts,\n ),\n initialState: () => ({ by: [] }),\n // After destroy(): still a declared value (`aria-sort` reads it during teardown renders).\n destroyedResult: { getSortDirection: () => false },\n createApi: (ctx) => ({\n toggleSort: (id, options) =>\n ctx.setState((s) => {\n const by = s.by\n const i = by.findIndex((e) => e.id === id)\n const cur = by[i]\n const next = !cur ? { id, desc: false } : cur.desc ? undefined : { id, desc: true }\n if (!options?.multi) return { by: next ? [next] : [] }\n if (!cur) return { by: [...by, next as SortEntry<unknown>] }\n const out = by.slice()\n if (next) out[i] = next\n else out.splice(i, 1)\n return { by: out }\n }),\n setSorting: (by) => setSort(ctx, by),\n clearSorting: () => setSort(ctx, []),\n getSortDirection: (id) => {\n const e = ctx.getState().by.find((x) => x.id === id)\n return e ? (e.desc ? 'desc' : 'asc') : false\n },\n }),\n rowModel: (indices, state, ctx) => {\n const by = state?.by\n if (!by || by.length === 0 || indices.length < 2) {\n shown = undefined\n return indices\n }\n const t0 = opts.debug ? now() : 0\n const cols = resolveColumns(ctx.columns)\n const entries = by.map((e) => {\n const id = String(e.id)\n const col = cols.byId.get(id)\n const sortBy = col && (fnField(col.def, 'sortBy') as SortBy | undefined)\n const values: ColumnValues = sortBy\n ? sortByValues(ctx, col, sortBy)\n : (ctx.getColumnValues(id) ?? pathValues(ctx, id))\n const sortFn =\n col && !sortBy ? (fnField(col.def, 'sortFn') as SortFn | undefined) : undefined\n return { col, desc: e.desc === true, values, sortFn, ranked: false }\n })\n\n // Dev (§8.3): a sampled sortFn check; an invalid one falls back to the default comparator.\n if ((process.env.NODE_ENV !== \"production\")) {\n for (const e of entries) {\n if (!e.sortFn) continue\n const bad = checkSortFn(e.sortFn, e.values, indices)\n if (!bad) continue\n e.sortFn = undefined\n const col = e.col as ResolvedColumn\n ctx.emit('DK_SORT_COMPARATOR_INVALID', { column: col.id, index: col.index, ...bad })\n }\n }\n\n // The requested algorithm: the primary column's `sortAlgorithm`, else the table's.\n const primary = entries[0] as (typeof entries)[number]\n const colAlgorithm =\n primary.col && (primary.col.def as { sortAlgorithm?: unknown }).sortAlgorithm\n const fromColumn = colAlgorithm !== undefined\n let requested = (fromColumn ? colAlgorithm : (opts.algorithm ?? 'auto')) as SortAlgorithm\n const noEffect = (reason: string) =>\n ctx.emit(\n 'DK_OPTION_NO_EFFECT',\n fromColumn\n ? { path: `columns[${primary.col?.index}].sortAlgorithm`, reason, once: false }\n : { path: 'algorithm', feature: 'sorting', reason, once: false },\n )\n if (\n typeof requested !== 'function' &&\n !(ALGORITHMS as readonly unknown[]).includes(requested)\n ) {\n noEffect(`not-algorithm|${JSON.stringify(requested)}`)\n requested = 'auto'\n }\n if (requested !== 'native' && exsorted === undefined) {\n // DK_DEP_INCOMPATIBLE is a development check (§8.5); the fallback is not.\n exsorted = (process.env.NODE_ENV !== \"production\")\n ? detectCapability(\n hasExsorted,\n {\n feature: 'sorting',\n dependency: 'exsorted',\n capability: 'timSort / radixSort / countingSort',\n supported: '^1.2.3',\n fallback: 'Array.prototype.sort (native, stable)',\n },\n ctx.emit,\n )\n : hasCapability(hasExsorted)\n }\n\n // auto at large n (§9.1): string columns sort by collation ranks, computed by a sliced job.\n if (requested === 'auto' && indices.length >= RANKS_MIN) {\n let computing = false\n for (const e of entries) {\n if (e.sortFn || e.values instanceof Float64Array) continue\n const ranks = ranksFor(ctx, e.values)\n if (ranks === undefined) computing = true\n else if (ranks) {\n e.values = ranks\n e.ranked = true\n }\n }\n // Meanwhile: the previous order of these rows (or the input order); 'pending'.\n if (computing) return shown && shown.input === indices ? shown.output : indices\n }\n const ranked = entries.some((e) => e.ranked)\n\n const build = (): IndexComparator => {\n const cmps = entries.map((e, k) => {\n const fn = e.sortFn\n if (!fn) return defaultIndexComparator(e.values, e.desc, getCollator(ctx.emit))\n const guarded: SortFn = (a, b) => {\n try {\n return fn(a, b)\n } catch (error) {\n throw new SortFnFailed(k, error)\n }\n }\n return sortFnIndexComparator(e.values, e.desc, guarded)\n })\n if (cmps.length === 1) return cmps[0] as IndexComparator\n return (a, b) => {\n for (let k = 0; k < cmps.length; k++) {\n const c = (cmps[k] as IndexComparator)(a, b)\n if (c !== 0) return c\n }\n return 0\n }\n }\n\n let algorithm: string = 'native'\n let reason = ''\n /** One attempt; a throwing sortFn propagates as SortFnFailed (the loop below retries). */\n const sortOnce = (): Uint32Array => {\n const want = requested\n if (typeof want === 'function') {\n const custom = want as CustomAlgorithm\n let res: unknown\n try {\n res = custom(indices.slice(), build())\n } catch (error) {\n if (error instanceof SortFnFailed) throw error\n reportCustom(true, error)\n return native('custom-threw')\n }\n if (res instanceof Uint32Array && res.length === indices.length) {\n algorithm = 'custom'\n reason = fromColumn ? 'column sortAlgorithm' : 'sorting({ algorithm })'\n return res\n }\n reportCustom(false, res)\n return native('custom-bad')\n }\n if (exsorted === false) return native('exsorted unavailable')\n const by = fromColumn ? 'column sortAlgorithm' : 'sorting({ algorithm })'\n // Integer keys: a single column with the default comparator (§6.4).\n const single = entries.length === 1 && !primary.sortFn\n const keys =\n single && want !== 'native' ? intKeys(primary.values, indices, primary.desc) : undefined\n if (want !== 'auto' && want !== 'native') {\n if (keys) {\n try {\n const out = sortIntKeys(keys, want)\n algorithm = want\n reason = `int-keys|${by}`\n return out\n } catch {\n noEffect(`exsorted-${want === 'counting' ? 'range' : 'failed'}|${want}`)\n }\n } else if (needsIntKeys(want)) {\n noEffect(`needs-int-keys|${want}`)\n } else {\n algorithm = want\n reason = by\n return sortWithComparator(indices, build(), want as 'tim')\n }\n } else if (want === 'native') return native(by)\n if (!keys) {\n return native(\n single ? 'not-safe-int' : entries.length > 1 ? 'multi-column' : 'custom sortFn',\n )\n }\n const choice = chooseAuto(keys)\n algorithm = choice.algorithm\n reason = `auto-${ranked ? 'ranked-' : ''}${choice.reason}`\n return sortIntKeys(keys, choice.algorithm)\n }\n const native = (why: string) => {\n algorithm = 'native'\n reason = ranked ? `ranks|${why}` : why\n return sortWithComparator(indices, build(), 'native')\n }\n /** A custom algorithm threw (`threw`, `value` = the error) or returned a bad `value`. */\n const reportCustom = (threw: boolean, value: unknown) => {\n const slot = fromColumn\n ? `columns[${primary.col?.index}].sortAlgorithm`\n : 'sorting.algorithm'\n const fallback = 'sorted-native'\n if (!threw) {\n // The slot contract check is dev only (§3.4 slotContract); the fallback applies always.\n if ((process.env.NODE_ENV !== \"production\")) {\n ctx.emit('DK_CALLBACK_BAD_RETURN', {\n slot,\n expected: `a Uint32Array of ${indices.length} row indices`,\n received: describeReturn(value),\n count: 1,\n fallback,\n })\n }\n return\n }\n const name = errorName(value)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot,\n count: 1,\n fallback,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: value },\n )\n }\n\n // At most one retry per entry: each failing sortFn falls back to the default comparator.\n for (;;) {\n try {\n const out = sortOnce()\n if (opts.debug) {\n ctx.emit('DK_SORT_STRATEGY', {\n algorithm,\n reason,\n n: indices.length,\n ms: now() - t0,\n by: by.map((e) => `${String(e.id)}:${e.desc ? 'desc' : 'asc'}`),\n ...(primary.col ? { column: { index: primary.col.index, id: primary.col.id } } : {}),\n })\n }\n shown = { input: indices, output: out }\n return out\n } catch (e) {\n if (!(e instanceof SortFnFailed)) throw e\n const entry = entries[e.entry] as (typeof entries)[number]\n entry.sortFn = undefined\n const col = entry.col as ResolvedColumn\n const name = errorName(e.error)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: `columns[${col.index}].sortFn`,\n column: col.id,\n count: 1,\n fallback: 'sorted-default',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e.error },\n )\n }\n }\n },\n })\n}\n"],"mappings":"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","names":["import_codes","reason","by"]}
1
+ {"version":3,"sources":["../../../src/features/sorting/sorting.ts"],"sourcesContent":["import { optionDiagnostics } from '../../catalog/codes'\nimport { defineOptions } from '../../catalog/options'\nimport { describeReturn } from '../../catalog/slots'\nimport type { SortAlgorithm } from '../../column/column-def'\nimport { compilePath, getValue } from '../../column/get-value'\nimport type { Path } from '../../column/path'\nimport { keepDiagnostics } from '../../diagnostics/catalog'\nimport '../../diagnostics/process-guard'\nimport { proseArg } from '../../diagnostics/prose'\nimport { describeValue } from '../../diagnostics/redact'\nimport type { Emit } from '../../diagnostics/types'\nimport { defineFeature } from '../../feature/define'\nimport { type SliceFix, sliceGuard } from '../../feature/slice-guard'\nimport type { FeatureTypes, RowModelContext } from '../../feature/types'\nimport { CellFailures } from '../../intercept/cell-batch'\nimport { errorName } from '../../intercept/classify'\nimport { boundaryDiagnostics } from '../../intercept/codes'\nimport { type ResolvedColumn, resolveColumns } from '../../pipeline/columns'\nimport { envDiagnostics } from '../../pipeline/env-codes'\nimport { allRows } from '../../pipeline/indices'\nimport { sliced } from '../../pipeline/slice'\nimport type { ColumnValues } from '../../pipeline/types'\nimport { type DataMode, modeOption } from '../../source/mode'\nimport { detectCapability, hasCapability } from '../../versioning/capability'\nimport { comparatorDiagnostics, sortingDiagnostics } from './codes'\nimport {\n defaultIndexComparator,\n type IndexComparator,\n RANK,\n sortFnIndexComparator,\n typeRank,\n} from './compare'\nimport { collationRanks } from './ranks'\nimport {\n chooseAuto,\n hasExsorted,\n intKeys,\n needsIntKeys,\n sortIntKeys,\n sortWithComparator,\n} from './strategy'\n\nkeepDiagnostics(\n sortingDiagnostics,\n comparatorDiagnostics,\n boundaryDiagnostics,\n optionDiagnostics,\n envDiagnostics,\n)\n\n/** One sort key: a column id (a path of the row type) and its direction. */\nexport type SortEntry<T> = { id: Path<T>; desc: boolean }\n\n/** The `sorting` slice (§6.4): multi-column, earlier entries first. Empty = unsorted. */\nexport type SortingState<T> = { by: readonly SortEntry<T>[] }\n\nexport type SortDirection = 'asc' | 'desc'\n\n/** An entry with an `id` (a `null` entry or one without an id is malformed, #89). */\nconst isEntry = (e: unknown): e is SortEntry<unknown> => (e as { id?: unknown } | null)?.id != null\n\nconst byOf = (s: unknown): unknown => (s as { by?: unknown } | null | undefined)?.by\n\n/**\n * The entries of a slice; `[]` for a malformed one (a controlled slice not fed back yet, #89).\n * The slice itself is replaced by the guard (`DK_INVALID_STATE`).\n */\nconst entriesOf = (s: unknown): readonly SortEntry<unknown>[] => {\n const by = byOf(s)\n return Array.isArray(by) ? by.filter(isEntry) : []\n}\n\n/** A malformed restored slice: the valid entries are kept (#89). */\nfunction fixSlice(s: unknown): SliceFix<SortingState<unknown>> | undefined {\n const raw = byOf(s)\n const by = entriesOf(s)\n if (Array.isArray(raw) && raw.length === by.length) return undefined\n const bad = Array.isArray(raw) ? raw.findIndex((e) => !isEntry(e)) : -1\n return [\n { by },\n bad < 0 ? describeValue(raw ?? s) : `by[${bad}]: ${describeValue((raw as unknown[])[bad])}`,\n `{ by: [${by.length} valid] }`,\n ]\n}\n\n/** Replaces the sort; an equal one keeps the slice (same reference, no notification, #21). */\nconst setSort = (\n ctx: { getState(): unknown; setState(s: SortingState<unknown>): void },\n by: readonly SortEntry<unknown>[],\n) => {\n // JSON equality (key order included, #21); a restored entry nested deep enough to overflow\n // JSON.stringify counts as a change instead of throwing (#103).\n try {\n if (JSON.stringify(byOf(ctx.getState())) === JSON.stringify(by)) return\n } catch {}\n // A value that is not an array reaches the guard (dev: replaced, DK_INVALID_STATE).\n ctx.setState({ by: Array.isArray(by) ? by.slice() : by })\n}\n\nexport type SortingApi<T> = {\n /**\n * Cycles `id` asc → desc → none. Without `multi` the result is a single-column sort; with `multi`\n * (Shift+click) `id` is appended, cycled in place or removed and the other entries are kept.\n */\n toggleSort(id: Path<T>, options?: { multi?: boolean }): void\n /** Replaces the whole sort. */\n setSorting(by: readonly SortEntry<T>[]): void\n /** Removes every sort entry (input order). */\n clearSorting(): void\n /** `id`'s direction in the current sort, or `false` (for `aria-sort`). */\n getSortDirection(id: Path<T>): SortDirection | false\n}\n\nexport interface SortingTypes extends FeatureTypes {\n state: SortingState<this['T']>\n api: SortingApi<this['T']>\n}\n\n/**\n * How rows are sorted (§6.4): `'auto'` (default) picks per sort from one O(n) scan — exsorted\n * tim / counting / radix for a single column of safe-integer keys (numbers, `Date`s), native\n * `Array.prototype.sort` otherwise. A built-in name forces that algorithm (radix / counting only\n * apply to safe-integer keys); a function sorts the row indices itself.\n */\nexport type SortAlgorithmOption = SortAlgorithm\n\nexport interface SortingOptions {\n /**\n * Locale(s) of the string collator (`Intl.Collator(locale, { numeric: true })`). Default `'en'`,\n * not the runtime's: the server and the browser must sort alike (SSR hydration, #12).\n */\n locale?: string | readonly string[]\n /** The sort algorithm (default `'auto'`); a column's `sortAlgorithm` takes precedence. */\n algorithm?: SortAlgorithmOption\n /** Reports the algorithm chosen for each sort, why, n and the time taken (`DK_SORT_STRATEGY`). */\n debug?: boolean\n /**\n * `'server'`: the server sorts (its state goes to `options.fetcher`, or the app fetches); core\n * skips this step (§7.1). Default `'client'`.\n */\n mode?: DataMode\n}\n\nconst validLocale = (v: unknown) => {\n try {\n Intl.getCanonicalLocales(v as string | string[])\n return true\n } catch {\n return false\n }\n}\n\nconst ALGORITHMS = ['auto', 'tim', 'radix', 'counting', 'native'] as const\n\nconst sortingOptions = {\n locale: {\n type: ['string', 'array'],\n check: validLocale,\n expected: 'a BCP 47 locale tag or a list of them, e.g. \"th\" or [\"th\", \"en\"]',\n },\n algorithm: {\n type: ['string', 'function'],\n oneOf: ALGORITHMS,\n // A literal (not built from ALGORITHMS): a module-level call would keep the schema in production.\n expected:\n \"one of 'auto', 'tim', 'radix', 'counting', 'native', or (indices, compare) => indices\",\n },\n debug: { type: 'boolean' },\n mode: modeOption,\n} as const\n\ntype CustomAlgorithm = Extract<SortAlgorithm, (...args: never[]) => unknown>\n\nconst now = () => (typeof performance === 'undefined' ? Date.now() : performance.now())\n\n/**\n * From this many rows, `auto` sorts a string column by precomputed collation ranks (§9.1): one\n * time-sliced job per column values, then integer-key sorts (a few ms at 100k rows) instead of a\n * collator call per comparison (~100–200 ms at 100k, one long task).\n */\nconst RANKS_MIN = 10_000\n\nconst missing = (v: unknown) => typeRank(v) === RANK.missing\n\n/**\n * Dev check of a column's `sortFn` (§8.3 `DK_SORT_COMPARATOR_INVALID`), sampled: up to 8 present\n * values spread over the input, every pair both ways. A throw gives no verdict (the sort reports\n * it as `DK_CALLBACK_FAILED`).\n */\nfunction checkSortFn(\n fn: SortFn,\n values: ColumnValues,\n indices: Uint32Array,\n): { reason: 'nan' | 'not-number' | 'inconsistent'; received?: string } | undefined {\n const sample: unknown[] = []\n const step = Math.max(1, Math.floor(indices.length / 8))\n for (let i = 0; i < indices.length && sample.length < 8; i += step) {\n const v = values[indices[i] as number]\n if (!missing(v)) sample.push(v)\n }\n try {\n for (let i = 0; i < sample.length; i++) {\n for (let j = i; j < sample.length; j++) {\n const x = fn(sample[i], sample[j])\n const y = fn(sample[j], sample[i])\n for (const r of [x, y]) {\n if (typeof r !== 'number') return { reason: 'not-number', received: describeReturn(r) }\n if (Number.isNaN(r)) return { reason: 'nan' }\n }\n if (Math.sign(x) !== -Math.sign(y)) return { reason: 'inconsistent' }\n }\n }\n } catch {\n return undefined\n }\n return undefined\n}\n\ntype SortFn = (a: unknown, b: unknown) => number\ntype SortBy = (row: unknown) => unknown\n\nconst fnField = (def: object, field: 'sortFn' | 'sortBy') => {\n const f = (def as Record<string, unknown>)[field]\n return typeof f === 'function' ? f : undefined\n}\n\n/** Aborts a native sort when a column's `sortFn` throws (the entry then falls back). */\nclass SortFnFailed {\n constructor(\n readonly entry: number,\n readonly error: unknown,\n ) {}\n}\n\n/**\n * Sorting (§6.4): `toggleSort` (asc → desc → none, `multi`), stable sort of the row indices with\n * the default comparator — missing values (`null`, `undefined`, `NaN`, invalid `Date`) last in both\n * directions, mixed types by type rank, strings with one `Intl.Collator(locale, { numeric: true })`\n * — or a column's `sortFn` / `sortBy`. Never touches the data: a copy of the index array is sorted.\n *\n * `algorithm: 'auto'` (default) picks per sort from one O(n) scan (§6.4): exsorted tim / counting /\n * radix for a single column of safe-integer keys (numbers, `Date`s), native `Array.prototype.sort`\n * (stable) for strings, floats, multi-column and `sortFn`. Every choice gives the same stable order.\n * `sorting({ algorithm })` or a column's `sortAlgorithm` overrides it; `debug: true` reports each\n * choice (`DK_SORT_STRATEGY`).\n */\nexport const sorting = (opts: SortingOptions = {}) => {\n // Dev only (§9.3): production reads a malformed slice as no sort and stays cheap.\n const guard = (process.env.NODE_ENV !== \"production\") ? sliceGuard('sorting', fixSlice) : undefined\n let collator: Intl.Collator | undefined\n /** The collator; `DK_ENV_FALLBACK` when the runtime supports none of the requested locales. */\n const getCollator = (emit: Emit) => {\n if (collator) return collator\n const locale = (opts.locale ?? 'en') as string | string[]\n let supported = true\n try {\n collator = new Intl.Collator(locale, { numeric: true })\n supported = Intl.Collator.supportedLocalesOf(locale).length > 0\n } catch {\n collator = new Intl.Collator(undefined, { numeric: true })\n supported = false\n }\n if (!supported) {\n emit('DK_ENV_FALLBACK', {\n api: 'Intl.Collator',\n feature: 'sorting',\n requested: ([] as string[]).concat(locale).join(', '),\n fallback: `collation|${collator.resolvedOptions().locale}`,\n })\n }\n return collator\n }\n\n /** Values array → the key of its collation-ranks job (`ctx.slice`); released with the values. */\n const rankKeys = new WeakMap<object, object>()\n function ranksFor(ctx: RowModelContext, values: readonly unknown[]) {\n let key = rankKeys.get(values)\n if (!key) {\n key = {}\n rankKeys.set(values, key)\n }\n const c = getCollator(ctx.emit)\n return sliced(ctx, key, () => collationRanks(values, c))\n }\n /** The last sorted output and its input: the stand-in while ranks are computed (§9.1). */\n let shown: { input: Uint32Array; output: Uint32Array } | undefined\n\n // Values that the column cache does not hold, per data reference (released with it).\n const sortByCache = new WeakMap<readonly unknown[], WeakMap<object, unknown[]>>()\n const pathCache = new WeakMap<readonly unknown[], Map<string, unknown[]>>()\n /** exsorted feature detection (§8.5), once per feature instance, on the first sort needing it. */\n let exsorted: boolean | undefined\n\n /** `sortBy` failures (§3.4): numbers only; text is built only when a cell failed. */\n const sortByFailures = new CellFailures()\n\n /**\n * `sortBy` is a cell slot: one `column:batch` per column per data reference, an inline\n * `try/catch` per row. A failed row (or a batch an interceptor skipped) keys as `undefined`,\n * which sorts last.\n */\n function sortByValues(ctx: RowModelContext, col: ResolvedColumn, sortBy: SortBy): unknown[] {\n const data = ctx.data\n let byDef = sortByCache.get(data)\n if (!byDef) {\n byDef = new WeakMap()\n sortByCache.set(data, byDef)\n }\n let out = byDef.get(col.def)\n if (out) return out\n const values: unknown[] = new Array(data.length).fill(undefined)\n const rows = allRows(data)\n sortByFailures.reset()\n ctx.batch(col.id, 'sortBy', rows, () => {\n for (let i = 0; i < rows.length; i++) {\n const r = rows[i] as number\n try {\n values[r] = sortBy(data[r])\n } catch (e) {\n sortByFailures.add(r, e)\n }\n }\n sortByFailures.report(ctx.emit, col.index, col.id, 'sortBy')\n })\n sortByFailures.reset()\n out = values\n byDef.set(col.def, out)\n return out\n }\n\n function pathValues(ctx: RowModelContext, id: string): unknown[] {\n const data = ctx.data\n let byId = pathCache.get(data)\n if (!byId) {\n byId = new Map()\n pathCache.set(data, byId)\n }\n let out = byId.get(id)\n if (out) return out\n const path = compilePath(id)\n out = new Array(data.length)\n for (let r = 0; r < data.length; r++) out[r] = getValue(data[r], path)\n byId.set(id, out)\n return out\n }\n\n return defineFeature<'sorting', SortingTypes>({\n name: 'sorting',\n stage: 'sort',\n mode: opts.mode ?? 'client',\n options: defineOptions(\n // The option validator runs in development only (§9.3): production drops the schema.\n (process.env.NODE_ENV !== \"production\") ? sortingOptions : ({} as typeof sortingOptions),\n opts,\n ),\n ...(guard ? { interceptors: [guard.interceptor] } : undefined),\n initialState: () => ({ by: [] }),\n // After destroy(): still a declared value (`aria-sort` reads it during teardown renders).\n destroyedResult: { getSortDirection: () => false },\n createApi: (ctx) => {\n guard?.install(ctx)\n // Values, not updaters: a library step is never reported as a failing user `updater` (#89).\n return {\n toggleSort: (id, options) => {\n const by = entriesOf(ctx.getState())\n const i = by.findIndex((e) => e.id === id)\n const cur = by[i]\n const next = !cur ? { id, desc: false } : cur.desc ? undefined : { id, desc: true }\n if (!options?.multi) return ctx.setState({ by: next ? [next] : [] })\n if (!cur) return ctx.setState({ by: [...by, next as SortEntry<unknown>] })\n const out = by.slice()\n if (next) out[i] = next as SortEntry<unknown>\n else out.splice(i, 1)\n ctx.setState({ by: out })\n },\n setSorting: (by) => setSort(ctx, by),\n clearSorting: () => setSort(ctx, []),\n getSortDirection: (id) => {\n const e = entriesOf(ctx.getState()).find((x) => x.id === id)\n return e ? (e.desc ? 'desc' : 'asc') : false\n },\n }\n },\n rowModel: (indices, state, ctx) => {\n const by = entriesOf(state)\n if (by.length === 0 || indices.length < 2) {\n shown = undefined\n return indices\n }\n const t0 = opts.debug ? now() : 0\n const cols = resolveColumns(ctx.columns)\n const entries = by.map((e) => {\n const id = String(e.id)\n const col = cols.byId.get(id)\n const sortBy = col && (fnField(col.def, 'sortBy') as SortBy | undefined)\n const values: ColumnValues = sortBy\n ? sortByValues(ctx, col, sortBy)\n : (ctx.getColumnValues(id) ?? pathValues(ctx, id))\n const sortFn =\n col && !sortBy ? (fnField(col.def, 'sortFn') as SortFn | undefined) : undefined\n return { col, desc: e.desc === true, values, sortFn, ranked: false }\n })\n\n // Dev (§8.3): a sampled sortFn check; an invalid one falls back to the default comparator.\n if ((process.env.NODE_ENV !== \"production\")) {\n for (const e of entries) {\n if (!e.sortFn) continue\n const bad = checkSortFn(e.sortFn, e.values, indices)\n if (!bad) continue\n e.sortFn = undefined\n const col = e.col as ResolvedColumn\n ctx.emit('DK_SORT_COMPARATOR_INVALID', { column: col.id, index: col.index, ...bad })\n }\n }\n\n // The requested algorithm: the primary column's `sortAlgorithm`, else the table's.\n const primary = entries[0] as (typeof entries)[number]\n const colAlgorithm =\n primary.col && (primary.col.def as { sortAlgorithm?: unknown }).sortAlgorithm\n const fromColumn = colAlgorithm !== undefined\n let requested = (fromColumn ? colAlgorithm : (opts.algorithm ?? 'auto')) as SortAlgorithm\n const noEffect = (reason: string) =>\n ctx.emit(\n 'DK_OPTION_NO_EFFECT',\n fromColumn\n ? { path: `columns[${primary.col?.index}].sortAlgorithm`, reason, once: false }\n : { path: 'algorithm', feature: 'sorting', reason, once: false },\n )\n if (\n typeof requested !== 'function' &&\n !(ALGORITHMS as readonly unknown[]).includes(requested)\n ) {\n noEffect(`not-algorithm|${proseArg(JSON.stringify(requested))}`)\n requested = 'auto'\n }\n if (requested !== 'native' && exsorted === undefined) {\n // DK_DEP_INCOMPATIBLE is a development check (§8.5); the fallback is not.\n exsorted = (process.env.NODE_ENV !== \"production\")\n ? detectCapability(\n hasExsorted,\n {\n feature: 'sorting',\n dependency: 'exsorted',\n capability: 'timSort / radixSort / countingSort',\n supported: '^1.2.3',\n fallback: 'Array.prototype.sort (native, stable)',\n },\n ctx.emit,\n )\n : hasCapability(hasExsorted)\n }\n\n // auto at large n (§9.1): string columns sort by collation ranks, computed by a sliced job.\n if (requested === 'auto' && indices.length >= RANKS_MIN) {\n let computing = false\n for (const e of entries) {\n if (e.sortFn || e.values instanceof Float64Array) continue\n const ranks = ranksFor(ctx, e.values)\n if (ranks === undefined) computing = true\n else if (ranks) {\n e.values = ranks\n e.ranked = true\n }\n }\n // Meanwhile: the previous order of these rows (or the input order); 'pending'.\n if (computing) return shown && shown.input === indices ? shown.output : indices\n }\n const ranked = entries.some((e) => e.ranked)\n\n const build = (): IndexComparator => {\n const cmps = entries.map((e, k) => {\n const fn = e.sortFn\n if (!fn) return defaultIndexComparator(e.values, e.desc, getCollator(ctx.emit))\n const guarded: SortFn = (a, b) => {\n try {\n return fn(a, b)\n } catch (error) {\n throw new SortFnFailed(k, error)\n }\n }\n return sortFnIndexComparator(e.values, e.desc, guarded)\n })\n if (cmps.length === 1) return cmps[0] as IndexComparator\n return (a, b) => {\n for (let k = 0; k < cmps.length; k++) {\n const c = (cmps[k] as IndexComparator)(a, b)\n if (c !== 0) return c\n }\n return 0\n }\n }\n\n let algorithm: string = 'native'\n let reason = ''\n /** One attempt; a throwing sortFn propagates as SortFnFailed (the loop below retries). */\n const sortOnce = (): Uint32Array => {\n const want = requested\n if (typeof want === 'function') {\n const custom = want as CustomAlgorithm\n let res: unknown\n try {\n res = custom(indices.slice(), build())\n } catch (error) {\n if (error instanceof SortFnFailed) throw error\n reportCustom(true, error)\n return native('custom-threw')\n }\n if (res instanceof Uint32Array && res.length === indices.length) {\n algorithm = 'custom'\n reason = fromColumn ? 'column sortAlgorithm' : 'sorting({ algorithm })'\n return res\n }\n reportCustom(false, res)\n return native('custom-bad')\n }\n if (exsorted === false) return native('exsorted unavailable')\n const by = fromColumn ? 'column sortAlgorithm' : 'sorting({ algorithm })'\n // Integer keys: a single column with the default comparator (§6.4).\n const single = entries.length === 1 && !primary.sortFn\n const keys =\n single && want !== 'native' ? intKeys(primary.values, indices, primary.desc) : undefined\n if (want !== 'auto' && want !== 'native') {\n if (keys) {\n try {\n const out = sortIntKeys(keys, want)\n algorithm = want\n reason = `int-keys|${by}`\n return out\n } catch {\n noEffect(`exsorted-${want === 'counting' ? 'range' : 'failed'}|${want}`)\n }\n } else if (needsIntKeys(want)) {\n noEffect(`needs-int-keys|${want}`)\n } else {\n algorithm = want\n reason = by\n return sortWithComparator(indices, build(), want as 'tim')\n }\n } else if (want === 'native') return native(by)\n if (!keys) {\n return native(\n single ? 'not-safe-int' : entries.length > 1 ? 'multi-column' : 'custom sortFn',\n )\n }\n const choice = chooseAuto(keys)\n algorithm = choice.algorithm\n reason = `auto-${ranked ? 'ranked-' : ''}${choice.reason}`\n return sortIntKeys(keys, choice.algorithm)\n }\n const native = (why: string) => {\n algorithm = 'native'\n reason = ranked ? `ranks|${why}` : why\n return sortWithComparator(indices, build(), 'native')\n }\n /** A custom algorithm threw (`threw`, `value` = the error) or returned a bad `value`. */\n const reportCustom = (threw: boolean, value: unknown) => {\n const slot = fromColumn\n ? `columns[${primary.col?.index}].sortAlgorithm`\n : 'sorting.algorithm'\n const fallback = 'sorted-native'\n if (!threw) {\n // The slot contract check is dev only (§3.4 slotContract); the fallback applies always.\n if ((process.env.NODE_ENV !== \"production\")) {\n ctx.emit('DK_CALLBACK_BAD_RETURN', {\n slot,\n expected: `a Uint32Array of ${indices.length} row indices`,\n received: describeReturn(value),\n count: 1,\n fallback,\n })\n }\n return\n }\n const name = errorName(value)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot,\n count: 1,\n fallback,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: value },\n )\n }\n\n // At most one retry per entry: each failing sortFn falls back to the default comparator.\n for (;;) {\n try {\n const out = sortOnce()\n if (opts.debug) {\n ctx.emit('DK_SORT_STRATEGY', {\n algorithm,\n reason,\n n: indices.length,\n ms: now() - t0,\n by: by.map((e) => `${String(e.id)}:${e.desc ? 'desc' : 'asc'}`),\n ...(primary.col ? { column: { index: primary.col.index, id: primary.col.id } } : {}),\n })\n }\n shown = { input: indices, output: out }\n return out\n } catch (e) {\n if (!(e instanceof SortFnFailed)) throw e\n const entry = entries[e.entry] as (typeof entries)[number]\n entry.sortFn = undefined\n const col = entry.col as ResolvedColumn\n const name = errorName(e.error)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: `columns[${col.index}].sortFn`,\n column: col.id,\n count: 1,\n fallback: 'sorted-default',\n ...(name === undefined ? {} : { errorName: name }),\n },\n { cause: e.error },\n )\n }\n }\n },\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAkC;AAClC,qBAA8B;AAC9B,mBAA+B;AAE/B,uBAAsC;AAEtC,qBAAgC;AAChC,2BAAO;AACP,mBAAyB;AACzB,oBAA8B;AAE9B,oBAA8B;AAC9B,yBAA0C;AAE1C,wBAA6B;AAC7B,sBAA0B;AAC1B,IAAAA,gBAAoC;AACpC,qBAAoD;AACpD,uBAA+B;AAC/B,qBAAwB;AACxB,mBAAuB;AAEvB,kBAA0C;AAC1C,wBAAgD;AAChD,IAAAA,gBAA0D;AAC1D,qBAMO;AACP,mBAA+B;AAC/B,sBAOO;AAAA,IAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWA,IAAM,UAAU,CAAC,MAAyC,GAA+B,MAAM;AAE/F,IAAM,OAAO,CAAC,MAAyB,GAA2C;AAMlF,IAAM,YAAY,CAAC,MAA8C;AAC/D,QAAM,KAAK,KAAK,CAAC;AACjB,SAAO,MAAM,QAAQ,EAAE,IAAI,GAAG,OAAO,OAAO,IAAI,CAAC;AACnD;AAGA,SAAS,SAAS,GAAyD;AACzE,QAAM,MAAM,KAAK,CAAC;AAClB,QAAM,KAAK,UAAU,CAAC;AACtB,MAAI,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,GAAG,OAAQ,QAAO;AAC3D,QAAM,MAAM,MAAM,QAAQ,GAAG,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI;AACrE,SAAO;AAAA,IACL,EAAE,GAAG;AAAA,IACL,MAAM,QAAI,6BAAc,OAAO,CAAC,IAAI,MAAM,GAAG,UAAM,6BAAe,IAAkB,GAAG,CAAC,CAAC;AAAA,IACzF,UAAU,GAAG,MAAM;AAAA,EACrB;AACF;AAGA,IAAM,UAAU,CACd,KACA,OACG;AAGH,MAAI;AACF,QAAI,KAAK,UAAU,KAAK,IAAI,SAAS,CAAC,CAAC,MAAM,KAAK,UAAU,EAAE,EAAG;AAAA,EACnE,QAAQ;AAAA,EAAC;AAET,MAAI,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC;AAC1D;AA8CA,IAAM,cAAc,CAAC,MAAe;AAClC,MAAI;AACF,SAAK,oBAAoB,CAAsB;AAC/C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,aAAa,CAAC,QAAQ,OAAO,SAAS,YAAY,QAAQ;AAEhE,IAAM,iBAAiB;AAAA,EACrB,QAAQ;AAAA,IACN,MAAM,CAAC,UAAU,OAAO;AAAA,IACxB,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AAAA,EACA,WAAW;AAAA,IACT,MAAM,CAAC,UAAU,UAAU;AAAA,IAC3B,OAAO;AAAA;AAAA,IAEP,UACE;AAAA,EACJ;AAAA,EACA,OAAO,EAAE,MAAM,UAAU;AAAA,EACzB,MAAM;AACR;AAIA,IAAM,MAAM,MAAO,OAAO,gBAAgB,cAAc,KAAK,IAAI,IAAI,YAAY,IAAI;AAOrF,IAAM,YAAY;AAElB,IAAM,UAAU,CAAC,UAAe,yBAAS,CAAC,MAAM,oBAAK;AAOrD,SAAS,YACP,IACA,QACA,SACkF;AAClF,QAAM,SAAoB,CAAC;AAC3B,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,SAAS,CAAC,CAAC;AACvD,WAAS,IAAI,GAAG,IAAI,QAAQ,UAAU,OAAO,SAAS,GAAG,KAAK,MAAM;AAClE,UAAM,IAAI,OAAO,QAAQ,CAAC,CAAW;AACrC,QAAI,CAAC,QAAQ,CAAC,EAAG,QAAO,KAAK,CAAC;AAAA,EAChC;AACA,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAM,IAAI,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACjC,cAAM,IAAI,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACjC,mBAAW,KAAK,CAAC,GAAG,CAAC,GAAG;AACtB,cAAI,OAAO,MAAM,SAAU,QAAO,EAAE,QAAQ,cAAc,cAAU,6BAAe,CAAC,EAAE;AACtF,cAAI,OAAO,MAAM,CAAC,EAAG,QAAO,EAAE,QAAQ,MAAM;AAAA,QAC9C;AACA,YAAI,KAAK,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,EAAG,QAAO,EAAE,QAAQ,eAAe;AAAA,MACtE;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAKA,IAAM,UAAU,CAAC,KAAa,UAA+B;AAC3D,QAAM,IAAK,IAAgC,KAAK;AAChD,SAAO,OAAO,MAAM,aAAa,IAAI;AACvC;AAGA,IAAM,eAAN,MAAmB;AAAA,EACjB,YACW,OACA,OACT;AAFS;AACA;AAAA,EACR;AACL;AAcO,IAAM,UAAU,CAAC,OAAuB,CAAC,MAAM;AAEpD,QAAM,QAAS,QAAQ,IAAI,aAAa,mBAAgB,+BAAW,WAAW,QAAQ,IAAI;AAC1F,MAAI;AAEJ,QAAM,cAAc,CAAC,SAAe;AAClC,QAAI,SAAU,QAAO;AACrB,UAAM,SAAU,KAAK,UAAU;AAC/B,QAAI,YAAY;AAChB,QAAI;AACF,iBAAW,IAAI,KAAK,SAAS,QAAQ,EAAE,SAAS,KAAK,CAAC;AACtD,kBAAY,KAAK,SAAS,mBAAmB,MAAM,EAAE,SAAS;AAAA,IAChE,QAAQ;AACN,iBAAW,IAAI,KAAK,SAAS,QAAW,EAAE,SAAS,KAAK,CAAC;AACzD,kBAAY;AAAA,IACd;AACA,QAAI,CAAC,WAAW;AACd,WAAK,mBAAmB;AAAA,QACtB,KAAK;AAAA,QACL,SAAS;AAAA,QACT,WAAY,CAAC,EAAe,OAAO,MAAM,EAAE,KAAK,IAAI;AAAA,QACpD,UAAU,aAAa,SAAS,gBAAgB,EAAE,MAAM;AAAA,MAC1D,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,oBAAI,QAAwB;AAC7C,WAAS,SAAS,KAAsB,QAA4B;AAClE,QAAI,MAAM,SAAS,IAAI,MAAM;AAC7B,QAAI,CAAC,KAAK;AACR,YAAM,CAAC;AACP,eAAS,IAAI,QAAQ,GAAG;AAAA,IAC1B;AACA,UAAM,IAAI,YAAY,IAAI,IAAI;AAC9B,eAAO,qBAAO,KAAK,KAAK,UAAM,6BAAe,QAAQ,CAAC,CAAC;AAAA,EACzD;AAEA,MAAI;AAGJ,QAAM,cAAc,oBAAI,QAAwD;AAChF,QAAM,YAAY,oBAAI,QAAoD;AAE1E,MAAI;AAGJ,QAAM,iBAAiB,IAAI,+BAAa;AAOxC,WAAS,aAAa,KAAsB,KAAqB,QAA2B;AAC1F,UAAM,OAAO,IAAI;AACjB,QAAI,QAAQ,YAAY,IAAI,IAAI;AAChC,QAAI,CAAC,OAAO;AACV,cAAQ,oBAAI,QAAQ;AACpB,kBAAY,IAAI,MAAM,KAAK;AAAA,IAC7B;AACA,QAAI,MAAM,MAAM,IAAI,IAAI,GAAG;AAC3B,QAAI,IAAK,QAAO;AAChB,UAAM,SAAoB,IAAI,MAAM,KAAK,MAAM,EAAE,KAAK,MAAS;AAC/D,UAAM,WAAO,wBAAQ,IAAI;AACzB,mBAAe,MAAM;AACrB,QAAI,MAAM,IAAI,IAAI,UAAU,MAAM,MAAM;AACtC,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAM,IAAI,KAAK,CAAC;AAChB,YAAI;AACF,iBAAO,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC;AAAA,QAC5B,SAAS,GAAG;AACV,yBAAe,IAAI,GAAG,CAAC;AAAA,QACzB;AAAA,MACF;AACA,qBAAe,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI,QAAQ;AAAA,IAC7D,CAAC;AACD,mBAAe,MAAM;AACrB,UAAM;AACN,UAAM,IAAI,IAAI,KAAK,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,WAAS,WAAW,KAAsB,IAAuB;AAC/D,UAAM,OAAO,IAAI;AACjB,QAAI,OAAO,UAAU,IAAI,IAAI;AAC7B,QAAI,CAAC,MAAM;AACT,aAAO,oBAAI,IAAI;AACf,gBAAU,IAAI,MAAM,IAAI;AAAA,IAC1B;AACA,QAAI,MAAM,KAAK,IAAI,EAAE;AACrB,QAAI,IAAK,QAAO;AAChB,UAAM,WAAO,8BAAY,EAAE;AAC3B,UAAM,IAAI,MAAM,KAAK,MAAM;AAC3B,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK,KAAI,CAAC,QAAI,2BAAS,KAAK,CAAC,GAAG,IAAI;AACrE,SAAK,IAAI,IAAI,GAAG;AAChB,WAAO;AAAA,EACT;AAEA,aAAO,6BAAuC;AAAA,IAC5C,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM,KAAK,QAAQ;AAAA,IACnB,aAAS;AAAA;AAAA,MAEN,QAAQ,IAAI,aAAa,eAAgB,iBAAkB,CAAC;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,GAAI,QAAQ,EAAE,cAAc,CAAC,MAAM,WAAW,EAAE,IAAI;AAAA,IACpD,cAAc,OAAO,EAAE,IAAI,CAAC,EAAE;AAAA;AAAA,IAE9B,iBAAiB,EAAE,kBAAkB,MAAM,MAAM;AAAA,IACjD,WAAW,CAAC,QAAQ;AAClB,aAAO,QAAQ,GAAG;AAElB,aAAO;AAAA,QACL,YAAY,CAAC,IAAI,YAAY;AAC3B,gBAAM,KAAK,UAAU,IAAI,SAAS,CAAC;AACnC,gBAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACzC,gBAAM,MAAM,GAAG,CAAC;AAChB,gBAAM,OAAO,CAAC,MAAM,EAAE,IAAI,MAAM,MAAM,IAAI,IAAI,OAAO,SAAY,EAAE,IAAI,MAAM,KAAK;AAClF,cAAI,CAAC,SAAS,MAAO,QAAO,IAAI,SAAS,EAAE,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;AACnE,cAAI,CAAC,IAAK,QAAO,IAAI,SAAS,EAAE,IAAI,CAAC,GAAG,IAAI,IAA0B,EAAE,CAAC;AACzE,gBAAM,MAAM,GAAG,MAAM;AACrB,cAAI,KAAM,KAAI,CAAC,IAAI;AAAA,cACd,KAAI,OAAO,GAAG,CAAC;AACpB,cAAI,SAAS,EAAE,IAAI,IAAI,CAAC;AAAA,QAC1B;AAAA,QACA,YAAY,CAAC,OAAO,QAAQ,KAAK,EAAE;AAAA,QACnC,cAAc,MAAM,QAAQ,KAAK,CAAC,CAAC;AAAA,QACnC,kBAAkB,CAAC,OAAO;AACxB,gBAAM,IAAI,UAAU,IAAI,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC3D,iBAAO,IAAK,EAAE,OAAO,SAAS,QAAS;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU,CAAC,SAAS,OAAO,QAAQ;AACjC,YAAM,KAAK,UAAU,KAAK;AAC1B,UAAI,GAAG,WAAW,KAAK,QAAQ,SAAS,GAAG;AACzC,gBAAQ;AACR,eAAO;AAAA,MACT;AACA,YAAM,KAAK,KAAK,QAAQ,IAAI,IAAI;AAChC,YAAM,WAAO,+BAAe,IAAI,OAAO;AACvC,YAAM,UAAU,GAAG,IAAI,CAAC,MAAM;AAC5B,cAAM,KAAK,OAAO,EAAE,EAAE;AACtB,cAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAC5B,cAAM,SAAS,OAAQ,QAAQ,IAAI,KAAK,QAAQ;AAChD,cAAM,SAAuB,SACzB,aAAa,KAAK,KAAK,MAAM,IAC5B,IAAI,gBAAgB,EAAE,KAAK,WAAW,KAAK,EAAE;AAClD,cAAM,SACJ,OAAO,CAAC,SAAU,QAAQ,IAAI,KAAK,QAAQ,IAA2B;AACxE,eAAO,EAAE,KAAK,MAAM,EAAE,SAAS,MAAM,QAAQ,QAAQ,QAAQ,MAAM;AAAA,MACrE,CAAC;AAGD,UAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,mBAAW,KAAK,SAAS;AACvB,cAAI,CAAC,EAAE,OAAQ;AACf,gBAAM,MAAM,YAAY,EAAE,QAAQ,EAAE,QAAQ,OAAO;AACnD,cAAI,CAAC,IAAK;AACV,YAAE,SAAS;AACX,gBAAM,MAAM,EAAE;AACd,cAAI,KAAK,8BAA8B,EAAE,QAAQ,IAAI,IAAI,OAAO,IAAI,OAAO,GAAG,IAAI,CAAC;AAAA,QACrF;AAAA,MACF;AAGA,YAAM,UAAU,QAAQ,CAAC;AACzB,YAAM,eACJ,QAAQ,OAAQ,QAAQ,IAAI,IAAoC;AAClE,YAAM,aAAa,iBAAiB;AACpC,UAAI,YAAa,aAAa,eAAgB,KAAK,aAAa;AAChE,YAAM,WAAW,CAACC,YAChB,IAAI;AAAA,QACF;AAAA,QACA,aACI,EAAE,MAAM,WAAW,QAAQ,KAAK,KAAK,mBAAmB,QAAAA,SAAQ,MAAM,MAAM,IAC5E,EAAE,MAAM,aAAa,SAAS,WAAW,QAAAA,SAAQ,MAAM,MAAM;AAAA,MACnE;AACF,UACE,OAAO,cAAc,cACrB,CAAE,WAAkC,SAAS,SAAS,GACtD;AACA,iBAAS,qBAAiB,uBAAS,KAAK,UAAU,SAAS,CAAC,CAAC,EAAE;AAC/D,oBAAY;AAAA,MACd;AACA,UAAI,cAAc,YAAY,aAAa,QAAW;AAEpD,mBAAY,QAAQ,IAAI,aAAa,mBACjC;AAAA,UACE;AAAA,UACA;AAAA,YACE,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,YAAY;AAAA,YACZ,WAAW;AAAA,YACX,UAAU;AAAA,UACZ;AAAA,UACA,IAAI;AAAA,QACN,QACA,iCAAc,2BAAW;AAAA,MAC/B;AAGA,UAAI,cAAc,UAAU,QAAQ,UAAU,WAAW;AACvD,YAAI,YAAY;AAChB,mBAAW,KAAK,SAAS;AACvB,cAAI,EAAE,UAAU,EAAE,kBAAkB,aAAc;AAClD,gBAAM,QAAQ,SAAS,KAAK,EAAE,MAAM;AACpC,cAAI,UAAU,OAAW,aAAY;AAAA,mBAC5B,OAAO;AACd,cAAE,SAAS;AACX,cAAE,SAAS;AAAA,UACb;AAAA,QACF;AAEA,YAAI,UAAW,QAAO,SAAS,MAAM,UAAU,UAAU,MAAM,SAAS;AAAA,MAC1E;AACA,YAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,MAAM;AAE3C,YAAM,QAAQ,MAAuB;AACnC,cAAM,OAAO,QAAQ,IAAI,CAAC,GAAG,MAAM;AACjC,gBAAM,KAAK,EAAE;AACb,cAAI,CAAC,GAAI,YAAO,uCAAuB,EAAE,QAAQ,EAAE,MAAM,YAAY,IAAI,IAAI,CAAC;AAC9E,gBAAM,UAAkB,CAAC,GAAG,MAAM;AAChC,gBAAI;AACF,qBAAO,GAAG,GAAG,CAAC;AAAA,YAChB,SAAS,OAAO;AACd,oBAAM,IAAI,aAAa,GAAG,KAAK;AAAA,YACjC;AAAA,UACF;AACA,qBAAO,sCAAsB,EAAE,QAAQ,EAAE,MAAM,OAAO;AAAA,QACxD,CAAC;AACD,YAAI,KAAK,WAAW,EAAG,QAAO,KAAK,CAAC;AACpC,eAAO,CAAC,GAAG,MAAM;AACf,mBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,kBAAM,IAAK,KAAK,CAAC,EAAsB,GAAG,CAAC;AAC3C,gBAAI,MAAM,EAAG,QAAO;AAAA,UACtB;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,UAAI,YAAoB;AACxB,UAAI,SAAS;AAEb,YAAM,WAAW,MAAmB;AAClC,cAAM,OAAO;AACb,YAAI,OAAO,SAAS,YAAY;AAC9B,gBAAM,SAAS;AACf,cAAI;AACJ,cAAI;AACF,kBAAM,OAAO,QAAQ,MAAM,GAAG,MAAM,CAAC;AAAA,UACvC,SAAS,OAAO;AACd,gBAAI,iBAAiB,aAAc,OAAM;AACzC,yBAAa,MAAM,KAAK;AACxB,mBAAO,OAAO,cAAc;AAAA,UAC9B;AACA,cAAI,eAAe,eAAe,IAAI,WAAW,QAAQ,QAAQ;AAC/D,wBAAY;AACZ,qBAAS,aAAa,yBAAyB;AAC/C,mBAAO;AAAA,UACT;AACA,uBAAa,OAAO,GAAG;AACvB,iBAAO,OAAO,YAAY;AAAA,QAC5B;AACA,YAAI,aAAa,MAAO,QAAO,OAAO,sBAAsB;AAC5D,cAAMC,MAAK,aAAa,yBAAyB;AAEjD,cAAM,SAAS,QAAQ,WAAW,KAAK,CAAC,QAAQ;AAChD,cAAM,OACJ,UAAU,SAAS,eAAW,yBAAQ,QAAQ,QAAQ,SAAS,QAAQ,IAAI,IAAI;AACjF,YAAI,SAAS,UAAU,SAAS,UAAU;AACxC,cAAI,MAAM;AACR,gBAAI;AACF,oBAAM,UAAM,6BAAY,MAAM,IAAI;AAClC,0BAAY;AACZ,uBAAS,YAAYA,GAAE;AACvB,qBAAO;AAAA,YACT,QAAQ;AACN,uBAAS,YAAY,SAAS,aAAa,UAAU,QAAQ,IAAI,IAAI,EAAE;AAAA,YACzE;AAAA,UACF,eAAW,8BAAa,IAAI,GAAG;AAC7B,qBAAS,kBAAkB,IAAI,EAAE;AAAA,UACnC,OAAO;AACL,wBAAY;AACZ,qBAASA;AACT,uBAAO,oCAAmB,SAAS,MAAM,GAAG,IAAa;AAAA,UAC3D;AAAA,QACF,WAAW,SAAS,SAAU,QAAO,OAAOA,GAAE;AAC9C,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,YACL,SAAS,iBAAiB,QAAQ,SAAS,IAAI,iBAAiB;AAAA,UAClE;AAAA,QACF;AACA,cAAM,aAAS,4BAAW,IAAI;AAC9B,oBAAY,OAAO;AACnB,iBAAS,QAAQ,SAAS,YAAY,EAAE,GAAG,OAAO,MAAM;AACxD,mBAAO,6BAAY,MAAM,OAAO,SAAS;AAAA,MAC3C;AACA,YAAM,SAAS,CAAC,QAAgB;AAC9B,oBAAY;AACZ,iBAAS,SAAS,SAAS,GAAG,KAAK;AACnC,mBAAO,oCAAmB,SAAS,MAAM,GAAG,QAAQ;AAAA,MACtD;AAEA,YAAM,eAAe,CAAC,OAAgB,UAAmB;AACvD,cAAM,OAAO,aACT,WAAW,QAAQ,KAAK,KAAK,oBAC7B;AACJ,cAAM,WAAW;AACjB,YAAI,CAAC,OAAO;AAEV,cAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,gBAAI,KAAK,0BAA0B;AAAA,cACjC;AAAA,cACA,UAAU,oBAAoB,QAAQ,MAAM;AAAA,cAC5C,cAAU,6BAAe,KAAK;AAAA,cAC9B,OAAO;AAAA,cACP;AAAA,YACF,CAAC;AAAA,UACH;AACA;AAAA,QACF;AACA,cAAM,WAAO,2BAAU,KAAK;AAC5B,YAAI;AAAA,UACF;AAAA,UACA;AAAA,YACE;AAAA,YACA,OAAO;AAAA,YACP;AAAA,YACA,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,UAClD;AAAA,UACA,EAAE,OAAO,MAAM;AAAA,QACjB;AAAA,MACF;AAGA,iBAAS;AACP,YAAI;AACF,gBAAM,MAAM,SAAS;AACrB,cAAI,KAAK,OAAO;AACd,gBAAI,KAAK,oBAAoB;AAAA,cAC3B;AAAA,cACA;AAAA,cACA,GAAG,QAAQ;AAAA,cACX,IAAI,IAAI,IAAI;AAAA,cACZ,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,OAAO,SAAS,KAAK,EAAE;AAAA,cAC9D,GAAI,QAAQ,MAAM,EAAE,QAAQ,EAAE,OAAO,QAAQ,IAAI,OAAO,IAAI,QAAQ,IAAI,GAAG,EAAE,IAAI,CAAC;AAAA,YACpF,CAAC;AAAA,UACH;AACA,kBAAQ,EAAE,OAAO,SAAS,QAAQ,IAAI;AACtC,iBAAO;AAAA,QACT,SAAS,GAAG;AACV,cAAI,EAAE,aAAa,cAAe,OAAM;AACxC,gBAAM,QAAQ,QAAQ,EAAE,KAAK;AAC7B,gBAAM,SAAS;AACf,gBAAM,MAAM,MAAM;AAClB,gBAAM,WAAO,2BAAU,EAAE,KAAK;AAC9B,cAAI;AAAA,YACF;AAAA,YACA;AAAA,cACE,MAAM,WAAW,IAAI,KAAK;AAAA,cAC1B,QAAQ,IAAI;AAAA,cACZ,OAAO;AAAA,cACP,UAAU;AAAA,cACV,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,YAClD;AAAA,YACA,EAAE,OAAO,EAAE,MAAM;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":["import_codes","reason","by"]}
@@ -5,7 +5,10 @@ import { describeReturn } from "../../catalog/slots.js";
5
5
  import { compilePath, getValue } from "../../column/get-value.js";
6
6
  import { keepDiagnostics } from "../../diagnostics/catalog.js";
7
7
  import "../../diagnostics/process-guard.js";
8
+ import { proseArg } from "../../diagnostics/prose.js";
9
+ import { describeValue } from "../../diagnostics/redact.js";
8
10
  import { defineFeature } from "../../feature/define.js";
11
+ import { sliceGuard } from "../../feature/slice-guard.js";
9
12
  import { CellFailures } from "../../intercept/cell-batch.js";
10
13
  import { errorName } from "../../intercept/classify.js";
11
14
  import { boundaryDiagnostics } from "../../intercept/codes.js";
@@ -38,7 +41,30 @@ keepDiagnostics(
38
41
  optionDiagnostics,
39
42
  envDiagnostics
40
43
  );
41
- var setSort = (ctx, by) => ctx.setState((s) => JSON.stringify(s.by) === JSON.stringify(by) ? s : { by: by.slice() });
44
+ var isEntry = (e) => e?.id != null;
45
+ var byOf = (s) => s?.by;
46
+ var entriesOf = (s) => {
47
+ const by = byOf(s);
48
+ return Array.isArray(by) ? by.filter(isEntry) : [];
49
+ };
50
+ function fixSlice(s) {
51
+ const raw = byOf(s);
52
+ const by = entriesOf(s);
53
+ if (Array.isArray(raw) && raw.length === by.length) return void 0;
54
+ const bad = Array.isArray(raw) ? raw.findIndex((e) => !isEntry(e)) : -1;
55
+ return [
56
+ { by },
57
+ bad < 0 ? describeValue(raw ?? s) : `by[${bad}]: ${describeValue(raw[bad])}`,
58
+ `{ by: [${by.length} valid] }`
59
+ ];
60
+ }
61
+ var setSort = (ctx, by) => {
62
+ try {
63
+ if (JSON.stringify(byOf(ctx.getState())) === JSON.stringify(by)) return;
64
+ } catch {
65
+ }
66
+ ctx.setState({ by: Array.isArray(by) ? by.slice() : by });
67
+ };
42
68
  var validLocale = (v) => {
43
69
  try {
44
70
  Intl.getCanonicalLocales(v);
@@ -101,6 +127,7 @@ var SortFnFailed = class {
101
127
  }
102
128
  };
103
129
  var sorting = (opts = {}) => {
130
+ const guard = process.env.NODE_ENV !== "production" ? sliceGuard("sorting", fixSlice) : void 0;
104
131
  let collator;
105
132
  const getCollator = (emit) => {
106
133
  if (collator) return collator;
@@ -190,32 +217,36 @@ var sorting = (opts = {}) => {
190
217
  process.env.NODE_ENV !== "production" ? sortingOptions : {},
191
218
  opts
192
219
  ),
220
+ ...guard ? { interceptors: [guard.interceptor] } : void 0,
193
221
  initialState: () => ({ by: [] }),
194
222
  // After destroy(): still a declared value (`aria-sort` reads it during teardown renders).
195
223
  destroyedResult: { getSortDirection: () => false },
196
- createApi: (ctx) => ({
197
- toggleSort: (id, options) => ctx.setState((s) => {
198
- const by = s.by;
199
- const i = by.findIndex((e) => e.id === id);
200
- const cur = by[i];
201
- const next = !cur ? { id, desc: false } : cur.desc ? void 0 : { id, desc: true };
202
- if (!options?.multi) return { by: next ? [next] : [] };
203
- if (!cur) return { by: [...by, next] };
204
- const out = by.slice();
205
- if (next) out[i] = next;
206
- else out.splice(i, 1);
207
- return { by: out };
208
- }),
209
- setSorting: (by) => setSort(ctx, by),
210
- clearSorting: () => setSort(ctx, []),
211
- getSortDirection: (id) => {
212
- const e = ctx.getState().by.find((x) => x.id === id);
213
- return e ? e.desc ? "desc" : "asc" : false;
214
- }
215
- }),
224
+ createApi: (ctx) => {
225
+ guard?.install(ctx);
226
+ return {
227
+ toggleSort: (id, options) => {
228
+ const by = entriesOf(ctx.getState());
229
+ const i = by.findIndex((e) => e.id === id);
230
+ const cur = by[i];
231
+ const next = !cur ? { id, desc: false } : cur.desc ? void 0 : { id, desc: true };
232
+ if (!options?.multi) return ctx.setState({ by: next ? [next] : [] });
233
+ if (!cur) return ctx.setState({ by: [...by, next] });
234
+ const out = by.slice();
235
+ if (next) out[i] = next;
236
+ else out.splice(i, 1);
237
+ ctx.setState({ by: out });
238
+ },
239
+ setSorting: (by) => setSort(ctx, by),
240
+ clearSorting: () => setSort(ctx, []),
241
+ getSortDirection: (id) => {
242
+ const e = entriesOf(ctx.getState()).find((x) => x.id === id);
243
+ return e ? e.desc ? "desc" : "asc" : false;
244
+ }
245
+ };
246
+ },
216
247
  rowModel: (indices, state, ctx) => {
217
- const by = state?.by;
218
- if (!by || by.length === 0 || indices.length < 2) {
248
+ const by = entriesOf(state);
249
+ if (by.length === 0 || indices.length < 2) {
219
250
  shown = void 0;
220
251
  return indices;
221
252
  }
@@ -248,7 +279,7 @@ var sorting = (opts = {}) => {
248
279
  fromColumn ? { path: `columns[${primary.col?.index}].sortAlgorithm`, reason: reason2, once: false } : { path: "algorithm", feature: "sorting", reason: reason2, once: false }
249
280
  );
250
281
  if (typeof requested !== "function" && !ALGORITHMS.includes(requested)) {
251
- noEffect(`not-algorithm|${JSON.stringify(requested)}`);
282
+ noEffect(`not-algorithm|${proseArg(JSON.stringify(requested))}`);
252
283
  requested = "auto";
253
284
  }
254
285
  if (requested !== "native" && exsorted === void 0) {