@graphty/graph-format 0.0.0 → 0.2.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 +21 -0
- package/README.md +216 -43
- package/dist/graph-format.d.ts +1 -0
- package/dist/graph-format.d.ts.map +1 -0
- package/dist/graph-format.js +15798 -0
- package/dist/graph-format.js.map +1 -0
- package/dist/src/builder/arena.d.ts +85 -0
- package/dist/src/builder/arena.d.ts.map +1 -0
- package/dist/src/builder/arena.js +154 -0
- package/dist/src/builder/arena.js.map +1 -0
- package/dist/src/builder/compact.d.ts +515 -0
- package/dist/src/builder/compact.d.ts.map +1 -0
- package/dist/src/builder/compact.js +1553 -0
- package/dist/src/builder/compact.js.map +1 -0
- package/dist/src/builder/counting-sort.d.ts +96 -0
- package/dist/src/builder/counting-sort.d.ts.map +1 -0
- package/dist/src/builder/counting-sort.js +430 -0
- package/dist/src/builder/counting-sort.js.map +1 -0
- package/dist/src/builder/freeze.d.ts +72 -0
- package/dist/src/builder/freeze.d.ts.map +1 -0
- package/dist/src/builder/freeze.js +548 -0
- package/dist/src/builder/freeze.js.map +1 -0
- package/dist/src/builder/graph-builder.d.ts +602 -0
- package/dist/src/builder/graph-builder.d.ts.map +1 -0
- package/dist/src/builder/graph-builder.js +1940 -0
- package/dist/src/builder/graph-builder.js.map +1 -0
- package/dist/src/builder/options.d.ts +16 -0
- package/dist/src/builder/options.d.ts.map +1 -0
- package/dist/src/builder/options.js +21 -0
- package/dist/src/builder/options.js.map +1 -0
- package/dist/src/columns/bitmap.d.ts +96 -0
- package/dist/src/columns/bitmap.d.ts.map +1 -0
- package/dist/src/columns/bitmap.js +184 -0
- package/dist/src/columns/bitmap.js.map +1 -0
- package/dist/src/columns/column.d.ts +220 -0
- package/dist/src/columns/column.d.ts.map +1 -0
- package/dist/src/columns/column.js +2109 -0
- package/dist/src/columns/column.js.map +1 -0
- package/dist/src/columns/dictionary.d.ts +60 -0
- package/dist/src/columns/dictionary.d.ts.map +1 -0
- package/dist/src/columns/dictionary.js +102 -0
- package/dist/src/columns/dictionary.js.map +1 -0
- package/dist/src/columns/growable.d.ts +198 -0
- package/dist/src/columns/growable.d.ts.map +1 -0
- package/dist/src/columns/growable.js +296 -0
- package/dist/src/columns/growable.js.map +1 -0
- package/dist/src/columns/infer.d.ts +121 -0
- package/dist/src/columns/infer.d.ts.map +1 -0
- package/dist/src/columns/infer.js +268 -0
- package/dist/src/columns/infer.js.map +1 -0
- package/dist/src/columns/remap.d.ts +143 -0
- package/dist/src/columns/remap.d.ts.map +1 -0
- package/dist/src/columns/remap.js +588 -0
- package/dist/src/columns/remap.js.map +1 -0
- package/dist/src/columns/table.d.ts +184 -0
- package/dist/src/columns/table.d.ts.map +1 -0
- package/dist/src/columns/table.js +485 -0
- package/dist/src/columns/table.js.map +1 -0
- package/dist/src/constants.d.ts +34 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +79 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/errors.d.ts +76 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +32 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/ids/edge-id-index.d.ts +77 -0
- package/dist/src/ids/edge-id-index.d.ts.map +1 -0
- package/dist/src/ids/edge-id-index.js +155 -0
- package/dist/src/ids/edge-id-index.js.map +1 -0
- package/dist/src/ids/node-id-map.d.ts +280 -0
- package/dist/src/ids/node-id-map.d.ts.map +1 -0
- package/dist/src/ids/node-id-map.js +1139 -0
- package/dist/src/ids/node-id-map.js.map +1 -0
- package/dist/src/ids/string-store.d.ts +219 -0
- package/dist/src/ids/string-store.d.ts.map +1 -0
- package/dist/src/ids/string-store.js +526 -0
- package/dist/src/ids/string-store.js.map +1 -0
- package/dist/src/index.d.ts +30 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +29 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/populate/from-csr.d.ts +61 -0
- package/dist/src/populate/from-csr.d.ts.map +1 -0
- package/dist/src/populate/from-csr.js +706 -0
- package/dist/src/populate/from-csr.js.map +1 -0
- package/dist/src/populate/from-edge-arrays.d.ts +51 -0
- package/dist/src/populate/from-edge-arrays.d.ts.map +1 -0
- package/dist/src/populate/from-edge-arrays.js +217 -0
- package/dist/src/populate/from-edge-arrays.js.map +1 -0
- package/dist/src/populate/from-records.d.ts +51 -0
- package/dist/src/populate/from-records.d.ts.map +1 -0
- package/dist/src/populate/from-records.js +447 -0
- package/dist/src/populate/from-records.js.map +1 -0
- package/dist/src/snapshot/derived.d.ts +211 -0
- package/dist/src/snapshot/derived.d.ts.map +1 -0
- package/dist/src/snapshot/derived.js +1254 -0
- package/dist/src/snapshot/derived.js.map +1 -0
- package/dist/src/snapshot/graph-meta.d.ts +23 -0
- package/dist/src/snapshot/graph-meta.d.ts.map +1 -0
- package/dist/src/snapshot/graph-meta.js +159 -0
- package/dist/src/snapshot/graph-meta.js.map +1 -0
- package/dist/src/snapshot/graph-snapshot.d.ts +509 -0
- package/dist/src/snapshot/graph-snapshot.d.ts.map +1 -0
- package/dist/src/snapshot/graph-snapshot.js +1247 -0
- package/dist/src/snapshot/graph-snapshot.js.map +1 -0
- package/dist/src/snapshot/hash.d.ts +90 -0
- package/dist/src/snapshot/hash.d.ts.map +1 -0
- package/dist/src/snapshot/hash.js +228 -0
- package/dist/src/snapshot/hash.js.map +1 -0
- package/dist/src/snapshot/queries.d.ts +74 -0
- package/dist/src/snapshot/queries.d.ts.map +1 -0
- package/dist/src/snapshot/queries.js +131 -0
- package/dist/src/snapshot/queries.js.map +1 -0
- package/dist/src/snapshot/validate.d.ts +192 -0
- package/dist/src/snapshot/validate.d.ts.map +1 -0
- package/dist/src/snapshot/validate.js +990 -0
- package/dist/src/snapshot/validate.js.map +1 -0
- package/dist/src/snapshot/views.d.ts +274 -0
- package/dist/src/snapshot/views.d.ts.map +1 -0
- package/dist/src/snapshot/views.js +856 -0
- package/dist/src/snapshot/views.js.map +1 -0
- package/dist/src/types/builder.d.ts +456 -0
- package/dist/src/types/builder.d.ts.map +1 -0
- package/dist/src/types/builder.js +11 -0
- package/dist/src/types/builder.js.map +1 -0
- package/dist/src/types/columns.d.ts +615 -0
- package/dist/src/types/columns.d.ts.map +1 -0
- package/dist/src/types/columns.js +14 -0
- package/dist/src/types/columns.js.map +1 -0
- package/dist/src/types/index.d.ts +14 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +11 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/internal.d.ts +172 -0
- package/dist/src/types/internal.d.ts.map +1 -0
- package/dist/src/types/internal.js +13 -0
- package/dist/src/types/internal.js.map +1 -0
- package/dist/src/types/snapshot.d.ts +801 -0
- package/dist/src/types/snapshot.d.ts.map +1 -0
- package/dist/src/types/snapshot.js +14 -0
- package/dist/src/types/snapshot.js.map +1 -0
- package/dist/src/types/wire.d.ts +196 -0
- package/dist/src/types/wire.d.ts.map +1 -0
- package/dist/src/types/wire.js +8 -0
- package/dist/src/types/wire.js.map +1 -0
- package/dist/src/util/mask.d.ts +55 -0
- package/dist/src/util/mask.d.ts.map +1 -0
- package/dist/src/util/mask.js +71 -0
- package/dist/src/util/mask.js.map +1 -0
- package/dist/src/util/options.d.ts +22 -0
- package/dist/src/util/options.d.ts.map +1 -0
- package/dist/src/util/options.js +49 -0
- package/dist/src/util/options.js.map +1 -0
- package/dist/src/util/shared-buffers.d.ts +42 -0
- package/dist/src/util/shared-buffers.d.ts.map +1 -0
- package/dist/src/util/shared-buffers.js +52 -0
- package/dist/src/util/shared-buffers.js.map +1 -0
- package/dist/src/util/typed-array.d.ts +205 -0
- package/dist/src/util/typed-array.d.ts.map +1 -0
- package/dist/src/util/typed-array.js +289 -0
- package/dist/src/util/typed-array.js.map +1 -0
- package/dist/src/wire/bytes.d.ts +69 -0
- package/dist/src/wire/bytes.d.ts.map +1 -0
- package/dist/src/wire/bytes.js +361 -0
- package/dist/src/wire/bytes.js.map +1 -0
- package/dist/src/wire/carried-views.d.ts +111 -0
- package/dist/src/wire/carried-views.d.ts.map +1 -0
- package/dist/src/wire/carried-views.js +286 -0
- package/dist/src/wire/carried-views.js.map +1 -0
- package/dist/src/wire/from-wire.d.ts +144 -0
- package/dist/src/wire/from-wire.d.ts.map +1 -0
- package/dist/src/wire/from-wire.js +1425 -0
- package/dist/src/wire/from-wire.js.map +1 -0
- package/dist/src/wire/to-wire.d.ts +171 -0
- package/dist/src/wire/to-wire.d.ts.map +1 -0
- package/dist/src/wire/to-wire.js +652 -0
- package/dist/src/wire/to-wire.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +72 -7
- package/src/builder/arena.ts +192 -0
- package/src/builder/compact.ts +1811 -0
- package/src/builder/counting-sort.ts +506 -0
- package/src/builder/freeze.ts +689 -0
- package/src/builder/graph-builder.ts +2264 -0
- package/src/builder/options.ts +29 -0
- package/src/columns/bitmap.ts +196 -0
- package/src/columns/column.ts +2574 -0
- package/src/columns/dictionary.ts +114 -0
- package/src/columns/growable.ts +350 -0
- package/src/columns/infer.ts +285 -0
- package/src/columns/remap.ts +663 -0
- package/src/columns/table.ts +568 -0
- package/src/constants.ts +89 -0
- package/src/errors.ts +115 -0
- package/src/ids/edge-id-index.ts +179 -0
- package/src/ids/node-id-map.ts +1340 -0
- package/src/ids/string-store.ts +589 -0
- package/src/index.ts +139 -0
- package/src/lib-resizable-array-buffer.d.ts +34 -0
- package/src/populate/from-csr.ts +802 -0
- package/src/populate/from-edge-arrays.ts +257 -0
- package/src/populate/from-records.ts +536 -0
- package/src/snapshot/derived.ts +1486 -0
- package/src/snapshot/graph-meta.ts +167 -0
- package/src/snapshot/graph-snapshot.ts +1503 -0
- package/src/snapshot/hash.ts +241 -0
- package/src/snapshot/queries.ts +136 -0
- package/src/snapshot/validate.ts +1108 -0
- package/src/snapshot/views.ts +943 -0
- package/src/types/builder.ts +480 -0
- package/src/types/columns.ts +727 -0
- package/src/types/index.ts +14 -0
- package/src/types/internal.ts +195 -0
- package/src/types/snapshot.ts +886 -0
- package/src/types/wire.ts +207 -0
- package/src/util/mask.ts +89 -0
- package/src/util/options.ts +57 -0
- package/src/util/shared-buffers.ts +56 -0
- package/src/util/typed-array.ts +371 -0
- package/src/wire/bytes.ts +440 -0
- package/src/wire/carried-views.ts +327 -0
- package/src/wire/from-wire.ts +1690 -0
- package/src/wire/to-wire.ts +755 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type inference for untyped sources (design section 5.1, decision C4): CSV cells, GML values, DOT
|
|
3
|
+
* strings, `fromRecords` and `addNodeRecord`. Inference runs per COLUMN, never per cell, widening
|
|
4
|
+
* monotonically in the order `(unset) -> bool -> i32 -> f64 -> string -> json`; it never yields
|
|
5
|
+
* `f32`. The lexical grammar for text is fixed so two implementations agree (invariant I15):
|
|
6
|
+
*
|
|
7
|
+
* - `bool` is exactly `true` / `false` (case-sensitive);
|
|
8
|
+
* - `i32` is `/^-?(0|[1-9][0-9]*)$/` within `[-2^31, 2^31)`;
|
|
9
|
+
* - `f64` is a decimal or exponent literal accepted by `Number()` that is not empty, not whitespace,
|
|
10
|
+
* not `Infinity` / `NaN` and not a hex / octal / binary form (and whose value is finite);
|
|
11
|
+
* - everything else is `string`. `0` / `1` text is `i32`, never `bool`.
|
|
12
|
+
*
|
|
13
|
+
* JS values map by `typeof`: `boolean -> bool`, integral `number` in i32 range -> `i32`, other
|
|
14
|
+
* `number -> f64`, `string -> string`, array or plain object -> `json`; `null` and `undefined` are
|
|
15
|
+
* unset and do not widen.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { GraphFormatError } from "../errors.js";
|
|
19
|
+
|
|
20
|
+
/** The dtypes inference can produce, in widening order. */
|
|
21
|
+
export type InferredDtype = "bool" | "i32" | "f64" | "string" | "json";
|
|
22
|
+
|
|
23
|
+
/** The widening order of design section 5.1; a column only ever moves to the right. */
|
|
24
|
+
export const WIDENING_ORDER: readonly InferredDtype[] = ["bool", "i32", "f64", "string", "json"];
|
|
25
|
+
|
|
26
|
+
const I32_TEXT = /^-?(0|[1-9][0-9]*)$/;
|
|
27
|
+
// integer part without leading zeros ("01" is a string, design section 5.1), optional fraction, optional exponent
|
|
28
|
+
const F64_TEXT = /^[+-]?((0|[1-9][0-9]*)(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?$/;
|
|
29
|
+
const I32_MIN = -2147483648;
|
|
30
|
+
const I32_MAX = 2147483647;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The rank of a dtype in the widening order.
|
|
34
|
+
* @param dtype - an inferred dtype
|
|
35
|
+
* @returns 0 for bool up to 4 for json
|
|
36
|
+
*/
|
|
37
|
+
export function wideningRank(dtype: InferredDtype): number {
|
|
38
|
+
return WIDENING_ORDER.indexOf(dtype);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Widen a column's dtype by one observation: the wider of the two, where null (unset, nothing seen
|
|
43
|
+
* yet) is narrower than everything.
|
|
44
|
+
* @param current - the column's dtype so far, or null when no value has been seen
|
|
45
|
+
* @param observed - the dtype of the newly observed value, or null for an unset cell
|
|
46
|
+
* @returns the widened dtype (null only when both are null)
|
|
47
|
+
*/
|
|
48
|
+
export function widenDtype(current: InferredDtype | null, observed: InferredDtype | null): InferredDtype | null {
|
|
49
|
+
if (current === null) {
|
|
50
|
+
return observed;
|
|
51
|
+
}
|
|
52
|
+
if (observed === null) {
|
|
53
|
+
return current;
|
|
54
|
+
}
|
|
55
|
+
return wideningRank(observed) > wideningRank(current) ? observed : current;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Classify one text cell by the fixed lexical grammar. Exported as the reference implementation of
|
|
60
|
+
* the text grammar of design section 5.1, which the text importers of graph-io must reproduce
|
|
61
|
+
* exactly (invariant I15); the core itself only infers from JS values, so nothing in src/ calls it.
|
|
62
|
+
* @public
|
|
63
|
+
* @param text - the cell text, exactly as read (no trimming)
|
|
64
|
+
* @returns bool, i32, f64 or string
|
|
65
|
+
*/
|
|
66
|
+
export function inferTextDtype(text: string): "bool" | "i32" | "f64" | "string" {
|
|
67
|
+
if (text === "true" || text === "false") {
|
|
68
|
+
return "bool";
|
|
69
|
+
}
|
|
70
|
+
if (I32_TEXT.test(text)) {
|
|
71
|
+
const n = Number(text);
|
|
72
|
+
if (n >= I32_MIN && n <= I32_MAX) {
|
|
73
|
+
return "i32";
|
|
74
|
+
}
|
|
75
|
+
return Number.isFinite(n) ? "f64" : "string";
|
|
76
|
+
}
|
|
77
|
+
if (F64_TEXT.test(text) && Number.isFinite(Number(text))) {
|
|
78
|
+
return "f64";
|
|
79
|
+
}
|
|
80
|
+
return "string";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Classify one JS value by `typeof`.
|
|
85
|
+
* @param value - the cell value
|
|
86
|
+
* @returns the dtype, or null for an unset cell (`undefined` or `null`); E_COLUMN_TYPE for a bigint,
|
|
87
|
+
* symbol or function, which no dtype can hold
|
|
88
|
+
*/
|
|
89
|
+
export function inferValueDtype(value: unknown): InferredDtype | null {
|
|
90
|
+
if (value === undefined || value === null) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
switch (typeof value) {
|
|
94
|
+
case "boolean":
|
|
95
|
+
return "bool";
|
|
96
|
+
case "number":
|
|
97
|
+
return Number.isInteger(value) && value >= I32_MIN && value <= I32_MAX ? "i32" : "f64";
|
|
98
|
+
case "string":
|
|
99
|
+
return "string";
|
|
100
|
+
case "object":
|
|
101
|
+
return "json";
|
|
102
|
+
default:
|
|
103
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `a ${typeof value} value cannot be stored in a column`, {
|
|
104
|
+
reason: "unsupported value type",
|
|
105
|
+
found: typeof value,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Parse a text cell into the storage value of a dtype the column has widened to. A text column
|
|
112
|
+
* never widens to json, but a column that was inferred from JS values may later receive text; in
|
|
113
|
+
* that case the text is stored as a string value. Part of the reference text grammar of design
|
|
114
|
+
* section 5.1 (see inferTextDtype).
|
|
115
|
+
* @public
|
|
116
|
+
* @param text - the cell text
|
|
117
|
+
* @param dtype - the column's current dtype
|
|
118
|
+
* @returns a boolean for bool, a number for i32 / f64, the text itself for string / json
|
|
119
|
+
*/
|
|
120
|
+
export function parseText(text: string, dtype: InferredDtype): boolean | number | string {
|
|
121
|
+
switch (dtype) {
|
|
122
|
+
case "bool":
|
|
123
|
+
if (text === "true") {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
if (text === "false") {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `text "${text}" is not a bool`, { value: text, dtype });
|
|
130
|
+
case "i32":
|
|
131
|
+
case "f64": {
|
|
132
|
+
const inferred = inferTextDtype(text);
|
|
133
|
+
if (inferred === "string") {
|
|
134
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `text "${text}" is not a ${dtype}`, { value: text, dtype });
|
|
135
|
+
}
|
|
136
|
+
if (inferred === "bool") {
|
|
137
|
+
return text === "true" ? 1 : 0;
|
|
138
|
+
}
|
|
139
|
+
return Number(text);
|
|
140
|
+
}
|
|
141
|
+
case "string":
|
|
142
|
+
case "json":
|
|
143
|
+
return text;
|
|
144
|
+
default: {
|
|
145
|
+
const name: string = dtype;
|
|
146
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `unknown dtype ${name}`, { dtype: name });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Convert a JS value to the storage value of a (possibly wider) inferred dtype, applying the
|
|
153
|
+
* widening conversions of design section 5.1: a bool widened to a number becomes 1 / 0, a number or
|
|
154
|
+
* boolean widened to string becomes its canonical JS text, anything widened to json is kept as is.
|
|
155
|
+
* @param value - the cell value (never undefined or null; unset cells are handled by the caller)
|
|
156
|
+
* @param dtype - the column's dtype
|
|
157
|
+
* @returns the storage value; E_COLUMN_TYPE when the value cannot be represented in the dtype
|
|
158
|
+
*/
|
|
159
|
+
export function coerceValue(value: unknown, dtype: InferredDtype): unknown {
|
|
160
|
+
switch (dtype) {
|
|
161
|
+
case "bool":
|
|
162
|
+
if (typeof value === "boolean") {
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
break;
|
|
166
|
+
case "i32":
|
|
167
|
+
case "f64":
|
|
168
|
+
if (typeof value === "number") {
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === "boolean") {
|
|
172
|
+
return value ? 1 : 0;
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
case "string":
|
|
176
|
+
if (typeof value === "string") {
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
180
|
+
return String(value);
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
case "json":
|
|
184
|
+
return value;
|
|
185
|
+
default: {
|
|
186
|
+
const name: string = dtype;
|
|
187
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `unknown dtype ${name}`, { dtype: name });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
throw new GraphFormatError("E_COLUMN_TYPE", `a ${typeof value} value cannot be stored in a ${dtype} column`, {
|
|
191
|
+
dtype,
|
|
192
|
+
found: typeof value,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Infer the dtype of a whole column of JS values in one pass.
|
|
198
|
+
* @param values - the cell values; undefined and null are unset
|
|
199
|
+
* @returns the widened dtype, or null when every cell is unset
|
|
200
|
+
*/
|
|
201
|
+
export function inferValuesDtype(values: Iterable<unknown>): InferredDtype | null {
|
|
202
|
+
let dtype: InferredDtype | null = null;
|
|
203
|
+
for (const value of values) {
|
|
204
|
+
dtype = widenDtype(dtype, inferValueDtype(value));
|
|
205
|
+
if (dtype === "json") {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return dtype;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Infer the dtype of a whole column of text cells in one pass. Part of the reference text grammar
|
|
214
|
+
* of design section 5.1 (see inferTextDtype).
|
|
215
|
+
* @public
|
|
216
|
+
* @param cells - the cell texts; an empty string is a string value, not an unset cell (the caller
|
|
217
|
+
* decides how blanks map to unset before calling)
|
|
218
|
+
* @returns the widened dtype, or null when the column is empty
|
|
219
|
+
*/
|
|
220
|
+
export function inferTextsDtype(cells: Iterable<string>): InferredDtype | null {
|
|
221
|
+
let dtype: InferredDtype | null = null;
|
|
222
|
+
for (const text of cells) {
|
|
223
|
+
dtype = widenDtype(dtype, inferTextDtype(text));
|
|
224
|
+
if (dtype === "string") {
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return dtype;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A per-column inference accumulator for row-at-a-time sources (`addNodeRecord`, CSV streaming):
|
|
233
|
+
* observe every cell and read `dtype`; each observe call reports whether the column widened so the
|
|
234
|
+
* caller can reallocate storage and record the widening in FreezeReport.widened.
|
|
235
|
+
*/
|
|
236
|
+
export class DtypeInferrer {
|
|
237
|
+
private current: InferredDtype | null = null;
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* The column's dtype so far.
|
|
241
|
+
* @returns the widened dtype, or null until a set cell has been observed
|
|
242
|
+
*/
|
|
243
|
+
get dtype(): InferredDtype | null {
|
|
244
|
+
return this.current;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Observe a JS value.
|
|
249
|
+
* @param value - the cell value; undefined and null are unset and never widen
|
|
250
|
+
* @returns true when the column's dtype changed
|
|
251
|
+
*/
|
|
252
|
+
observeValue(value: unknown): boolean {
|
|
253
|
+
return this.apply(inferValueDtype(value));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Observe a text cell. Part of the reference text grammar of design section 5.1 (see
|
|
258
|
+
* inferTextDtype).
|
|
259
|
+
* @public
|
|
260
|
+
* @param text - the cell text
|
|
261
|
+
* @returns true when the column's dtype changed
|
|
262
|
+
*/
|
|
263
|
+
observeText(text: string): boolean {
|
|
264
|
+
return this.apply(inferTextDtype(text));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Force the dtype to at least the given one (a declared lower bound, or the dtype of a column
|
|
269
|
+
* being merged in).
|
|
270
|
+
* @param dtype - the dtype to widen to
|
|
271
|
+
* @returns true when the column's dtype changed
|
|
272
|
+
*/
|
|
273
|
+
widenTo(dtype: InferredDtype): boolean {
|
|
274
|
+
return this.apply(dtype);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private apply(observed: InferredDtype | null): boolean {
|
|
278
|
+
const next = widenDtype(this.current, observed);
|
|
279
|
+
if (next === this.current) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
this.current = next;
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
}
|