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

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.mjs CHANGED
@@ -8,7 +8,8 @@ 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
+ var JSON_FRAME_DIAGNOSTIC_KEY_LIMIT = 5;
12
+ var JSON_FRAME_DIAGNOSTIC_KEY_TEXT_BUDGET = 200;
12
13
  var freezeCopy = (values) => Object.freeze([...values]);
13
14
  var summarizeDiagnosticValue = (value) => {
14
15
  if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
@@ -19,11 +20,27 @@ var summarizeDiagnosticValue = (value) => {
19
20
  }
20
21
  if (typeof value === "object") {
21
22
  const keys = Object.keys(value);
23
+ const head = keys.slice(0, JSON_FRAME_DIAGNOSTIC_KEY_LIMIT);
24
+ const preview = [];
25
+ let remaining = JSON_FRAME_DIAGNOSTIC_KEY_TEXT_BUDGET;
26
+ let textTruncated = false;
27
+ for (const key of head) {
28
+ if (key.length <= remaining) {
29
+ preview.push(key);
30
+ remaining -= key.length;
31
+ } else {
32
+ if (remaining > 0) {
33
+ preview.push(key.slice(0, remaining));
34
+ }
35
+ textTruncated = true;
36
+ break;
37
+ }
38
+ }
22
39
  return Object.freeze({
23
40
  kind: "object",
24
41
  keyCount: keys.length,
25
- keys: freezeCopy(keys.slice(0, DIAGNOSTIC_KEY_LIMIT)),
26
- truncated: keys.length > DIAGNOSTIC_KEY_LIMIT
42
+ keys: freezeCopy(preview),
43
+ truncated: keys.length > JSON_FRAME_DIAGNOSTIC_KEY_LIMIT || textTruncated
27
44
  });
28
45
  }
29
46
  if (typeof value === "undefined") {
@@ -106,6 +123,7 @@ var INT32_MAX = 2147483647;
106
123
  var freezeArray = (values) => Object.freeze([...values]);
107
124
  var freezeColumnInfo = (info) => Object.freeze({ ...info });
108
125
  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}))?)?$/;
126
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
109
127
  var columnOperationCounters = {
110
128
  materializeColumnCalls: 0,
111
129
  materializedCells: 0,
@@ -199,8 +217,9 @@ var isPandasNaiveIsoDatetime = (value) => {
199
217
  if (month < 1 || month > 12 || hour > 23 || minute > 59 || second > 59) {
200
218
  return false;
201
219
  }
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;
220
+ const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
221
+ const daysInMonth = month === 2 && leapYear ? 29 : DAYS_IN_MONTH[month - 1];
222
+ return day >= 1 && day <= daysInMonth;
204
223
  };
205
224
  var isScalarCategory = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
206
225
  var isJsonContainer = (value) => {
@@ -279,6 +298,28 @@ var validateColumnValuesForType = ({
279
298
  });
280
299
  }
281
300
  };
301
+ var validateStoredColumnValuesForType = ({
302
+ column,
303
+ columnIndex,
304
+ stored,
305
+ type,
306
+ orient,
307
+ index
308
+ }) => {
309
+ for (let rowIndex = 0; rowIndex < stored.length; rowIndex += 1) {
310
+ const value = stored[rowIndex];
311
+ if (isColumnValueCompatible(type, value)) {
312
+ continue;
313
+ }
314
+ throw new JsonFrameValidationError("Column cells are incompatible with the declared logical type.", {
315
+ ...orient === void 0 ? {} : { orient },
316
+ path: getColumnCellPath(orient, column, columnIndex, rowIndex, index?.[rowIndex]),
317
+ row: rowIndex,
318
+ column,
319
+ value
320
+ });
321
+ }
322
+ };
282
323
  var packColumn = (values, info, packThreshold) => {
283
324
  if (packThreshold === 0 || values.length < packThreshold || info.nullable) {
284
325
  return freezeArray(values);
@@ -290,6 +331,9 @@ var packColumn = (values, info, packThreshold) => {
290
331
  if (typeof value !== "number" || !Number.isInteger(value) || value < INT32_MIN || value > INT32_MAX) {
291
332
  return freezeArray(values);
292
333
  }
334
+ if (Object.is(value, -0)) {
335
+ return freezeArray(values);
336
+ }
293
337
  packed[index] = value;
294
338
  }
295
339
  return packed;
@@ -336,18 +380,14 @@ var resolveSchemaTypeByColumn = (frame) => {
336
380
  return /* @__PURE__ */ new Map();
337
381
  }
338
382
  const schemaTypes = /* @__PURE__ */ new Map();
383
+ const columnNames = new Set(frame.columns);
339
384
  for (const field of frame.tableSchema.fields) {
340
- if (frame.columns.includes(field.name)) {
385
+ if (columnNames.has(field.name)) {
341
386
  schemaTypes.set(field.name, mapTableSchemaFieldType(field));
342
387
  }
343
388
  }
344
389
  return schemaTypes;
345
390
  };
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
391
  var getStoredColumnValue = (column, position) => {
352
392
  columnOperationCounters.scalarReads += 1;
353
393
  return column[position];
@@ -360,20 +400,6 @@ var rebuildStoredColumn = (column, positions) => {
360
400
  columnOperationCounters.rebuiltCells += positions.length;
361
401
  return rebuilt;
362
402
  };
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
403
  var buildFrameState = (frame, options) => {
378
404
  validateExplicitColumnTypes(frame.columns, options.columnTypes);
379
405
  const schemaTypes = resolveSchemaTypeByColumn(frame);
@@ -389,8 +415,9 @@ var buildFrameState = (frame, options) => {
389
415
  });
390
416
  }
391
417
  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) {
418
+ const explicitType = options.columnTypes !== void 0 && Object.prototype.hasOwnProperty.call(options.columnTypes, column) ? options.columnTypes[column] : void 0;
419
+ const resolvedType = schemaTypes.get(column) ?? explicitType ?? inferred.type;
420
+ if (schemaTypes.has(column) === false && explicitType !== void 0) {
394
421
  validateColumnValuesForType({
395
422
  column,
396
423
  columnIndex,
@@ -489,6 +516,16 @@ var throwValidation = (message, path, value, orient) => {
489
516
  value
490
517
  });
491
518
  };
519
+ var createNodeBudget = (maxNodes, orient) => {
520
+ let remaining = maxNodes;
521
+ return (value, path) => {
522
+ if (remaining === void 0) return;
523
+ if (remaining === 0) {
524
+ throwValidation(`JSON traversal exceeds maxNodes budget of ${maxNodes}.`, path, value, orient);
525
+ }
526
+ remaining -= 1;
527
+ };
528
+ };
492
529
  var cloneScalar = (value, path, orient) => {
493
530
  if (value === null || typeof value === "string" || typeof value === "boolean") {
494
531
  return value;
@@ -504,7 +541,8 @@ var cloneScalar = (value, path, orient) => {
504
541
  }
505
542
  return void 0;
506
543
  };
507
- var createFrame = (source, path, depth, ancestors, orient) => {
544
+ var createFrame = (source, path, depth, ancestors, orient, charge) => {
545
+ charge(source, path);
508
546
  const scalar = cloneScalar(source, path, orient);
509
547
  if (scalar !== void 0) {
510
548
  return { value: scalar };
@@ -539,9 +577,80 @@ var createFrame = (source, path, depth, ancestors, orient) => {
539
577
  frame: { kind: "object", source: objectSource, target, keys: Object.keys(objectSource), path, depth, index: 0 }
540
578
  };
541
579
  };
542
- var cloneJsonCompatible = (value, orient, path = "$") => {
580
+ var createValidateFrame = (source, path, depth, ancestors, orient, charge) => {
581
+ charge(source, path);
582
+ const scalar = cloneScalar(source, path, orient);
583
+ if (scalar !== void 0) {
584
+ return void 0;
585
+ }
586
+ if (depth > JSON_FRAME_MAX_DEPTH) {
587
+ throwValidation(
588
+ `JSON input exceeds the maximum supported nesting depth of ${JSON_FRAME_MAX_DEPTH}.`,
589
+ path,
590
+ source,
591
+ orient
592
+ );
593
+ }
594
+ if (Array.isArray(source)) {
595
+ if (ancestors.has(source)) {
596
+ throwValidation("Input contains a cyclic array.", path, source, orient);
597
+ }
598
+ ancestors.add(source);
599
+ return { kind: "array", source, path, depth, index: 0 };
600
+ }
601
+ if (!isPlainObject(source)) {
602
+ throwValidation("Input objects must be plain JSON objects or arrays.", path, source, orient);
603
+ }
604
+ const objectSource = source;
605
+ if (ancestors.has(objectSource)) {
606
+ throwValidation("Input contains a cyclic object.", path, objectSource, orient);
607
+ }
608
+ ancestors.add(objectSource);
609
+ return { kind: "object", source: objectSource, keys: Object.keys(objectSource), path, depth, index: 0 };
610
+ };
611
+ var assertJsonCompatible = (value, orient, path = "$", maxNodes) => {
543
612
  const ancestors = /* @__PURE__ */ new Set();
544
- const root = createFrame(value, rootPath(path), 0, ancestors, orient);
613
+ const charge = createNodeBudget(maxNodes, orient);
614
+ const root = createValidateFrame(value, rootPath(path), 0, ancestors, orient, charge);
615
+ const stack = root === void 0 ? [] : [root];
616
+ while (stack.length > 0) {
617
+ const frame = stack[stack.length - 1];
618
+ if (frame.kind === "array") {
619
+ if (frame.index >= frame.source.length) {
620
+ ancestors.delete(frame.source);
621
+ stack.pop();
622
+ continue;
623
+ }
624
+ const index = frame.index;
625
+ frame.index += 1;
626
+ const childPath2 = childIndexPath(frame.path, index);
627
+ if (!(index in frame.source)) {
628
+ throwValidation("Sparse arrays are not valid JSON input.", childPath2, frame.source, orient);
629
+ }
630
+ const child2 = createValidateFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient, charge);
631
+ if (child2 !== void 0) {
632
+ stack.push(child2);
633
+ }
634
+ continue;
635
+ }
636
+ if (frame.index >= frame.keys.length) {
637
+ ancestors.delete(frame.source);
638
+ stack.pop();
639
+ continue;
640
+ }
641
+ const key = frame.keys[frame.index];
642
+ frame.index += 1;
643
+ const childPath = childPropertyPath(frame.path, key);
644
+ const child = createValidateFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient, charge);
645
+ if (child !== void 0) {
646
+ stack.push(child);
647
+ }
648
+ }
649
+ };
650
+ var cloneJsonCompatible = (value, orient, path = "$", maxNodes) => {
651
+ const ancestors = /* @__PURE__ */ new Set();
652
+ const charge = createNodeBudget(maxNodes, orient);
653
+ const root = createFrame(value, rootPath(path), 0, ancestors, orient, charge);
545
654
  const stack = root.frame === void 0 ? [] : [root.frame];
546
655
  while (stack.length > 0) {
547
656
  const frame = stack[stack.length - 1];
@@ -557,7 +666,7 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
557
666
  if (!(index in frame.source)) {
558
667
  throwValidation("Sparse arrays are not valid JSON input.", childPath2, frame.source, orient);
559
668
  }
560
- const child2 = createFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient);
669
+ const child2 = createFrame(frame.source[index], childPath2, frame.depth + 1, ancestors, orient, charge);
561
670
  frame.target.push(child2.value);
562
671
  if (child2.frame !== void 0) {
563
672
  stack.push(child2.frame);
@@ -572,7 +681,7 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
572
681
  const key = frame.keys[frame.index];
573
682
  frame.index += 1;
574
683
  const childPath = childPropertyPath(frame.path, key);
575
- const child = createFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient);
684
+ const child = createFrame(frame.source[key], childPath, frame.depth + 1, ancestors, orient, charge);
576
685
  frame.target[key] = child.value;
577
686
  if (child.frame !== void 0) {
578
687
  stack.push(child.frame);
@@ -581,6 +690,142 @@ var cloneJsonCompatible = (value, orient, path = "$") => {
581
690
  return root.value;
582
691
  };
583
692
 
693
+ // src/options.ts
694
+ var RESOLVED_ORIENTS = [
695
+ "records",
696
+ "index",
697
+ "columns",
698
+ "values",
699
+ "split",
700
+ "table"
701
+ ];
702
+ var ORIENTS = ["auto", ...RESOLVED_ORIENTS];
703
+ var COLUMN_TYPES = [
704
+ "integer",
705
+ "float",
706
+ "string",
707
+ "boolean",
708
+ "datetime",
709
+ "categorical",
710
+ "mixed",
711
+ "unknown"
712
+ ];
713
+ var DEFAULT_PACK_THRESHOLD = 256;
714
+ var validateMaxNodes = (maxNodes) => {
715
+ if (maxNodes === void 0) return void 0;
716
+ if (typeof maxNodes !== "number" || !Number.isSafeInteger(maxNodes) || maxNodes <= 0) {
717
+ throw new JsonFrameOptionError("`options.maxNodes` must be a positive safe integer.", "maxNodes", maxNodes);
718
+ }
719
+ return maxNodes;
720
+ };
721
+ var normalizeToTableOptions = (options, method = "toTable") => {
722
+ if (options === void 0) return {};
723
+ if (Array.isArray(options) || typeof options !== "object" || options === null) {
724
+ throw new JsonFrameOptionError(`\`${method}\` options must be an object when provided.`, "options", options);
725
+ }
726
+ const indexField = options.indexField;
727
+ if (indexField !== void 0 && typeof indexField !== "string") {
728
+ throw new JsonFrameOptionError(
729
+ `\`${method}\` options.indexField must be a string when provided.`,
730
+ "indexField",
731
+ indexField
732
+ );
733
+ }
734
+ return indexField === void 0 ? {} : { indexField };
735
+ };
736
+ var normalizeToJSONStringOptions = (options) => {
737
+ const tableOptions = normalizeToTableOptions(options, "toJSONString");
738
+ const maxNodes = validateMaxNodes(options?.maxNodes);
739
+ return { ...tableOptions, ...maxNodes === void 0 ? {} : { maxNodes } };
740
+ };
741
+ var isOrient = (value) => typeof value === "string" && ORIENTS.includes(value);
742
+ var isColumnType = (value) => typeof value === "string" && COLUMN_TYPES.includes(value);
743
+ var normalizeFromOrientOptions = (options) => {
744
+ if (options == null) {
745
+ return {
746
+ orient: "auto",
747
+ packThreshold: DEFAULT_PACK_THRESHOLD
748
+ };
749
+ }
750
+ if (Array.isArray(options) || typeof options !== "object") {
751
+ throw new JsonFrameOptionError("`fromOrient` options must be an object when provided.", "options", options);
752
+ }
753
+ const orient = options.orient ?? "auto";
754
+ if (!isOrient(orient)) {
755
+ throw new JsonFrameOptionError(
756
+ "`options.orient` must be one of auto, records, index, columns, values, split, or table.",
757
+ "orient",
758
+ orient
759
+ );
760
+ }
761
+ const maxNodes = validateMaxNodes(options.maxNodes);
762
+ const packThreshold = options.packThreshold ?? DEFAULT_PACK_THRESHOLD;
763
+ if (!Number.isFinite(packThreshold) || !Number.isInteger(packThreshold) || packThreshold < 0) {
764
+ throw new JsonFrameOptionError(
765
+ "`options.packThreshold` must be a finite non-negative integer.",
766
+ "packThreshold",
767
+ packThreshold
768
+ );
769
+ }
770
+ let columns;
771
+ if (options.columns !== void 0) {
772
+ if (!Array.isArray(options.columns)) {
773
+ throw new JsonFrameOptionError("`options.columns` must be an array of strings.", "columns", options.columns);
774
+ }
775
+ const seen = /* @__PURE__ */ new Set();
776
+ const validated = [];
777
+ const source = options.columns;
778
+ for (let position = 0; position < source.length; position += 1) {
779
+ if (!Object.prototype.hasOwnProperty.call(source, position)) {
780
+ throw new JsonFrameOptionError(
781
+ "`options.columns` must not contain holes; every position must be a string label.",
782
+ "columns",
783
+ source
784
+ );
785
+ }
786
+ const column = source[position];
787
+ if (typeof column !== "string") {
788
+ throw new JsonFrameOptionError("`options.columns` must contain only strings.", "columns", column);
789
+ }
790
+ if (seen.has(column)) {
791
+ throw new JsonFrameOptionError("`options.columns` must not contain duplicates.", "columns", column);
792
+ }
793
+ seen.add(column);
794
+ validated.push(column);
795
+ }
796
+ columns = validated;
797
+ }
798
+ let columnTypes;
799
+ if (options.columnTypes !== void 0) {
800
+ if (Array.isArray(options.columnTypes) || typeof options.columnTypes !== "object" || options.columnTypes === null) {
801
+ throw new JsonFrameOptionError(
802
+ "`options.columnTypes` must be an object keyed by column name.",
803
+ "columnTypes",
804
+ options.columnTypes
805
+ );
806
+ }
807
+ const normalized = /* @__PURE__ */ Object.create(null);
808
+ for (const [column, type] of Object.entries(options.columnTypes)) {
809
+ if (!isColumnType(type)) {
810
+ throw new JsonFrameOptionError(
811
+ "`options.columnTypes` values must be valid JSON Frame logical column types.",
812
+ `columnTypes.${column}`,
813
+ type
814
+ );
815
+ }
816
+ normalized[column] = type;
817
+ }
818
+ columnTypes = Object.freeze(normalized);
819
+ }
820
+ return {
821
+ orient,
822
+ packThreshold,
823
+ ...maxNodes === void 0 ? {} : { maxNodes },
824
+ ...columns === void 0 ? {} : { columns: Object.freeze([...columns]) },
825
+ ...columnTypes === void 0 ? {} : { columnTypes }
826
+ };
827
+ };
828
+
584
829
  // src/export/payload.ts
585
830
  var createRecord = () => /* @__PURE__ */ Object.create(null);
586
831
  var appendPath = (path, key) => `${path}[${JSON.stringify(key)}]`;
@@ -672,30 +917,46 @@ var getIndexFieldTemplate = (state) => {
672
917
  if (state.tableSchema === void 0 || state.tableIndexField === void 0) {
673
918
  return void 0;
674
919
  }
675
- return state.tableSchema.fields.find((field) => field.name === state.tableIndexField);
920
+ const fields = state.tableSchema.fields;
921
+ if (new Set(fields.map((field) => field.name)).size === fields.length) {
922
+ return fields.find((field) => field.name === state.tableIndexField);
923
+ }
924
+ if (fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
925
+ return fields[0];
926
+ }
927
+ return fields.find((field) => field.name === state.tableIndexField);
676
928
  };
677
929
  var getDataFieldTemplates = (state) => {
678
930
  if (state.tableSchema === void 0) {
679
931
  return [];
680
932
  }
681
- const fieldsByName = new Map(state.tableSchema.fields.map((field) => [field.name, field]));
682
- return state.columns.map((column) => fieldsByName.get(column)).filter((field) => field !== void 0);
683
- };
684
- var resolveIndexFieldName = (state, options) => {
685
- if (options !== void 0 && (Array.isArray(options) || typeof options !== "object" || options === null)) {
686
- throw new JsonFrameOptionError("`toTable` options must be an object when provided.", "options", options);
933
+ const fields = state.tableSchema.fields;
934
+ if (new Set(fields.map((field) => field.name)).size === fields.length) {
935
+ const fieldsByName = new Map(fields.map((field) => [field.name, field]));
936
+ return state.columns.map((column) => fieldsByName.get(column)).filter((field) => field !== void 0);
687
937
  }
688
- if (options?.indexField !== void 0 && typeof options.indexField !== "string") {
689
- throw new JsonFrameOptionError(
690
- "`toTable` options.indexField must be a string when provided.",
691
- "indexField",
692
- options.indexField
693
- );
938
+ let dataSlice;
939
+ if (state.tableIndexField !== void 0 && fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
940
+ dataSlice = fields.slice(1);
941
+ } else if (state.tableIndexField !== void 0) {
942
+ const indexPosition = fields.findIndex((field) => field.name === state.tableIndexField);
943
+ dataSlice = indexPosition === -1 ? fields : [...fields.slice(0, indexPosition), ...fields.slice(indexPosition + 1)];
944
+ } else {
945
+ dataSlice = fields;
694
946
  }
947
+ const dataByName = new Map(dataSlice.map((field) => [field.name, field]));
948
+ const ordered = state.columns.map((column) => dataByName.get(column)).filter((field) => field !== void 0);
949
+ if (ordered.length === state.columns.length) {
950
+ return ordered;
951
+ }
952
+ return dataSlice.length === state.columns.length ? [...dataSlice] : ordered;
953
+ };
954
+ var resolveIndexFieldName = (state, options) => {
955
+ const normalized = normalizeToTableOptions(options);
695
956
  if (state.indexKind === "synthetic") {
696
957
  return void 0;
697
958
  }
698
- const indexField = options?.indexField ?? state.tableIndexField ?? "index";
959
+ const indexField = normalized.indexField ?? state.tableIndexField ?? "index";
699
960
  if (state.columns.includes(indexField)) {
700
961
  throw new JsonFrameValidationError("Table export index field name must not collide with a data column.", {
701
962
  path: "$.schema.fields",
@@ -740,55 +1001,73 @@ var resolveIndexKeys = (state, orient) => {
740
1001
  }
741
1002
  return keys;
742
1003
  };
743
- var exportRecords = (state, materialized) => {
1004
+ var getStoredColumn = (state, column) => {
1005
+ const stored = state.data.get(column);
1006
+ if (stored === void 0) {
1007
+ throw new JsonFrameValidationError("Stored frame data is missing a declared column.", {
1008
+ path: "$",
1009
+ column
1010
+ });
1011
+ }
1012
+ return stored;
1013
+ };
1014
+ var resolveStoredColumns = (state) => state.columns.map((column) => getStoredColumn(state, column));
1015
+ var exportRecords = (state) => {
1016
+ const storedColumns = resolveStoredColumns(state);
744
1017
  const rows = [];
745
1018
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
746
1019
  const row = createRecord();
747
- for (const column of state.columns) {
748
- row[column] = materialized.get(column)[rowIndex];
1020
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1021
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
749
1022
  }
750
1023
  rows.push(row);
751
1024
  }
752
1025
  return rows;
753
1026
  };
754
- var exportIndex = (state, materialized) => {
1027
+ var exportIndex = (state) => {
755
1028
  const keys = resolveIndexKeys(state, "index");
1029
+ const storedColumns = resolveStoredColumns(state);
756
1030
  const rows = createRecord();
757
1031
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
758
1032
  const row = createRecord();
759
- for (const column of state.columns) {
760
- row[column] = materialized.get(column)[rowIndex];
1033
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1034
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
761
1035
  }
762
1036
  rows[keys[rowIndex]] = row;
763
1037
  }
764
1038
  return rows;
765
1039
  };
766
- var exportColumns = (state, materialized) => {
1040
+ var exportColumns = (state) => {
767
1041
  const keys = resolveIndexKeys(state, "columns");
768
1042
  const columns = createRecord();
769
1043
  for (const column of state.columns) {
1044
+ const stored = getStoredColumn(state, column);
770
1045
  const values = createRecord();
771
- const entries = materialized.get(column);
772
1046
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
773
- values[keys[rowIndex]] = entries[rowIndex];
1047
+ values[keys[rowIndex]] = getStoredColumnValue(stored, rowIndex);
774
1048
  }
775
1049
  columns[column] = values;
776
1050
  }
777
1051
  return columns;
778
1052
  };
779
- var exportValues = (state, materialized) => {
1053
+ var exportValues = (state) => {
1054
+ const storedColumns = resolveStoredColumns(state);
780
1055
  const rows = [];
781
1056
  for (let rowIndex = 0; rowIndex < state.index.length; rowIndex += 1) {
782
- rows.push(state.columns.map((column) => materialized.get(column)[rowIndex]));
1057
+ const row = new Array(storedColumns.length);
1058
+ for (let columnIndex = 0; columnIndex < storedColumns.length; columnIndex += 1) {
1059
+ row[columnIndex] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
1060
+ }
1061
+ rows.push(row);
783
1062
  }
784
1063
  return rows;
785
1064
  };
786
- var exportSplit = (state, materialized) => ({
1065
+ var exportSplit = (state) => ({
787
1066
  columns: [...state.columns],
788
1067
  index: [...state.index],
789
- data: exportValues(state, materialized)
1068
+ data: exportValues(state)
790
1069
  });
791
- var exportTable = (state, materialized, columnInfo, options) => {
1070
+ var exportTable = (state, columnInfo, options) => {
792
1071
  const indexField = resolveIndexFieldName(state, options);
793
1072
  if (indexField !== void 0) {
794
1073
  assertUniqueTableIndexLabels(state.index, indexField);
@@ -801,14 +1080,15 @@ var exportTable = (state, materialized, columnInfo, options) => {
801
1080
  indexTemplate === void 0 ? { name: indexField, type: inferIndexFieldType(state.index) } : cloneSchemaField(indexTemplate, indexField, "$.schema.fields[0]")
802
1081
  );
803
1082
  }
1083
+ const storedColumns = resolveStoredColumns(state);
804
1084
  for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
805
1085
  const column = state.columns[columnIndex];
806
1086
  const template = dataTemplates[columnIndex];
807
1087
  if (template === void 0) {
808
- validateColumnValuesForType({
1088
+ validateStoredColumnValuesForType({
809
1089
  column,
810
1090
  columnIndex,
811
- values: materialized.get(column) ?? [],
1091
+ stored: storedColumns[columnIndex],
812
1092
  type: columnInfo.get(column).type,
813
1093
  orient: "table",
814
1094
  index: state.index
@@ -824,8 +1104,8 @@ var exportTable = (state, materialized, columnInfo, options) => {
824
1104
  if (indexField !== void 0) {
825
1105
  row[indexField] = state.index[rowIndex];
826
1106
  }
827
- for (const column of state.columns) {
828
- row[column] = materialized.get(column)[rowIndex];
1107
+ for (let columnIndex = 0; columnIndex < state.columns.length; columnIndex += 1) {
1108
+ row[state.columns[columnIndex]] = getStoredColumnValue(storedColumns[columnIndex], rowIndex);
829
1109
  }
830
1110
  data.push(row);
831
1111
  }
@@ -854,7 +1134,57 @@ var cloneSchema2 = (schema, fields, primaryKey) => {
854
1134
  }
855
1135
  return Object.freeze(cloned);
856
1136
  };
857
- var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, materializedData_fn, createRow_fn, columnInfoOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
1137
+ var partitionSchemaFields = (state) => {
1138
+ const empty = {
1139
+ indexTemplate: void 0,
1140
+ dataByColumn: /* @__PURE__ */ new Map(),
1141
+ dataInColumnOrder: []
1142
+ };
1143
+ if (state.tableSchema === void 0) {
1144
+ return empty;
1145
+ }
1146
+ const fields = state.tableSchema.fields;
1147
+ if (state.tableIndexField === void 0) {
1148
+ const byName = new Map(fields.map((field) => [field.name, field]));
1149
+ const ordered2 = state.columns.map((column) => byName.get(column)).filter((field) => field !== void 0);
1150
+ return {
1151
+ indexTemplate: void 0,
1152
+ dataByColumn: new Map(ordered2.map((field, index) => [state.columns[index], field])),
1153
+ dataInColumnOrder: ordered2
1154
+ };
1155
+ }
1156
+ const names = fields.map((field) => field.name);
1157
+ const unique = new Set(names).size === names.length;
1158
+ if (unique) {
1159
+ const byName = new Map(fields.map((field) => [field.name, field]));
1160
+ const indexTemplate2 = byName.get(state.tableIndexField);
1161
+ const ordered2 = state.columns.map((column) => byName.get(column)).filter((field) => field !== void 0);
1162
+ return {
1163
+ indexTemplate: indexTemplate2,
1164
+ dataByColumn: new Map(ordered2.map((field, index) => [state.columns[index], field])),
1165
+ dataInColumnOrder: ordered2
1166
+ };
1167
+ }
1168
+ let indexTemplate;
1169
+ let dataSlice;
1170
+ if (fields.length === state.columns.length + 1 && fields[0].name === state.tableIndexField) {
1171
+ indexTemplate = fields[0];
1172
+ dataSlice = fields.slice(1);
1173
+ } else {
1174
+ const indexPosition = fields.findIndex((field) => field.name === state.tableIndexField);
1175
+ indexTemplate = indexPosition === -1 ? void 0 : fields[indexPosition];
1176
+ dataSlice = indexPosition === -1 ? fields : [...fields.slice(0, indexPosition), ...fields.slice(indexPosition + 1)];
1177
+ }
1178
+ const dataByName = new Map(dataSlice.map((field) => [field.name, field]));
1179
+ const ordered = state.columns.map((column) => dataByName.get(column)).filter((field) => field !== void 0);
1180
+ const dataInColumnOrder = ordered.length === state.columns.length ? ordered : dataSlice.length === state.columns.length ? [...dataSlice] : ordered;
1181
+ return {
1182
+ indexTemplate,
1183
+ dataByColumn: new Map(dataInColumnOrder.map((field, index) => [state.columns[index], field])),
1184
+ dataInColumnOrder
1185
+ };
1186
+ };
1187
+ var _state, _packThreshold, _DataFrame_instances, assertRowPosition_fn, createRow_fn, columnInfoOverrides_fn, rebuild_fn, selectSchema_fn, renameSchema_fn, resetIndexSchema_fn;
858
1188
  var DataFrame = class {
859
1189
  constructor(state, packThreshold) {
860
1190
  __privateAdd(this, _DataFrame_instances);
@@ -877,42 +1207,82 @@ var DataFrame = class {
877
1207
  return __privateGet(this, _state).index.length;
878
1208
  }
879
1209
  toRecords() {
880
- return exportRecords(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1210
+ return exportRecords(__privateGet(this, _state));
881
1211
  }
882
1212
  toIndex() {
883
- return exportIndex(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1213
+ return exportIndex(__privateGet(this, _state));
884
1214
  }
885
1215
  toColumns() {
886
- return exportColumns(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1216
+ return exportColumns(__privateGet(this, _state));
887
1217
  }
888
1218
  toValues() {
889
- return exportValues(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1219
+ return exportValues(__privateGet(this, _state));
890
1220
  }
891
1221
  toSplit() {
892
- return exportSplit(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this));
1222
+ return exportSplit(__privateGet(this, _state));
893
1223
  }
894
1224
  toTable(options) {
895
- return exportTable(__privateGet(this, _state), __privateMethod(this, _DataFrame_instances, materializedData_fn).call(this), __privateGet(this, _state).columnInfo, options);
896
- }
1225
+ return exportTable(__privateGet(this, _state), __privateGet(this, _state).columnInfo, options);
1226
+ }
1227
+ /**
1228
+ * Serialize the selected orient after validating the complete exported
1229
+ * payload with the shared bounded traversal.
1230
+ *
1231
+ * Depth is measured from the exported payload root, including orient
1232
+ * wrappers (`split`/`table` nest cells one level deeper than
1233
+ * `records`/`values`/`index`/`columns`). A cell accepted at ingestion may be
1234
+ * rejected here when a deeper output layout pushes it past
1235
+ * `JSON_FRAME_MAX_DEPTH`. Cycles, over-depth containers, sparse arrays, and
1236
+ * non-JSON values introduced through caller-mutable nested cells fail with
1237
+ * path-bearing `JsonFrameValidationError` carrying the selected orient.
1238
+ *
1239
+ * Validation performs one full traversal without cloning, then native
1240
+ * serialization performs a second pass. Repeated references are visited per
1241
+ * occurrence (detached semantics), so both passes expand aliases exactly as
1242
+ * `JSON.stringify()` does. Optional maxNodes bounds validation occurrences
1243
+ * (root, wrappers, metadata and scalars included), independently per call;
1244
+ * no default quota or inherited ingestion budget applies. It does not bound
1245
+ * payload construction, key allocation, bytes, or native hooks. Validation
1246
+ * reads own enumerable properties and array elements, invoking
1247
+ * caller-installed getters/`Proxy` traps, and native serialization may
1248
+ * additionally invoke `toJSON` hooks. Hooks are caller responsibility; the
1249
+ * package does not sandbox arbitrary JavaScript.
1250
+ */
897
1251
  toJSONString(orient, options) {
1252
+ const normalized = normalizeToJSONStringOptions(options);
1253
+ let payload;
898
1254
  switch (orient) {
899
- case "records":
900
- return JSON.stringify(this.toRecords());
901
- case "index":
902
- return JSON.stringify(this.toIndex());
903
- case "columns":
904
- return JSON.stringify(this.toColumns());
905
- case "values":
906
- return JSON.stringify(this.toValues());
907
- case "split":
908
- return JSON.stringify(this.toSplit());
909
- case "table":
910
- return JSON.stringify(this.toTable(options));
1255
+ case "records": {
1256
+ payload = this.toRecords();
1257
+ break;
1258
+ }
1259
+ case "index": {
1260
+ payload = this.toIndex();
1261
+ break;
1262
+ }
1263
+ case "columns": {
1264
+ payload = this.toColumns();
1265
+ break;
1266
+ }
1267
+ case "values": {
1268
+ payload = this.toValues();
1269
+ break;
1270
+ }
1271
+ case "split": {
1272
+ payload = this.toSplit();
1273
+ break;
1274
+ }
1275
+ case "table": {
1276
+ payload = this.toTable(normalized);
1277
+ break;
1278
+ }
911
1279
  default: {
912
1280
  const exhaustive = orient;
913
1281
  throw new JsonFrameValidationError("Unsupported export orient.", { value: exhaustive });
914
1282
  }
915
1283
  }
1284
+ assertJsonCompatible(payload, orient, "$", normalized.maxNodes);
1285
+ return JSON.stringify(payload);
916
1286
  }
917
1287
  row(position) {
918
1288
  __privateMethod(this, _DataFrame_instances, assertRowPosition_fn).call(this, position);
@@ -1037,7 +1407,7 @@ var DataFrame = class {
1037
1407
  }
1038
1408
  seen.add(column);
1039
1409
  }
1040
- const renamedSchema = __privateMethod(this, _DataFrame_instances, renameSchema_fn).call(this, mapping);
1410
+ const renamedSchema = __privateMethod(this, _DataFrame_instances, renameSchema_fn).call(this, mapping, nextColumns);
1041
1411
  return __privateMethod(this, _DataFrame_instances, rebuild_fn).call(this, {
1042
1412
  columns: nextColumns,
1043
1413
  sourceColumns: __privateGet(this, _state).columns,
@@ -1067,9 +1437,6 @@ assertRowPosition_fn = function(position) {
1067
1437
  throw new RangeError(`Row position must be an integer in [0, ${this.length}).`);
1068
1438
  }
1069
1439
  };
1070
- materializedData_fn = function() {
1071
- return materializeFrameData(__privateGet(this, _state).columns, __privateGet(this, _state).data);
1072
- };
1073
1440
  createRow_fn = function(position) {
1074
1441
  const row = /* @__PURE__ */ Object.create(null);
1075
1442
  for (const column of __privateGet(this, _state).columns) {
@@ -1141,16 +1508,13 @@ selectSchema_fn = function(columns) {
1141
1508
  if (__privateGet(this, _state).tableSchema === void 0) {
1142
1509
  return {};
1143
1510
  }
1144
- const fieldByName = new Map(__privateGet(this, _state).tableSchema.fields.map((field) => [field.name, field]));
1511
+ const { indexTemplate, dataByColumn } = partitionSchemaFields(__privateGet(this, _state));
1145
1512
  const fields = [];
1146
- if (__privateGet(this, _state).tableIndexField !== void 0) {
1147
- const indexField = fieldByName.get(__privateGet(this, _state).tableIndexField);
1148
- if (indexField !== void 0) {
1149
- fields.push(cloneField(indexField));
1150
- }
1513
+ if (__privateGet(this, _state).tableIndexField !== void 0 && indexTemplate !== void 0) {
1514
+ fields.push(cloneField(indexTemplate));
1151
1515
  }
1152
1516
  for (const column of columns) {
1153
- const field = fieldByName.get(column);
1517
+ const field = dataByColumn.get(column);
1154
1518
  if (field !== void 0) {
1155
1519
  fields.push(cloneField(field));
1156
1520
  }
@@ -1160,15 +1524,36 @@ selectSchema_fn = function(columns) {
1160
1524
  ...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
1161
1525
  };
1162
1526
  };
1163
- renameSchema_fn = function(mapping) {
1527
+ renameSchema_fn = function(mapping, nextColumns) {
1164
1528
  if (__privateGet(this, _state).tableSchema === void 0) {
1165
1529
  return {};
1166
1530
  }
1167
- const fields = __privateGet(this, _state).tableSchema.fields.map((field) => {
1168
- if (!__privateGet(this, _state).columns.includes(field.name)) {
1169
- return cloneField(field);
1531
+ const names = __privateGet(this, _state).tableSchema.fields.map((field) => field.name);
1532
+ const collidesWithIndex = __privateGet(this, _state).tableIndexField !== void 0 && nextColumns.includes(__privateGet(this, _state).tableIndexField);
1533
+ if (new Set(names).size === names.length && !collidesWithIndex) {
1534
+ const columnNames = new Set(__privateGet(this, _state).columns);
1535
+ const fields2 = __privateGet(this, _state).tableSchema.fields.map((field) => {
1536
+ if (!columnNames.has(field.name)) {
1537
+ return cloneField(field);
1538
+ }
1539
+ return cloneField(field, hasOwn.call(mapping, field.name) ? mapping[field.name] : field.name);
1540
+ });
1541
+ return {
1542
+ tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields2, __privateGet(this, _state).tableSchema.primaryKey),
1543
+ ...__privateGet(this, _state).tableIndexField === void 0 ? {} : { tableIndexField: __privateGet(this, _state).tableIndexField }
1544
+ };
1545
+ }
1546
+ const { indexTemplate, dataInColumnOrder } = partitionSchemaFields(__privateGet(this, _state));
1547
+ const fields = [];
1548
+ if (__privateGet(this, _state).tableIndexField !== void 0 && indexTemplate !== void 0) {
1549
+ fields.push(cloneField(indexTemplate));
1550
+ }
1551
+ __privateGet(this, _state).columns.forEach((column, position) => {
1552
+ const template = dataInColumnOrder[position];
1553
+ if (template === void 0) {
1554
+ return;
1170
1555
  }
1171
- return cloneField(field, hasOwn.call(mapping, field.name) ? mapping[field.name] : field.name);
1556
+ fields.push(cloneField(template, hasOwn.call(mapping, column) ? mapping[column] : column));
1172
1557
  });
1173
1558
  return {
1174
1559
  tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields, __privateGet(this, _state).tableSchema.primaryKey),
@@ -1187,7 +1572,8 @@ resetIndexSchema_fn = function() {
1187
1572
  )
1188
1573
  };
1189
1574
  }
1190
- const fields = __privateGet(this, _state).tableSchema.fields.filter((field) => field.name !== __privateGet(this, _state).tableIndexField).map((field) => cloneField(field));
1575
+ const { dataInColumnOrder } = partitionSchemaFields(__privateGet(this, _state));
1576
+ 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));
1191
1577
  return {
1192
1578
  tableSchema: cloneSchema2(__privateGet(this, _state).tableSchema, fields)
1193
1579
  };
@@ -1199,105 +1585,6 @@ var InternalDataFrame = class extends DataFrame {
1199
1585
  };
1200
1586
  var createDataFrame = (state, packThreshold) => new InternalDataFrame(state, packThreshold);
1201
1587
 
1202
- // src/options.ts
1203
- var RESOLVED_ORIENTS = [
1204
- "records",
1205
- "index",
1206
- "columns",
1207
- "values",
1208
- "split",
1209
- "table"
1210
- ];
1211
- var ORIENTS = ["auto", ...RESOLVED_ORIENTS];
1212
- var COLUMN_TYPES = [
1213
- "integer",
1214
- "float",
1215
- "string",
1216
- "boolean",
1217
- "datetime",
1218
- "categorical",
1219
- "mixed",
1220
- "unknown"
1221
- ];
1222
- var DEFAULT_PACK_THRESHOLD = 256;
1223
- var isOrient = (value) => typeof value === "string" && ORIENTS.includes(value);
1224
- var isColumnType = (value) => typeof value === "string" && COLUMN_TYPES.includes(value);
1225
- var normalizeFromOrientOptions = (options) => {
1226
- if (options == null) {
1227
- return {
1228
- orient: "auto",
1229
- packThreshold: DEFAULT_PACK_THRESHOLD
1230
- };
1231
- }
1232
- if (Array.isArray(options) || typeof options !== "object") {
1233
- throw new JsonFrameOptionError("`fromOrient` options must be an object when provided.", "options", options);
1234
- }
1235
- const orient = options.orient ?? "auto";
1236
- if (!isOrient(orient)) {
1237
- throw new JsonFrameOptionError(
1238
- "`options.orient` must be one of auto, records, index, columns, values, split, or table.",
1239
- "orient",
1240
- orient
1241
- );
1242
- }
1243
- const packThreshold = options.packThreshold ?? DEFAULT_PACK_THRESHOLD;
1244
- if (!Number.isFinite(packThreshold) || !Number.isInteger(packThreshold) || packThreshold < 0) {
1245
- throw new JsonFrameOptionError(
1246
- "`options.packThreshold` must be a finite non-negative integer.",
1247
- "packThreshold",
1248
- packThreshold
1249
- );
1250
- }
1251
- let columns;
1252
- if (options.columns !== void 0) {
1253
- if (!Array.isArray(options.columns)) {
1254
- throw new JsonFrameOptionError("`options.columns` must be an array of strings.", "columns", options.columns);
1255
- }
1256
- const seen = /* @__PURE__ */ new Set();
1257
- columns = options.columns.map((column) => {
1258
- if (typeof column !== "string") {
1259
- throw new JsonFrameOptionError("`options.columns` must contain only strings.", "columns", column);
1260
- }
1261
- if (seen.has(column)) {
1262
- throw new JsonFrameOptionError("`options.columns` must not contain duplicates.", "columns", column);
1263
- }
1264
- seen.add(column);
1265
- return column;
1266
- });
1267
- }
1268
- let columnTypes;
1269
- if (options.columnTypes !== void 0) {
1270
- if (Array.isArray(options.columnTypes) || typeof options.columnTypes !== "object" || options.columnTypes === null) {
1271
- throw new JsonFrameOptionError(
1272
- "`options.columnTypes` must be an object keyed by column name.",
1273
- "columnTypes",
1274
- options.columnTypes
1275
- );
1276
- }
1277
- const entries = Object.entries(options.columnTypes);
1278
- columnTypes = Object.freeze(
1279
- Object.fromEntries(
1280
- entries.map(([column, type]) => {
1281
- if (!isColumnType(type)) {
1282
- throw new JsonFrameOptionError(
1283
- "`options.columnTypes` values must be valid JSON Frame logical column types.",
1284
- `columnTypes.${column}`,
1285
- type
1286
- );
1287
- }
1288
- return [column, type];
1289
- })
1290
- )
1291
- );
1292
- }
1293
- return {
1294
- orient,
1295
- packThreshold,
1296
- ...columns === void 0 ? {} : { columns: Object.freeze([...columns]) },
1297
- ...columnTypes === void 0 ? {} : { columnTypes }
1298
- };
1299
- };
1300
-
1301
1588
  // src/parse/parse.ts
1302
1589
  var hasOwn2 = Object.prototype.hasOwnProperty;
1303
1590
  var IDENTIFIER_PATTERN2 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
@@ -1639,6 +1926,13 @@ var parseSplit = (value, orient) => {
1639
1926
  }
1640
1927
  const columns = assertUniqueStringColumns(value.columns, orient, "$.columns");
1641
1928
  const data = initializeData(columns);
1929
+ if (value.index !== void 0 && !Array.isArray(value.index)) {
1930
+ throw new JsonFrameValidationError("`split.index` must be an array of index labels when present.", {
1931
+ orient,
1932
+ path: "$.index",
1933
+ value: value.index
1934
+ });
1935
+ }
1642
1936
  const index = [];
1643
1937
  const indexKind = Array.isArray(value.index) ? "source" : "synthetic";
1644
1938
  if (Array.isArray(value.index)) {
@@ -1952,7 +2246,12 @@ var parseInput = (input, options) => {
1952
2246
  throw error;
1953
2247
  }
1954
2248
  })();
1955
- const jsonValue = cloneJsonCompatible(parsedValue);
2249
+ const jsonValue = cloneJsonCompatible(
2250
+ parsedValue,
2251
+ options.orient === "auto" ? void 0 : options.orient,
2252
+ "$",
2253
+ options.maxNodes
2254
+ );
1956
2255
  const orient = options.orient === "auto" ? detectOrient(jsonValue) : options.orient;
1957
2256
  switch (orient) {
1958
2257
  case "records":