@web-ts-toolkit/json-frame 0.34.3 → 0.35.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/index.d.mts +195 -1
- package/index.d.ts +195 -1
- package/index.js +1660 -0
- package/index.mjs +1645 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -3,6 +3,13 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __typeError = (msg) => {
|
|
7
|
+
throw TypeError(msg);
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
6
13
|
var __copyProps = (to, from, except, desc) => {
|
|
7
14
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
15
|
for (let key of __getOwnPropNames(from))
|
|
@@ -12,7 +19,1660 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
12
19
|
return to;
|
|
13
20
|
};
|
|
14
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
23
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
24
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
25
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
26
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
15
27
|
|
|
16
28
|
// src/index.ts
|
|
17
29
|
var index_exports = {};
|
|
30
|
+
__export(index_exports, {
|
|
31
|
+
AmbiguousOrientError: () => AmbiguousOrientError,
|
|
32
|
+
ExportKeyCollisionError: () => ExportKeyCollisionError,
|
|
33
|
+
JsonFrameError: () => JsonFrameError,
|
|
34
|
+
JsonFrameOptionError: () => JsonFrameOptionError,
|
|
35
|
+
JsonFrameParseError: () => JsonFrameParseError,
|
|
36
|
+
JsonFrameValidationError: () => JsonFrameValidationError,
|
|
37
|
+
UnsupportedFeatureError: () => UnsupportedFeatureError,
|
|
38
|
+
fromOrient: () => fromOrient
|
|
39
|
+
});
|
|
18
40
|
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
|
|
42
|
+
// src/errors.ts
|
|
43
|
+
var freezeCopy = (values) => Object.freeze([...values]);
|
|
44
|
+
var JsonFrameError = class extends Error {
|
|
45
|
+
constructor(message, context = {}) {
|
|
46
|
+
super(message);
|
|
47
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
48
|
+
this.name = "JsonFrameError";
|
|
49
|
+
this.orient = context.orient;
|
|
50
|
+
this.path = context.path;
|
|
51
|
+
this.row = context.row;
|
|
52
|
+
this.column = context.column;
|
|
53
|
+
this.value = context.value;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var JsonFrameParseError = class extends JsonFrameError {
|
|
57
|
+
constructor(message, cause) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "JsonFrameParseError";
|
|
60
|
+
this.cause = cause;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var JsonFrameOptionError = class extends JsonFrameError {
|
|
64
|
+
constructor(message, option, value) {
|
|
65
|
+
super(message, { value });
|
|
66
|
+
this.name = "JsonFrameOptionError";
|
|
67
|
+
this.option = option;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var JsonFrameValidationError = class extends JsonFrameError {
|
|
71
|
+
constructor(message, context = {}) {
|
|
72
|
+
super(message, context);
|
|
73
|
+
this.name = "JsonFrameValidationError";
|
|
74
|
+
this.orient = context.orient;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var AmbiguousOrientError = class extends JsonFrameError {
|
|
78
|
+
constructor(message, candidates) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = "AmbiguousOrientError";
|
|
81
|
+
this.candidates = freezeCopy(candidates);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var UnsupportedFeatureError = class extends JsonFrameError {
|
|
85
|
+
constructor(message, feature, context = {}) {
|
|
86
|
+
super(message, context);
|
|
87
|
+
this.name = "UnsupportedFeatureError";
|
|
88
|
+
this.feature = feature;
|
|
89
|
+
this.orient = context.orient;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
var ExportKeyCollisionError = class extends JsonFrameError {
|
|
93
|
+
constructor(message, orient, key, labels) {
|
|
94
|
+
super(message, { orient });
|
|
95
|
+
this.name = "ExportKeyCollisionError";
|
|
96
|
+
this.orient = orient;
|
|
97
|
+
this.key = key;
|
|
98
|
+
this.labels = freezeCopy(labels);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/export/payload.ts
|
|
103
|
+
var createRecord = () => /* @__PURE__ */ Object.create(null);
|
|
104
|
+
var cloneJsonValue = (value) => {
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
return value.map((entry) => cloneJsonValue(entry));
|
|
107
|
+
}
|
|
108
|
+
if (value !== null && typeof value === "object") {
|
|
109
|
+
const cloned = createRecord();
|
|
110
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
111
|
+
cloned[key] = cloneJsonValue(entryValue);
|
|
112
|
+
}
|
|
113
|
+
return cloned;
|
|
114
|
+
}
|
|
115
|
+
return value;
|
|
116
|
+
};
|
|
117
|
+
var cloneSchemaField = (field, name = field.name) => {
|
|
118
|
+
const cloned = createRecord();
|
|
119
|
+
for (const [key, value] of Object.entries(field)) {
|
|
120
|
+
cloned[key] = key === "name" ? name : value === void 0 ? void 0 : cloneJsonValue(value);
|
|
121
|
+
}
|
|
122
|
+
return cloned;
|
|
123
|
+
};
|
|
124
|
+
var cloneSchema = (schema, fields, primaryKey) => {
|
|
125
|
+
const cloned = createRecord();
|
|
126
|
+
if (schema !== void 0) {
|
|
127
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
128
|
+
if (key === "fields" || key === "primaryKey") {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
cloned[key] = value === void 0 ? void 0 : cloneJsonValue(value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
cloned.fields = fields.map((field) => cloneSchemaField(field));
|
|
135
|
+
if (primaryKey !== void 0) {
|
|
136
|
+
cloned.primaryKey = [...primaryKey];
|
|
137
|
+
}
|
|
138
|
+
return cloned;
|
|
139
|
+
};
|
|
140
|
+
var mapColumnTypeToSchemaField = (name, info) => {
|
|
141
|
+
const type = (() => {
|
|
142
|
+
switch (info.type) {
|
|
143
|
+
case "integer":
|
|
144
|
+
return "integer";
|
|
145
|
+
case "float":
|
|
146
|
+
return "number";
|
|
147
|
+
case "string":
|
|
148
|
+
case "categorical":
|
|
149
|
+
return "string";
|
|
150
|
+
case "boolean":
|
|
151
|
+
return "boolean";
|
|
152
|
+
case "datetime":
|
|
153
|
+
return "datetime";
|
|
154
|
+
case "mixed":
|
|
155
|
+
case "unknown":
|
|
156
|
+
return "any";
|
|
157
|
+
default: {
|
|
158
|
+
const exhaustive = info.type;
|
|
159
|
+
throw new JsonFrameValidationError("Unsupported logical column type for table export.", {
|
|
160
|
+
path: "$.columnInfo",
|
|
161
|
+
column: name,
|
|
162
|
+
value: exhaustive
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
})();
|
|
167
|
+
return info.type === "categorical" ? { name, type, extDtype: "category" } : { name, type };
|
|
168
|
+
};
|
|
169
|
+
var inferIndexFieldType = (index) => {
|
|
170
|
+
let sawString = false;
|
|
171
|
+
let sawInteger = false;
|
|
172
|
+
let sawFloat = false;
|
|
173
|
+
for (const label of index) {
|
|
174
|
+
if (typeof label === "string") {
|
|
175
|
+
sawString = true;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (Number.isInteger(label)) {
|
|
179
|
+
sawInteger = true;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
sawFloat = true;
|
|
183
|
+
}
|
|
184
|
+
if (sawString && (sawInteger || sawFloat)) {
|
|
185
|
+
return "any";
|
|
186
|
+
}
|
|
187
|
+
if (sawString) {
|
|
188
|
+
return "string";
|
|
189
|
+
}
|
|
190
|
+
if (sawFloat) {
|
|
191
|
+
return "number";
|
|
192
|
+
}
|
|
193
|
+
if (sawInteger) {
|
|
194
|
+
return "integer";
|
|
195
|
+
}
|
|
196
|
+
return "string";
|
|
197
|
+
};
|
|
198
|
+
var getIndexFieldTemplate = (state) => {
|
|
199
|
+
if (state.tableSchema === void 0 || state.tableIndexField === void 0) {
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
202
|
+
if (state.tableSchema.fields.length === state.columns.length + 1) {
|
|
203
|
+
return state.tableSchema.fields[0];
|
|
204
|
+
}
|
|
205
|
+
return state.tableSchema.fields.find((field) => field.name === state.tableIndexField);
|
|
206
|
+
};
|
|
207
|
+
var getDataFieldTemplates = (state) => {
|
|
208
|
+
if (state.tableSchema === void 0) {
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
if (state.tableIndexField === void 0) {
|
|
212
|
+
return state.tableSchema.fields.slice(0, state.columns.length);
|
|
213
|
+
}
|
|
214
|
+
if (state.tableSchema.fields.length >= state.columns.length + 1) {
|
|
215
|
+
return state.tableSchema.fields.slice(1, state.columns.length + 1);
|
|
216
|
+
}
|
|
217
|
+
let skippedIndexField = false;
|
|
218
|
+
const templates = [];
|
|
219
|
+
for (const field of state.tableSchema.fields) {
|
|
220
|
+
if (!skippedIndexField && field.name === state.tableIndexField) {
|
|
221
|
+
skippedIndexField = true;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
templates.push(field);
|
|
225
|
+
if (templates.length === state.columns.length) {
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return templates;
|
|
230
|
+
};
|
|
231
|
+
var resolveIndexFieldName = (state, options) => {
|
|
232
|
+
if (options !== void 0 && (Array.isArray(options) || typeof options !== "object" || options === null)) {
|
|
233
|
+
throw new JsonFrameOptionError("`toTable` options must be an object when provided.", "options", options);
|
|
234
|
+
}
|
|
235
|
+
if (options?.indexField !== void 0 && typeof options.indexField !== "string") {
|
|
236
|
+
throw new JsonFrameOptionError(
|
|
237
|
+
"`toTable` options.indexField must be a string when provided.",
|
|
238
|
+
"indexField",
|
|
239
|
+
options.indexField
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
if (state.indexKind === "synthetic") {
|
|
243
|
+
return void 0;
|
|
244
|
+
}
|
|
245
|
+
const indexField = options?.indexField ?? state.tableIndexField ?? "index";
|
|
246
|
+
if (state.columns.includes(indexField)) {
|
|
247
|
+
throw new JsonFrameValidationError("Table export index field name must not collide with a data column.", {
|
|
248
|
+
path: "$.schema.fields",
|
|
249
|
+
column: indexField,
|
|
250
|
+
value: indexField
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
return indexField;
|
|
254
|
+
};
|
|
255
|
+
var resolveIndexKeys = (state, orient) => {
|
|
256
|
+
const seenKeys = /* @__PURE__ */ new Map();
|
|
257
|
+
const keys = [];
|
|
258
|
+
for (const label of state.index) {
|
|
259
|
+
const key = String(label);
|
|
260
|
+
const priorLabel = seenKeys.get(key);
|
|
261
|
+
if (priorLabel !== void 0) {
|
|
262
|
+
throw new ExportKeyCollisionError(
|
|
263
|
+
`Cannot export distinct rows to orient="${orient}" because index labels collide after stringification.`,
|
|
264
|
+
orient,
|
|
265
|
+
key,
|
|
266
|
+
[priorLabel, label]
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
seenKeys.set(key, label);
|
|
270
|
+
keys.push(key);
|
|
271
|
+
}
|
|
272
|
+
return keys;
|
|
273
|
+
};
|
|
274
|
+
var exportRecords = (state, materialized) => {
|
|
275
|
+
const rows = [];
|
|
276
|
+
for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
|
|
277
|
+
const row = createRecord();
|
|
278
|
+
for (const column of state.columns) {
|
|
279
|
+
row[column] = materialized.get(column)[rowIndex];
|
|
280
|
+
}
|
|
281
|
+
rows.push(row);
|
|
282
|
+
}
|
|
283
|
+
return rows;
|
|
284
|
+
};
|
|
285
|
+
var exportIndex = (state, materialized) => {
|
|
286
|
+
const keys = resolveIndexKeys(state, "index");
|
|
287
|
+
const rows = createRecord();
|
|
288
|
+
for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
|
|
289
|
+
const row = createRecord();
|
|
290
|
+
for (const column of state.columns) {
|
|
291
|
+
row[column] = materialized.get(column)[rowIndex];
|
|
292
|
+
}
|
|
293
|
+
rows[keys[rowIndex]] = row;
|
|
294
|
+
}
|
|
295
|
+
return rows;
|
|
296
|
+
};
|
|
297
|
+
var exportColumns = (state, materialized) => {
|
|
298
|
+
const keys = resolveIndexKeys(state, "columns");
|
|
299
|
+
const columns = createRecord();
|
|
300
|
+
for (const column of state.columns) {
|
|
301
|
+
const values = createRecord();
|
|
302
|
+
const entries = materialized.get(column);
|
|
303
|
+
for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
|
|
304
|
+
values[keys[rowIndex]] = entries[rowIndex];
|
|
305
|
+
}
|
|
306
|
+
columns[column] = values;
|
|
307
|
+
}
|
|
308
|
+
return columns;
|
|
309
|
+
};
|
|
310
|
+
var exportValues = (state, materialized) => {
|
|
311
|
+
const rows = [];
|
|
312
|
+
for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
|
|
313
|
+
rows.push(state.columns.map((column) => materialized.get(column)[rowIndex]));
|
|
314
|
+
}
|
|
315
|
+
return rows;
|
|
316
|
+
};
|
|
317
|
+
var exportSplit = (state, materialized) => ({
|
|
318
|
+
columns: [...state.columns],
|
|
319
|
+
index: [...state.index],
|
|
320
|
+
data: exportValues(state, materialized)
|
|
321
|
+
});
|
|
322
|
+
var exportTable = (state, materialized, columnInfo, options) => {
|
|
323
|
+
const indexField = resolveIndexFieldName(state, options);
|
|
324
|
+
const indexTemplate = getIndexFieldTemplate(state);
|
|
325
|
+
const dataTemplates = getDataFieldTemplates(state);
|
|
326
|
+
const fields = [];
|
|
327
|
+
if (indexField !== void 0) {
|
|
328
|
+
fields.push(
|
|
329
|
+
indexTemplate === void 0 ? { name: indexField, type: inferIndexFieldType(state.index) } : cloneSchemaField(indexTemplate, indexField)
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
|
|
333
|
+
const column = state.columns[columnIndex];
|
|
334
|
+
const template = dataTemplates[columnIndex];
|
|
335
|
+
fields.push(
|
|
336
|
+
template === void 0 ? mapColumnTypeToSchemaField(column, columnInfo.get(column)) : cloneSchemaField(template, column)
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
const data = [];
|
|
340
|
+
for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
|
|
341
|
+
const row = createRecord();
|
|
342
|
+
if (indexField !== void 0) {
|
|
343
|
+
row[indexField] = state.index[rowIndex];
|
|
344
|
+
}
|
|
345
|
+
for (const column of state.columns) {
|
|
346
|
+
row[column] = materialized.get(column)[rowIndex];
|
|
347
|
+
}
|
|
348
|
+
data.push(row);
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
schema: cloneSchema(state.tableSchema, fields, indexField === void 0 ? void 0 : [indexField]),
|
|
352
|
+
data
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// src/frame/column.ts
|
|
357
|
+
var INT32_MIN = -2147483648;
|
|
358
|
+
var INT32_MAX = 2147483647;
|
|
359
|
+
var freezeArray = (values) => Object.freeze([...values]);
|
|
360
|
+
var freezeColumnInfo = (info) => Object.freeze({ ...info });
|
|
361
|
+
var hasCategoricalMetadata = (field) => field.constraints?.enum !== void 0 || field.ordered === true || field.extDtype === "category";
|
|
362
|
+
var mapTableSchemaFieldType = (field) => {
|
|
363
|
+
if (hasCategoricalMetadata(field)) {
|
|
364
|
+
return "categorical";
|
|
365
|
+
}
|
|
366
|
+
switch (field.type) {
|
|
367
|
+
case "boolean":
|
|
368
|
+
return "boolean";
|
|
369
|
+
case "integer":
|
|
370
|
+
case "year":
|
|
371
|
+
return "integer";
|
|
372
|
+
case "number":
|
|
373
|
+
return "float";
|
|
374
|
+
case "date":
|
|
375
|
+
case "datetime":
|
|
376
|
+
return "datetime";
|
|
377
|
+
case "string":
|
|
378
|
+
return "string";
|
|
379
|
+
case "any":
|
|
380
|
+
return "unknown";
|
|
381
|
+
default:
|
|
382
|
+
return "unknown";
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
var inferColumnType = (values) => {
|
|
386
|
+
let nullable = false;
|
|
387
|
+
let sawBoolean = false;
|
|
388
|
+
let sawString = false;
|
|
389
|
+
let sawInteger = false;
|
|
390
|
+
let sawFloat = false;
|
|
391
|
+
let sawStructured = false;
|
|
392
|
+
for (const value of values) {
|
|
393
|
+
if (value === null) {
|
|
394
|
+
nullable = true;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (typeof value === "boolean") {
|
|
398
|
+
sawBoolean = true;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (typeof value === "string") {
|
|
402
|
+
sawString = true;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (typeof value === "number") {
|
|
406
|
+
if (Number.isInteger(value)) {
|
|
407
|
+
sawInteger = true;
|
|
408
|
+
} else {
|
|
409
|
+
sawFloat = true;
|
|
410
|
+
}
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
sawStructured = true;
|
|
414
|
+
}
|
|
415
|
+
const nonNullKinds = [sawBoolean, sawString, sawInteger || sawFloat, sawStructured].filter(Boolean).length;
|
|
416
|
+
if (nonNullKinds === 0) {
|
|
417
|
+
return freezeColumnInfo({ type: "unknown", nullable });
|
|
418
|
+
}
|
|
419
|
+
if (sawStructured || nonNullKinds > 1 || sawBoolean && (sawString || sawInteger || sawFloat)) {
|
|
420
|
+
return freezeColumnInfo({ type: "mixed", nullable });
|
|
421
|
+
}
|
|
422
|
+
if (sawString) {
|
|
423
|
+
return freezeColumnInfo({ type: "string", nullable });
|
|
424
|
+
}
|
|
425
|
+
if (sawBoolean) {
|
|
426
|
+
return freezeColumnInfo({ type: "boolean", nullable });
|
|
427
|
+
}
|
|
428
|
+
if (sawFloat) {
|
|
429
|
+
return freezeColumnInfo({ type: "float", nullable });
|
|
430
|
+
}
|
|
431
|
+
return freezeColumnInfo({ type: "integer", nullable });
|
|
432
|
+
};
|
|
433
|
+
var packColumn = (values, info, packThreshold) => {
|
|
434
|
+
if (packThreshold === 0 || values.length < packThreshold || info.nullable) {
|
|
435
|
+
return freezeArray(values);
|
|
436
|
+
}
|
|
437
|
+
if (info.type === "integer") {
|
|
438
|
+
const packed = new Int32Array(values.length);
|
|
439
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
440
|
+
const value = values[index];
|
|
441
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < INT32_MIN || value > INT32_MAX) {
|
|
442
|
+
return freezeArray(values);
|
|
443
|
+
}
|
|
444
|
+
packed[index] = value;
|
|
445
|
+
}
|
|
446
|
+
return packed;
|
|
447
|
+
}
|
|
448
|
+
if (info.type === "float") {
|
|
449
|
+
const packed = new Float64Array(values.length);
|
|
450
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
451
|
+
const value = values[index];
|
|
452
|
+
if (typeof value !== "number") {
|
|
453
|
+
return freezeArray(values);
|
|
454
|
+
}
|
|
455
|
+
packed[index] = value;
|
|
456
|
+
}
|
|
457
|
+
return packed;
|
|
458
|
+
}
|
|
459
|
+
return freezeArray(values);
|
|
460
|
+
};
|
|
461
|
+
var validateExplicitColumnTypes = (columns, columnTypes) => {
|
|
462
|
+
if (columnTypes === void 0) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const knownColumns = new Set(columns);
|
|
466
|
+
for (const column of Object.keys(columnTypes)) {
|
|
467
|
+
if (!knownColumns.has(column)) {
|
|
468
|
+
throw new JsonFrameOptionError(
|
|
469
|
+
"`options.columnTypes` keys must match parsed column names.",
|
|
470
|
+
`columnTypes.${column}`,
|
|
471
|
+
columnTypes[column]
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var resolveSchemaTypeByColumn = (frame) => {
|
|
477
|
+
if (frame.tableSchema === void 0) {
|
|
478
|
+
return /* @__PURE__ */ new Map();
|
|
479
|
+
}
|
|
480
|
+
const schemaTypes = /* @__PURE__ */ new Map();
|
|
481
|
+
for (const field of frame.tableSchema.fields) {
|
|
482
|
+
if (frame.columns.includes(field.name)) {
|
|
483
|
+
schemaTypes.set(field.name, mapTableSchemaFieldType(field));
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return schemaTypes;
|
|
487
|
+
};
|
|
488
|
+
var materializeColumn = (column) => Array.isArray(column) ? freezeArray(column) : freezeArray(Array.from(column));
|
|
489
|
+
var materializeFrameData = (columns, data) => {
|
|
490
|
+
const materialized = /* @__PURE__ */ new Map();
|
|
491
|
+
for (const column of columns) {
|
|
492
|
+
const stored = data.get(column);
|
|
493
|
+
if (stored === void 0) {
|
|
494
|
+
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
495
|
+
path: "$",
|
|
496
|
+
column
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
materialized.set(column, materializeColumn(stored));
|
|
500
|
+
}
|
|
501
|
+
return materialized;
|
|
502
|
+
};
|
|
503
|
+
var buildFrameState = (frame, options) => {
|
|
504
|
+
validateExplicitColumnTypes(frame.columns, options.columnTypes);
|
|
505
|
+
const schemaTypes = resolveSchemaTypeByColumn(frame);
|
|
506
|
+
const data = /* @__PURE__ */ new Map();
|
|
507
|
+
const columnInfo = /* @__PURE__ */ new Map();
|
|
508
|
+
for (const column of frame.columns) {
|
|
509
|
+
const values = frame.data.get(column);
|
|
510
|
+
if (values === void 0) {
|
|
511
|
+
throw new JsonFrameValidationError("Parsed frame data is missing a declared column.", {
|
|
512
|
+
orient: frame.orient,
|
|
513
|
+
column
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
const inferred = inferColumnType(values);
|
|
517
|
+
const resolvedType = schemaTypes.get(column) ?? options.columnTypes?.[column] ?? inferred.type;
|
|
518
|
+
const info = freezeColumnInfo({ type: resolvedType, nullable: inferred.nullable });
|
|
519
|
+
columnInfo.set(column, info);
|
|
520
|
+
data.set(column, packColumn(values, info, options.packThreshold));
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
columns: freezeArray(frame.columns),
|
|
524
|
+
index: freezeArray(frame.index),
|
|
525
|
+
indexKind: frame.indexKind,
|
|
526
|
+
data,
|
|
527
|
+
columnInfo,
|
|
528
|
+
...frame.tableSchema === void 0 ? {} : { tableSchema: frame.tableSchema },
|
|
529
|
+
...frame.tableIndexField === void 0 ? {} : { tableIndexField: frame.tableIndexField }
|
|
530
|
+
};
|
|
531
|
+
};
|
|
532
|
+
var createFrameStateFromData = (frame, options) => buildFrameState(frame, options);
|
|
533
|
+
var createFrameState = (frame, options) => buildFrameState(frame, options);
|
|
534
|
+
|
|
535
|
+
// src/frame/DataFrame.ts
|
|
536
|
+
var hasOwn = Object.prototype.hasOwnProperty;
|
|
537
|
+
var frameStateByInstance = /* @__PURE__ */ new WeakMap();
|
|
538
|
+
var freezeArray2 = (values) => Object.freeze([...values]);
|
|
539
|
+
var cloneField = (field, name = field.name) => Object.freeze({ ...field, name });
|
|
540
|
+
var cloneSchema2 = (schema, fields, primaryKey) => {
|
|
541
|
+
const cloned = /* @__PURE__ */ Object.create(null);
|
|
542
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
543
|
+
if (key === "fields" || key === "primaryKey") {
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
cloned[key] = value;
|
|
547
|
+
}
|
|
548
|
+
cloned.fields = freezeArray2(fields);
|
|
549
|
+
if (primaryKey !== void 0) {
|
|
550
|
+
cloned.primaryKey = freezeArray2(primaryKey);
|
|
551
|
+
}
|
|
552
|
+
return Object.freeze(cloned);
|
|
553
|
+
};
|
|
554
|
+
var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, materializedData_fn, createRow_fn, columnTypeOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
|
|
555
|
+
var DataFrame = class {
|
|
556
|
+
constructor(state, packThreshold) {
|
|
557
|
+
__privateAdd(this, _DataFrame_instances);
|
|
558
|
+
__privateAdd(this, _state);
|
|
559
|
+
__privateAdd(this, _packThreshold);
|
|
560
|
+
__privateSet(this, _state, state);
|
|
561
|
+
__privateSet(this, _packThreshold, packThreshold);
|
|
562
|
+
frameStateByInstance.set(this, state);
|
|
563
|
+
}
|
|
564
|
+
get columns() {
|
|
565
|
+
return freezeArray2(__privateGet(this, _state).columns);
|
|
566
|
+
}
|
|
567
|
+
get index() {
|
|
568
|
+
return freezeArray2(__privateGet(this, _state).index);
|
|
569
|
+
}
|
|
570
|
+
get columnInfo() {
|
|
571
|
+
return new Map(__privateGet(this, _state).columnInfo);
|
|
572
|
+
}
|
|
573
|
+
get length() {
|
|
574
|
+
return __privateGet(this, _state).index.length;
|
|
575
|
+
}
|
|
576
|
+
toRecords() {
|
|
577
|
+
return exportRecords(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
|
|
578
|
+
}
|
|
579
|
+
toIndex() {
|
|
580
|
+
return exportIndex(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
|
|
581
|
+
}
|
|
582
|
+
toColumns() {
|
|
583
|
+
return exportColumns(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
|
|
584
|
+
}
|
|
585
|
+
toValues() {
|
|
586
|
+
return exportValues(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
|
|
587
|
+
}
|
|
588
|
+
toSplit() {
|
|
589
|
+
return exportSplit(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
|
|
590
|
+
}
|
|
591
|
+
toTable(options) {
|
|
592
|
+
return exportTable(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this), __privateGet(this, _state).columnInfo, options);
|
|
593
|
+
}
|
|
594
|
+
toJSONString(orient, options) {
|
|
595
|
+
switch (orient) {
|
|
596
|
+
case "records":
|
|
597
|
+
return JSON.stringify(this.toRecords());
|
|
598
|
+
case "index":
|
|
599
|
+
return JSON.stringify(this.toIndex());
|
|
600
|
+
case "columns":
|
|
601
|
+
return JSON.stringify(this.toColumns());
|
|
602
|
+
case "values":
|
|
603
|
+
return JSON.stringify(this.toValues());
|
|
604
|
+
case "split":
|
|
605
|
+
return JSON.stringify(this.toSplit());
|
|
606
|
+
case "table":
|
|
607
|
+
return JSON.stringify(this.toTable(options));
|
|
608
|
+
default: {
|
|
609
|
+
const exhaustive = orient;
|
|
610
|
+
throw new JsonFrameValidationError("Unsupported export orient.", { value: exhaustive });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
row(position) {
|
|
615
|
+
__privateMethod(this, _DataFrame_instances, assertRowPosition_fn).call(this, position);
|
|
616
|
+
return __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this), position);
|
|
617
|
+
}
|
|
618
|
+
rows() {
|
|
619
|
+
const materialized = __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this);
|
|
620
|
+
const rows = __privateGet(this, _state).index.map((_, position) => __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, materialized, position));
|
|
621
|
+
return freezeArray2(rows);
|
|
622
|
+
}
|
|
623
|
+
filter(predicate) {
|
|
624
|
+
const materialized = __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this);
|
|
625
|
+
const keptPositions = [];
|
|
626
|
+
for (let position = 0; position < this.length; position += 1) {
|
|
627
|
+
if (predicate(__privateMethod(this, _DataFrame_instances, createRow_fn).call(this, materialized, position), __privateGet(this, _state).index[position], position)) {
|
|
628
|
+
keptPositions.push(position);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
|
|
632
|
+
columns: __privateGet(this, _state).columns,
|
|
633
|
+
sourceColumns: __privateGet(this, _state).columns,
|
|
634
|
+
positions: keptPositions,
|
|
635
|
+
index: keptPositions.map((position) => __privateGet(this, _state).index[position]),
|
|
636
|
+
indexKind: __privateGet(this, _state).indexKind,
|
|
637
|
+
schema: {
|
|
638
|
+
tableSchema: __privateGet(this, _state).tableSchema,
|
|
639
|
+
tableIndexField: __privateGet(this, _state).tableIndexField
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
sort(compare) {
|
|
644
|
+
const materialized = __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this);
|
|
645
|
+
const ordering = __privateGet(this, _state).index.map((indexLabel, position) => ({
|
|
646
|
+
indexLabel,
|
|
647
|
+
position,
|
|
648
|
+
row: __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, materialized, position)
|
|
649
|
+
}));
|
|
650
|
+
ordering.sort((left, right) => {
|
|
651
|
+
const result = compare(left.row, right.row, left.indexLabel, right.indexLabel, left.position, right.position);
|
|
652
|
+
return (Number.isNaN(result) ? 0 : result) || left.position - right.position;
|
|
653
|
+
});
|
|
654
|
+
return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
|
|
655
|
+
columns: __privateGet(this, _state).columns,
|
|
656
|
+
sourceColumns: __privateGet(this, _state).columns,
|
|
657
|
+
positions: ordering.map(({ position }) => position),
|
|
658
|
+
index: ordering.map(({ indexLabel }) => indexLabel),
|
|
659
|
+
indexKind: __privateGet(this, _state).indexKind,
|
|
660
|
+
schema: {
|
|
661
|
+
tableSchema: __privateGet(this, _state).tableSchema,
|
|
662
|
+
tableIndexField: __privateGet(this, _state).tableIndexField
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
select(...columns) {
|
|
667
|
+
const seen = /* @__PURE__ */ new Set();
|
|
668
|
+
for (const column of columns) {
|
|
669
|
+
if (!__privateGet(this, _state).data.has(column)) {
|
|
670
|
+
throw new JsonFrameValidationError("Selected columns must exist in the frame.", {
|
|
671
|
+
path: "$.columns",
|
|
672
|
+
column,
|
|
673
|
+
value: column
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
if (seen.has(column)) {
|
|
677
|
+
throw new JsonFrameValidationError("Selected columns must be unique.", {
|
|
678
|
+
path: "$.columns",
|
|
679
|
+
column,
|
|
680
|
+
value: column
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
seen.add(column);
|
|
684
|
+
}
|
|
685
|
+
const selectedSchema = __privateMethod(this, _DataFrame_instances, selectSchema_fn).call(this, columns);
|
|
686
|
+
return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
|
|
687
|
+
columns,
|
|
688
|
+
sourceColumns: columns,
|
|
689
|
+
positions: __privateGet(this, _state).index.map((_, position) => position),
|
|
690
|
+
index: __privateGet(this, _state).index,
|
|
691
|
+
indexKind: __privateGet(this, _state).indexKind,
|
|
692
|
+
schema: selectedSchema
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
rename(mapping) {
|
|
696
|
+
const nextColumns = __privateGet(this, _state).columns.map((column) => hasOwn.call(mapping, column) ? mapping[column] : column);
|
|
697
|
+
const seen = /* @__PURE__ */ new Set();
|
|
698
|
+
for (let position = 0; position < nextColumns.length; position += 1) {
|
|
699
|
+
const column = nextColumns[position];
|
|
700
|
+
if (seen.has(column)) {
|
|
701
|
+
throw new JsonFrameValidationError("Renamed columns must remain unique.", {
|
|
702
|
+
path: "$.columns",
|
|
703
|
+
column,
|
|
704
|
+
value: column
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
seen.add(column);
|
|
708
|
+
}
|
|
709
|
+
const renamedSchema = __privateMethod(this, _DataFrame_instances, renameSchema_fn).call(this, mapping);
|
|
710
|
+
return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
|
|
711
|
+
columns: nextColumns,
|
|
712
|
+
sourceColumns: __privateGet(this, _state).columns,
|
|
713
|
+
positions: __privateGet(this, _state).index.map((_, position) => position),
|
|
714
|
+
index: __privateGet(this, _state).index,
|
|
715
|
+
indexKind: __privateGet(this, _state).indexKind,
|
|
716
|
+
schema: renamedSchema
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
resetIndex() {
|
|
720
|
+
const resetSchema = __privateMethod(this, _DataFrame_instances, resetIndexSchema_fn).call(this);
|
|
721
|
+
return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
|
|
722
|
+
columns: __privateGet(this, _state).columns,
|
|
723
|
+
sourceColumns: __privateGet(this, _state).columns,
|
|
724
|
+
positions: __privateGet(this, _state).index.map((_, position) => position),
|
|
725
|
+
index: __privateGet(this, _state).index.map((_, position) => position),
|
|
726
|
+
indexKind: "synthetic",
|
|
727
|
+
schema: resetSchema
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
_state = new WeakMap();
|
|
732
|
+
_packThreshold = new WeakMap();
|
|
733
|
+
_DataFrame_instances = new WeakSet();
|
|
734
|
+
assertRowPosition_fn = function(position) {
|
|
735
|
+
if (!Number.isInteger(position) || position < 0 || position >= this.length) {
|
|
736
|
+
throw new RangeError(`Row position must be an integer in [0, ${this.length}).`);
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
materializedData_fn = function() {
|
|
740
|
+
return materializeFrameData(__privateGet(this, _state).columns, __privateGet(this, _state).data);
|
|
741
|
+
};
|
|
742
|
+
createRow_fn = function(materialized, position) {
|
|
743
|
+
const row = /* @__PURE__ */ Object.create(null);
|
|
744
|
+
for (const column of __privateGet(this, _state).columns) {
|
|
745
|
+
row[column] = materialized.get(column)[position];
|
|
746
|
+
}
|
|
747
|
+
return Object.freeze(row);
|
|
748
|
+
};
|
|
749
|
+
columnTypeOverrides_fn = function(columns, sourceColumns) {
|
|
750
|
+
return Object.freeze(
|
|
751
|
+
Object.fromEntries(
|
|
752
|
+
columns.map((column, position) => [column, __privateGet(this, _state).columnInfo.get(sourceColumns[position]).type])
|
|
753
|
+
)
|
|
754
|
+
);
|
|
755
|
+
};
|
|
756
|
+
rebuild_fn = function({
|
|
757
|
+
columns,
|
|
758
|
+
sourceColumns,
|
|
759
|
+
positions,
|
|
760
|
+
index,
|
|
761
|
+
indexKind,
|
|
762
|
+
schema
|
|
763
|
+
}) {
|
|
764
|
+
const materialized = __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this);
|
|
765
|
+
const nextData = /* @__PURE__ */ new Map();
|
|
766
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
767
|
+
const column = columns[columnIndex];
|
|
768
|
+
const sourceColumn = materialized.get(sourceColumns[columnIndex]);
|
|
769
|
+
if (sourceColumn === void 0) {
|
|
770
|
+
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
771
|
+
path: "$",
|
|
772
|
+
column
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
nextData.set(column, freezeArray2(positions.map((position) => sourceColumn[position])));
|
|
776
|
+
}
|
|
777
|
+
const state = createFrameStateFromData(
|
|
778
|
+
{
|
|
779
|
+
columns,
|
|
780
|
+
index,
|
|
781
|
+
indexKind,
|
|
782
|
+
data: nextData,
|
|
783
|
+
...schema.tableSchema === void 0 ? {} : { tableSchema: schema.tableSchema },
|
|
784
|
+
...schema.tableIndexField === void 0 ? {} : { tableIndexField: schema.tableIndexField }
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
packThreshold: __privateGet(this, _packThreshold),
|
|
788
|
+
columnTypes: __privateMethod(this, _DataFrame_instances, columnTypeOverrides_fn).call(this, columns, sourceColumns)
|
|
789
|
+
}
|
|
790
|
+
);
|
|
791
|
+
return createDataFrame(state, __privateGet(this, _packThreshold));
|
|
792
|
+
};
|
|
793
|
+
selectSchema_fn = function(columns) {
|
|
794
|
+
if (__privateGet(this, _state).tableSchema === void 0) {
|
|
795
|
+
return {};
|
|
796
|
+
}
|
|
797
|
+
const fieldByName = new Map(__privateGet(this, _state).tableSchema.fields.map((field) => [field.name, field]));
|
|
798
|
+
const fields = [];
|
|
799
|
+
if (__privateGet(this, _state).tableIndexField !== void 0) {
|
|
800
|
+
const indexField = fieldByName.get(__privateGet(this, _state).tableIndexField);
|
|
801
|
+
if (indexField !== void 0) {
|
|
802
|
+
fields.push(cloneField(indexField));
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
for (const column of columns) {
|
|
806
|
+
const field = fieldByName.get(column);
|
|
807
|
+
if (field !== void 0) {
|
|
808
|
+
fields.push(cloneField(field));
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return {
|
|
812
|
+
tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields, __privateGet(this, _state).tableSchema.primaryKey),
|
|
813
|
+
...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
|
|
814
|
+
};
|
|
815
|
+
};
|
|
816
|
+
renameSchema_fn = function(mapping) {
|
|
817
|
+
if (__privateGet(this, _state).tableSchema === void 0) {
|
|
818
|
+
return {};
|
|
819
|
+
}
|
|
820
|
+
const fields = __privateGet(this, _state).tableSchema.fields.map((field) => {
|
|
821
|
+
if (!__privateGet(this, _state).columns.includes(field.name)) {
|
|
822
|
+
return cloneField(field);
|
|
823
|
+
}
|
|
824
|
+
return cloneField(field, hasOwn.call(mapping, field.name) ? mapping[field.name] : field.name);
|
|
825
|
+
});
|
|
826
|
+
return {
|
|
827
|
+
tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields, __privateGet(this, _state).tableSchema.primaryKey),
|
|
828
|
+
...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
resetIndexSchema_fn = function() {
|
|
832
|
+
if (__privateGet(this, _state).tableSchema === void 0) {
|
|
833
|
+
return {};
|
|
834
|
+
}
|
|
835
|
+
if (__privateGet(this, _state).tableIndexField === void 0) {
|
|
836
|
+
return {
|
|
837
|
+
tableSchema: cloneSchema2(
|
|
838
|
+
__privateGet(this, _state).tableSchema,
|
|
839
|
+
__privateGet(this, _state).tableSchema.fields.map((field) => cloneField(field))
|
|
840
|
+
)
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
const fields = __privateGet(this, _state).tableSchema.fields.filter((field) => field.name !== __privateGet(this, _state).tableIndexField).map((field) => cloneField(field));
|
|
844
|
+
return {
|
|
845
|
+
tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields)
|
|
846
|
+
};
|
|
847
|
+
};
|
|
848
|
+
var InternalDataFrame = class extends DataFrame {
|
|
849
|
+
constructor(state, packThreshold) {
|
|
850
|
+
super(state, packThreshold);
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
var createDataFrame = (state, packThreshold) => new InternalDataFrame(state, packThreshold);
|
|
854
|
+
|
|
855
|
+
// src/options.ts
|
|
856
|
+
var RESOLVED_ORIENTS = [
|
|
857
|
+
"records",
|
|
858
|
+
"index",
|
|
859
|
+
"columns",
|
|
860
|
+
"values",
|
|
861
|
+
"split",
|
|
862
|
+
"table"
|
|
863
|
+
];
|
|
864
|
+
var ORIENTS = ["auto", ...RESOLVED_ORIENTS];
|
|
865
|
+
var COLUMN_TYPES = [
|
|
866
|
+
"integer",
|
|
867
|
+
"float",
|
|
868
|
+
"string",
|
|
869
|
+
"boolean",
|
|
870
|
+
"datetime",
|
|
871
|
+
"categorical",
|
|
872
|
+
"mixed",
|
|
873
|
+
"unknown"
|
|
874
|
+
];
|
|
875
|
+
var DEFAULT_PACK_THRESHOLD = 256;
|
|
876
|
+
var isOrient = (value) => typeof value === "string" && ORIENTS.includes(value);
|
|
877
|
+
var isColumnType = (value) => typeof value === "string" && COLUMN_TYPES.includes(value);
|
|
878
|
+
var normalizeFromOrientOptions = (options) => {
|
|
879
|
+
if (options == null) {
|
|
880
|
+
return {
|
|
881
|
+
orient: "auto",
|
|
882
|
+
packThreshold: DEFAULT_PACK_THRESHOLD
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
if (Array.isArray(options) || typeof options !== "object") {
|
|
886
|
+
throw new JsonFrameOptionError("`fromOrient` options must be an object when provided.", "options", options);
|
|
887
|
+
}
|
|
888
|
+
const orient = options.orient ?? "auto";
|
|
889
|
+
if (!isOrient(orient)) {
|
|
890
|
+
throw new JsonFrameOptionError(
|
|
891
|
+
"`options.orient` must be one of auto, records, index, columns, values, split, or table.",
|
|
892
|
+
"orient",
|
|
893
|
+
orient
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
const packThreshold = options.packThreshold ?? DEFAULT_PACK_THRESHOLD;
|
|
897
|
+
if (!Number.isFinite(packThreshold) || !Number.isInteger(packThreshold) || packThreshold < 0) {
|
|
898
|
+
throw new JsonFrameOptionError(
|
|
899
|
+
"`options.packThreshold` must be a finite non-negative integer.",
|
|
900
|
+
"packThreshold",
|
|
901
|
+
packThreshold
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
let columns;
|
|
905
|
+
if (options.columns !== void 0) {
|
|
906
|
+
if (!Array.isArray(options.columns)) {
|
|
907
|
+
throw new JsonFrameOptionError("`options.columns` must be an array of strings.", "columns", options.columns);
|
|
908
|
+
}
|
|
909
|
+
const seen = /* @__PURE__ */ new Set();
|
|
910
|
+
columns = options.columns.map((column) => {
|
|
911
|
+
if (typeof column !== "string") {
|
|
912
|
+
throw new JsonFrameOptionError("`options.columns` must contain only strings.", "columns", column);
|
|
913
|
+
}
|
|
914
|
+
if (seen.has(column)) {
|
|
915
|
+
throw new JsonFrameOptionError("`options.columns` must not contain duplicates.", "columns", column);
|
|
916
|
+
}
|
|
917
|
+
seen.add(column);
|
|
918
|
+
return column;
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
let columnTypes;
|
|
922
|
+
if (options.columnTypes !== void 0) {
|
|
923
|
+
if (Array.isArray(options.columnTypes) || typeof options.columnTypes !== "object" || options.columnTypes === null) {
|
|
924
|
+
throw new JsonFrameOptionError(
|
|
925
|
+
"`options.columnTypes` must be an object keyed by column name.",
|
|
926
|
+
"columnTypes",
|
|
927
|
+
options.columnTypes
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
const entries = Object.entries(options.columnTypes);
|
|
931
|
+
columnTypes = Object.freeze(
|
|
932
|
+
Object.fromEntries(
|
|
933
|
+
entries.map(([column, type]) => {
|
|
934
|
+
if (!isColumnType(type)) {
|
|
935
|
+
throw new JsonFrameOptionError(
|
|
936
|
+
"`options.columnTypes` values must be valid JSON Frame logical column types.",
|
|
937
|
+
`columnTypes.${column}`,
|
|
938
|
+
type
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
return [column, type];
|
|
942
|
+
})
|
|
943
|
+
)
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
return {
|
|
947
|
+
orient,
|
|
948
|
+
packThreshold,
|
|
949
|
+
...columns === void 0 ? {} : { columns: Object.freeze([...columns]) },
|
|
950
|
+
...columnTypes === void 0 ? {} : { columnTypes }
|
|
951
|
+
};
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
// src/parse/parse.ts
|
|
955
|
+
var hasOwn2 = Object.prototype.hasOwnProperty;
|
|
956
|
+
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
957
|
+
var freezeArray3 = (values) => Object.freeze([...values]);
|
|
958
|
+
var appendPropertyPath = (path, key) => IDENTIFIER_PATTERN.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
|
|
959
|
+
var appendIndexPath = (path, index) => `${path}[${index}]`;
|
|
960
|
+
var isPlainObject = (value) => {
|
|
961
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
962
|
+
return false;
|
|
963
|
+
}
|
|
964
|
+
const prototype = Object.getPrototypeOf(value);
|
|
965
|
+
return prototype === Object.prototype || prototype === null;
|
|
966
|
+
};
|
|
967
|
+
var assertSupportedIndexLabel = (value, orient, path) => {
|
|
968
|
+
if (typeof value === "string") {
|
|
969
|
+
return value;
|
|
970
|
+
}
|
|
971
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
972
|
+
return value;
|
|
973
|
+
}
|
|
974
|
+
throw new JsonFrameValidationError("Index labels must be strings or finite numbers.", {
|
|
975
|
+
orient,
|
|
976
|
+
path,
|
|
977
|
+
value
|
|
978
|
+
});
|
|
979
|
+
};
|
|
980
|
+
var assertUniqueStringColumns = (values, orient, path) => {
|
|
981
|
+
const columns = [];
|
|
982
|
+
const seen = /* @__PURE__ */ new Set();
|
|
983
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
984
|
+
const value = values[index];
|
|
985
|
+
const entryPath = appendIndexPath(path, index);
|
|
986
|
+
if (typeof value !== "string") {
|
|
987
|
+
throw new JsonFrameValidationError("Column labels must be strings.", {
|
|
988
|
+
orient,
|
|
989
|
+
path: entryPath,
|
|
990
|
+
value
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
if (seen.has(value)) {
|
|
994
|
+
throw new JsonFrameValidationError("Column labels must be unique.", {
|
|
995
|
+
orient,
|
|
996
|
+
path: entryPath,
|
|
997
|
+
column: value,
|
|
998
|
+
value
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
seen.add(value);
|
|
1002
|
+
columns.push(value);
|
|
1003
|
+
}
|
|
1004
|
+
return freezeArray3(columns);
|
|
1005
|
+
};
|
|
1006
|
+
var initializeData = (columns) => new Map(columns.map((column) => [column, []]));
|
|
1007
|
+
var finalizeFrame = ({
|
|
1008
|
+
orient,
|
|
1009
|
+
columns,
|
|
1010
|
+
index,
|
|
1011
|
+
indexKind,
|
|
1012
|
+
data,
|
|
1013
|
+
tableSchema,
|
|
1014
|
+
tableIndexField
|
|
1015
|
+
}) => {
|
|
1016
|
+
const finalizedData = /* @__PURE__ */ new Map();
|
|
1017
|
+
for (const column of columns) {
|
|
1018
|
+
const values = data.get(column);
|
|
1019
|
+
if (values === void 0) {
|
|
1020
|
+
throw new JsonFrameValidationError("Parsed frame data is missing a declared column.", {
|
|
1021
|
+
orient,
|
|
1022
|
+
column
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
finalizedData.set(column, freezeArray3(values));
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
orient,
|
|
1029
|
+
columns: freezeArray3(columns),
|
|
1030
|
+
index: freezeArray3(index),
|
|
1031
|
+
indexKind,
|
|
1032
|
+
data: finalizedData,
|
|
1033
|
+
...tableSchema === void 0 ? {} : { tableSchema },
|
|
1034
|
+
...tableIndexField === void 0 ? {} : { tableIndexField }
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
1037
|
+
var validateJsonCompatible = (value, path = "$", stack = /* @__PURE__ */ new Set()) => {
|
|
1038
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
1039
|
+
return value;
|
|
1040
|
+
}
|
|
1041
|
+
if (typeof value === "number") {
|
|
1042
|
+
if (!Number.isFinite(value)) {
|
|
1043
|
+
throw new JsonFrameValidationError("Numbers must be finite JSON values.", { path, value });
|
|
1044
|
+
}
|
|
1045
|
+
return value;
|
|
1046
|
+
}
|
|
1047
|
+
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") {
|
|
1048
|
+
throw new JsonFrameValidationError("Input must contain only JSON-compatible values.", { path, value });
|
|
1049
|
+
}
|
|
1050
|
+
if (Array.isArray(value)) {
|
|
1051
|
+
if (stack.has(value)) {
|
|
1052
|
+
throw new JsonFrameValidationError("Input contains a cyclic array.", { path, value });
|
|
1053
|
+
}
|
|
1054
|
+
stack.add(value);
|
|
1055
|
+
const normalized2 = [];
|
|
1056
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
1057
|
+
if (!(index in value)) {
|
|
1058
|
+
stack.delete(value);
|
|
1059
|
+
throw new JsonFrameValidationError("Sparse arrays are not valid JSON input.", {
|
|
1060
|
+
path: appendIndexPath(path, index),
|
|
1061
|
+
value
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
normalized2.push(validateJsonCompatible(value[index], appendIndexPath(path, index), stack));
|
|
1065
|
+
}
|
|
1066
|
+
stack.delete(value);
|
|
1067
|
+
return normalized2;
|
|
1068
|
+
}
|
|
1069
|
+
if (!isPlainObject(value)) {
|
|
1070
|
+
throw new JsonFrameValidationError("Input objects must be plain JSON objects or arrays.", { path, value });
|
|
1071
|
+
}
|
|
1072
|
+
if (stack.has(value)) {
|
|
1073
|
+
throw new JsonFrameValidationError("Input contains a cyclic object.", { path, value });
|
|
1074
|
+
}
|
|
1075
|
+
stack.add(value);
|
|
1076
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
1077
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
1078
|
+
normalized[key] = validateJsonCompatible(entryValue, appendPropertyPath(path, key), stack);
|
|
1079
|
+
}
|
|
1080
|
+
stack.delete(value);
|
|
1081
|
+
return normalized;
|
|
1082
|
+
};
|
|
1083
|
+
var detectOrient = (value) => {
|
|
1084
|
+
if (Array.isArray(value)) {
|
|
1085
|
+
if (value.length === 0) {
|
|
1086
|
+
throw new AmbiguousOrientError(
|
|
1087
|
+
"Auto detection cannot distinguish between empty records and empty values payloads.",
|
|
1088
|
+
["records", "values"]
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
if (value.every((entry) => Array.isArray(entry))) {
|
|
1092
|
+
return "values";
|
|
1093
|
+
}
|
|
1094
|
+
if (value.every((entry) => isPlainObject(entry))) {
|
|
1095
|
+
return "records";
|
|
1096
|
+
}
|
|
1097
|
+
throw new JsonFrameValidationError("Auto detection requires a non-empty array of row objects or row arrays.", {
|
|
1098
|
+
path: "$",
|
|
1099
|
+
value
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
if (!isPlainObject(value)) {
|
|
1103
|
+
throw new JsonFrameValidationError("Auto detection requires a JSON array or object payload.", {
|
|
1104
|
+
path: "$",
|
|
1105
|
+
value
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
if (isPlainObject(value.schema) && Array.isArray(value.data)) {
|
|
1109
|
+
return "table";
|
|
1110
|
+
}
|
|
1111
|
+
if (Array.isArray(value.columns) && Array.isArray(value.data) && (value.index === void 0 || Array.isArray(value.index))) {
|
|
1112
|
+
return "split";
|
|
1113
|
+
}
|
|
1114
|
+
const keys = Object.keys(value);
|
|
1115
|
+
if (keys.length === 0 || keys.every((key) => isPlainObject(value[key]))) {
|
|
1116
|
+
throw new AmbiguousOrientError("Auto detection cannot distinguish between index and columns payloads.", [
|
|
1117
|
+
"index",
|
|
1118
|
+
"columns"
|
|
1119
|
+
]);
|
|
1120
|
+
}
|
|
1121
|
+
throw new JsonFrameValidationError("Auto detection could not resolve the payload orient.", {
|
|
1122
|
+
path: "$",
|
|
1123
|
+
value
|
|
1124
|
+
});
|
|
1125
|
+
};
|
|
1126
|
+
var parseRecords = (value, orient) => {
|
|
1127
|
+
if (!Array.isArray(value)) {
|
|
1128
|
+
throw new JsonFrameValidationError("`records` payloads must be arrays.", { orient, path: "$", value });
|
|
1129
|
+
}
|
|
1130
|
+
const columns = [];
|
|
1131
|
+
const knownColumns = /* @__PURE__ */ new Set();
|
|
1132
|
+
const data = /* @__PURE__ */ new Map();
|
|
1133
|
+
const index = [];
|
|
1134
|
+
for (let rowIndex = 0; rowIndex < value.length; rowIndex += 1) {
|
|
1135
|
+
const row = value[rowIndex];
|
|
1136
|
+
const rowPath = appendIndexPath("$", rowIndex);
|
|
1137
|
+
if (!isPlainObject(row)) {
|
|
1138
|
+
throw new JsonFrameValidationError("`records` rows must be JSON objects.", {
|
|
1139
|
+
orient,
|
|
1140
|
+
path: rowPath,
|
|
1141
|
+
row: rowIndex,
|
|
1142
|
+
value: row
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
for (const column of Object.keys(row)) {
|
|
1146
|
+
if (!knownColumns.has(column)) {
|
|
1147
|
+
knownColumns.add(column);
|
|
1148
|
+
columns.push(column);
|
|
1149
|
+
data.set(column, Array(rowIndex).fill(null));
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
for (const column of columns) {
|
|
1153
|
+
data.get(column).push(hasOwn2.call(row, column) ? row[column] : null);
|
|
1154
|
+
}
|
|
1155
|
+
index.push(rowIndex);
|
|
1156
|
+
}
|
|
1157
|
+
return finalizeFrame({
|
|
1158
|
+
orient,
|
|
1159
|
+
columns,
|
|
1160
|
+
index,
|
|
1161
|
+
indexKind: "synthetic",
|
|
1162
|
+
data
|
|
1163
|
+
});
|
|
1164
|
+
};
|
|
1165
|
+
var parseIndex = (value, orient) => {
|
|
1166
|
+
if (!isPlainObject(value)) {
|
|
1167
|
+
throw new JsonFrameValidationError("`index` payloads must be objects keyed by index label.", {
|
|
1168
|
+
orient,
|
|
1169
|
+
path: "$",
|
|
1170
|
+
value
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
const columns = [];
|
|
1174
|
+
const knownColumns = /* @__PURE__ */ new Set();
|
|
1175
|
+
const data = /* @__PURE__ */ new Map();
|
|
1176
|
+
const index = Object.keys(value);
|
|
1177
|
+
for (let rowIndex = 0; rowIndex < index.length; rowIndex += 1) {
|
|
1178
|
+
const indexLabel = index[rowIndex];
|
|
1179
|
+
const row = value[indexLabel];
|
|
1180
|
+
const rowPath = appendPropertyPath("$", indexLabel);
|
|
1181
|
+
if (!isPlainObject(row)) {
|
|
1182
|
+
throw new JsonFrameValidationError("`index` payload rows must be JSON objects.", {
|
|
1183
|
+
orient,
|
|
1184
|
+
path: rowPath,
|
|
1185
|
+
row: rowIndex,
|
|
1186
|
+
value: row
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
for (const column of Object.keys(row)) {
|
|
1190
|
+
if (!knownColumns.has(column)) {
|
|
1191
|
+
knownColumns.add(column);
|
|
1192
|
+
columns.push(column);
|
|
1193
|
+
data.set(column, Array(rowIndex).fill(null));
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
for (const column of columns) {
|
|
1197
|
+
data.get(column).push(hasOwn2.call(row, column) ? row[column] : null);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return finalizeFrame({
|
|
1201
|
+
orient,
|
|
1202
|
+
columns,
|
|
1203
|
+
index,
|
|
1204
|
+
indexKind: "source",
|
|
1205
|
+
data
|
|
1206
|
+
});
|
|
1207
|
+
};
|
|
1208
|
+
var parseColumns = (value, orient) => {
|
|
1209
|
+
if (!isPlainObject(value)) {
|
|
1210
|
+
throw new JsonFrameValidationError("`columns` payloads must be objects keyed by column label.", {
|
|
1211
|
+
orient,
|
|
1212
|
+
path: "$",
|
|
1213
|
+
value
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
const columns = Object.keys(value);
|
|
1217
|
+
const data = /* @__PURE__ */ new Map();
|
|
1218
|
+
if (columns.length === 0) {
|
|
1219
|
+
return finalizeFrame({
|
|
1220
|
+
orient,
|
|
1221
|
+
columns,
|
|
1222
|
+
index: [],
|
|
1223
|
+
indexKind: "source",
|
|
1224
|
+
data
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
let index;
|
|
1228
|
+
for (const column of columns) {
|
|
1229
|
+
const columnValue = value[column];
|
|
1230
|
+
const columnPath = appendPropertyPath("$", column);
|
|
1231
|
+
if (!isPlainObject(columnValue)) {
|
|
1232
|
+
throw new JsonFrameValidationError("`columns` payload values must be objects keyed by index label.", {
|
|
1233
|
+
orient,
|
|
1234
|
+
path: columnPath,
|
|
1235
|
+
column,
|
|
1236
|
+
value: columnValue
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
const keys = Object.keys(columnValue);
|
|
1240
|
+
if (index === void 0) {
|
|
1241
|
+
index = freezeArray3(keys);
|
|
1242
|
+
} else if (keys.length !== index.length || keys.some((key, indexPosition) => key !== index[indexPosition])) {
|
|
1243
|
+
throw new JsonFrameValidationError("Every `columns` payload column must expose the same ordered index keys.", {
|
|
1244
|
+
orient,
|
|
1245
|
+
path: columnPath,
|
|
1246
|
+
column,
|
|
1247
|
+
value: columnValue
|
|
1248
|
+
});
|
|
1249
|
+
}
|
|
1250
|
+
data.set(
|
|
1251
|
+
column,
|
|
1252
|
+
keys.map((indexKey) => columnValue[indexKey])
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
return finalizeFrame({
|
|
1256
|
+
orient,
|
|
1257
|
+
columns,
|
|
1258
|
+
index: index ?? [],
|
|
1259
|
+
indexKind: "source",
|
|
1260
|
+
data
|
|
1261
|
+
});
|
|
1262
|
+
};
|
|
1263
|
+
var parseValues = (value, options, orient) => {
|
|
1264
|
+
if (options.columns === void 0) {
|
|
1265
|
+
throw new JsonFrameOptionError(
|
|
1266
|
+
'`options.columns` is required for `orient="values"` input.',
|
|
1267
|
+
"columns",
|
|
1268
|
+
options.columns
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
if (!Array.isArray(value)) {
|
|
1272
|
+
throw new JsonFrameValidationError("`values` payloads must be arrays of arrays.", { orient, path: "$", value });
|
|
1273
|
+
}
|
|
1274
|
+
const columns = [...options.columns];
|
|
1275
|
+
const data = initializeData(columns);
|
|
1276
|
+
const index = [];
|
|
1277
|
+
for (let rowIndex = 0; rowIndex < value.length; rowIndex += 1) {
|
|
1278
|
+
const row = value[rowIndex];
|
|
1279
|
+
const rowPath = appendIndexPath("$", rowIndex);
|
|
1280
|
+
if (!Array.isArray(row)) {
|
|
1281
|
+
throw new JsonFrameValidationError("`values` rows must be arrays.", {
|
|
1282
|
+
orient,
|
|
1283
|
+
path: rowPath,
|
|
1284
|
+
row: rowIndex,
|
|
1285
|
+
value: row
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
if (row.length !== columns.length) {
|
|
1289
|
+
throw new JsonFrameValidationError("`values` row widths must match `options.columns`.", {
|
|
1290
|
+
orient,
|
|
1291
|
+
path: rowPath,
|
|
1292
|
+
row: rowIndex,
|
|
1293
|
+
value: row
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
1297
|
+
data.get(columns[columnIndex]).push(row[columnIndex]);
|
|
1298
|
+
}
|
|
1299
|
+
index.push(rowIndex);
|
|
1300
|
+
}
|
|
1301
|
+
return finalizeFrame({
|
|
1302
|
+
orient,
|
|
1303
|
+
columns,
|
|
1304
|
+
index,
|
|
1305
|
+
indexKind: "synthetic",
|
|
1306
|
+
data
|
|
1307
|
+
});
|
|
1308
|
+
};
|
|
1309
|
+
var parseSplit = (value, orient) => {
|
|
1310
|
+
if (!isPlainObject(value)) {
|
|
1311
|
+
throw new JsonFrameValidationError("`split` payloads must be objects.", { orient, path: "$", value });
|
|
1312
|
+
}
|
|
1313
|
+
if (!Array.isArray(value.columns)) {
|
|
1314
|
+
throw new JsonFrameValidationError("`split.columns` must be an array of unique strings.", {
|
|
1315
|
+
orient,
|
|
1316
|
+
path: "$.columns",
|
|
1317
|
+
value: value.columns
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
if (!Array.isArray(value.data)) {
|
|
1321
|
+
throw new JsonFrameValidationError("`split.data` must be an array of row arrays.", {
|
|
1322
|
+
orient,
|
|
1323
|
+
path: "$.data",
|
|
1324
|
+
value: value.data
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
const columns = assertUniqueStringColumns(value.columns, orient, "$.columns");
|
|
1328
|
+
const data = initializeData(columns);
|
|
1329
|
+
const index = [];
|
|
1330
|
+
const indexKind = Array.isArray(value.index) ? "source" : "synthetic";
|
|
1331
|
+
if (Array.isArray(value.index)) {
|
|
1332
|
+
for (let indexPosition = 0; indexPosition < value.index.length; indexPosition += 1) {
|
|
1333
|
+
index.push(
|
|
1334
|
+
assertSupportedIndexLabel(
|
|
1335
|
+
value.index[indexPosition],
|
|
1336
|
+
orient,
|
|
1337
|
+
appendIndexPath("$.index", indexPosition)
|
|
1338
|
+
)
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
const rows = value.data;
|
|
1343
|
+
if (indexKind === "source" && index.length !== rows.length) {
|
|
1344
|
+
throw new JsonFrameValidationError("`split.index` length must match `split.data` length.", {
|
|
1345
|
+
orient,
|
|
1346
|
+
path: "$.index",
|
|
1347
|
+
value: value.index
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex += 1) {
|
|
1351
|
+
const row = rows[rowIndex];
|
|
1352
|
+
const rowPath = appendIndexPath("$.data", rowIndex);
|
|
1353
|
+
if (!Array.isArray(row)) {
|
|
1354
|
+
throw new JsonFrameValidationError("`split.data` rows must be arrays.", {
|
|
1355
|
+
orient,
|
|
1356
|
+
path: rowPath,
|
|
1357
|
+
row: rowIndex,
|
|
1358
|
+
value: row
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
if (row.length !== columns.length) {
|
|
1362
|
+
throw new JsonFrameValidationError("`split.data` row widths must match `split.columns`.", {
|
|
1363
|
+
orient,
|
|
1364
|
+
path: rowPath,
|
|
1365
|
+
row: rowIndex,
|
|
1366
|
+
value: row
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
1370
|
+
data.get(columns[columnIndex]).push(row[columnIndex]);
|
|
1371
|
+
}
|
|
1372
|
+
if (indexKind === "synthetic") {
|
|
1373
|
+
index.push(rowIndex);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
return finalizeFrame({
|
|
1377
|
+
orient,
|
|
1378
|
+
columns,
|
|
1379
|
+
index,
|
|
1380
|
+
indexKind,
|
|
1381
|
+
data
|
|
1382
|
+
});
|
|
1383
|
+
};
|
|
1384
|
+
var cloneConstraints = (value, orient, path) => {
|
|
1385
|
+
if (!isPlainObject(value)) {
|
|
1386
|
+
throw new JsonFrameValidationError("Table Schema field constraints must be an object when present.", {
|
|
1387
|
+
orient,
|
|
1388
|
+
path,
|
|
1389
|
+
value
|
|
1390
|
+
});
|
|
1391
|
+
}
|
|
1392
|
+
const cloned = /* @__PURE__ */ Object.create(null);
|
|
1393
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
1394
|
+
if (key === "enum") {
|
|
1395
|
+
if (!Array.isArray(entryValue)) {
|
|
1396
|
+
throw new JsonFrameValidationError("Table Schema `constraints.enum` must be an array of scalar JSON values.", {
|
|
1397
|
+
orient,
|
|
1398
|
+
path: appendPropertyPath(path, key),
|
|
1399
|
+
value: entryValue
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
cloned[key] = freezeArray3(
|
|
1403
|
+
entryValue.map((enumValue, index) => {
|
|
1404
|
+
const enumPath = appendIndexPath(appendPropertyPath(path, key), index);
|
|
1405
|
+
if (enumValue === null || typeof enumValue === "string" || typeof enumValue === "boolean") {
|
|
1406
|
+
return enumValue;
|
|
1407
|
+
}
|
|
1408
|
+
if (typeof enumValue === "number" && Number.isFinite(enumValue)) {
|
|
1409
|
+
return enumValue;
|
|
1410
|
+
}
|
|
1411
|
+
throw new JsonFrameValidationError("Table Schema `constraints.enum` must contain only scalar JSON values.", {
|
|
1412
|
+
orient,
|
|
1413
|
+
path: enumPath,
|
|
1414
|
+
value: enumValue
|
|
1415
|
+
});
|
|
1416
|
+
})
|
|
1417
|
+
);
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
cloned[key] = entryValue;
|
|
1421
|
+
}
|
|
1422
|
+
return Object.freeze(cloned);
|
|
1423
|
+
};
|
|
1424
|
+
var cloneTableField = (value, index) => {
|
|
1425
|
+
const orient = "table";
|
|
1426
|
+
const path = appendIndexPath("$.schema.fields", index);
|
|
1427
|
+
if (!isPlainObject(value)) {
|
|
1428
|
+
throw new JsonFrameValidationError("Table Schema fields must be objects.", {
|
|
1429
|
+
orient,
|
|
1430
|
+
path,
|
|
1431
|
+
value
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
if (typeof value.name !== "string") {
|
|
1435
|
+
throw new JsonFrameValidationError("Table Schema field names must be strings.", {
|
|
1436
|
+
orient,
|
|
1437
|
+
path: appendPropertyPath(path, "name"),
|
|
1438
|
+
value: value.name
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
if (typeof value.type !== "string") {
|
|
1442
|
+
throw new JsonFrameValidationError("Table Schema field types must be strings.", {
|
|
1443
|
+
orient,
|
|
1444
|
+
path: appendPropertyPath(path, "type"),
|
|
1445
|
+
value: value.type
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
if (value.ordered !== void 0 && typeof value.ordered !== "boolean") {
|
|
1449
|
+
throw new JsonFrameValidationError("Table Schema `ordered` must be boolean when present.", {
|
|
1450
|
+
orient,
|
|
1451
|
+
path: appendPropertyPath(path, "ordered"),
|
|
1452
|
+
value: value.ordered
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
const stringKeys = ["format", "extDtype", "tz", "freq"];
|
|
1456
|
+
for (const key of stringKeys) {
|
|
1457
|
+
const entryValue = value[key];
|
|
1458
|
+
if (entryValue !== void 0 && typeof entryValue !== "string") {
|
|
1459
|
+
throw new JsonFrameValidationError(`Table Schema \`${key}\` must be a string when present.`, {
|
|
1460
|
+
orient,
|
|
1461
|
+
path: appendPropertyPath(path, key),
|
|
1462
|
+
value: entryValue
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
const cloned = /* @__PURE__ */ Object.create(null);
|
|
1467
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
1468
|
+
cloned[key] = key === "constraints" && entryValue !== void 0 ? cloneConstraints(entryValue, orient, appendPropertyPath(path, key)) : entryValue;
|
|
1469
|
+
}
|
|
1470
|
+
return Object.freeze(cloned);
|
|
1471
|
+
};
|
|
1472
|
+
var cloneTableSchema = (value) => {
|
|
1473
|
+
const orient = "table";
|
|
1474
|
+
if (!isPlainObject(value)) {
|
|
1475
|
+
throw new JsonFrameValidationError("`table.schema` must be an object.", {
|
|
1476
|
+
orient,
|
|
1477
|
+
path: "$.schema",
|
|
1478
|
+
value
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
if (!Array.isArray(value.fields)) {
|
|
1482
|
+
throw new JsonFrameValidationError("`table.schema.fields` must be an array.", {
|
|
1483
|
+
orient,
|
|
1484
|
+
path: "$.schema.fields",
|
|
1485
|
+
value: value.fields
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
const fields = freezeArray3(value.fields.map((field, index) => cloneTableField(field, index)));
|
|
1489
|
+
const seenFieldNames = /* @__PURE__ */ new Set();
|
|
1490
|
+
for (const field of fields) {
|
|
1491
|
+
if (seenFieldNames.has(field.name)) {
|
|
1492
|
+
throw new JsonFrameValidationError("Table Schema field names must be unique.", {
|
|
1493
|
+
orient,
|
|
1494
|
+
path: "$.schema.fields",
|
|
1495
|
+
column: field.name,
|
|
1496
|
+
value: field.name
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
seenFieldNames.add(field.name);
|
|
1500
|
+
}
|
|
1501
|
+
let primaryKey;
|
|
1502
|
+
if (value.primaryKey !== void 0) {
|
|
1503
|
+
if (!Array.isArray(value.primaryKey)) {
|
|
1504
|
+
throw new JsonFrameValidationError("`table.schema.primaryKey` must be an array of strings when present.", {
|
|
1505
|
+
orient,
|
|
1506
|
+
path: "$.schema.primaryKey",
|
|
1507
|
+
value: value.primaryKey
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
primaryKey = freezeArray3(
|
|
1511
|
+
value.primaryKey.map((entryValue, index) => {
|
|
1512
|
+
if (typeof entryValue !== "string") {
|
|
1513
|
+
throw new JsonFrameValidationError("`table.schema.primaryKey` entries must be strings.", {
|
|
1514
|
+
orient,
|
|
1515
|
+
path: appendIndexPath("$.schema.primaryKey", index),
|
|
1516
|
+
value: entryValue
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
return entryValue;
|
|
1520
|
+
})
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
if (primaryKey !== void 0 && primaryKey.length > 1) {
|
|
1524
|
+
throw new UnsupportedFeatureError("MultiIndex table payloads are not supported.", "multi-index", {
|
|
1525
|
+
orient,
|
|
1526
|
+
path: "$.schema.primaryKey",
|
|
1527
|
+
value: primaryKey
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
if (value.pandas_version !== void 0 && typeof value.pandas_version !== "string") {
|
|
1531
|
+
throw new JsonFrameValidationError("`table.schema.pandas_version` must be a string when present.", {
|
|
1532
|
+
orient,
|
|
1533
|
+
path: "$.schema.pandas_version",
|
|
1534
|
+
value: value.pandas_version
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
const cloned = /* @__PURE__ */ Object.create(null);
|
|
1538
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
1539
|
+
if (key === "fields") {
|
|
1540
|
+
cloned[key] = fields;
|
|
1541
|
+
} else if (key === "primaryKey") {
|
|
1542
|
+
cloned[key] = primaryKey;
|
|
1543
|
+
} else {
|
|
1544
|
+
cloned[key] = entryValue;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return Object.freeze(cloned);
|
|
1548
|
+
};
|
|
1549
|
+
var parseTable = (value, orient) => {
|
|
1550
|
+
if (!isPlainObject(value)) {
|
|
1551
|
+
throw new JsonFrameValidationError("`table` payloads must be objects.", { orient, path: "$", value });
|
|
1552
|
+
}
|
|
1553
|
+
const schema = cloneTableSchema(value.schema);
|
|
1554
|
+
if (!Array.isArray(value.data)) {
|
|
1555
|
+
throw new JsonFrameValidationError("`table.data` must be an array of row objects.", {
|
|
1556
|
+
orient,
|
|
1557
|
+
path: "$.data",
|
|
1558
|
+
value: value.data
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
const primaryKey = schema.primaryKey?.[0];
|
|
1562
|
+
if (primaryKey !== void 0 && !schema.fields.some((field) => field.name === primaryKey)) {
|
|
1563
|
+
throw new JsonFrameValidationError("`table.schema.primaryKey` must reference a declared field.", {
|
|
1564
|
+
orient,
|
|
1565
|
+
path: "$.schema.primaryKey",
|
|
1566
|
+
column: primaryKey,
|
|
1567
|
+
value: schema.primaryKey
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
const columns = schema.fields.filter((field) => field.name !== primaryKey).map((field) => field.name);
|
|
1571
|
+
const data = initializeData(columns);
|
|
1572
|
+
const fieldNames = new Set(schema.fields.map((field) => field.name));
|
|
1573
|
+
const index = [];
|
|
1574
|
+
const indexKind = primaryKey === void 0 ? "synthetic" : "source";
|
|
1575
|
+
for (let rowIndex = 0; rowIndex < value.data.length; rowIndex += 1) {
|
|
1576
|
+
const row = value.data[rowIndex];
|
|
1577
|
+
const rowPath = appendIndexPath("$.data", rowIndex);
|
|
1578
|
+
if (!isPlainObject(row)) {
|
|
1579
|
+
throw new JsonFrameValidationError("`table.data` rows must be objects.", {
|
|
1580
|
+
orient,
|
|
1581
|
+
path: rowPath,
|
|
1582
|
+
row: rowIndex,
|
|
1583
|
+
value: row
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
for (const key of Object.keys(row)) {
|
|
1587
|
+
if (!fieldNames.has(key)) {
|
|
1588
|
+
throw new JsonFrameValidationError("`table.data` rows must not include fields missing from `schema.fields`.", {
|
|
1589
|
+
orient,
|
|
1590
|
+
path: appendPropertyPath(rowPath, key),
|
|
1591
|
+
row: rowIndex,
|
|
1592
|
+
column: key,
|
|
1593
|
+
value: row[key]
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
if (primaryKey === void 0) {
|
|
1598
|
+
index.push(rowIndex);
|
|
1599
|
+
} else if (!hasOwn2.call(row, primaryKey)) {
|
|
1600
|
+
throw new JsonFrameValidationError("`table.data` rows must include the primary-key field.", {
|
|
1601
|
+
orient,
|
|
1602
|
+
path: rowPath,
|
|
1603
|
+
row: rowIndex,
|
|
1604
|
+
column: primaryKey,
|
|
1605
|
+
value: row
|
|
1606
|
+
});
|
|
1607
|
+
} else {
|
|
1608
|
+
index.push(
|
|
1609
|
+
assertSupportedIndexLabel(row[primaryKey], orient, appendPropertyPath(rowPath, primaryKey))
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
for (const column of columns) {
|
|
1613
|
+
data.get(column).push(hasOwn2.call(row, column) ? row[column] : null);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
return finalizeFrame({
|
|
1617
|
+
orient,
|
|
1618
|
+
columns,
|
|
1619
|
+
index,
|
|
1620
|
+
indexKind,
|
|
1621
|
+
data,
|
|
1622
|
+
tableSchema: schema,
|
|
1623
|
+
...primaryKey === void 0 ? {} : { tableIndexField: primaryKey }
|
|
1624
|
+
});
|
|
1625
|
+
};
|
|
1626
|
+
var parseInput = (input, options) => {
|
|
1627
|
+
const parsedValue = (() => {
|
|
1628
|
+
if (typeof input !== "string") {
|
|
1629
|
+
return input;
|
|
1630
|
+
}
|
|
1631
|
+
try {
|
|
1632
|
+
return JSON.parse(input);
|
|
1633
|
+
} catch (error) {
|
|
1634
|
+
if (error instanceof SyntaxError) {
|
|
1635
|
+
throw new JsonFrameParseError("Failed to parse JSON input.", error);
|
|
1636
|
+
}
|
|
1637
|
+
throw error;
|
|
1638
|
+
}
|
|
1639
|
+
})();
|
|
1640
|
+
const jsonValue = validateJsonCompatible(parsedValue);
|
|
1641
|
+
const orient = options.orient === "auto" ? detectOrient(jsonValue) : options.orient;
|
|
1642
|
+
switch (orient) {
|
|
1643
|
+
case "records":
|
|
1644
|
+
return parseRecords(jsonValue, orient);
|
|
1645
|
+
case "index":
|
|
1646
|
+
return parseIndex(jsonValue, orient);
|
|
1647
|
+
case "columns":
|
|
1648
|
+
return parseColumns(jsonValue, orient);
|
|
1649
|
+
case "values":
|
|
1650
|
+
return parseValues(jsonValue, options, orient);
|
|
1651
|
+
case "split":
|
|
1652
|
+
return parseSplit(jsonValue, orient);
|
|
1653
|
+
case "table":
|
|
1654
|
+
return parseTable(jsonValue, orient);
|
|
1655
|
+
default: {
|
|
1656
|
+
const exhaustive = orient;
|
|
1657
|
+
throw new JsonFrameValidationError("Unsupported orient.", { value: exhaustive });
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
};
|
|
1661
|
+
|
|
1662
|
+
// src/api.ts
|
|
1663
|
+
function fromOrient(input, options) {
|
|
1664
|
+
const normalized = normalizeFromOrientOptions(options);
|
|
1665
|
+
const parsed = parseInput(input, normalized);
|
|
1666
|
+
return createDataFrame(createFrameState(parsed, normalized), normalized.packThreshold);
|
|
1667
|
+
}
|
|
1668
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1669
|
+
0 && (module.exports = {
|
|
1670
|
+
AmbiguousOrientError,
|
|
1671
|
+
ExportKeyCollisionError,
|
|
1672
|
+
JsonFrameError,
|
|
1673
|
+
JsonFrameOptionError,
|
|
1674
|
+
JsonFrameParseError,
|
|
1675
|
+
JsonFrameValidationError,
|
|
1676
|
+
UnsupportedFeatureError,
|
|
1677
|
+
fromOrient
|
|
1678
|
+
});
|