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.
- package/LICENSE +201 -0
- package/README.md +200 -0
- package/dist/arrow/index.cjs +60 -0
- package/dist/arrow/index.cjs.map +1 -0
- package/dist/arrow/index.d.cts +125 -0
- package/dist/arrow/index.d.ts +125 -0
- package/dist/arrow/index.js +3 -0
- package/dist/arrow/index.js.map +1 -0
- package/dist/arrowToCube-BdRWZ5oG.d.cts +29 -0
- package/dist/arrowToCube-Mjr79ZHM.d.ts +29 -0
- package/dist/chunk-2HY7NRKX.js +259 -0
- package/dist/chunk-2HY7NRKX.js.map +1 -0
- package/dist/chunk-62NIY7ML.js +191 -0
- package/dist/chunk-62NIY7ML.js.map +1 -0
- package/dist/chunk-AXUZF6O5.cjs +352 -0
- package/dist/chunk-AXUZF6O5.cjs.map +1 -0
- package/dist/chunk-EFRDFQOT.js +335 -0
- package/dist/chunk-EFRDFQOT.js.map +1 -0
- package/dist/chunk-GDKDYLZ4.cjs +263 -0
- package/dist/chunk-GDKDYLZ4.cjs.map +1 -0
- package/dist/chunk-IDTQZG4B.js +432 -0
- package/dist/chunk-IDTQZG4B.js.map +1 -0
- package/dist/chunk-KFIKGBIJ.cjs +200 -0
- package/dist/chunk-KFIKGBIJ.cjs.map +1 -0
- package/dist/chunk-L65CRXTV.js +64 -0
- package/dist/chunk-L65CRXTV.js.map +1 -0
- package/dist/chunk-PHLCWTHB.cjs +446 -0
- package/dist/chunk-PHLCWTHB.cjs.map +1 -0
- package/dist/chunk-VQCS4LVD.cjs +166 -0
- package/dist/chunk-VQCS4LVD.cjs.map +1 -0
- package/dist/chunk-VYS7DPB3.js +162 -0
- package/dist/chunk-VYS7DPB3.js.map +1 -0
- package/dist/chunk-ZEDTWRDN.cjs +70 -0
- package/dist/chunk-ZEDTWRDN.cjs.map +1 -0
- package/dist/cli/index.cjs +337 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +90 -0
- package/dist/cli/index.d.ts +90 -0
- package/dist/cli/index.js +333 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cubeBuilder-BEGA4C5Y.js +4 -0
- package/dist/cubeBuilder-BEGA4C5Y.js.map +1 -0
- package/dist/cubeBuilder-ZU76VVEX.cjs +25 -0
- package/dist/cubeBuilder-ZU76VVEX.cjs.map +1 -0
- package/dist/cubeReader-7QVUF3TI.js +4 -0
- package/dist/cubeReader-7QVUF3TI.js.map +1 -0
- package/dist/cubeReader-UN2BHQWK.cjs +21 -0
- package/dist/cubeReader-UN2BHQWK.cjs.map +1 -0
- package/dist/index.cjs +172 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +445 -0
- package/dist/index.d.ts +445 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/ir-BArfNxo-.d.cts +143 -0
- package/dist/ir-Jae2ymov.d.ts +143 -0
- package/dist/jsonstat-BX4mBLci.d.cts +179 -0
- package/dist/jsonstat-BX4mBLci.d.ts +179 -0
- package/dist/sources/csv.cjs +40 -0
- package/dist/sources/csv.cjs.map +1 -0
- package/dist/sources/csv.d.cts +112 -0
- package/dist/sources/csv.d.ts +112 -0
- package/dist/sources/csv.js +3 -0
- package/dist/sources/csv.js.map +1 -0
- package/dist/sources/csvw.cjs +236 -0
- package/dist/sources/csvw.cjs.map +1 -0
- package/dist/sources/csvw.d.cts +143 -0
- package/dist/sources/csvw.d.ts +143 -0
- package/dist/sources/csvw.js +230 -0
- package/dist/sources/csvw.js.map +1 -0
- package/dist/sources/duckdb.cjs +121 -0
- package/dist/sources/duckdb.cjs.map +1 -0
- package/dist/sources/duckdb.d.cts +111 -0
- package/dist/sources/duckdb.d.ts +111 -0
- package/dist/sources/duckdb.js +115 -0
- package/dist/sources/duckdb.js.map +1 -0
- package/dist/sources/parquet.cjs +117 -0
- package/dist/sources/parquet.cjs.map +1 -0
- package/dist/sources/parquet.d.cts +83 -0
- package/dist/sources/parquet.d.ts +83 -0
- package/dist/sources/parquet.js +111 -0
- package/dist/sources/parquet.js.map +1 -0
- package/dist/sources/polars.cjs +94 -0
- package/dist/sources/polars.cjs.map +1 -0
- package/dist/sources/polars.d.cts +91 -0
- package/dist/sources/polars.d.ts +91 -0
- package/dist/sources/polars.js +87 -0
- package/dist/sources/polars.js.map +1 -0
- package/docs/api.md +322 -0
- package/docs/architecture.md +140 -0
- package/docs/cli.md +159 -0
- package/docs/formats/arrow.md +111 -0
- package/docs/formats/csv.md +115 -0
- package/docs/formats/csvw.md +152 -0
- package/docs/formats/duckdb.md +151 -0
- package/docs/formats/parquet.md +132 -0
- package/docs/formats/polars.md +111 -0
- package/docs/mapping.md +136 -0
- package/package.json +119 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { a as JsonStatRole, b as JsonStatUnit } from './jsonstat-BX4mBLci.js';
|
|
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 };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-stat 2.0 type model.
|
|
3
|
+
*
|
|
4
|
+
* Faithful TypeScript representation of the JSON-stat 2.0 format, derived from
|
|
5
|
+
* the official specification (raw/fullspec.html) and the vendored JSON Schemas
|
|
6
|
+
* (raw/schema/{index,dataset,collection,dimension}.json).
|
|
7
|
+
*
|
|
8
|
+
* These are *structural* types: they describe the wire format. Cross-field
|
|
9
|
+
* cube invariants (e.g. `value.length === size.reduce(product)`) live in the
|
|
10
|
+
* core engine, mirroring how the official JSON Schemas defer semantic checks
|
|
11
|
+
* to jsonstat-validator (see wiki/validator.md and wiki/schema.md).
|
|
12
|
+
*/
|
|
13
|
+
/** Allowed JSON-stat response classes (see wiki/response-classes.md). */
|
|
14
|
+
type JsonStatClass = "dataset" | "dimension" | "collection" | "bundle" | "error";
|
|
15
|
+
/** Semantic role assigned to one or more dimension IDs (see wiki/dimensions.md). */
|
|
16
|
+
interface JsonStatRole {
|
|
17
|
+
/** Dimension IDs carrying temporal data (chronological order assumed). */
|
|
18
|
+
time?: string[];
|
|
19
|
+
/** Dimension IDs carrying spatial data (categories may have coordinates). */
|
|
20
|
+
geo?: string[];
|
|
21
|
+
/** Dimension IDs carrying different metrics/measures (units attached). */
|
|
22
|
+
metric?: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Unit of measure metadata for a metric-role category (see wiki/dimensions.md). */
|
|
25
|
+
interface JsonStatUnit {
|
|
26
|
+
/** Required when `unit` is present: number of decimals. */
|
|
27
|
+
decimals: number;
|
|
28
|
+
/** Unit text displayed after (or before) the value. */
|
|
29
|
+
label?: string;
|
|
30
|
+
/** Unit symbol, e.g. "$" or "%". */
|
|
31
|
+
symbol?: string;
|
|
32
|
+
/** Where the symbol goes relative to the value. Defaults to "end". */
|
|
33
|
+
position?: "start" | "end";
|
|
34
|
+
}
|
|
35
|
+
/** [longitude, latitude] pair for geo-role categories. */
|
|
36
|
+
type Coordinates = [longitude: number, latitude: number];
|
|
37
|
+
/**
|
|
38
|
+
* Category block of a dimension.
|
|
39
|
+
*
|
|
40
|
+
* `index` may be an array (IDs in order) or an object (ID→position map). For
|
|
41
|
+
* constant (single-category) dimensions `index` is unnecessary provided a
|
|
42
|
+
* `label` is given. `label` is optional and falls back to category IDs.
|
|
43
|
+
*/
|
|
44
|
+
interface JsonStatCategory {
|
|
45
|
+
/** Category ordering. Array form: `["M","F","T"]`. Object form: `{"M":0,...}`. */
|
|
46
|
+
index?: string[] | Record<string, number>;
|
|
47
|
+
/** ID→human-readable label map. If omitted, IDs are used as labels. */
|
|
48
|
+
label?: Record<string, string>;
|
|
49
|
+
/** Parent ID → array of direct-child IDs (hierarchies; see wiki/dimensions.md). */
|
|
50
|
+
child?: Record<string, string[]>;
|
|
51
|
+
/** ID → [lon, lat] for geo-role categories. */
|
|
52
|
+
coordinates?: Record<string, Coordinates>;
|
|
53
|
+
/** ID → unit metadata for metric-role categories. */
|
|
54
|
+
unit?: Record<string, JsonStatUnit>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A dimension object within `dimension`.
|
|
58
|
+
*
|
|
59
|
+
* `category` is the only required property in practice for the dimension
|
|
60
|
+
* class; for dataset-class dimensions it is always present.
|
|
61
|
+
*/
|
|
62
|
+
interface JsonStatDimension {
|
|
63
|
+
/** Short descriptive text (lowercase recommended). */
|
|
64
|
+
label?: string;
|
|
65
|
+
/** The categories of this dimension. */
|
|
66
|
+
category?: JsonStatCategory;
|
|
67
|
+
/** URL to an external dimension definition. */
|
|
68
|
+
href?: string;
|
|
69
|
+
/** Provider-specific extension data. */
|
|
70
|
+
extension?: Record<string, unknown>;
|
|
71
|
+
/** Related resources (see wiki/links.md). */
|
|
72
|
+
link?: JsonStatLink[];
|
|
73
|
+
/** Annotations. */
|
|
74
|
+
note?: string[];
|
|
75
|
+
}
|
|
76
|
+
/** A single link entry. `rel` is an IANA link relation (e.g. "item", "self"). */
|
|
77
|
+
interface JsonStatLink {
|
|
78
|
+
/** IANA link relation type. */
|
|
79
|
+
rel?: string;
|
|
80
|
+
/** Target URL. */
|
|
81
|
+
href?: string;
|
|
82
|
+
/** Type of the linked resource (e.g. a class value). */
|
|
83
|
+
type?: string;
|
|
84
|
+
/** Human-readable label. */
|
|
85
|
+
label?: string;
|
|
86
|
+
/** When present, the item is embedded inline rather than referenced by href. */
|
|
87
|
+
[embedded: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
/** Container for links, indexed by relation. The "item" relation holds an array. */
|
|
90
|
+
interface JsonStatLinkMap {
|
|
91
|
+
[rel: string]: JsonStatLink[] | undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Observation-level status. Three forms:
|
|
95
|
+
* - array: one status code per cell (aligned with `value`)
|
|
96
|
+
* - string: a single status applied to all cells
|
|
97
|
+
* - object: position→status for specific cells (sparse status)
|
|
98
|
+
*
|
|
99
|
+
* Status has no standard vocabulary — it is provider-defined.
|
|
100
|
+
*/
|
|
101
|
+
type JsonStatStatus = string[] | string | Record<string, string>;
|
|
102
|
+
/**
|
|
103
|
+
* Cell values in row-major order ("what does not change, first"; the last
|
|
104
|
+
* dimension in `id` changes fastest).
|
|
105
|
+
*
|
|
106
|
+
* - Array form (dense): missing values are `null`.
|
|
107
|
+
* - Object form (sparse): maps flat position index → value, omitting nulls.
|
|
108
|
+
*/
|
|
109
|
+
type JsonStatValue = (number | null)[] | Record<string, number>;
|
|
110
|
+
/** Top-level dataset response (see wiki/response-classes.md). */
|
|
111
|
+
interface JsonStatDataset {
|
|
112
|
+
version: "2.0";
|
|
113
|
+
class: "dataset";
|
|
114
|
+
/** Short descriptive text. */
|
|
115
|
+
label?: string;
|
|
116
|
+
/** Short text describing the dataset source. */
|
|
117
|
+
source?: string;
|
|
118
|
+
/** Update time in ISO 8601. */
|
|
119
|
+
updated?: string;
|
|
120
|
+
/** Ordered list of dimension IDs. */
|
|
121
|
+
id: string[];
|
|
122
|
+
/** Number of categories per dimension, same order as `id`. */
|
|
123
|
+
size: number[];
|
|
124
|
+
/** Per-dimension metadata, keyed by dimension ID. */
|
|
125
|
+
dimension: Record<string, JsonStatDimension>;
|
|
126
|
+
/** Cell values (dense or sparse). */
|
|
127
|
+
value: JsonStatValue;
|
|
128
|
+
/** Observation-level status metadata. */
|
|
129
|
+
status?: JsonStatStatus;
|
|
130
|
+
/** Semantic roles for dimensions. */
|
|
131
|
+
role?: JsonStatRole;
|
|
132
|
+
/** Provider-specific extension data. */
|
|
133
|
+
extension?: Record<string, unknown>;
|
|
134
|
+
/** Related resources. */
|
|
135
|
+
link?: JsonStatLinkMap;
|
|
136
|
+
/** Annotations. */
|
|
137
|
+
note?: string[];
|
|
138
|
+
/** URL of the dataset. */
|
|
139
|
+
href?: string;
|
|
140
|
+
/** Optional error array (suggested, not mandatory). */
|
|
141
|
+
error?: JsonStatError[];
|
|
142
|
+
}
|
|
143
|
+
/** Dimension-only response. */
|
|
144
|
+
interface JsonStatDimensionResponse {
|
|
145
|
+
version: "2.0";
|
|
146
|
+
class: "dimension";
|
|
147
|
+
label?: string;
|
|
148
|
+
category: JsonStatCategory;
|
|
149
|
+
extension?: Record<string, unknown>;
|
|
150
|
+
link?: JsonStatLinkMap;
|
|
151
|
+
href?: string;
|
|
152
|
+
}
|
|
153
|
+
/** Collection response (2.0 replacement for bundles). */
|
|
154
|
+
interface JsonStatCollection {
|
|
155
|
+
version: "2.0";
|
|
156
|
+
class: "collection";
|
|
157
|
+
href?: string;
|
|
158
|
+
label?: string;
|
|
159
|
+
updated?: string;
|
|
160
|
+
link: JsonStatLinkMap;
|
|
161
|
+
extension?: Record<string, unknown>;
|
|
162
|
+
}
|
|
163
|
+
/** A proposed (not mandatory) error entry. */
|
|
164
|
+
interface JsonStatError {
|
|
165
|
+
status?: number;
|
|
166
|
+
id?: string;
|
|
167
|
+
href?: string;
|
|
168
|
+
label?: string;
|
|
169
|
+
}
|
|
170
|
+
/** Any top-level JSON-stat 2.0 response. */
|
|
171
|
+
type JsonStatResponse = JsonStatDataset | JsonStatDimensionResponse | JsonStatCollection;
|
|
172
|
+
/** Discriminated union guard helper: is this a dataset response? */
|
|
173
|
+
declare function isDataset(r: JsonStatResponse): r is JsonStatDataset;
|
|
174
|
+
/** Discriminated union guard helper: is this a collection response? */
|
|
175
|
+
declare function isCollection(r: JsonStatResponse): r is JsonStatCollection;
|
|
176
|
+
/** Discriminated union guard helper: is this a dimension response? */
|
|
177
|
+
declare function isDimensionResponse(r: JsonStatResponse): r is JsonStatDimensionResponse;
|
|
178
|
+
|
|
179
|
+
export { type Coordinates as C, type JsonStatDataset as J, type JsonStatRole as a, type JsonStatUnit as b, type JsonStatResponse as c, type JsonStatCategory as d, type JsonStatClass as e, type JsonStatCollection as f, type JsonStatDimension as g, type JsonStatDimensionResponse as h, type JsonStatError as i, type JsonStatLink as j, type JsonStatLinkMap as k, type JsonStatStatus as l, type JsonStatValue as m, isCollection as n, isDataset as o, isDimensionResponse as p };
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-stat 2.0 type model.
|
|
3
|
+
*
|
|
4
|
+
* Faithful TypeScript representation of the JSON-stat 2.0 format, derived from
|
|
5
|
+
* the official specification (raw/fullspec.html) and the vendored JSON Schemas
|
|
6
|
+
* (raw/schema/{index,dataset,collection,dimension}.json).
|
|
7
|
+
*
|
|
8
|
+
* These are *structural* types: they describe the wire format. Cross-field
|
|
9
|
+
* cube invariants (e.g. `value.length === size.reduce(product)`) live in the
|
|
10
|
+
* core engine, mirroring how the official JSON Schemas defer semantic checks
|
|
11
|
+
* to jsonstat-validator (see wiki/validator.md and wiki/schema.md).
|
|
12
|
+
*/
|
|
13
|
+
/** Allowed JSON-stat response classes (see wiki/response-classes.md). */
|
|
14
|
+
type JsonStatClass = "dataset" | "dimension" | "collection" | "bundle" | "error";
|
|
15
|
+
/** Semantic role assigned to one or more dimension IDs (see wiki/dimensions.md). */
|
|
16
|
+
interface JsonStatRole {
|
|
17
|
+
/** Dimension IDs carrying temporal data (chronological order assumed). */
|
|
18
|
+
time?: string[];
|
|
19
|
+
/** Dimension IDs carrying spatial data (categories may have coordinates). */
|
|
20
|
+
geo?: string[];
|
|
21
|
+
/** Dimension IDs carrying different metrics/measures (units attached). */
|
|
22
|
+
metric?: string[];
|
|
23
|
+
}
|
|
24
|
+
/** Unit of measure metadata for a metric-role category (see wiki/dimensions.md). */
|
|
25
|
+
interface JsonStatUnit {
|
|
26
|
+
/** Required when `unit` is present: number of decimals. */
|
|
27
|
+
decimals: number;
|
|
28
|
+
/** Unit text displayed after (or before) the value. */
|
|
29
|
+
label?: string;
|
|
30
|
+
/** Unit symbol, e.g. "$" or "%". */
|
|
31
|
+
symbol?: string;
|
|
32
|
+
/** Where the symbol goes relative to the value. Defaults to "end". */
|
|
33
|
+
position?: "start" | "end";
|
|
34
|
+
}
|
|
35
|
+
/** [longitude, latitude] pair for geo-role categories. */
|
|
36
|
+
type Coordinates = [longitude: number, latitude: number];
|
|
37
|
+
/**
|
|
38
|
+
* Category block of a dimension.
|
|
39
|
+
*
|
|
40
|
+
* `index` may be an array (IDs in order) or an object (ID→position map). For
|
|
41
|
+
* constant (single-category) dimensions `index` is unnecessary provided a
|
|
42
|
+
* `label` is given. `label` is optional and falls back to category IDs.
|
|
43
|
+
*/
|
|
44
|
+
interface JsonStatCategory {
|
|
45
|
+
/** Category ordering. Array form: `["M","F","T"]`. Object form: `{"M":0,...}`. */
|
|
46
|
+
index?: string[] | Record<string, number>;
|
|
47
|
+
/** ID→human-readable label map. If omitted, IDs are used as labels. */
|
|
48
|
+
label?: Record<string, string>;
|
|
49
|
+
/** Parent ID → array of direct-child IDs (hierarchies; see wiki/dimensions.md). */
|
|
50
|
+
child?: Record<string, string[]>;
|
|
51
|
+
/** ID → [lon, lat] for geo-role categories. */
|
|
52
|
+
coordinates?: Record<string, Coordinates>;
|
|
53
|
+
/** ID → unit metadata for metric-role categories. */
|
|
54
|
+
unit?: Record<string, JsonStatUnit>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A dimension object within `dimension`.
|
|
58
|
+
*
|
|
59
|
+
* `category` is the only required property in practice for the dimension
|
|
60
|
+
* class; for dataset-class dimensions it is always present.
|
|
61
|
+
*/
|
|
62
|
+
interface JsonStatDimension {
|
|
63
|
+
/** Short descriptive text (lowercase recommended). */
|
|
64
|
+
label?: string;
|
|
65
|
+
/** The categories of this dimension. */
|
|
66
|
+
category?: JsonStatCategory;
|
|
67
|
+
/** URL to an external dimension definition. */
|
|
68
|
+
href?: string;
|
|
69
|
+
/** Provider-specific extension data. */
|
|
70
|
+
extension?: Record<string, unknown>;
|
|
71
|
+
/** Related resources (see wiki/links.md). */
|
|
72
|
+
link?: JsonStatLink[];
|
|
73
|
+
/** Annotations. */
|
|
74
|
+
note?: string[];
|
|
75
|
+
}
|
|
76
|
+
/** A single link entry. `rel` is an IANA link relation (e.g. "item", "self"). */
|
|
77
|
+
interface JsonStatLink {
|
|
78
|
+
/** IANA link relation type. */
|
|
79
|
+
rel?: string;
|
|
80
|
+
/** Target URL. */
|
|
81
|
+
href?: string;
|
|
82
|
+
/** Type of the linked resource (e.g. a class value). */
|
|
83
|
+
type?: string;
|
|
84
|
+
/** Human-readable label. */
|
|
85
|
+
label?: string;
|
|
86
|
+
/** When present, the item is embedded inline rather than referenced by href. */
|
|
87
|
+
[embedded: string]: unknown;
|
|
88
|
+
}
|
|
89
|
+
/** Container for links, indexed by relation. The "item" relation holds an array. */
|
|
90
|
+
interface JsonStatLinkMap {
|
|
91
|
+
[rel: string]: JsonStatLink[] | undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Observation-level status. Three forms:
|
|
95
|
+
* - array: one status code per cell (aligned with `value`)
|
|
96
|
+
* - string: a single status applied to all cells
|
|
97
|
+
* - object: position→status for specific cells (sparse status)
|
|
98
|
+
*
|
|
99
|
+
* Status has no standard vocabulary — it is provider-defined.
|
|
100
|
+
*/
|
|
101
|
+
type JsonStatStatus = string[] | string | Record<string, string>;
|
|
102
|
+
/**
|
|
103
|
+
* Cell values in row-major order ("what does not change, first"; the last
|
|
104
|
+
* dimension in `id` changes fastest).
|
|
105
|
+
*
|
|
106
|
+
* - Array form (dense): missing values are `null`.
|
|
107
|
+
* - Object form (sparse): maps flat position index → value, omitting nulls.
|
|
108
|
+
*/
|
|
109
|
+
type JsonStatValue = (number | null)[] | Record<string, number>;
|
|
110
|
+
/** Top-level dataset response (see wiki/response-classes.md). */
|
|
111
|
+
interface JsonStatDataset {
|
|
112
|
+
version: "2.0";
|
|
113
|
+
class: "dataset";
|
|
114
|
+
/** Short descriptive text. */
|
|
115
|
+
label?: string;
|
|
116
|
+
/** Short text describing the dataset source. */
|
|
117
|
+
source?: string;
|
|
118
|
+
/** Update time in ISO 8601. */
|
|
119
|
+
updated?: string;
|
|
120
|
+
/** Ordered list of dimension IDs. */
|
|
121
|
+
id: string[];
|
|
122
|
+
/** Number of categories per dimension, same order as `id`. */
|
|
123
|
+
size: number[];
|
|
124
|
+
/** Per-dimension metadata, keyed by dimension ID. */
|
|
125
|
+
dimension: Record<string, JsonStatDimension>;
|
|
126
|
+
/** Cell values (dense or sparse). */
|
|
127
|
+
value: JsonStatValue;
|
|
128
|
+
/** Observation-level status metadata. */
|
|
129
|
+
status?: JsonStatStatus;
|
|
130
|
+
/** Semantic roles for dimensions. */
|
|
131
|
+
role?: JsonStatRole;
|
|
132
|
+
/** Provider-specific extension data. */
|
|
133
|
+
extension?: Record<string, unknown>;
|
|
134
|
+
/** Related resources. */
|
|
135
|
+
link?: JsonStatLinkMap;
|
|
136
|
+
/** Annotations. */
|
|
137
|
+
note?: string[];
|
|
138
|
+
/** URL of the dataset. */
|
|
139
|
+
href?: string;
|
|
140
|
+
/** Optional error array (suggested, not mandatory). */
|
|
141
|
+
error?: JsonStatError[];
|
|
142
|
+
}
|
|
143
|
+
/** Dimension-only response. */
|
|
144
|
+
interface JsonStatDimensionResponse {
|
|
145
|
+
version: "2.0";
|
|
146
|
+
class: "dimension";
|
|
147
|
+
label?: string;
|
|
148
|
+
category: JsonStatCategory;
|
|
149
|
+
extension?: Record<string, unknown>;
|
|
150
|
+
link?: JsonStatLinkMap;
|
|
151
|
+
href?: string;
|
|
152
|
+
}
|
|
153
|
+
/** Collection response (2.0 replacement for bundles). */
|
|
154
|
+
interface JsonStatCollection {
|
|
155
|
+
version: "2.0";
|
|
156
|
+
class: "collection";
|
|
157
|
+
href?: string;
|
|
158
|
+
label?: string;
|
|
159
|
+
updated?: string;
|
|
160
|
+
link: JsonStatLinkMap;
|
|
161
|
+
extension?: Record<string, unknown>;
|
|
162
|
+
}
|
|
163
|
+
/** A proposed (not mandatory) error entry. */
|
|
164
|
+
interface JsonStatError {
|
|
165
|
+
status?: number;
|
|
166
|
+
id?: string;
|
|
167
|
+
href?: string;
|
|
168
|
+
label?: string;
|
|
169
|
+
}
|
|
170
|
+
/** Any top-level JSON-stat 2.0 response. */
|
|
171
|
+
type JsonStatResponse = JsonStatDataset | JsonStatDimensionResponse | JsonStatCollection;
|
|
172
|
+
/** Discriminated union guard helper: is this a dataset response? */
|
|
173
|
+
declare function isDataset(r: JsonStatResponse): r is JsonStatDataset;
|
|
174
|
+
/** Discriminated union guard helper: is this a collection response? */
|
|
175
|
+
declare function isCollection(r: JsonStatResponse): r is JsonStatCollection;
|
|
176
|
+
/** Discriminated union guard helper: is this a dimension response? */
|
|
177
|
+
declare function isDimensionResponse(r: JsonStatResponse): r is JsonStatDimensionResponse;
|
|
178
|
+
|
|
179
|
+
export { type Coordinates as C, type JsonStatDataset as J, type JsonStatRole as a, type JsonStatUnit as b, type JsonStatResponse as c, type JsonStatCategory as d, type JsonStatClass as e, type JsonStatCollection as f, type JsonStatDimension as g, type JsonStatDimensionResponse as h, type JsonStatError as i, type JsonStatLink as j, type JsonStatLinkMap as k, type JsonStatStatus as l, type JsonStatValue as m, isCollection as n, isDataset as o, isDimensionResponse as p };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkKFIKGBIJ_cjs = require('../chunk-KFIKGBIJ.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "CsvSourceError", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkKFIKGBIJ_cjs.CsvSourceError; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "csvToCube", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkKFIKGBIJ_cjs.csvToCube; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "csvToDataset", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkKFIKGBIJ_cjs.csvToDataset; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "cubeColumns", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkKFIKGBIJ_cjs.cubeColumns; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, "cubeToCsv", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return chunkKFIKGBIJ_cjs.cubeToCsv; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "parseCsv", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return chunkKFIKGBIJ_cjs.parseCsv; }
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, "quoteCsvField", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return chunkKFIKGBIJ_cjs.quoteCsvField; }
|
|
34
|
+
});
|
|
35
|
+
Object.defineProperty(exports, "serializeRows", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () { return chunkKFIKGBIJ_cjs.serializeRows; }
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=csv.cjs.map
|
|
40
|
+
//# sourceMappingURL=csv.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"csv.cjs"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { R as RoleMap, O as Observations } from '../ir-BArfNxo-.cjs';
|
|
2
|
+
import { J as JsonStatDataset } from '../jsonstat-BX4mBLci.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* CSV adapter — `jsonstat-io/csv`.
|
|
6
|
+
*
|
|
7
|
+
* **Import:** unlike Parquet/DuckDB/Polars (which funnel through the Arrow
|
|
8
|
+
* hub), plain CSV has no native Arrow producer in this package, so this adapter
|
|
9
|
+
* builds the [`Observations`](../model/ir.ts) IR **directly** from parsed rows.
|
|
10
|
+
*
|
|
11
|
+
* **Export:** [`cubeToCsv`] writes the [`Observations`] IR to RFC-4180-style
|
|
12
|
+
* CSV text (dimension columns + measure column + optional status column).
|
|
13
|
+
*
|
|
14
|
+
* ## Mapping heuristics (no metadata)
|
|
15
|
+
*
|
|
16
|
+
* Without a schema, the adapter infers:
|
|
17
|
+
* - The **measure** is the first column that parses as a number for every
|
|
18
|
+
* non-empty row (or the one named by `options.measure`).
|
|
19
|
+
* - Every other column is a **dimension** (string-typed), in file order.
|
|
20
|
+
* - A column named `status` (case-insensitive) is treated as the status
|
|
21
|
+
* column unless `options.status` overrides it.
|
|
22
|
+
*
|
|
23
|
+
* Empty cells become `null` in the measure and `""` in dimensions (then
|
|
24
|
+
* rejected by the builder; sources should pre-clean). For richer, lossless
|
|
25
|
+
* mapping with declared types/labels/roles, use CSVW (see [`csvw`](./csvw.ts)).
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
declare class CsvSourceError extends Error {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
interface CsvToCubeOptions {
|
|
32
|
+
/** Explicit measure column name. Overrides inference. */
|
|
33
|
+
measure?: string;
|
|
34
|
+
/** Explicit dimension column names, in order. */
|
|
35
|
+
dimensions?: string[];
|
|
36
|
+
/** Explicit status column name. Overrides the `status`-name heuristic. */
|
|
37
|
+
status?: string;
|
|
38
|
+
/** Role assignments. */
|
|
39
|
+
roles?: RoleMap;
|
|
40
|
+
/** Value-form hint. */
|
|
41
|
+
valueForm?: "auto" | "dense" | "sparse";
|
|
42
|
+
/** CSV delimiter (default ","). */
|
|
43
|
+
delimiter?: string;
|
|
44
|
+
/** Treat the first row as a header (default true). */
|
|
45
|
+
header?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A tiny, dependency-free RFC-4180-ish CSV parser. Handles quoted fields,
|
|
49
|
+
* embedded quotes (doubled), and embedded newlines. Sufficient for the
|
|
50
|
+
* importer's needs; for heavy CSV work, prefer piping through DuckDB/Polars.
|
|
51
|
+
*/
|
|
52
|
+
declare function parseCsv(input: string, delimiter?: string): string[][];
|
|
53
|
+
/**
|
|
54
|
+
* Parse CSV text into the [`Observations`] IR.
|
|
55
|
+
*
|
|
56
|
+
* @throws [`CsvSourceError`] on structural problems.
|
|
57
|
+
*/
|
|
58
|
+
declare function csvToCube(text: string, options?: CsvToCubeOptions): Observations;
|
|
59
|
+
/** Convenience: CSV text → JSON-stat [`Dataset`]. */
|
|
60
|
+
declare function csvToDataset(text: string, options?: CsvToCubeOptions): Promise<JsonStatDataset>;
|
|
61
|
+
interface CubeToCsvOptions {
|
|
62
|
+
/** CSV delimiter (default ","). */
|
|
63
|
+
delimiter?: string;
|
|
64
|
+
/** Line terminator: "\r\n" (RFC-4180 default) or "\n". */
|
|
65
|
+
lineTerminator?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the ordered list of (column name, row value extractor) pairs for a
|
|
69
|
+
* dataset IR. Shared by [`cubeToCsv`] and [`cubeToCsvw`] so the two writers
|
|
70
|
+
* agree on column layout.
|
|
71
|
+
*
|
|
72
|
+
* Column order: dimension IDs (in `model.dimensionIds` order) → measure
|
|
73
|
+
* (named `measure.name ?? "value"`) → status (`"status"`, if present).
|
|
74
|
+
*
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
declare function cubeColumns(obs: Observations): {
|
|
78
|
+
header: string[];
|
|
79
|
+
rows: string[];
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Quote a single CSV field per RFC-4180. A field needs quoting if it contains
|
|
83
|
+
* the delimiter, a double quote, a CR, or an LF. Embedded quotes are doubled.
|
|
84
|
+
*/
|
|
85
|
+
declare function quoteCsvField(value: string, delimiter: string, force?: boolean): string;
|
|
86
|
+
/**
|
|
87
|
+
* Serialize a CSV header + rows (as produced by [`cubeColumns`]) into RFC-4180
|
|
88
|
+
* text. Extracted so CSV and CSVW writers share one escaping path.
|
|
89
|
+
*
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
declare function serializeRows(header: string[], rows: string[], options?: CubeToCsvOptions): string;
|
|
93
|
+
/**
|
|
94
|
+
* Write the [`Observations`](../model/ir.ts) IR to RFC-4180-style CSV text.
|
|
95
|
+
*
|
|
96
|
+
* The output is a tidy long table: one header row + one row per observation.
|
|
97
|
+
* Columns are the dimension IDs (in `model.dimensionIds` order), then the
|
|
98
|
+
* measure column (`measure.name ?? "value"`), then an optional `status`
|
|
99
|
+
* column. Null measures are emitted as empty cells.
|
|
100
|
+
*
|
|
101
|
+
* This is the lossy inverse of [`csvToCube`]: labels, roles, and category
|
|
102
|
+
* metadata are not preserved (use [`cubeToCsvw`] for a lossless export).
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { cubeToCsv } from "jsonstat-io/csv";
|
|
107
|
+
* const csv = cubeToCsv(observations);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function cubeToCsv(obs: Observations, options?: CubeToCsvOptions): string;
|
|
111
|
+
|
|
112
|
+
export { CsvSourceError, type CsvToCubeOptions, type CubeToCsvOptions, csvToCube, csvToDataset, cubeColumns, cubeToCsv, parseCsv, quoteCsvField, serializeRows };
|