@datakable/core 1.0.1 → 2.0.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.
- package/README.md +5 -3
- package/dist/catalog/codes.cjs +12 -8
- package/dist/catalog/codes.cjs.map +1 -1
- package/dist/catalog/codes.js +12 -8
- package/dist/catalog/codes.js.map +1 -1
- package/dist/catalog/slots.cjs +10 -6
- package/dist/catalog/slots.cjs.map +1 -1
- package/dist/catalog/slots.js +10 -6
- package/dist/catalog/slots.js.map +1 -1
- package/dist/{codes-OsjAR3Wz.d.cts → codes-B9bCK73-.d.cts} +30 -4
- package/dist/{codes-OsjAR3Wz.d.ts → codes-B9bCK73-.d.ts} +30 -4
- package/dist/column/column-def.cjs.map +1 -1
- package/dist/column/get-value.cjs +6 -1
- package/dist/column/get-value.cjs.map +1 -1
- package/dist/column/get-value.js +6 -1
- package/dist/column/get-value.js.map +1 -1
- package/dist/column-filters.d.cts +2 -2
- package/dist/column-filters.d.ts +2 -2
- package/dist/diagnostics/build.cjs +4 -1
- package/dist/diagnostics/build.cjs.map +1 -1
- package/dist/diagnostics/build.js +4 -1
- package/dist/diagnostics/build.js.map +1 -1
- package/dist/diagnostics/catalog.cjs +11 -5
- package/dist/diagnostics/catalog.cjs.map +1 -1
- package/dist/diagnostics/catalog.js +10 -5
- package/dist/diagnostics/catalog.js.map +1 -1
- package/dist/diagnostics/codes.cjs +12 -8
- package/dist/diagnostics/codes.cjs.map +1 -1
- package/dist/diagnostics/codes.js +12 -8
- package/dist/diagnostics/codes.js.map +1 -1
- package/dist/diagnostics/console.cjs +13 -6
- package/dist/diagnostics/console.cjs.map +1 -1
- package/dist/diagnostics/console.js +13 -6
- package/dist/diagnostics/console.js.map +1 -1
- package/dist/diagnostics/env.cjs +1 -0
- package/dist/diagnostics/env.cjs.map +1 -1
- package/dist/diagnostics/env.js +1 -0
- package/dist/diagnostics/env.js.map +1 -1
- package/dist/diagnostics/explain-text.cjs +2 -1
- package/dist/diagnostics/explain-text.cjs.map +1 -1
- package/dist/diagnostics/explain-text.js +2 -1
- package/dist/diagnostics/explain-text.js.map +1 -1
- package/dist/diagnostics/explain.cjs +3 -2
- package/dist/diagnostics/explain.cjs.map +1 -1
- package/dist/diagnostics/explain.js +3 -2
- package/dist/diagnostics/explain.js.map +1 -1
- package/dist/diagnostics/hub.cjs +5 -4
- package/dist/diagnostics/hub.cjs.map +1 -1
- package/dist/diagnostics/hub.js +5 -4
- package/dist/diagnostics/hub.js.map +1 -1
- package/dist/diagnostics/process-guard.cjs +26 -0
- package/dist/diagnostics/process-guard.cjs.map +1 -0
- package/dist/diagnostics/process-guard.js +9 -0
- package/dist/diagnostics/process-guard.js.map +1 -0
- package/dist/diagnostics/prose.cjs +120 -0
- package/dist/diagnostics/prose.cjs.map +1 -0
- package/dist/diagnostics/prose.js +93 -0
- package/dist/diagnostics/prose.js.map +1 -0
- package/dist/diagnostics/redact.cjs +7 -4
- package/dist/diagnostics/redact.cjs.map +1 -1
- package/dist/diagnostics/redact.js +6 -4
- package/dist/diagnostics/redact.js.map +1 -1
- package/dist/diagnostics/trace-store.cjs +6 -0
- package/dist/diagnostics/trace-store.cjs.map +1 -1
- package/dist/diagnostics/trace-store.js +4 -0
- package/dist/diagnostics/trace-store.js.map +1 -1
- package/dist/diagnostics/tracer.cjs +74 -13
- package/dist/diagnostics/tracer.cjs.map +1 -1
- package/dist/diagnostics/tracer.js +75 -14
- package/dist/diagnostics/tracer.js.map +1 -1
- package/dist/diagnostics/types.cjs.map +1 -1
- package/dist/{explain-vkD2cewE.d.cts → explain-Q8Cg0cZy.d.cts} +13 -4
- package/dist/{explain-Dn99IQt0.d.ts → explain-i0OATi_W.d.ts} +13 -4
- package/dist/feature/codes.cjs +1 -0
- package/dist/feature/codes.cjs.map +1 -1
- package/dist/feature/codes.js +1 -0
- package/dist/feature/codes.js.map +1 -1
- package/dist/feature/install.cjs +4 -3
- package/dist/feature/install.cjs.map +1 -1
- package/dist/feature/install.js +4 -3
- package/dist/feature/install.js.map +1 -1
- package/dist/features/column-filters/codes.cjs +1 -0
- package/dist/features/column-filters/codes.cjs.map +1 -1
- package/dist/features/column-filters/codes.js +1 -0
- package/dist/features/column-filters/codes.js.map +1 -1
- package/dist/features/column-filters/column-filters.cjs +4 -2
- package/dist/features/column-filters/column-filters.cjs.map +1 -1
- package/dist/features/column-filters/column-filters.js +4 -2
- package/dist/features/column-filters/column-filters.js.map +1 -1
- package/dist/features/column-filters/match.cjs +5 -5
- package/dist/features/column-filters/match.cjs.map +1 -1
- package/dist/features/column-filters/match.js +5 -5
- package/dist/features/column-filters/match.js.map +1 -1
- package/dist/features/pagination/codes.cjs +1 -0
- package/dist/features/pagination/codes.cjs.map +1 -1
- package/dist/features/pagination/codes.js +1 -0
- package/dist/features/pagination/codes.js.map +1 -1
- package/dist/features/pagination/pagination.cjs +16 -13
- package/dist/features/pagination/pagination.cjs.map +1 -1
- package/dist/features/pagination/pagination.js +16 -13
- package/dist/features/pagination/pagination.js.map +1 -1
- package/dist/features/search/codes.cjs +1 -0
- package/dist/features/search/codes.cjs.map +1 -1
- package/dist/features/search/codes.js +1 -0
- package/dist/features/search/codes.js.map +1 -1
- package/dist/features/search/search-index.cjs +68 -15
- package/dist/features/search/search-index.cjs.map +1 -1
- package/dist/features/search/search-index.js +68 -15
- package/dist/features/search/search-index.js.map +1 -1
- package/dist/features/search/search.cjs +41 -9
- package/dist/features/search/search.cjs.map +1 -1
- package/dist/features/search/search.js +41 -9
- package/dist/features/search/search.js.map +1 -1
- package/dist/features/search/skipped-codes.cjs +45 -0
- package/dist/features/search/skipped-codes.cjs.map +1 -0
- package/dist/features/search/skipped-codes.js +20 -0
- package/dist/features/search/skipped-codes.js.map +1 -0
- package/dist/features/sorting/codes.cjs +1 -0
- package/dist/features/sorting/codes.cjs.map +1 -1
- package/dist/features/sorting/codes.js +1 -0
- package/dist/features/sorting/codes.js.map +1 -1
- package/dist/features/sorting/sorting.cjs +16 -20
- package/dist/features/sorting/sorting.cjs.map +1 -1
- package/dist/features/sorting/sorting.js +16 -20
- package/dist/features/sorting/sorting.js.map +1 -1
- package/dist/features/sorting/strategy.cjs +4 -4
- package/dist/features/sorting/strategy.cjs.map +1 -1
- package/dist/features/sorting/strategy.js +4 -4
- package/dist/features/sorting/strategy.js.map +1 -1
- package/dist/features/validity/codes.cjs +1 -0
- package/dist/features/validity/codes.cjs.map +1 -1
- package/dist/features/validity/codes.js +1 -0
- package/dist/features/validity/codes.js.map +1 -1
- package/dist/features/validity/validity.cjs +3 -3
- package/dist/features/validity/validity.cjs.map +1 -1
- package/dist/features/validity/validity.js +3 -3
- package/dist/features/validity/validity.js.map +1 -1
- package/dist/index.d.cts +13 -10
- package/dist/index.d.ts +13 -10
- package/dist/ingest/data-check-codes.cjs +4 -2
- package/dist/ingest/data-check-codes.cjs.map +1 -1
- package/dist/ingest/data-check-codes.js +4 -2
- package/dist/ingest/data-check-codes.js.map +1 -1
- package/dist/ingest/data-checks.cjs +1 -1
- package/dist/ingest/data-checks.cjs.map +1 -1
- package/dist/ingest/data-checks.js +1 -1
- package/dist/ingest/data-checks.js.map +1 -1
- package/dist/ingest/row-key-codes.cjs +1 -0
- package/dist/ingest/row-key-codes.cjs.map +1 -1
- package/dist/ingest/row-key-codes.js +1 -0
- package/dist/ingest/row-key-codes.js.map +1 -1
- package/dist/ingest/row-key.cjs +23 -20
- package/dist/ingest/row-key.cjs.map +1 -1
- package/dist/ingest/row-key.js +23 -20
- package/dist/ingest/row-key.js.map +1 -1
- package/dist/ingest/schema-codes.cjs +1 -0
- package/dist/ingest/schema-codes.cjs.map +1 -1
- package/dist/ingest/schema-codes.js +1 -0
- package/dist/ingest/schema-codes.js.map +1 -1
- package/dist/ingest/unique-fields.cjs +2 -2
- package/dist/ingest/unique-fields.cjs.map +1 -1
- package/dist/ingest/unique-fields.js +2 -2
- package/dist/ingest/unique-fields.js.map +1 -1
- package/dist/intercept/boundary.cjs +4 -2
- package/dist/intercept/boundary.cjs.map +1 -1
- package/dist/intercept/boundary.js +4 -2
- package/dist/intercept/boundary.js.map +1 -1
- package/dist/intercept/cell-batch.cjs +4 -4
- package/dist/intercept/cell-batch.cjs.map +1 -1
- package/dist/intercept/cell-batch.js +4 -4
- package/dist/intercept/cell-batch.js.map +1 -1
- package/dist/intercept/codes.cjs +1 -0
- package/dist/intercept/codes.cjs.map +1 -1
- package/dist/intercept/codes.js +1 -0
- package/dist/intercept/codes.js.map +1 -1
- package/dist/intercept/fallbacks.cjs +12 -20
- package/dist/intercept/fallbacks.cjs.map +1 -1
- package/dist/intercept/fallbacks.js +12 -20
- package/dist/intercept/fallbacks.js.map +1 -1
- package/dist/intercept/runtime.cjs +7 -9
- package/dist/intercept/runtime.cjs.map +1 -1
- package/dist/intercept/runtime.js +7 -9
- package/dist/intercept/runtime.js.map +1 -1
- package/dist/messages/index.cjs +4 -1
- package/dist/messages/index.cjs.map +1 -1
- package/dist/messages/index.js +4 -1
- package/dist/messages/index.js.map +1 -1
- package/dist/pagination.d.cts +2 -2
- package/dist/pagination.d.ts +2 -2
- package/dist/pipeline/codes.cjs +1 -0
- package/dist/pipeline/codes.cjs.map +1 -1
- package/dist/pipeline/codes.js +1 -0
- package/dist/pipeline/codes.js.map +1 -1
- package/dist/pipeline/column-cache.cjs +94 -76
- package/dist/pipeline/column-cache.cjs.map +1 -1
- package/dist/pipeline/column-cache.js +92 -75
- package/dist/pipeline/column-cache.js.map +1 -1
- package/dist/pipeline/dev-checks.cjs +1 -0
- package/dist/pipeline/dev-checks.cjs.map +1 -1
- package/dist/pipeline/dev-checks.js +1 -0
- package/dist/pipeline/dev-checks.js.map +1 -1
- package/dist/pipeline/env-codes.cjs +3 -2
- package/dist/pipeline/env-codes.cjs.map +1 -1
- package/dist/pipeline/env-codes.js +3 -2
- package/dist/pipeline/env-codes.js.map +1 -1
- package/dist/pipeline/perf-codes.cjs +1 -0
- package/dist/pipeline/perf-codes.cjs.map +1 -1
- package/dist/pipeline/perf-codes.js +1 -0
- package/dist/pipeline/perf-codes.js.map +1 -1
- package/dist/pipeline/runner.cjs +17 -9
- package/dist/pipeline/runner.cjs.map +1 -1
- package/dist/pipeline/runner.js +17 -9
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/pipeline/slice.cjs +3 -1
- package/dist/pipeline/slice.cjs.map +1 -1
- package/dist/pipeline/slice.js +3 -1
- package/dist/pipeline/slice.js.map +1 -1
- package/dist/schema.d.cts +2 -2
- package/dist/schema.d.ts +2 -2
- package/dist/{search-async-entry-v5JdEk5Y.d.cts → search-async-entry-CuLYPfY_.d.cts} +2 -2
- package/dist/{search-async-entry-DGSw2pDL.d.ts → search-async-entry-Cx7xpuVZ.d.ts} +2 -2
- package/dist/search-async.d.cts +3 -3
- package/dist/search-async.d.ts +3 -3
- package/dist/search.d.cts +8 -6
- package/dist/search.d.ts +8 -6
- package/dist/server.d.cts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/sorting.d.cts +2 -2
- package/dist/sorting.d.ts +2 -2
- package/dist/source/codes.cjs +1 -0
- package/dist/source/codes.cjs.map +1 -1
- package/dist/source/codes.js +1 -0
- package/dist/source/codes.js.map +1 -1
- package/dist/source/fetch-codes.cjs +1 -0
- package/dist/source/fetch-codes.cjs.map +1 -1
- package/dist/source/fetch-codes.js +1 -0
- package/dist/source/fetch-codes.js.map +1 -1
- package/dist/table/codes.cjs +1 -0
- package/dist/table/codes.cjs.map +1 -1
- package/dist/table/codes.js +1 -0
- package/dist/table/codes.js.map +1 -1
- package/dist/table/create-table.cjs +39 -9
- package/dist/table/create-table.cjs.map +1 -1
- package/dist/table/create-table.js +39 -9
- package/dist/table/create-table.js.map +1 -1
- package/dist/table/data-mutation.cjs +1 -0
- package/dist/table/data-mutation.cjs.map +1 -1
- package/dist/table/data-mutation.js +1 -0
- package/dist/table/data-mutation.js.map +1 -1
- package/dist/table/internals.cjs.map +1 -1
- package/dist/table/internals.js.map +1 -1
- package/dist/table/ssr-codes.cjs +1 -0
- package/dist/table/ssr-codes.cjs.map +1 -1
- package/dist/table/ssr-codes.js +1 -0
- package/dist/table/ssr-codes.js.map +1 -1
- package/dist/table/ssr.cjs +4 -1
- package/dist/table/ssr.cjs.map +1 -1
- package/dist/table/ssr.js +4 -1
- package/dist/table/ssr.js.map +1 -1
- package/dist/table/state-feedback.cjs +19 -0
- package/dist/table/state-feedback.cjs.map +1 -1
- package/dist/table/state-feedback.js +19 -0
- package/dist/table/state-feedback.js.map +1 -1
- package/dist/table/types.cjs.map +1 -1
- package/dist/table/types.js.map +1 -1
- package/dist/validity.d.cts +2 -2
- package/dist/validity.d.ts +2 -2
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/versioning/codes.cjs +18 -0
- package/dist/versioning/codes.cjs.map +1 -1
- package/dist/versioning/codes.js +18 -0
- package/dist/versioning/codes.js.map +1 -1
- package/dist/versioning/registry.cjs +4 -2
- package/dist/versioning/registry.cjs.map +1 -1
- package/dist/versioning/registry.js +4 -2
- package/dist/versioning/registry.js.map +1 -1
- package/package.json +39 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/row-key-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_DUPLICATE_ROW_KEY: {\n /** The `rowKey` path; absent for a `rowKey` function. */\n path?: string\n /** The first repeated key value (hashed under `'safe'`). */\n key: string | number\n /** A sample of the rows sharing `key` (first few, in order; the first keeps its key). */\n rows: readonly number[]\n /** How many rows share `key`. */\n shared: number\n /** How many rows got a fallback key (all repeated values). */\n count: number\n /** How many distinct key values repeat. */\n groups: number\n /** `data.length`. */\n total: number\n /** Fields unique across all rows (computed by a scan). */\n unique: readonly string[]\n /** No unique field: a field that, with the `rowKey` path, makes a unique composite key. */\n pair?: string\n }\n DK_MISSING_ROW_KEY: {\n /** The `rowKey` path; absent for a `rowKey` function. */\n path?: string\n /** A sample of the rows without a usable key (first few, in order). */\n rows: readonly number[]\n count: number\n /** `data.length`. */\n total: number\n /** The type of the first unusable value: `undefined`, `null`, `object`, `number(NaN)`, … */\n valueType: string\n /** Fields unique across all rows (computed by a scan). */\n unique: readonly string[]\n }\n }\n}\n\nconst n = (x: number) => x.toLocaleString('en-US')\nconst rowList = (rows: readonly number[], total: number) =>\n rows.map((r) => `#${r}`).join(', ') + (total > rows.length ? ', …' : '')\nconst uniqueFixes = (unique: readonly string[], total: number) =>\n unique.map((f) => `rowKey: '${f}' (unique in all ${n(total)} rows)`)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const rowKeyMessages: DiagnosticMessages<'DK_DUPLICATE_ROW_KEY' | 'DK_MISSING_ROW_KEY'> = {\n DK_DUPLICATE_ROW_KEY: {\n problem: (d) => {\n const head =\n d.path === undefined\n ? 'the rowKey function returns repeated keys'\n : `rowKey \"${d.path}\" is not unique`\n const more = d.groups > 1 ? `${n(d.groups)} values are repeated; ` : ''\n const what = d.path === undefined ? `key ${d.key}` : `${d.path} = ${d.key}`\n return `${head}: ${more}rows ${rowList(d.rows, d.shared)} share ${what}`\n },\n impact: (d) => {\n const shown = Math.min(d.shared - 1, 2)\n const keys = Array.from({ length: shown }, (_, i) => `${d.key}#${i + 1}`).join(', ')\n const rows = d.count === 1 ? '1 row renders' : `${n(d.count)} rows render`\n return `${rows} with fallback keys (${keys}${d.count > shown ? ', …' : ''}) — updates may hit the wrong row`\n },\n fix: (d) => {\n const fixes = uniqueFixes(d.unique, d.total)\n if (d.pair !== undefined && d.path !== undefined) {\n fixes.push(\n `rowKey: (row) => \\`\\${row.${d.path}}-\\${row.${d.pair}}\\` (unique in all ${n(d.total)} rows)`,\n )\n }\n if (fixes.length === 0) {\n fixes.push(\n `no field is unique across all ${n(d.total)} rows: add a unique id to each row, ` +\n 'or remove the duplicate rows at the source',\n )\n }\n if (d.path === undefined) fixes.push('or make the rowKey function return a unique value')\n return fixes\n },\n },\n DK_MISSING_ROW_KEY: {\n problem: (d) => {\n const rows = `rows ${rowList(d.rows, d.count)}`\n if (d.path === undefined) {\n return (\n `the rowKey function returned no usable key for ${d.count === 1 ? '1 row' : `${n(d.count)} rows`} ` +\n `(${rows}; the first is ${d.valueType})`\n )\n }\n const has = d.count === 1 ? '1 row has' : `${n(d.count)} rows have`\n return `${has} no usable key at \"${d.path}\" (${rows}; the first is ${d.valueType})`\n },\n impact: () =>\n \"those rows use the fallback key '#<index>', which changes when rows are added or removed\",\n fix: (d) => [\n ...uniqueFixes(d.unique, d.total),\n d.path === undefined\n ? 'return a string or a number for every row from the rowKey function'\n : `give every row a string or a number at \"${d.path}\"`,\n ],\n },\n}\n\n/** Codes owned by row-key resolution (§5.2, §8.3). */\nexport const rowKeyDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_DUPLICATE_ROW_KEY',\n level: 'error',\n redact: { key: 'rowKey' },\n where: (d) => ({ kind: 'row', index: d.rows[1] ?? d.rows[0] ?? 0, key: String(d.key) }),\n },\n (process.env.NODE_ENV !== \"production\") && rowKeyMessages.DK_DUPLICATE_ROW_KEY,\n ),\n defineDiagnostic(\n {\n code: 'DK_MISSING_ROW_KEY',\n level: 'error',\n where: (d) => ({ kind: 'row', index: d.rows[0] ?? 0 }),\n },\n (process.env.NODE_ENV !== \"production\") && rowKeyMessages.DK_MISSING_ROW_KEY,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/row-key-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_DUPLICATE_ROW_KEY: {\n /** The `rowKey` path; absent for a `rowKey` function. */\n path?: string\n /** The first repeated key value (hashed under `'safe'`). */\n key: string | number\n /** A sample of the rows sharing `key` (first few, in order; the first keeps its key). */\n rows: readonly number[]\n /** How many rows share `key`. */\n shared: number\n /** How many rows got a fallback key (all repeated values). */\n count: number\n /** How many distinct key values repeat. */\n groups: number\n /** `data.length`. */\n total: number\n /** Fields unique across all rows (computed by a scan). */\n unique: readonly string[]\n /** No unique field: a field that, with the `rowKey` path, makes a unique composite key. */\n pair?: string\n }\n DK_MISSING_ROW_KEY: {\n /** The `rowKey` path; absent for a `rowKey` function. */\n path?: string\n /** A sample of the rows without a usable key (first few, in order). */\n rows: readonly number[]\n count: number\n /** `data.length`. */\n total: number\n /** The type of the first unusable value: `undefined`, `null`, `object`, `number(NaN)`, … */\n valueType: string\n /** Fields unique across all rows (computed by a scan). */\n unique: readonly string[]\n }\n }\n}\n\nconst n = (x: number) => x.toLocaleString('en-US')\nconst rowList = (rows: readonly number[], total: number) =>\n rows.map((r) => `#${r}`).join(', ') + (total > rows.length ? ', …' : '')\nconst uniqueFixes = (unique: readonly string[], total: number) =>\n unique.map((f) => `rowKey: '${f}' (unique in all ${n(total)} rows)`)\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const rowKeyMessages: DiagnosticMessages<'DK_DUPLICATE_ROW_KEY' | 'DK_MISSING_ROW_KEY'> = {\n DK_DUPLICATE_ROW_KEY: {\n problem: (d) => {\n const head =\n d.path === undefined\n ? 'the rowKey function returns repeated keys'\n : `rowKey \"${d.path}\" is not unique`\n const more = d.groups > 1 ? `${n(d.groups)} values are repeated; ` : ''\n const what = d.path === undefined ? `key ${d.key}` : `${d.path} = ${d.key}`\n return `${head}: ${more}rows ${rowList(d.rows, d.shared)} share ${what}`\n },\n impact: (d) => {\n const shown = Math.min(d.shared - 1, 2)\n const keys = Array.from({ length: shown }, (_, i) => `${d.key}#${i + 1}`).join(', ')\n const rows = d.count === 1 ? '1 row renders' : `${n(d.count)} rows render`\n return `${rows} with fallback keys (${keys}${d.count > shown ? ', …' : ''}) — updates may hit the wrong row`\n },\n fix: (d) => {\n const fixes = uniqueFixes(d.unique, d.total)\n if (d.pair !== undefined && d.path !== undefined) {\n fixes.push(\n `rowKey: (row) => \\`\\${row.${d.path}}-\\${row.${d.pair}}\\` (unique in all ${n(d.total)} rows)`,\n )\n }\n if (fixes.length === 0) {\n fixes.push(\n `no field is unique across all ${n(d.total)} rows: add a unique id to each row, ` +\n 'or remove the duplicate rows at the source',\n )\n }\n if (d.path === undefined) fixes.push('or make the rowKey function return a unique value')\n return fixes\n },\n },\n DK_MISSING_ROW_KEY: {\n problem: (d) => {\n const rows = `rows ${rowList(d.rows, d.count)}`\n if (d.path === undefined) {\n return (\n `the rowKey function returned no usable key for ${d.count === 1 ? '1 row' : `${n(d.count)} rows`} ` +\n `(${rows}; the first is ${d.valueType})`\n )\n }\n const has = d.count === 1 ? '1 row has' : `${n(d.count)} rows have`\n return `${has} no usable key at \"${d.path}\" (${rows}; the first is ${d.valueType})`\n },\n impact: () =>\n \"those rows use the fallback key '#<index>', which changes when rows are added or removed\",\n fix: (d) => [\n ...uniqueFixes(d.unique, d.total),\n d.path === undefined\n ? 'return a string or a number for every row from the rowKey function'\n : `give every row a string or a number at \"${d.path}\"`,\n ],\n },\n}\n\n/** Codes owned by row-key resolution (§5.2, §8.3). */\nexport const rowKeyDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_DUPLICATE_ROW_KEY',\n level: 'error',\n redact: { key: 'rowKey' },\n where: (d) => ({ kind: 'row', index: d.rows[1] ?? d.rows[0] ?? 0, key: String(d.key) }),\n },\n (process.env.NODE_ENV !== \"production\") && rowKeyMessages.DK_DUPLICATE_ROW_KEY,\n ),\n defineDiagnostic(\n {\n code: 'DK_MISSING_ROW_KEY',\n level: 'error',\n where: (d) => ({ kind: 'row', index: d.rows[0] ?? 0 }),\n },\n (process.env.NODE_ENV !== \"production\") && rowKeyMessages.DK_MISSING_ROW_KEY,\n ),\n]\n"],"mappings":"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","names":[]}
|
package/dist/ingest/row-key.cjs
CHANGED
|
@@ -82,46 +82,49 @@ function keyReader(rowKey, onThrow) {
|
|
|
82
82
|
function scan(data, rowKey, read, emit) {
|
|
83
83
|
const taken = /* @__PURE__ */ new Map();
|
|
84
84
|
const suffix = /* @__PURE__ */ new Map();
|
|
85
|
-
let fallbacks;
|
|
86
|
-
const free = (base, from) => {
|
|
87
|
-
let s = from;
|
|
88
|
-
let k = `${base}#${s++}`;
|
|
89
|
-
while (taken.has(k)) k = `${base}#${s++}`;
|
|
90
|
-
return [k, s];
|
|
91
|
-
};
|
|
92
85
|
const missing = { count: 0, rows: [], valueType: "" };
|
|
93
86
|
const dup = { count: 0, key: void 0, rows: [], shared: 0 };
|
|
87
|
+
const pending = [];
|
|
94
88
|
for (let i = 0; i < data.length; i++) {
|
|
95
89
|
const raw = read(data[i], i);
|
|
96
|
-
|
|
90
|
+
const str = String(raw);
|
|
97
91
|
if (!usable(raw)) {
|
|
98
92
|
if (raw !== THREW) {
|
|
99
93
|
if (missing.count === 0) missing.valueType = typeOf(raw);
|
|
100
94
|
if (missing.rows.length < SAMPLE) missing.rows.push(i);
|
|
101
95
|
missing.count++;
|
|
102
96
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
} else if (taken.has(raw)) {
|
|
97
|
+
pending.push([i, `#${i}`]);
|
|
98
|
+
} else if (taken.has(str)) {
|
|
106
99
|
dup.count++;
|
|
107
100
|
if (dup.key === void 0) {
|
|
108
101
|
dup.key = raw;
|
|
109
|
-
dup.rows.push(taken.get(
|
|
102
|
+
dup.rows.push(taken.get(str));
|
|
110
103
|
dup.shared = 1;
|
|
111
104
|
}
|
|
112
|
-
if (
|
|
105
|
+
if (str === String(dup.key)) {
|
|
113
106
|
dup.shared++;
|
|
114
107
|
if (dup.rows.length < SAMPLE) dup.rows.push(i);
|
|
115
108
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
key = k;
|
|
109
|
+
suffix.set(str, 1);
|
|
110
|
+
pending.push([i, str]);
|
|
119
111
|
} else {
|
|
120
|
-
taken.set(
|
|
121
|
-
|
|
112
|
+
taken.set(str, i);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const groups = suffix.size;
|
|
116
|
+
let fallbacks;
|
|
117
|
+
for (const [i, base] of pending) {
|
|
118
|
+
let key = base;
|
|
119
|
+
if (taken.has(key)) {
|
|
120
|
+
let n = suffix.get(base) ?? 1;
|
|
121
|
+
do
|
|
122
|
+
key = `${base}#${n++}`;
|
|
123
|
+
while (taken.has(key));
|
|
124
|
+
suffix.set(base, n);
|
|
122
125
|
}
|
|
123
126
|
taken.set(key, i);
|
|
124
|
-
|
|
127
|
+
fallbacks ??= /* @__PURE__ */ new Map();
|
|
125
128
|
fallbacks.set(i, key);
|
|
126
129
|
}
|
|
127
130
|
if (dup.key !== void 0 || missing.count > 0) {
|
|
@@ -135,7 +138,7 @@ function scan(data, rowKey, read, emit) {
|
|
|
135
138
|
rows: dup.rows,
|
|
136
139
|
shared: dup.shared,
|
|
137
140
|
count: dup.count,
|
|
138
|
-
groups
|
|
141
|
+
groups,
|
|
139
142
|
total: data.length,
|
|
140
143
|
unique: found.unique,
|
|
141
144
|
...found.pair === void 0 ? {} : { pair: found.pair }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/row-key.ts"],"sourcesContent":["import { compilePath, getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit } from '../diagnostics/types'\nimport type { RowKey } from '../pipeline/row'\nimport { rowKeyDiagnostics } from './row-key-codes'\nimport { findUniqueFields } from './unique-fields'\n\nkeepDiagnostics(rowKeyDiagnostics)\n\n/** Rows listed in a diagnostic's `rows` sample. */\nconst SAMPLE = 5\n\n/** `(row, index) => key` for the rows the pipeline builds. */\nexport type KeyOf = (row: unknown, index: number) => RowKey\n\nconst usable = (k: unknown): k is RowKey =>\n typeof k === 'string' || (typeof k === 'number' && !Number.isNaN(k))\n\nconst THREW: unique symbol = Symbol('threw')\n\nconst typeOf = (v: unknown): string => {\n if (v === null) return 'null'\n if (Array.isArray(v)) return 'array'\n return typeof v === 'number' ? 'number(NaN)' : typeof v\n}\n\n/**\n * Resolves `rowKey` (§5.2) over **all** rows, once per (data, rowKey) reference, so keys do not\n * change with filtering, sorting or paging:\n *\n * - a repeated key: the first row keeps it, later rows get `key#1`, `key#2`, …\n * (`DK_DUPLICATE_ROW_KEY`, whose `fix` names fields that are unique across all rows);\n * - a missing / `null` / non-string-or-number key: `#index` (`DK_MISSING_ROW_KEY`);\n * - a throwing `rowKey` function: `#index`, passed to `onThrow` (reported by the runner as\n * `DK_CALLBACK_FAILED`, as in T09).\n *\n * Only the rows that need a fallback are remembered; the returned reader re-reads the key of the\n * (visible) rows it is asked for, so a clean data set keeps no per-row memory. Without `rowKey`,\n * the key is the row index.\n */\nexport function resolveRowKeys(\n data: readonly unknown[],\n rowKey: unknown,\n emit: Emit,\n onThrow: (index: number, error: unknown) => void,\n): KeyOf {\n const read = keyReader(rowKey, onThrow)\n if (read === undefined) return (_row, index) => index\n const fallbacks = scan(data, rowKey, read, emit)\n return (row, index) => {\n const f = fallbacks?.get(index)\n if (f !== undefined) return f\n const k = read(row, index)\n return usable(k) ? k : `#${index}`\n }\n}\n\ntype Read = (row: unknown, index: number) => unknown\n\nfunction keyReader(\n rowKey: unknown,\n onThrow: (index: number, error: unknown) => void,\n): Read | undefined {\n let read: Read\n if (typeof rowKey === 'function') {\n const fn = rowKey as (row: unknown) => unknown\n read = (row, index) => {\n try {\n return fn(row)\n } catch (e) {\n onThrow(index, e)\n return THREW\n }\n }\n } else if (typeof rowKey === 'string') {\n const path = compilePath(rowKey)\n let cur = 0\n let threw = false\n const onError = (e: unknown) => {\n threw = true\n onThrow(cur, e)\n }\n read = (row, index) => {\n cur = index\n const k = getValue(row, path, onError)\n if (!threw) return k\n threw = false\n return THREW\n }\n } else {\n return undefined\n }\n return read\n}\n\n/**\n * One pass over every row
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/row-key.ts"],"sourcesContent":["import { compilePath, getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit } from '../diagnostics/types'\nimport type { RowKey } from '../pipeline/row'\nimport { rowKeyDiagnostics } from './row-key-codes'\nimport { findUniqueFields } from './unique-fields'\n\nkeepDiagnostics(rowKeyDiagnostics)\n\n/** Rows listed in a diagnostic's `rows` sample. */\nconst SAMPLE = 5\n\n/** `(row, index) => key` for the rows the pipeline builds. */\nexport type KeyOf = (row: unknown, index: number) => RowKey\n\nconst usable = (k: unknown): k is RowKey =>\n typeof k === 'string' || (typeof k === 'number' && !Number.isNaN(k))\n\nconst THREW: unique symbol = Symbol('threw')\n\nconst typeOf = (v: unknown): string => {\n if (v === null) return 'null'\n if (Array.isArray(v)) return 'array'\n return typeof v === 'number' ? 'number(NaN)' : typeof v\n}\n\n/**\n * Resolves `rowKey` (§5.2) over **all** rows, once per (data, rowKey) reference, so keys do not\n * change with filtering, sorting or paging:\n *\n * - a repeated key: the first row keeps it, later rows get `key#1`, `key#2`, …\n * (`DK_DUPLICATE_ROW_KEY`, whose `fix` names fields that are unique across all rows). Keys are\n * compared as strings (`1` repeats `'1'`), as React keys and `explainRow` compare them;\n * - a missing / `null` / non-string-or-number key: `#index` (`DK_MISSING_ROW_KEY`);\n * - a throwing `rowKey` function: `#index`, passed to `onThrow` (reported by the runner as\n * `DK_CALLBACK_FAILED`, as in T09).\n *\n * Only the rows that need a fallback are remembered; the returned reader re-reads the key of the\n * (visible) rows it is asked for, so a clean data set keeps no per-row memory. Without `rowKey`,\n * the key is the row index.\n */\nexport function resolveRowKeys(\n data: readonly unknown[],\n rowKey: unknown,\n emit: Emit,\n onThrow: (index: number, error: unknown) => void,\n): KeyOf {\n const read = keyReader(rowKey, onThrow)\n if (read === undefined) return (_row, index) => index\n const fallbacks = scan(data, rowKey, read, emit)\n return (row, index) => {\n const f = fallbacks?.get(index)\n if (f !== undefined) return f\n const k = read(row, index)\n return usable(k) ? k : `#${index}`\n }\n}\n\ntype Read = (row: unknown, index: number) => unknown\n\nfunction keyReader(\n rowKey: unknown,\n onThrow: (index: number, error: unknown) => void,\n): Read | undefined {\n let read: Read\n if (typeof rowKey === 'function') {\n const fn = rowKey as (row: unknown) => unknown\n read = (row, index) => {\n try {\n return fn(row)\n } catch (e) {\n onThrow(index, e)\n return THREW\n }\n }\n } else if (typeof rowKey === 'string') {\n const path = compilePath(rowKey)\n let cur = 0\n let threw = false\n const onError = (e: unknown) => {\n threw = true\n onThrow(cur, e)\n }\n read = (row, index) => {\n cur = index\n const k = getValue(row, path, onError)\n if (!threw) return k\n threw = false\n return THREW\n }\n } else {\n return undefined\n }\n return read\n}\n\n/**\n * One pass over every row, then one over the rows that need a fallback key: returns those keys\n * and emits the key diagnostics. Kept apart from the returned reader so the scan's maps are not\n * captured by it.\n */\nfunction scan(\n data: readonly unknown[],\n rowKey: unknown,\n read: Read,\n emit: Emit,\n): Map<number, RowKey> | undefined {\n /** Every key handed out so far (raw keys and fallbacks), as a string → the row that holds it. */\n const taken = new Map<string, number>()\n /** Repeated raw key, as a string → the next `#n` to try. */\n const suffix = new Map<string, number>()\n const missing = { count: 0, rows: [] as number[], valueType: '' }\n const dup = { count: 0, key: undefined as RowKey | undefined, rows: [] as number[], shared: 0 }\n /** Rows that need a fallback: [index, the base it is built on (`#index` or the repeated key)]. */\n const pending: [number, string][] = []\n\n for (let i = 0; i < data.length; i++) {\n const raw = read(data[i], i)\n const str = String(raw)\n if (!usable(raw)) {\n if (raw !== THREW) {\n if (missing.count === 0) missing.valueType = typeOf(raw)\n if (missing.rows.length < SAMPLE) missing.rows.push(i)\n missing.count++\n }\n pending.push([i, `#${i}`])\n } else if (taken.has(str)) {\n dup.count++\n if (dup.key === undefined) {\n dup.key = raw\n dup.rows.push(taken.get(str) as number)\n dup.shared = 1\n }\n if (str === String(dup.key)) {\n dup.shared++\n if (dup.rows.length < SAMPLE) dup.rows.push(i)\n }\n suffix.set(str, 1)\n pending.push([i, str])\n } else {\n taken.set(str, i)\n }\n }\n const groups = suffix.size\n\n // Fallbacks only once every real key is taken, so none takes the key of a later row: `base#n`\n // for the first free `n` (a missing row's `#index` itself when free).\n let fallbacks: Map<number, RowKey> | undefined\n for (const [i, base] of pending) {\n let key = base\n if (taken.has(key)) {\n let n = suffix.get(base) ?? 1\n do key = `${base}#${n++}`\n while (taken.has(key))\n suffix.set(base, n)\n }\n taken.set(key, i)\n fallbacks ??= new Map()\n fallbacks.set(i, key)\n }\n\n if (dup.key !== undefined || missing.count > 0) {\n // Error path only: the fix is computed from the data (a scan per candidate field).\n const path = typeof rowKey === 'string' ? rowKey : undefined\n const at = path === undefined ? {} : { path }\n if (dup.key !== undefined) {\n const found = findUniqueFields(data, path)\n emit('DK_DUPLICATE_ROW_KEY', {\n ...at,\n key: dup.key,\n rows: dup.rows,\n shared: dup.shared,\n count: dup.count,\n groups,\n total: data.length,\n unique: found.unique,\n ...(found.pair === undefined ? {} : { pair: found.pair }),\n })\n }\n if (missing.count > 0) {\n emit('DK_MISSING_ROW_KEY', {\n ...at,\n rows: missing.rows,\n count: missing.count,\n total: data.length,\n valueType: missing.valueType,\n unique: findUniqueFields(data, path, undefined).unique,\n })\n }\n }\n\n return fallbacks\n}\n"],"mappings":"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","names":[]}
|
package/dist/ingest/row-key.js
CHANGED
|
@@ -58,46 +58,49 @@ function keyReader(rowKey, onThrow) {
|
|
|
58
58
|
function scan(data, rowKey, read, emit) {
|
|
59
59
|
const taken = /* @__PURE__ */ new Map();
|
|
60
60
|
const suffix = /* @__PURE__ */ new Map();
|
|
61
|
-
let fallbacks;
|
|
62
|
-
const free = (base, from) => {
|
|
63
|
-
let s = from;
|
|
64
|
-
let k = `${base}#${s++}`;
|
|
65
|
-
while (taken.has(k)) k = `${base}#${s++}`;
|
|
66
|
-
return [k, s];
|
|
67
|
-
};
|
|
68
61
|
const missing = { count: 0, rows: [], valueType: "" };
|
|
69
62
|
const dup = { count: 0, key: void 0, rows: [], shared: 0 };
|
|
63
|
+
const pending = [];
|
|
70
64
|
for (let i = 0; i < data.length; i++) {
|
|
71
65
|
const raw = read(data[i], i);
|
|
72
|
-
|
|
66
|
+
const str = String(raw);
|
|
73
67
|
if (!usable(raw)) {
|
|
74
68
|
if (raw !== THREW) {
|
|
75
69
|
if (missing.count === 0) missing.valueType = typeOf(raw);
|
|
76
70
|
if (missing.rows.length < SAMPLE) missing.rows.push(i);
|
|
77
71
|
missing.count++;
|
|
78
72
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
} else if (taken.has(raw)) {
|
|
73
|
+
pending.push([i, `#${i}`]);
|
|
74
|
+
} else if (taken.has(str)) {
|
|
82
75
|
dup.count++;
|
|
83
76
|
if (dup.key === void 0) {
|
|
84
77
|
dup.key = raw;
|
|
85
|
-
dup.rows.push(taken.get(
|
|
78
|
+
dup.rows.push(taken.get(str));
|
|
86
79
|
dup.shared = 1;
|
|
87
80
|
}
|
|
88
|
-
if (
|
|
81
|
+
if (str === String(dup.key)) {
|
|
89
82
|
dup.shared++;
|
|
90
83
|
if (dup.rows.length < SAMPLE) dup.rows.push(i);
|
|
91
84
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
key = k;
|
|
85
|
+
suffix.set(str, 1);
|
|
86
|
+
pending.push([i, str]);
|
|
95
87
|
} else {
|
|
96
|
-
taken.set(
|
|
97
|
-
|
|
88
|
+
taken.set(str, i);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const groups = suffix.size;
|
|
92
|
+
let fallbacks;
|
|
93
|
+
for (const [i, base] of pending) {
|
|
94
|
+
let key = base;
|
|
95
|
+
if (taken.has(key)) {
|
|
96
|
+
let n = suffix.get(base) ?? 1;
|
|
97
|
+
do
|
|
98
|
+
key = `${base}#${n++}`;
|
|
99
|
+
while (taken.has(key));
|
|
100
|
+
suffix.set(base, n);
|
|
98
101
|
}
|
|
99
102
|
taken.set(key, i);
|
|
100
|
-
|
|
103
|
+
fallbacks ??= /* @__PURE__ */ new Map();
|
|
101
104
|
fallbacks.set(i, key);
|
|
102
105
|
}
|
|
103
106
|
if (dup.key !== void 0 || missing.count > 0) {
|
|
@@ -111,7 +114,7 @@ function scan(data, rowKey, read, emit) {
|
|
|
111
114
|
rows: dup.rows,
|
|
112
115
|
shared: dup.shared,
|
|
113
116
|
count: dup.count,
|
|
114
|
-
groups
|
|
117
|
+
groups,
|
|
115
118
|
total: data.length,
|
|
116
119
|
unique: found.unique,
|
|
117
120
|
...found.pair === void 0 ? {} : { pair: found.pair }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/row-key.ts"],"sourcesContent":["import { compilePath, getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit } from '../diagnostics/types'\nimport type { RowKey } from '../pipeline/row'\nimport { rowKeyDiagnostics } from './row-key-codes'\nimport { findUniqueFields } from './unique-fields'\n\nkeepDiagnostics(rowKeyDiagnostics)\n\n/** Rows listed in a diagnostic's `rows` sample. */\nconst SAMPLE = 5\n\n/** `(row, index) => key` for the rows the pipeline builds. */\nexport type KeyOf = (row: unknown, index: number) => RowKey\n\nconst usable = (k: unknown): k is RowKey =>\n typeof k === 'string' || (typeof k === 'number' && !Number.isNaN(k))\n\nconst THREW: unique symbol = Symbol('threw')\n\nconst typeOf = (v: unknown): string => {\n if (v === null) return 'null'\n if (Array.isArray(v)) return 'array'\n return typeof v === 'number' ? 'number(NaN)' : typeof v\n}\n\n/**\n * Resolves `rowKey` (§5.2) over **all** rows, once per (data, rowKey) reference, so keys do not\n * change with filtering, sorting or paging:\n *\n * - a repeated key: the first row keeps it, later rows get `key#1`, `key#2`, …\n * (`DK_DUPLICATE_ROW_KEY`, whose `fix` names fields that are unique across all rows);\n * - a missing / `null` / non-string-or-number key: `#index` (`DK_MISSING_ROW_KEY`);\n * - a throwing `rowKey` function: `#index`, passed to `onThrow` (reported by the runner as\n * `DK_CALLBACK_FAILED`, as in T09).\n *\n * Only the rows that need a fallback are remembered; the returned reader re-reads the key of the\n * (visible) rows it is asked for, so a clean data set keeps no per-row memory. Without `rowKey`,\n * the key is the row index.\n */\nexport function resolveRowKeys(\n data: readonly unknown[],\n rowKey: unknown,\n emit: Emit,\n onThrow: (index: number, error: unknown) => void,\n): KeyOf {\n const read = keyReader(rowKey, onThrow)\n if (read === undefined) return (_row, index) => index\n const fallbacks = scan(data, rowKey, read, emit)\n return (row, index) => {\n const f = fallbacks?.get(index)\n if (f !== undefined) return f\n const k = read(row, index)\n return usable(k) ? k : `#${index}`\n }\n}\n\ntype Read = (row: unknown, index: number) => unknown\n\nfunction keyReader(\n rowKey: unknown,\n onThrow: (index: number, error: unknown) => void,\n): Read | undefined {\n let read: Read\n if (typeof rowKey === 'function') {\n const fn = rowKey as (row: unknown) => unknown\n read = (row, index) => {\n try {\n return fn(row)\n } catch (e) {\n onThrow(index, e)\n return THREW\n }\n }\n } else if (typeof rowKey === 'string') {\n const path = compilePath(rowKey)\n let cur = 0\n let threw = false\n const onError = (e: unknown) => {\n threw = true\n onThrow(cur, e)\n }\n read = (row, index) => {\n cur = index\n const k = getValue(row, path, onError)\n if (!threw) return k\n threw = false\n return THREW\n }\n } else {\n return undefined\n }\n return read\n}\n\n/**\n * One pass over every row
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/row-key.ts"],"sourcesContent":["import { compilePath, getValue } from '../column/get-value'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport type { Emit } from '../diagnostics/types'\nimport type { RowKey } from '../pipeline/row'\nimport { rowKeyDiagnostics } from './row-key-codes'\nimport { findUniqueFields } from './unique-fields'\n\nkeepDiagnostics(rowKeyDiagnostics)\n\n/** Rows listed in a diagnostic's `rows` sample. */\nconst SAMPLE = 5\n\n/** `(row, index) => key` for the rows the pipeline builds. */\nexport type KeyOf = (row: unknown, index: number) => RowKey\n\nconst usable = (k: unknown): k is RowKey =>\n typeof k === 'string' || (typeof k === 'number' && !Number.isNaN(k))\n\nconst THREW: unique symbol = Symbol('threw')\n\nconst typeOf = (v: unknown): string => {\n if (v === null) return 'null'\n if (Array.isArray(v)) return 'array'\n return typeof v === 'number' ? 'number(NaN)' : typeof v\n}\n\n/**\n * Resolves `rowKey` (§5.2) over **all** rows, once per (data, rowKey) reference, so keys do not\n * change with filtering, sorting or paging:\n *\n * - a repeated key: the first row keeps it, later rows get `key#1`, `key#2`, …\n * (`DK_DUPLICATE_ROW_KEY`, whose `fix` names fields that are unique across all rows). Keys are\n * compared as strings (`1` repeats `'1'`), as React keys and `explainRow` compare them;\n * - a missing / `null` / non-string-or-number key: `#index` (`DK_MISSING_ROW_KEY`);\n * - a throwing `rowKey` function: `#index`, passed to `onThrow` (reported by the runner as\n * `DK_CALLBACK_FAILED`, as in T09).\n *\n * Only the rows that need a fallback are remembered; the returned reader re-reads the key of the\n * (visible) rows it is asked for, so a clean data set keeps no per-row memory. Without `rowKey`,\n * the key is the row index.\n */\nexport function resolveRowKeys(\n data: readonly unknown[],\n rowKey: unknown,\n emit: Emit,\n onThrow: (index: number, error: unknown) => void,\n): KeyOf {\n const read = keyReader(rowKey, onThrow)\n if (read === undefined) return (_row, index) => index\n const fallbacks = scan(data, rowKey, read, emit)\n return (row, index) => {\n const f = fallbacks?.get(index)\n if (f !== undefined) return f\n const k = read(row, index)\n return usable(k) ? k : `#${index}`\n }\n}\n\ntype Read = (row: unknown, index: number) => unknown\n\nfunction keyReader(\n rowKey: unknown,\n onThrow: (index: number, error: unknown) => void,\n): Read | undefined {\n let read: Read\n if (typeof rowKey === 'function') {\n const fn = rowKey as (row: unknown) => unknown\n read = (row, index) => {\n try {\n return fn(row)\n } catch (e) {\n onThrow(index, e)\n return THREW\n }\n }\n } else if (typeof rowKey === 'string') {\n const path = compilePath(rowKey)\n let cur = 0\n let threw = false\n const onError = (e: unknown) => {\n threw = true\n onThrow(cur, e)\n }\n read = (row, index) => {\n cur = index\n const k = getValue(row, path, onError)\n if (!threw) return k\n threw = false\n return THREW\n }\n } else {\n return undefined\n }\n return read\n}\n\n/**\n * One pass over every row, then one over the rows that need a fallback key: returns those keys\n * and emits the key diagnostics. Kept apart from the returned reader so the scan's maps are not\n * captured by it.\n */\nfunction scan(\n data: readonly unknown[],\n rowKey: unknown,\n read: Read,\n emit: Emit,\n): Map<number, RowKey> | undefined {\n /** Every key handed out so far (raw keys and fallbacks), as a string → the row that holds it. */\n const taken = new Map<string, number>()\n /** Repeated raw key, as a string → the next `#n` to try. */\n const suffix = new Map<string, number>()\n const missing = { count: 0, rows: [] as number[], valueType: '' }\n const dup = { count: 0, key: undefined as RowKey | undefined, rows: [] as number[], shared: 0 }\n /** Rows that need a fallback: [index, the base it is built on (`#index` or the repeated key)]. */\n const pending: [number, string][] = []\n\n for (let i = 0; i < data.length; i++) {\n const raw = read(data[i], i)\n const str = String(raw)\n if (!usable(raw)) {\n if (raw !== THREW) {\n if (missing.count === 0) missing.valueType = typeOf(raw)\n if (missing.rows.length < SAMPLE) missing.rows.push(i)\n missing.count++\n }\n pending.push([i, `#${i}`])\n } else if (taken.has(str)) {\n dup.count++\n if (dup.key === undefined) {\n dup.key = raw\n dup.rows.push(taken.get(str) as number)\n dup.shared = 1\n }\n if (str === String(dup.key)) {\n dup.shared++\n if (dup.rows.length < SAMPLE) dup.rows.push(i)\n }\n suffix.set(str, 1)\n pending.push([i, str])\n } else {\n taken.set(str, i)\n }\n }\n const groups = suffix.size\n\n // Fallbacks only once every real key is taken, so none takes the key of a later row: `base#n`\n // for the first free `n` (a missing row's `#index` itself when free).\n let fallbacks: Map<number, RowKey> | undefined\n for (const [i, base] of pending) {\n let key = base\n if (taken.has(key)) {\n let n = suffix.get(base) ?? 1\n do key = `${base}#${n++}`\n while (taken.has(key))\n suffix.set(base, n)\n }\n taken.set(key, i)\n fallbacks ??= new Map()\n fallbacks.set(i, key)\n }\n\n if (dup.key !== undefined || missing.count > 0) {\n // Error path only: the fix is computed from the data (a scan per candidate field).\n const path = typeof rowKey === 'string' ? rowKey : undefined\n const at = path === undefined ? {} : { path }\n if (dup.key !== undefined) {\n const found = findUniqueFields(data, path)\n emit('DK_DUPLICATE_ROW_KEY', {\n ...at,\n key: dup.key,\n rows: dup.rows,\n shared: dup.shared,\n count: dup.count,\n groups,\n total: data.length,\n unique: found.unique,\n ...(found.pair === undefined ? {} : { pair: found.pair }),\n })\n }\n if (missing.count > 0) {\n emit('DK_MISSING_ROW_KEY', {\n ...at,\n rows: missing.rows,\n count: missing.count,\n total: data.length,\n valueType: missing.valueType,\n unique: findUniqueFields(data, path, undefined).unique,\n })\n }\n }\n\n return fallbacks\n}\n"],"mappings":"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","names":[]}
|
|
@@ -25,6 +25,7 @@ __export(schema_codes_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(schema_codes_exports);
|
|
27
27
|
var import_catalog = require("../diagnostics/catalog.cjs");
|
|
28
|
+
var import_process_guard = require("../diagnostics/process-guard.cjs");
|
|
28
29
|
var rowList = (rows, count) => {
|
|
29
30
|
const list = rows.map((r) => `#${r}`).join(", ");
|
|
30
31
|
return count > rows.length ? `${list}, \u2026` : list;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/schema-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\n/** `options.invalidRows` (§5.1). */\nexport type InvalidRowsMode = 'drop' | 'flag' | 'throw'\n\n/** An issue path matched to a column (`DK_SCHEMA_INVALID_ROW.columns`). */\nexport interface SchemaIssueColumn {\n /** The issue path, dot-joined (`address.city`; `''` for the row itself). */\n readonly path: string\n /** The column whose key is or contains the path, if one does. */\n readonly column?: string\n /** That column's position in `options.columns`. */\n readonly index?: number\n /** Invalid rows with an issue at this path. */\n readonly count: number\n}\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_SCHEMA_INVALID_ROW: {\n mode: InvalidRowsMode\n /** Rows with issues. */\n count: number\n /** Rows validated. */\n total: number\n /** A sample of the invalid rows' indices in `options.data` (first few, in order). */\n rows: readonly number[]\n /** The first issue of each sampled row (redacted: `scrubSchemaIssue`). */\n issues: readonly unknown[]\n /** Issue paths with their column, most frequent first (at most a few). */\n columns: readonly SchemaIssueColumn[]\n }\n DK_SCHEMA_CRASHED: {\n mode: InvalidRowsMode\n /** Rows for which `validate` threw or rejected. */\n count: number\n rows: readonly number[]\n /** `error.name` of the first failure; the error itself is `context.cause`. */\n errorName?: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `${list}, …` : list\n}\n\nconst plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`\n\nconst handled = (mode: InvalidRowsMode, rows: string) => {\n switch (mode) {\n case 'drop':\n return `${rows} removed from the table (getInvalidRows() lists them)`\n case 'flag':\n return `${rows} kept with row.valid === false and row.issues (cell / invalidCell must handle them)`\n case 'throw':\n return 'DatakableSchemaError was thrown; the previous data was kept'\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const schemaMessages: DiagnosticMessages<'DK_SCHEMA_INVALID_ROW' | 'DK_SCHEMA_CRASHED'> = {\n DK_SCHEMA_INVALID_ROW: {\n problem: (d) =>\n `${d.count} of ${plural(d.total, 'row')} failed schema validation ` +\n `(rows ${rowList(d.rows, d.count)})`,\n impact: (d) => handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: (d) => {\n const out: string[] = []\n for (const c of d.columns) {\n const at = c.path === '' ? 'the row itself' : `\"${c.path}\"`\n const col =\n c.column === undefined\n ? 'no column shows it'\n : `column \"${c.column}\" (columns[${c.index}])`\n out.push(\n `${plural(c.count, 'row')} fail at ${at}, ${col}: fix the data source there, ` +\n `or relax the schema at ${at}`,\n )\n }\n if (d.mode === 'drop') {\n out.push(\n \"use invalidRows: 'flag' to keep and show the invalid rows instead of dropping them\",\n )\n }\n if (d.mode === 'throw') {\n out.push(\"use invalidRows: 'drop' or 'flag' to keep the table usable with invalid rows\")\n }\n out.push('inspect them with table.getInvalidRows() (index, raw value and issues per row)')\n return out\n },\n },\n DK_SCHEMA_CRASHED: {\n problem: (d) =>\n `the schema threw${d.errorName ? ` ${d.errorName}` : ''} instead of returning issues ` +\n `for ${plural(d.count, 'row')} (rows ${rowList(d.rows, d.count)})`,\n impact: (d) =>\n `each such row got a synthetic issue and was treated as invalid: ` +\n handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: () => [\n 'find the throwing refinement / transform in the schema: the original error is ' +\n 'context.cause (passed to onDiagnostic)',\n 'make custom checks return an issue (e.g. ctx.addIssue / a refine predicate) instead of ' +\n 'throwing on unexpected input',\n ],\n },\n}\n\n/** Codes owned by the schema ingest (§5.1, §8.3). */\nexport const schemaDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_INVALID_ROW',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n redact: { issues: 'schemaIssues' },\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_INVALID_ROW,\n ),\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_CRASHED',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_CRASHED,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/schema-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\n/** `options.invalidRows` (§5.1). */\nexport type InvalidRowsMode = 'drop' | 'flag' | 'throw'\n\n/** An issue path matched to a column (`DK_SCHEMA_INVALID_ROW.columns`). */\nexport interface SchemaIssueColumn {\n /** The issue path, dot-joined (`address.city`; `''` for the row itself). */\n readonly path: string\n /** The column whose key is or contains the path, if one does. */\n readonly column?: string\n /** That column's position in `options.columns`. */\n readonly index?: number\n /** Invalid rows with an issue at this path. */\n readonly count: number\n}\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_SCHEMA_INVALID_ROW: {\n mode: InvalidRowsMode\n /** Rows with issues. */\n count: number\n /** Rows validated. */\n total: number\n /** A sample of the invalid rows' indices in `options.data` (first few, in order). */\n rows: readonly number[]\n /** The first issue of each sampled row (redacted: `scrubSchemaIssue`). */\n issues: readonly unknown[]\n /** Issue paths with their column, most frequent first (at most a few). */\n columns: readonly SchemaIssueColumn[]\n }\n DK_SCHEMA_CRASHED: {\n mode: InvalidRowsMode\n /** Rows for which `validate` threw or rejected. */\n count: number\n rows: readonly number[]\n /** `error.name` of the first failure; the error itself is `context.cause`. */\n errorName?: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `${list}, …` : list\n}\n\nconst plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`\n\nconst handled = (mode: InvalidRowsMode, rows: string) => {\n switch (mode) {\n case 'drop':\n return `${rows} removed from the table (getInvalidRows() lists them)`\n case 'flag':\n return `${rows} kept with row.valid === false and row.issues (cell / invalidCell must handle them)`\n case 'throw':\n return 'DatakableSchemaError was thrown; the previous data was kept'\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const schemaMessages: DiagnosticMessages<'DK_SCHEMA_INVALID_ROW' | 'DK_SCHEMA_CRASHED'> = {\n DK_SCHEMA_INVALID_ROW: {\n problem: (d) =>\n `${d.count} of ${plural(d.total, 'row')} failed schema validation ` +\n `(rows ${rowList(d.rows, d.count)})`,\n impact: (d) => handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: (d) => {\n const out: string[] = []\n for (const c of d.columns) {\n const at = c.path === '' ? 'the row itself' : `\"${c.path}\"`\n const col =\n c.column === undefined\n ? 'no column shows it'\n : `column \"${c.column}\" (columns[${c.index}])`\n out.push(\n `${plural(c.count, 'row')} fail at ${at}, ${col}: fix the data source there, ` +\n `or relax the schema at ${at}`,\n )\n }\n if (d.mode === 'drop') {\n out.push(\n \"use invalidRows: 'flag' to keep and show the invalid rows instead of dropping them\",\n )\n }\n if (d.mode === 'throw') {\n out.push(\"use invalidRows: 'drop' or 'flag' to keep the table usable with invalid rows\")\n }\n out.push('inspect them with table.getInvalidRows() (index, raw value and issues per row)')\n return out\n },\n },\n DK_SCHEMA_CRASHED: {\n problem: (d) =>\n `the schema threw${d.errorName ? ` ${d.errorName}` : ''} instead of returning issues ` +\n `for ${plural(d.count, 'row')} (rows ${rowList(d.rows, d.count)})`,\n impact: (d) =>\n `each such row got a synthetic issue and was treated as invalid: ` +\n handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: () => [\n 'find the throwing refinement / transform in the schema: the original error is ' +\n 'context.cause (passed to onDiagnostic)',\n 'make custom checks return an issue (e.g. ctx.addIssue / a refine predicate) instead of ' +\n 'throwing on unexpected input',\n ],\n },\n}\n\n/** Codes owned by the schema ingest (§5.1, §8.3). */\nexport const schemaDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_INVALID_ROW',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n redact: { issues: 'schemaIssues' },\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_INVALID_ROW,\n ),\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_CRASHED',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_CRASHED,\n ),\n]\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0D;AAC1D,2BAAO;AA2CP,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,GAAG,IAAI,aAAQ;AAC9C;AAEA,IAAM,SAAS,CAAC,GAAW,QAAgB,GAAG,CAAC,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,GAAG;AAE3E,IAAM,UAAU,CAAC,MAAuB,SAAiB;AACvD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,GAAG,IAAI;AAAA,IAChB,KAAK;AACH,aAAO,GAAG,IAAI;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAGO,IAAM,iBAAoF;AAAA,EAC/F,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,GAAG,EAAE,KAAK,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC,mCAC9B,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IACnC,QAAQ,CAAC,MAAM,QAAQ,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,iBAAiB;AAAA,IACjF,KAAK,CAAC,MAAM;AACV,YAAM,MAAgB,CAAC;AACvB,iBAAW,KAAK,EAAE,SAAS;AACzB,cAAM,KAAK,EAAE,SAAS,KAAK,mBAAmB,IAAI,EAAE,IAAI;AACxD,cAAM,MACJ,EAAE,WAAW,SACT,uBACA,WAAW,EAAE,MAAM,cAAc,EAAE,KAAK;AAC9C,YAAI;AAAA,UACF,GAAG,OAAO,EAAE,OAAO,KAAK,CAAC,YAAY,EAAE,KAAK,GAAG,uDACnB,EAAE;AAAA,QAChC;AAAA,MACF;AACA,UAAI,EAAE,SAAS,QAAQ;AACrB,YAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,EAAE,SAAS,SAAS;AACtB,YAAI,KAAK,8EAA8E;AAAA,MACzF;AACA,UAAI,KAAK,gFAAgF;AACzF,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS,CAAC,MACR,mBAAmB,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,oCAChD,OAAO,EAAE,OAAO,KAAK,CAAC,UAAU,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IACjE,QAAQ,CAAC,MACP,qEACA,QAAQ,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,iBAAiB;AAAA,IACpE,KAAK,MAAM;AAAA,MACT;AAAA,MAEA;AAAA,IAEF;AAAA,EACF;AACF;AAGO,IAAM,oBAAoB;AAAA,MAC/B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,OAAO,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MAC/C,QAAQ,EAAE,QAAQ,eAAe;AAAA,IACnC;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AAAA,MACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,OAAO,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,IACjD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AACF;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/ingest/schema-codes.ts
|
|
2
2
|
import { defineDiagnostic } from "../diagnostics/catalog.js";
|
|
3
|
+
import "../diagnostics/process-guard.js";
|
|
3
4
|
var rowList = (rows, count) => {
|
|
4
5
|
const list = rows.map((r) => `#${r}`).join(", ");
|
|
5
6
|
return count > rows.length ? `${list}, \u2026` : list;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/schema-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\n\n/** `options.invalidRows` (§5.1). */\nexport type InvalidRowsMode = 'drop' | 'flag' | 'throw'\n\n/** An issue path matched to a column (`DK_SCHEMA_INVALID_ROW.columns`). */\nexport interface SchemaIssueColumn {\n /** The issue path, dot-joined (`address.city`; `''` for the row itself). */\n readonly path: string\n /** The column whose key is or contains the path, if one does. */\n readonly column?: string\n /** That column's position in `options.columns`. */\n readonly index?: number\n /** Invalid rows with an issue at this path. */\n readonly count: number\n}\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_SCHEMA_INVALID_ROW: {\n mode: InvalidRowsMode\n /** Rows with issues. */\n count: number\n /** Rows validated. */\n total: number\n /** A sample of the invalid rows' indices in `options.data` (first few, in order). */\n rows: readonly number[]\n /** The first issue of each sampled row (redacted: `scrubSchemaIssue`). */\n issues: readonly unknown[]\n /** Issue paths with their column, most frequent first (at most a few). */\n columns: readonly SchemaIssueColumn[]\n }\n DK_SCHEMA_CRASHED: {\n mode: InvalidRowsMode\n /** Rows for which `validate` threw or rejected. */\n count: number\n rows: readonly number[]\n /** `error.name` of the first failure; the error itself is `context.cause`. */\n errorName?: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `${list}, …` : list\n}\n\nconst plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`\n\nconst handled = (mode: InvalidRowsMode, rows: string) => {\n switch (mode) {\n case 'drop':\n return `${rows} removed from the table (getInvalidRows() lists them)`\n case 'flag':\n return `${rows} kept with row.valid === false and row.issues (cell / invalidCell must handle them)`\n case 'throw':\n return 'DatakableSchemaError was thrown; the previous data was kept'\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const schemaMessages: DiagnosticMessages<'DK_SCHEMA_INVALID_ROW' | 'DK_SCHEMA_CRASHED'> = {\n DK_SCHEMA_INVALID_ROW: {\n problem: (d) =>\n `${d.count} of ${plural(d.total, 'row')} failed schema validation ` +\n `(rows ${rowList(d.rows, d.count)})`,\n impact: (d) => handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: (d) => {\n const out: string[] = []\n for (const c of d.columns) {\n const at = c.path === '' ? 'the row itself' : `\"${c.path}\"`\n const col =\n c.column === undefined\n ? 'no column shows it'\n : `column \"${c.column}\" (columns[${c.index}])`\n out.push(\n `${plural(c.count, 'row')} fail at ${at}, ${col}: fix the data source there, ` +\n `or relax the schema at ${at}`,\n )\n }\n if (d.mode === 'drop') {\n out.push(\n \"use invalidRows: 'flag' to keep and show the invalid rows instead of dropping them\",\n )\n }\n if (d.mode === 'throw') {\n out.push(\"use invalidRows: 'drop' or 'flag' to keep the table usable with invalid rows\")\n }\n out.push('inspect them with table.getInvalidRows() (index, raw value and issues per row)')\n return out\n },\n },\n DK_SCHEMA_CRASHED: {\n problem: (d) =>\n `the schema threw${d.errorName ? ` ${d.errorName}` : ''} instead of returning issues ` +\n `for ${plural(d.count, 'row')} (rows ${rowList(d.rows, d.count)})`,\n impact: (d) =>\n `each such row got a synthetic issue and was treated as invalid: ` +\n handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: () => [\n 'find the throwing refinement / transform in the schema: the original error is ' +\n 'context.cause (passed to onDiagnostic)',\n 'make custom checks return an issue (e.g. ctx.addIssue / a refine predicate) instead of ' +\n 'throwing on unexpected input',\n ],\n },\n}\n\n/** Codes owned by the schema ingest (§5.1, §8.3). */\nexport const schemaDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_INVALID_ROW',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n redact: { issues: 'schemaIssues' },\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_INVALID_ROW,\n ),\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_CRASHED',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_CRASHED,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/schema-codes.ts"],"sourcesContent":["import { type DiagnosticMessages, defineDiagnostic } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\n\n/** `options.invalidRows` (§5.1). */\nexport type InvalidRowsMode = 'drop' | 'flag' | 'throw'\n\n/** An issue path matched to a column (`DK_SCHEMA_INVALID_ROW.columns`). */\nexport interface SchemaIssueColumn {\n /** The issue path, dot-joined (`address.city`; `''` for the row itself). */\n readonly path: string\n /** The column whose key is or contains the path, if one does. */\n readonly column?: string\n /** That column's position in `options.columns`. */\n readonly index?: number\n /** Invalid rows with an issue at this path. */\n readonly count: number\n}\n\ndeclare module '../diagnostics/catalog' {\n interface DiagnosticCatalog {\n DK_SCHEMA_INVALID_ROW: {\n mode: InvalidRowsMode\n /** Rows with issues. */\n count: number\n /** Rows validated. */\n total: number\n /** A sample of the invalid rows' indices in `options.data` (first few, in order). */\n rows: readonly number[]\n /** The first issue of each sampled row (redacted: `scrubSchemaIssue`). */\n issues: readonly unknown[]\n /** Issue paths with their column, most frequent first (at most a few). */\n columns: readonly SchemaIssueColumn[]\n }\n DK_SCHEMA_CRASHED: {\n mode: InvalidRowsMode\n /** Rows for which `validate` threw or rejected. */\n count: number\n rows: readonly number[]\n /** `error.name` of the first failure; the error itself is `context.cause`. */\n errorName?: string\n }\n }\n}\n\nconst rowList = (rows: readonly number[], count: number) => {\n const list = rows.map((r) => `#${r}`).join(', ')\n return count > rows.length ? `${list}, …` : list\n}\n\nconst plural = (n: number, one: string) => `${n} ${one}${n === 1 ? '' : 's'}`\n\nconst handled = (mode: InvalidRowsMode, rows: string) => {\n switch (mode) {\n case 'drop':\n return `${rows} removed from the table (getInvalidRows() lists them)`\n case 'flag':\n return `${rows} kept with row.valid === false and row.issues (cell / invalidCell must handle them)`\n case 'throw':\n return 'DatakableSchemaError was thrown; the previous data was kept'\n }\n}\n\n/** Message text (§8.2): development builds, or production via `@datakable/core/messages`. */\nexport const schemaMessages: DiagnosticMessages<'DK_SCHEMA_INVALID_ROW' | 'DK_SCHEMA_CRASHED'> = {\n DK_SCHEMA_INVALID_ROW: {\n problem: (d) =>\n `${d.count} of ${plural(d.total, 'row')} failed schema validation ` +\n `(rows ${rowList(d.rows, d.count)})`,\n impact: (d) => handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: (d) => {\n const out: string[] = []\n for (const c of d.columns) {\n const at = c.path === '' ? 'the row itself' : `\"${c.path}\"`\n const col =\n c.column === undefined\n ? 'no column shows it'\n : `column \"${c.column}\" (columns[${c.index}])`\n out.push(\n `${plural(c.count, 'row')} fail at ${at}, ${col}: fix the data source there, ` +\n `or relax the schema at ${at}`,\n )\n }\n if (d.mode === 'drop') {\n out.push(\n \"use invalidRows: 'flag' to keep and show the invalid rows instead of dropping them\",\n )\n }\n if (d.mode === 'throw') {\n out.push(\"use invalidRows: 'drop' or 'flag' to keep the table usable with invalid rows\")\n }\n out.push('inspect them with table.getInvalidRows() (index, raw value and issues per row)')\n return out\n },\n },\n DK_SCHEMA_CRASHED: {\n problem: (d) =>\n `the schema threw${d.errorName ? ` ${d.errorName}` : ''} instead of returning issues ` +\n `for ${plural(d.count, 'row')} (rows ${rowList(d.rows, d.count)})`,\n impact: (d) =>\n `each such row got a synthetic issue and was treated as invalid: ` +\n handled(d.mode, d.count === 1 ? 'that row was' : 'those rows were'),\n fix: () => [\n 'find the throwing refinement / transform in the schema: the original error is ' +\n 'context.cause (passed to onDiagnostic)',\n 'make custom checks return an issue (e.g. ctx.addIssue / a refine predicate) instead of ' +\n 'throwing on unexpected input',\n ],\n },\n}\n\n/** Codes owned by the schema ingest (§5.1, §8.3). */\nexport const schemaDiagnostics = [\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_INVALID_ROW',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n redact: { issues: 'schemaIssues' },\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_INVALID_ROW,\n ),\n defineDiagnostic(\n {\n code: 'DK_SCHEMA_CRASHED',\n level: 'error',\n where: () => ({ kind: 'option', path: 'schema' }),\n },\n (process.env.NODE_ENV !== \"production\") && schemaMessages.DK_SCHEMA_CRASHED,\n ),\n]\n"],"mappings":";AAAA,SAAkC,wBAAwB;AAC1D,OAAO;AA2CP,IAAM,UAAU,CAAC,MAAyB,UAAkB;AAC1D,QAAM,OAAO,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC/C,SAAO,QAAQ,KAAK,SAAS,GAAG,IAAI,aAAQ;AAC9C;AAEA,IAAM,SAAS,CAAC,GAAW,QAAgB,GAAG,CAAC,IAAI,GAAG,GAAG,MAAM,IAAI,KAAK,GAAG;AAE3E,IAAM,UAAU,CAAC,MAAuB,SAAiB;AACvD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,GAAG,IAAI;AAAA,IAChB,KAAK;AACH,aAAO,GAAG,IAAI;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAGO,IAAM,iBAAoF;AAAA,EAC/F,uBAAuB;AAAA,IACrB,SAAS,CAAC,MACR,GAAG,EAAE,KAAK,OAAO,OAAO,EAAE,OAAO,KAAK,CAAC,mCAC9B,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IACnC,QAAQ,CAAC,MAAM,QAAQ,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,iBAAiB;AAAA,IACjF,KAAK,CAAC,MAAM;AACV,YAAM,MAAgB,CAAC;AACvB,iBAAW,KAAK,EAAE,SAAS;AACzB,cAAM,KAAK,EAAE,SAAS,KAAK,mBAAmB,IAAI,EAAE,IAAI;AACxD,cAAM,MACJ,EAAE,WAAW,SACT,uBACA,WAAW,EAAE,MAAM,cAAc,EAAE,KAAK;AAC9C,YAAI;AAAA,UACF,GAAG,OAAO,EAAE,OAAO,KAAK,CAAC,YAAY,EAAE,KAAK,GAAG,uDACnB,EAAE;AAAA,QAChC;AAAA,MACF;AACA,UAAI,EAAE,SAAS,QAAQ;AACrB,YAAI;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,EAAE,SAAS,SAAS;AACtB,YAAI,KAAK,8EAA8E;AAAA,MACzF;AACA,UAAI,KAAK,gFAAgF;AACzF,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,SAAS,CAAC,MACR,mBAAmB,EAAE,YAAY,IAAI,EAAE,SAAS,KAAK,EAAE,oCAChD,OAAO,EAAE,OAAO,KAAK,CAAC,UAAU,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IACjE,QAAQ,CAAC,MACP,qEACA,QAAQ,EAAE,MAAM,EAAE,UAAU,IAAI,iBAAiB,iBAAiB;AAAA,IACpE,KAAK,MAAM;AAAA,MACT;AAAA,MAEA;AAAA,IAEF;AAAA,EACF;AACF;AAGO,IAAM,oBAAoB;AAAA,EAC/B;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,OAAO,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MAC/C,QAAQ,EAAE,QAAQ,eAAe;AAAA,IACnC;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AAAA,EACA;AAAA,IACE;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,OAAO,OAAO,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,IACjD;AAAA,IACC,QAAQ,IAAI,aAAa,gBAAiB,eAAe;AAAA,EAC5D;AACF;","names":[]}
|
|
@@ -53,8 +53,8 @@ function allDistinct(n, keyAt) {
|
|
|
53
53
|
const seen = /* @__PURE__ */ new Set();
|
|
54
54
|
for (let i = 0; i < n; i++) {
|
|
55
55
|
const v = keyAt(i);
|
|
56
|
-
if (!isKey(v) || seen.has(v)) return false;
|
|
57
|
-
seen.add(v);
|
|
56
|
+
if (!isKey(v) || seen.has(String(v))) return false;
|
|
57
|
+
seen.add(String(v));
|
|
58
58
|
}
|
|
59
59
|
return true;
|
|
60
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/unique-fields.ts"],"sourcesContent":["import { type CompiledPath, compilePath, getValue } from '../column/get-value'\n\n/** Depth cap of a candidate path (as `Path<T>`, §4.1). */\nconst MAX_DEPTH = 4\n/** Bound on the candidates checked (each is one pass over the data). */\nconst MAX_CANDIDATES = 64\n/** Unique fields reported in a `fix`. */\nconst MAX_UNIQUE = 3\n\nexport interface UniqueFields {\n /** Paths whose value is a string / number in every row, never repeated (row-0 order). */\n unique: string[]\n /** With no unique field: a field `f` for which `${row.<rowKey>}-${row.<f>}` is unique. */\n pair?: string\n}\n\nconst isKey = (v: unknown): v is string | number =>\n typeof v === 'string' || (typeof v === 'number' && !Number.isNaN(v))\n\nconst isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date)\n\n/**\n * Primitive leaf paths of `row` (depth ≤ 4; arrays and Dates are not walked). A field must be in\n * every row to be unique, so row 0's paths are the only candidates.\n */\nfunction candidates(row: unknown, skip: string | undefined): string[] {\n const out: string[] = []\n const walk = (obj: Record<string, unknown>, prefix: string, depth: number) => {\n for (const k of Object.keys(obj)) {\n if (out.length >= MAX_CANDIDATES) return\n const path = prefix ? `${prefix}.${k}` : k\n let v: unknown\n try {\n v = obj[k]\n } catch {\n continue\n }\n if (isKey(v)) {\n if (path !== skip) out.push(path)\n } else if (isPlain(v) && depth < MAX_DEPTH) walk(v, path, depth + 1)\n }\n }\n if (isPlain(row)) walk(row, '', 1)\n return out\n}\n\n/** `true` when `keyAt(i)` is a usable key for every row and never repeats. */\nfunction allDistinct(n: number, keyAt: (i: number) => unknown): boolean {\n const seen = new Set<
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/unique-fields.ts"],"sourcesContent":["import { type CompiledPath, compilePath, getValue } from '../column/get-value'\n\n/** Depth cap of a candidate path (as `Path<T>`, §4.1). */\nconst MAX_DEPTH = 4\n/** Bound on the candidates checked (each is one pass over the data). */\nconst MAX_CANDIDATES = 64\n/** Unique fields reported in a `fix`. */\nconst MAX_UNIQUE = 3\n\nexport interface UniqueFields {\n /** Paths whose value is a string / number in every row, never repeated (row-0 order). */\n unique: string[]\n /** With no unique field: a field `f` for which `${row.<rowKey>}-${row.<f>}` is unique. */\n pair?: string\n}\n\nconst isKey = (v: unknown): v is string | number =>\n typeof v === 'string' || (typeof v === 'number' && !Number.isNaN(v))\n\nconst isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date)\n\n/**\n * Primitive leaf paths of `row` (depth ≤ 4; arrays and Dates are not walked). A field must be in\n * every row to be unique, so row 0's paths are the only candidates.\n */\nfunction candidates(row: unknown, skip: string | undefined): string[] {\n const out: string[] = []\n const walk = (obj: Record<string, unknown>, prefix: string, depth: number) => {\n for (const k of Object.keys(obj)) {\n if (out.length >= MAX_CANDIDATES) return\n const path = prefix ? `${prefix}.${k}` : k\n let v: unknown\n try {\n v = obj[k]\n } catch {\n continue\n }\n if (isKey(v)) {\n if (path !== skip) out.push(path)\n } else if (isPlain(v) && depth < MAX_DEPTH) walk(v, path, depth + 1)\n }\n }\n if (isPlain(row)) walk(row, '', 1)\n return out\n}\n\n/** `true` when `keyAt(i)` is a usable key for every row and never repeats (as a string). */\nfunction allDistinct(n: number, keyAt: (i: number) => unknown): boolean {\n const seen = new Set<string>()\n for (let i = 0; i < n; i++) {\n const v = keyAt(i)\n if (!isKey(v) || seen.has(String(v))) return false\n seen.add(String(v))\n }\n return true\n}\n\n/**\n * The fields that would make a good `rowKey`, computed by scanning every row (§5.2: the `fix` of\n * `DK_DUPLICATE_ROW_KEY` / `DK_MISSING_ROW_KEY`). Runs only when a key problem was found. With\n * `pairWith` (the `rowKey` path) and no unique field, also looks for a composite key, checked with\n * exactly the string the suggested `(row) => \\`${row.a}-${row.b}\\`` builds.\n */\nexport function findUniqueFields(\n data: readonly unknown[],\n rowKeyPath: string | undefined,\n pairWith = rowKeyPath,\n): UniqueFields {\n if (data.length === 0) return { unique: [] }\n const paths = candidates(data[0], rowKeyPath)\n const compiled = paths.map(compilePath)\n const at = (path: CompiledPath) => (i: number) => getValue(data[i], path)\n const unique: string[] = []\n for (let c = 0; c < paths.length && unique.length < MAX_UNIQUE; c++) {\n if (allDistinct(data.length, at(compiled[c] as CompiledPath))) unique.push(paths[c] as string)\n }\n if (unique.length > 0 || pairWith === undefined) return { unique }\n const key = at(compilePath(pairWith))\n for (let c = 0; c < paths.length; c++) {\n const other = at(compiled[c] as CompiledPath)\n const ok = allDistinct(data.length, (i) => {\n const a = key(i)\n const b = other(i)\n return isKey(a) && isKey(b) ? `${a}-${b}` : undefined\n })\n if (ok) return { unique, pair: paths[c] as string }\n }\n return { unique }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAyD;AAGzD,IAAM,YAAY;AAElB,IAAM,iBAAiB;AAEvB,IAAM,aAAa;AASnB,IAAM,QAAQ,CAAC,MACb,OAAO,MAAM,YAAa,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,CAAC;AAEpE,IAAM,UAAU,CAAC,MACf,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,aAAa;AAM7E,SAAS,WAAW,KAAc,MAAoC;AACpE,QAAM,MAAgB,CAAC;AACvB,QAAM,OAAO,CAAC,KAA8B,QAAgB,UAAkB;AAC5E,eAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,UAAI,IAAI,UAAU,eAAgB;AAClC,YAAM,OAAO,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK;AACzC,UAAI;AACJ,UAAI;AACF,YAAI,IAAI,CAAC;AAAA,MACX,QAAQ;AACN;AAAA,MACF;AACA,UAAI,MAAM,CAAC,GAAG;AACZ,YAAI,SAAS,KAAM,KAAI,KAAK,IAAI;AAAA,MAClC,WAAW,QAAQ,CAAC,KAAK,QAAQ,UAAW,MAAK,GAAG,MAAM,QAAQ,CAAC;AAAA,IACrE;AAAA,EACF;AACA,MAAI,QAAQ,GAAG,EAAG,MAAK,KAAK,IAAI,CAAC;AACjC,SAAO;AACT;AAGA,SAAS,YAAY,GAAW,OAAwC;AACtE,QAAM,OAAO,oBAAI,IAAY;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,IAAI,MAAM,CAAC;AACjB,QAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,OAAO,CAAC,CAAC,EAAG,QAAO;AAC7C,SAAK,IAAI,OAAO,CAAC,CAAC;AAAA,EACpB;AACA,SAAO;AACT;AAQO,SAAS,iBACd,MACA,YACA,WAAW,YACG;AACd,MAAI,KAAK,WAAW,EAAG,QAAO,EAAE,QAAQ,CAAC,EAAE;AAC3C,QAAM,QAAQ,WAAW,KAAK,CAAC,GAAG,UAAU;AAC5C,QAAM,WAAW,MAAM,IAAI,4BAAW;AACtC,QAAM,KAAK,CAAC,SAAuB,CAAC,UAAc,2BAAS,KAAK,CAAC,GAAG,IAAI;AACxE,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,MAAM,UAAU,OAAO,SAAS,YAAY,KAAK;AACnE,QAAI,YAAY,KAAK,QAAQ,GAAG,SAAS,CAAC,CAAiB,CAAC,EAAG,QAAO,KAAK,MAAM,CAAC,CAAW;AAAA,EAC/F;AACA,MAAI,OAAO,SAAS,KAAK,aAAa,OAAW,QAAO,EAAE,OAAO;AACjE,QAAM,MAAM,OAAG,8BAAY,QAAQ,CAAC;AACpC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,QAAQ,GAAG,SAAS,CAAC,CAAiB;AAC5C,UAAM,KAAK,YAAY,KAAK,QAAQ,CAAC,MAAM;AACzC,YAAM,IAAI,IAAI,CAAC;AACf,YAAM,IAAI,MAAM,CAAC;AACjB,aAAO,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK;AAAA,IAC9C,CAAC;AACD,QAAI,GAAI,QAAO,EAAE,QAAQ,MAAM,MAAM,CAAC,EAAY;AAAA,EACpD;AACA,SAAO,EAAE,OAAO;AAClB;","names":[]}
|
|
@@ -29,8 +29,8 @@ function allDistinct(n, keyAt) {
|
|
|
29
29
|
const seen = /* @__PURE__ */ new Set();
|
|
30
30
|
for (let i = 0; i < n; i++) {
|
|
31
31
|
const v = keyAt(i);
|
|
32
|
-
if (!isKey(v) || seen.has(v)) return false;
|
|
33
|
-
seen.add(v);
|
|
32
|
+
if (!isKey(v) || seen.has(String(v))) return false;
|
|
33
|
+
seen.add(String(v));
|
|
34
34
|
}
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ingest/unique-fields.ts"],"sourcesContent":["import { type CompiledPath, compilePath, getValue } from '../column/get-value'\n\n/** Depth cap of a candidate path (as `Path<T>`, §4.1). */\nconst MAX_DEPTH = 4\n/** Bound on the candidates checked (each is one pass over the data). */\nconst MAX_CANDIDATES = 64\n/** Unique fields reported in a `fix`. */\nconst MAX_UNIQUE = 3\n\nexport interface UniqueFields {\n /** Paths whose value is a string / number in every row, never repeated (row-0 order). */\n unique: string[]\n /** With no unique field: a field `f` for which `${row.<rowKey>}-${row.<f>}` is unique. */\n pair?: string\n}\n\nconst isKey = (v: unknown): v is string | number =>\n typeof v === 'string' || (typeof v === 'number' && !Number.isNaN(v))\n\nconst isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date)\n\n/**\n * Primitive leaf paths of `row` (depth ≤ 4; arrays and Dates are not walked). A field must be in\n * every row to be unique, so row 0's paths are the only candidates.\n */\nfunction candidates(row: unknown, skip: string | undefined): string[] {\n const out: string[] = []\n const walk = (obj: Record<string, unknown>, prefix: string, depth: number) => {\n for (const k of Object.keys(obj)) {\n if (out.length >= MAX_CANDIDATES) return\n const path = prefix ? `${prefix}.${k}` : k\n let v: unknown\n try {\n v = obj[k]\n } catch {\n continue\n }\n if (isKey(v)) {\n if (path !== skip) out.push(path)\n } else if (isPlain(v) && depth < MAX_DEPTH) walk(v, path, depth + 1)\n }\n }\n if (isPlain(row)) walk(row, '', 1)\n return out\n}\n\n/** `true` when `keyAt(i)` is a usable key for every row and never repeats. */\nfunction allDistinct(n: number, keyAt: (i: number) => unknown): boolean {\n const seen = new Set<
|
|
1
|
+
{"version":3,"sources":["../../src/ingest/unique-fields.ts"],"sourcesContent":["import { type CompiledPath, compilePath, getValue } from '../column/get-value'\n\n/** Depth cap of a candidate path (as `Path<T>`, §4.1). */\nconst MAX_DEPTH = 4\n/** Bound on the candidates checked (each is one pass over the data). */\nconst MAX_CANDIDATES = 64\n/** Unique fields reported in a `fix`. */\nconst MAX_UNIQUE = 3\n\nexport interface UniqueFields {\n /** Paths whose value is a string / number in every row, never repeated (row-0 order). */\n unique: string[]\n /** With no unique field: a field `f` for which `${row.<rowKey>}-${row.<f>}` is unique. */\n pair?: string\n}\n\nconst isKey = (v: unknown): v is string | number =>\n typeof v === 'string' || (typeof v === 'number' && !Number.isNaN(v))\n\nconst isPlain = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Date)\n\n/**\n * Primitive leaf paths of `row` (depth ≤ 4; arrays and Dates are not walked). A field must be in\n * every row to be unique, so row 0's paths are the only candidates.\n */\nfunction candidates(row: unknown, skip: string | undefined): string[] {\n const out: string[] = []\n const walk = (obj: Record<string, unknown>, prefix: string, depth: number) => {\n for (const k of Object.keys(obj)) {\n if (out.length >= MAX_CANDIDATES) return\n const path = prefix ? `${prefix}.${k}` : k\n let v: unknown\n try {\n v = obj[k]\n } catch {\n continue\n }\n if (isKey(v)) {\n if (path !== skip) out.push(path)\n } else if (isPlain(v) && depth < MAX_DEPTH) walk(v, path, depth + 1)\n }\n }\n if (isPlain(row)) walk(row, '', 1)\n return out\n}\n\n/** `true` when `keyAt(i)` is a usable key for every row and never repeats (as a string). */\nfunction allDistinct(n: number, keyAt: (i: number) => unknown): boolean {\n const seen = new Set<string>()\n for (let i = 0; i < n; i++) {\n const v = keyAt(i)\n if (!isKey(v) || seen.has(String(v))) return false\n seen.add(String(v))\n }\n return true\n}\n\n/**\n * The fields that would make a good `rowKey`, computed by scanning every row (§5.2: the `fix` of\n * `DK_DUPLICATE_ROW_KEY` / `DK_MISSING_ROW_KEY`). Runs only when a key problem was found. With\n * `pairWith` (the `rowKey` path) and no unique field, also looks for a composite key, checked with\n * exactly the string the suggested `(row) => \\`${row.a}-${row.b}\\`` builds.\n */\nexport function findUniqueFields(\n data: readonly unknown[],\n rowKeyPath: string | undefined,\n pairWith = rowKeyPath,\n): UniqueFields {\n if (data.length === 0) return { unique: [] }\n const paths = candidates(data[0], rowKeyPath)\n const compiled = paths.map(compilePath)\n const at = (path: CompiledPath) => (i: number) => getValue(data[i], path)\n const unique: string[] = []\n for (let c = 0; c < paths.length && unique.length < MAX_UNIQUE; c++) {\n if (allDistinct(data.length, at(compiled[c] as CompiledPath))) unique.push(paths[c] as string)\n }\n if (unique.length > 0 || pairWith === undefined) return { unique }\n const key = at(compilePath(pairWith))\n for (let c = 0; c < paths.length; c++) {\n const other = at(compiled[c] as CompiledPath)\n const ok = allDistinct(data.length, (i) => {\n const a = key(i)\n const b = other(i)\n return isKey(a) && isKey(b) ? `${a}-${b}` : undefined\n })\n if (ok) return { unique, pair: paths[c] as string }\n }\n return { unique }\n}\n"],"mappings":";AAAA,SAA4B,aAAa,gBAAgB;AAGzD,IAAM,YAAY;AAElB,IAAM,iBAAiB;AAEvB,IAAM,aAAa;AASnB,IAAM,QAAQ,CAAC,MACb,OAAO,MAAM,YAAa,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,CAAC;AAEpE,IAAM,UAAU,CAAC,MACf,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,aAAa;AAM7E,SAAS,WAAW,KAAc,MAAoC;AACpE,QAAM,MAAgB,CAAC;AACvB,QAAM,OAAO,CAAC,KAA8B,QAAgB,UAAkB;AAC5E,eAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,UAAI,IAAI,UAAU,eAAgB;AAClC,YAAM,OAAO,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK;AACzC,UAAI;AACJ,UAAI;AACF,YAAI,IAAI,CAAC;AAAA,MACX,QAAQ;AACN;AAAA,MACF;AACA,UAAI,MAAM,CAAC,GAAG;AACZ,YAAI,SAAS,KAAM,KAAI,KAAK,IAAI;AAAA,MAClC,WAAW,QAAQ,CAAC,KAAK,QAAQ,UAAW,MAAK,GAAG,MAAM,QAAQ,CAAC;AAAA,IACrE;AAAA,EACF;AACA,MAAI,QAAQ,GAAG,EAAG,MAAK,KAAK,IAAI,CAAC;AACjC,SAAO;AACT;AAGA,SAAS,YAAY,GAAW,OAAwC;AACtE,QAAM,OAAO,oBAAI,IAAY;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,IAAI,MAAM,CAAC;AACjB,QAAI,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,OAAO,CAAC,CAAC,EAAG,QAAO;AAC7C,SAAK,IAAI,OAAO,CAAC,CAAC;AAAA,EACpB;AACA,SAAO;AACT;AAQO,SAAS,iBACd,MACA,YACA,WAAW,YACG;AACd,MAAI,KAAK,WAAW,EAAG,QAAO,EAAE,QAAQ,CAAC,EAAE;AAC3C,QAAM,QAAQ,WAAW,KAAK,CAAC,GAAG,UAAU;AAC5C,QAAM,WAAW,MAAM,IAAI,WAAW;AACtC,QAAM,KAAK,CAAC,SAAuB,CAAC,MAAc,SAAS,KAAK,CAAC,GAAG,IAAI;AACxE,QAAM,SAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,MAAM,UAAU,OAAO,SAAS,YAAY,KAAK;AACnE,QAAI,YAAY,KAAK,QAAQ,GAAG,SAAS,CAAC,CAAiB,CAAC,EAAG,QAAO,KAAK,MAAM,CAAC,CAAW;AAAA,EAC/F;AACA,MAAI,OAAO,SAAS,KAAK,aAAa,OAAW,QAAO,EAAE,OAAO;AACjE,QAAM,MAAM,GAAG,YAAY,QAAQ,CAAC;AACpC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,QAAQ,GAAG,SAAS,CAAC,CAAiB;AAC5C,UAAM,KAAK,YAAY,KAAK,QAAQ,CAAC,MAAM;AACzC,YAAM,IAAI,IAAI,CAAC;AACf,YAAM,IAAI,MAAM,CAAC;AACjB,aAAO,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK;AAAA,IAC9C,CAAC;AACD,QAAI,GAAI,QAAO,EAAE,QAAQ,MAAM,MAAM,CAAC,EAAY;AAAA,EACpD;AACA,SAAO,EAAE,OAAO;AAClB;","names":[]}
|
|
@@ -25,6 +25,8 @@ __export(boundary_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(boundary_exports);
|
|
26
26
|
var import_build = require("../diagnostics/build.cjs");
|
|
27
27
|
var import_catalog = require("../diagnostics/catalog.cjs");
|
|
28
|
+
var import_process_guard = require("../diagnostics/process-guard.cjs");
|
|
29
|
+
var import_prose = require("../diagnostics/prose.cjs");
|
|
28
30
|
var import_redact = require("../diagnostics/redact.cjs");
|
|
29
31
|
var import_classify = require("./classify.cjs");
|
|
30
32
|
var import_codes = require("./codes.cjs");
|
|
@@ -40,7 +42,7 @@ function recover(ctx, error) {
|
|
|
40
42
|
if (!silenced.has(ctx.emit)) {
|
|
41
43
|
silenced.add(ctx.emit);
|
|
42
44
|
console.error(
|
|
43
|
-
`[DataKable] ${ctx.op} failed; ${fallback.describe}. Later failures are silent.`,
|
|
45
|
+
`[DataKable] ${ctx.op} failed; ${(0, import_prose.expandProse)(fallback.describe, process.env.NODE_ENV !== "production")}. Later failures are silent.`,
|
|
44
46
|
process.env.NODE_ENV !== "production" ? error : (0, import_redact.scrubError)(error)
|
|
45
47
|
);
|
|
46
48
|
}
|
|
@@ -69,7 +71,7 @@ function recover(ctx, error) {
|
|
|
69
71
|
"DK_INTERNAL",
|
|
70
72
|
{
|
|
71
73
|
op: ctx.op,
|
|
72
|
-
problem: "
|
|
74
|
+
problem: "escaped",
|
|
73
75
|
message: error.message,
|
|
74
76
|
...slot,
|
|
75
77
|
errorName: error.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/intercept/boundary.ts"],"sourcesContent":["import { DatakableError } from '../diagnostics/build'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport { scrubError } from '../diagnostics/redact'\nimport type { EmitOptions } from '../diagnostics/types'\nimport { type CallbackError, classifyError, errorName } from './classify'\nimport { boundaryDiagnostics } from './codes'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { FAILED, getFallback } from './fallbacks'\nimport type { OpName } from './operations'\n\nkeepDiagnostics(boundaryDiagnostics)\n\n/** Emitters (one per table) that already printed their silent `diagnostic:emit` failure. */\nconst silenced = new WeakSet<object>()\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\n/** catch → classify → emit → registry fallback (§3.4). */\nfunction recover(ctx: InterceptorContext, error: unknown): unknown {\n // Config errors, `strict: true` rethrows and core invariants are meant to reach the caller.\n if (error instanceof DatakableError) throw error\n ctx.meta.set(FAILED, error)\n const fallback = getFallback(ctx.op)\n if (fallback.silent) {\n if (!silenced.has(ctx.emit)) {\n silenced.add(ctx.emit)\n // Production prints the error name only: its message can embed row values (§8.2).\n console.error(\n `[DataKable] ${ctx.op} failed; ${fallback.describe}. Later failures are silent.`,\n (process.env.NODE_ENV !== \"production\") ? error : scrubError(error),\n )\n }\n return fallback.value(ctx as never)\n }\n const opts: EmitOptions = { run: ctx.run, trigger: ctx.trigger, phase: ctx.phase }\n const slot = ctx.where ? { slot: ctx.where } : {}\n const code = classifyError(error)\n if (code === 'DK_CALLBACK_FAILED') {\n const e = error as CallbackError\n const name = errorName(e.cause)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: e.slot,\n ...(e.op === undefined ? {} : { op: e.op }),\n ...(e.row === undefined ? {} : { rows: [e.row] }),\n count: 1,\n fallback: fallback.describe,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { ...opts, cause: e.cause },\n )\n } else if (code === 'DK_INTERNAL') {\n ctx.emit(\n 'DK_INTERNAL',\n {\n op: ctx.op,\n problem: '
|
|
1
|
+
{"version":3,"sources":["../../src/intercept/boundary.ts"],"sourcesContent":["import { DatakableError } from '../diagnostics/build'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\nimport { expandProse } from '../diagnostics/prose'\nimport { scrubError } from '../diagnostics/redact'\nimport type { EmitOptions } from '../diagnostics/types'\nimport { type CallbackError, classifyError, errorName } from './classify'\nimport { boundaryDiagnostics } from './codes'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { FAILED, getFallback } from './fallbacks'\nimport type { OpName } from './operations'\n\nkeepDiagnostics(boundaryDiagnostics)\n\n/** Emitters (one per table) that already printed their silent `diagnostic:emit` failure. */\nconst silenced = new WeakSet<object>()\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\n/** catch → classify → emit → registry fallback (§3.4). */\nfunction recover(ctx: InterceptorContext, error: unknown): unknown {\n // Config errors, `strict: true` rethrows and core invariants are meant to reach the caller.\n if (error instanceof DatakableError) throw error\n ctx.meta.set(FAILED, error)\n const fallback = getFallback(ctx.op)\n if (fallback.silent) {\n if (!silenced.has(ctx.emit)) {\n silenced.add(ctx.emit)\n // Production prints the error name only: its message can embed row values (§8.2).\n console.error(\n `[DataKable] ${ctx.op} failed; ${expandProse(fallback.describe, (process.env.NODE_ENV !== \"production\"))}. Later failures are silent.`,\n (process.env.NODE_ENV !== \"production\") ? error : scrubError(error),\n )\n }\n return fallback.value(ctx as never)\n }\n const opts: EmitOptions = { run: ctx.run, trigger: ctx.trigger, phase: ctx.phase }\n const slot = ctx.where ? { slot: ctx.where } : {}\n const code = classifyError(error)\n if (code === 'DK_CALLBACK_FAILED') {\n const e = error as CallbackError\n const name = errorName(e.cause)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: e.slot,\n ...(e.op === undefined ? {} : { op: e.op }),\n ...(e.row === undefined ? {} : { rows: [e.row] }),\n count: 1,\n fallback: fallback.describe,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { ...opts, cause: e.cause },\n )\n } else if (code === 'DK_INTERNAL') {\n ctx.emit(\n 'DK_INTERNAL',\n {\n op: ctx.op,\n problem: 'escaped',\n message: (error as Error).message,\n ...slot,\n errorName: (error as Error).name,\n fallback: fallback.describe,\n },\n { ...opts, cause: error },\n )\n } else {\n const name = errorName(error)\n ctx.emit(\n 'DK_UNKNOWN',\n {\n op: ctx.op,\n ...slot,\n ...(name === undefined ? {} : { errorName: name }),\n fallback: fallback.describe,\n },\n { ...opts, cause: error },\n )\n }\n return fallback.value(ctx as never)\n}\n\n/**\n * The outermost, non-removable interceptor (§3.4, §8.6). Install it once per table with\n * `runtime.installBoundary(errorBoundary)`. Reports through `ctx.emit`, so its sinks are the table's\n * diagnostics sinks. Hot-safe: the success path is one `try` and a thenable check, no allocation.\n */\nexport const errorBoundary: Interceptor<OpName> = {\n name: 'errorBoundary',\n on: '*',\n hot: true,\n intercept(ctx, next) {\n let out: unknown\n try {\n out = next()\n } catch (e) {\n return recover(ctx, e) as never\n }\n if (isThenable(out)) {\n return Promise.resolve(out).then(undefined, (e: unknown) => recover(ctx, e)) as never\n }\n return out as never\n },\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/intercept/boundary.ts
|
|
2
2
|
import { DatakableError } from "../diagnostics/build.js";
|
|
3
3
|
import { keepDiagnostics } from "../diagnostics/catalog.js";
|
|
4
|
+
import "../diagnostics/process-guard.js";
|
|
5
|
+
import { expandProse } from "../diagnostics/prose.js";
|
|
4
6
|
import { scrubError } from "../diagnostics/redact.js";
|
|
5
7
|
import { classifyError, errorName } from "./classify.js";
|
|
6
8
|
import { boundaryDiagnostics } from "./codes.js";
|
|
@@ -16,7 +18,7 @@ function recover(ctx, error) {
|
|
|
16
18
|
if (!silenced.has(ctx.emit)) {
|
|
17
19
|
silenced.add(ctx.emit);
|
|
18
20
|
console.error(
|
|
19
|
-
`[DataKable] ${ctx.op} failed; ${fallback.describe}. Later failures are silent.`,
|
|
21
|
+
`[DataKable] ${ctx.op} failed; ${expandProse(fallback.describe, process.env.NODE_ENV !== "production")}. Later failures are silent.`,
|
|
20
22
|
process.env.NODE_ENV !== "production" ? error : scrubError(error)
|
|
21
23
|
);
|
|
22
24
|
}
|
|
@@ -45,7 +47,7 @@ function recover(ctx, error) {
|
|
|
45
47
|
"DK_INTERNAL",
|
|
46
48
|
{
|
|
47
49
|
op: ctx.op,
|
|
48
|
-
problem: "
|
|
50
|
+
problem: "escaped",
|
|
49
51
|
message: error.message,
|
|
50
52
|
...slot,
|
|
51
53
|
errorName: error.name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/intercept/boundary.ts"],"sourcesContent":["import { DatakableError } from '../diagnostics/build'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport { scrubError } from '../diagnostics/redact'\nimport type { EmitOptions } from '../diagnostics/types'\nimport { type CallbackError, classifyError, errorName } from './classify'\nimport { boundaryDiagnostics } from './codes'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { FAILED, getFallback } from './fallbacks'\nimport type { OpName } from './operations'\n\nkeepDiagnostics(boundaryDiagnostics)\n\n/** Emitters (one per table) that already printed their silent `diagnostic:emit` failure. */\nconst silenced = new WeakSet<object>()\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\n/** catch → classify → emit → registry fallback (§3.4). */\nfunction recover(ctx: InterceptorContext, error: unknown): unknown {\n // Config errors, `strict: true` rethrows and core invariants are meant to reach the caller.\n if (error instanceof DatakableError) throw error\n ctx.meta.set(FAILED, error)\n const fallback = getFallback(ctx.op)\n if (fallback.silent) {\n if (!silenced.has(ctx.emit)) {\n silenced.add(ctx.emit)\n // Production prints the error name only: its message can embed row values (§8.2).\n console.error(\n `[DataKable] ${ctx.op} failed; ${fallback.describe}. Later failures are silent.`,\n (process.env.NODE_ENV !== \"production\") ? error : scrubError(error),\n )\n }\n return fallback.value(ctx as never)\n }\n const opts: EmitOptions = { run: ctx.run, trigger: ctx.trigger, phase: ctx.phase }\n const slot = ctx.where ? { slot: ctx.where } : {}\n const code = classifyError(error)\n if (code === 'DK_CALLBACK_FAILED') {\n const e = error as CallbackError\n const name = errorName(e.cause)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: e.slot,\n ...(e.op === undefined ? {} : { op: e.op }),\n ...(e.row === undefined ? {} : { rows: [e.row] }),\n count: 1,\n fallback: fallback.describe,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { ...opts, cause: e.cause },\n )\n } else if (code === 'DK_INTERNAL') {\n ctx.emit(\n 'DK_INTERNAL',\n {\n op: ctx.op,\n problem: '
|
|
1
|
+
{"version":3,"sources":["../../src/intercept/boundary.ts"],"sourcesContent":["import { DatakableError } from '../diagnostics/build'\nimport { keepDiagnostics } from '../diagnostics/catalog'\nimport '../diagnostics/process-guard'\nimport { expandProse } from '../diagnostics/prose'\nimport { scrubError } from '../diagnostics/redact'\nimport type { EmitOptions } from '../diagnostics/types'\nimport { type CallbackError, classifyError, errorName } from './classify'\nimport { boundaryDiagnostics } from './codes'\nimport type { InterceptorContext } from './context'\nimport type { Interceptor } from './define'\nimport { FAILED, getFallback } from './fallbacks'\nimport type { OpName } from './operations'\n\nkeepDiagnostics(boundaryDiagnostics)\n\n/** Emitters (one per table) that already printed their silent `diagnostic:emit` failure. */\nconst silenced = new WeakSet<object>()\n\nconst isThenable = (v: unknown): v is PromiseLike<unknown> =>\n v != null && typeof (v as { then?: unknown }).then === 'function'\n\n/** catch → classify → emit → registry fallback (§3.4). */\nfunction recover(ctx: InterceptorContext, error: unknown): unknown {\n // Config errors, `strict: true` rethrows and core invariants are meant to reach the caller.\n if (error instanceof DatakableError) throw error\n ctx.meta.set(FAILED, error)\n const fallback = getFallback(ctx.op)\n if (fallback.silent) {\n if (!silenced.has(ctx.emit)) {\n silenced.add(ctx.emit)\n // Production prints the error name only: its message can embed row values (§8.2).\n console.error(\n `[DataKable] ${ctx.op} failed; ${expandProse(fallback.describe, (process.env.NODE_ENV !== \"production\"))}. Later failures are silent.`,\n (process.env.NODE_ENV !== \"production\") ? error : scrubError(error),\n )\n }\n return fallback.value(ctx as never)\n }\n const opts: EmitOptions = { run: ctx.run, trigger: ctx.trigger, phase: ctx.phase }\n const slot = ctx.where ? { slot: ctx.where } : {}\n const code = classifyError(error)\n if (code === 'DK_CALLBACK_FAILED') {\n const e = error as CallbackError\n const name = errorName(e.cause)\n ctx.emit(\n 'DK_CALLBACK_FAILED',\n {\n slot: e.slot,\n ...(e.op === undefined ? {} : { op: e.op }),\n ...(e.row === undefined ? {} : { rows: [e.row] }),\n count: 1,\n fallback: fallback.describe,\n ...(name === undefined ? {} : { errorName: name }),\n },\n { ...opts, cause: e.cause },\n )\n } else if (code === 'DK_INTERNAL') {\n ctx.emit(\n 'DK_INTERNAL',\n {\n op: ctx.op,\n problem: 'escaped',\n message: (error as Error).message,\n ...slot,\n errorName: (error as Error).name,\n fallback: fallback.describe,\n },\n { ...opts, cause: error },\n )\n } else {\n const name = errorName(error)\n ctx.emit(\n 'DK_UNKNOWN',\n {\n op: ctx.op,\n ...slot,\n ...(name === undefined ? {} : { errorName: name }),\n fallback: fallback.describe,\n },\n { ...opts, cause: error },\n )\n }\n return fallback.value(ctx as never)\n}\n\n/**\n * The outermost, non-removable interceptor (§3.4, §8.6). Install it once per table with\n * `runtime.installBoundary(errorBoundary)`. Reports through `ctx.emit`, so its sinks are the table's\n * diagnostics sinks. Hot-safe: the success path is one `try` and a thenable check, no allocation.\n */\nexport const errorBoundary: Interceptor<OpName> = {\n name: 'errorBoundary',\n on: '*',\n hot: true,\n intercept(ctx, next) {\n let out: unknown\n try {\n out = next()\n } catch (e) {\n return recover(ctx, e) as never\n }\n if (isThenable(out)) {\n return Promise.resolve(out).then(undefined, (e: unknown) => recover(ctx, e)) as never\n }\n return out as never\n },\n}\n"],"mappings":";AAAA,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,OAAO;AACP,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAE3B,SAA6B,eAAe,iBAAiB;AAC7D,SAAS,2BAA2B;AAGpC,SAAS,QAAQ,mBAAmB;AAGpC,gBAAgB,mBAAmB;AAGnC,IAAM,WAAW,oBAAI,QAAgB;AAErC,IAAM,aAAa,CAAC,MAClB,KAAK,QAAQ,OAAQ,EAAyB,SAAS;AAGzD,SAAS,QAAQ,KAAyB,OAAyB;AAEjE,MAAI,iBAAiB,eAAgB,OAAM;AAC3C,MAAI,KAAK,IAAI,QAAQ,KAAK;AAC1B,QAAM,WAAW,YAAY,IAAI,EAAE;AACnC,MAAI,SAAS,QAAQ;AACnB,QAAI,CAAC,SAAS,IAAI,IAAI,IAAI,GAAG;AAC3B,eAAS,IAAI,IAAI,IAAI;AAErB,cAAQ;AAAA,QACN,eAAe,IAAI,EAAE,YAAY,YAAY,SAAS,UAAW,QAAQ,IAAI,aAAa,YAAa,CAAC;AAAA,QACvG,QAAQ,IAAI,aAAa,eAAgB,QAAQ,WAAW,KAAK;AAAA,MACpE;AAAA,IACF;AACA,WAAO,SAAS,MAAM,GAAY;AAAA,EACpC;AACA,QAAM,OAAoB,EAAE,KAAK,IAAI,KAAK,SAAS,IAAI,SAAS,OAAO,IAAI,MAAM;AACjF,QAAM,OAAO,IAAI,QAAQ,EAAE,MAAM,IAAI,MAAM,IAAI,CAAC;AAChD,QAAM,OAAO,cAAc,KAAK;AAChC,MAAI,SAAS,sBAAsB;AACjC,UAAM,IAAI;AACV,UAAM,OAAO,UAAU,EAAE,KAAK;AAC9B,QAAI;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM,EAAE;AAAA,QACR,GAAI,EAAE,OAAO,SAAY,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,QACzC,GAAI,EAAE,QAAQ,SAAY,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE;AAAA,QAC/C,OAAO;AAAA,QACP,UAAU,SAAS;AAAA,QACnB,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,MAClD;AAAA,MACA,EAAE,GAAG,MAAM,OAAO,EAAE,MAAM;AAAA,IAC5B;AAAA,EACF,WAAW,SAAS,eAAe;AACjC,QAAI;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI,IAAI;AAAA,QACR,SAAS;AAAA,QACT,SAAU,MAAgB;AAAA,QAC1B,GAAG;AAAA,QACH,WAAY,MAAgB;AAAA,QAC5B,UAAU,SAAS;AAAA,MACrB;AAAA,MACA,EAAE,GAAG,MAAM,OAAO,MAAM;AAAA,IAC1B;AAAA,EACF,OAAO;AACL,UAAM,OAAO,UAAU,KAAK;AAC5B,QAAI;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI,IAAI;AAAA,QACR,GAAG;AAAA,QACH,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK;AAAA,QAChD,UAAU,SAAS;AAAA,MACrB;AAAA,MACA,EAAE,GAAG,MAAM,OAAO,MAAM;AAAA,IAC1B;AAAA,EACF;AACA,SAAO,SAAS,MAAM,GAAY;AACpC;AAOO,IAAM,gBAAqC;AAAA,EAChD,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,UAAU,KAAK,MAAM;AACnB,QAAI;AACJ,QAAI;AACF,YAAM,KAAK;AAAA,IACb,SAAS,GAAG;AACV,aAAO,QAAQ,KAAK,CAAC;AAAA,IACvB;AACA,QAAI,WAAW,GAAG,GAAG;AACnB,aAAO,QAAQ,QAAQ,GAAG,EAAE,KAAK,QAAW,CAAC,MAAe,QAAQ,KAAK,CAAC,CAAC;AAAA,IAC7E;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|