@web-ts-toolkit/json-frame 0.40.0 → 0.41.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/README.md +75 -16
- package/index.d.mts +115 -29
- package/index.d.ts +115 -29
- package/index.js +661 -292
- package/index.mjs +660 -292
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -8,7 +8,38 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
|
|
|
8
8
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
9
9
|
|
|
10
10
|
// src/errors.ts
|
|
11
|
+
var DIAGNOSTIC_KEY_LIMIT = 5;
|
|
11
12
|
var freezeCopy = (values) => Object.freeze([...values]);
|
|
13
|
+
var summarizeDiagnosticValue = (value) => {
|
|
14
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
return Object.freeze({ kind: "array", length: value.length });
|
|
19
|
+
}
|
|
20
|
+
if (typeof value === "object") {
|
|
21
|
+
const keys = Object.keys(value);
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
kind: "object",
|
|
24
|
+
keyCount: keys.length,
|
|
25
|
+
keys: freezeCopy(keys.slice(0, DIAGNOSTIC_KEY_LIMIT)),
|
|
26
|
+
truncated: keys.length > DIAGNOSTIC_KEY_LIMIT
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (typeof value === "undefined") {
|
|
30
|
+
return Object.freeze({ kind: "undefined" });
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === "symbol") {
|
|
33
|
+
return Object.freeze({ kind: "symbol" });
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === "bigint") {
|
|
36
|
+
return Object.freeze({ kind: "bigint" });
|
|
37
|
+
}
|
|
38
|
+
if (typeof value === "function") {
|
|
39
|
+
return Object.freeze({ kind: "function" });
|
|
40
|
+
}
|
|
41
|
+
return Object.freeze({ kind: "object", keyCount: 0, keys: freezeCopy([]), truncated: false });
|
|
42
|
+
};
|
|
12
43
|
var JsonFrameError = class extends Error {
|
|
13
44
|
constructor(message, context = {}) {
|
|
14
45
|
super(message);
|
|
@@ -18,7 +49,9 @@ var JsonFrameError = class extends Error {
|
|
|
18
49
|
this.path = context.path;
|
|
19
50
|
this.row = context.row;
|
|
20
51
|
this.column = context.column;
|
|
21
|
-
|
|
52
|
+
if ("value" in context) {
|
|
53
|
+
this.value = summarizeDiagnosticValue(context.value);
|
|
54
|
+
}
|
|
22
55
|
}
|
|
23
56
|
};
|
|
24
57
|
var JsonFrameParseError = class extends JsonFrameError {
|
|
@@ -67,25 +100,494 @@ var ExportKeyCollisionError = class extends JsonFrameError {
|
|
|
67
100
|
}
|
|
68
101
|
};
|
|
69
102
|
|
|
103
|
+
// src/frame/column.ts
|
|
104
|
+
var INT32_MIN = -2147483648;
|
|
105
|
+
var INT32_MAX = 2147483647;
|
|
106
|
+
var freezeArray = (values) => Object.freeze([...values]);
|
|
107
|
+
var freezeColumnInfo = (info) => Object.freeze({ ...info });
|
|
108
|
+
var DATETIME_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})(?:[T ](?<hour>\d{2}):(?<minute>\d{2}):(?<second>\d{2})(?:\.(?<fraction>\d{1,9}))?)?$/;
|
|
109
|
+
var columnOperationCounters = {
|
|
110
|
+
materializeColumnCalls: 0,
|
|
111
|
+
materializedCells: 0,
|
|
112
|
+
scalarReads: 0,
|
|
113
|
+
rebuiltCells: 0,
|
|
114
|
+
nullableChecks: 0
|
|
115
|
+
};
|
|
116
|
+
var hasCategoricalMetadata = (field) => field.constraints?.enum !== void 0 || field.ordered === true || field.extDtype === "category";
|
|
117
|
+
var mapTableSchemaFieldType = (field) => {
|
|
118
|
+
if (hasCategoricalMetadata(field)) {
|
|
119
|
+
return "categorical";
|
|
120
|
+
}
|
|
121
|
+
switch (field.type) {
|
|
122
|
+
case "boolean":
|
|
123
|
+
return "boolean";
|
|
124
|
+
case "integer":
|
|
125
|
+
case "year":
|
|
126
|
+
return "integer";
|
|
127
|
+
case "number":
|
|
128
|
+
return "float";
|
|
129
|
+
case "date":
|
|
130
|
+
case "datetime":
|
|
131
|
+
return "datetime";
|
|
132
|
+
case "string":
|
|
133
|
+
return "string";
|
|
134
|
+
case "any":
|
|
135
|
+
return "unknown";
|
|
136
|
+
default:
|
|
137
|
+
return "unknown";
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var inferColumnType = (values) => {
|
|
141
|
+
let nullable = false;
|
|
142
|
+
let sawBoolean = false;
|
|
143
|
+
let sawString = false;
|
|
144
|
+
let sawInteger = false;
|
|
145
|
+
let sawFloat = false;
|
|
146
|
+
let sawStructured = false;
|
|
147
|
+
for (const value of values) {
|
|
148
|
+
if (value === null) {
|
|
149
|
+
nullable = true;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (typeof value === "boolean") {
|
|
153
|
+
sawBoolean = true;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (typeof value === "string") {
|
|
157
|
+
sawString = true;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (typeof value === "number") {
|
|
161
|
+
if (Number.isInteger(value)) {
|
|
162
|
+
sawInteger = true;
|
|
163
|
+
} else {
|
|
164
|
+
sawFloat = true;
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
sawStructured = true;
|
|
169
|
+
}
|
|
170
|
+
const nonNullKinds = [sawBoolean, sawString, sawInteger || sawFloat, sawStructured].filter(Boolean).length;
|
|
171
|
+
if (nonNullKinds === 0) {
|
|
172
|
+
return freezeColumnInfo({ type: "unknown", nullable });
|
|
173
|
+
}
|
|
174
|
+
if (sawStructured || nonNullKinds > 1 || sawBoolean && (sawString || sawInteger || sawFloat)) {
|
|
175
|
+
return freezeColumnInfo({ type: "mixed", nullable });
|
|
176
|
+
}
|
|
177
|
+
if (sawString) {
|
|
178
|
+
return freezeColumnInfo({ type: "string", nullable });
|
|
179
|
+
}
|
|
180
|
+
if (sawBoolean) {
|
|
181
|
+
return freezeColumnInfo({ type: "boolean", nullable });
|
|
182
|
+
}
|
|
183
|
+
if (sawFloat) {
|
|
184
|
+
return freezeColumnInfo({ type: "float", nullable });
|
|
185
|
+
}
|
|
186
|
+
return freezeColumnInfo({ type: "integer", nullable });
|
|
187
|
+
};
|
|
188
|
+
var isPandasNaiveIsoDatetime = (value) => {
|
|
189
|
+
const match = DATETIME_PATTERN.exec(value);
|
|
190
|
+
if (match?.groups === void 0) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
const year = Number(match.groups.year);
|
|
194
|
+
const month = Number(match.groups.month);
|
|
195
|
+
const day = Number(match.groups.day);
|
|
196
|
+
const hour = match.groups.hour === void 0 ? 0 : Number(match.groups.hour);
|
|
197
|
+
const minute = match.groups.minute === void 0 ? 0 : Number(match.groups.minute);
|
|
198
|
+
const second = match.groups.second === void 0 ? 0 : Number(match.groups.second);
|
|
199
|
+
if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const normalized = new Date(Date.UTC(year, month - 1, day, hour, minute, second));
|
|
203
|
+
return normalized.getUTCFullYear() === year && normalized.getUTCMonth() === month - 1 && normalized.getUTCDate() === day && normalized.getUTCHours() === hour && normalized.getUTCMinutes() === minute && normalized.getUTCSeconds() === second;
|
|
204
|
+
};
|
|
205
|
+
var isScalarCategory = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
206
|
+
var isJsonContainer = (value) => {
|
|
207
|
+
if (Array.isArray(value)) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
if (value === null || typeof value !== "object") {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const prototype = Object.getPrototypeOf(value);
|
|
214
|
+
return prototype === Object.prototype || prototype === null;
|
|
215
|
+
};
|
|
216
|
+
var isColumnValueCompatible = (type, value) => {
|
|
217
|
+
if (value === null) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
switch (type) {
|
|
221
|
+
case "integer":
|
|
222
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
223
|
+
case "float":
|
|
224
|
+
return typeof value === "number";
|
|
225
|
+
case "string":
|
|
226
|
+
return typeof value === "string";
|
|
227
|
+
case "boolean":
|
|
228
|
+
return typeof value === "boolean";
|
|
229
|
+
case "datetime":
|
|
230
|
+
return typeof value === "string" && isPandasNaiveIsoDatetime(value);
|
|
231
|
+
case "categorical":
|
|
232
|
+
return isScalarCategory(value);
|
|
233
|
+
case "mixed":
|
|
234
|
+
case "unknown":
|
|
235
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isJsonContainer(value);
|
|
236
|
+
default: {
|
|
237
|
+
const exhaustive = type;
|
|
238
|
+
return exhaustive;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var getColumnCellPath = (orient, column, columnIndex, rowIndex, rowLabel) => {
|
|
243
|
+
switch (orient) {
|
|
244
|
+
case "records":
|
|
245
|
+
return `$[${rowIndex}][${JSON.stringify(column)}]`;
|
|
246
|
+
case "values":
|
|
247
|
+
return `$[${rowIndex}][${columnIndex}]`;
|
|
248
|
+
case "split":
|
|
249
|
+
return `$.data[${rowIndex}][${columnIndex}]`;
|
|
250
|
+
case "table":
|
|
251
|
+
return `$.data[${rowIndex}][${JSON.stringify(column)}]`;
|
|
252
|
+
case "index":
|
|
253
|
+
return `$[${JSON.stringify(String(rowLabel))}][${JSON.stringify(column)}]`;
|
|
254
|
+
case "columns":
|
|
255
|
+
return `$[${JSON.stringify(column)}][${JSON.stringify(String(rowLabel))}]`;
|
|
256
|
+
default:
|
|
257
|
+
return `$.data[${rowIndex}][${JSON.stringify(column)}]`;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
var validateColumnValuesForType = ({
|
|
261
|
+
column,
|
|
262
|
+
columnIndex,
|
|
263
|
+
values,
|
|
264
|
+
type,
|
|
265
|
+
orient,
|
|
266
|
+
index
|
|
267
|
+
}) => {
|
|
268
|
+
for (let rowIndex = 0; rowIndex < values.length; rowIndex += 1) {
|
|
269
|
+
const value = values[rowIndex];
|
|
270
|
+
if (isColumnValueCompatible(type, value)) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
throw new JsonFrameValidationError("Column cells are incompatible with the declared logical type.", {
|
|
274
|
+
...orient === void 0 ? {} : { orient },
|
|
275
|
+
path: getColumnCellPath(orient, column, columnIndex, rowIndex, index?.[rowIndex]),
|
|
276
|
+
row: rowIndex,
|
|
277
|
+
column,
|
|
278
|
+
value
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
var packColumn = (values, info, packThreshold) => {
|
|
283
|
+
if (packThreshold === 0 || values.length < packThreshold || info.nullable) {
|
|
284
|
+
return freezeArray(values);
|
|
285
|
+
}
|
|
286
|
+
if (info.type === "integer") {
|
|
287
|
+
const packed = new Int32Array(values.length);
|
|
288
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
289
|
+
const value = values[index];
|
|
290
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < INT32_MIN || value > INT32_MAX) {
|
|
291
|
+
return freezeArray(values);
|
|
292
|
+
}
|
|
293
|
+
packed[index] = value;
|
|
294
|
+
}
|
|
295
|
+
return packed;
|
|
296
|
+
}
|
|
297
|
+
if (info.type === "float") {
|
|
298
|
+
const packed = new Float64Array(values.length);
|
|
299
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
300
|
+
const value = values[index];
|
|
301
|
+
if (typeof value !== "number") {
|
|
302
|
+
return freezeArray(values);
|
|
303
|
+
}
|
|
304
|
+
packed[index] = value;
|
|
305
|
+
}
|
|
306
|
+
return packed;
|
|
307
|
+
}
|
|
308
|
+
return freezeArray(values);
|
|
309
|
+
};
|
|
310
|
+
var hasNullValue = (values) => {
|
|
311
|
+
columnOperationCounters.nullableChecks += values.length;
|
|
312
|
+
for (const value of values) {
|
|
313
|
+
if (value === null) {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
};
|
|
319
|
+
var validateExplicitColumnTypes = (columns, columnTypes) => {
|
|
320
|
+
if (columnTypes === void 0) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const knownColumns = new Set(columns);
|
|
324
|
+
for (const column of Object.keys(columnTypes)) {
|
|
325
|
+
if (!knownColumns.has(column)) {
|
|
326
|
+
throw new JsonFrameOptionError(
|
|
327
|
+
"`options.columnTypes` keys must match parsed column names.",
|
|
328
|
+
`columnTypes.${column}`,
|
|
329
|
+
columnTypes[column]
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
var resolveSchemaTypeByColumn = (frame) => {
|
|
335
|
+
if (frame.tableSchema === void 0) {
|
|
336
|
+
return /* @__PURE__ */ new Map();
|
|
337
|
+
}
|
|
338
|
+
const schemaTypes = /* @__PURE__ */ new Map();
|
|
339
|
+
for (const field of frame.tableSchema.fields) {
|
|
340
|
+
if (frame.columns.includes(field.name)) {
|
|
341
|
+
schemaTypes.set(field.name, mapTableSchemaFieldType(field));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return schemaTypes;
|
|
345
|
+
};
|
|
346
|
+
var materializeColumn = (column) => {
|
|
347
|
+
columnOperationCounters.materializeColumnCalls += 1;
|
|
348
|
+
columnOperationCounters.materializedCells += column.length;
|
|
349
|
+
return Array.isArray(column) ? freezeArray(column) : freezeArray(Array.from(column));
|
|
350
|
+
};
|
|
351
|
+
var getStoredColumnValue = (column, position) => {
|
|
352
|
+
columnOperationCounters.scalarReads += 1;
|
|
353
|
+
return column[position];
|
|
354
|
+
};
|
|
355
|
+
var rebuildStoredColumn = (column, positions) => {
|
|
356
|
+
const rebuilt = new Array(positions.length);
|
|
357
|
+
for (let index = 0; index < positions.length; index += 1) {
|
|
358
|
+
rebuilt[index] = getStoredColumnValue(column, positions[index]);
|
|
359
|
+
}
|
|
360
|
+
columnOperationCounters.rebuiltCells += positions.length;
|
|
361
|
+
return rebuilt;
|
|
362
|
+
};
|
|
363
|
+
var materializeFrameData = (columns, data) => {
|
|
364
|
+
const materialized = /* @__PURE__ */ new Map();
|
|
365
|
+
for (const column of columns) {
|
|
366
|
+
const stored = data.get(column);
|
|
367
|
+
if (stored === void 0) {
|
|
368
|
+
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
369
|
+
path: "$",
|
|
370
|
+
column
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
materialized.set(column, materializeColumn(stored));
|
|
374
|
+
}
|
|
375
|
+
return materialized;
|
|
376
|
+
};
|
|
377
|
+
var buildFrameState = (frame, options) => {
|
|
378
|
+
validateExplicitColumnTypes(frame.columns, options.columnTypes);
|
|
379
|
+
const schemaTypes = resolveSchemaTypeByColumn(frame);
|
|
380
|
+
const data = /* @__PURE__ */ new Map();
|
|
381
|
+
const columnInfo = /* @__PURE__ */ new Map();
|
|
382
|
+
for (let columnIndex = 0; columnIndex < frame.columns.length; columnIndex += 1) {
|
|
383
|
+
const column = frame.columns[columnIndex];
|
|
384
|
+
const values = frame.data.get(column);
|
|
385
|
+
if (values === void 0) {
|
|
386
|
+
throw new JsonFrameValidationError("Parsed frame data is missing a declared column.", {
|
|
387
|
+
orient: frame.orient,
|
|
388
|
+
column
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
const inferred = inferColumnType(values);
|
|
392
|
+
const resolvedType = schemaTypes.get(column) ?? options.columnTypes?.[column] ?? inferred.type;
|
|
393
|
+
if (schemaTypes.has(column) === false && options.columnTypes?.[column] !== void 0) {
|
|
394
|
+
validateColumnValuesForType({
|
|
395
|
+
column,
|
|
396
|
+
columnIndex,
|
|
397
|
+
values,
|
|
398
|
+
type: resolvedType,
|
|
399
|
+
orient: frame.orient,
|
|
400
|
+
index: frame.index
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
const info = freezeColumnInfo({ type: resolvedType, nullable: inferred.nullable });
|
|
404
|
+
columnInfo.set(column, info);
|
|
405
|
+
data.set(column, packColumn(values, info, options.packThreshold));
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
columns: freezeArray(frame.columns),
|
|
409
|
+
index: freezeArray(frame.index),
|
|
410
|
+
indexKind: frame.indexKind,
|
|
411
|
+
data,
|
|
412
|
+
columnInfo,
|
|
413
|
+
...frame.tableSchema === void 0 ? {} : { tableSchema: frame.tableSchema },
|
|
414
|
+
...frame.tableIndexField === void 0 ? {} : { tableIndexField: frame.tableIndexField }
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
var createFrameStateFromRebuiltData = (frame, options) => {
|
|
418
|
+
const data = /* @__PURE__ */ new Map();
|
|
419
|
+
const columnInfo = /* @__PURE__ */ new Map();
|
|
420
|
+
for (const column of frame.columns) {
|
|
421
|
+
const values = frame.data.get(column);
|
|
422
|
+
if (values === void 0) {
|
|
423
|
+
throw new JsonFrameValidationError("Rebuilt frame data is missing a declared column.", {
|
|
424
|
+
path: "$",
|
|
425
|
+
column
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const sourceInfo = frame.columnInfo.get(column);
|
|
429
|
+
if (sourceInfo === void 0) {
|
|
430
|
+
throw new JsonFrameValidationError("Rebuilt frame metadata is missing a declared column.", {
|
|
431
|
+
path: "$",
|
|
432
|
+
column
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
const info = freezeColumnInfo({
|
|
436
|
+
type: sourceInfo.type,
|
|
437
|
+
nullable: sourceInfo.nullable && hasNullValue(values)
|
|
438
|
+
});
|
|
439
|
+
columnInfo.set(column, info);
|
|
440
|
+
data.set(column, packColumn(values, info, options.packThreshold));
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
columns: freezeArray(frame.columns),
|
|
444
|
+
index: freezeArray(frame.index),
|
|
445
|
+
indexKind: frame.indexKind,
|
|
446
|
+
data,
|
|
447
|
+
columnInfo,
|
|
448
|
+
...frame.tableSchema === void 0 ? {} : { tableSchema: frame.tableSchema },
|
|
449
|
+
...frame.tableIndexField === void 0 ? {} : { tableIndexField: frame.tableIndexField }
|
|
450
|
+
};
|
|
451
|
+
};
|
|
452
|
+
var createFrameState = (frame, options) => buildFrameState(frame, options);
|
|
453
|
+
|
|
454
|
+
// src/json.ts
|
|
455
|
+
var JSON_FRAME_MAX_DEPTH = 1e3;
|
|
456
|
+
var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
457
|
+
var rootPath = (path) => ({ type: "root", path });
|
|
458
|
+
var isPlainObject = (value) => {
|
|
459
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
const prototype = Object.getPrototypeOf(value);
|
|
463
|
+
return prototype === Object.prototype || prototype === null;
|
|
464
|
+
};
|
|
465
|
+
var pathToString = (path) => {
|
|
466
|
+
const segments = [];
|
|
467
|
+
let current = path;
|
|
468
|
+
while (current !== void 0 && current.type !== "root") {
|
|
469
|
+
segments.push(current);
|
|
470
|
+
current = current.parent;
|
|
471
|
+
}
|
|
472
|
+
let formatted = current?.type === "root" ? current.path : "$";
|
|
473
|
+
for (let index = segments.length - 1; index >= 0; index -= 1) {
|
|
474
|
+
const segment = segments[index];
|
|
475
|
+
if (segment.type === "index") {
|
|
476
|
+
formatted += `[${segment.index}]`;
|
|
477
|
+
} else if (segment.type === "property") {
|
|
478
|
+
formatted += IDENTIFIER_PATTERN.test(segment.key) ? `.${segment.key}` : `[${JSON.stringify(segment.key)}]`;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return formatted;
|
|
482
|
+
};
|
|
483
|
+
var childIndexPath = (parent, index) => ({ parent, type: "index", index });
|
|
484
|
+
var childPropertyPath = (parent, key) => ({ parent, type: "property", key });
|
|
485
|
+
var throwValidation = (message, path, value, orient) => {
|
|
486
|
+
throw new JsonFrameValidationError(message, {
|
|
487
|
+
...orient === void 0 ? {} : { orient },
|
|
488
|
+
path: pathToString(path),
|
|
489
|
+
value
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
var cloneScalar = (value, path, orient) => {
|
|
493
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
494
|
+
return value;
|
|
495
|
+
}
|
|
496
|
+
if (typeof value === "number") {
|
|
497
|
+
if (!Number.isFinite(value)) {
|
|
498
|
+
throwValidation("Numbers must be finite JSON values.", path, value, orient);
|
|
499
|
+
}
|
|
500
|
+
return value;
|
|
501
|
+
}
|
|
502
|
+
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") {
|
|
503
|
+
throwValidation("Input must contain only JSON-compatible values.", path, value, orient);
|
|
504
|
+
}
|
|
505
|
+
return void 0;
|
|
506
|
+
};
|
|
507
|
+
var createFrame = (source, path, depth, ancestors, orient) => {
|
|
508
|
+
const scalar = cloneScalar(source, path, orient);
|
|
509
|
+
if (scalar !== void 0) {
|
|
510
|
+
return { value: scalar };
|
|
511
|
+
}
|
|
512
|
+
if (depth > JSON_FRAME_MAX_DEPTH) {
|
|
513
|
+
throwValidation(
|
|
514
|
+
`JSON input exceeds the maximum supported nesting depth of ${JSON_FRAME_MAX_DEPTH}.`,
|
|
515
|
+
path,
|
|
516
|
+
source,
|
|
517
|
+
orient
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
if (Array.isArray(source)) {
|
|
521
|
+
if (ancestors.has(source)) {
|
|
522
|
+
throwValidation("Input contains a cyclic array.", path, source, orient);
|
|
523
|
+
}
|
|
524
|
+
const target2 = [];
|
|
525
|
+
ancestors.add(source);
|
|
526
|
+
return { value: target2, frame: { kind: "array", source, target: target2, path, depth, index: 0 } };
|
|
527
|
+
}
|
|
528
|
+
if (!isPlainObject(source)) {
|
|
529
|
+
throwValidation("Input objects must be plain JSON objects or arrays.", path, source, orient);
|
|
530
|
+
}
|
|
531
|
+
const objectSource = source;
|
|
532
|
+
if (ancestors.has(objectSource)) {
|
|
533
|
+
throwValidation("Input contains a cyclic object.", path, objectSource, orient);
|
|
534
|
+
}
|
|
535
|
+
const target = /* @__PURE__ */ Object.create(null);
|
|
536
|
+
ancestors.add(objectSource);
|
|
537
|
+
return {
|
|
538
|
+
value: target,
|
|
539
|
+
frame: { kind: "object", source: objectSource, target, keys: Object.keys(objectSource), path, depth, index: 0 }
|
|
540
|
+
};
|
|
541
|
+
};
|
|
542
|
+
var cloneJsonCompatible = (value, orient, path = "$") => {
|
|
543
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
544
|
+
const root = createFrame(value, rootPath(path), 0, ancestors, orient);
|
|
545
|
+
const stack = root.frame === void 0 ? [] : [root.frame];
|
|
546
|
+
while (stack.length > 0) {
|
|
547
|
+
const frame = stack[stack.length - 1];
|
|
548
|
+
if (frame.kind === "array") {
|
|
549
|
+
if (frame.index >= frame.source.length) {
|
|
550
|
+
ancestors.delete(frame.source);
|
|
551
|
+
stack.pop();
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
const index = frame.index;
|
|
555
|
+
frame.index += 1;
|
|
556
|
+
const childPath2 = childIndexPath(frame.path, index);
|
|
557
|
+
if (!(index in frame.source)) {
|
|
558
|
+
throwValidation("Sparse arrays are not valid JSON input.", childPath2, frame.source, orient);
|
|
559
|
+
}
|
|
560
|
+
const child2 = createFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient);
|
|
561
|
+
frame.target.push(child2.value);
|
|
562
|
+
if (child2.frame !== void 0) {
|
|
563
|
+
stack.push(child2.frame);
|
|
564
|
+
}
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
if (frame.index >= frame.keys.length) {
|
|
568
|
+
ancestors.delete(frame.source);
|
|
569
|
+
stack.pop();
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
const key = frame.keys[frame.index];
|
|
573
|
+
frame.index += 1;
|
|
574
|
+
const childPath = childPropertyPath(frame.path, key);
|
|
575
|
+
const child = createFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient);
|
|
576
|
+
frame.target[key] = child.value;
|
|
577
|
+
if (child.frame !== void 0) {
|
|
578
|
+
stack.push(child.frame);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return root.value;
|
|
582
|
+
};
|
|
583
|
+
|
|
70
584
|
// src/export/payload.ts
|
|
71
585
|
var createRecord = () => /* @__PURE__ */ Object.create(null);
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
return value.map((entry) => cloneJsonValue(entry));
|
|
75
|
-
}
|
|
76
|
-
if (value !== null && typeof value === "object") {
|
|
77
|
-
const cloned = createRecord();
|
|
78
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
79
|
-
cloned[key] = cloneJsonValue(entryValue);
|
|
80
|
-
}
|
|
81
|
-
return cloned;
|
|
82
|
-
}
|
|
83
|
-
return value;
|
|
84
|
-
};
|
|
85
|
-
var cloneSchemaField = (field, name = field.name) => {
|
|
586
|
+
var appendPath = (path, key) => `${path}[${JSON.stringify(key)}]`;
|
|
587
|
+
var cloneSchemaField = (field, name = field.name, path = "$.schema.fields[]") => {
|
|
86
588
|
const cloned = createRecord();
|
|
87
589
|
for (const [key, value] of Object.entries(field)) {
|
|
88
|
-
cloned[key] = key === "name" ? name : value === void 0 ? void 0 :
|
|
590
|
+
cloned[key] = key === "name" ? name : value === void 0 ? void 0 : cloneJsonCompatible(value, "table", appendPath(path, key));
|
|
89
591
|
}
|
|
90
592
|
return cloned;
|
|
91
593
|
};
|
|
@@ -96,10 +598,12 @@ var cloneSchema = (schema, fields, primaryKey) => {
|
|
|
96
598
|
if (key === "fields" || key === "primaryKey") {
|
|
97
599
|
continue;
|
|
98
600
|
}
|
|
99
|
-
cloned[key] = value === void 0 ? void 0 :
|
|
601
|
+
cloned[key] = value === void 0 ? void 0 : cloneJsonCompatible(value, "table", appendPath("$.schema", key));
|
|
100
602
|
}
|
|
101
603
|
}
|
|
102
|
-
cloned.fields = fields.map(
|
|
604
|
+
cloned.fields = fields.map(
|
|
605
|
+
(field, index) => cloneSchemaField(field, field.name, `$.schema.fields[${index}]`)
|
|
606
|
+
);
|
|
103
607
|
if (primaryKey !== void 0) {
|
|
104
608
|
cloned.primaryKey = [...primaryKey];
|
|
105
609
|
}
|
|
@@ -113,8 +617,9 @@ var mapColumnTypeToSchemaField = (name, info) => {
|
|
|
113
617
|
case "float":
|
|
114
618
|
return "number";
|
|
115
619
|
case "string":
|
|
116
|
-
case "categorical":
|
|
117
620
|
return "string";
|
|
621
|
+
case "categorical":
|
|
622
|
+
return "any";
|
|
118
623
|
case "boolean":
|
|
119
624
|
return "boolean";
|
|
120
625
|
case "datetime":
|
|
@@ -200,6 +705,22 @@ var resolveIndexFieldName = (state, options) => {
|
|
|
200
705
|
}
|
|
201
706
|
return indexField;
|
|
202
707
|
};
|
|
708
|
+
var assertUniqueTableIndexLabels = (index, indexField) => {
|
|
709
|
+
const seen = /* @__PURE__ */ new Map();
|
|
710
|
+
for (let rowIndex = 0; rowIndex < index.length; rowIndex += 1) {
|
|
711
|
+
const label = index[rowIndex];
|
|
712
|
+
if (seen.has(label)) {
|
|
713
|
+
throw new JsonFrameValidationError("Cannot export duplicate index labels as a table primary key.", {
|
|
714
|
+
orient: "table",
|
|
715
|
+
path: `$.data[${rowIndex}][${JSON.stringify(indexField)}]`,
|
|
716
|
+
row: rowIndex,
|
|
717
|
+
column: indexField,
|
|
718
|
+
value: label
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
seen.set(label, rowIndex);
|
|
722
|
+
}
|
|
723
|
+
};
|
|
203
724
|
var resolveIndexKeys = (state, orient) => {
|
|
204
725
|
const seenKeys = /* @__PURE__ */ new Map();
|
|
205
726
|
const keys = [];
|
|
@@ -269,19 +790,32 @@ var exportSplit = (state, materialized) => ({
|
|
|
269
790
|
});
|
|
270
791
|
var exportTable = (state, materialized, columnInfo, options) => {
|
|
271
792
|
const indexField = resolveIndexFieldName(state, options);
|
|
793
|
+
if (indexField !== void 0) {
|
|
794
|
+
assertUniqueTableIndexLabels(state.index, indexField);
|
|
795
|
+
}
|
|
272
796
|
const indexTemplate = getIndexFieldTemplate(state);
|
|
273
797
|
const dataTemplates = getDataFieldTemplates(state);
|
|
274
798
|
const fields = [];
|
|
275
799
|
if (indexField !== void 0) {
|
|
276
800
|
fields.push(
|
|
277
|
-
indexTemplate === void 0 ? { name: indexField, type: inferIndexFieldType(state.index) } : cloneSchemaField(indexTemplate, indexField)
|
|
801
|
+
indexTemplate === void 0 ? { name: indexField, type: inferIndexFieldType(state.index) } : cloneSchemaField(indexTemplate, indexField, "$.schema.fields[0]")
|
|
278
802
|
);
|
|
279
803
|
}
|
|
280
804
|
for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
|
|
281
805
|
const column = state.columns[columnIndex];
|
|
282
806
|
const template = dataTemplates[columnIndex];
|
|
807
|
+
if (template === void 0) {
|
|
808
|
+
validateColumnValuesForType({
|
|
809
|
+
column,
|
|
810
|
+
columnIndex,
|
|
811
|
+
values: materialized.get(column) ?? [],
|
|
812
|
+
type: columnInfo.get(column).type,
|
|
813
|
+
orient: "table",
|
|
814
|
+
index: state.index
|
|
815
|
+
});
|
|
816
|
+
}
|
|
283
817
|
fields.push(
|
|
284
|
-
template === void 0 ? mapColumnTypeToSchemaField(column, columnInfo.get(column)) : cloneSchemaField(template, column)
|
|
818
|
+
template === void 0 ? mapColumnTypeToSchemaField(column, columnInfo.get(column)) : cloneSchemaField(template, column, `$.schema.fields[${fields.length}]`)
|
|
285
819
|
);
|
|
286
820
|
}
|
|
287
821
|
const data = [];
|
|
@@ -301,185 +835,6 @@ var exportTable = (state, materialized, columnInfo, options) => {
|
|
|
301
835
|
};
|
|
302
836
|
};
|
|
303
837
|
|
|
304
|
-
// src/frame/column.ts
|
|
305
|
-
var INT32_MIN = -2147483648;
|
|
306
|
-
var INT32_MAX = 2147483647;
|
|
307
|
-
var freezeArray = (values) => Object.freeze([...values]);
|
|
308
|
-
var freezeColumnInfo = (info) => Object.freeze({ ...info });
|
|
309
|
-
var hasCategoricalMetadata = (field) => field.constraints?.enum !== void 0 || field.ordered === true || field.extDtype === "category";
|
|
310
|
-
var mapTableSchemaFieldType = (field) => {
|
|
311
|
-
if (hasCategoricalMetadata(field)) {
|
|
312
|
-
return "categorical";
|
|
313
|
-
}
|
|
314
|
-
switch (field.type) {
|
|
315
|
-
case "boolean":
|
|
316
|
-
return "boolean";
|
|
317
|
-
case "integer":
|
|
318
|
-
case "year":
|
|
319
|
-
return "integer";
|
|
320
|
-
case "number":
|
|
321
|
-
return "float";
|
|
322
|
-
case "date":
|
|
323
|
-
case "datetime":
|
|
324
|
-
return "datetime";
|
|
325
|
-
case "string":
|
|
326
|
-
return "string";
|
|
327
|
-
case "any":
|
|
328
|
-
return "unknown";
|
|
329
|
-
default:
|
|
330
|
-
return "unknown";
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
var inferColumnType = (values) => {
|
|
334
|
-
let nullable = false;
|
|
335
|
-
let sawBoolean = false;
|
|
336
|
-
let sawString = false;
|
|
337
|
-
let sawInteger = false;
|
|
338
|
-
let sawFloat = false;
|
|
339
|
-
let sawStructured = false;
|
|
340
|
-
for (const value of values) {
|
|
341
|
-
if (value === null) {
|
|
342
|
-
nullable = true;
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
if (typeof value === "boolean") {
|
|
346
|
-
sawBoolean = true;
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
if (typeof value === "string") {
|
|
350
|
-
sawString = true;
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
if (typeof value === "number") {
|
|
354
|
-
if (Number.isInteger(value)) {
|
|
355
|
-
sawInteger = true;
|
|
356
|
-
} else {
|
|
357
|
-
sawFloat = true;
|
|
358
|
-
}
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
sawStructured = true;
|
|
362
|
-
}
|
|
363
|
-
const nonNullKinds = [sawBoolean, sawString, sawInteger || sawFloat, sawStructured].filter(Boolean).length;
|
|
364
|
-
if (nonNullKinds === 0) {
|
|
365
|
-
return freezeColumnInfo({ type: "unknown", nullable });
|
|
366
|
-
}
|
|
367
|
-
if (sawStructured || nonNullKinds > 1 || sawBoolean && (sawString || sawInteger || sawFloat)) {
|
|
368
|
-
return freezeColumnInfo({ type: "mixed", nullable });
|
|
369
|
-
}
|
|
370
|
-
if (sawString) {
|
|
371
|
-
return freezeColumnInfo({ type: "string", nullable });
|
|
372
|
-
}
|
|
373
|
-
if (sawBoolean) {
|
|
374
|
-
return freezeColumnInfo({ type: "boolean", nullable });
|
|
375
|
-
}
|
|
376
|
-
if (sawFloat) {
|
|
377
|
-
return freezeColumnInfo({ type: "float", nullable });
|
|
378
|
-
}
|
|
379
|
-
return freezeColumnInfo({ type: "integer", nullable });
|
|
380
|
-
};
|
|
381
|
-
var packColumn = (values, info, packThreshold) => {
|
|
382
|
-
if (packThreshold === 0 || values.length < packThreshold || info.nullable) {
|
|
383
|
-
return freezeArray(values);
|
|
384
|
-
}
|
|
385
|
-
if (info.type === "integer") {
|
|
386
|
-
const packed = new Int32Array(values.length);
|
|
387
|
-
for (let index = 0; index < values.length; index += 1) {
|
|
388
|
-
const value = values[index];
|
|
389
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < INT32_MIN || value > INT32_MAX) {
|
|
390
|
-
return freezeArray(values);
|
|
391
|
-
}
|
|
392
|
-
packed[index] = value;
|
|
393
|
-
}
|
|
394
|
-
return packed;
|
|
395
|
-
}
|
|
396
|
-
if (info.type === "float") {
|
|
397
|
-
const packed = new Float64Array(values.length);
|
|
398
|
-
for (let index = 0; index < values.length; index += 1) {
|
|
399
|
-
const value = values[index];
|
|
400
|
-
if (typeof value !== "number") {
|
|
401
|
-
return freezeArray(values);
|
|
402
|
-
}
|
|
403
|
-
packed[index] = value;
|
|
404
|
-
}
|
|
405
|
-
return packed;
|
|
406
|
-
}
|
|
407
|
-
return freezeArray(values);
|
|
408
|
-
};
|
|
409
|
-
var validateExplicitColumnTypes = (columns, columnTypes) => {
|
|
410
|
-
if (columnTypes === void 0) {
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
const knownColumns = new Set(columns);
|
|
414
|
-
for (const column of Object.keys(columnTypes)) {
|
|
415
|
-
if (!knownColumns.has(column)) {
|
|
416
|
-
throw new JsonFrameOptionError(
|
|
417
|
-
"`options.columnTypes` keys must match parsed column names.",
|
|
418
|
-
`columnTypes.${column}`,
|
|
419
|
-
columnTypes[column]
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
var resolveSchemaTypeByColumn = (frame) => {
|
|
425
|
-
if (frame.tableSchema === void 0) {
|
|
426
|
-
return /* @__PURE__ */ new Map();
|
|
427
|
-
}
|
|
428
|
-
const schemaTypes = /* @__PURE__ */ new Map();
|
|
429
|
-
for (const field of frame.tableSchema.fields) {
|
|
430
|
-
if (frame.columns.includes(field.name)) {
|
|
431
|
-
schemaTypes.set(field.name, mapTableSchemaFieldType(field));
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
return schemaTypes;
|
|
435
|
-
};
|
|
436
|
-
var materializeColumn = (column) => Array.isArray(column) ? freezeArray(column) : freezeArray(Array.from(column));
|
|
437
|
-
var materializeFrameData = (columns, data) => {
|
|
438
|
-
const materialized = /* @__PURE__ */ new Map();
|
|
439
|
-
for (const column of columns) {
|
|
440
|
-
const stored = data.get(column);
|
|
441
|
-
if (stored === void 0) {
|
|
442
|
-
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
443
|
-
path: "$",
|
|
444
|
-
column
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
materialized.set(column, materializeColumn(stored));
|
|
448
|
-
}
|
|
449
|
-
return materialized;
|
|
450
|
-
};
|
|
451
|
-
var buildFrameState = (frame, options) => {
|
|
452
|
-
validateExplicitColumnTypes(frame.columns, options.columnTypes);
|
|
453
|
-
const schemaTypes = resolveSchemaTypeByColumn(frame);
|
|
454
|
-
const data = /* @__PURE__ */ new Map();
|
|
455
|
-
const columnInfo = /* @__PURE__ */ new Map();
|
|
456
|
-
for (const column of frame.columns) {
|
|
457
|
-
const values = frame.data.get(column);
|
|
458
|
-
if (values === void 0) {
|
|
459
|
-
throw new JsonFrameValidationError("Parsed frame data is missing a declared column.", {
|
|
460
|
-
orient: frame.orient,
|
|
461
|
-
column
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
const inferred = inferColumnType(values);
|
|
465
|
-
const resolvedType = schemaTypes.get(column) ?? options.columnTypes?.[column] ?? inferred.type;
|
|
466
|
-
const info = freezeColumnInfo({ type: resolvedType, nullable: inferred.nullable });
|
|
467
|
-
columnInfo.set(column, info);
|
|
468
|
-
data.set(column, packColumn(values, info, options.packThreshold));
|
|
469
|
-
}
|
|
470
|
-
return {
|
|
471
|
-
columns: freezeArray(frame.columns),
|
|
472
|
-
index: freezeArray(frame.index),
|
|
473
|
-
indexKind: frame.indexKind,
|
|
474
|
-
data,
|
|
475
|
-
columnInfo,
|
|
476
|
-
...frame.tableSchema === void 0 ? {} : { tableSchema: frame.tableSchema },
|
|
477
|
-
...frame.tableIndexField === void 0 ? {} : { tableIndexField: frame.tableIndexField }
|
|
478
|
-
};
|
|
479
|
-
};
|
|
480
|
-
var createFrameStateFromData = (frame, options) => buildFrameState(frame, options);
|
|
481
|
-
var createFrameState = (frame, options) => buildFrameState(frame, options);
|
|
482
|
-
|
|
483
838
|
// src/frame/DataFrame.ts
|
|
484
839
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
485
840
|
var frameStateByInstance = /* @__PURE__ */ new WeakMap();
|
|
@@ -499,7 +854,7 @@ var cloneSchema2 = (schema, fields, primaryKey) => {
|
|
|
499
854
|
}
|
|
500
855
|
return Object.freeze(cloned);
|
|
501
856
|
};
|
|
502
|
-
var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, materializedData_fn, createRow_fn,
|
|
857
|
+
var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, materializedData_fn, createRow_fn, columnInfoOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
|
|
503
858
|
var DataFrame = class {
|
|
504
859
|
constructor(state, packThreshold) {
|
|
505
860
|
__privateAdd(this, _DataFrame_instances);
|
|
@@ -561,18 +916,22 @@ var DataFrame = class {
|
|
|
561
916
|
}
|
|
562
917
|
row(position) {
|
|
563
918
|
__privateMethod(this, _DataFrame_instances, assertRowPosition_fn).call(this, position);
|
|
564
|
-
return __privateMethod(this, _DataFrame_instances, createRow_fn).call(this,
|
|
919
|
+
return __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, position);
|
|
565
920
|
}
|
|
566
921
|
rows() {
|
|
567
|
-
const
|
|
568
|
-
const rows = __privateGet(this, _state).index.map((_, position) => __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, materialized, position));
|
|
922
|
+
const rows = __privateGet(this, _state).index.map((_, position) => __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, position));
|
|
569
923
|
return freezeArray2(rows);
|
|
570
924
|
}
|
|
571
925
|
filter(predicate) {
|
|
572
|
-
|
|
926
|
+
if (typeof predicate !== "function") {
|
|
927
|
+
throw new JsonFrameValidationError("`filter` predicate must be a function.", {
|
|
928
|
+
path: "$.predicate",
|
|
929
|
+
value: predicate
|
|
930
|
+
});
|
|
931
|
+
}
|
|
573
932
|
const keptPositions = [];
|
|
574
933
|
for (let position = 0; position < this.length; position += 1) {
|
|
575
|
-
if (predicate(__privateMethod(this, _DataFrame_instances, createRow_fn).call(this,
|
|
934
|
+
if (predicate(__privateMethod(this, _DataFrame_instances, createRow_fn).call(this, position), __privateGet(this, _state).index[position], position)) {
|
|
576
935
|
keptPositions.push(position);
|
|
577
936
|
}
|
|
578
937
|
}
|
|
@@ -589,11 +948,16 @@ var DataFrame = class {
|
|
|
589
948
|
});
|
|
590
949
|
}
|
|
591
950
|
sort(compare) {
|
|
592
|
-
|
|
951
|
+
if (typeof compare !== "function") {
|
|
952
|
+
throw new JsonFrameValidationError("`sort` compare must be a function.", {
|
|
953
|
+
path: "$.compare",
|
|
954
|
+
value: compare
|
|
955
|
+
});
|
|
956
|
+
}
|
|
593
957
|
const ordering = __privateGet(this, _state).index.map((indexLabel, position) => ({
|
|
594
958
|
indexLabel,
|
|
595
959
|
position,
|
|
596
|
-
row: __privateMethod(this, _DataFrame_instances, createRow_fn).call(this,
|
|
960
|
+
row: __privateMethod(this, _DataFrame_instances, createRow_fn).call(this, position)
|
|
597
961
|
}));
|
|
598
962
|
ordering.sort((left, right) => {
|
|
599
963
|
const result = compare(left.row, right.row, left.indexLabel, right.indexLabel, left.position, right.position);
|
|
@@ -641,7 +1005,26 @@ var DataFrame = class {
|
|
|
641
1005
|
});
|
|
642
1006
|
}
|
|
643
1007
|
rename(mapping) {
|
|
644
|
-
|
|
1008
|
+
if (mapping === null || typeof mapping !== "object" || Array.isArray(mapping)) {
|
|
1009
|
+
throw new JsonFrameValidationError("`rename` mapping must be a non-array object.", {
|
|
1010
|
+
path: "$.mapping",
|
|
1011
|
+
value: mapping
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
const nextColumns = __privateGet(this, _state).columns.map((column) => {
|
|
1015
|
+
if (!hasOwn.call(mapping, column)) {
|
|
1016
|
+
return column;
|
|
1017
|
+
}
|
|
1018
|
+
const renamedColumn = mapping[column];
|
|
1019
|
+
if (typeof renamedColumn !== "string") {
|
|
1020
|
+
throw new JsonFrameValidationError("`rename` mapping values must be strings for existing columns.", {
|
|
1021
|
+
path: `$.mapping[${JSON.stringify(column)}]`,
|
|
1022
|
+
column,
|
|
1023
|
+
value: renamedColumn
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
return renamedColumn;
|
|
1027
|
+
});
|
|
645
1028
|
const seen = /* @__PURE__ */ new Set();
|
|
646
1029
|
for (let position = 0; position < nextColumns.length; position += 1) {
|
|
647
1030
|
const column = nextColumns[position];
|
|
@@ -687,19 +1070,35 @@ assertRowPosition_fn = function(position) {
|
|
|
687
1070
|
materializedData_fn = function() {
|
|
688
1071
|
return materializeFrameData(__privateGet(this, _state).columns, __privateGet(this, _state).data);
|
|
689
1072
|
};
|
|
690
|
-
createRow_fn = function(
|
|
1073
|
+
createRow_fn = function(position) {
|
|
691
1074
|
const row = /* @__PURE__ */ Object.create(null);
|
|
692
1075
|
for (const column of __privateGet(this, _state).columns) {
|
|
693
|
-
|
|
1076
|
+
const stored = __privateGet(this, _state).data.get(column);
|
|
1077
|
+
if (stored === void 0) {
|
|
1078
|
+
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
1079
|
+
path: "$",
|
|
1080
|
+
column
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
row[column] = getStoredColumnValue(stored, position);
|
|
694
1084
|
}
|
|
695
1085
|
return Object.freeze(row);
|
|
696
1086
|
};
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1087
|
+
columnInfoOverrides_fn = function(columns, sourceColumns) {
|
|
1088
|
+
const columnInfo = /* @__PURE__ */ new Map();
|
|
1089
|
+
for (let position = 0; position < columns.length; position += 1) {
|
|
1090
|
+
const column = columns[position];
|
|
1091
|
+
const sourceColumn = sourceColumns[position];
|
|
1092
|
+
const sourceInfo = __privateGet(this, _state).columnInfo.get(sourceColumn);
|
|
1093
|
+
if (sourceInfo === void 0) {
|
|
1094
|
+
throw new JsonFrameValidationError("Stored frame metadata is missing a declared column.", {
|
|
1095
|
+
path: "$",
|
|
1096
|
+
column: sourceColumn
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
columnInfo.set(column, sourceInfo);
|
|
1100
|
+
}
|
|
1101
|
+
return columnInfo;
|
|
703
1102
|
};
|
|
704
1103
|
rebuild_fn = function({
|
|
705
1104
|
columns,
|
|
@@ -709,31 +1108,31 @@ rebuild_fn = function({
|
|
|
709
1108
|
indexKind,
|
|
710
1109
|
schema
|
|
711
1110
|
}) {
|
|
712
|
-
const materialized = __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this);
|
|
713
1111
|
const nextData = /* @__PURE__ */ new Map();
|
|
1112
|
+
const nextColumnInfo = __privateMethod(this, _DataFrame_instances, columnInfoOverrides_fn).call(this, columns, sourceColumns);
|
|
714
1113
|
for (let columnIndex = 0; columnIndex < columns.length; columnIndex += 1) {
|
|
715
1114
|
const column = columns[columnIndex];
|
|
716
|
-
const
|
|
717
|
-
if (
|
|
1115
|
+
const sourceStoredColumn = __privateGet(this, _state).data.get(sourceColumns[columnIndex]);
|
|
1116
|
+
if (sourceStoredColumn === void 0) {
|
|
718
1117
|
throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
|
|
719
1118
|
path: "$",
|
|
720
1119
|
column
|
|
721
1120
|
});
|
|
722
1121
|
}
|
|
723
|
-
nextData.set(column,
|
|
1122
|
+
nextData.set(column, rebuildStoredColumn(sourceStoredColumn, positions));
|
|
724
1123
|
}
|
|
725
|
-
const state =
|
|
1124
|
+
const state = createFrameStateFromRebuiltData(
|
|
726
1125
|
{
|
|
727
1126
|
columns,
|
|
728
1127
|
index,
|
|
729
1128
|
indexKind,
|
|
730
1129
|
data: nextData,
|
|
1130
|
+
columnInfo: nextColumnInfo,
|
|
731
1131
|
...schema.tableSchema === void 0 ? {} : { tableSchema: schema.tableSchema },
|
|
732
1132
|
...schema.tableIndexField === void 0 ? {} : { tableIndexField: schema.tableIndexField }
|
|
733
1133
|
},
|
|
734
1134
|
{
|
|
735
|
-
packThreshold: __privateGet(this, _packThreshold)
|
|
736
|
-
columnTypes: __privateMethod(this, _DataFrame_instances, columnTypeOverrides_fn).call(this, columns, sourceColumns)
|
|
1135
|
+
packThreshold: __privateGet(this, _packThreshold)
|
|
737
1136
|
}
|
|
738
1137
|
);
|
|
739
1138
|
return createDataFrame(state, __privateGet(this, _packThreshold));
|
|
@@ -901,11 +1300,11 @@ var normalizeFromOrientOptions = (options) => {
|
|
|
901
1300
|
|
|
902
1301
|
// src/parse/parse.ts
|
|
903
1302
|
var hasOwn2 = Object.prototype.hasOwnProperty;
|
|
904
|
-
var
|
|
1303
|
+
var IDENTIFIER_PATTERN2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
905
1304
|
var freezeArray3 = (values) => Object.freeze([...values]);
|
|
906
|
-
var appendPropertyPath = (path, key) =>
|
|
1305
|
+
var appendPropertyPath = (path, key) => IDENTIFIER_PATTERN2.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
|
|
907
1306
|
var appendIndexPath = (path, index) => `${path}[${index}]`;
|
|
908
|
-
var
|
|
1307
|
+
var isPlainObject2 = (value) => {
|
|
909
1308
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
910
1309
|
return false;
|
|
911
1310
|
}
|
|
@@ -925,6 +1324,18 @@ var assertSupportedIndexLabel = (value, orient, path) => {
|
|
|
925
1324
|
value
|
|
926
1325
|
});
|
|
927
1326
|
};
|
|
1327
|
+
var assertUniqueTablePrimaryKeyLabel = (seen, label, row, column, path) => {
|
|
1328
|
+
if (seen.has(label)) {
|
|
1329
|
+
throw new JsonFrameValidationError("Table primary-key values must be unique.", {
|
|
1330
|
+
orient: "table",
|
|
1331
|
+
path,
|
|
1332
|
+
row,
|
|
1333
|
+
column,
|
|
1334
|
+
value: label
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
seen.set(label, row);
|
|
1338
|
+
};
|
|
928
1339
|
var assertUniqueStringColumns = (values, orient, path) => {
|
|
929
1340
|
const columns = [];
|
|
930
1341
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -982,52 +1393,6 @@ var finalizeFrame = ({
|
|
|
982
1393
|
...tableIndexField === void 0 ? {} : { tableIndexField }
|
|
983
1394
|
};
|
|
984
1395
|
};
|
|
985
|
-
var validateJsonCompatible = (value, path = "$", stack = /* @__PURE__ */ new Set()) => {
|
|
986
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
987
|
-
return value;
|
|
988
|
-
}
|
|
989
|
-
if (typeof value === "number") {
|
|
990
|
-
if (!Number.isFinite(value)) {
|
|
991
|
-
throw new JsonFrameValidationError("Numbers must be finite JSON values.", { path, value });
|
|
992
|
-
}
|
|
993
|
-
return value;
|
|
994
|
-
}
|
|
995
|
-
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") {
|
|
996
|
-
throw new JsonFrameValidationError("Input must contain only JSON-compatible values.", { path, value });
|
|
997
|
-
}
|
|
998
|
-
if (Array.isArray(value)) {
|
|
999
|
-
if (stack.has(value)) {
|
|
1000
|
-
throw new JsonFrameValidationError("Input contains a cyclic array.", { path, value });
|
|
1001
|
-
}
|
|
1002
|
-
stack.add(value);
|
|
1003
|
-
const normalized2 = [];
|
|
1004
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
1005
|
-
if (!(index in value)) {
|
|
1006
|
-
stack.delete(value);
|
|
1007
|
-
throw new JsonFrameValidationError("Sparse arrays are not valid JSON input.", {
|
|
1008
|
-
path: appendIndexPath(path, index),
|
|
1009
|
-
value
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
normalized2.push(validateJsonCompatible(value[index], appendIndexPath(path, index), stack));
|
|
1013
|
-
}
|
|
1014
|
-
stack.delete(value);
|
|
1015
|
-
return normalized2;
|
|
1016
|
-
}
|
|
1017
|
-
if (!isPlainObject(value)) {
|
|
1018
|
-
throw new JsonFrameValidationError("Input objects must be plain JSON objects or arrays.", { path, value });
|
|
1019
|
-
}
|
|
1020
|
-
if (stack.has(value)) {
|
|
1021
|
-
throw new JsonFrameValidationError("Input contains a cyclic object.", { path, value });
|
|
1022
|
-
}
|
|
1023
|
-
stack.add(value);
|
|
1024
|
-
const normalized = /* @__PURE__ */ Object.create(null);
|
|
1025
|
-
for (const [key, entryValue] of Object.entries(value)) {
|
|
1026
|
-
normalized[key] = validateJsonCompatible(entryValue, appendPropertyPath(path, key), stack);
|
|
1027
|
-
}
|
|
1028
|
-
stack.delete(value);
|
|
1029
|
-
return normalized;
|
|
1030
|
-
};
|
|
1031
1396
|
var detectOrient = (value) => {
|
|
1032
1397
|
if (Array.isArray(value)) {
|
|
1033
1398
|
if (value.length === 0) {
|
|
@@ -1039,7 +1404,7 @@ var detectOrient = (value) => {
|
|
|
1039
1404
|
if (value.every((entry) => Array.isArray(entry))) {
|
|
1040
1405
|
return "values";
|
|
1041
1406
|
}
|
|
1042
|
-
if (value.every((entry) =>
|
|
1407
|
+
if (value.every((entry) => isPlainObject2(entry))) {
|
|
1043
1408
|
return "records";
|
|
1044
1409
|
}
|
|
1045
1410
|
throw new JsonFrameValidationError("Auto detection requires a non-empty array of row objects or row arrays.", {
|
|
@@ -1047,20 +1412,20 @@ var detectOrient = (value) => {
|
|
|
1047
1412
|
value
|
|
1048
1413
|
});
|
|
1049
1414
|
}
|
|
1050
|
-
if (!
|
|
1415
|
+
if (!isPlainObject2(value)) {
|
|
1051
1416
|
throw new JsonFrameValidationError("Auto detection requires a JSON array or object payload.", {
|
|
1052
1417
|
path: "$",
|
|
1053
1418
|
value
|
|
1054
1419
|
});
|
|
1055
1420
|
}
|
|
1056
|
-
if (
|
|
1421
|
+
if (isPlainObject2(value.schema) && Array.isArray(value.data)) {
|
|
1057
1422
|
return "table";
|
|
1058
1423
|
}
|
|
1059
1424
|
if (Array.isArray(value.columns) && Array.isArray(value.data) && (value.index === void 0 || Array.isArray(value.index))) {
|
|
1060
1425
|
return "split";
|
|
1061
1426
|
}
|
|
1062
1427
|
const keys = Object.keys(value);
|
|
1063
|
-
if (keys.length === 0 || keys.every((key) =>
|
|
1428
|
+
if (keys.length === 0 || keys.every((key) => isPlainObject2(value[key]))) {
|
|
1064
1429
|
throw new AmbiguousOrientError("Auto detection cannot distinguish between index and columns payloads.", [
|
|
1065
1430
|
"index",
|
|
1066
1431
|
"columns"
|
|
@@ -1082,7 +1447,7 @@ var parseRecords = (value, orient) => {
|
|
|
1082
1447
|
for (let rowIndex = 0; rowIndex < value.length; rowIndex += 1) {
|
|
1083
1448
|
const row = value[rowIndex];
|
|
1084
1449
|
const rowPath = appendIndexPath("$", rowIndex);
|
|
1085
|
-
if (!
|
|
1450
|
+
if (!isPlainObject2(row)) {
|
|
1086
1451
|
throw new JsonFrameValidationError("`records` rows must be JSON objects.", {
|
|
1087
1452
|
orient,
|
|
1088
1453
|
path: rowPath,
|
|
@@ -1111,7 +1476,7 @@ var parseRecords = (value, orient) => {
|
|
|
1111
1476
|
});
|
|
1112
1477
|
};
|
|
1113
1478
|
var parseIndex = (value, orient) => {
|
|
1114
|
-
if (!
|
|
1479
|
+
if (!isPlainObject2(value)) {
|
|
1115
1480
|
throw new JsonFrameValidationError("`index` payloads must be objects keyed by index label.", {
|
|
1116
1481
|
orient,
|
|
1117
1482
|
path: "$",
|
|
@@ -1126,7 +1491,7 @@ var parseIndex = (value, orient) => {
|
|
|
1126
1491
|
const indexLabel = index[rowIndex];
|
|
1127
1492
|
const row = value[indexLabel];
|
|
1128
1493
|
const rowPath = appendPropertyPath("$", indexLabel);
|
|
1129
|
-
if (!
|
|
1494
|
+
if (!isPlainObject2(row)) {
|
|
1130
1495
|
throw new JsonFrameValidationError("`index` payload rows must be JSON objects.", {
|
|
1131
1496
|
orient,
|
|
1132
1497
|
path: rowPath,
|
|
@@ -1154,7 +1519,7 @@ var parseIndex = (value, orient) => {
|
|
|
1154
1519
|
});
|
|
1155
1520
|
};
|
|
1156
1521
|
var parseColumns = (value, orient) => {
|
|
1157
|
-
if (!
|
|
1522
|
+
if (!isPlainObject2(value)) {
|
|
1158
1523
|
throw new JsonFrameValidationError("`columns` payloads must be objects keyed by column label.", {
|
|
1159
1524
|
orient,
|
|
1160
1525
|
path: "$",
|
|
@@ -1176,7 +1541,7 @@ var parseColumns = (value, orient) => {
|
|
|
1176
1541
|
for (const column of columns) {
|
|
1177
1542
|
const columnValue = value[column];
|
|
1178
1543
|
const columnPath = appendPropertyPath("$", column);
|
|
1179
|
-
if (!
|
|
1544
|
+
if (!isPlainObject2(columnValue)) {
|
|
1180
1545
|
throw new JsonFrameValidationError("`columns` payload values must be objects keyed by index label.", {
|
|
1181
1546
|
orient,
|
|
1182
1547
|
path: columnPath,
|
|
@@ -1255,7 +1620,7 @@ var parseValues = (value, options, orient) => {
|
|
|
1255
1620
|
});
|
|
1256
1621
|
};
|
|
1257
1622
|
var parseSplit = (value, orient) => {
|
|
1258
|
-
if (!
|
|
1623
|
+
if (!isPlainObject2(value)) {
|
|
1259
1624
|
throw new JsonFrameValidationError("`split` payloads must be objects.", { orient, path: "$", value });
|
|
1260
1625
|
}
|
|
1261
1626
|
if (!Array.isArray(value.columns)) {
|
|
@@ -1330,7 +1695,7 @@ var parseSplit = (value, orient) => {
|
|
|
1330
1695
|
});
|
|
1331
1696
|
};
|
|
1332
1697
|
var cloneConstraints = (value, orient, path) => {
|
|
1333
|
-
if (!
|
|
1698
|
+
if (!isPlainObject2(value)) {
|
|
1334
1699
|
throw new JsonFrameValidationError("Table Schema field constraints must be an object when present.", {
|
|
1335
1700
|
orient,
|
|
1336
1701
|
path,
|
|
@@ -1372,7 +1737,7 @@ var cloneConstraints = (value, orient, path) => {
|
|
|
1372
1737
|
var cloneTableField = (value, index) => {
|
|
1373
1738
|
const orient = "table";
|
|
1374
1739
|
const path = appendIndexPath("$.schema.fields", index);
|
|
1375
|
-
if (!
|
|
1740
|
+
if (!isPlainObject2(value)) {
|
|
1376
1741
|
throw new JsonFrameValidationError("Table Schema fields must be objects.", {
|
|
1377
1742
|
orient,
|
|
1378
1743
|
path,
|
|
@@ -1419,7 +1784,7 @@ var cloneTableField = (value, index) => {
|
|
|
1419
1784
|
};
|
|
1420
1785
|
var cloneTableSchema = (value) => {
|
|
1421
1786
|
const orient = "table";
|
|
1422
|
-
if (!
|
|
1787
|
+
if (!isPlainObject2(value)) {
|
|
1423
1788
|
throw new JsonFrameValidationError("`table.schema` must be an object.", {
|
|
1424
1789
|
orient,
|
|
1425
1790
|
path: "$.schema",
|
|
@@ -1495,7 +1860,7 @@ var cloneTableSchema = (value) => {
|
|
|
1495
1860
|
return Object.freeze(cloned);
|
|
1496
1861
|
};
|
|
1497
1862
|
var parseTable = (value, orient) => {
|
|
1498
|
-
if (!
|
|
1863
|
+
if (!isPlainObject2(value)) {
|
|
1499
1864
|
throw new JsonFrameValidationError("`table` payloads must be objects.", { orient, path: "$", value });
|
|
1500
1865
|
}
|
|
1501
1866
|
const schema = cloneTableSchema(value.schema);
|
|
@@ -1520,10 +1885,11 @@ var parseTable = (value, orient) => {
|
|
|
1520
1885
|
const fieldNames = new Set(schema.fields.map((field) => field.name));
|
|
1521
1886
|
const index = [];
|
|
1522
1887
|
const indexKind = primaryKey === void 0 ? "synthetic" : "source";
|
|
1888
|
+
const seenPrimaryKeyLabels = /* @__PURE__ */ new Map();
|
|
1523
1889
|
for (let rowIndex = 0; rowIndex < value.data.length; rowIndex += 1) {
|
|
1524
1890
|
const row = value.data[rowIndex];
|
|
1525
1891
|
const rowPath = appendIndexPath("$.data", rowIndex);
|
|
1526
|
-
if (!
|
|
1892
|
+
if (!isPlainObject2(row)) {
|
|
1527
1893
|
throw new JsonFrameValidationError("`table.data` rows must be objects.", {
|
|
1528
1894
|
orient,
|
|
1529
1895
|
path: rowPath,
|
|
@@ -1553,9 +1919,10 @@ var parseTable = (value, orient) => {
|
|
|
1553
1919
|
value: row
|
|
1554
1920
|
});
|
|
1555
1921
|
} else {
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
);
|
|
1922
|
+
const primaryKeyPath = appendPropertyPath(rowPath, primaryKey);
|
|
1923
|
+
const indexLabel = assertSupportedIndexLabel(row[primaryKey], orient, primaryKeyPath);
|
|
1924
|
+
assertUniqueTablePrimaryKeyLabel(seenPrimaryKeyLabels, indexLabel, rowIndex, primaryKey, primaryKeyPath);
|
|
1925
|
+
index.push(indexLabel);
|
|
1559
1926
|
}
|
|
1560
1927
|
for (const column of columns) {
|
|
1561
1928
|
data.get(column).push(hasOwn2.call(row, column) ? row[column] : null);
|
|
@@ -1585,7 +1952,7 @@ var parseInput = (input, options) => {
|
|
|
1585
1952
|
throw error;
|
|
1586
1953
|
}
|
|
1587
1954
|
})();
|
|
1588
|
-
const jsonValue =
|
|
1955
|
+
const jsonValue = cloneJsonCompatible(parsedValue);
|
|
1589
1956
|
const orient = options.orient === "auto" ? detectOrient(jsonValue) : options.orient;
|
|
1590
1957
|
switch (orient) {
|
|
1591
1958
|
case "records":
|
|
@@ -1616,6 +1983,7 @@ function fromOrient(input, options) {
|
|
|
1616
1983
|
export {
|
|
1617
1984
|
AmbiguousOrientError,
|
|
1618
1985
|
ExportKeyCollisionError,
|
|
1986
|
+
JSON_FRAME_MAX_DEPTH,
|
|
1619
1987
|
JsonFrameError,
|
|
1620
1988
|
JsonFrameOptionError,
|
|
1621
1989
|
JsonFrameParseError,
|