seroval 0.4.0-alpha.1 → 0.4.0-alpha.3

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/src/tree.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
1
2
  /* eslint-disable guard-for-in */
2
3
  /* eslint-disable @typescript-eslint/no-for-in-array */
3
4
  /* eslint-disable no-await-in-loop */
@@ -535,35 +536,40 @@ function generateSemiPrimitiveValue(
535
536
  return undefined;
536
537
  }
537
538
 
539
+ function serializePropertiesSync(
540
+ ctx: SerializationContext,
541
+ properties: Record<string, unknown>,
542
+ ): SerovalDictionaryNode {
543
+ const keys = Object.keys(properties);
544
+ const size = keys.length;
545
+ const keyNodes = new Array<string>(size);
546
+ const valueNodes = new Array<SerovalNode>(size);
547
+ const deferredKeys = new Array<string>(size);
548
+ const deferredValues = new Array<ServerValue>(size);
549
+ let deferredSize = 0;
550
+ let nodesSize = 0;
551
+ for (const key of keys) {
552
+ if (isIterable(properties[key])) {
553
+ deferredKeys[deferredSize] = key;
554
+ deferredValues[deferredSize] = properties[key] as ServerValue;
555
+ deferredSize++;
556
+ } else {
557
+ keyNodes[nodesSize] = key;
558
+ valueNodes[nodesSize] = generateTreeSync(ctx, properties[key] as ServerValue);
559
+ nodesSize++;
560
+ }
561
+ }
562
+ for (let i = 0; i < deferredSize; i++) {
563
+ keyNodes[nodesSize + i] = deferredKeys[i];
564
+ valueNodes[nodesSize + i] = generateTreeSync(ctx, deferredValues[i]);
565
+ }
566
+ return [keyNodes, valueNodes, size];
567
+ }
568
+
538
569
  export function generateTreeSync(
539
570
  ctx: SerializationContext,
540
571
  current: ServerValue,
541
572
  ): SerovalNode {
542
- function serializeProperties(
543
- properties: Record<string, unknown>,
544
- ): SerovalDictionaryNode {
545
- const keyNodes: string[] = [];
546
- const valueNodes: SerovalNode[] = [];
547
- const deferredKeys: string[] = [];
548
- const deferredValues: ServerValue[] = [];
549
- const keys = Object.keys(properties);
550
- let deferredSize = 0;
551
- for (const key of keys) {
552
- if (isIterable(properties[key])) {
553
- deferredKeys.push(key);
554
- deferredValues.push(properties[key] as ServerValue);
555
- deferredSize++;
556
- } else {
557
- keyNodes.push(key);
558
- valueNodes.push(generateTreeSync(ctx, properties[key] as ServerValue));
559
- }
560
- }
561
- for (let i = 0; i < deferredSize; i++) {
562
- keyNodes.push(deferredKeys[i]);
563
- valueNodes.push(generateTreeSync(ctx, deferredValues[i]));
564
- }
565
- return [keyNodes, valueNodes, keys.length];
566
- }
567
573
  if (isPrimitive(current)) {
568
574
  return [SerovalNodeType.Primitive, current];
569
575
  }
@@ -579,45 +585,51 @@ export function generateTreeSync(
579
585
  }
580
586
  if (constructorCheck<Set<ServerValue>>(current, Set)) {
581
587
  assert(ctx.features.has(Feature.Set), 'Unsupported type "Set"');
582
- const nodes: SerovalNode[] = [];
583
- const deferred: ServerValue[] = [];
588
+ const len = current.size;
589
+ const nodes = new Array<SerovalNode>(len);
590
+ const deferred = new Array<ServerValue>(len);
591
+ let deferredSize = 0;
592
+ let nodeSize = 0;
584
593
  for (const item of current.keys()) {
585
594
  // Iterables are lazy, so the evaluation must be deferred
586
595
  if (isIterable(item)) {
587
- deferred.push(item);
596
+ deferred[deferredSize++] = item;
588
597
  } else {
589
- nodes.push(generateTreeSync(ctx, item));
598
+ nodes[nodeSize++] = generateTreeSync(ctx, item);
590
599
  }
591
600
  }
592
601
  // Parse deferred items
593
- for (let i = 0, len = deferred.length; i < len; i++) {
594
- nodes.push(generateTreeSync(ctx, deferred[i]));
602
+ for (let i = 0; i < deferredSize; i++) {
603
+ nodes[nodeSize + i] = generateTreeSync(ctx, deferred[i]);
595
604
  }
596
605
  return [SerovalNodeType.Set, nodes, id];
597
606
  }
598
607
  if (constructorCheck<Map<ServerValue, ServerValue>>(current, Map)) {
599
608
  assert(ctx.features.has(Feature.Map), 'Unsupported type "Map"');
600
- const keyNodes: SerovalNode[] = [];
601
- const valueNodes: SerovalNode[] = [];
602
- const deferredKey: ServerValue[] = [];
603
- const deferredValue: ServerValue[] = [];
609
+ const len = current.size;
610
+ const keyNodes = new Array<SerovalNode>(len);
611
+ const valueNodes = new Array<SerovalNode>(len);
612
+ const deferredKey = new Array<ServerValue>(len);
613
+ const deferredValue = new Array<ServerValue>(len);
604
614
  let deferredSize = 0;
615
+ let nodeSize = 0;
605
616
  for (const [key, value] of current.entries()) {
606
617
  // Either key or value might be an iterable
607
618
  if (isIterable(key) || isIterable(value)) {
608
- deferredKey.push(key);
609
- deferredValue.push(value);
619
+ deferredKey[deferredSize] = key;
620
+ deferredValue[deferredSize] = value;
610
621
  deferredSize++;
611
622
  } else {
612
- keyNodes.push(generateTreeSync(ctx, key));
613
- valueNodes.push(generateTreeSync(ctx, value));
623
+ keyNodes[nodeSize] = generateTreeSync(ctx, key);
624
+ valueNodes[nodeSize] = generateTreeSync(ctx, value);
625
+ nodeSize++;
614
626
  }
615
627
  }
616
628
  for (let i = 0; i < deferredSize; i++) {
617
- keyNodes.push(generateTreeSync(ctx, deferredKey[i]));
618
- valueNodes.push(generateTreeSync(ctx, deferredValue[i]));
629
+ keyNodes[nodeSize + i] = generateTreeSync(ctx, deferredKey[i]);
630
+ valueNodes[nodeSize + i] = generateTreeSync(ctx, deferredValue[i]);
619
631
  }
620
- return [SerovalNodeType.Map, [keyNodes, valueNodes, current.size], id];
632
+ return [SerovalNodeType.Map, [keyNodes, valueNodes, len], id];
621
633
  }
622
634
  if (Array.isArray(current)) {
623
635
  const size = current.length;
@@ -642,7 +654,7 @@ export function generateTreeSync(
642
654
  if (current instanceof AggregateError && ctx.features.has(Feature.AggregateError)) {
643
655
  const options = getErrorOptions(current);
644
656
  const optionsNode = options
645
- ? serializeProperties(options)
657
+ ? serializePropertiesSync(ctx, options)
646
658
  : undefined;
647
659
  const errorsNode = generateTreeSync(ctx, current.errors as ServerValue);
648
660
  return [SerovalNodeType.AggregateError, [current.message, optionsNode, errorsNode], id];
@@ -650,7 +662,7 @@ export function generateTreeSync(
650
662
  if (current instanceof Error) {
651
663
  const options = getErrorOptions(current);
652
664
  const optionsNode = options
653
- ? serializeProperties(options)
665
+ ? serializePropertiesSync(ctx, options)
654
666
  : undefined;
655
667
  return [
656
668
  SerovalNodeType.Error,
@@ -663,7 +675,7 @@ export function generateTreeSync(
663
675
  const options = getIterableOptions(current);
664
676
  return [SerovalNodeType.Iterable, [
665
677
  // Parse options first before the items
666
- options ? serializeProperties(options) : undefined,
678
+ options ? serializePropertiesSync(ctx, options) : undefined,
667
679
  generateTreeSync(ctx, Array.from(current)),
668
680
  ], id];
669
681
  }
@@ -671,42 +683,47 @@ export function generateTreeSync(
671
683
  if (current.constructor === Object || empty) {
672
684
  return [
673
685
  empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
674
- serializeProperties(current as Record<string, unknown>),
686
+ serializePropertiesSync(ctx, current as Record<string, unknown>),
675
687
  id,
676
688
  ];
677
689
  }
678
690
  throw new Error('Unsupported value');
679
691
  }
680
692
 
693
+ async function serializePropertiesAsync(
694
+ ctx: SerializationContext,
695
+ properties: Record<string, unknown>,
696
+ ): Promise<SerovalDictionaryNode> {
697
+ const keys = Object.keys(properties);
698
+ const size = keys.length;
699
+ const keyNodes = new Array<string>(size);
700
+ const valueNodes = new Array<SerovalNode>(size);
701
+ const deferredKeys = new Array<string>(size);
702
+ const deferredValues = new Array<ServerValue>(size);
703
+ let deferredSize = 0;
704
+ let nodesSize = 0;
705
+ for (const key of keys) {
706
+ if (isIterable(properties[key])) {
707
+ deferredKeys[deferredSize] = key;
708
+ deferredValues[deferredSize] = properties[key] as ServerValue;
709
+ deferredSize++;
710
+ } else {
711
+ keyNodes[nodesSize] = key;
712
+ valueNodes[nodesSize] = await generateTreeAsync(ctx, properties[key] as ServerValue);
713
+ nodesSize++;
714
+ }
715
+ }
716
+ for (let i = 0; i < deferredSize; i++) {
717
+ keyNodes[nodesSize + i] = deferredKeys[i];
718
+ valueNodes[nodesSize + i] = await generateTreeAsync(ctx, deferredValues[i]);
719
+ }
720
+ return [keyNodes, valueNodes, size];
721
+ }
722
+
681
723
  export async function generateTreeAsync(
682
724
  ctx: SerializationContext,
683
725
  current: AsyncServerValue,
684
726
  ): Promise<SerovalNode> {
685
- async function serializeProperties(
686
- properties: Record<string, unknown>,
687
- ): Promise<SerovalDictionaryNode> {
688
- const keyNodes: string[] = [];
689
- const valueNodes: SerovalNode[] = [];
690
- const deferredKeys: string[] = [];
691
- const deferredValues: ServerValue[] = [];
692
- const keys = Object.keys(properties);
693
- let deferredSize = 0;
694
- for (const key of keys) {
695
- if (isIterable(properties[key])) {
696
- deferredKeys.push(key);
697
- deferredValues.push(properties[key] as ServerValue);
698
- deferredSize++;
699
- } else {
700
- keyNodes.push(key);
701
- valueNodes.push(await generateTreeAsync(ctx, properties[key] as ServerValue));
702
- }
703
- }
704
- for (let i = 0; i < deferredSize; i++) {
705
- keyNodes.push(deferredKeys[i]);
706
- valueNodes.push(await generateTreeAsync(ctx, deferredValues[i]));
707
- }
708
- return [keyNodes, valueNodes, keys.length];
709
- }
710
727
  if (isPrimitive(current)) {
711
728
  return [SerovalNodeType.Primitive, current];
712
729
  }
@@ -728,42 +745,51 @@ export async function generateTreeAsync(
728
745
  }
729
746
  if (constructorCheck<Set<AsyncServerValue>>(current, Set)) {
730
747
  assert(ctx.features.has(Feature.Set), 'Unsupported type "Set"');
731
- const nodes: SerovalNode[] = [];
732
- const deferred: AsyncServerValue[] = [];
748
+ const len = current.size;
749
+ const nodes = new Array<SerovalNode>(len);
750
+ const deferred = new Array<AsyncServerValue>(len);
751
+ let deferredSize = 0;
752
+ let nodeSize = 0;
733
753
  for (const item of current.keys()) {
754
+ // Iterables are lazy, so the evaluation must be deferred
734
755
  if (isIterable(item)) {
735
- deferred.push(item);
756
+ deferred[deferredSize++] = item;
736
757
  } else {
737
- nodes.push(await generateTreeAsync(ctx, item));
758
+ nodes[nodeSize++] = await generateTreeAsync(ctx, item);
738
759
  }
739
760
  }
740
- for (let i = 0, len = deferred.length; i < len; i++) {
741
- nodes.push(await generateTreeAsync(ctx, deferred[i]));
761
+ // Parse deferred items
762
+ for (let i = 0; i < deferredSize; i++) {
763
+ nodes[nodeSize + i] = await generateTreeAsync(ctx, deferred[i]);
742
764
  }
743
765
  return [SerovalNodeType.Set, nodes, id];
744
766
  }
745
767
  if (constructorCheck<Map<AsyncServerValue, AsyncServerValue>>(current, Map)) {
746
768
  assert(ctx.features.has(Feature.Map), 'Unsupported type "Map"');
747
- const keyNodes: SerovalNode[] = [];
748
- const valueNodes: SerovalNode[] = [];
749
- const deferredKey: AsyncServerValue[] = [];
750
- const deferredValue: AsyncServerValue[] = [];
769
+ const len = current.size;
770
+ const keyNodes = new Array<SerovalNode>(len);
771
+ const valueNodes = new Array<SerovalNode>(len);
772
+ const deferredKey = new Array<AsyncServerValue>(len);
773
+ const deferredValue = new Array<AsyncServerValue>(len);
751
774
  let deferredSize = 0;
775
+ let nodeSize = 0;
752
776
  for (const [key, value] of current.entries()) {
777
+ // Either key or value might be an iterable
753
778
  if (isIterable(key) || isIterable(value)) {
754
- deferredKey.push(key);
755
- deferredValue.push(value);
779
+ deferredKey[deferredSize] = key;
780
+ deferredValue[deferredSize] = value;
756
781
  deferredSize++;
757
782
  } else {
758
- keyNodes.push(await generateTreeAsync(ctx, key));
759
- valueNodes.push(await generateTreeAsync(ctx, value));
783
+ keyNodes[nodeSize] = await generateTreeAsync(ctx, key);
784
+ valueNodes[nodeSize] = await generateTreeAsync(ctx, value);
785
+ nodeSize++;
760
786
  }
761
787
  }
762
788
  for (let i = 0; i < deferredSize; i++) {
763
- keyNodes.push(await generateTreeAsync(ctx, deferredKey[i]));
764
- valueNodes.push(await generateTreeAsync(ctx, deferredValue[i]));
789
+ keyNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredKey[i]);
790
+ valueNodes[nodeSize + i] = await generateTreeAsync(ctx, deferredValue[i]);
765
791
  }
766
- return [SerovalNodeType.Map, [keyNodes, valueNodes, current.size], id];
792
+ return [SerovalNodeType.Map, [keyNodes, valueNodes, len], id];
767
793
  }
768
794
  if (Array.isArray(current)) {
769
795
  const size = current.length;
@@ -789,7 +815,7 @@ export async function generateTreeAsync(
789
815
  if (current instanceof AggregateError) {
790
816
  const options = getErrorOptions(current);
791
817
  const optionsNode = options
792
- ? await serializeProperties(options)
818
+ ? await serializePropertiesAsync(ctx, options)
793
819
  : undefined;
794
820
  const errorsNode = await generateTreeAsync(ctx, current.errors as ServerValue);
795
821
  return [SerovalNodeType.AggregateError, [current.message, optionsNode, errorsNode], id];
@@ -797,7 +823,7 @@ export async function generateTreeAsync(
797
823
  if (current instanceof Error) {
798
824
  const options = getErrorOptions(current);
799
825
  const optionsNode = options
800
- ? await serializeProperties(options)
826
+ ? await serializePropertiesAsync(ctx, options)
801
827
  : undefined;
802
828
  return [
803
829
  SerovalNodeType.Error,
@@ -810,7 +836,7 @@ export async function generateTreeAsync(
810
836
  const options = getIterableOptions(current);
811
837
  return [SerovalNodeType.Iterable, [
812
838
  options
813
- ? await serializeProperties(options)
839
+ ? await serializePropertiesAsync(ctx, options)
814
840
  : undefined,
815
841
  await generateTreeAsync(ctx, Array.from(current)),
816
842
  ], id];
@@ -819,7 +845,7 @@ export async function generateTreeAsync(
819
845
  if (current.constructor === Object || empty) {
820
846
  return [
821
847
  empty ? SerovalNodeType.NullConstructor : SerovalNodeType.Object,
822
- await serializeProperties(current as Record<string, unknown>),
848
+ await serializePropertiesAsync(ctx, current as Record<string, unknown>),
823
849
  id,
824
850
  ];
825
851
  }
@@ -863,80 +889,80 @@ export function serializePrimitive(
863
889
  return String(value);
864
890
  }
865
891
 
866
- export function serializeTree(
892
+ const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
893
+
894
+ function serializeAssignments(
867
895
  ctx: SerializationContext,
868
- [type, value, id]: SerovalNode,
869
- ): string {
870
- function serializeAssignments(
871
- targetRef: number,
872
- [keys, values, size]: SerovalDictionaryNode,
873
- ) {
874
- ctx.stack.push(targetRef);
875
- const mainAssignments: Assignment[] = [];
876
- for (let i = 0; i < size; i++) {
877
- const parentStack = ctx.stack;
878
- ctx.stack = [];
879
- const refParam = serializeTree(ctx, values[i]);
880
- ctx.stack = parentStack;
881
- const key = keys[i];
882
- const check = Number(key);
883
- // Test if key is a valid number or JS identifier
884
- // so that we don't have to serialize the key and wrap with brackets
885
- const parentAssignment = ctx.assignments;
886
- ctx.assignments = mainAssignments;
887
- if (
888
- check >= 0
889
- || (Number.isNaN(check) && /^([$A-Z_][0-9A-Z_$]*)$/i.test(key))
890
- ) {
891
- if (!Number.isNaN(check)) {
892
- createObjectComputedAssign(ctx, targetRef, key, refParam);
893
- } else {
894
- createObjectIdentifierAssign(ctx, targetRef, key, refParam);
895
- }
896
+ targetRef: number,
897
+ [keys, values, size]: SerovalDictionaryNode,
898
+ ) {
899
+ ctx.stack.push(targetRef);
900
+ const mainAssignments: Assignment[] = [];
901
+ for (let i = 0; i < size; i++) {
902
+ const parentStack = ctx.stack;
903
+ ctx.stack = [];
904
+ const refParam = serializeTree(ctx, values[i]);
905
+ ctx.stack = parentStack;
906
+ const key = keys[i];
907
+ const check = Number(key);
908
+ const parentAssignment = ctx.assignments;
909
+ ctx.assignments = mainAssignments;
910
+ // Test if key is a valid number or JS identifier
911
+ // so that we don't have to serialize the key and wrap with brackets
912
+ if (IDENTIFIER_CHECK.test(key) || check >= 0) {
913
+ if (!Number.isNaN(check)) {
914
+ createObjectComputedAssign(ctx, targetRef, key, refParam);
896
915
  } else {
897
- createObjectComputedAssign(ctx, targetRef, quote(key), refParam);
916
+ createObjectIdentifierAssign(ctx, targetRef, key, refParam);
898
917
  }
899
- ctx.assignments = parentAssignment;
918
+ } else {
919
+ createObjectComputedAssign(ctx, targetRef, quote(key), refParam);
900
920
  }
901
- ctx.stack.pop();
902
- return resolveAssignments(mainAssignments);
921
+ ctx.assignments = parentAssignment;
903
922
  }
904
- function serializeObject(
905
- sourceID: number,
906
- [keys, values, size]: SerovalDictionaryNode,
907
- ) {
908
- let result = '';
909
- ctx.stack.push(sourceID);
910
- for (let i = 0; i < size; i++) {
911
- const key = keys[i];
912
- const val = values[i];
913
- const check = Number(key);
914
- // Test if key is a valid number or JS identifier
915
- // so that we don't have to serialize the key and wrap with brackets
916
- if (
917
- check >= 0
918
- || (Number.isNaN(check) && /^([$A-Z_][0-9A-Z_$]*)$/i.test(key))
919
- ) {
920
- if (isReferenceInStack(ctx, val)) {
921
- const refParam = getRefParam(ctx, val[1]);
922
- if (!Number.isNaN(check)) {
923
- createObjectComputedAssign(ctx, sourceID, key, refParam);
924
- } else {
925
- createObjectIdentifierAssign(ctx, sourceID, key, refParam);
926
- }
923
+ ctx.stack.pop();
924
+ return resolveAssignments(mainAssignments);
925
+ }
926
+
927
+ function serializeObject(
928
+ ctx: SerializationContext,
929
+ sourceID: number,
930
+ [keys, values, size]: SerovalDictionaryNode,
931
+ ) {
932
+ let result = '';
933
+ ctx.stack.push(sourceID);
934
+ for (let i = 0; i < size; i++) {
935
+ const key = keys[i];
936
+ const val = values[i];
937
+ const check = Number(key);
938
+ // Test if key is a valid number or JS identifier
939
+ // so that we don't have to serialize the key and wrap with brackets
940
+ const isIdentifier = IDENTIFIER_CHECK.test(key) || check >= 0;
941
+ if (isReferenceInStack(ctx, val)) {
942
+ const refParam = getRefParam(ctx, val[1]);
943
+ if (isIdentifier) {
944
+ if (!Number.isNaN(check)) {
945
+ createObjectComputedAssign(ctx, sourceID, key, refParam);
927
946
  } else {
928
- result += `${key}:${serializeTree(ctx, val)},`;
947
+ createObjectIdentifierAssign(ctx, sourceID, key, refParam);
929
948
  }
930
- } else if (isReferenceInStack(ctx, val)) {
931
- const refParam = getRefParam(ctx, val[1]);
932
- createObjectComputedAssign(ctx, sourceID, quote(key), refParam);
933
949
  } else {
934
- result += `${quote(key)}:${serializeTree(ctx, val)},`;
950
+ createObjectComputedAssign(ctx, sourceID, quote(key), refParam);
935
951
  }
952
+ } else if (isIdentifier) {
953
+ result += `${key}:${serializeTree(ctx, val)},`;
954
+ } else {
955
+ result += `${quote(key)}:${serializeTree(ctx, val)},`;
936
956
  }
937
- ctx.stack.pop();
938
- return `{${result.substring(0, result.length - 1)}}`;
939
957
  }
958
+ ctx.stack.pop();
959
+ return `{${result.substring(0, result.length - 1)}}`;
960
+ }
961
+
962
+ export function serializeTree(
963
+ ctx: SerializationContext,
964
+ [type, value, id]: SerovalNode,
965
+ ): string {
940
966
  switch (type) {
941
967
  case SerovalNodeType.Primitive:
942
968
  return serializePrimitive(ctx, value);
@@ -1090,11 +1116,11 @@ export function serializeTree(
1090
1116
  // Make sure to assign extra properties
1091
1117
  if (value[1]) {
1092
1118
  if (ctx.features.has(Feature.ObjectAssign)) {
1093
- const options = serializeObject(id, value[1]);
1119
+ const options = serializeObject(ctx, id, value[1]);
1094
1120
  serialized = `Object.assign(${serialized},${options})`;
1095
1121
  } else {
1096
1122
  markRef(ctx, id);
1097
- const assignments = serializeAssignments(id, value[1]);
1123
+ const assignments = serializeAssignments(ctx, id, value[1]);
1098
1124
  if (assignments) {
1099
1125
  const ref = getRefParam(ctx, id);
1100
1126
  return `(${assignRef(ctx, id, serialized)},${assignments}${ref})`;
@@ -1107,11 +1133,11 @@ export function serializeTree(
1107
1133
  let serialized = `new ${value[0]}(${quote(value[1])})`;
1108
1134
  if (value[2]) {
1109
1135
  if (ctx.features.has(Feature.ObjectAssign)) {
1110
- const options = serializeObject(id, value[2]);
1136
+ const options = serializeObject(ctx, id, value[2]);
1111
1137
  serialized = `Object.assign(${serialized},${options})`;
1112
1138
  } else {
1113
1139
  markRef(ctx, id);
1114
- const assignments = serializeAssignments(id, value[2]);
1140
+ const assignments = serializeAssignments(ctx, id, value[2]);
1115
1141
  if (assignments) {
1116
1142
  const ref = getRefParam(ctx, id);
1117
1143
  return `(${assignRef(ctx, id, serialized)},${assignments}${ref})`;
@@ -1140,11 +1166,11 @@ export function serializeTree(
1140
1166
  }
1141
1167
  if (value[0]) {
1142
1168
  if (ctx.features.has(Feature.ObjectAssign)) {
1143
- const options = serializeObject(id, value[0]);
1169
+ const options = serializeObject(ctx, id, value[0]);
1144
1170
  serialized = `Object.assign(${serialized},${options})`;
1145
1171
  } else {
1146
1172
  markRef(ctx, id);
1147
- const assignments = serializeAssignments(id, value[0]);
1173
+ const assignments = serializeAssignments(ctx, id, value[0]);
1148
1174
  if (assignments) {
1149
1175
  const ref = getRefParam(ctx, id);
1150
1176
  return `(${assignRef(ctx, id, serialized)},${assignments}${ref})`;
@@ -1156,13 +1182,13 @@ export function serializeTree(
1156
1182
  case SerovalNodeType.NullConstructor: {
1157
1183
  let serialized = 'Object.create(null)';
1158
1184
  if (ctx.features.has(Feature.ObjectAssign)) {
1159
- const fields = serializeObject(id, value);
1185
+ const fields = serializeObject(ctx, id, value);
1160
1186
  if (fields !== '{}') {
1161
1187
  serialized = `Object.assign(${serialized},${fields})`;
1162
1188
  }
1163
1189
  } else {
1164
1190
  markRef(ctx, id);
1165
- const assignments = serializeAssignments(id, value);
1191
+ const assignments = serializeAssignments(ctx, id, value);
1166
1192
  if (assignments) {
1167
1193
  const ref = getRefParam(ctx, id);
1168
1194
  return `(${assignRef(ctx, id, serialized)},${assignments}${ref})`;
@@ -1171,7 +1197,7 @@ export function serializeTree(
1171
1197
  return assignRef(ctx, id, serialized);
1172
1198
  }
1173
1199
  case SerovalNodeType.Object:
1174
- return assignRef(ctx, id, serializeObject(id, value));
1200
+ return assignRef(ctx, id, serializeObject(ctx, id, value));
1175
1201
  default:
1176
1202
  throw new Error('Unsupported type');
1177
1203
  }