@web-ts-toolkit/json-frame 0.43.0 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. package/README.md +117 -6
  2. package/index.d.mts +130 -12
  3. package/index.d.ts +130 -12
  4. package/index.js +500 -201
  5. package/index.mjs +500 -201
  6. package/package.json +1 -1
package/index.js CHANGED
@@ -41,7 +41,8 @@ __export(index_exports, {
41
41
  module.exports = __toCommonJS(index_exports);
42
42
 
43
43
  // src/errors.ts
44
- var DIAGNOSTIC_KEY_LIMIT = 5;
44
+ var JSON_FRAME_DIAGNOSTIC_KEY_LIMIT = 5;
45
+ var JSON_FRAME_DIAGNOSTIC_KEY_TEXT_BUDGET = 200;
45
46
  var freezeCopy = (values) => Object.freeze([...values]);
46
47
  var summarizeDiagnosticValue = (value) => {
47
48
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
@@ -52,11 +53,27 @@ var summarizeDiagnosticValue = (value) => {
52
53
  }
53
54
  if (typeof value === "object") {
54
55
  const keys = Object.keys(value);
56
+ const head = keys.slice(0, JSON_FRAME_DIAGNOSTIC_KEY_LIMIT);
57
+ const preview = [];
58
+ let remaining = JSON_FRAME_DIAGNOSTIC_KEY_TEXT_BUDGET;
59
+ let textTruncated = false;
60
+ for (const key of head) {
61
+ if (key.length <= remaining) {
62
+ preview.push(key);
63
+ remaining -= key.length;
64
+ } else {
65
+ if (remaining > 0) {
66
+ preview.push(key.slice(0, remaining));
67
+ }
68
+ textTruncated = true;
69
+ break;
70
+ }
71
+ }
55
72
  return Object.freeze({
56
73
  kind: "object",
57
74
  keyCount: keys.length,
58
- keys: freezeCopy(keys.slice(0, DIAGNOSTIC_KEY_LIMIT)),
59
- truncated: keys.length > DIAGNOSTIC_KEY_LIMIT
75
+ keys: freezeCopy(preview),
76
+ truncated: keys.length > JSON_FRAME_DIAGNOSTIC_KEY_LIMIT || textTruncated
60
77
  });
61
78
  }
62
79
  if (typeof value === "undefined") {
@@ -139,6 +156,7 @@ var INT32_MAX = 2147483647;
139
156
  var freezeArray = (values) => Object.freeze([...values]);
140
157
  var freezeColumnInfo = (info) => Object.freeze({ ...info });
141
158
  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}))?)?$/;
159
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
142
160
  var columnOperationCounters = {
143
161
  materializeColumnCalls: 0,
144
162
  materializedCells: 0,
@@ -232,8 +250,9 @@ var isPandasNaiveIsoDatetime = (value) => {
232
250
  if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) {
233
251
  return false;
234
252
  }
235
- const normalized = new Date(Date.UTC(year, month - 1, day, hour, minute, second));
236
- return normalized.getUTCFullYear() === year && normalized.getUTCMonth() === month - 1 && normalized.getUTCDate() === day && normalized.getUTCHours() === hour && normalized.getUTCMinutes() === minute && normalized.getUTCSeconds() === second;
253
+ const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
254
+ const daysInMonth = month === 2 && leapYear ? 29 : DAYS_IN_MONTH[month - 1];
255
+ return day >= 1 && day <= daysInMonth;
237
256
  };
238
257
  var isScalarCategory = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
239
258
  var isJsonContainer = (value) => {
@@ -312,6 +331,28 @@ var validateColumnValuesForType = ({
312
331
  });
313
332
  }
314
333
  };
334
+ var validateStoredColumnValuesForType = ({
335
+ column,
336
+ columnIndex,
337
+ stored,
338
+ type,
339
+ orient,
340
+ index
341
+ }) => {
342
+ for (let rowIndex = 0; rowIndex < stored.length; rowIndex += 1) {
343
+ const value = stored[rowIndex];
344
+ if (isColumnValueCompatible(type, value)) {
345
+ continue;
346
+ }
347
+ throw new JsonFrameValidationError("Column cells are incompatible with the declared logical type.", {
348
+ ...orient === void 0 ? {} : { orient },
349
+ path: getColumnCellPath(orient, column, columnIndex, rowIndex, index?.[rowIndex]),
350
+ row: rowIndex,
351
+ column,
352
+ value
353
+ });
354
+ }
355
+ };
315
356
  var packColumn = (values, info, packThreshold) => {
316
357
  if (packThreshold === 0 || values.length < packThreshold || info.nullable) {
317
358
  return freezeArray(values);
@@ -323,6 +364,9 @@ var packColumn = (values, info, packThreshold) => {
323
364
  if (typeof value !== "number" || !Number.isInteger(value) || value < INT32_MIN || value > INT32_MAX) {
324
365
  return freezeArray(values);
325
366
  }
367
+ if (Object.is(value, -0)) {
368
+ return freezeArray(values);
369
+ }
326
370
  packed[index] = value;
327
371
  }
328
372
  return packed;
@@ -369,18 +413,14 @@ var resolveSchemaTypeByColumn = (frame) => {
369
413
  return /* @__PURE__ */ new Map();
370
414
  }
371
415
  const schemaTypes = /* @__PURE__ */ new Map();
416
+ const columnNames = new Set(frame.columns);
372
417
  for (const field of frame.tableSchema.fields) {
373
- if (frame.columns.includes(field.name)) {
418
+ if (columnNames.has(field.name)) {
374
419
  schemaTypes.set(field.name, mapTableSchemaFieldType(field));
375
420
  }
376
421
  }
377
422
  return schemaTypes;
378
423
  };
379
- var materializeColumn = (column) => {
380
- columnOperationCounters.materializeColumnCalls += 1;
381
- columnOperationCounters.materializedCells += column.length;
382
- return Array.isArray(column) ? freezeArray(column) : freezeArray(Array.from(column));
383
- };
384
424
  var getStoredColumnValue = (column, position) => {
385
425
  columnOperationCounters.scalarReads += 1;
386
426
  return column[position];
@@ -393,20 +433,6 @@ var rebuildStoredColumn = (column, positions) => {
393
433
  columnOperationCounters.rebuiltCells += positions.length;
394
434
  return rebuilt;
395
435
  };
396
- var materializeFrameData = (columns, data) => {
397
- const materialized = /* @__PURE__ */ new Map();
398
- for (const column of columns) {
399
- const stored = data.get(column);
400
- if (stored === void 0) {
401
- throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
402
- path: "$",
403
- column
404
- });
405
- }
406
- materialized.set(column, materializeColumn(stored));
407
- }
408
- return materialized;
409
- };
410
436
  var buildFrameState = (frame, options) => {
411
437
  validateExplicitColumnTypes(frame.columns, options.columnTypes);
412
438
  const schemaTypes = resolveSchemaTypeByColumn(frame);
@@ -422,8 +448,9 @@ var buildFrameState = (frame, options) => {
422
448
  });
423
449
  }
424
450
  const inferred = inferColumnType(values);
425
- const resolvedType = schemaTypes.get(column) ?? options.columnTypes?.[column] ?? inferred.type;
426
- if (schemaTypes.has(column) === false && options.columnTypes?.[column] !== void 0) {
451
+ const explicitType = options.columnTypes !== void 0 && Object.prototype.hasOwnProperty.call(options.columnTypes, column) ? options.columnTypes[column] : void 0;
452
+ const resolvedType = schemaTypes.get(column) ?? explicitType ?? inferred.type;
453
+ if (schemaTypes.has(column) === false && explicitType !== void 0) {
427
454
  validateColumnValuesForType({
428
455
  column,
429
456
  columnIndex,
@@ -522,6 +549,16 @@ var throwValidation = (message, path, value, orient) => {
522
549
  value
523
550
  });
524
551
  };
552
+ var createNodeBudget = (maxNodes, orient) => {
553
+ let remaining = maxNodes;
554
+ return (value, path) => {
555
+ if (remaining === void 0) return;
556
+ if (remaining === 0) {
557
+ throwValidation(`JSON traversal exceeds maxNodes budget of ${maxNodes}.`, path, value, orient);
558
+ }
559
+ remaining -= 1;
560
+ };
561
+ };
525
562
  var cloneScalar = (value, path, orient) => {
526
563
  if (value === null || typeof value === "string" || typeof value === "boolean") {
527
564
  return value;
@@ -537,7 +574,8 @@ var cloneScalar = (value, path, orient) => {
537
574
  }
538
575
  return void 0;
539
576
  };
540
- var createFrame = (source, path, depth, ancestors, orient) => {
577
+ var createFrame = (source, path, depth, ancestors, orient, charge) => {
578
+ charge(source, path);
541
579
  const scalar = cloneScalar(source, path, orient);
542
580
  if (scalar !== void 0) {
543
581
  return { value: scalar };
@@ -572,9 +610,80 @@ var createFrame = (source, path, depth, ancestors, orient) => {
572
610
  frame: { kind: "object", source: objectSource, target, keys: Object.keys(objectSource), path, depth, index: 0 }
573
611
  };
574
612
  };
575
- var cloneJsonCompatible = (value, orient, path = "$") => {
613
+ var createValidateFrame = (source, path, depth, ancestors, orient, charge) => {
614
+ charge(source, path);
615
+ const scalar = cloneScalar(source, path, orient);
616
+ if (scalar !== void 0) {
617
+ return void 0;
618
+ }
619
+ if (depth > JSON_FRAME_MAX_DEPTH) {
620
+ throwValidation(
621
+ `JSON input exceeds the maximum supported nesting depth of ${JSON_FRAME_MAX_DEPTH}.`,
622
+ path,
623
+ source,
624
+ orient
625
+ );
626
+ }
627
+ if (Array.isArray(source)) {
628
+ if (ancestors.has(source)) {
629
+ throwValidation("Input contains a cyclic array.", path, source, orient);
630
+ }
631
+ ancestors.add(source);
632
+ return { kind: "array", source, path, depth, index: 0 };
633
+ }
634
+ if (!isPlainObject(source)) {
635
+ throwValidation("Input objects must be plain JSON objects or arrays.", path, source, orient);
636
+ }
637
+ const objectSource = source;
638
+ if (ancestors.has(objectSource)) {
639
+ throwValidation("Input contains a cyclic object.", path, objectSource, orient);
640
+ }
641
+ ancestors.add(objectSource);
642
+ return { kind: "object", source: objectSource, keys: Object.keys(objectSource), path, depth, index: 0 };
643
+ };
644
+ var assertJsonCompatible = (value, orient, path = "$", maxNodes) => {
576
645
  const ancestors = /* @__PURE__ */ new Set();
577
- const root = createFrame(value, rootPath(path), 0, ancestors, orient);
646
+ const charge = createNodeBudget(maxNodes, orient);
647
+ const root = createValidateFrame(value, rootPath(path), 0, ancestors, orient, charge);
648
+ const stack = root === void 0 ? [] : [root];
649
+ while (stack.length > 0) {
650
+ const frame = stack[stack.length - 1];
651
+ if (frame.kind === "array") {
652
+ if (frame.index >= frame.source.length) {
653
+ ancestors.delete(frame.source);
654
+ stack.pop();
655
+ continue;
656
+ }
657
+ const index = frame.index;
658
+ frame.index += 1;
659
+ const childPath2 = childIndexPath(frame.path, index);
660
+ if (!(index in frame.source)) {
661
+ throwValidation("Sparse arrays are not valid JSON input.", childPath2, frame.source, orient);
662
+ }
663
+ const child2 = createValidateFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient, charge);
664
+ if (child2 !== void 0) {
665
+ stack.push(child2);
666
+ }
667
+ continue;
668
+ }
669
+ if (frame.index >= frame.keys.length) {
670
+ ancestors.delete(frame.source);
671
+ stack.pop();
672
+ continue;
673
+ }
674
+ const key = frame.keys[frame.index];
675
+ frame.index += 1;
676
+ const childPath = childPropertyPath(frame.path, key);
677
+ const child = createValidateFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient, charge);
678
+ if (child !== void 0) {
679
+ stack.push(child);
680
+ }
681
+ }
682
+ };
683
+ var cloneJsonCompatible = (value, orient, path = "$", maxNodes) => {
684
+ const ancestors = /* @__PURE__ */ new Set();
685
+ const charge = createNodeBudget(maxNodes, orient);
686
+ const root = createFrame(value, rootPath(path), 0, ancestors, orient, charge);
578
687
  const stack = root.frame === void 0 ? [] : [root.frame];
579
688
  while (stack.length > 0) {
580
689
  const frame = stack[stack.length - 1];
@@ -590,7 +699,7 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
590
699
  if (!(index in frame.source)) {
591
700
  throwValidation("Sparse arrays are not valid JSON input.", childPath2, frame.source, orient);
592
701
  }
593
- const child2 = createFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient);
702
+ const child2 = createFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient, charge);
594
703
  frame.target.push(child2.value);
595
704
  if (child2.frame !== void 0) {
596
705
  stack.push(child2.frame);
@@ -605,7 +714,7 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
605
714
  const key = frame.keys[frame.index];
606
715
  frame.index += 1;
607
716
  const childPath = childPropertyPath(frame.path, key);
608
- const child = createFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient);
717
+ const child = createFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient, charge);
609
718
  frame.target[key] = child.value;
610
719
  if (child.frame !== void 0) {
611
720
  stack.push(child.frame);
@@ -614,6 +723,142 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
614
723
  return root.value;
615
724
  };
616
725
 
726
+ // src/options.ts
727
+ var RESOLVED_ORIENTS = [
728
+ "records",
729
+ "index",
730
+ "columns",
731
+ "values",
732
+ "split",
733
+ "table"
734
+ ];
735
+ var ORIENTS = ["auto", ...RESOLVED_ORIENTS];
736
+ var COLUMN_TYPES = [
737
+ "integer",
738
+ "float",
739
+ "string",
740
+ "boolean",
741
+ "datetime",
742
+ "categorical",
743
+ "mixed",
744
+ "unknown"
745
+ ];
746
+ var DEFAULT_PACK_THRESHOLD = 256;
747
+ var validateMaxNodes = (maxNodes) => {
748
+ if (maxNodes === void 0) return void 0;
749
+ if (typeof maxNodes !== "number" || !Number.isSafeInteger(maxNodes) || maxNodes <= 0) {
750
+ throw new JsonFrameOptionError("`options.maxNodes` must be a positive safe integer.", "maxNodes", maxNodes);
751
+ }
752
+ return maxNodes;
753
+ };
754
+ var normalizeToTableOptions = (options, method = "toTable") => {
755
+ if (options === void 0) return {};
756
+ if (Array.isArray(options) || typeof options !== "object" || options === null) {
757
+ throw new JsonFrameOptionError(`\`${method}\` options must be an object when provided.`, "options", options);
758
+ }
759
+ const indexField = options.indexField;
760
+ if (indexField !== void 0 && typeof indexField !== "string") {
761
+ throw new JsonFrameOptionError(
762
+ `\`${method}\` options.indexField must be a string when provided.`,
763
+ "indexField",
764
+ indexField
765
+ );
766
+ }
767
+ return indexField === void 0 ? {} : { indexField };
768
+ };
769
+ var normalizeToJSONStringOptions = (options) => {
770
+ const tableOptions = normalizeToTableOptions(options, "toJSONString");
771
+ const maxNodes = validateMaxNodes(options?.maxNodes);
772
+ return { ...tableOptions, ...maxNodes === void 0 ? {} : { maxNodes } };
773
+ };
774
+ var isOrient = (value) => typeof value === "string" && ORIENTS.includes(value);
775
+ var isColumnType = (value) => typeof value === "string" && COLUMN_TYPES.includes(value);
776
+ var normalizeFromOrientOptions = (options) => {
777
+ if (options == null) {
778
+ return {
779
+ orient: "auto",
780
+ packThreshold: DEFAULT_PACK_THRESHOLD
781
+ };
782
+ }
783
+ if (Array.isArray(options) || typeof options !== "object") {
784
+ throw new JsonFrameOptionError("`fromOrient` options must be an object when provided.", "options", options);
785
+ }
786
+ const orient = options.orient ?? "auto";
787
+ if (!isOrient(orient)) {
788
+ throw new JsonFrameOptionError(
789
+ "`options.orient` must be one of auto, records, index, columns, values, split, or table.",
790
+ "orient",
791
+ orient
792
+ );
793
+ }
794
+ const maxNodes = validateMaxNodes(options.maxNodes);
795
+ const packThreshold = options.packThreshold ?? DEFAULT_PACK_THRESHOLD;
796
+ if (!Number.isFinite(packThreshold) || !Number.isInteger(packThreshold) || packThreshold < 0) {
797
+ throw new JsonFrameOptionError(
798
+ "`options.packThreshold` must be a finite non-negative integer.",
799
+ "packThreshold",
800
+ packThreshold
801
+ );
802
+ }
803
+ let columns;
804
+ if (options.columns !== void 0) {
805
+ if (!Array.isArray(options.columns)) {
806
+ throw new JsonFrameOptionError("`options.columns` must be an array of strings.", "columns", options.columns);
807
+ }
808
+ const seen = /* @__PURE__ */ new Set();
809
+ const validated = [];
810
+ const source = options.columns;
811
+ for (let position = 0; position < source.length; position += 1) {
812
+ if (!Object.prototype.hasOwnProperty.call(source, position)) {
813
+ throw new JsonFrameOptionError(
814
+ "`options.columns` must not contain holes; every position must be a string label.",
815
+ "columns",
816
+ source
817
+ );
818
+ }
819
+ const column = source[position];
820
+ if (typeof column !== "string") {
821
+ throw new JsonFrameOptionError("`options.columns` must contain only strings.", "columns", column);
822
+ }
823
+ if (seen.has(column)) {
824
+ throw new JsonFrameOptionError("`options.columns` must not contain duplicates.", "columns", column);
825
+ }
826
+ seen.add(column);
827
+ validated.push(column);
828
+ }
829
+ columns = validated;
830
+ }
831
+ let columnTypes;
832
+ if (options.columnTypes !== void 0) {
833
+ if (Array.isArray(options.columnTypes) || typeof options.columnTypes !== "object" || options.columnTypes === null) {
834
+ throw new JsonFrameOptionError(
835
+ "`options.columnTypes` must be an object keyed by column name.",
836
+ "columnTypes",
837
+ options.columnTypes
838
+ );
839
+ }
840
+ const normalized = /* @__PURE__ */ Object.create(null);
841
+ for (const [column, type] of Object.entries(options.columnTypes)) {
842
+ if (!isColumnType(type)) {
843
+ throw new JsonFrameOptionError(
844
+ "`options.columnTypes` values must be valid JSON Frame logical column types.",
845
+ `columnTypes.${column}`,
846
+ type
847
+ );
848
+ }
849
+ normalized[column] = type;
850
+ }
851
+ columnTypes = Object.freeze(normalized);
852
+ }
853
+ return {
854
+ orient,
855
+ packThreshold,
856
+ ...maxNodes === void 0 ? {} : { maxNodes },
857
+ ...columns === void 0 ? {} : { columns: Object.freeze([...columns]) },
858
+ ...columnTypes === void 0 ? {} : { columnTypes }
859
+ };
860
+ };
861
+
617
862
  // src/export/payload.ts
618
863
  var createRecord = () => /* @__PURE__ */ Object.create(null);
619
864
  var appendPath = (path, key) => `${path}[${JSON.stringify(key)}]`;
@@ -705,30 +950,46 @@ var getIndexFieldTemplate = (state) => {
705
950
  if (state.tableSchema === void 0 || state.tableIndexField === void 0) {
706
951
  return void 0;
707
952
  }
708
- return state.tableSchema.fields.find((field) => field.name === state.tableIndexField);
953
+ const fields = state.tableSchema.fields;
954
+ if (new Set(fields.map((field) => field.name)).size === fields.length) {
955
+ return fields.find((field) => field.name === state.tableIndexField);
956
+ }
957
+ if (fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
958
+ return fields[0];
959
+ }
960
+ return fields.find((field) => field.name === state.tableIndexField);
709
961
  };
710
962
  var getDataFieldTemplates = (state) => {
711
963
  if (state.tableSchema === void 0) {
712
964
  return [];
713
965
  }
714
- const fieldsByName = new Map(state.tableSchema.fields.map((field) => [field.name, field]));
715
- return state.columns.map((column) => fieldsByName.get(column)).filter((field) => field !== void 0);
716
- };
717
- var resolveIndexFieldName = (state, options) => {
718
- if (options !== void 0 && (Array.isArray(options) || typeof options !== "object" || options === null)) {
719
- throw new JsonFrameOptionError("`toTable` options must be an object when provided.", "options", options);
966
+ const fields = state.tableSchema.fields;
967
+ if (new Set(fields.map((field) => field.name)).size === fields.length) {
968
+ const fieldsByName = new Map(fields.map((field) => [field.name, field]));
969
+ return state.columns.map((column) => fieldsByName.get(column)).filter((field) => field !== void 0);
720
970
  }
721
- if (options?.indexField !== void 0 && typeof options.indexField !== "string") {
722
- throw new JsonFrameOptionError(
723
- "`toTable` options.indexField must be a string when provided.",
724
- "indexField",
725
- options.indexField
726
- );
971
+ let dataSlice;
972
+ if (state.tableIndexField !== void 0 && fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
973
+ dataSlice = fields.slice(1);
974
+ } else if (state.tableIndexField !== void 0) {
975
+ const indexPosition = fields.findIndex((field) => field.name === state.tableIndexField);
976
+ dataSlice = indexPosition === -1 ? fields : [...fields.slice(0, indexPosition), ...fields.slice(indexPosition + 1)];
977
+ } else {
978
+ dataSlice = fields;
727
979
  }
980
+ const dataByName = new Map(dataSlice.map((field) => [field.name, field]));
981
+ const ordered = state.columns.map((column) => dataByName.get(column)).filter((field) => field !== void 0);
982
+ if (ordered.length === state.columns.length) {
983
+ return ordered;
984
+ }
985
+ return dataSlice.length === state.columns.length ? [...dataSlice] : ordered;
986
+ };
987
+ var resolveIndexFieldName = (state, options) => {
988
+ const normalized = normalizeToTableOptions(options);
728
989
  if (state.indexKind === "synthetic") {
729
990
  return void 0;
730
991
  }
731
- const indexField = options?.indexField ?? state.tableIndexField ?? "index";
992
+ const indexField = normalized.indexField ?? state.tableIndexField ?? "index";
732
993
  if (state.columns.includes(indexField)) {
733
994
  throw new JsonFrameValidationError("Table export index field name must not collide with a data column.", {
734
995
  path: "$.schema.fields",
@@ -773,55 +1034,73 @@ var resolveIndexKeys = (state, orient) => {
773
1034
  }
774
1035
  return keys;
775
1036
  };
776
- var exportRecords = (state, materialized) => {
1037
+ var getStoredColumn = (state, column) => {
1038
+ const stored = state.data.get(column);
1039
+ if (stored === void 0) {
1040
+ throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
1041
+ path: "$",
1042
+ column
1043
+ });
1044
+ }
1045
+ return stored;
1046
+ };
1047
+ var resolveStoredColumns = (state) => state.columns.map((column) => getStoredColumn(state, column));
1048
+ var exportRecords = (state) => {
1049
+ const storedColumns = resolveStoredColumns(state);
777
1050
  const rows = [];
778
1051
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
779
1052
  const row = createRecord();
780
- for (const column of state.columns) {
781
- row[column] = materialized.get(column)[rowIndex];
1053
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1054
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
782
1055
  }
783
1056
  rows.push(row);
784
1057
  }
785
1058
  return rows;
786
1059
  };
787
- var exportIndex = (state, materialized) => {
1060
+ var exportIndex = (state) => {
788
1061
  const keys = resolveIndexKeys(state, "index");
1062
+ const storedColumns = resolveStoredColumns(state);
789
1063
  const rows = createRecord();
790
1064
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
791
1065
  const row = createRecord();
792
- for (const column of state.columns) {
793
- row[column] = materialized.get(column)[rowIndex];
1066
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1067
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
794
1068
  }
795
1069
  rows[keys[rowIndex]] = row;
796
1070
  }
797
1071
  return rows;
798
1072
  };
799
- var exportColumns = (state, materialized) => {
1073
+ var exportColumns = (state) => {
800
1074
  const keys = resolveIndexKeys(state, "columns");
801
1075
  const columns = createRecord();
802
1076
  for (const column of state.columns) {
1077
+ const stored = getStoredColumn(state, column);
803
1078
  const values = createRecord();
804
- const entries = materialized.get(column);
805
1079
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
806
- values[keys[rowIndex]] = entries[rowIndex];
1080
+ values[keys[rowIndex]] = getStoredColumnValue(stored, rowIndex);
807
1081
  }
808
1082
  columns[column] = values;
809
1083
  }
810
1084
  return columns;
811
1085
  };
812
- var exportValues = (state, materialized) => {
1086
+ var exportValues = (state) => {
1087
+ const storedColumns = resolveStoredColumns(state);
813
1088
  const rows = [];
814
1089
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
815
- rows.push(state.columns.map((column) => materialized.get(column)[rowIndex]));
1090
+ const row = new Array(storedColumns.length);
1091
+ for (let columnIndex = 0; columnIndex < storedColumns.length; columnIndex += 1) {
1092
+ row[columnIndex] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
1093
+ }
1094
+ rows.push(row);
816
1095
  }
817
1096
  return rows;
818
1097
  };
819
- var exportSplit = (state, materialized) => ({
1098
+ var exportSplit = (state) => ({
820
1099
  columns: [...state.columns],
821
1100
  index: [...state.index],
822
- data: exportValues(state, materialized)
1101
+ data: exportValues(state)
823
1102
  });
824
- var exportTable = (state, materialized, columnInfo, options) => {
1103
+ var exportTable = (state, columnInfo, options) => {
825
1104
  const indexField = resolveIndexFieldName(state, options);
826
1105
  if (indexField !== void 0) {
827
1106
  assertUniqueTableIndexLabels(state.index, indexField);
@@ -834,14 +1113,15 @@ var exportTable = (state, materialized, columnInfo, options) => {
834
1113
  indexTemplate === void 0 ? { name: indexField, type: inferIndexFieldType(state.index) } : cloneSchemaField(indexTemplate, indexField, "$.schema.fields[0]")
835
1114
  );
836
1115
  }
1116
+ const storedColumns = resolveStoredColumns(state);
837
1117
  for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
838
1118
  const column = state.columns[columnIndex];
839
1119
  const template = dataTemplates[columnIndex];
840
1120
  if (template === void 0) {
841
- validateColumnValuesForType({
1121
+ validateStoredColumnValuesForType({
842
1122
  column,
843
1123
  columnIndex,
844
- values: materialized.get(column) ?? [],
1124
+ stored: storedColumns[columnIndex],
845
1125
  type: columnInfo.get(column).type,
846
1126
  orient: "table",
847
1127
  index: state.index
@@ -857,8 +1137,8 @@ var exportTable = (state, materialized, columnInfo, options) => {
857
1137
  if (indexField !== void 0) {
858
1138
  row[indexField] = state.index[rowIndex];
859
1139
  }
860
- for (const column of state.columns) {
861
- row[column] = materialized.get(column)[rowIndex];
1140
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1141
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
862
1142
  }
863
1143
  data.push(row);
864
1144
  }
@@ -887,7 +1167,57 @@ var cloneSchema2 = (schema, fields, primaryKey) => {
887
1167
  }
888
1168
  return Object.freeze(cloned);
889
1169
  };
890
- var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, materializedData_fn, createRow_fn, columnInfoOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
1170
+ var partitionSchemaFields = (state) => {
1171
+ const empty = {
1172
+ indexTemplate: void 0,
1173
+ dataByColumn: /* @__PURE__ */ new Map(),
1174
+ dataInColumnOrder: []
1175
+ };
1176
+ if (state.tableSchema === void 0) {
1177
+ return empty;
1178
+ }
1179
+ const fields = state.tableSchema.fields;
1180
+ if (state.tableIndexField === void 0) {
1181
+ const byName = new Map(fields.map((field) => [field.name, field]));
1182
+ const ordered2 = state.columns.map((column) => byName.get(column)).filter((field) => field !== void 0);
1183
+ return {
1184
+ indexTemplate: void 0,
1185
+ dataByColumn: new Map(ordered2.map((field, index) => [state.columns[index], field])),
1186
+ dataInColumnOrder: ordered2
1187
+ };
1188
+ }
1189
+ const names = fields.map((field) => field.name);
1190
+ const unique = new Set(names).size === names.length;
1191
+ if (unique) {
1192
+ const byName = new Map(fields.map((field) => [field.name, field]));
1193
+ const indexTemplate2 = byName.get(state.tableIndexField);
1194
+ const ordered2 = state.columns.map((column) => byName.get(column)).filter((field) => field !== void 0);
1195
+ return {
1196
+ indexTemplate: indexTemplate2,
1197
+ dataByColumn: new Map(ordered2.map((field, index) => [state.columns[index], field])),
1198
+ dataInColumnOrder: ordered2
1199
+ };
1200
+ }
1201
+ let indexTemplate;
1202
+ let dataSlice;
1203
+ if (fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
1204
+ indexTemplate = fields[0];
1205
+ dataSlice = fields.slice(1);
1206
+ } else {
1207
+ const indexPosition = fields.findIndex((field) => field.name === state.tableIndexField);
1208
+ indexTemplate = indexPosition === -1 ? void 0 : fields[indexPosition];
1209
+ dataSlice = indexPosition === -1 ? fields : [...fields.slice(0, indexPosition), ...fields.slice(indexPosition + 1)];
1210
+ }
1211
+ const dataByName = new Map(dataSlice.map((field) => [field.name, field]));
1212
+ const ordered = state.columns.map((column) => dataByName.get(column)).filter((field) => field !== void 0);
1213
+ const dataInColumnOrder = ordered.length === state.columns.length ? ordered : dataSlice.length === state.columns.length ? [...dataSlice] : ordered;
1214
+ return {
1215
+ indexTemplate,
1216
+ dataByColumn: new Map(dataInColumnOrder.map((field, index) => [state.columns[index], field])),
1217
+ dataInColumnOrder
1218
+ };
1219
+ };
1220
+ var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, createRow_fn, columnInfoOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
891
1221
  var DataFrame = class {
892
1222
  constructor(state, packThreshold) {
893
1223
  __privateAdd(this, _DataFrame_instances);
@@ -910,42 +1240,82 @@ var DataFrame = class {
910
1240
  return __privateGet(this, _state).index.length;
911
1241
  }
912
1242
  toRecords() {
913
- return exportRecords(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1243
+ return exportRecords(__privateGet(this, _state));
914
1244
  }
915
1245
  toIndex() {
916
- return exportIndex(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1246
+ return exportIndex(__privateGet(this, _state));
917
1247
  }
918
1248
  toColumns() {
919
- return exportColumns(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1249
+ return exportColumns(__privateGet(this, _state));
920
1250
  }
921
1251
  toValues() {
922
- return exportValues(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1252
+ return exportValues(__privateGet(this, _state));
923
1253
  }
924
1254
  toSplit() {
925
- return exportSplit(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1255
+ return exportSplit(__privateGet(this, _state));
926
1256
  }
927
1257
  toTable(options) {
928
- return exportTable(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this), __privateGet(this, _state).columnInfo, options);
929
- }
1258
+ return exportTable(__privateGet(this, _state), __privateGet(this, _state).columnInfo, options);
1259
+ }
1260
+ /**
1261
+ * Serialize the selected orient after validating the complete exported
1262
+ * payload with the shared bounded traversal.
1263
+ *
1264
+ * Depth is measured from the exported payload root, including orient
1265
+ * wrappers (`split`/`table` nest cells one level deeper than
1266
+ * `records`/`values`/`index`/`columns`). A cell accepted at ingestion may be
1267
+ * rejected here when a deeper output layout pushes it past
1268
+ * `JSON_FRAME_MAX_DEPTH`. Cycles, over-depth containers, sparse arrays, and
1269
+ * non-JSON values introduced through caller-mutable nested cells fail with
1270
+ * path-bearing `JsonFrameValidationError` carrying the selected orient.
1271
+ *
1272
+ * Validation performs one full traversal without cloning, then native
1273
+ * serialization performs a second pass. Repeated references are visited per
1274
+ * occurrence (detached semantics), so both passes expand aliases exactly as
1275
+ * `JSON.stringify()` does. Optional maxNodes bounds validation occurrences
1276
+ * (root, wrappers, metadata and scalars included), independently per call;
1277
+ * no default quota or inherited ingestion budget applies. It does not bound
1278
+ * payload construction, key allocation, bytes, or native hooks. Validation
1279
+ * reads own enumerable properties and array elements, invoking
1280
+ * caller-installed getters/`Proxy` traps, and native serialization may
1281
+ * additionally invoke `toJSON` hooks. Hooks are caller responsibility; the
1282
+ * package does not sandbox arbitrary JavaScript.
1283
+ */
930
1284
  toJSONString(orient, options) {
1285
+ const normalized = normalizeToJSONStringOptions(options);
1286
+ let payload;
931
1287
  switch (orient) {
932
- case "records":
933
- return JSON.stringify(this.toRecords());
934
- case "index":
935
- return JSON.stringify(this.toIndex());
936
- case "columns":
937
- return JSON.stringify(this.toColumns());
938
- case "values":
939
- return JSON.stringify(this.toValues());
940
- case "split":
941
- return JSON.stringify(this.toSplit());
942
- case "table":
943
- return JSON.stringify(this.toTable(options));
1288
+ case "records": {
1289
+ payload = this.toRecords();
1290
+ break;
1291
+ }
1292
+ case "index": {
1293
+ payload = this.toIndex();
1294
+ break;
1295
+ }
1296
+ case "columns": {
1297
+ payload = this.toColumns();
1298
+ break;
1299
+ }
1300
+ case "values": {
1301
+ payload = this.toValues();
1302
+ break;
1303
+ }
1304
+ case "split": {
1305
+ payload = this.toSplit();
1306
+ break;
1307
+ }
1308
+ case "table": {
1309
+ payload = this.toTable(normalized);
1310
+ break;
1311
+ }
944
1312
  default: {
945
1313
  const exhaustive = orient;
946
1314
  throw new JsonFrameValidationError("Unsupported export orient.", { value: exhaustive });
947
1315
  }
948
1316
  }
1317
+ assertJsonCompatible(payload, orient, "$", normalized.maxNodes);
1318
+ return JSON.stringify(payload);
949
1319
  }
950
1320
  row(position) {
951
1321
  __privateMethod(this, _DataFrame_instances, assertRowPosition_fn).call(this, position);
@@ -1070,7 +1440,7 @@ var DataFrame = class {
1070
1440
  }
1071
1441
  seen.add(column);
1072
1442
  }
1073
- const renamedSchema = __privateMethod(this, _DataFrame_instances, renameSchema_fn).call(this, mapping);
1443
+ const renamedSchema = __privateMethod(this, _DataFrame_instances, renameSchema_fn).call(this, mapping, nextColumns);
1074
1444
  return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
1075
1445
  columns: nextColumns,
1076
1446
  sourceColumns: __privateGet(this, _state).columns,
@@ -1100,9 +1470,6 @@ assertRowPosition_fn = function(position) {
1100
1470
  throw new RangeError(`Row position must be an integer in [0, ${this.length}).`);
1101
1471
  }
1102
1472
  };
1103
- materializedData_fn = function() {
1104
- return materializeFrameData(__privateGet(this, _state).columns, __privateGet(this, _state).data);
1105
- };
1106
1473
  createRow_fn = function(position) {
1107
1474
  const row = /* @__PURE__ */ Object.create(null);
1108
1475
  for (const column of __privateGet(this, _state).columns) {
@@ -1174,16 +1541,13 @@ selectSchema_fn = function(columns) {
1174
1541
  if (__privateGet(this, _state).tableSchema === void 0) {
1175
1542
  return {};
1176
1543
  }
1177
- const fieldByName = new Map(__privateGet(this, _state).tableSchema.fields.map((field) => [field.name, field]));
1544
+ const { indexTemplate, dataByColumn } = partitionSchemaFields(__privateGet(this, _state));
1178
1545
  const fields = [];
1179
- if (__privateGet(this, _state).tableIndexField !== void 0) {
1180
- const indexField = fieldByName.get(__privateGet(this, _state).tableIndexField);
1181
- if (indexField !== void 0) {
1182
- fields.push(cloneField(indexField));
1183
- }
1546
+ if (__privateGet(this, _state).tableIndexField !== void 0 && indexTemplate !== void 0) {
1547
+ fields.push(cloneField(indexTemplate));
1184
1548
  }
1185
1549
  for (const column of columns) {
1186
- const field = fieldByName.get(column);
1550
+ const field = dataByColumn.get(column);
1187
1551
  if (field !== void 0) {
1188
1552
  fields.push(cloneField(field));
1189
1553
  }
@@ -1193,15 +1557,36 @@ selectSchema_fn = function(columns) {
1193
1557
  ...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
1194
1558
  };
1195
1559
  };
1196
- renameSchema_fn = function(mapping) {
1560
+ renameSchema_fn = function(mapping, nextColumns) {
1197
1561
  if (__privateGet(this, _state).tableSchema === void 0) {
1198
1562
  return {};
1199
1563
  }
1200
- const fields = __privateGet(this, _state).tableSchema.fields.map((field) => {
1201
- if (!__privateGet(this, _state).columns.includes(field.name)) {
1202
- return cloneField(field);
1564
+ const names = __privateGet(this, _state).tableSchema.fields.map((field) => field.name);
1565
+ const collidesWithIndex = __privateGet(this, _state).tableIndexField !== void 0 && nextColumns.includes(__privateGet(this, _state).tableIndexField);
1566
+ if (new Set(names).size === names.length && !collidesWithIndex) {
1567
+ const columnNames = new Set(__privateGet(this, _state).columns);
1568
+ const fields2 = __privateGet(this, _state).tableSchema.fields.map((field) => {
1569
+ if (!columnNames.has(field.name)) {
1570
+ return cloneField(field);
1571
+ }
1572
+ return cloneField(field, hasOwn.call(mapping, field.name) ? mapping[field.name] : field.name);
1573
+ });
1574
+ return {
1575
+ tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields2, __privateGet(this, _state).tableSchema.primaryKey),
1576
+ ...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
1577
+ };
1578
+ }
1579
+ const { indexTemplate, dataInColumnOrder } = partitionSchemaFields(__privateGet(this, _state));
1580
+ const fields = [];
1581
+ if (__privateGet(this, _state).tableIndexField !== void 0 && indexTemplate !== void 0) {
1582
+ fields.push(cloneField(indexTemplate));
1583
+ }
1584
+ __privateGet(this, _state).columns.forEach((column, position) => {
1585
+ const template = dataInColumnOrder[position];
1586
+ if (template === void 0) {
1587
+ return;
1203
1588
  }
1204
- return cloneField(field, hasOwn.call(mapping, field.name) ? mapping[field.name] : field.name);
1589
+ fields.push(cloneField(template, hasOwn.call(mapping, column) ? mapping[column] : column));
1205
1590
  });
1206
1591
  return {
1207
1592
  tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields, __privateGet(this, _state).tableSchema.primaryKey),
@@ -1220,7 +1605,8 @@ resetIndexSchema_fn = function() {
1220
1605
  )
1221
1606
  };
1222
1607
  }
1223
- const fields = __privateGet(this, _state).tableSchema.fields.filter((field) => field.name !== __privateGet(this, _state).tableIndexField).map((field) => cloneField(field));
1608
+ const { dataInColumnOrder } = partitionSchemaFields(__privateGet(this, _state));
1609
+ const fields = dataInColumnOrder.length === __privateGet(this, _state).columns.length ? dataInColumnOrder.map((field) => cloneField(field)) : __privateGet(this, _state).tableSchema.fields.filter((field) => field.name !== __privateGet(this, _state).tableIndexField).map((field) => cloneField(field));
1224
1610
  return {
1225
1611
  tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields)
1226
1612
  };
@@ -1232,105 +1618,6 @@ var InternalDataFrame = class extends DataFrame {
1232
1618
  };
1233
1619
  var createDataFrame = (state, packThreshold) => new InternalDataFrame(state, packThreshold);
1234
1620
 
1235
- // src/options.ts
1236
- var RESOLVED_ORIENTS = [
1237
- "records",
1238
- "index",
1239
- "columns",
1240
- "values",
1241
- "split",
1242
- "table"
1243
- ];
1244
- var ORIENTS = ["auto", ...RESOLVED_ORIENTS];
1245
- var COLUMN_TYPES = [
1246
- "integer",
1247
- "float",
1248
- "string",
1249
- "boolean",
1250
- "datetime",
1251
- "categorical",
1252
- "mixed",
1253
- "unknown"
1254
- ];
1255
- var DEFAULT_PACK_THRESHOLD = 256;
1256
- var isOrient = (value) => typeof value === "string" && ORIENTS.includes(value);
1257
- var isColumnType = (value) => typeof value === "string" && COLUMN_TYPES.includes(value);
1258
- var normalizeFromOrientOptions = (options) => {
1259
- if (options == null) {
1260
- return {
1261
- orient: "auto",
1262
- packThreshold: DEFAULT_PACK_THRESHOLD
1263
- };
1264
- }
1265
- if (Array.isArray(options) || typeof options !== "object") {
1266
- throw new JsonFrameOptionError("`fromOrient` options must be an object when provided.", "options", options);
1267
- }
1268
- const orient = options.orient ?? "auto";
1269
- if (!isOrient(orient)) {
1270
- throw new JsonFrameOptionError(
1271
- "`options.orient` must be one of auto, records, index, columns, values, split, or table.",
1272
- "orient",
1273
- orient
1274
- );
1275
- }
1276
- const packThreshold = options.packThreshold ?? DEFAULT_PACK_THRESHOLD;
1277
- if (!Number.isFinite(packThreshold) || !Number.isInteger(packThreshold) || packThreshold < 0) {
1278
- throw new JsonFrameOptionError(
1279
- "`options.packThreshold` must be a finite non-negative integer.",
1280
- "packThreshold",
1281
- packThreshold
1282
- );
1283
- }
1284
- let columns;
1285
- if (options.columns !== void 0) {
1286
- if (!Array.isArray(options.columns)) {
1287
- throw new JsonFrameOptionError("`options.columns` must be an array of strings.", "columns", options.columns);
1288
- }
1289
- const seen = /* @__PURE__ */ new Set();
1290
- columns = options.columns.map((column) => {
1291
- if (typeof column !== "string") {
1292
- throw new JsonFrameOptionError("`options.columns` must contain only strings.", "columns", column);
1293
- }
1294
- if (seen.has(column)) {
1295
- throw new JsonFrameOptionError("`options.columns` must not contain duplicates.", "columns", column);
1296
- }
1297
- seen.add(column);
1298
- return column;
1299
- });
1300
- }
1301
- let columnTypes;
1302
- if (options.columnTypes !== void 0) {
1303
- if (Array.isArray(options.columnTypes) || typeof options.columnTypes !== "object" || options.columnTypes === null) {
1304
- throw new JsonFrameOptionError(
1305
- "`options.columnTypes` must be an object keyed by column name.",
1306
- "columnTypes",
1307
- options.columnTypes
1308
- );
1309
- }
1310
- const entries = Object.entries(options.columnTypes);
1311
- columnTypes = Object.freeze(
1312
- Object.fromEntries(
1313
- entries.map(([column, type]) => {
1314
- if (!isColumnType(type)) {
1315
- throw new JsonFrameOptionError(
1316
- "`options.columnTypes` values must be valid JSON Frame logical column types.",
1317
- `columnTypes.${column}`,
1318
- type
1319
- );
1320
- }
1321
- return [column, type];
1322
- })
1323
- )
1324
- );
1325
- }
1326
- return {
1327
- orient,
1328
- packThreshold,
1329
- ...columns === void 0 ? {} : { columns: Object.freeze([...columns]) },
1330
- ...columnTypes === void 0 ? {} : { columnTypes }
1331
- };
1332
- };
1333
-
1334
1621
  // src/parse/parse.ts
1335
1622
  var hasOwn2 = Object.prototype.hasOwnProperty;
1336
1623
  var IDENTIFIER_PATTERN2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
@@ -1672,6 +1959,13 @@ var parseSplit = (value, orient) => {
1672
1959
  }
1673
1960
  const columns = assertUniqueStringColumns(value.columns, orient, "$.columns");
1674
1961
  const data = initializeData(columns);
1962
+ if (value.index !== void 0 && !Array.isArray(value.index)) {
1963
+ throw new JsonFrameValidationError("`split.index` must be an array of index labels when present.", {
1964
+ orient,
1965
+ path: "$.index",
1966
+ value: value.index
1967
+ });
1968
+ }
1675
1969
  const index = [];
1676
1970
  const indexKind = Array.isArray(value.index) ? "source" : "synthetic";
1677
1971
  if (Array.isArray(value.index)) {
@@ -1985,7 +2279,12 @@ var parseInput = (input, options) => {
1985
2279
  throw error;
1986
2280
  }
1987
2281
  })();
1988
- const jsonValue = cloneJsonCompatible(parsedValue);
2282
+ const jsonValue = cloneJsonCompatible(
2283
+ parsedValue,
2284
+ options.orient === "auto" ? void 0 : options.orient,
2285
+ "$",
2286
+ options.maxNodes
2287
+ );
1989
2288
  const orient = options.orient === "auto" ? detectOrient(jsonValue) : options.orient;
1990
2289
  switch (orient) {
1991
2290
  case "records":