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/dist/cjs/development/index.cjs +159 -140
- package/dist/cjs/development/index.cjs.map +2 -2
- package/dist/cjs/production/index.cjs +2 -2
- package/dist/esm/development/index.mjs +159 -140
- package/dist/esm/development/index.mjs.map +2 -2
- package/dist/esm/production/index.mjs +2 -2
- package/package.json +2 -2
- package/src/tree.ts +190 -164
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
|
|
583
|
-
const
|
|
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
|
|
596
|
+
deferred[deferredSize++] = item;
|
|
588
597
|
} else {
|
|
589
|
-
nodes
|
|
598
|
+
nodes[nodeSize++] = generateTreeSync(ctx, item);
|
|
590
599
|
}
|
|
591
600
|
}
|
|
592
601
|
// Parse deferred items
|
|
593
|
-
for (let i = 0
|
|
594
|
-
nodes
|
|
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
|
|
601
|
-
const
|
|
602
|
-
const
|
|
603
|
-
const
|
|
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
|
|
609
|
-
deferredValue
|
|
619
|
+
deferredKey[deferredSize] = key;
|
|
620
|
+
deferredValue[deferredSize] = value;
|
|
610
621
|
deferredSize++;
|
|
611
622
|
} else {
|
|
612
|
-
keyNodes
|
|
613
|
-
valueNodes
|
|
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
|
|
618
|
-
valueNodes
|
|
629
|
+
keyNodes[nodeSize + i] = generateTreeSync(ctx, deferredKey[i]);
|
|
630
|
+
valueNodes[nodeSize + i] = generateTreeSync(ctx, deferredValue[i]);
|
|
619
631
|
}
|
|
620
|
-
return [SerovalNodeType.Map, [keyNodes, valueNodes,
|
|
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
|
-
?
|
|
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
|
-
?
|
|
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 ?
|
|
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
|
-
|
|
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
|
|
732
|
-
const
|
|
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
|
|
756
|
+
deferred[deferredSize++] = item;
|
|
736
757
|
} else {
|
|
737
|
-
nodes
|
|
758
|
+
nodes[nodeSize++] = await generateTreeAsync(ctx, item);
|
|
738
759
|
}
|
|
739
760
|
}
|
|
740
|
-
|
|
741
|
-
|
|
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
|
|
748
|
-
const
|
|
749
|
-
const
|
|
750
|
-
const
|
|
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
|
|
755
|
-
deferredValue
|
|
779
|
+
deferredKey[deferredSize] = key;
|
|
780
|
+
deferredValue[deferredSize] = value;
|
|
756
781
|
deferredSize++;
|
|
757
782
|
} else {
|
|
758
|
-
keyNodes
|
|
759
|
-
valueNodes
|
|
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
|
|
764
|
-
valueNodes
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
892
|
+
const IDENTIFIER_CHECK = /^([$A-Z_][0-9A-Z_$]*)$/i;
|
|
893
|
+
|
|
894
|
+
function serializeAssignments(
|
|
867
895
|
ctx: SerializationContext,
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
) {
|
|
874
|
-
ctx.stack
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
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
|
-
|
|
916
|
+
createObjectIdentifierAssign(ctx, targetRef, key, refParam);
|
|
898
917
|
}
|
|
899
|
-
|
|
918
|
+
} else {
|
|
919
|
+
createObjectComputedAssign(ctx, targetRef, quote(key), refParam);
|
|
900
920
|
}
|
|
901
|
-
ctx.
|
|
902
|
-
return resolveAssignments(mainAssignments);
|
|
921
|
+
ctx.assignments = parentAssignment;
|
|
903
922
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|