@datakable/core 1.0.1 → 1.1.0

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 (280) hide show
  1. package/README.md +4 -2
  2. package/dist/catalog/codes.cjs +12 -8
  3. package/dist/catalog/codes.cjs.map +1 -1
  4. package/dist/catalog/codes.js +12 -8
  5. package/dist/catalog/codes.js.map +1 -1
  6. package/dist/catalog/slots.cjs +10 -6
  7. package/dist/catalog/slots.cjs.map +1 -1
  8. package/dist/catalog/slots.js +10 -6
  9. package/dist/catalog/slots.js.map +1 -1
  10. package/dist/{codes-OsjAR3Wz.d.cts → codes-B9bCK73-.d.cts} +30 -4
  11. package/dist/{codes-OsjAR3Wz.d.ts → codes-B9bCK73-.d.ts} +30 -4
  12. package/dist/column/column-def.cjs.map +1 -1
  13. package/dist/column/get-value.cjs +6 -1
  14. package/dist/column/get-value.cjs.map +1 -1
  15. package/dist/column/get-value.js +6 -1
  16. package/dist/column/get-value.js.map +1 -1
  17. package/dist/column-filters.d.cts +2 -2
  18. package/dist/column-filters.d.ts +2 -2
  19. package/dist/diagnostics/build.cjs +4 -1
  20. package/dist/diagnostics/build.cjs.map +1 -1
  21. package/dist/diagnostics/build.js +4 -1
  22. package/dist/diagnostics/build.js.map +1 -1
  23. package/dist/diagnostics/catalog.cjs +11 -5
  24. package/dist/diagnostics/catalog.cjs.map +1 -1
  25. package/dist/diagnostics/catalog.js +10 -5
  26. package/dist/diagnostics/catalog.js.map +1 -1
  27. package/dist/diagnostics/codes.cjs +12 -8
  28. package/dist/diagnostics/codes.cjs.map +1 -1
  29. package/dist/diagnostics/codes.js +12 -8
  30. package/dist/diagnostics/codes.js.map +1 -1
  31. package/dist/diagnostics/console.cjs +13 -6
  32. package/dist/diagnostics/console.cjs.map +1 -1
  33. package/dist/diagnostics/console.js +13 -6
  34. package/dist/diagnostics/console.js.map +1 -1
  35. package/dist/diagnostics/env.cjs +1 -0
  36. package/dist/diagnostics/env.cjs.map +1 -1
  37. package/dist/diagnostics/env.js +1 -0
  38. package/dist/diagnostics/env.js.map +1 -1
  39. package/dist/diagnostics/explain-text.cjs +2 -1
  40. package/dist/diagnostics/explain-text.cjs.map +1 -1
  41. package/dist/diagnostics/explain-text.js +2 -1
  42. package/dist/diagnostics/explain-text.js.map +1 -1
  43. package/dist/diagnostics/explain.cjs +3 -2
  44. package/dist/diagnostics/explain.cjs.map +1 -1
  45. package/dist/diagnostics/explain.js +3 -2
  46. package/dist/diagnostics/explain.js.map +1 -1
  47. package/dist/diagnostics/hub.cjs +5 -4
  48. package/dist/diagnostics/hub.cjs.map +1 -1
  49. package/dist/diagnostics/hub.js +5 -4
  50. package/dist/diagnostics/hub.js.map +1 -1
  51. package/dist/diagnostics/process-guard.cjs +26 -0
  52. package/dist/diagnostics/process-guard.cjs.map +1 -0
  53. package/dist/diagnostics/process-guard.js +9 -0
  54. package/dist/diagnostics/process-guard.js.map +1 -0
  55. package/dist/diagnostics/prose.cjs +120 -0
  56. package/dist/diagnostics/prose.cjs.map +1 -0
  57. package/dist/diagnostics/prose.js +93 -0
  58. package/dist/diagnostics/prose.js.map +1 -0
  59. package/dist/diagnostics/redact.cjs +7 -4
  60. package/dist/diagnostics/redact.cjs.map +1 -1
  61. package/dist/diagnostics/redact.js +6 -4
  62. package/dist/diagnostics/redact.js.map +1 -1
  63. package/dist/diagnostics/trace-store.cjs +6 -0
  64. package/dist/diagnostics/trace-store.cjs.map +1 -1
  65. package/dist/diagnostics/trace-store.js +4 -0
  66. package/dist/diagnostics/trace-store.js.map +1 -1
  67. package/dist/diagnostics/tracer.cjs +74 -13
  68. package/dist/diagnostics/tracer.cjs.map +1 -1
  69. package/dist/diagnostics/tracer.js +75 -14
  70. package/dist/diagnostics/tracer.js.map +1 -1
  71. package/dist/diagnostics/types.cjs.map +1 -1
  72. package/dist/{explain-vkD2cewE.d.cts → explain-Q8Cg0cZy.d.cts} +13 -4
  73. package/dist/{explain-Dn99IQt0.d.ts → explain-i0OATi_W.d.ts} +13 -4
  74. package/dist/feature/codes.cjs +1 -0
  75. package/dist/feature/codes.cjs.map +1 -1
  76. package/dist/feature/codes.js +1 -0
  77. package/dist/feature/codes.js.map +1 -1
  78. package/dist/feature/install.cjs +4 -3
  79. package/dist/feature/install.cjs.map +1 -1
  80. package/dist/feature/install.js +4 -3
  81. package/dist/feature/install.js.map +1 -1
  82. package/dist/features/column-filters/codes.cjs +1 -0
  83. package/dist/features/column-filters/codes.cjs.map +1 -1
  84. package/dist/features/column-filters/codes.js +1 -0
  85. package/dist/features/column-filters/codes.js.map +1 -1
  86. package/dist/features/column-filters/column-filters.cjs +4 -2
  87. package/dist/features/column-filters/column-filters.cjs.map +1 -1
  88. package/dist/features/column-filters/column-filters.js +4 -2
  89. package/dist/features/column-filters/column-filters.js.map +1 -1
  90. package/dist/features/column-filters/match.cjs +5 -5
  91. package/dist/features/column-filters/match.cjs.map +1 -1
  92. package/dist/features/column-filters/match.js +5 -5
  93. package/dist/features/column-filters/match.js.map +1 -1
  94. package/dist/features/pagination/codes.cjs +1 -0
  95. package/dist/features/pagination/codes.cjs.map +1 -1
  96. package/dist/features/pagination/codes.js +1 -0
  97. package/dist/features/pagination/codes.js.map +1 -1
  98. package/dist/features/pagination/pagination.cjs +16 -13
  99. package/dist/features/pagination/pagination.cjs.map +1 -1
  100. package/dist/features/pagination/pagination.js +16 -13
  101. package/dist/features/pagination/pagination.js.map +1 -1
  102. package/dist/features/search/codes.cjs +1 -0
  103. package/dist/features/search/codes.cjs.map +1 -1
  104. package/dist/features/search/codes.js +1 -0
  105. package/dist/features/search/codes.js.map +1 -1
  106. package/dist/features/search/search-index.cjs +68 -15
  107. package/dist/features/search/search-index.cjs.map +1 -1
  108. package/dist/features/search/search-index.js +68 -15
  109. package/dist/features/search/search-index.js.map +1 -1
  110. package/dist/features/search/search.cjs +41 -9
  111. package/dist/features/search/search.cjs.map +1 -1
  112. package/dist/features/search/search.js +41 -9
  113. package/dist/features/search/search.js.map +1 -1
  114. package/dist/features/search/skipped-codes.cjs +45 -0
  115. package/dist/features/search/skipped-codes.cjs.map +1 -0
  116. package/dist/features/search/skipped-codes.js +20 -0
  117. package/dist/features/search/skipped-codes.js.map +1 -0
  118. package/dist/features/sorting/codes.cjs +1 -0
  119. package/dist/features/sorting/codes.cjs.map +1 -1
  120. package/dist/features/sorting/codes.js +1 -0
  121. package/dist/features/sorting/codes.js.map +1 -1
  122. package/dist/features/sorting/sorting.cjs +16 -20
  123. package/dist/features/sorting/sorting.cjs.map +1 -1
  124. package/dist/features/sorting/sorting.js +16 -20
  125. package/dist/features/sorting/sorting.js.map +1 -1
  126. package/dist/features/sorting/strategy.cjs +4 -4
  127. package/dist/features/sorting/strategy.cjs.map +1 -1
  128. package/dist/features/sorting/strategy.js +4 -4
  129. package/dist/features/sorting/strategy.js.map +1 -1
  130. package/dist/features/validity/codes.cjs +1 -0
  131. package/dist/features/validity/codes.cjs.map +1 -1
  132. package/dist/features/validity/codes.js +1 -0
  133. package/dist/features/validity/codes.js.map +1 -1
  134. package/dist/features/validity/validity.cjs +3 -3
  135. package/dist/features/validity/validity.cjs.map +1 -1
  136. package/dist/features/validity/validity.js +3 -3
  137. package/dist/features/validity/validity.js.map +1 -1
  138. package/dist/index.d.cts +13 -10
  139. package/dist/index.d.ts +13 -10
  140. package/dist/ingest/data-check-codes.cjs +4 -2
  141. package/dist/ingest/data-check-codes.cjs.map +1 -1
  142. package/dist/ingest/data-check-codes.js +4 -2
  143. package/dist/ingest/data-check-codes.js.map +1 -1
  144. package/dist/ingest/data-checks.cjs +1 -1
  145. package/dist/ingest/data-checks.cjs.map +1 -1
  146. package/dist/ingest/data-checks.js +1 -1
  147. package/dist/ingest/data-checks.js.map +1 -1
  148. package/dist/ingest/row-key-codes.cjs +1 -0
  149. package/dist/ingest/row-key-codes.cjs.map +1 -1
  150. package/dist/ingest/row-key-codes.js +1 -0
  151. package/dist/ingest/row-key-codes.js.map +1 -1
  152. package/dist/ingest/row-key.cjs +23 -20
  153. package/dist/ingest/row-key.cjs.map +1 -1
  154. package/dist/ingest/row-key.js +23 -20
  155. package/dist/ingest/row-key.js.map +1 -1
  156. package/dist/ingest/schema-codes.cjs +1 -0
  157. package/dist/ingest/schema-codes.cjs.map +1 -1
  158. package/dist/ingest/schema-codes.js +1 -0
  159. package/dist/ingest/schema-codes.js.map +1 -1
  160. package/dist/ingest/unique-fields.cjs +2 -2
  161. package/dist/ingest/unique-fields.cjs.map +1 -1
  162. package/dist/ingest/unique-fields.js +2 -2
  163. package/dist/ingest/unique-fields.js.map +1 -1
  164. package/dist/intercept/boundary.cjs +4 -2
  165. package/dist/intercept/boundary.cjs.map +1 -1
  166. package/dist/intercept/boundary.js +4 -2
  167. package/dist/intercept/boundary.js.map +1 -1
  168. package/dist/intercept/cell-batch.cjs +4 -4
  169. package/dist/intercept/cell-batch.cjs.map +1 -1
  170. package/dist/intercept/cell-batch.js +4 -4
  171. package/dist/intercept/cell-batch.js.map +1 -1
  172. package/dist/intercept/codes.cjs +1 -0
  173. package/dist/intercept/codes.cjs.map +1 -1
  174. package/dist/intercept/codes.js +1 -0
  175. package/dist/intercept/codes.js.map +1 -1
  176. package/dist/intercept/fallbacks.cjs +12 -20
  177. package/dist/intercept/fallbacks.cjs.map +1 -1
  178. package/dist/intercept/fallbacks.js +12 -20
  179. package/dist/intercept/fallbacks.js.map +1 -1
  180. package/dist/intercept/runtime.cjs +7 -9
  181. package/dist/intercept/runtime.cjs.map +1 -1
  182. package/dist/intercept/runtime.js +7 -9
  183. package/dist/intercept/runtime.js.map +1 -1
  184. package/dist/messages/index.cjs +4 -1
  185. package/dist/messages/index.cjs.map +1 -1
  186. package/dist/messages/index.js +4 -1
  187. package/dist/messages/index.js.map +1 -1
  188. package/dist/pagination.d.cts +2 -2
  189. package/dist/pagination.d.ts +2 -2
  190. package/dist/pipeline/codes.cjs +1 -0
  191. package/dist/pipeline/codes.cjs.map +1 -1
  192. package/dist/pipeline/codes.js +1 -0
  193. package/dist/pipeline/codes.js.map +1 -1
  194. package/dist/pipeline/column-cache.cjs +94 -76
  195. package/dist/pipeline/column-cache.cjs.map +1 -1
  196. package/dist/pipeline/column-cache.js +92 -75
  197. package/dist/pipeline/column-cache.js.map +1 -1
  198. package/dist/pipeline/dev-checks.cjs +1 -0
  199. package/dist/pipeline/dev-checks.cjs.map +1 -1
  200. package/dist/pipeline/dev-checks.js +1 -0
  201. package/dist/pipeline/dev-checks.js.map +1 -1
  202. package/dist/pipeline/env-codes.cjs +3 -2
  203. package/dist/pipeline/env-codes.cjs.map +1 -1
  204. package/dist/pipeline/env-codes.js +3 -2
  205. package/dist/pipeline/env-codes.js.map +1 -1
  206. package/dist/pipeline/perf-codes.cjs +1 -0
  207. package/dist/pipeline/perf-codes.cjs.map +1 -1
  208. package/dist/pipeline/perf-codes.js +1 -0
  209. package/dist/pipeline/perf-codes.js.map +1 -1
  210. package/dist/pipeline/runner.cjs +17 -9
  211. package/dist/pipeline/runner.cjs.map +1 -1
  212. package/dist/pipeline/runner.js +17 -9
  213. package/dist/pipeline/runner.js.map +1 -1
  214. package/dist/pipeline/slice.cjs +3 -1
  215. package/dist/pipeline/slice.cjs.map +1 -1
  216. package/dist/pipeline/slice.js +3 -1
  217. package/dist/pipeline/slice.js.map +1 -1
  218. package/dist/schema.d.cts +2 -2
  219. package/dist/schema.d.ts +2 -2
  220. package/dist/{search-async-entry-v5JdEk5Y.d.cts → search-async-entry-CuLYPfY_.d.cts} +2 -2
  221. package/dist/{search-async-entry-DGSw2pDL.d.ts → search-async-entry-Cx7xpuVZ.d.ts} +2 -2
  222. package/dist/search-async.d.cts +3 -3
  223. package/dist/search-async.d.ts +3 -3
  224. package/dist/search.d.cts +8 -6
  225. package/dist/search.d.ts +8 -6
  226. package/dist/server.d.cts +3 -3
  227. package/dist/server.d.ts +3 -3
  228. package/dist/sorting.d.cts +2 -2
  229. package/dist/sorting.d.ts +2 -2
  230. package/dist/source/codes.cjs +1 -0
  231. package/dist/source/codes.cjs.map +1 -1
  232. package/dist/source/codes.js +1 -0
  233. package/dist/source/codes.js.map +1 -1
  234. package/dist/source/fetch-codes.cjs +1 -0
  235. package/dist/source/fetch-codes.cjs.map +1 -1
  236. package/dist/source/fetch-codes.js +1 -0
  237. package/dist/source/fetch-codes.js.map +1 -1
  238. package/dist/table/codes.cjs +1 -0
  239. package/dist/table/codes.cjs.map +1 -1
  240. package/dist/table/codes.js +1 -0
  241. package/dist/table/codes.js.map +1 -1
  242. package/dist/table/create-table.cjs +39 -9
  243. package/dist/table/create-table.cjs.map +1 -1
  244. package/dist/table/create-table.js +39 -9
  245. package/dist/table/create-table.js.map +1 -1
  246. package/dist/table/data-mutation.cjs +1 -0
  247. package/dist/table/data-mutation.cjs.map +1 -1
  248. package/dist/table/data-mutation.js +1 -0
  249. package/dist/table/data-mutation.js.map +1 -1
  250. package/dist/table/internals.cjs.map +1 -1
  251. package/dist/table/internals.js.map +1 -1
  252. package/dist/table/ssr-codes.cjs +1 -0
  253. package/dist/table/ssr-codes.cjs.map +1 -1
  254. package/dist/table/ssr-codes.js +1 -0
  255. package/dist/table/ssr-codes.js.map +1 -1
  256. package/dist/table/ssr.cjs +4 -1
  257. package/dist/table/ssr.cjs.map +1 -1
  258. package/dist/table/ssr.js +4 -1
  259. package/dist/table/ssr.js.map +1 -1
  260. package/dist/table/state-feedback.cjs +19 -0
  261. package/dist/table/state-feedback.cjs.map +1 -1
  262. package/dist/table/state-feedback.js +19 -0
  263. package/dist/table/state-feedback.js.map +1 -1
  264. package/dist/table/types.cjs.map +1 -1
  265. package/dist/table/types.js.map +1 -1
  266. package/dist/validity.d.cts +2 -2
  267. package/dist/validity.d.ts +2 -2
  268. package/dist/version.cjs +1 -1
  269. package/dist/version.cjs.map +1 -1
  270. package/dist/version.js +1 -1
  271. package/dist/version.js.map +1 -1
  272. package/dist/versioning/codes.cjs +18 -0
  273. package/dist/versioning/codes.cjs.map +1 -1
  274. package/dist/versioning/codes.js +18 -0
  275. package/dist/versioning/codes.js.map +1 -1
  276. package/dist/versioning/registry.cjs +4 -2
  277. package/dist/versioning/registry.cjs.map +1 -1
  278. package/dist/versioning/registry.js +4 -2
  279. package/dist/versioning/registry.js.map +1 -1
  280. package/package.json +39 -3
package/README.md CHANGED
@@ -17,7 +17,7 @@ constant and remove development-only checks, tracing and message text from produ
17
17
  Vite, webpack, Next.js, Rollup (`@rollup/plugin-replace`) and esbuild
18
18
  (`--define:process.env.NODE_ENV='"production"'`) all replace it. Without a replacement, unbundled
19
19
  browser code throws `ReferenceError: process is not defined`, as React and Redux do. Node needs
20
- nothing.
20
+ nothing beyond Node.js `>=18.18`. The types need TypeScript `>=5.4`.
21
21
 
22
22
  ## Contents
23
23
 
@@ -111,7 +111,9 @@ The features are also exported from `@datakable/core` itself. The pipeline alway
111
111
  (number / bigint / Date, inclusive) and `custom` (`fn(value, filterValue, row)`). Filters AND
112
112
  together; an array cell matches when any element matches.
113
113
  - **Search:** fuzzy matching over the formatted cell values. When a column declares
114
- `search: weight`, only columns with a weight are searched; otherwise every column is, at weight 1. `input` follows the keyboard,
114
+ `search: weight`, only columns with a weight are searched; otherwise the columns of strings,
115
+ numbers and booleans are, at weight 1 (a column of dates, arrays or objects needs a weight;
116
+ `DK_SEARCH_COLUMN_SKIPPED` in development). `input` follows the keyboard,
115
117
  `query` is the applied value; `typing` sets `immediate` / `debounce` / `throttle`, `wait`,
116
118
  `minLength` and `commitOn: 'enter'`. `setSearch` / `flushSearch` return a promise of
117
119
  `{ status: 'applied' | 'superseded' | 'error' }` and never reject. A `searchFn` replaces the
@@ -25,6 +25,7 @@ __export(codes_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(codes_exports);
27
27
  var import_catalog = require("../diagnostics/catalog.cjs");
28
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
28
29
  var where = (d) => d.feature === void 0 ? { kind: "option", path: d.path } : { kind: "feature", name: d.feature };
29
30
  var label = (d) => d.feature === void 0 ? `options.${d.path}` : `${d.feature}({ ${d.path} })`;
30
31
  var leaf = (path) => path.slice(path.lastIndexOf(".") + 1);
@@ -68,14 +69,17 @@ var optionMessages = {
68
69
  }
69
70
  };
70
71
  var optionDiagnostics = [
71
- (0, import_catalog.defineDiagnostic)(
72
- {
73
- code: "DK_UNKNOWN_OPTION",
74
- level: "warn",
75
- where
76
- },
77
- process.env.NODE_ENV !== "production" && optionMessages.DK_UNKNOWN_OPTION
78
- ),
72
+ // Only the development option validator emits it: no definition in production.
73
+ ...process.env.NODE_ENV !== "production" ? [
74
+ (0, import_catalog.defineDiagnostic)(
75
+ {
76
+ code: "DK_UNKNOWN_OPTION",
77
+ level: "warn",
78
+ where
79
+ },
80
+ process.env.NODE_ENV !== "production" && optionMessages.DK_UNKNOWN_OPTION
81
+ )
82
+ ] : [],
79
83
  (0, import_catalog.defineDiagnostic)(
80
84
  {
81
85
  code: "DK_INVALID_OPTION",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/catalog/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport type { Location } from '../diagnostics/types'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNKNOWN_OPTION: {\n /** Option path as written (`colums`, `diagnostics.redcat`); option keys, never values. */\n path: string\n /** Set when the option was given to a feature factory. */\n feature?: string\n /** Close accepted names, best first (did-you-mean). */\n suggestions: string[]\n /** The accepted options at that level. */\n known: string[]\n /** An installed feature that has this option (it was passed to the table instead). */\n owner?: string\n }\n DK_INVALID_OPTION: {\n path: string\n feature?: string\n /** The accepted values in words. */\n expected: string\n /** What was given: a type, or a short constant (`\"ful\"`, `NaN`). */\n received: string\n /** Close accepted values (enums), best first. */\n suggestions: string[]\n /** A fix specific to this mistake, shown first. */\n hint?: string\n /** Where it was given: `createTable` (the table was not created) or `setOptions` (rejected). */\n phase: 'init' | 'setOptions'\n }\n DK_OPTION_NO_EFFECT: {\n path: string\n feature?: string\n /** Why the option is ignored. */\n reason: string\n /** `true` for a read-once option changed with `setOptions`. */\n once: boolean\n }\n }\n}\n\nconst where = (d: { path: string; feature?: string }): Location =>\n d.feature === undefined ? { kind: 'option', path: d.path } : { kind: 'feature', name: d.feature }\n\n/** `options.timeout` / `paging({ pageSize })`. */\nconst label = (d: { path: string; feature?: string }) =>\n d.feature === undefined ? `options.${d.path}` : `${d.feature}({ ${d.path} })`\n\nconst leaf = (path: string) => path.slice(path.lastIndexOf('.') + 1)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const optionMessages: DiagnosticMessages<\n 'DK_UNKNOWN_OPTION' | 'DK_INVALID_OPTION' | 'DK_OPTION_NO_EFFECT'\n> = {\n DK_UNKNOWN_OPTION: {\n problem: (d) =>\n d.feature === undefined\n ? `unknown option \"${d.path}\"`\n : `feature \"${d.feature}\" got an unknown option \"${d.path}\"`,\n impact: () => 'the option is ignored',\n fix: (d) => {\n const out: string[] = []\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`did you mean \"${s}\"? rename \"${leaf(d.path)}\" to \"${s}\"`)\n if (d.owner !== undefined) {\n out.push(\n `\"${d.path}\" is an option of feature \"${d.owner}\": pass it to the feature, ` +\n `${d.owner}({ ${d.path}: ... })`,\n )\n }\n out.push(\n `remove \"${leaf(d.path)}\"; accepted ${d.feature === undefined ? '' : `${d.feature} `}` +\n `options here: ${d.known.join(', ') || '(none)'}`,\n )\n return out\n },\n },\n DK_INVALID_OPTION: {\n problem: (d) => `${label(d)} must be ${d.expected}, got ${d.received}`,\n impact: (d) =>\n d.phase === 'init'\n ? 'the table was not created'\n : 'setOptions() was rejected; the previous options are kept',\n fix: (d) => {\n const out: string[] = []\n if (d.hint !== undefined) out.push(d.hint)\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`use '${s}' (the closest accepted value) for ${label(d)}`)\n out.push(`pass ${d.expected} as ${label(d)}, or leave it out for the default`)\n return out\n },\n },\n DK_OPTION_NO_EFFECT: {\n problem: (d) =>\n d.once\n ? `setOptions({ ${d.path} }) has no effect: ${d.reason}`\n : `${label(d)} has no effect: ${d.reason}`,\n impact: (d) =>\n d.once\n ? 'the new value was ignored; the table keeps the value it was created with'\n : 'the option is ignored in this configuration',\n fix: (d) =>\n d.once\n ? [\n `pass ${d.path} to createTable() instead; to change it, create a new table ` +\n '(in React, change the component key)',\n ]\n : [`remove ${label(d)}, or change the configuration so that it applies (${d.reason})`],\n },\n}\n\n/** Codes owned by the options catalog (§3.5, §8.3). */\nexport const optionDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN_OPTION',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_UNKNOWN_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_INVALID_OPTION',\n level: 'error',\n config: true,\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_INVALID_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPTION_NO_EFFECT',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_OPTION_NO_EFFECT,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AA0C1D,IAAM,QAAQ,CAAC,MACb,EAAE,YAAY,SAAY,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,MAAM,EAAE,QAAQ;AAGlG,IAAM,QAAQ,CAAC,MACb,EAAE,YAAY,SAAY,WAAW,EAAE,IAAI,KAAK,GAAG,EAAE,OAAO,MAAM,EAAE,IAAI;AAE1E,IAAM,OAAO,CAAC,SAAiB,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC;AAG5D,IAAM,iBAET;AAAA,EACF,mBAAmB;AAAA,IACjB,SAAS,CAAC,MACR,EAAE,YAAY,SACV,mBAAmB,EAAE,IAAI,MACzB,YAAY,EAAE,OAAO,4BAA4B,EAAE,IAAI;AAAA,IAC7D,QAAQ,MAAM;AAAA,IACd,KAAK,CAAC,MAAM;AACV,YAAM,MAAgB,CAAC;AACvB,YAAM,IAAI,EAAE,YAAY,CAAC;AACzB,UAAI,MAAM,OAAW,KAAI,KAAK,iBAAiB,CAAC,cAAc,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG;AACvF,UAAI,EAAE,UAAU,QAAW;AACzB,YAAI;AAAA,UACF,IAAI,EAAE,IAAI,8BAA8B,EAAE,KAAK,8BAC1C,EAAE,KAAK,MAAM,EAAE,IAAI;AAAA,QAC1B;AAAA,MACF;AACA,UAAI;AAAA,QACF,WAAW,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,SAAY,KAAK,GAAG,EAAE,OAAO,GAAG,iBACjE,EAAE,MAAM,KAAK,IAAI,KAAK,QAAQ;AAAA,MACnD;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,YAAY,EAAE,QAAQ,SAAS,EAAE,QAAQ;AAAA,IACpE,QAAQ,CAAC,MACP,EAAE,UAAU,SACR,8BACA;AAAA,IACN,KAAK,CAAC,MAAM;AACV,YAAM,MAAgB,CAAC;AACvB,UAAI,EAAE,SAAS,OAAW,KAAI,KAAK,EAAE,IAAI;AACzC,YAAM,IAAI,EAAE,YAAY,CAAC;AACzB,UAAI,MAAM,OAAW,KAAI,KAAK,QAAQ,CAAC,sCAAsC,MAAM,CAAC,CAAC,EAAE;AACvF,UAAI,KAAK,QAAQ,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,mCAAmC;AAC7E,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB,SAAS,CAAC,MACR,EAAE,OACE,gBAAgB,EAAE,IAAI,sBAAsB,EAAE,MAAM,KACpD,GAAG,MAAM,CAAC,CAAC,mBAAmB,EAAE,MAAM;AAAA,IAC5C,QAAQ,CAAC,MACP,EAAE,OACE,6EACA;AAAA,IACN,KAAK,CAAC,MACJ,EAAE,OACE;AAAA,MACE,QAAQ,EAAE,IAAI;AAAA,IAEhB,IACA,CAAC,UAAU,MAAM,CAAC,CAAC,qDAAqD,EAAE,MAAM,GAAG;AAAA,EAC3F;AACF;AAGO,IAAM,oBAAoB;AAAA,MAC/B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,IACF;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AAAA,MACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AAAA,MACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,IACF;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/catalog/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\nimport type { Location } from '../diagnostics/types'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNKNOWN_OPTION: {\n /** Option path as written (`colums`, `diagnostics.redcat`); option keys, never values. */\n path: string\n /** Set when the option was given to a feature factory. */\n feature?: string\n /** Close accepted names, best first (did-you-mean). */\n suggestions: string[]\n /** The accepted options at that level. */\n known: string[]\n /** An installed feature that has this option (it was passed to the table instead). */\n owner?: string\n }\n DK_INVALID_OPTION: {\n path: string\n feature?: string\n /** The accepted values in words. */\n expected: string\n /** What was given: a type, or a short constant (`\"ful\"`, `NaN`). */\n received: string\n /** Close accepted values (enums), best first. */\n suggestions: string[]\n /** A fix specific to this mistake, shown first. */\n hint?: string\n /** Where it was given: `createTable` (the table was not created) or `setOptions` (rejected). */\n phase: 'init' | 'setOptions'\n }\n DK_OPTION_NO_EFFECT: {\n path: string\n feature?: string\n /** Why the option is ignored. */\n reason: string\n /** `true` for a read-once option changed with `setOptions`. */\n once: boolean\n }\n }\n}\n\nconst where = (d: { path: string; feature?: string }): Location =>\n d.feature === undefined ? { kind: 'option', path: d.path } : { kind: 'feature', name: d.feature }\n\n/** `options.timeout` / `paging({ pageSize })`. */\nconst label = (d: { path: string; feature?: string }) =>\n d.feature === undefined ? `options.${d.path}` : `${d.feature}({ ${d.path} })`\n\nconst leaf = (path: string) => path.slice(path.lastIndexOf('.') + 1)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const optionMessages: DiagnosticMessages<\n 'DK_UNKNOWN_OPTION' | 'DK_INVALID_OPTION' | 'DK_OPTION_NO_EFFECT'\n> = {\n DK_UNKNOWN_OPTION: {\n problem: (d) =>\n d.feature === undefined\n ? `unknown option \"${d.path}\"`\n : `feature \"${d.feature}\" got an unknown option \"${d.path}\"`,\n impact: () => 'the option is ignored',\n fix: (d) => {\n const out: string[] = []\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`did you mean \"${s}\"? rename \"${leaf(d.path)}\" to \"${s}\"`)\n if (d.owner !== undefined) {\n out.push(\n `\"${d.path}\" is an option of feature \"${d.owner}\": pass it to the feature, ` +\n `${d.owner}({ ${d.path}: ... })`,\n )\n }\n out.push(\n `remove \"${leaf(d.path)}\"; accepted ${d.feature === undefined ? '' : `${d.feature} `}` +\n `options here: ${d.known.join(', ') || '(none)'}`,\n )\n return out\n },\n },\n DK_INVALID_OPTION: {\n problem: (d) => `${label(d)} must be ${d.expected}, got ${d.received}`,\n impact: (d) =>\n d.phase === 'init'\n ? 'the table was not created'\n : 'setOptions() was rejected; the previous options are kept',\n fix: (d) => {\n const out: string[] = []\n if (d.hint !== undefined) out.push(d.hint)\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`use '${s}' (the closest accepted value) for ${label(d)}`)\n out.push(`pass ${d.expected} as ${label(d)}, or leave it out for the default`)\n return out\n },\n },\n DK_OPTION_NO_EFFECT: {\n problem: (d) =>\n d.once\n ? `setOptions({ ${d.path} }) has no effect: ${d.reason}`\n : `${label(d)} has no effect: ${d.reason}`,\n impact: (d) =>\n d.once\n ? 'the new value was ignored; the table keeps the value it was created with'\n : 'the option is ignored in this configuration',\n fix: (d) =>\n d.once\n ? [\n `pass ${d.path} to createTable() instead; to change it, create a new table ` +\n '(in React, change the component key)',\n ]\n : [`remove ${label(d)}, or change the configuration so that it applies (${d.reason})`],\n },\n}\n\n/** Codes owned by the options catalog (§3.5, §8.3). */\nexport const optionDiagnostics = [\n // Only the development option validator emits it: no definition in production.\n ...((process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN_OPTION',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_UNKNOWN_OPTION,\n ),\n ]\n : []),\n defineDiagnostic(\n {\n code: 'DK_INVALID_OPTION',\n level: 'error',\n config: true,\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_INVALID_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPTION_NO_EFFECT',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_OPTION_NO_EFFECT,\n ),\n]\n"],"mappings":"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","names":[]}
@@ -1,5 +1,6 @@
1
1
  // src/catalog/codes.ts
2
2
  import { defineDiagnostic } from "../diagnostics/catalog.js";
3
+ import "../diagnostics/process-guard.js";
3
4
  var where = (d) => d.feature === void 0 ? { kind: "option", path: d.path } : { kind: "feature", name: d.feature };
4
5
  var label = (d) => d.feature === void 0 ? `options.${d.path}` : `${d.feature}({ ${d.path} })`;
5
6
  var leaf = (path) => path.slice(path.lastIndexOf(".") + 1);
@@ -43,14 +44,17 @@ var optionMessages = {
43
44
  }
44
45
  };
45
46
  var optionDiagnostics = [
46
- defineDiagnostic(
47
- {
48
- code: "DK_UNKNOWN_OPTION",
49
- level: "warn",
50
- where
51
- },
52
- process.env.NODE_ENV !== "production" && optionMessages.DK_UNKNOWN_OPTION
53
- ),
47
+ // Only the development option validator emits it: no definition in production.
48
+ ...process.env.NODE_ENV !== "production" ? [
49
+ defineDiagnostic(
50
+ {
51
+ code: "DK_UNKNOWN_OPTION",
52
+ level: "warn",
53
+ where
54
+ },
55
+ process.env.NODE_ENV !== "production" && optionMessages.DK_UNKNOWN_OPTION
56
+ )
57
+ ] : [],
54
58
  defineDiagnostic(
55
59
  {
56
60
  code: "DK_INVALID_OPTION",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/catalog/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport type { Location } from '../diagnostics/types'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNKNOWN_OPTION: {\n /** Option path as written (`colums`, `diagnostics.redcat`); option keys, never values. */\n path: string\n /** Set when the option was given to a feature factory. */\n feature?: string\n /** Close accepted names, best first (did-you-mean). */\n suggestions: string[]\n /** The accepted options at that level. */\n known: string[]\n /** An installed feature that has this option (it was passed to the table instead). */\n owner?: string\n }\n DK_INVALID_OPTION: {\n path: string\n feature?: string\n /** The accepted values in words. */\n expected: string\n /** What was given: a type, or a short constant (`\"ful\"`, `NaN`). */\n received: string\n /** Close accepted values (enums), best first. */\n suggestions: string[]\n /** A fix specific to this mistake, shown first. */\n hint?: string\n /** Where it was given: `createTable` (the table was not created) or `setOptions` (rejected). */\n phase: 'init' | 'setOptions'\n }\n DK_OPTION_NO_EFFECT: {\n path: string\n feature?: string\n /** Why the option is ignored. */\n reason: string\n /** `true` for a read-once option changed with `setOptions`. */\n once: boolean\n }\n }\n}\n\nconst where = (d: { path: string; feature?: string }): Location =>\n d.feature === undefined ? { kind: 'option', path: d.path } : { kind: 'feature', name: d.feature }\n\n/** `options.timeout` / `paging({ pageSize })`. */\nconst label = (d: { path: string; feature?: string }) =>\n d.feature === undefined ? `options.${d.path}` : `${d.feature}({ ${d.path} })`\n\nconst leaf = (path: string) => path.slice(path.lastIndexOf('.') + 1)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const optionMessages: DiagnosticMessages<\n 'DK_UNKNOWN_OPTION' | 'DK_INVALID_OPTION' | 'DK_OPTION_NO_EFFECT'\n> = {\n DK_UNKNOWN_OPTION: {\n problem: (d) =>\n d.feature === undefined\n ? `unknown option \"${d.path}\"`\n : `feature \"${d.feature}\" got an unknown option \"${d.path}\"`,\n impact: () => 'the option is ignored',\n fix: (d) => {\n const out: string[] = []\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`did you mean \"${s}\"? rename \"${leaf(d.path)}\" to \"${s}\"`)\n if (d.owner !== undefined) {\n out.push(\n `\"${d.path}\" is an option of feature \"${d.owner}\": pass it to the feature, ` +\n `${d.owner}({ ${d.path}: ... })`,\n )\n }\n out.push(\n `remove \"${leaf(d.path)}\"; accepted ${d.feature === undefined ? '' : `${d.feature} `}` +\n `options here: ${d.known.join(', ') || '(none)'}`,\n )\n return out\n },\n },\n DK_INVALID_OPTION: {\n problem: (d) => `${label(d)} must be ${d.expected}, got ${d.received}`,\n impact: (d) =>\n d.phase === 'init'\n ? 'the table was not created'\n : 'setOptions() was rejected; the previous options are kept',\n fix: (d) => {\n const out: string[] = []\n if (d.hint !== undefined) out.push(d.hint)\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`use '${s}' (the closest accepted value) for ${label(d)}`)\n out.push(`pass ${d.expected} as ${label(d)}, or leave it out for the default`)\n return out\n },\n },\n DK_OPTION_NO_EFFECT: {\n problem: (d) =>\n d.once\n ? `setOptions({ ${d.path} }) has no effect: ${d.reason}`\n : `${label(d)} has no effect: ${d.reason}`,\n impact: (d) =>\n d.once\n ? 'the new value was ignored; the table keeps the value it was created with'\n : 'the option is ignored in this configuration',\n fix: (d) =>\n d.once\n ? [\n `pass ${d.path} to createTable() instead; to change it, create a new table ` +\n '(in React, change the component key)',\n ]\n : [`remove ${label(d)}, or change the configuration so that it applies (${d.reason})`],\n },\n}\n\n/** Codes owned by the options catalog (§3.5, §8.3). */\nexport const optionDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN_OPTION',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_UNKNOWN_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_INVALID_OPTION',\n level: 'error',\n config: true,\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_INVALID_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPTION_NO_EFFECT',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_OPTION_NO_EFFECT,\n ),\n]\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/catalog/codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\nimport type { Location } from '../diagnostics/types'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_UNKNOWN_OPTION: {\n /** Option path as written (`colums`, `diagnostics.redcat`); option keys, never values. */\n path: string\n /** Set when the option was given to a feature factory. */\n feature?: string\n /** Close accepted names, best first (did-you-mean). */\n suggestions: string[]\n /** The accepted options at that level. */\n known: string[]\n /** An installed feature that has this option (it was passed to the table instead). */\n owner?: string\n }\n DK_INVALID_OPTION: {\n path: string\n feature?: string\n /** The accepted values in words. */\n expected: string\n /** What was given: a type, or a short constant (`\"ful\"`, `NaN`). */\n received: string\n /** Close accepted values (enums), best first. */\n suggestions: string[]\n /** A fix specific to this mistake, shown first. */\n hint?: string\n /** Where it was given: `createTable` (the table was not created) or `setOptions` (rejected). */\n phase: 'init' | 'setOptions'\n }\n DK_OPTION_NO_EFFECT: {\n path: string\n feature?: string\n /** Why the option is ignored. */\n reason: string\n /** `true` for a read-once option changed with `setOptions`. */\n once: boolean\n }\n }\n}\n\nconst where = (d: { path: string; feature?: string }): Location =>\n d.feature === undefined ? { kind: 'option', path: d.path } : { kind: 'feature', name: d.feature }\n\n/** `options.timeout` / `paging({ pageSize })`. */\nconst label = (d: { path: string; feature?: string }) =>\n d.feature === undefined ? `options.${d.path}` : `${d.feature}({ ${d.path} })`\n\nconst leaf = (path: string) => path.slice(path.lastIndexOf('.') + 1)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const optionMessages: DiagnosticMessages<\n 'DK_UNKNOWN_OPTION' | 'DK_INVALID_OPTION' | 'DK_OPTION_NO_EFFECT'\n> = {\n DK_UNKNOWN_OPTION: {\n problem: (d) =>\n d.feature === undefined\n ? `unknown option \"${d.path}\"`\n : `feature \"${d.feature}\" got an unknown option \"${d.path}\"`,\n impact: () => 'the option is ignored',\n fix: (d) => {\n const out: string[] = []\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`did you mean \"${s}\"? rename \"${leaf(d.path)}\" to \"${s}\"`)\n if (d.owner !== undefined) {\n out.push(\n `\"${d.path}\" is an option of feature \"${d.owner}\": pass it to the feature, ` +\n `${d.owner}({ ${d.path}: ... })`,\n )\n }\n out.push(\n `remove \"${leaf(d.path)}\"; accepted ${d.feature === undefined ? '' : `${d.feature} `}` +\n `options here: ${d.known.join(', ') || '(none)'}`,\n )\n return out\n },\n },\n DK_INVALID_OPTION: {\n problem: (d) => `${label(d)} must be ${d.expected}, got ${d.received}`,\n impact: (d) =>\n d.phase === 'init'\n ? 'the table was not created'\n : 'setOptions() was rejected; the previous options are kept',\n fix: (d) => {\n const out: string[] = []\n if (d.hint !== undefined) out.push(d.hint)\n const s = d.suggestions[0]\n if (s !== undefined) out.push(`use '${s}' (the closest accepted value) for ${label(d)}`)\n out.push(`pass ${d.expected} as ${label(d)}, or leave it out for the default`)\n return out\n },\n },\n DK_OPTION_NO_EFFECT: {\n problem: (d) =>\n d.once\n ? `setOptions({ ${d.path} }) has no effect: ${d.reason}`\n : `${label(d)} has no effect: ${d.reason}`,\n impact: (d) =>\n d.once\n ? 'the new value was ignored; the table keeps the value it was created with'\n : 'the option is ignored in this configuration',\n fix: (d) =>\n d.once\n ? [\n `pass ${d.path} to createTable() instead; to change it, create a new table ` +\n '(in React, change the component key)',\n ]\n : [`remove ${label(d)}, or change the configuration so that it applies (${d.reason})`],\n },\n}\n\n/** Codes owned by the options catalog (§3.5, §8.3). */\nexport const optionDiagnostics = [\n // Only the development option validator emits it: no definition in production.\n ...((process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic(\n {\n code: 'DK_UNKNOWN_OPTION',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_UNKNOWN_OPTION,\n ),\n ]\n : []),\n defineDiagnostic(\n {\n code: 'DK_INVALID_OPTION',\n level: 'error',\n config: true,\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_INVALID_OPTION,\n ),\n defineDiagnostic(\n {\n code: 'DK_OPTION_NO_EFFECT',\n level: 'warn',\n where,\n },\n (process.env.NODE_ENV !== \"production\") && optionMessages.DK_OPTION_NO_EFFECT,\n ),\n]\n"],"mappings":"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","names":[]}
@@ -30,13 +30,16 @@ __export(slots_exports, {
30
30
  });
31
31
  module.exports = __toCommonJS(slots_exports);
32
32
  var import_catalog = require("../diagnostics/catalog.cjs");
33
+ var import_process_guard = require("../diagnostics/process-guard.cjs");
33
34
  var slots = /* @__PURE__ */ new Map();
34
35
  function defineSlot(slot) {
35
- const prev = slots.get(slot.name);
36
- if (process.env.NODE_ENV !== "production" && prev && prev.returns !== slot.returns) {
37
- throw new Error(
38
- `[DataKable] slot "${slot.name}" is already defined to return ${prev.returns}; a slot contract is never redefined \u2014 pick a new slot name`
39
- );
36
+ if (process.env.NODE_ENV !== "production") {
37
+ const prev = slots.get(slot.name);
38
+ if (prev && prev.returns !== slot.returns) {
39
+ throw new Error(
40
+ `[DataKable] slot "${slot.name}" is already defined to return ${prev.returns}; a slot contract is never redefined \u2014 pick a new slot name`
41
+ );
42
+ }
40
43
  }
41
44
  slots.set(slot.name, slot);
42
45
  return slot;
@@ -70,7 +73,8 @@ var expectedReturn = (slot) => expectedText[slot.returns];
70
73
  var formatSlot = defineSlot({
71
74
  name: "format",
72
75
  returns: "string",
73
- fallback: "those cells were coerced with the default formatter"
76
+ fallback: "cells-coerced"
77
+ // prose key (diagnostics/prose.ts)
74
78
  });
75
79
  var rowList = (rows, count) => {
76
80
  if (!rows || rows.length === 0) return "";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/catalog/slots.ts"],"sourcesContent":["import { defineDiagnostic } from '../diagnostics/catalog'\n\n/** What a callback slot must return: a type, or `'sync'` (anything but a thenable). */\nexport type SlotReturns = 'string' | 'number' | 'boolean' | 'sync'\n\n/** A callback return contract (§3.5): read by the slot checks to report `DK_CALLBACK_BAD_RETURN`. */\nexport interface SlotDefinition {\n /** The slot name, as in `columns[i].<name>` (`format`, `cell`). */\n readonly name: string\n readonly returns: SlotReturns\n /** What DataKable does with a bad return (the diagnostic's impact). */\n readonly fallback?: string\n}\n\nconst slots = new Map<string, SlotDefinition>()\n\n/**\n * Adds a callback return contract to the slot catalog and returns it. Like a diagnostic code, a slot\n * is never redefined with another contract (module re-evaluation with the same one is fine).\n */\nexport function defineSlot<const S extends SlotDefinition>(slot: S): S {\n const prev = slots.get(slot.name)\n // Development check: slots are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\") && prev && prev.returns !== slot.returns) {\n throw new Error(\n `[DataKable] slot \"${slot.name}\" is already defined to return ${prev.returns}; ` +\n 'a slot contract is never redefined — pick a new slot name',\n )\n }\n slots.set(slot.name, slot)\n return slot\n}\n\nexport function getSlot(name: string): SlotDefinition | undefined {\n return slots.get(name)\n}\n\nconst isThenable = (v: unknown) =>\n v != null &&\n (typeof v === 'object' || typeof v === 'function') &&\n typeof (v as { then?: unknown }).then === 'function'\n\n/** Whether `value` meets the slot's contract. */\nexport function matchesSlot(slot: Pick<SlotDefinition, 'returns'>, value: unknown): boolean {\n return slot.returns === 'sync' ? !isThenable(value) : typeof value === slot.returns\n}\n\nconst article = (word: string) => (/^[AEIOUaeiou]/.test(word) ? `an ${word}` : `a ${word}`)\n\n/** The type of a returned value in words (`a number`, `an Array`, `a Promise`); never the value. */\nexport function describeReturn(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n const type = typeof value\n if (type !== 'object' && type !== 'function') return article(type)\n if (Array.isArray(value)) return 'an Array'\n if (isThenable(value)) return 'a Promise'\n const proto = Object.getPrototypeOf(value) as { constructor?: { name?: unknown } } | null\n const name = proto?.constructor?.name\n return typeof name === 'string' && name !== '' ? article(name) : article(type)\n}\n\nconst expectedText: Record<SlotReturns, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n sync: 'a value (not a Promise)',\n}\n\n/** `expected` of a `DK_CALLBACK_BAD_RETURN` for `slot`. */\nexport const expectedReturn = (slot: Pick<SlotDefinition, 'returns'>) => expectedText[slot.returns]\n\n/** `columns[i].format` (§4.1): its value is coerced with the default formatter when not a string. */\nexport const formatSlot = defineSlot({\n name: 'format',\n returns: 'string',\n fallback: 'those cells were coerced with the default formatter',\n})\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_BAD_RETURN: {\n /** The callback's option path, e.g. `columns[2].format`. */\n slot: string\n /** Column id, for cell slots. */\n column?: string\n /** The contract, in words (`a string`). */\n expected: string\n /** The type of the first bad return (`a number`); never the value. */\n received: string\n /** How many calls returned a bad value. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows?: readonly number[]\n /** The fallback that was applied. */\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/**\n * The slot contract check (§3.4 `slotContract`). Dev only: the definition, its text and every call\n * site sit behind `(process.env.NODE_ENV !== \"production\")`, so a production bundle has none of it. It runs inside the existing\n * `column:batch` loop (per batch, never an interceptor per cell).\n */\nexport const slotDiagnostics = (process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic({\n code: 'DK_CALLBACK_BAD_RETURN',\n level: 'warn',\n where: (d) => ({ kind: 'option', path: d.slot }),\n problem: (d) =>\n `${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} returned ` +\n `${d.received} instead of ${d.expected} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => d.fallback,\n fix: (d) => [\n d.expected === 'a string'\n ? `return a string from ${d.slot}, e.g. (v) => String(v) or (v) => v.toFixed(2)`\n : `return ${d.expected} from ${d.slot}`,\n `if ${d.slot} is async or returns markup, compute the value before the table ` +\n '(or render it with cell)',\n ],\n }),\n ]\n : []\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AAcjC,IAAM,QAAQ,oBAAI,IAA4B;AAMvC,SAAS,WAA2C,MAAY;AACrE,QAAM,OAAO,MAAM,IAAI,KAAK,IAAI;AAEhC,MAAK,QAAQ,IAAI,aAAa,gBAAiB,QAAQ,KAAK,YAAY,KAAK,SAAS;AACpF,UAAM,IAAI;AAAA,MACR,qBAAqB,KAAK,IAAI,kCAAkC,KAAK,OAAO;AAAA,IAE9E;AAAA,EACF;AACA,QAAM,IAAI,KAAK,MAAM,IAAI;AACzB,SAAO;AACT;AAEO,SAAS,QAAQ,MAA0C;AAChE,SAAO,MAAM,IAAI,IAAI;AACvB;AAEA,IAAM,aAAa,CAAC,MAClB,KAAK,SACJ,OAAO,MAAM,YAAY,OAAO,MAAM,eACvC,OAAQ,EAAyB,SAAS;AAGrC,SAAS,YAAY,MAAuC,OAAyB;AAC1F,SAAO,KAAK,YAAY,SAAS,CAAC,WAAW,KAAK,IAAI,OAAO,UAAU,KAAK;AAC9E;AAEA,IAAM,UAAU,CAAC,SAAkB,gBAAgB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,KAAK,IAAI;AAGjF,SAAS,eAAe,OAAwB;AACrD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,WAAY,QAAO,QAAQ,IAAI;AACjE,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,WAAW,KAAK,EAAG,QAAO;AAC9B,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,QAAM,OAAO,OAAO,aAAa;AACjC,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAC/E;AAEA,IAAM,eAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;AAGO,IAAM,iBAAiB,CAAC,SAA0C,aAAa,KAAK,OAAO;AAG3F,IAAM,aAAa,WAAW;AAAA,EACnC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AACZ,CAAC;AAuBD,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAOO,IAAM,kBAAmB,QAAQ,IAAI,aAAa,eACrD;AAAA,MACE,iCAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK;AAAA,IAC9C,SAAS,CAAC,MACR,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,aAChE,EAAE,QAAQ,eAAe,EAAE,QAAQ,QACnC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,EAAE;AAAA,IACjB,KAAK,CAAC,MAAM;AAAA,MACV,EAAE,aAAa,aACX,wBAAwB,EAAE,IAAI,mDAC9B,UAAU,EAAE,QAAQ,SAAS,EAAE,IAAI;AAAA,MACvC,MAAM,EAAE,IAAI;AAAA,IAEd;AAAA,EACF,CAAC;AACH,IACA,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/catalog/slots.ts"],"sourcesContent":["import { defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\n/** What a callback slot must return: a type, or `'sync'` (anything but a thenable). */\nexport type SlotReturns = 'string' | 'number' | 'boolean' | 'sync'\n\n/** A callback return contract (§3.5): read by the slot checks to report `DK_CALLBACK_BAD_RETURN`. */\nexport interface SlotDefinition {\n /** The slot name, as in `columns[i].<name>` (`format`, `cell`). */\n readonly name: string\n readonly returns: SlotReturns\n /** What DataKable does with a bad return (the diagnostic's impact). */\n readonly fallback?: string\n}\n\nconst slots = new Map<string, SlotDefinition>()\n\n/**\n * Adds a callback return contract to the slot catalog and returns it. Like a diagnostic code, a slot\n * is never redefined with another contract (module re-evaluation with the same one is fine).\n */\nexport function defineSlot<const S extends SlotDefinition>(slot: S): S {\n // Development check: slots are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\")) {\n const prev = slots.get(slot.name)\n if (prev && prev.returns !== slot.returns) {\n throw new Error(\n `[DataKable] slot \"${slot.name}\" is already defined to return ${prev.returns}; ` +\n 'a slot contract is never redefined — pick a new slot name',\n )\n }\n }\n slots.set(slot.name, slot)\n return slot\n}\n\nexport function getSlot(name: string): SlotDefinition | undefined {\n return slots.get(name)\n}\n\nconst isThenable = (v: unknown) =>\n v != null &&\n (typeof v === 'object' || typeof v === 'function') &&\n typeof (v as { then?: unknown }).then === 'function'\n\n/** Whether `value` meets the slot's contract. */\nexport function matchesSlot(slot: Pick<SlotDefinition, 'returns'>, value: unknown): boolean {\n return slot.returns === 'sync' ? !isThenable(value) : typeof value === slot.returns\n}\n\nconst article = (word: string) => (/^[AEIOUaeiou]/.test(word) ? `an ${word}` : `a ${word}`)\n\n/** The type of a returned value in words (`a number`, `an Array`, `a Promise`); never the value. */\nexport function describeReturn(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n const type = typeof value\n if (type !== 'object' && type !== 'function') return article(type)\n if (Array.isArray(value)) return 'an Array'\n if (isThenable(value)) return 'a Promise'\n const proto = Object.getPrototypeOf(value) as { constructor?: { name?: unknown } } | null\n const name = proto?.constructor?.name\n return typeof name === 'string' && name !== '' ? article(name) : article(type)\n}\n\nconst expectedText: Record<SlotReturns, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n sync: 'a value (not a Promise)',\n}\n\n/** `expected` of a `DK_CALLBACK_BAD_RETURN` for `slot`. */\nexport const expectedReturn = (slot: Pick<SlotDefinition, 'returns'>) => expectedText[slot.returns]\n\n/** `columns[i].format` (§4.1): its value is coerced with the default formatter when not a string. */\nexport const formatSlot = defineSlot({\n name: 'format',\n returns: 'string',\n fallback: 'cells-coerced', // prose key (diagnostics/prose.ts)\n})\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_BAD_RETURN: {\n /** The callback's option path, e.g. `columns[2].format`. */\n slot: string\n /** Column id, for cell slots. */\n column?: string\n /** The contract, in words (`a string`). */\n expected: string\n /** The type of the first bad return (`a number`); never the value. */\n received: string\n /** How many calls returned a bad value. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows?: readonly number[]\n /** The fallback that was applied. */\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/**\n * The slot contract check (§3.4 `slotContract`). Dev only: the definition, its text and every call\n * site sit behind `(process.env.NODE_ENV !== \"production\")`, so a production bundle has none of it. It runs inside the existing\n * `column:batch` loop (per batch, never an interceptor per cell).\n */\nexport const slotDiagnostics = (process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic({\n code: 'DK_CALLBACK_BAD_RETURN',\n level: 'warn',\n where: (d) => ({ kind: 'option', path: d.slot }),\n problem: (d) =>\n `${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} returned ` +\n `${d.received} instead of ${d.expected} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => d.fallback,\n fix: (d) => [\n d.expected === 'a string'\n ? `return a string from ${d.slot}, e.g. (v) => String(v) or (v) => v.toFixed(2)`\n : `return ${d.expected} from ${d.slot}`,\n `if ${d.slot} is async or returns markup, compute the value before the table ` +\n '(or render it with cell)',\n ],\n }),\n ]\n : []\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAiC;AACjC,2BAAO;AAcP,IAAM,QAAQ,oBAAI,IAA4B;AAMvC,SAAS,WAA2C,MAAY;AAErE,MAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,UAAM,OAAO,MAAM,IAAI,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAK,YAAY,KAAK,SAAS;AACzC,YAAM,IAAI;AAAA,QACR,qBAAqB,KAAK,IAAI,kCAAkC,KAAK,OAAO;AAAA,MAE9E;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,KAAK,MAAM,IAAI;AACzB,SAAO;AACT;AAEO,SAAS,QAAQ,MAA0C;AAChE,SAAO,MAAM,IAAI,IAAI;AACvB;AAEA,IAAM,aAAa,CAAC,MAClB,KAAK,SACJ,OAAO,MAAM,YAAY,OAAO,MAAM,eACvC,OAAQ,EAAyB,SAAS;AAGrC,SAAS,YAAY,MAAuC,OAAyB;AAC1F,SAAO,KAAK,YAAY,SAAS,CAAC,WAAW,KAAK,IAAI,OAAO,UAAU,KAAK;AAC9E;AAEA,IAAM,UAAU,CAAC,SAAkB,gBAAgB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,KAAK,IAAI;AAGjF,SAAS,eAAe,OAAwB;AACrD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,WAAY,QAAO,QAAQ,IAAI;AACjE,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,WAAW,KAAK,EAAG,QAAO;AAC9B,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,QAAM,OAAO,OAAO,aAAa;AACjC,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAC/E;AAEA,IAAM,eAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;AAGO,IAAM,iBAAiB,CAAC,SAA0C,aAAa,KAAK,OAAO;AAG3F,IAAM,aAAa,WAAW;AAAA,EACnC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAuBD,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAOO,IAAM,kBAAmB,QAAQ,IAAI,aAAa,eACrD;AAAA,MACE,iCAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK;AAAA,IAC9C,SAAS,CAAC,MACR,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,aAChE,EAAE,QAAQ,eAAe,EAAE,QAAQ,QACnC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,EAAE;AAAA,IACjB,KAAK,CAAC,MAAM;AAAA,MACV,EAAE,aAAa,aACX,wBAAwB,EAAE,IAAI,mDAC9B,UAAU,EAAE,QAAQ,SAAS,EAAE,IAAI;AAAA,MACvC,MAAM,EAAE,IAAI;AAAA,IAEd;AAAA,EACF,CAAC;AACH,IACA,CAAC;","names":[]}
@@ -1,12 +1,15 @@
1
1
  // src/catalog/slots.ts
2
2
  import { defineDiagnostic } from "../diagnostics/catalog.js";
3
+ import "../diagnostics/process-guard.js";
3
4
  var slots = /* @__PURE__ */ new Map();
4
5
  function defineSlot(slot) {
5
- const prev = slots.get(slot.name);
6
- if (process.env.NODE_ENV !== "production" && prev && prev.returns !== slot.returns) {
7
- throw new Error(
8
- `[DataKable] slot "${slot.name}" is already defined to return ${prev.returns}; a slot contract is never redefined \u2014 pick a new slot name`
9
- );
6
+ if (process.env.NODE_ENV !== "production") {
7
+ const prev = slots.get(slot.name);
8
+ if (prev && prev.returns !== slot.returns) {
9
+ throw new Error(
10
+ `[DataKable] slot "${slot.name}" is already defined to return ${prev.returns}; a slot contract is never redefined \u2014 pick a new slot name`
11
+ );
12
+ }
10
13
  }
11
14
  slots.set(slot.name, slot);
12
15
  return slot;
@@ -40,7 +43,8 @@ var expectedReturn = (slot) => expectedText[slot.returns];
40
43
  var formatSlot = defineSlot({
41
44
  name: "format",
42
45
  returns: "string",
43
- fallback: "those cells were coerced with the default formatter"
46
+ fallback: "cells-coerced"
47
+ // prose key (diagnostics/prose.ts)
44
48
  });
45
49
  var rowList = (rows, count) => {
46
50
  if (!rows || rows.length === 0) return "";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/catalog/slots.ts"],"sourcesContent":["import { defineDiagnostic } from '../diagnostics/catalog'\n\n/** What a callback slot must return: a type, or `'sync'` (anything but a thenable). */\nexport type SlotReturns = 'string' | 'number' | 'boolean' | 'sync'\n\n/** A callback return contract (§3.5): read by the slot checks to report `DK_CALLBACK_BAD_RETURN`. */\nexport interface SlotDefinition {\n /** The slot name, as in `columns[i].<name>` (`format`, `cell`). */\n readonly name: string\n readonly returns: SlotReturns\n /** What DataKable does with a bad return (the diagnostic's impact). */\n readonly fallback?: string\n}\n\nconst slots = new Map<string, SlotDefinition>()\n\n/**\n * Adds a callback return contract to the slot catalog and returns it. Like a diagnostic code, a slot\n * is never redefined with another contract (module re-evaluation with the same one is fine).\n */\nexport function defineSlot<const S extends SlotDefinition>(slot: S): S {\n const prev = slots.get(slot.name)\n // Development check: slots are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\") && prev && prev.returns !== slot.returns) {\n throw new Error(\n `[DataKable] slot \"${slot.name}\" is already defined to return ${prev.returns}; ` +\n 'a slot contract is never redefined — pick a new slot name',\n )\n }\n slots.set(slot.name, slot)\n return slot\n}\n\nexport function getSlot(name: string): SlotDefinition | undefined {\n return slots.get(name)\n}\n\nconst isThenable = (v: unknown) =>\n v != null &&\n (typeof v === 'object' || typeof v === 'function') &&\n typeof (v as { then?: unknown }).then === 'function'\n\n/** Whether `value` meets the slot's contract. */\nexport function matchesSlot(slot: Pick<SlotDefinition, 'returns'>, value: unknown): boolean {\n return slot.returns === 'sync' ? !isThenable(value) : typeof value === slot.returns\n}\n\nconst article = (word: string) => (/^[AEIOUaeiou]/.test(word) ? `an ${word}` : `a ${word}`)\n\n/** The type of a returned value in words (`a number`, `an Array`, `a Promise`); never the value. */\nexport function describeReturn(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n const type = typeof value\n if (type !== 'object' && type !== 'function') return article(type)\n if (Array.isArray(value)) return 'an Array'\n if (isThenable(value)) return 'a Promise'\n const proto = Object.getPrototypeOf(value) as { constructor?: { name?: unknown } } | null\n const name = proto?.constructor?.name\n return typeof name === 'string' && name !== '' ? article(name) : article(type)\n}\n\nconst expectedText: Record<SlotReturns, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n sync: 'a value (not a Promise)',\n}\n\n/** `expected` of a `DK_CALLBACK_BAD_RETURN` for `slot`. */\nexport const expectedReturn = (slot: Pick<SlotDefinition, 'returns'>) => expectedText[slot.returns]\n\n/** `columns[i].format` (§4.1): its value is coerced with the default formatter when not a string. */\nexport const formatSlot = defineSlot({\n name: 'format',\n returns: 'string',\n fallback: 'those cells were coerced with the default formatter',\n})\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_BAD_RETURN: {\n /** The callback's option path, e.g. `columns[2].format`. */\n slot: string\n /** Column id, for cell slots. */\n column?: string\n /** The contract, in words (`a string`). */\n expected: string\n /** The type of the first bad return (`a number`); never the value. */\n received: string\n /** How many calls returned a bad value. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows?: readonly number[]\n /** The fallback that was applied. */\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/**\n * The slot contract check (§3.4 `slotContract`). Dev only: the definition, its text and every call\n * site sit behind `(process.env.NODE_ENV !== \"production\")`, so a production bundle has none of it. It runs inside the existing\n * `column:batch` loop (per batch, never an interceptor per cell).\n */\nexport const slotDiagnostics = (process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic({\n code: 'DK_CALLBACK_BAD_RETURN',\n level: 'warn',\n where: (d) => ({ kind: 'option', path: d.slot }),\n problem: (d) =>\n `${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} returned ` +\n `${d.received} instead of ${d.expected} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => d.fallback,\n fix: (d) => [\n d.expected === 'a string'\n ? `return a string from ${d.slot}, e.g. (v) => String(v) or (v) => v.toFixed(2)`\n : `return ${d.expected} from ${d.slot}`,\n `if ${d.slot} is async or returns markup, compute the value before the table ` +\n '(or render it with cell)',\n ],\n }),\n ]\n : []\n"],"mappings":";AAAA,SAAS,wBAAwB;AAcjC,IAAM,QAAQ,oBAAI,IAA4B;AAMvC,SAAS,WAA2C,MAAY;AACrE,QAAM,OAAO,MAAM,IAAI,KAAK,IAAI;AAEhC,MAAK,QAAQ,IAAI,aAAa,gBAAiB,QAAQ,KAAK,YAAY,KAAK,SAAS;AACpF,UAAM,IAAI;AAAA,MACR,qBAAqB,KAAK,IAAI,kCAAkC,KAAK,OAAO;AAAA,IAE9E;AAAA,EACF;AACA,QAAM,IAAI,KAAK,MAAM,IAAI;AACzB,SAAO;AACT;AAEO,SAAS,QAAQ,MAA0C;AAChE,SAAO,MAAM,IAAI,IAAI;AACvB;AAEA,IAAM,aAAa,CAAC,MAClB,KAAK,SACJ,OAAO,MAAM,YAAY,OAAO,MAAM,eACvC,OAAQ,EAAyB,SAAS;AAGrC,SAAS,YAAY,MAAuC,OAAyB;AAC1F,SAAO,KAAK,YAAY,SAAS,CAAC,WAAW,KAAK,IAAI,OAAO,UAAU,KAAK;AAC9E;AAEA,IAAM,UAAU,CAAC,SAAkB,gBAAgB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,KAAK,IAAI;AAGjF,SAAS,eAAe,OAAwB;AACrD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,WAAY,QAAO,QAAQ,IAAI;AACjE,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,WAAW,KAAK,EAAG,QAAO;AAC9B,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,QAAM,OAAO,OAAO,aAAa;AACjC,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAC/E;AAEA,IAAM,eAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;AAGO,IAAM,iBAAiB,CAAC,SAA0C,aAAa,KAAK,OAAO;AAG3F,IAAM,aAAa,WAAW;AAAA,EACnC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AACZ,CAAC;AAuBD,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAOO,IAAM,kBAAmB,QAAQ,IAAI,aAAa,eACrD;AAAA,EACE,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK;AAAA,IAC9C,SAAS,CAAC,MACR,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,aAChE,EAAE,QAAQ,eAAe,EAAE,QAAQ,QACnC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,EAAE;AAAA,IACjB,KAAK,CAAC,MAAM;AAAA,MACV,EAAE,aAAa,aACX,wBAAwB,EAAE,IAAI,mDAC9B,UAAU,EAAE,QAAQ,SAAS,EAAE,IAAI;AAAA,MACvC,MAAM,EAAE,IAAI;AAAA,IAEd;AAAA,EACF,CAAC;AACH,IACA,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/catalog/slots.ts"],"sourcesContent":["import { defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\n/** What a callback slot must return: a type, or `'sync'` (anything but a thenable). */\nexport type SlotReturns = 'string' | 'number' | 'boolean' | 'sync'\n\n/** A callback return contract (§3.5): read by the slot checks to report `DK_CALLBACK_BAD_RETURN`. */\nexport interface SlotDefinition {\n /** The slot name, as in `columns[i].<name>` (`format`, `cell`). */\n readonly name: string\n readonly returns: SlotReturns\n /** What DataKable does with a bad return (the diagnostic's impact). */\n readonly fallback?: string\n}\n\nconst slots = new Map<string, SlotDefinition>()\n\n/**\n * Adds a callback return contract to the slot catalog and returns it. Like a diagnostic code, a slot\n * is never redefined with another contract (module re-evaluation with the same one is fine).\n */\nexport function defineSlot<const S extends SlotDefinition>(slot: S): S {\n // Development check: slots are fixed at build time, a production bundle skips it.\n if ((process.env.NODE_ENV !== \"production\")) {\n const prev = slots.get(slot.name)\n if (prev && prev.returns !== slot.returns) {\n throw new Error(\n `[DataKable] slot \"${slot.name}\" is already defined to return ${prev.returns}; ` +\n 'a slot contract is never redefined — pick a new slot name',\n )\n }\n }\n slots.set(slot.name, slot)\n return slot\n}\n\nexport function getSlot(name: string): SlotDefinition | undefined {\n return slots.get(name)\n}\n\nconst isThenable = (v: unknown) =>\n v != null &&\n (typeof v === 'object' || typeof v === 'function') &&\n typeof (v as { then?: unknown }).then === 'function'\n\n/** Whether `value` meets the slot's contract. */\nexport function matchesSlot(slot: Pick<SlotDefinition, 'returns'>, value: unknown): boolean {\n return slot.returns === 'sync' ? !isThenable(value) : typeof value === slot.returns\n}\n\nconst article = (word: string) => (/^[AEIOUaeiou]/.test(word) ? `an ${word}` : `a ${word}`)\n\n/** The type of a returned value in words (`a number`, `an Array`, `a Promise`); never the value. */\nexport function describeReturn(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n const type = typeof value\n if (type !== 'object' && type !== 'function') return article(type)\n if (Array.isArray(value)) return 'an Array'\n if (isThenable(value)) return 'a Promise'\n const proto = Object.getPrototypeOf(value) as { constructor?: { name?: unknown } } | null\n const name = proto?.constructor?.name\n return typeof name === 'string' && name !== '' ? article(name) : article(type)\n}\n\nconst expectedText: Record<SlotReturns, string> = {\n string: 'a string',\n number: 'a number',\n boolean: 'a boolean',\n sync: 'a value (not a Promise)',\n}\n\n/** `expected` of a `DK_CALLBACK_BAD_RETURN` for `slot`. */\nexport const expectedReturn = (slot: Pick<SlotDefinition, 'returns'>) => expectedText[slot.returns]\n\n/** `columns[i].format` (§4.1): its value is coerced with the default formatter when not a string. */\nexport const formatSlot = defineSlot({\n name: 'format',\n returns: 'string',\n fallback: 'cells-coerced', // prose key (diagnostics/prose.ts)\n})\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_CALLBACK_BAD_RETURN: {\n /** The callback's option path, e.g. `columns[2].format`. */\n slot: string\n /** Column id, for cell slots. */\n column?: string\n /** The contract, in words (`a string`). */\n expected: string\n /** The type of the first bad return (`a number`); never the value. */\n received: string\n /** How many calls returned a bad value. */\n count: number\n /** A sample of the row indices (first few, in order). */\n rows?: readonly number[]\n /** The fallback that was applied. */\n fallback: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[] | undefined, count: number) => {\n if (!rows || rows.length === 0) return ''\n const list = rows.map((r) => `#${r}`).join(', ')\n return ` (${count > rows.length ? `first: ${list}, …` : `rows ${list}`})`\n}\n\n/**\n * The slot contract check (§3.4 `slotContract`). Dev only: the definition, its text and every call\n * site sit behind `(process.env.NODE_ENV !== \"production\")`, so a production bundle has none of it. It runs inside the existing\n * `column:batch` loop (per batch, never an interceptor per cell).\n */\nexport const slotDiagnostics = (process.env.NODE_ENV !== \"production\")\n ? [\n defineDiagnostic({\n code: 'DK_CALLBACK_BAD_RETURN',\n level: 'warn',\n where: (d) => ({ kind: 'option', path: d.slot }),\n problem: (d) =>\n `${d.slot}${d.column === undefined ? '' : ` (column \"${d.column}\")`} returned ` +\n `${d.received} instead of ${d.expected} for ` +\n `${d.count === 1 ? '1 row' : `${d.count} rows`}${rowList(d.rows, d.count)}`,\n impact: (d) => d.fallback,\n fix: (d) => [\n d.expected === 'a string'\n ? `return a string from ${d.slot}, e.g. (v) => String(v) or (v) => v.toFixed(2)`\n : `return ${d.expected} from ${d.slot}`,\n `if ${d.slot} is async or returns markup, compute the value before the table ` +\n '(or render it with cell)',\n ],\n }),\n ]\n : []\n"],"mappings":";AAAA,SAAS,wBAAwB;AACjC,OAAO;AAcP,IAAM,QAAQ,oBAAI,IAA4B;AAMvC,SAAS,WAA2C,MAAY;AAErE,MAAK,QAAQ,IAAI,aAAa,cAAe;AAC3C,UAAM,OAAO,MAAM,IAAI,KAAK,IAAI;AAChC,QAAI,QAAQ,KAAK,YAAY,KAAK,SAAS;AACzC,YAAM,IAAI;AAAA,QACR,qBAAqB,KAAK,IAAI,kCAAkC,KAAK,OAAO;AAAA,MAE9E;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,KAAK,MAAM,IAAI;AACzB,SAAO;AACT;AAEO,SAAS,QAAQ,MAA0C;AAChE,SAAO,MAAM,IAAI,IAAI;AACvB;AAEA,IAAM,aAAa,CAAC,MAClB,KAAK,SACJ,OAAO,MAAM,YAAY,OAAO,MAAM,eACvC,OAAQ,EAAyB,SAAS;AAGrC,SAAS,YAAY,MAAuC,OAAyB;AAC1F,SAAO,KAAK,YAAY,SAAS,CAAC,WAAW,KAAK,IAAI,OAAO,UAAU,KAAK;AAC9E;AAEA,IAAM,UAAU,CAAC,SAAkB,gBAAgB,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,KAAK,IAAI;AAGjF,SAAS,eAAe,OAAwB;AACrD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,WAAY,QAAO,QAAQ,IAAI;AACjE,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,MAAI,WAAW,KAAK,EAAG,QAAO;AAC9B,QAAM,QAAQ,OAAO,eAAe,KAAK;AACzC,QAAM,OAAO,OAAO,aAAa;AACjC,SAAO,OAAO,SAAS,YAAY,SAAS,KAAK,QAAQ,IAAI,IAAI,QAAQ,IAAI;AAC/E;AAEA,IAAM,eAA4C;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;AAGO,IAAM,iBAAiB,CAAC,SAA0C,aAAa,KAAK,OAAO;AAG3F,IAAM,aAAa,WAAW;AAAA,EACnC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA;AACZ,CAAC;AAuBD,IAAM,UAAU,CAAC,MAAqC,UAAkB;AACtE,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,IAAI,aAAQ,QAAQ,IAAI,EAAE;AACxE;AAOO,IAAM,kBAAmB,QAAQ,IAAI,aAAa,eACrD;AAAA,EACE,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO,CAAC,OAAO,EAAE,MAAM,UAAU,MAAM,EAAE,KAAK;AAAA,IAC9C,SAAS,CAAC,MACR,GAAG,EAAE,IAAI,GAAG,EAAE,WAAW,SAAY,KAAK,aAAa,EAAE,MAAM,IAAI,aAChE,EAAE,QAAQ,eAAe,EAAE,QAAQ,QACnC,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC3E,QAAQ,CAAC,MAAM,EAAE;AAAA,IACjB,KAAK,CAAC,MAAM;AAAA,MACV,EAAE,aAAa,aACX,wBAAwB,EAAE,IAAI,mDAC9B,UAAU,EAAE,QAAQ,SAAS,EAAE,IAAI;AAAA,MACvC,MAAM,EAAE,IAAI;AAAA,IAEd;AAAA,EACF,CAAC;AACH,IACA,CAAC;","names":[]}
@@ -86,6 +86,11 @@ interface EmitOptions {
86
86
  run?: number;
87
87
  trigger?: Trigger;
88
88
  phase?: Phase;
89
+ /**
90
+ * Not printed by the default console sink (another table printed it in this process, #38). Still
91
+ * stored and delivered to `onDiagnostic`.
92
+ */
93
+ quiet?: boolean;
89
94
  }
90
95
  /** Emits a catalog diagnostic; `details` is typed by `code` (see `DiagnosticCatalog`). */
91
96
  type Emit = <C extends DiagnosticCode>(code: C, details: DiagnosticDetails<C>, options?: EmitOptions) => void;
@@ -114,7 +119,7 @@ interface RedactionOptions {
114
119
  redact?: RedactFn;
115
120
  /** Ids / keys of `sensitive: true` columns: never logged at any level. */
116
121
  sensitiveColumns?: () => Iterable<string>;
117
- /** The `rowKey` column is sensitive: row keys are hashed at every level. */
122
+ /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */
118
123
  rowKeySensitive?: () => boolean;
119
124
  }
120
125
  /**
@@ -148,7 +153,9 @@ declare function hashRowKey(key: unknown): string;
148
153
  declare function describeValue(v: unknown): string;
149
154
  /**
150
155
  * A schema issue as `{ path, message }`. Validators embed received values in their messages, so
151
- * under `'safe'` / `'keys'` (and for sensitive columns) the message is DataKable's own text.
156
+ * under `'safe'` / `'keys'` the message is DataKable's own text. So it is at every level when the
157
+ * table has a sensitive column: any message (a root-level refinement, another field's) may embed
158
+ * its value (#46).
152
159
  */
153
160
  declare function scrubSchemaIssue(issue: unknown, r: Redactor, fieldPath?: string): {
154
161
  path: string;
@@ -307,7 +314,7 @@ declare function describeReturn(value: unknown): string;
307
314
  declare const formatSlot: {
308
315
  readonly name: "format";
309
316
  readonly returns: "string";
310
- readonly fallback: "those cells were coerced with the default formatter";
317
+ readonly fallback: "cells-coerced";
311
318
  };
312
319
  declare module '@datakable/core' {
313
320
  interface DiagnosticCatalog {
@@ -721,6 +728,12 @@ declare module '@datakable/core' {
721
728
  /** Whether a previous `searchFn` result is shown (`false`: none applied yet). */
722
729
  hadResults: boolean;
723
730
  };
731
+ DK_SEARCH_COLUMN_SKIPPED: {
732
+ /** Column id (`key` or `id`). */
733
+ column: string;
734
+ /** Position in the table's columns (`options.columns`, else the derived columns). */
735
+ index: number;
736
+ };
724
737
  }
725
738
  }
726
739
  /** Codes owned by the `search` feature (spec §6.3, §8.3). */
@@ -956,6 +969,14 @@ declare module '@datakable/core' {
956
969
  rows: number;
957
970
  /** The budget, in milliseconds (§9.3: the longest task). */
958
971
  budget: number;
972
+ /** One slice of the step's time-sliced work, run between pipeline runs (#61). */
973
+ sliced?: boolean;
974
+ /** The column slot at least half of the time went to, e.g. `columns[0].format` (#62). */
975
+ slot?: string;
976
+ /** Its column id. */
977
+ column?: string;
978
+ /** Its share of {@link ms}, 0.5 to 1. */
979
+ share?: number;
959
980
  };
960
981
  }
961
982
  }
@@ -1055,6 +1076,11 @@ declare module '@datakable/core' {
1055
1076
  /** Versions of every registered core copy, in registration order (this copy last). */
1056
1077
  versions: string[];
1057
1078
  };
1079
+ DK_DUPLICATE_CORE_SAME_VERSION: {
1080
+ version: string;
1081
+ /** Copies of core registered so far (this copy included), all of `version`. */
1082
+ copies: number;
1083
+ };
1058
1084
  DK_VERSION_MISMATCH: {
1059
1085
  /** The fixed-group package whose version differs, e.g. `@datakable/react`. */
1060
1086
  package: string;
@@ -1083,7 +1109,7 @@ declare module '@datakable/core' {
1083
1109
  }
1084
1110
  }
1085
1111
  /** Codes owned by versioning (§8.5). */
1086
- declare const versioningDiagnostics: (DiagnosticDefinition<"DK_DEPRECATED"> | DiagnosticDefinition<"DK_DUPLICATE_CORE"> | DiagnosticDefinition<"DK_VERSION_MISMATCH"> | DiagnosticDefinition<"DK_DEP_INCOMPATIBLE"> | DiagnosticDefinition<"DK_FEATURE_INCOMPATIBLE">)[];
1112
+ declare const versioningDiagnostics: (DiagnosticDefinition<"DK_DEPRECATED"> | DiagnosticDefinition<"DK_DUPLICATE_CORE"> | DiagnosticDefinition<"DK_DUPLICATE_CORE_SAME_VERSION"> | DiagnosticDefinition<"DK_VERSION_MISMATCH"> | DiagnosticDefinition<"DK_DEP_INCOMPATIBLE"> | DiagnosticDefinition<"DK_FEATURE_INCOMPATIBLE">)[];
1087
1113
 
1088
1114
  declare module '@datakable/core' {
1089
1115
  interface DiagnosticCatalog {
@@ -86,6 +86,11 @@ interface EmitOptions {
86
86
  run?: number;
87
87
  trigger?: Trigger;
88
88
  phase?: Phase;
89
+ /**
90
+ * Not printed by the default console sink (another table printed it in this process, #38). Still
91
+ * stored and delivered to `onDiagnostic`.
92
+ */
93
+ quiet?: boolean;
89
94
  }
90
95
  /** Emits a catalog diagnostic; `details` is typed by `code` (see `DiagnosticCatalog`). */
91
96
  type Emit = <C extends DiagnosticCode>(code: C, details: DiagnosticDetails<C>, options?: EmitOptions) => void;
@@ -114,7 +119,7 @@ interface RedactionOptions {
114
119
  redact?: RedactFn;
115
120
  /** Ids / keys of `sensitive: true` columns: never logged at any level. */
116
121
  sensitiveColumns?: () => Iterable<string>;
117
- /** The `rowKey` column is sensitive: row keys are hashed at every level. */
122
+ /** The `rowKey` path is, is inside or contains a sensitive column: keys hashed at every level. */
118
123
  rowKeySensitive?: () => boolean;
119
124
  }
120
125
  /**
@@ -148,7 +153,9 @@ declare function hashRowKey(key: unknown): string;
148
153
  declare function describeValue(v: unknown): string;
149
154
  /**
150
155
  * A schema issue as `{ path, message }`. Validators embed received values in their messages, so
151
- * under `'safe'` / `'keys'` (and for sensitive columns) the message is DataKable's own text.
156
+ * under `'safe'` / `'keys'` the message is DataKable's own text. So it is at every level when the
157
+ * table has a sensitive column: any message (a root-level refinement, another field's) may embed
158
+ * its value (#46).
152
159
  */
153
160
  declare function scrubSchemaIssue(issue: unknown, r: Redactor, fieldPath?: string): {
154
161
  path: string;
@@ -307,7 +314,7 @@ declare function describeReturn(value: unknown): string;
307
314
  declare const formatSlot: {
308
315
  readonly name: "format";
309
316
  readonly returns: "string";
310
- readonly fallback: "those cells were coerced with the default formatter";
317
+ readonly fallback: "cells-coerced";
311
318
  };
312
319
  declare module '@datakable/core' {
313
320
  interface DiagnosticCatalog {
@@ -721,6 +728,12 @@ declare module '@datakable/core' {
721
728
  /** Whether a previous `searchFn` result is shown (`false`: none applied yet). */
722
729
  hadResults: boolean;
723
730
  };
731
+ DK_SEARCH_COLUMN_SKIPPED: {
732
+ /** Column id (`key` or `id`). */
733
+ column: string;
734
+ /** Position in the table's columns (`options.columns`, else the derived columns). */
735
+ index: number;
736
+ };
724
737
  }
725
738
  }
726
739
  /** Codes owned by the `search` feature (spec §6.3, §8.3). */
@@ -956,6 +969,14 @@ declare module '@datakable/core' {
956
969
  rows: number;
957
970
  /** The budget, in milliseconds (§9.3: the longest task). */
958
971
  budget: number;
972
+ /** One slice of the step's time-sliced work, run between pipeline runs (#61). */
973
+ sliced?: boolean;
974
+ /** The column slot at least half of the time went to, e.g. `columns[0].format` (#62). */
975
+ slot?: string;
976
+ /** Its column id. */
977
+ column?: string;
978
+ /** Its share of {@link ms}, 0.5 to 1. */
979
+ share?: number;
959
980
  };
960
981
  }
961
982
  }
@@ -1055,6 +1076,11 @@ declare module '@datakable/core' {
1055
1076
  /** Versions of every registered core copy, in registration order (this copy last). */
1056
1077
  versions: string[];
1057
1078
  };
1079
+ DK_DUPLICATE_CORE_SAME_VERSION: {
1080
+ version: string;
1081
+ /** Copies of core registered so far (this copy included), all of `version`. */
1082
+ copies: number;
1083
+ };
1058
1084
  DK_VERSION_MISMATCH: {
1059
1085
  /** The fixed-group package whose version differs, e.g. `@datakable/react`. */
1060
1086
  package: string;
@@ -1083,7 +1109,7 @@ declare module '@datakable/core' {
1083
1109
  }
1084
1110
  }
1085
1111
  /** Codes owned by versioning (§8.5). */
1086
- declare const versioningDiagnostics: (DiagnosticDefinition<"DK_DEPRECATED"> | DiagnosticDefinition<"DK_DUPLICATE_CORE"> | DiagnosticDefinition<"DK_VERSION_MISMATCH"> | DiagnosticDefinition<"DK_DEP_INCOMPATIBLE"> | DiagnosticDefinition<"DK_FEATURE_INCOMPATIBLE">)[];
1112
+ declare const versioningDiagnostics: (DiagnosticDefinition<"DK_DEPRECATED"> | DiagnosticDefinition<"DK_DUPLICATE_CORE"> | DiagnosticDefinition<"DK_DUPLICATE_CORE_SAME_VERSION"> | DiagnosticDefinition<"DK_VERSION_MISMATCH"> | DiagnosticDefinition<"DK_DEP_INCOMPATIBLE"> | DiagnosticDefinition<"DK_FEATURE_INCOMPATIBLE">)[];
1087
1113
 
1088
1114
  declare module '@datakable/core' {
1089
1115
  interface DiagnosticCatalog {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/column/column-def.ts"],"sourcesContent":["import type { RowIssue } from '../pipeline/row'\nimport type { IsAny, Path, PathValue, Primitive } from './path'\n\n/** Whole-row `any` is treated as `Record<string, unknown>` (spec §4.2); other rows pass through. */\nexport type LooseRow<T> = IsAny<T> extends true ? Record<string, unknown> : T\n\n/** `true` for `any` and `unknown`: values whose shape is not known at compile time. */\ntype IsLoose<V> = IsAny<V> extends true ? true : unknown extends V ? true : false\n\n/** Type-agnostic filter kinds, the only ones allowed for `any` / `unknown` values. */\ntype LooseFilter = { type: 'equals' } | { type: 'contains' }\n\n// The filter sets are named so a wrong kind reads \"not assignable to type 'StringFilter'\" instead\n// of an inlined union (docs/how-to-fix/reading-type-errors.md, E3).\n/** Filter kinds for number, bigint and `Date` values. */\ntype NumberFilter = { type: 'range' } | { type: 'equals' } | { type: 'in' }\n/** Filter kinds for string values. `range` is not one of them. */\ntype StringFilter = { type: 'equals' } | { type: 'in' } | { type: 'contains' }\n/** Filter kinds for boolean values. */\ntype BooleanFilter = { type: 'equals' }\n\n/**\n * Filter kinds allowed for a column whose value type is `V` (spec §4.1, §6.1). Arrays of\n * primitives take their element's kinds (an array cell matches if any element matches).\n */\nexport type FilterFor<V> =\n IsLoose<V> extends true\n ? LooseFilter\n : NonNullable<V> extends number | bigint | Date\n ? NumberFilter\n : NonNullable<V> extends string\n ? StringFilter\n : NonNullable<V> extends boolean\n ? BooleanFilter\n : NonNullable<V> extends readonly (infer E)[]\n ? FilterFor<E>\n : never\n\n/** Values the default formatter can render: primitives, `Date`, arrays of those. */\ntype Displayable = Primitive | readonly Primitive[]\n\n/** Argument of a column's `cell` renderer. */\nexport type CellContext<T, V> = { row: T; value: V }\n\n/** Argument of a column's `invalidCell` renderer (a flagged row, `invalidRows: 'flag'`, §5.1). */\nexport type InvalidCellContext = {\n /** The raw, unvalidated row. */\n original: unknown\n /** The cell's raw value (the column's key path or accessor over `original`). */\n value: unknown\n /** The row's schema issues that touch this cell: `row.getCellIssues(column)`. */\n issues: readonly RowIssue[]\n}\n\n/** Built-in sort algorithms, or a custom one over row indices (spec §6.4). */\nexport type SortAlgorithm =\n | 'auto'\n | 'tim'\n | 'radix'\n | 'counting'\n | 'native'\n | ((indices: Uint32Array, compare: (a: number, b: number) => number) => Uint32Array)\n\n/** Fields shared by every column whose value type is `V`. */\ntype BaseColumn<T, V, R> = {\n header?: string\n /** Search weight; omit to exclude the column from search. */\n search?: number\n sortable?: boolean\n sortFn?: (a: V, b: V) => number\n sortBy?: (row: T) => Primitive\n sortAlgorithm?: SortAlgorithm\n filter?: FilterFor<V>\n /** Never logged by diagnostics at any level. */\n sensitive?: boolean\n invalidCell?: (ctx: InvalidCellContext) => R\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell?: (ctx: CellContext<T, V>) => R\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format?: (value: V) => string\n}\n\n/**\n * Rendering requirement for value `V`: objects, functions and arrays of objects MUST give `cell`\n * or `format`. Primitives, `Date`, arrays of primitives, `unknown` and `any` need neither.\n */\nexport type RenderReq<T, V, R> =\n IsLoose<V> extends true\n ? BaseColumn<T, V, R>\n : [NonNullable<V>] extends [Displayable]\n ? BaseColumn<T, V, R>\n : BaseColumn<T, V, R> & (NeedsCell<T, V, R> | NeedsFormat<V>)\n\n// The two ways to satisfy the rendering requirement are named so that a column missing both reads\n// \"Property 'format' is missing ... required in type 'NeedsFormat<V>'\", with `NeedsCell<T, V, R>`\n// listed as the alternative (docs/how-to-fix/reading-type-errors.md, E4 / E5). The JSDoc repeats BaseColumn's\n// word for word: autocomplete on a required `cell` / `format` shows it once only while the copies\n// are identical (pinned in type-errors.test.ts).\n\n/** Value `V` cannot be shown by the default formatter: the column needs `cell` (or `format`). */\ntype NeedsCell<T, V, R> = {\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell: (ctx: CellContext<T, V>) => R\n}\n\n/** Value `V` cannot be shown by the default formatter: the column needs `format` (or `cell`). */\ntype NeedsFormat<V> = {\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format: (value: V) => string\n}\n\n/**\n * Sort requirement for value `V` (spec §6.4): an object, function or array-of-objects column has\n * no default order, so `sortable: true` needs `sortFn` or `sortBy`. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither.\n */\nexport type SortReq<T, V> =\n IsLoose<V> extends true\n ? unknown\n : [NonNullable<V>] extends [Displayable]\n ? unknown\n : { sortable?: false } | NeedsSortFn<V> | NeedsSortBy<T>\n\n/** `sortable: true` on a column without a default order: compare the values with `sortFn`. */\ntype NeedsSortFn<V> = { sortable: true; sortFn: (a: V, b: V) => number }\n/** `sortable: true` on a column without a default order: sort by a primitive key. */\ntype NeedsSortBy<T> = { sortable: true; sortBy: (row: T) => Primitive }\n\n/** A column bound to a dot-path of `T`; a distributive union over every path. */\nexport type KeyColumn<T, R> = {\n [P in Path<T>]: { key: P } & RenderReq<T, PathValue<T, P>, R> & SortReq<T, PathValue<T, P>>\n}[Path<T>]\n\n/** A derived column: `accessor` computes the value from the (contextually typed) row. */\nexport type AccessorColumn<T, R> = {\n id: string\n accessor: (row: T) => unknown\n key?: never\n} & BaseColumn<T, unknown, R>\n\n/**\n * One column of a table over rows `T`. `R` is the `cell` render result (`unknown` in core,\n * `ReactNode` in `@datakable/react`). Whole-row `any` is treated as `Record<string, unknown>`.\n */\nexport type ColumnDef<T, R = unknown> = KeyColumn<LooseRow<T>, R> | AccessorColumn<LooseRow<T>, R>\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../src/column/column-def.ts"],"sourcesContent":["import type { RowIssue } from '../pipeline/row'\nimport type { IsAny, Path, PathValue, Primitive } from './path'\n\n/** Whole-row `any` is treated as `Record<string, unknown>` (spec §4.2); other rows pass through. */\nexport type LooseRow<T> = IsAny<T> extends true ? Record<string, unknown> : T\n\n/** `true` for `any` and `unknown`: values whose shape is not known at compile time. */\ntype IsLoose<V> = IsAny<V> extends true ? true : unknown extends V ? true : false\n\n/** Type-agnostic filter kinds, the only ones allowed for `any` / `unknown` values. */\ntype LooseFilter = { type: 'equals' } | { type: 'contains' }\n\n// The filter sets are named so a wrong kind reads \"not assignable to type 'StringFilter'\" instead\n// of an inlined union (docs/how-to-fix/reading-type-errors.md, E3).\n/** Filter kinds for number, bigint and `Date` values. */\ntype NumberFilter = { type: 'range' } | { type: 'equals' } | { type: 'in' }\n/** Filter kinds for string values. `range` is not one of them. */\ntype StringFilter = { type: 'equals' } | { type: 'in' } | { type: 'contains' }\n/** Filter kinds for boolean values. */\ntype BooleanFilter = { type: 'equals' }\n\n/**\n * Filter kinds allowed for a column whose value type is `V` (spec §4.1, §6.1). Arrays of\n * primitives take their element's kinds (an array cell matches if any element matches).\n */\nexport type FilterFor<V> =\n IsLoose<V> extends true\n ? LooseFilter\n : NonNullable<V> extends number | bigint | Date\n ? NumberFilter\n : NonNullable<V> extends string\n ? StringFilter\n : NonNullable<V> extends boolean\n ? BooleanFilter\n : NonNullable<V> extends readonly (infer E)[]\n ? FilterFor<E>\n : never\n\n/** Values the default formatter can render: primitives, `Date`, arrays of those. */\ntype Displayable = Primitive | readonly Primitive[]\n\n/** Argument of a column's `cell` renderer. */\nexport type CellContext<T, V> = { row: T; value: V }\n\n/** Argument of a column's `invalidCell` renderer (a flagged row, `invalidRows: 'flag'`, §5.1). */\nexport type InvalidCellContext = {\n /** The raw, unvalidated row. */\n original: unknown\n /** The cell's raw value (the column's key path or accessor over `original`). */\n value: unknown\n /** The row's schema issues that touch this cell: `row.getCellIssues(column)`. */\n issues: readonly RowIssue[]\n}\n\n/** Built-in sort algorithms, or a custom one over row indices (spec §6.4). */\nexport type SortAlgorithm =\n | 'auto'\n | 'tim'\n | 'radix'\n | 'counting'\n | 'native'\n | ((indices: Uint32Array, compare: (a: number, b: number) => number) => Uint32Array)\n\n/** Fields shared by every column whose value type is `V`. */\ntype BaseColumn<T, V, R> = {\n header?: string\n /**\n * Search weight. Once any column declares one, only weighted columns are searched; when none\n * does, the columns of strings, numbers and booleans are (a date, array or object column needs a\n * weight to be searched).\n */\n search?: number\n sortable?: boolean\n sortFn?: (a: V, b: V) => number\n sortBy?: (row: T) => Primitive\n sortAlgorithm?: SortAlgorithm\n filter?: FilterFor<V>\n /** Never logged by diagnostics at any level. */\n sensitive?: boolean\n invalidCell?: (ctx: InvalidCellContext) => R\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell?: (ctx: CellContext<T, V>) => R\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format?: (value: V) => string\n}\n\n/**\n * Rendering requirement for value `V`: objects, functions and arrays of objects MUST give `cell`\n * or `format`. Primitives, `Date`, arrays of primitives, `unknown` and `any` need neither.\n */\nexport type RenderReq<T, V, R> =\n IsLoose<V> extends true\n ? BaseColumn<T, V, R>\n : [NonNullable<V>] extends [Displayable]\n ? BaseColumn<T, V, R>\n : BaseColumn<T, V, R> & (NeedsCell<T, V, R> | NeedsFormat<V>)\n\n// The two ways to satisfy the rendering requirement are named so that a column missing both reads\n// \"Property 'format' is missing ... required in type 'NeedsFormat<V>'\", with `NeedsCell<T, V, R>`\n// listed as the alternative (docs/how-to-fix/reading-type-errors.md, E4 / E5). The JSDoc repeats BaseColumn's\n// word for word: autocomplete on a required `cell` / `format` shows it once only while the copies\n// are identical (pinned in type-errors.test.ts).\n\n/** Value `V` cannot be shown by the default formatter: the column needs `cell` (or `format`). */\ntype NeedsCell<T, V, R> = {\n /**\n * Renders the cell. Required (or `format`) when the value is an object, a function or an\n * array of objects — the default formatter cannot display those. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither. Returns `R` (`ReactNode` in\n * `@datakable/react`).\n */\n cell: (ctx: CellContext<T, V>) => R\n}\n\n/** Value `V` cannot be shown by the default formatter: the column needs `format` (or `cell`). */\ntype NeedsFormat<V> = {\n /**\n * Formats the value to a string. Required (or `cell`) when the value is an object, a function\n * or an array of objects — the default formatter cannot display those. Primitives, `Date`,\n * arrays of primitives, `unknown` and `any` need neither.\n */\n format: (value: V) => string\n}\n\n/**\n * Sort requirement for value `V` (spec §6.4): an object, function or array-of-objects column has\n * no default order, so `sortable: true` needs `sortFn` or `sortBy`. Primitives, `Date`, arrays of\n * primitives, `unknown` and `any` need neither.\n */\nexport type SortReq<T, V> =\n IsLoose<V> extends true\n ? unknown\n : [NonNullable<V>] extends [Displayable]\n ? unknown\n : { sortable?: false } | NeedsSortFn<V> | NeedsSortBy<T>\n\n/** `sortable: true` on a column without a default order: compare the values with `sortFn`. */\ntype NeedsSortFn<V> = { sortable: true; sortFn: (a: V, b: V) => number }\n/** `sortable: true` on a column without a default order: sort by a primitive key. */\ntype NeedsSortBy<T> = { sortable: true; sortBy: (row: T) => Primitive }\n\n/** A column bound to a dot-path of `T`; a distributive union over every path. */\nexport type KeyColumn<T, R> = {\n [P in Path<T>]: { key: P } & RenderReq<T, PathValue<T, P>, R> & SortReq<T, PathValue<T, P>>\n}[Path<T>]\n\n/** A derived column: `accessor` computes the value from the (contextually typed) row. */\nexport type AccessorColumn<T, R> = {\n id: string\n accessor: (row: T) => unknown\n key?: never\n} & BaseColumn<T, unknown, R>\n\n/**\n * One column of a table over rows `T`. `R` is the `cell` render result (`unknown` in core,\n * `ReactNode` in `@datakable/react`). Whole-row `any` is treated as `Record<string, unknown>`.\n */\nexport type ColumnDef<T, R = unknown> = KeyColumn<LooseRow<T>, R> | AccessorColumn<LooseRow<T>, R>\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -33,7 +33,12 @@ function getValue(row, path, onError) {
33
33
  try {
34
34
  for (let i = 0; i < segs.length; i++) {
35
35
  if (cur === null || typeof cur !== "object") return void 0;
36
- cur = cur[segs[i]];
36
+ const seg = segs[i];
37
+ const next = cur[seg];
38
+ if ((typeof next === "function" || seg === "__proto__") && !Object.hasOwn(cur, seg)) {
39
+ return void 0;
40
+ }
41
+ cur = next;
37
42
  }
38
43
  } catch (error) {
39
44
  onError?.(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[segs[i] as string]\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AASO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAO,IAAgC,KAAK,CAAC,CAAW;AAAA,IAC1D;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. An\n * inherited method or `__proto__` (`constructor`, `toString`, `map`) yields `undefined`. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n const seg = segs[i] as string\n const next = (cur as Record<string, unknown>)[seg]\n // Inherited methods and `__proto__` (`constructor`, `toString`) are not row data (#42);\n // checked only for function values, so plain data and class getters cost nothing more.\n if ((typeof next === 'function' || seg === '__proto__') && !Object.hasOwn(cur, seg)) {\n return undefined\n }\n cur = next\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AAUO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,OAAQ,IAAgC,GAAG;AAGjD,WAAK,OAAO,SAAS,cAAc,QAAQ,gBAAgB,CAAC,OAAO,OAAO,KAAK,GAAG,GAAG;AACnF,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
@@ -8,7 +8,12 @@ function getValue(row, path, onError) {
8
8
  try {
9
9
  for (let i = 0; i < segs.length; i++) {
10
10
  if (cur === null || typeof cur !== "object") return void 0;
11
- cur = cur[segs[i]];
11
+ const seg = segs[i];
12
+ const next = cur[seg];
13
+ if ((typeof next === "function" || seg === "__proto__") && !Object.hasOwn(cur, seg)) {
14
+ return void 0;
15
+ }
16
+ cur = next;
12
17
  }
13
18
  } catch (error) {
14
19
  onError?.(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[segs[i] as string]\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AASO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAO,IAAgC,KAAK,CAAC,CAAW;AAAA,IAC1D;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/column/get-value.ts"],"sourcesContent":["/** A dot-path split into its segments once, for repeated per-cell walks. */\nexport type CompiledPath = readonly string[]\n\n/** Splits a dot-path (`'address.geo.lat'`) into segments. Call once per column, not per cell. */\nexport function compilePath(path: string): CompiledPath {\n return path.split('.')\n}\n\n/**\n * Reads the value at `path` of `row`, defensively (§4.3): a `null`, `undefined` or non-object\n * (primitive, function) part-way through yields `undefined`. Arrays are walked by index. An\n * inherited method or `__proto__` (`constructor`, `toString`, `map`) yields `undefined`. Never\n * throws: a throwing getter or Proxy trap yields `undefined` and is passed to `onError`.\n *\n * Hot paths should pass a {@link compilePath} result so the walk allocates nothing per cell.\n */\nexport function getValue(\n row: unknown,\n path: string | CompiledPath,\n onError?: (error: unknown) => void,\n): unknown {\n const segs = typeof path === 'string' ? compilePath(path) : path\n let cur: unknown = row\n try {\n for (let i = 0; i < segs.length; i++) {\n if (cur === null || typeof cur !== 'object') return undefined\n const seg = segs[i] as string\n const next = (cur as Record<string, unknown>)[seg]\n // Inherited methods and `__proto__` (`constructor`, `toString`) are not row data (#42);\n // checked only for function values, so plain data and class getters cost nothing more.\n if ((typeof next === 'function' || seg === '__proto__') && !Object.hasOwn(cur, seg)) {\n return undefined\n }\n cur = next\n }\n } catch (error) {\n // The column cache (pipeline/column-cache.ts) passes onError and reports DK_CALLBACK_FAILED\n // once per column batch with the failing row indices (no per-cell emit).\n onError?.(error)\n return undefined\n }\n return cur\n}\n"],"mappings":";AAIO,SAAS,YAAY,MAA4B;AACtD,SAAO,KAAK,MAAM,GAAG;AACvB;AAUO,SAAS,SACd,KACA,MACA,SACS;AACT,QAAM,OAAO,OAAO,SAAS,WAAW,YAAY,IAAI,IAAI;AAC5D,MAAI,MAAe;AACnB,MAAI;AACF,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,QAAQ,QAAQ,OAAO,QAAQ,SAAU,QAAO;AACpD,YAAM,MAAM,KAAK,CAAC;AAClB,YAAM,OAAQ,IAAgC,GAAG;AAGjD,WAAK,OAAO,SAAS,cAAc,QAAQ,gBAAgB,CAAC,OAAO,OAAO,KAAK,GAAG,GAAG;AACnF,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAAA,EACF,SAAS,OAAO;AAGd,cAAU,KAAK;AACf,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-OsjAR3Wz.cjs';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-vkD2cewE.cjs';
1
+ export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.cjs';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-Q8Cg0cZy.cjs';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.cjs';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */
@@ -1,5 +1,5 @@
1
- export { U as columnFiltersDiagnostics } from './codes-OsjAR3Wz.js';
2
- import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-Dn99IQt0.js';
1
+ export { U as columnFiltersDiagnostics } from './codes-B9bCK73-.js';
2
+ import { G as FilterFor, a1 as Path, P as LooseRow, a2 as PathValue, e as FeatureTypes, F as Feature } from './explain-i0OATi_W.js';
3
3
  import { a as DataMode } from './mode-DFV8ryXo.js';
4
4
 
5
5
  /** The value a filter compares against: the element type for array-valued cells (§6.1). */