jsonstat-io 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +200 -0
  3. package/dist/arrow/index.cjs +60 -0
  4. package/dist/arrow/index.cjs.map +1 -0
  5. package/dist/arrow/index.d.cts +125 -0
  6. package/dist/arrow/index.d.ts +125 -0
  7. package/dist/arrow/index.js +3 -0
  8. package/dist/arrow/index.js.map +1 -0
  9. package/dist/arrowToCube-BdRWZ5oG.d.cts +29 -0
  10. package/dist/arrowToCube-Mjr79ZHM.d.ts +29 -0
  11. package/dist/chunk-2HY7NRKX.js +259 -0
  12. package/dist/chunk-2HY7NRKX.js.map +1 -0
  13. package/dist/chunk-62NIY7ML.js +191 -0
  14. package/dist/chunk-62NIY7ML.js.map +1 -0
  15. package/dist/chunk-AXUZF6O5.cjs +352 -0
  16. package/dist/chunk-AXUZF6O5.cjs.map +1 -0
  17. package/dist/chunk-EFRDFQOT.js +335 -0
  18. package/dist/chunk-EFRDFQOT.js.map +1 -0
  19. package/dist/chunk-GDKDYLZ4.cjs +263 -0
  20. package/dist/chunk-GDKDYLZ4.cjs.map +1 -0
  21. package/dist/chunk-IDTQZG4B.js +432 -0
  22. package/dist/chunk-IDTQZG4B.js.map +1 -0
  23. package/dist/chunk-KFIKGBIJ.cjs +200 -0
  24. package/dist/chunk-KFIKGBIJ.cjs.map +1 -0
  25. package/dist/chunk-L65CRXTV.js +64 -0
  26. package/dist/chunk-L65CRXTV.js.map +1 -0
  27. package/dist/chunk-PHLCWTHB.cjs +446 -0
  28. package/dist/chunk-PHLCWTHB.cjs.map +1 -0
  29. package/dist/chunk-VQCS4LVD.cjs +166 -0
  30. package/dist/chunk-VQCS4LVD.cjs.map +1 -0
  31. package/dist/chunk-VYS7DPB3.js +162 -0
  32. package/dist/chunk-VYS7DPB3.js.map +1 -0
  33. package/dist/chunk-ZEDTWRDN.cjs +70 -0
  34. package/dist/chunk-ZEDTWRDN.cjs.map +1 -0
  35. package/dist/cli/index.cjs +337 -0
  36. package/dist/cli/index.cjs.map +1 -0
  37. package/dist/cli/index.d.cts +90 -0
  38. package/dist/cli/index.d.ts +90 -0
  39. package/dist/cli/index.js +333 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cubeBuilder-BEGA4C5Y.js +4 -0
  42. package/dist/cubeBuilder-BEGA4C5Y.js.map +1 -0
  43. package/dist/cubeBuilder-ZU76VVEX.cjs +25 -0
  44. package/dist/cubeBuilder-ZU76VVEX.cjs.map +1 -0
  45. package/dist/cubeReader-7QVUF3TI.js +4 -0
  46. package/dist/cubeReader-7QVUF3TI.js.map +1 -0
  47. package/dist/cubeReader-UN2BHQWK.cjs +21 -0
  48. package/dist/cubeReader-UN2BHQWK.cjs.map +1 -0
  49. package/dist/index.cjs +172 -0
  50. package/dist/index.cjs.map +1 -0
  51. package/dist/index.d.cts +445 -0
  52. package/dist/index.d.ts +445 -0
  53. package/dist/index.js +7 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/ir-BArfNxo-.d.cts +143 -0
  56. package/dist/ir-Jae2ymov.d.ts +143 -0
  57. package/dist/jsonstat-BX4mBLci.d.cts +179 -0
  58. package/dist/jsonstat-BX4mBLci.d.ts +179 -0
  59. package/dist/sources/csv.cjs +40 -0
  60. package/dist/sources/csv.cjs.map +1 -0
  61. package/dist/sources/csv.d.cts +112 -0
  62. package/dist/sources/csv.d.ts +112 -0
  63. package/dist/sources/csv.js +3 -0
  64. package/dist/sources/csv.js.map +1 -0
  65. package/dist/sources/csvw.cjs +236 -0
  66. package/dist/sources/csvw.cjs.map +1 -0
  67. package/dist/sources/csvw.d.cts +143 -0
  68. package/dist/sources/csvw.d.ts +143 -0
  69. package/dist/sources/csvw.js +230 -0
  70. package/dist/sources/csvw.js.map +1 -0
  71. package/dist/sources/duckdb.cjs +121 -0
  72. package/dist/sources/duckdb.cjs.map +1 -0
  73. package/dist/sources/duckdb.d.cts +111 -0
  74. package/dist/sources/duckdb.d.ts +111 -0
  75. package/dist/sources/duckdb.js +115 -0
  76. package/dist/sources/duckdb.js.map +1 -0
  77. package/dist/sources/parquet.cjs +117 -0
  78. package/dist/sources/parquet.cjs.map +1 -0
  79. package/dist/sources/parquet.d.cts +83 -0
  80. package/dist/sources/parquet.d.ts +83 -0
  81. package/dist/sources/parquet.js +111 -0
  82. package/dist/sources/parquet.js.map +1 -0
  83. package/dist/sources/polars.cjs +94 -0
  84. package/dist/sources/polars.cjs.map +1 -0
  85. package/dist/sources/polars.d.cts +91 -0
  86. package/dist/sources/polars.d.ts +91 -0
  87. package/dist/sources/polars.js +87 -0
  88. package/dist/sources/polars.js.map +1 -0
  89. package/docs/api.md +322 -0
  90. package/docs/architecture.md +140 -0
  91. package/docs/cli.md +159 -0
  92. package/docs/formats/arrow.md +111 -0
  93. package/docs/formats/csv.md +115 -0
  94. package/docs/formats/csvw.md +152 -0
  95. package/docs/formats/duckdb.md +151 -0
  96. package/docs/formats/parquet.md +132 -0
  97. package/docs/formats/polars.md +111 -0
  98. package/docs/mapping.md +136 -0
  99. package/package.json +119 -0
@@ -0,0 +1,445 @@
1
+ import { J as JsonStatDataset, c as JsonStatResponse } from './jsonstat-BX4mBLci.js';
2
+ export { C as Coordinates, d as JsonStatCategory, e as JsonStatClass, f as JsonStatCollection, g as JsonStatDimension, h as JsonStatDimensionResponse, i as JsonStatError, j as JsonStatLink, k as JsonStatLinkMap, a as JsonStatRole, l as JsonStatStatus, b as JsonStatUnit, m as JsonStatValue, n as isCollection, o as isDataset, p as isDimensionResponse } from './jsonstat-BX4mBLci.js';
3
+ import { D as DatasetMeta, O as Observations } from './ir-Jae2ymov.js';
4
+ export { C as CubeModel, a as DimensionColumn, M as MeasureColumn, R as RoleMap, S as StatusColumn, o as observationCount } from './ir-Jae2ymov.js';
5
+ export { META_PREFIX, buildFieldMeta, buildSchemaMeta, cubeToArrow, getFieldMeta, getFieldMetaJson, getFieldRole, isMeasureField, isStatusField, readSchemaMeta } from './arrow/index.js';
6
+ import { A as ArrowToCubeOptions } from './arrowToCube-Mjr79ZHM.js';
7
+ export { a as ArrowConversionError, b as arrowToCube, c as arrowToDataset } from './arrowToCube-Mjr79ZHM.js';
8
+ import { Table } from 'apache-arrow';
9
+
10
+ /**
11
+ * Row-major index math — the correctness backbone of the importer.
12
+ *
13
+ * JSON-stat stores cell values in a flat array laid out in **row-major order**,
14
+ * described by the spec as "what does not change, first": the *last* dimension
15
+ * in `id` changes fastest (see wiki/format-specification.md and
16
+ * wiki/sparse-cubes.md).
17
+ *
18
+ * Concretely, for dimensions with sizes `s₀, s₁, …, sₖ₋₁`, the flat position of
19
+ * a cell at multi-index `(i₀, i₁, …, iₖ₋₁)` is:
20
+ *
21
+ * pos = i₀·(s₁·…·sₖ₋₁) + i₁·(s₂·…·sₖ₋₁) + … + iₖ₋₂·sₖ₋₁ + iₖ₋₁
22
+ *
23
+ * i.e. the stride of dimension `d` is the product of the sizes of all
24
+ * dimensions that come *after* it. This module centralizes that arithmetic so
25
+ * every converter and the round-trip tests share one source of truth.
26
+ */
27
+ /** Compute row-major strides from a `size` array. strides[d] = ∏ size[d+1..]. */
28
+ declare function strides(size: number[]): number[];
29
+ /** Total number of cells = product of all sizes (the dense cell count). */
30
+ declare function totalCells(size: number[]): number;
31
+ /**
32
+ * Convert a multi-index to a flat row-major position.
33
+ *
34
+ * `indices` length must equal `size` length; each `indices[d]` must satisfy
35
+ * `0 ≤ indices[d] < size[d]`.
36
+ */
37
+ declare function flatPosition(indices: number[], size: number[]): number;
38
+ /**
39
+ * Inverse of [`flatPosition`](#flatposition): decompose a flat position back
40
+ * into a multi-index. Used by the cube reader (Phase-2 seam) and by tests.
41
+ */
42
+ declare function multiIndex(pos: number, size: number[]): number[];
43
+ /**
44
+ * Enumerate every multi-index in row-major order, yielding flat positions
45
+ * 0..(total-1). Useful for materializing a dense value array from a sparse map.
46
+ *
47
+ * Calls `visit(indices, flatPos)` for each cell. Iterative (no recursion) to
48
+ * avoid stack overflow on large cubes.
49
+ */
50
+ declare function enumerateCells(size: number[], visit: (indices: number[], flatPos: number) => void): void;
51
+
52
+ /**
53
+ * CubeBuilder — turns an [`Observations`](../model/ir.ts) IR into a JSON-stat
54
+ * [`Dataset`](../model/jsonstat.ts).
55
+ *
56
+ * This is the central transform of the importer: a tidy long table → an
57
+ * N-dimensional cube laid out in row-major order ("what does not change, first";
58
+ * see wiki/format-specification.md).
59
+ *
60
+ * Responsibilities:
61
+ * 1. Resolve dimension order and enumerate categories (first-seen order unless
62
+ * `categoryOrder` pins it).
63
+ * 2. Build the `dimension` block with `category.index`/`label`/`unit`/
64
+ * `coordinates`/`child` and dimension `label`.
65
+ * 3. Scatter the measure values into a row-major `value` array (dense) or a
66
+ * sparse object, per [`CubeModel.valueForm`](../model/ir.ts) and the null
67
+ * ratio threshold.
68
+ * 4. Emit `status` in the most compact correct form (string/array/object).
69
+ * 5. Attach `role`, and dataset-level `label`/`source`/`updated`/`extension`.
70
+ *
71
+ * Pure: no I/O, no side effects. All index math delegated to
72
+ * [`strides`](./strides.ts).
73
+ */
74
+
75
+ /** Thrown when the IR violates a structural invariant the builder relies on. */
76
+ declare class CubeBuilderError extends Error {
77
+ constructor(message: string);
78
+ }
79
+ interface BuildOptions {
80
+ /** Override the emitted value form. Defaults to `model.valueForm ?? "auto"`. */
81
+ valueForm?: "auto" | "dense" | "sparse";
82
+ /** Override the sparse threshold (null ratio). Defaults to 0.5. */
83
+ sparseThreshold?: number;
84
+ /** Override status emission. Defaults to `model.statusForm ?? "auto"`. */
85
+ statusForm?: "auto" | "array" | "string" | "object" | "none";
86
+ /** Override dataset metadata. Defaults to `model.meta`. */
87
+ meta?: DatasetMeta;
88
+ }
89
+ interface BuildResult {
90
+ dataset: JsonStatDataset;
91
+ /** Diagnostics from the build (non-fatal observations). */
92
+ diagnostics: {
93
+ valueForm: "dense" | "sparse";
94
+ nullRatio: number;
95
+ duplicates: number;
96
+ cellCount: number;
97
+ };
98
+ }
99
+ /**
100
+ * Build a JSON-stat [`Dataset`](../model/jsonstat.ts) from an
101
+ * [`Observations`](../model/ir.ts) IR.
102
+ *
103
+ * @throws [`CubeBuilderError`](#cubebuildererror) on invariant violations.
104
+ */
105
+ declare function buildDataset(obs: Observations, options?: BuildOptions): BuildResult;
106
+ /**
107
+ * Convenience: build and return *just* the dataset (no diagnostics).
108
+ * Useful for the common programmatic case.
109
+ */
110
+ declare function toDataset(obs: Observations, options?: BuildOptions): JsonStatDataset;
111
+
112
+ /**
113
+ * CubeReader — the inverse of [`CubeBuilder`](./cubeBuilder.ts): converts a
114
+ * JSON-stat [`Dataset`](../model/jsonstat.ts) back into the
115
+ * [`Observations`](../model/ir.ts) IR (a tidy long table).
116
+ *
117
+ * ## Why this exists now (Phase-1 import project)
118
+ *
119
+ * Although the primary deliverable is *import* (columnar → JSON-stat), the
120
+ * reader is shipped in v0.1 for two reasons:
121
+ *
122
+ * 1. **Round-trip fidelity tests.** The canonical JSON-stat samples
123
+ * (oecd, canada, galicia, order, hierarchy, us-gsp, us-unr — see
124
+ * wiki/sample-files.md) are read into the IR, written back through the
125
+ * builder, and asserted equal. This is the strongest correctness proof we
126
+ * have that the importer faithfully preserves the JSON-stat model.
127
+ *
128
+ * 2. **The Phase-2 export seam.** Export (JSON-stat → columnar) is
129
+ * `cubeReader` → IR → [`arrowFromCube`](../arrow/arrowFromCube.ts) →
130
+ * Arrow/Parquet/DuckDB/Polars/CSV writers. Building the reader now means
131
+ * the IR is verified bidirectional, and Phase 2 is "just" the writers.
132
+ * See [docs/architecture.md](../../docs/architecture.md) §"The two seams".
133
+ *
134
+ * ## Semantics
135
+ *
136
+ * The reader *materializes the dense cube* from `value` (handling both the
137
+ * array form and the sparse object form — see wiki/sparse-cubes.md), then walks
138
+ * every cell in row-major order ([`multiIndex`](./strides.ts)) to emit one
139
+ * observation per cell. Missing cells (`null`) are emitted as rows with a
140
+ * `null` measure, preserving the full Cartesian product of categories — which
141
+ * is what round-trip equality requires.
142
+ *
143
+ * `status` is normalized back to a per-row `StatusColumn` regardless of whether
144
+ * the source used the string, array, or object form.
145
+ */
146
+
147
+ /** Thrown when a dataset cannot be read (malformed or unsupported). */
148
+ declare class CubeReaderError extends Error {
149
+ constructor(message: string);
150
+ }
151
+ interface ReadOptions {
152
+ /**
153
+ * When true (default), cells whose measure is `null` are *omitted* from the
154
+ * emitted long table (a truly sparse/tidy representation). When false, every
155
+ * cell — including nulls — is emitted as a row (required for exact round-trip
156
+ * equality against a dense `value` array).
157
+ */
158
+ dropNulls?: boolean;
159
+ }
160
+ /**
161
+ * Read a JSON-stat [`Dataset`](../model/jsonstat.ts) into the
162
+ * [`Observations`](../model/ir.ts) IR.
163
+ *
164
+ * @throws [`CubeReaderError`](#cubereadererror) on structural problems.
165
+ */
166
+ declare function readDataset(dataset: JsonStatDataset, options?: ReadOptions): Observations;
167
+ /** Convenience: read a JSON-stat response, rejecting non-dataset classes. */
168
+ declare function readResponse(response: unknown, options?: ReadOptions): Observations;
169
+
170
+ /**
171
+ * Serialize — turn a JSON-stat [`Dataset`](../model/jsonstat.ts) into a JSON
172
+ * string or Buffer for writing to stdout/file.
173
+ *
174
+ * Also offers a lightweight "pretty" mode that sorts top-level keys in the
175
+ * canonical JSON-stat order (version, class, label, href, source, updated,
176
+ * id, size, dimension, role, value, status, …) so output is stable and
177
+ * diff-friendly — useful for fixtures and round-trip tests.
178
+ */
179
+
180
+ interface SerializeOptions {
181
+ /** Pretty-print with 2-space indentation (default true). */
182
+ pretty?: boolean;
183
+ /** Reorder top-level keys canonically (default true, only with pretty). */
184
+ canonicalKeys?: boolean;
185
+ }
186
+ /**
187
+ * Serialize a JSON-stat response to a JSON string.
188
+ *
189
+ * @param response The dataset (or any JSON-stat response).
190
+ */
191
+ declare function serialize(response: JsonStatResponse | JsonStatDataset, options?: SerializeOptions): string;
192
+ /**
193
+ * Serialize and encode as UTF-8 bytes (Uint8Array). Handy for file writing
194
+ * without pulling in Node's Buffer in browser contexts.
195
+ */
196
+ declare function serializeToBytes(response: JsonStatResponse | JsonStatDataset, options?: SerializeOptions): Uint8Array;
197
+
198
+ /**
199
+ * Format detection — sniffs the input source to pick the right adapter.
200
+ *
201
+ * Two signals are used, in order of reliability:
202
+ * 1. **Magic bytes** (content sniffing) — authoritative for binary formats
203
+ * (Parquet `PAR1`, Arrow IPC `ARROW1`).
204
+ * 2. **File extension** — used when content is not yet available (e.g. a path
205
+ * or URL) or for text formats (`.csv`, `.csvw`).
206
+ */
207
+ type SourceFormat = "parquet" | "arrow" | "csv" | "csvw" | "jsonstat" | "json" | "unknown";
208
+ /**
209
+ * Sniff the format from the leading bytes of a binary/text input.
210
+ *
211
+ * @returns The detected format, or "unknown" if no magic matches.
212
+ */
213
+ declare function detectFromBytes(bytes: Uint8Array | ArrayBuffer): SourceFormat;
214
+ /** Map a file extension (without dot) to a source format. */
215
+ declare function detectFromExtension(ext: string): SourceFormat;
216
+ /** Extract the extension from a path/URL (without the dot), or undefined. */
217
+ declare function extensionOf(path: string): string | undefined;
218
+ /**
219
+ * Detect a format from a filename/URL, falling back to bytes if the extension
220
+ * is unknown or ambiguous.
221
+ */
222
+ declare function detectFormat(pathOrUrl: string | undefined, bytes?: Uint8Array | ArrayBuffer): SourceFormat;
223
+
224
+ /**
225
+ * Density helper — sparse vs dense `value` decision.
226
+ *
227
+ * Centralizes the null-ratio threshold logic so the cube builder and tests
228
+ * share one definition. See wiki/sparse-cubes.md for the rationale: the object
229
+ * (sparse) form is preferred when many cells are null.
230
+ */
231
+ interface DensityResult {
232
+ form: "dense" | "sparse";
233
+ nullRatio: number;
234
+ nullCount: number;
235
+ total: number;
236
+ }
237
+ interface DensityOptions {
238
+ /** Null ratio above which "auto" chooses sparse. Default 0.5. */
239
+ threshold?: number;
240
+ }
241
+ /**
242
+ * Decide dense vs sparse for a flat value array.
243
+ *
244
+ * @param values The dense row-major array (with nulls).
245
+ * @param requested "auto" | "dense" | "sparse".
246
+ */
247
+ declare function decideDensity(values: (number | null)[], requested?: "auto" | "dense" | "sparse", options?: DensityOptions): DensityResult;
248
+
249
+ /**
250
+ * Isomorphic input loader — works in both Node and the browser.
251
+ *
252
+ * Resolves a source specifier (file path, URL, or raw bytes/text) into a
253
+ * `Uint8Array` of bytes and, where possible, a hint about its origin (path/URL)
254
+ * so format detection can use the extension.
255
+ *
256
+ * - **Node**: reads from `node:fs` for local paths; uses `fetch` for URLs and
257
+ * for the browser. Reading from stdin is supported via the special source
258
+ * `"-"`.
259
+ * - **Browser**: uses the global `fetch` for URLs and `File`/`Blob` inputs;
260
+ * local paths are not available.
261
+ *
262
+ * The Node-specific `fs`/`stdin` imports are guarded by a runtime check so the
263
+ * same code path works in browsers without bundling `node:fs`.
264
+ */
265
+ interface LoadedInput {
266
+ bytes: Uint8Array;
267
+ /** The original source path/URL, if known (used for extension detection). */
268
+ source?: string;
269
+ /** True if the source was stdin ("-"). */
270
+ fromStdin?: boolean;
271
+ }
272
+ /**
273
+ * Load input bytes from a path, URL, `"-"` (stdin), `Uint8Array`, `Blob`, or
274
+ * string.
275
+ *
276
+ * @param source A file path, `http(s)://` URL, `"-"` for stdin, or raw data.
277
+ * @throws If the source cannot be read.
278
+ */
279
+ declare function loadInput(source: string | Uint8Array | Blob): Promise<LoadedInput>;
280
+
281
+ /**
282
+ * jsonstat-io — public API surface (main entry).
283
+ *
284
+ * This package is a **bidirectional** bridge between JSON-stat 2.0 and the
285
+ * columnar stack (Arrow, Parquet, DuckDB, Polars, CSVW, CSV):
286
+ *
287
+ * - **Import** (columnar → JSON-stat): [`importToCube`](#importtocube) /
288
+ * [`importToDataset`](#importtodataset) — load, auto-detect, convert, build.
289
+ * - **Export** (JSON-stat → columnar): [`exportDataset`](#exportdataset) — read
290
+ * the JSON-stat cube into the IR and route to the requested sink writer.
291
+ *
292
+ * This barrel re-exports the **always loaded** layers: the model types, the
293
+ * core cube engine (strides, builder, reader), the Arrow hub, the sink, and the
294
+ * isomorphic utilities (format detection, input loading, density decision).
295
+ *
296
+ * Source/sink adapters that pull in optional peer dependencies live behind
297
+ * **subpath exports** so that browser bundles stay lean and tree-shakeable:
298
+ *
299
+ * - `jsonstat-io/arrow` — Arrow hub (re-exported here too, since
300
+ * `apache-arrow` is a hard dependency, not an optional peer).
301
+ * - `jsonstat-io/parquet` — Parquet ↔ Arrow ↔ cube (needs `parquet-wasm`).
302
+ * - `jsonstat-io/duckdb` — DuckDB ↔ Arrow ↔ cube (needs duckdb).
303
+ * - `jsonstat-io/polars` — Polars ↔ Arrow ↔ cube (Node-only).
304
+ * - `jsonstat-io/csvw` — CSVW + CSV metadata-aware path (no deps).
305
+ * - `jsonstat-io/csv` — plain CSV inference path (no deps).
306
+ *
307
+ * For a one-call convenience, see the dispatchers:
308
+ * - Import: [`importToCube`](#importtocube) / [`importToDataset`](#importtodataset).
309
+ * - Export: [`exportDataset`](#exportdataset).
310
+ *
311
+ * @packageDocumentation
312
+ */
313
+
314
+ /**
315
+ * Options for the high-level [`importToCube`](#importtocube) /
316
+ * [`importToDataset`](#importtodataset) dispatchers.
317
+ *
318
+ * These combine format detection, source loading, and Arrow-hub conversion
319
+ * hints into a single call.
320
+ */
321
+ interface ImportOptions extends ArrowToCubeOptions {
322
+ /**
323
+ * Force a source format instead of auto-detecting. One of `"parquet"`,
324
+ * `"arrow"`, `"csv"`, `"csvw"`, `"jsonstat"`, `"json"`. When omitted the
325
+ * format is sniffed from magic bytes (Parquet `PAR1`, Arrow IPC `ARROW1`)
326
+ * and then from the file extension.
327
+ */
328
+ from?: SourceFormat | "auto";
329
+ /** Passed through to [`buildDataset`](./core/cubeBuilder.ts) as `BuildOptions`. */
330
+ build?: BuildOptions;
331
+ /**
332
+ * CSVW metadata, when the source is CSVW. If `from === "csvw"` and this is
333
+ * omitted, the dispatcher attempts to load a sibling `*-metadata.json` next
334
+ * to the CSV path (Node only). In the browser the caller must supply it.
335
+ */
336
+ csvwMetadata?: unknown;
337
+ /**
338
+ * CSV delimiter (default `,`). Only used when the source is plain CSV.
339
+ */
340
+ delimiter?: string;
341
+ }
342
+ /**
343
+ * Error thrown by the high-level dispatchers when a format cannot be detected,
344
+ * a required peer dependency is missing, or the source produces no data.
345
+ */
346
+ declare class ImporterError extends Error {
347
+ constructor(message: string);
348
+ }
349
+ /**
350
+ * Load a columnar source (file path, URL, stdin `"-"`, `Uint8Array`, or `Blob`)
351
+ * and convert it to the [`Observations`](./model/ir.ts) IR.
352
+ *
353
+ * This is the one-call convenience that ties together
354
+ * [`loadInput`](./util/fetch.ts), [`detectFormat`](./util/detect.ts), the
355
+ * appropriate source adapter, and the Arrow hub. It auto-detects the format
356
+ * unless [`options.from`](#ImportOptions.from) is set.
357
+ *
358
+ * Parquet/DuckDB/Polars adapters are imported lazily, so they are only pulled
359
+ * into the bundle when actually needed.
360
+ *
361
+ * @param source A file path, `http(s)://` URL, `"-"` for stdin (Node),
362
+ * `Uint8Array`, or `Blob`.
363
+ * @returns The [`Observations`](./model/ir.ts) IR, ready for
364
+ * [`buildDataset`](./core/cubeBuilder.ts).
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * import { importToDataset } from "jsonstat-io";
369
+ * const dataset = await importToDataset("./sales.parquet");
370
+ * console.log(JSON.stringify(dataset, null, 2));
371
+ * ```
372
+ */
373
+ declare function importToCube(source: string | Uint8Array | Blob, options?: ImportOptions): Promise<Observations>;
374
+ /**
375
+ * Like [`importToCube`](#importtocube) but also builds the final
376
+ * [`JsonStatDataset`](./model/jsonstat.ts) via [`buildDataset`](./core/cubeBuilder.ts).
377
+ *
378
+ * @returns The serialized-ready [`JsonStatDataset`](./model/jsonstat.ts).
379
+ */
380
+ declare function importToDataset(source: string | Uint8Array | Blob, options?: ImportOptions): Promise<JsonStatDataset>;
381
+ /** Supported export sinks for [`exportDataset`](#exportdataset). */
382
+ type ExportTarget = "arrow" | "parquet" | "csv" | "csvw";
383
+ /**
384
+ * Options for [`exportDataset`](#exportdataset).
385
+ *
386
+ * Format-specific knobs are passed through to the underlying writer. For
387
+ * Parquet, `init` is forwarded to `parquet-wasm`; for CSVW, `url` sets the
388
+ * metadata `url`. DuckDB and Polars are intentionally not exposed here because
389
+ * they require a live connection / native module — use the dedicated subpath
390
+ * exports (`jsonstat-io/duckdb`, `jsonstat-io/polars`) for those.
391
+ */
392
+ interface ExportOptions {
393
+ to: ExportTarget;
394
+ /** Parquet compression codec (forwarded to `parquet-wasm` `writeParquet`). */
395
+ compression?: string;
396
+ /** CSV / CSVW delimiter (default ","). */
397
+ delimiter?: string;
398
+ /** CSVW metadata `url` field. */
399
+ url?: string;
400
+ /** Line terminator for CSV / CSVW output (default "\r\n"). */
401
+ lineTerminator?: string;
402
+ /** Async initializer for parquet-wasm (browser base URL, etc.). */
403
+ init?: () => Promise<void>;
404
+ }
405
+ /**
406
+ * The polymorphic result of [`exportDataset`](#exportdataset). The concrete
407
+ * shape depends on [`ExportOptions.to`](#ExportOptions.to):
408
+ *
409
+ * - `"arrow"` → an Apache Arrow [`Table`](https://arrow.apache.org/docs/js/).
410
+ * - `"parquet"` → a `Uint8Array` of the Parquet file bytes.
411
+ * - `"csv"` → the CSV text (`string`).
412
+ * - `"csvw"` → `{ csv: string; metadata: CsvwMetadata }`.
413
+ */
414
+ type ExportResult = Table | Uint8Array | string | CsvwExportShape;
415
+ /** Shape of the `"csvw"` export result (mirrors `csvw.CsvwExport`). */
416
+ interface CsvwExportShape {
417
+ csv: string;
418
+ metadata: unknown;
419
+ }
420
+ /**
421
+ * Export a JSON-stat [`Dataset`](./model/jsonstat.ts) to a columnar format.
422
+ *
423
+ * This is the high-level export dispatcher, the mirror of
424
+ * [`importToDataset`](#importtodataset). It reads the dataset into the
425
+ * [`Observations`](./model/ir.ts) IR via [`readDataset`](./core/cubeReader.ts),
426
+ * then routes to the appropriate writer:
427
+ *
428
+ * - `"arrow"` → [`cubeToArrow`](./arrow/arrowFromCube.ts) → Arrow `Table`.
429
+ * - `"parquet"` → Arrow → `parquet-wasm` `writeParquet` → `Uint8Array`.
430
+ * - `"csv"` → [`cubeToCsv`](./sources/csv.ts) → CSV text.
431
+ * - `"csvw"` → [`cubeToCsvw`](./sources/csvw.ts) → `{ csv, metadata }`.
432
+ *
433
+ * DuckDB and Polars require a live connection / native module and are not
434
+ * reachable from this dispatcher — use the dedicated subpath writers
435
+ * (`cubeToDuckdb`, `cubeToPolars`) directly.
436
+ *
437
+ * @example
438
+ * ```ts
439
+ * import { exportDataset } from "jsonstat-io";
440
+ * const bytes = await exportDataset(dataset, { to: "parquet" });
441
+ * ```
442
+ */
443
+ declare function exportDataset(dataset: JsonStatDataset, options: ExportOptions): Promise<ExportResult>;
444
+
445
+ export { ArrowToCubeOptions, type BuildOptions, type BuildResult, type CsvwExportShape, CubeBuilderError, CubeReaderError, DatasetMeta, type DensityOptions, type DensityResult, type ExportOptions, type ExportResult, type ExportTarget, type ImportOptions, ImporterError, JsonStatDataset, JsonStatResponse, type LoadedInput, Observations, type ReadOptions, type SerializeOptions, type SourceFormat, buildDataset, decideDensity, detectFormat, detectFromBytes, detectFromExtension, enumerateCells, exportDataset, extensionOf, flatPosition, importToCube, importToDataset, loadInput, multiIndex, readDataset, readResponse, serialize, serializeToBytes, strides, toDataset, totalCells };
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { ImporterError, decideDensity, detectFormat, detectFromBytes, detectFromExtension, exportDataset, extensionOf, importToCube, importToDataset, isCollection, isDataset, isDimensionResponse, loadInput, observationCount, serialize, serializeToBytes } from './chunk-EFRDFQOT.js';
2
+ export { CubeBuilderError, buildDataset, toDataset } from './chunk-2HY7NRKX.js';
3
+ export { CubeReaderError, readDataset, readResponse } from './chunk-VYS7DPB3.js';
4
+ export { enumerateCells, flatPosition, multiIndex, strides, totalCells } from './chunk-L65CRXTV.js';
5
+ export { ArrowConversionError, META_PREFIX, arrowToCube, arrowToDataset, buildFieldMeta, buildSchemaMeta, cubeToArrow, getFieldMeta, getFieldMetaJson, getFieldRole, isMeasureField, isStatusField, readSchemaMeta } from './chunk-IDTQZG4B.js';
6
+ //# sourceMappingURL=index.js.map
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,143 @@
1
+ import { a as JsonStatRole, b as JsonStatUnit } from './jsonstat-BX4mBLci.cjs';
2
+
3
+ /**
4
+ * Observations IR — the format-agnostic intermediate representation.
5
+ *
6
+ * Every source (Arrow, Parquet, DuckDB, Polars, CSVW, CSV) converts its data
7
+ * into this IR. The cube builder ([`CubeBuilder`](../core/cubeBuilder.ts))
8
+ * then turns the IR into a JSON-stat [`Dataset`](./jsonstat.ts).
9
+ *
10
+ * The IR is deliberately a **long / tidy table**: one row per observation,
11
+ * with one column per dimension and a single measure column. This is the
12
+ * natural shape of the columnar stack and the dual of a JSON-stat cube.
13
+ *
14
+ * Because the IR is bidirectional, the same model also powers the Phase-2
15
+ * export path ([`cubeReader`](../core/cubeReader.ts) → IR →
16
+ * [`arrowFromCube`](../arrow/arrowFromCube.ts) → Arrow/Parquet/CSV). See
17
+ * [docs/architecture.md](../../docs/architecture.md) §"The two documented seams".
18
+ */
19
+
20
+ /**
21
+ * A dimension column: the observed category *labels or IDs* for each row.
22
+ *
23
+ * `values` is a parallel array (one entry per observation) of category IDs.
24
+ * Category order is *not* implied here — it is resolved by the builder, which
25
+ * enumerates distinct values and assigns indices. Use `categoryOrder` to pin
26
+ * a specific order (e.g. chronological time) when the source knows it.
27
+ */
28
+ interface DimensionColumn {
29
+ /** Dimension ID (becomes a key in JSON-stat `dimension`). */
30
+ id: string;
31
+ /** Human-readable dimension label. */
32
+ label?: string;
33
+ /** Per-row category ID. `null` is not permitted for dimensions. */
34
+ values: string[];
35
+ /**
36
+ * Optional explicit category ordering. When omitted the builder enumerates
37
+ * distinct values in first-seen order. Provide for time dimensions whose
38
+ * chronological order is not lexicographic.
39
+ */
40
+ categoryOrder?: string[];
41
+ /** ID → human-readable category label. Falls back to the ID. */
42
+ categoryLabels?: Record<string, string>;
43
+ /** ID → unit metadata (metric-role dimensions only). */
44
+ categoryUnits?: Record<string, JsonStatUnit>;
45
+ /** ID → [lon, lat] (geo-role dimensions only). */
46
+ categoryCoordinates?: Record<string, [number, number]>;
47
+ /** Parent ID → direct child IDs (hierarchical dimensions only). */
48
+ categoryChild?: Record<string, string[]>;
49
+ /** Optional href to an external dimension definition. */
50
+ href?: string;
51
+ }
52
+ /**
53
+ * The measure column: the numeric observation values, one per row.
54
+ *
55
+ * `null` represents a missing observation. The importer supports a single
56
+ * measure column in v0.1 — multi-measure datasets should be split across
57
+ * multiple datasets (one per metric) or modeled as a metric *dimension*,
58
+ * matching how JSON-stat treats measures as a dimension with the `metric`
59
+ * role rather than as separate value arrays.
60
+ */
61
+ interface MeasureColumn {
62
+ /** Column name in the source (kept for round-trip fidelity, not emitted). */
63
+ name?: string;
64
+ /** Numeric values; `null` = missing. */
65
+ values: (number | null)[];
66
+ }
67
+ /**
68
+ * Optional per-row status column. Provider-defined vocabulary; emitted verbatim
69
+ * as JSON-stat `status` (array form) by the builder.
70
+ */
71
+ interface StatusColumn {
72
+ /** Per-row status code. */
73
+ values: string[];
74
+ }
75
+ /**
76
+ * Role assignment. Mirrors JSON-stat's `role` object: each role maps to a list
77
+ * of dimension IDs. The importer assigns roles from source metadata or CLI
78
+ * hints; unassigned dimensions default to the implicit "classification" role.
79
+ */
80
+ type RoleMap = JsonStatRole;
81
+ /**
82
+ * Dataset-level metadata carried alongside the observations.
83
+ *
84
+ * These fields map directly to top-level JSON-stat dataset properties
85
+ * (`label`, `source`, `updated`, `extension`).
86
+ */
87
+ interface DatasetMeta {
88
+ label?: string;
89
+ source?: string;
90
+ updated?: string;
91
+ extension?: Record<string, unknown>;
92
+ }
93
+ /**
94
+ * The complete cube model: everything the builder needs besides the raw
95
+ * observation columns to produce a fully-specified JSON-stat dataset.
96
+ */
97
+ interface CubeModel {
98
+ /** Ordered dimension IDs. Determines row-major stride order. */
99
+ dimensionIds: string[];
100
+ /** Role assignments (time/geo/metric). */
101
+ roles?: RoleMap;
102
+ /** Dataset-level metadata. */
103
+ meta?: DatasetMeta;
104
+ /**
105
+ * How to emit `value`.
106
+ * - "auto": dense unless null-ratio exceeds `sparseThreshold`.
107
+ * - "dense": always array form.
108
+ * - "sparse": always object form.
109
+ */
110
+ valueForm?: "auto" | "dense" | "sparse";
111
+ /** Null ratio above which "auto" chooses sparse. Default 0.5. */
112
+ sparseThreshold?: number;
113
+ /**
114
+ * Whether to emit a status array. When a StatusColumn is present and this is
115
+ * not "none", the builder emits status. "object" emits the sparse object form
116
+ * when there are few non-default statuses; "string" collapses a uniform
117
+ * status to a single string.
118
+ */
119
+ statusForm?: "auto" | "array" | "string" | "object" | "none";
120
+ }
121
+ /**
122
+ * The Observations IR: a tidy long table plus its cube model.
123
+ *
124
+ * Invariants the builder assumes (validated in [`CubeBuilder.build`]):
125
+ * - All columns in `dimensions` and `measure` share the same length `n`.
126
+ * - `status`, if present, has length `n`.
127
+ * - `model.dimensionIds` lists every dimension column id, and no others.
128
+ * - No dimension value is `null` or `undefined`.
129
+ */
130
+ interface Observations {
131
+ /** Dimension columns, keyed by dimension ID. */
132
+ dimensions: Record<string, DimensionColumn>;
133
+ /** The single measure column. */
134
+ measure: MeasureColumn;
135
+ /** Optional per-row status. */
136
+ status?: StatusColumn;
137
+ /** The cube model governing how to build the JSON-stat dataset. */
138
+ model: CubeModel;
139
+ }
140
+ /** Number of observations (rows). */
141
+ declare function observationCount(obs: Observations): number;
142
+
143
+ export { type CubeModel as C, type DatasetMeta as D, type MeasureColumn as M, type Observations as O, type RoleMap as R, type StatusColumn as S, type DimensionColumn as a, observationCount as o };