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,191 @@
1
+ // src/sources/csv.ts
2
+ var CsvSourceError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "CsvSourceError";
6
+ }
7
+ };
8
+ function parseCsv(input, delimiter = ",") {
9
+ const rows = [];
10
+ let row = [];
11
+ let field = "";
12
+ let inQuotes = false;
13
+ const delim = delimiter.charCodeAt(0);
14
+ for (let i = 0; i < input.length; i++) {
15
+ const c = input.charCodeAt(i);
16
+ if (inQuotes) {
17
+ if (c === 34) {
18
+ if (input.charCodeAt(i + 1) === 34) {
19
+ field += '"';
20
+ i++;
21
+ } else {
22
+ inQuotes = false;
23
+ }
24
+ } else {
25
+ field += input[i];
26
+ }
27
+ } else {
28
+ if (c === 34) {
29
+ inQuotes = true;
30
+ } else if (c === delim) {
31
+ row.push(field);
32
+ field = "";
33
+ } else if (c === 13) {
34
+ if (input.charCodeAt(i + 1) === 10) i++;
35
+ row.push(field);
36
+ rows.push(row);
37
+ row = [];
38
+ field = "";
39
+ } else if (c === 10) {
40
+ row.push(field);
41
+ rows.push(row);
42
+ row = [];
43
+ field = "";
44
+ } else {
45
+ field += input[i];
46
+ }
47
+ }
48
+ }
49
+ if (field.length > 0 || row.length > 0) {
50
+ row.push(field);
51
+ rows.push(row);
52
+ }
53
+ return rows;
54
+ }
55
+ function isAllNumeric(values) {
56
+ let any = false;
57
+ for (const v of values) {
58
+ if (v === "") continue;
59
+ any = true;
60
+ const n = Number(v);
61
+ if (!Number.isFinite(n)) return false;
62
+ }
63
+ return any;
64
+ }
65
+ function csvToCube(text, options = {}) {
66
+ const delimiter = options.delimiter ?? ",";
67
+ const header = options.header ?? true;
68
+ const rows = parseCsv(text, delimiter);
69
+ if (rows.length === 0) throw new CsvSourceError("CSV has no rows");
70
+ let headerNames;
71
+ let dataRows;
72
+ if (header) {
73
+ headerNames = rows[0];
74
+ dataRows = rows.slice(1);
75
+ } else {
76
+ headerNames = rows[0].map((_, i) => `col${i}`);
77
+ dataRows = rows;
78
+ }
79
+ if (headerNames.length === 0) throw new CsvSourceError("CSV header is empty");
80
+ if (dataRows.length === 0) throw new CsvSourceError("CSV has no data rows");
81
+ const colCount = headerNames.length;
82
+ const columns = headerNames.map(() => []);
83
+ for (const r of dataRows) {
84
+ for (let c = 0; c < colCount; c++) columns[c].push(r[c] ?? "");
85
+ }
86
+ let measureIdx = headerNames.findIndex((n2) => n2 === options.measure);
87
+ if (measureIdx === -1) {
88
+ measureIdx = columns.findIndex((col) => isAllNumeric(col));
89
+ if (measureIdx === -1) {
90
+ throw new CsvSourceError(
91
+ "No measure column found: no column is fully numeric. Pass options.measure to name one (values will be parsed with Number())."
92
+ );
93
+ }
94
+ }
95
+ let statusIdx = headerNames.findIndex((n2) => n2 === options.status);
96
+ if (statusIdx === -1 && !options.status) {
97
+ statusIdx = headerNames.findIndex((n2) => n2.toLowerCase() === "status");
98
+ if (statusIdx === measureIdx) statusIdx = -1;
99
+ }
100
+ let dimensionIdxs;
101
+ if (options.dimensions) {
102
+ dimensionIdxs = options.dimensions.map((n2) => {
103
+ const idx = headerNames.indexOf(n2);
104
+ if (idx === -1) throw new CsvSourceError(`Dimension column "${n2}" not found in CSV header`);
105
+ return idx;
106
+ });
107
+ } else {
108
+ dimensionIdxs = headerNames.map((_, i) => i).filter((i) => i !== measureIdx && i !== statusIdx);
109
+ if (dimensionIdxs.length === 0) {
110
+ throw new CsvSourceError("No dimension columns remain after measure/status selection");
111
+ }
112
+ }
113
+ dataRows.length;
114
+ const dimensions = {};
115
+ for (const idx of dimensionIdxs) {
116
+ const name = headerNames[idx];
117
+ dimensions[name] = {
118
+ id: name,
119
+ values: columns[idx].map((v) => v === "" ? "" : v)
120
+ };
121
+ }
122
+ const measure = {
123
+ name: headerNames[measureIdx],
124
+ values: columns[measureIdx].map((v) => v === "" ? null : Number(v))
125
+ };
126
+ let status;
127
+ if (statusIdx !== -1) {
128
+ status = { values: columns[statusIdx].map((v) => v) };
129
+ }
130
+ const observations = {
131
+ dimensions,
132
+ measure,
133
+ status,
134
+ model: {
135
+ dimensionIds: dimensionIdxs.map((i) => headerNames[i]),
136
+ roles: options.roles,
137
+ valueForm: options.valueForm ?? "auto",
138
+ statusForm: status ? "auto" : "none"
139
+ }
140
+ };
141
+ return observations;
142
+ }
143
+ async function csvToDataset(text, options) {
144
+ const { toDataset } = await import('./cubeBuilder-BEGA4C5Y.js');
145
+ return toDataset(csvToCube(text, options));
146
+ }
147
+ function cubeColumns(obs) {
148
+ const dimIds = obs.model.dimensionIds;
149
+ const measureName = obs.measure.name ?? "value";
150
+ const hasStatus = obs.status !== void 0;
151
+ const header = [...dimIds, measureName];
152
+ if (hasStatus) header.push("status");
153
+ const n = obs.measure.values.length;
154
+ const rows = new Array(n);
155
+ for (let i = 0; i < n; i++) {
156
+ const cells = [];
157
+ for (const id of dimIds) {
158
+ const col = obs.dimensions[id];
159
+ cells.push(col ? col.values[i] : "");
160
+ }
161
+ const v = obs.measure.values[i];
162
+ cells.push(v === null ? "" : String(v));
163
+ if (hasStatus) cells.push(obs.status.values[i] ?? "");
164
+ rows[i] = cells.join("\0");
165
+ }
166
+ return { header, rows };
167
+ }
168
+ function quoteCsvField(value, delimiter, force = false) {
169
+ const needsQuoting = force || value.includes(delimiter) || value.includes('"') || value.includes("\r") || value.includes("\n");
170
+ if (!needsQuoting) return value;
171
+ return `"${value.replace(/"/g, '""')}"`;
172
+ }
173
+ function serializeRows(header, rows, options = {}) {
174
+ const delimiter = options.delimiter ?? ",";
175
+ const eol = options.lineTerminator ?? "\r\n";
176
+ const parts = [];
177
+ parts.push(header.map((h) => quoteCsvField(h, delimiter)).join(delimiter));
178
+ for (const row of rows) {
179
+ const cells = row.split("\0");
180
+ parts.push(cells.map((c) => quoteCsvField(c, delimiter)).join(delimiter));
181
+ }
182
+ return parts.join(eol) + eol;
183
+ }
184
+ function cubeToCsv(obs, options = {}) {
185
+ const { header, rows } = cubeColumns(obs);
186
+ return serializeRows(header, rows, options);
187
+ }
188
+
189
+ export { CsvSourceError, csvToCube, csvToDataset, cubeColumns, cubeToCsv, parseCsv, quoteCsvField, serializeRows };
190
+ //# sourceMappingURL=chunk-62NIY7ML.js.map
191
+ //# sourceMappingURL=chunk-62NIY7ML.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sources/csv.ts"],"names":["n"],"mappings":"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","file":"chunk-62NIY7ML.js","sourcesContent":["/**\n * CSV adapter — `jsonstat-io/csv`.\n *\n * **Import:** unlike Parquet/DuckDB/Polars (which funnel through the Arrow\n * hub), plain CSV has no native Arrow producer in this package, so this adapter\n * builds the [`Observations`](../model/ir.ts) IR **directly** from parsed rows.\n *\n * **Export:** [`cubeToCsv`] writes the [`Observations`] IR to RFC-4180-style\n * CSV text (dimension columns + measure column + optional status column).\n *\n * ## Mapping heuristics (no metadata)\n *\n * Without a schema, the adapter infers:\n * - The **measure** is the first column that parses as a number for every\n * non-empty row (or the one named by `options.measure`).\n * - Every other column is a **dimension** (string-typed), in file order.\n * - A column named `status` (case-insensitive) is treated as the status\n * column unless `options.status` overrides it.\n *\n * Empty cells become `null` in the measure and `\"\"` in dimensions (then\n * rejected by the builder; sources should pre-clean). For richer, lossless\n * mapping with declared types/labels/roles, use CSVW (see [`csvw`](./csvw.ts)).\n */\n\nimport type {\n DimensionColumn,\n MeasureColumn,\n Observations,\n RoleMap,\n StatusColumn,\n} from \"../model/ir\";\nimport type { JsonStatDataset } from \"../model/jsonstat\";\n\n// ---------------------------------------------------------------------------\n// Errors & options\n// ---------------------------------------------------------------------------\n\nexport class CsvSourceError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CsvSourceError\";\n }\n}\n\nexport interface CsvToCubeOptions {\n /** Explicit measure column name. Overrides inference. */\n measure?: string;\n /** Explicit dimension column names, in order. */\n dimensions?: string[];\n /** Explicit status column name. Overrides the `status`-name heuristic. */\n status?: string;\n /** Role assignments. */\n roles?: RoleMap;\n /** Value-form hint. */\n valueForm?: \"auto\" | \"dense\" | \"sparse\";\n /** CSV delimiter (default \",\"). */\n delimiter?: string;\n /** Treat the first row as a header (default true). */\n header?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Minimal CSV parser\n// ---------------------------------------------------------------------------\n\n/**\n * A tiny, dependency-free RFC-4180-ish CSV parser. Handles quoted fields,\n * embedded quotes (doubled), and embedded newlines. Sufficient for the\n * importer's needs; for heavy CSV work, prefer piping through DuckDB/Polars.\n */\nexport function parseCsv(input: string, delimiter = \",\"): string[][] {\n const rows: string[][] = [];\n let row: string[] = [];\n let field = \"\";\n let inQuotes = false;\n const delim = delimiter.charCodeAt(0);\n\n for (let i = 0; i < input.length; i++) {\n const c = input.charCodeAt(i);\n if (inQuotes) {\n if (c === 34 /* \" */) {\n // Doubled quote → literal quote; otherwise end quote.\n if (input.charCodeAt(i + 1) === 34) {\n field += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n field += input[i];\n }\n } else {\n if (c === 34) {\n inQuotes = true;\n } else if (c === delim) {\n row.push(field);\n field = \"\";\n } else if (c === 13 /* \\r */) {\n // swallow; handle \\n\n if (input.charCodeAt(i + 1) === 10) i++;\n row.push(field);\n rows.push(row);\n row = [];\n field = \"\";\n } else if (c === 10 /* \\n */) {\n row.push(field);\n rows.push(row);\n row = [];\n field = \"\";\n } else {\n field += input[i];\n }\n }\n }\n // Flush trailing field/row.\n if (field.length > 0 || row.length > 0) {\n row.push(field);\n rows.push(row);\n }\n return rows;\n}\n\n// ---------------------------------------------------------------------------\n// Type inference\n// ---------------------------------------------------------------------------\n\n/** Does every non-empty value parse as a finite number? */\nfunction isAllNumeric(values: string[]): boolean {\n let any = false;\n for (const v of values) {\n if (v === \"\") continue;\n any = true;\n const n = Number(v);\n if (!Number.isFinite(n)) return false;\n }\n return any;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Parse CSV text into the [`Observations`] IR.\n *\n * @throws [`CsvSourceError`] on structural problems.\n */\nexport function csvToCube(text: string, options: CsvToCubeOptions = {}): Observations {\n const delimiter = options.delimiter ?? \",\";\n const header = options.header ?? true;\n const rows = parseCsv(text, delimiter);\n if (rows.length === 0) throw new CsvSourceError(\"CSV has no rows\");\n\n let headerNames: string[];\n let dataRows: string[][];\n if (header) {\n headerNames = rows[0];\n dataRows = rows.slice(1);\n } else {\n headerNames = rows[0].map((_, i) => `col${i}`);\n dataRows = rows;\n }\n if (headerNames.length === 0) throw new CsvSourceError(\"CSV header is empty\");\n if (dataRows.length === 0) throw new CsvSourceError(\"CSV has no data rows\");\n\n const colCount = headerNames.length;\n\n // Transpose into columnar arrays for inference.\n const columns: string[][] = headerNames.map(() => []);\n for (const r of dataRows) {\n // Pad/truncate to header length.\n for (let c = 0; c < colCount; c++) columns[c].push(r[c] ?? \"\");\n }\n\n // Resolve measure column.\n let measureIdx = headerNames.findIndex((n) => n === options.measure);\n if (measureIdx === -1) {\n // Inference: first all-numeric column.\n measureIdx = columns.findIndex((col) => isAllNumeric(col));\n if (measureIdx === -1) {\n throw new CsvSourceError(\n \"No measure column found: no column is fully numeric. \" +\n \"Pass options.measure to name one (values will be parsed with Number()).\",\n );\n }\n }\n\n // Resolve status column.\n let statusIdx = headerNames.findIndex((n) => n === options.status);\n if (statusIdx === -1 && !options.status) {\n statusIdx = headerNames.findIndex((n) => n.toLowerCase() === \"status\");\n if (statusIdx === measureIdx) statusIdx = -1;\n }\n\n // Resolve dimensions: everything that's not measure or status.\n let dimensionIdxs: number[];\n if (options.dimensions) {\n dimensionIdxs = options.dimensions.map((n) => {\n const idx = headerNames.indexOf(n);\n if (idx === -1) throw new CsvSourceError(`Dimension column \"${n}\" not found in CSV header`);\n return idx;\n });\n } else {\n dimensionIdxs = headerNames\n .map((_, i) => i)\n .filter((i) => i !== measureIdx && i !== statusIdx);\n if (dimensionIdxs.length === 0) {\n throw new CsvSourceError(\"No dimension columns remain after measure/status selection\");\n }\n }\n\n const n = dataRows.length;\n const dimensions: Record<string, DimensionColumn> = {};\n for (const idx of dimensionIdxs) {\n const name = headerNames[idx];\n dimensions[name] = {\n id: name,\n values: columns[idx].map((v) => (v === \"\" ? \"\" : v)),\n };\n }\n\n const measure: MeasureColumn = {\n name: headerNames[measureIdx],\n values: columns[measureIdx].map((v) => (v === \"\" ? null : Number(v))),\n };\n\n let status: StatusColumn | undefined;\n if (statusIdx !== -1) {\n status = { values: columns[statusIdx].map((v) => v) };\n }\n\n const observations: Observations = {\n dimensions,\n measure,\n status,\n model: {\n dimensionIds: dimensionIdxs.map((i) => headerNames[i]),\n roles: options.roles,\n valueForm: options.valueForm ?? \"auto\",\n statusForm: status ? \"auto\" : \"none\",\n },\n };\n // n unused guard (kept for clarity; columns already encode length).\n void n;\n\n return observations;\n}\n\n/** Convenience: CSV text → JSON-stat [`Dataset`]. */\nexport async function csvToDataset(\n text: string,\n options?: CsvToCubeOptions,\n): Promise<JsonStatDataset> {\n const { toDataset } = await import(\"../core/cubeBuilder\");\n return toDataset(csvToCube(text, options));\n}\n\n// ---------------------------------------------------------------------------\n// Export: Observations IR → CSV text\n// ---------------------------------------------------------------------------\n\nexport interface CubeToCsvOptions {\n /** CSV delimiter (default \",\"). */\n delimiter?: string;\n /** Line terminator: \"\\r\\n\" (RFC-4180 default) or \"\\n\". */\n lineTerminator?: string;\n}\n\n/**\n * Resolve the ordered list of (column name, row value extractor) pairs for a\n * dataset IR. Shared by [`cubeToCsv`] and [`cubeToCsvw`] so the two writers\n * agree on column layout.\n *\n * Column order: dimension IDs (in `model.dimensionIds` order) → measure\n * (named `measure.name ?? \"value\"`) → status (`\"status\"`, if present).\n *\n * @internal\n */\nexport function cubeColumns(obs: Observations): {\n header: string[];\n rows: string[];\n} {\n const dimIds = obs.model.dimensionIds;\n const measureName = obs.measure.name ?? \"value\";\n const hasStatus = obs.status !== undefined;\n\n const header: string[] = [...dimIds, measureName];\n if (hasStatus) header.push(\"status\");\n\n const n = obs.measure.values.length;\n const rows: string[] = new Array(n);\n for (let i = 0; i < n; i++) {\n const cells: string[] = [];\n for (const id of dimIds) {\n const col = obs.dimensions[id];\n cells.push(col ? col.values[i] : \"\");\n }\n const v = obs.measure.values[i];\n cells.push(v === null ? \"\" : String(v));\n if (hasStatus) cells.push(obs.status!.values[i] ?? \"\");\n rows[i] = cells.join(\"\\u0000\"); // placeholder; real delimiter applied later\n }\n return { header, rows };\n}\n\n/**\n * Quote a single CSV field per RFC-4180. A field needs quoting if it contains\n * the delimiter, a double quote, a CR, or an LF. Embedded quotes are doubled.\n */\nexport function quoteCsvField(\n value: string,\n delimiter: string,\n force = false,\n): string {\n const needsQuoting =\n force ||\n value.includes(delimiter) ||\n value.includes('\"') ||\n value.includes(\"\\r\") ||\n value.includes(\"\\n\");\n if (!needsQuoting) return value;\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Serialize a CSV header + rows (as produced by [`cubeColumns`]) into RFC-4180\n * text. Extracted so CSV and CSVW writers share one escaping path.\n *\n * @internal\n */\nexport function serializeRows(\n header: string[],\n rows: string[],\n options: CubeToCsvOptions = {},\n): string {\n const delimiter = options.delimiter ?? \",\";\n const eol = options.lineTerminator ?? \"\\r\\n\";\n const parts: string[] = [];\n parts.push(header.map((h) => quoteCsvField(h, delimiter)).join(delimiter));\n for (const row of rows) {\n const cells = row.split(\"\\u0000\");\n parts.push(cells.map((c) => quoteCsvField(c, delimiter)).join(delimiter));\n }\n return parts.join(eol) + eol;\n}\n\n/**\n * Write the [`Observations`](../model/ir.ts) IR to RFC-4180-style CSV text.\n *\n * The output is a tidy long table: one header row + one row per observation.\n * Columns are the dimension IDs (in `model.dimensionIds` order), then the\n * measure column (`measure.name ?? \"value\"`), then an optional `status`\n * column. Null measures are emitted as empty cells.\n *\n * This is the lossy inverse of [`csvToCube`]: labels, roles, and category\n * metadata are not preserved (use [`cubeToCsvw`] for a lossless export).\n *\n * @example\n * ```ts\n * import { cubeToCsv } from \"jsonstat-io/csv\";\n * const csv = cubeToCsv(observations);\n * ```\n */\nexport function cubeToCsv(\n obs: Observations,\n options: CubeToCsvOptions = {},\n): string {\n const { header, rows } = cubeColumns(obs);\n return serializeRows(header, rows, options);\n}\n\n"]}
@@ -0,0 +1,352 @@
1
+ 'use strict';
2
+
3
+ var chunkGDKDYLZ4_cjs = require('./chunk-GDKDYLZ4.cjs');
4
+ var chunkPHLCWTHB_cjs = require('./chunk-PHLCWTHB.cjs');
5
+ var apacheArrow = require('apache-arrow');
6
+
7
+ // src/model/jsonstat.ts
8
+ function isDataset(r) {
9
+ return r.class === "dataset";
10
+ }
11
+ function isCollection(r) {
12
+ return r.class === "collection";
13
+ }
14
+ function isDimensionResponse(r) {
15
+ return r.class === "dimension";
16
+ }
17
+
18
+ // src/model/ir.ts
19
+ function observationCount(obs) {
20
+ return obs.measure.values.length;
21
+ }
22
+
23
+ // src/sink/serialize.ts
24
+ var KEY_ORDER = [
25
+ "version",
26
+ "class",
27
+ "label",
28
+ "href",
29
+ "source",
30
+ "updated",
31
+ "id",
32
+ "size",
33
+ "dimension",
34
+ "role",
35
+ "value",
36
+ "status",
37
+ "extension",
38
+ "link",
39
+ "note",
40
+ "error"
41
+ ];
42
+ function serialize(response, options = {}) {
43
+ const pretty = options.pretty ?? true;
44
+ const canonical = options.canonicalKeys ?? true;
45
+ let value = response;
46
+ if (pretty && canonical) {
47
+ value = reorderKeys(response, KEY_ORDER);
48
+ }
49
+ return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);
50
+ }
51
+ function serializeToBytes(response, options) {
52
+ return new TextEncoder().encode(serialize(response, options));
53
+ }
54
+ function reorderKeys(obj, order) {
55
+ const source = obj;
56
+ const out = {};
57
+ const known = /* @__PURE__ */ new Set();
58
+ for (const k of order) {
59
+ if (k in source) {
60
+ out[k] = source[k];
61
+ known.add(k);
62
+ }
63
+ }
64
+ const rest = Object.keys(source).filter((k) => !known.has(k)).sort();
65
+ for (const k of rest) out[k] = source[k];
66
+ return out;
67
+ }
68
+
69
+ // src/util/detect.ts
70
+ var PARQUET_MAGIC = [80, 65, 82, 49];
71
+ var ARROW_MAGIC = [65, 82, 82, 79, 87, 49];
72
+ function bytesStartWith(bytes, magic) {
73
+ if (bytes.length < magic.length) return false;
74
+ for (let i = 0; i < magic.length; i++) {
75
+ if (bytes[i] !== magic[i]) return false;
76
+ }
77
+ return true;
78
+ }
79
+ function detectFromBytes(bytes) {
80
+ const view = bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes;
81
+ if (bytesStartWith(view, PARQUET_MAGIC)) return "parquet";
82
+ if (bytesStartWith(view, ARROW_MAGIC)) return "arrow";
83
+ const head = view.slice(0, Math.min(64, view.length));
84
+ const text = new TextDecoder().decode(head).trimStart();
85
+ if (text.startsWith("{") || text.startsWith("[")) {
86
+ if (text.includes("json-stat") || text.includes('"class"') && text.includes('"version"')) {
87
+ return "jsonstat";
88
+ }
89
+ return "json";
90
+ }
91
+ if (text.includes(",") || text.includes(";") || text.includes(" ")) return "csv";
92
+ return "unknown";
93
+ }
94
+ function detectFromExtension(ext) {
95
+ const e = ext.toLowerCase().replace(/^\./, "");
96
+ switch (e) {
97
+ case "parquet":
98
+ return "parquet";
99
+ case "arrow":
100
+ case "ipc":
101
+ case "feather":
102
+ return "arrow";
103
+ case "csv":
104
+ return "csv";
105
+ case "csvw":
106
+ case "csv-metadata":
107
+ return "csvw";
108
+ case "json-stat":
109
+ case "jsonstat":
110
+ return "jsonstat";
111
+ case "json":
112
+ return "jsonstat";
113
+ // assume JSON-stat by default for .json
114
+ default:
115
+ return "unknown";
116
+ }
117
+ }
118
+ function extensionOf(path) {
119
+ const clean = path.split("?")[0]?.split("#")[0] ?? path;
120
+ const dot = clean.lastIndexOf(".");
121
+ const slash = Math.max(clean.lastIndexOf("/"), clean.lastIndexOf("\\"));
122
+ if (dot === -1 || dot < slash) return void 0;
123
+ return clean.slice(dot + 1);
124
+ }
125
+ function detectFormat(pathOrUrl, bytes) {
126
+ if (pathOrUrl) {
127
+ const ext = extensionOf(pathOrUrl);
128
+ if (ext) {
129
+ const byExt = detectFromExtension(ext);
130
+ if (byExt !== "unknown") return byExt;
131
+ }
132
+ }
133
+ if (bytes) return detectFromBytes(bytes);
134
+ return "unknown";
135
+ }
136
+
137
+ // src/util/density.ts
138
+ function decideDensity(values, requested = "auto", options = {}) {
139
+ const total = values.length;
140
+ const threshold = options.threshold ?? 0.5;
141
+ let nullCount = 0;
142
+ for (const v of values) {
143
+ if (v === null) nullCount++;
144
+ }
145
+ const nullRatio = total === 0 ? 0 : nullCount / total;
146
+ let form;
147
+ if (requested === "dense") form = "dense";
148
+ else if (requested === "sparse") form = "sparse";
149
+ else form = nullRatio > threshold ? "sparse" : "dense";
150
+ return { form, nullRatio, nullCount, total };
151
+ }
152
+
153
+ // src/util/fetch.ts
154
+ function isNode() {
155
+ return typeof process !== "undefined" && typeof process.versions !== "undefined" && typeof process.versions.node === "string";
156
+ }
157
+ async function loadInput(source) {
158
+ if (source instanceof Uint8Array) {
159
+ return { bytes: source };
160
+ }
161
+ if (typeof Blob !== "undefined" && source instanceof Blob) {
162
+ const buf = await source.arrayBuffer();
163
+ return { bytes: new Uint8Array(buf), source: source.name };
164
+ }
165
+ if (typeof source !== "string") {
166
+ throw new TypeError(`loadInput: unsupported source type ${typeof source}`);
167
+ }
168
+ if (source === "-") {
169
+ if (!isNode()) {
170
+ throw new Error('loadInput: stdin ("-") is only supported in Node');
171
+ }
172
+ const bytes = await readStdin();
173
+ return { bytes, fromStdin: true };
174
+ }
175
+ if (/^https?:\/\//i.test(source) || /^file:\/\//i.test(source)) {
176
+ const res = await fetch(source);
177
+ if (!res.ok) {
178
+ throw new Error(`loadInput: fetch ${source} failed: ${res.status} ${res.statusText}`);
179
+ }
180
+ const buf = await res.arrayBuffer();
181
+ return { bytes: new Uint8Array(buf), source };
182
+ }
183
+ if (isNode()) {
184
+ const bytes = await readFileNode(source);
185
+ return { bytes, source };
186
+ }
187
+ throw new Error(
188
+ `loadInput: cannot resolve "${source}" in a browser without a URL scheme`
189
+ );
190
+ }
191
+ async function readStdin() {
192
+ const chunks = [];
193
+ for await (const chunk of process.stdin) {
194
+ chunks.push(chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk));
195
+ }
196
+ const total = chunks.reduce((n, c) => n + c.length, 0);
197
+ const out = new Uint8Array(total);
198
+ let off = 0;
199
+ for (const c of chunks) {
200
+ out.set(c, off);
201
+ off += c.length;
202
+ }
203
+ return out;
204
+ }
205
+ async function readFileNode(path) {
206
+ const { readFile } = await import('fs/promises');
207
+ const buf = await readFile(path);
208
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
209
+ }
210
+ var ImporterError = class extends Error {
211
+ constructor(message) {
212
+ super(message);
213
+ this.name = "ImporterError";
214
+ }
215
+ };
216
+ async function importToCube(source, options = {}) {
217
+ const loaded = await loadInput(source);
218
+ let format;
219
+ if (options.from && options.from !== "auto") {
220
+ format = options.from;
221
+ } else if (loaded.source) {
222
+ format = detectFormat(loaded.source, loaded.bytes);
223
+ } else {
224
+ format = detectFromBytes(loaded.bytes);
225
+ }
226
+ switch (format) {
227
+ case "arrow": {
228
+ const table = apacheArrow.tableFromIPC(loaded.bytes);
229
+ return chunkPHLCWTHB_cjs.arrowToCube(table, options);
230
+ }
231
+ case "parquet": {
232
+ const { parquetToCube } = await import('./sources/parquet.cjs');
233
+ return parquetToCube(loaded.bytes, options);
234
+ }
235
+ case "csv": {
236
+ const { csvToCube } = await import('./sources/csv.cjs');
237
+ const text = new TextDecoder().decode(loaded.bytes);
238
+ return csvToCube(text, {
239
+ measure: options.measure,
240
+ dimensions: options.dimensions,
241
+ status: options.status,
242
+ roles: options.roles,
243
+ delimiter: options.delimiter
244
+ });
245
+ }
246
+ case "csvw": {
247
+ const { csvwToCube, parseCsvwMetadata } = await import('./sources/csvw.cjs');
248
+ const text = new TextDecoder().decode(loaded.bytes);
249
+ let metadata;
250
+ if (options.csvwMetadata !== void 0) {
251
+ metadata = parseCsvwMetadata(options.csvwMetadata);
252
+ } else if (loaded.source) {
253
+ try {
254
+ const metaPath = siblingMetadataPath(loaded.source);
255
+ const metaBytes = await loadInput(metaPath);
256
+ metadata = parseCsvwMetadata(
257
+ JSON.parse(new TextDecoder().decode(metaBytes.bytes))
258
+ );
259
+ } catch {
260
+ throw new ImporterError(
261
+ `CSVW metadata not supplied and could not be auto-loaded next to "${loaded.source}". Pass options.csvwMetadata or set options.from = "csv".`
262
+ );
263
+ }
264
+ }
265
+ if (metadata === void 0) {
266
+ throw new ImporterError(
267
+ "CSVW source requires metadata. Pass options.csvwMetadata."
268
+ );
269
+ }
270
+ return csvwToCube(text, metadata, {
271
+ measure: options.measure,
272
+ dimensions: options.dimensions,
273
+ status: options.status,
274
+ roles: options.roles
275
+ });
276
+ }
277
+ case "jsonstat":
278
+ case "json": {
279
+ const { readDataset: readDataset2 } = await import('./cubeReader-UN2BHQWK.cjs');
280
+ const parsed = JSON.parse(new TextDecoder().decode(loaded.bytes));
281
+ return readDataset2(parsed, { dropNulls: false });
282
+ }
283
+ default:
284
+ throw new ImporterError(
285
+ `Could not detect the source format. Set options.from explicitly (e.g. "parquet", "arrow", "csv", "csvw", "jsonstat"). DuckDB and Polars require a live connection/DataFrame \u2014 use the dedicated subpath import (e.g. import { duckdbToCube } from "jsonstat-io/duckdb").`
286
+ );
287
+ }
288
+ }
289
+ async function importToDataset(source, options = {}) {
290
+ const obs = await importToCube(source, options);
291
+ const result = chunkGDKDYLZ4_cjs.buildDataset(obs, options.build);
292
+ return result.dataset;
293
+ }
294
+ function siblingMetadataPath(csvPath) {
295
+ const dot = csvPath.lastIndexOf(".");
296
+ const base = dot > 0 ? csvPath.slice(0, dot) : csvPath;
297
+ return `${base}-metadata.json`;
298
+ }
299
+ async function exportDataset(dataset, options) {
300
+ const { readDataset: readDataset2 } = await import('./cubeReader-UN2BHQWK.cjs');
301
+ const obs = readDataset2(dataset, { dropNulls: false });
302
+ switch (options.to) {
303
+ case "arrow": {
304
+ return chunkPHLCWTHB_cjs.cubeToArrow(obs);
305
+ }
306
+ case "parquet": {
307
+ const { cubeToParquet } = await import('./sources/parquet.cjs');
308
+ return cubeToParquet(obs, {
309
+ init: options.init,
310
+ compression: options.compression
311
+ });
312
+ }
313
+ case "csv": {
314
+ const { cubeToCsv } = await import('./sources/csv.cjs');
315
+ return cubeToCsv(obs, {
316
+ delimiter: options.delimiter,
317
+ lineTerminator: options.lineTerminator
318
+ });
319
+ }
320
+ case "csvw": {
321
+ const { cubeToCsvw } = await import('./sources/csvw.cjs');
322
+ return cubeToCsvw(obs, {
323
+ delimiter: options.delimiter,
324
+ lineTerminator: options.lineTerminator,
325
+ url: options.url
326
+ });
327
+ }
328
+ default:
329
+ throw new ImporterError(
330
+ `Unsupported export target "${options.to}". Use one of: "arrow", "parquet", "csv", "csvw". For DuckDB/Polars, use the dedicated subpath writers.`
331
+ );
332
+ }
333
+ }
334
+
335
+ exports.ImporterError = ImporterError;
336
+ exports.decideDensity = decideDensity;
337
+ exports.detectFormat = detectFormat;
338
+ exports.detectFromBytes = detectFromBytes;
339
+ exports.detectFromExtension = detectFromExtension;
340
+ exports.exportDataset = exportDataset;
341
+ exports.extensionOf = extensionOf;
342
+ exports.importToCube = importToCube;
343
+ exports.importToDataset = importToDataset;
344
+ exports.isCollection = isCollection;
345
+ exports.isDataset = isDataset;
346
+ exports.isDimensionResponse = isDimensionResponse;
347
+ exports.loadInput = loadInput;
348
+ exports.observationCount = observationCount;
349
+ exports.serialize = serialize;
350
+ exports.serializeToBytes = serializeToBytes;
351
+ //# sourceMappingURL=chunk-AXUZF6O5.cjs.map
352
+ //# sourceMappingURL=chunk-AXUZF6O5.cjs.map