seroval 1.0.0 → 1.0.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 +63 -67
- package/dist/cjs/development/index.cjs.map +2 -2
- package/dist/cjs/production/index.cjs +3 -3
- package/dist/esm/development/index.mjs +63 -67
- package/dist/esm/development/index.mjs.map +2 -2
- package/dist/esm/production/index.mjs +3 -3
- package/dist/types/core/context/parser/stream.d.ts.map +1 -1
- package/dist/types/core/context/parser/sync.d.ts.map +1 -1
- package/dist/types/core/context/parser.d.ts +10 -4
- package/dist/types/core/context/parser.d.ts.map +1 -1
- package/dist/types/core/context/serializer.d.ts +10 -5
- package/dist/types/core/context/serializer.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/context/parser/stream.ts +1 -14
- package/src/core/context/parser/sync.ts +1 -15
- package/src/core/context/parser.ts +38 -12
- package/src/core/context/serializer.ts +71 -55
|
@@ -48,29 +48,36 @@ import type {
|
|
|
48
48
|
} from '../types';
|
|
49
49
|
import { isValidIdentifier } from '../utils/is-valid-identifier';
|
|
50
50
|
|
|
51
|
+
const enum AssignmentType {
|
|
52
|
+
Index = 0,
|
|
53
|
+
Add = 1,
|
|
54
|
+
Set = 2,
|
|
55
|
+
Delete = 3,
|
|
56
|
+
}
|
|
57
|
+
|
|
51
58
|
interface IndexAssignment {
|
|
52
|
-
t:
|
|
59
|
+
t: AssignmentType.Index;
|
|
53
60
|
s: string;
|
|
54
61
|
k: undefined;
|
|
55
62
|
v: string;
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
interface SetAssignment {
|
|
59
|
-
t:
|
|
66
|
+
t: AssignmentType.Set;
|
|
60
67
|
s: string;
|
|
61
68
|
k: string;
|
|
62
69
|
v: string;
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
interface AddAssignment {
|
|
66
|
-
t:
|
|
73
|
+
t: AssignmentType.Add;
|
|
67
74
|
s: string;
|
|
68
75
|
k: undefined;
|
|
69
76
|
v: string;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
interface DeleteAssignment {
|
|
73
|
-
t:
|
|
80
|
+
t: AssignmentType.Delete;
|
|
74
81
|
s: string;
|
|
75
82
|
k: string;
|
|
76
83
|
v: undefined;
|
|
@@ -90,16 +97,14 @@ export interface FlaggedObject {
|
|
|
90
97
|
|
|
91
98
|
function getAssignmentExpression(assignment: Assignment): string {
|
|
92
99
|
switch (assignment.t) {
|
|
93
|
-
case
|
|
100
|
+
case AssignmentType.Index:
|
|
94
101
|
return assignment.s + '=' + assignment.v;
|
|
95
|
-
case
|
|
102
|
+
case AssignmentType.Set:
|
|
96
103
|
return assignment.s + '.set(' + assignment.k + ',' + assignment.v + ')';
|
|
97
|
-
case
|
|
104
|
+
case AssignmentType.Add:
|
|
98
105
|
return assignment.s + '.add(' + assignment.v + ')';
|
|
99
|
-
case
|
|
106
|
+
case AssignmentType.Delete:
|
|
100
107
|
return assignment.s + '.delete(' + assignment.k + ')';
|
|
101
|
-
default:
|
|
102
|
-
return '';
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
110
|
|
|
@@ -112,35 +117,35 @@ function mergeAssignments(assignments: Assignment[]): Assignment[] {
|
|
|
112
117
|
i++
|
|
113
118
|
) {
|
|
114
119
|
item = assignments[i];
|
|
115
|
-
if (item.t ===
|
|
120
|
+
if (item.t === AssignmentType.Index && item.v === prev.v) {
|
|
116
121
|
// Merge if the right-hand value is the same
|
|
117
122
|
// saves at least 2 chars
|
|
118
123
|
current = {
|
|
119
|
-
t:
|
|
124
|
+
t: AssignmentType.Index,
|
|
120
125
|
s: item.s,
|
|
121
126
|
k: undefined,
|
|
122
127
|
v: getAssignmentExpression(current),
|
|
123
128
|
} as IndexAssignment;
|
|
124
|
-
} else if (item.t ===
|
|
129
|
+
} else if (item.t === AssignmentType.Set && item.s === prev.s) {
|
|
125
130
|
// Maps has chaining methods, merge if source is the same
|
|
126
131
|
current = {
|
|
127
|
-
t:
|
|
132
|
+
t: AssignmentType.Set,
|
|
128
133
|
s: getAssignmentExpression(current),
|
|
129
134
|
k: item.k,
|
|
130
135
|
v: item.v,
|
|
131
136
|
} as SetAssignment;
|
|
132
|
-
} else if (item.t ===
|
|
137
|
+
} else if (item.t === AssignmentType.Add && item.s === prev.s) {
|
|
133
138
|
// Sets has chaining methods too
|
|
134
139
|
current = {
|
|
135
|
-
t:
|
|
140
|
+
t: AssignmentType.Add,
|
|
136
141
|
s: getAssignmentExpression(current),
|
|
137
142
|
k: undefined,
|
|
138
143
|
v: item.v,
|
|
139
144
|
} as AddAssignment;
|
|
140
|
-
} else if (item.t ===
|
|
145
|
+
} else if (item.t === AssignmentType.Delete && item.s === prev.s) {
|
|
141
146
|
// Maps has chaining methods, merge if source is the same
|
|
142
147
|
current = {
|
|
143
|
-
t:
|
|
148
|
+
t: AssignmentType.Delete,
|
|
144
149
|
s: getAssignmentExpression(current),
|
|
145
150
|
k: item.k,
|
|
146
151
|
v: undefined,
|
|
@@ -319,7 +324,7 @@ export default abstract class BaseSerializerContext
|
|
|
319
324
|
*/
|
|
320
325
|
protected createAssignment(source: string, value: string): void {
|
|
321
326
|
this.assignments.push({
|
|
322
|
-
t:
|
|
327
|
+
t: AssignmentType.Index,
|
|
323
328
|
s: source,
|
|
324
329
|
k: undefined,
|
|
325
330
|
v: value,
|
|
@@ -328,7 +333,7 @@ export default abstract class BaseSerializerContext
|
|
|
328
333
|
|
|
329
334
|
protected createAddAssignment(ref: number, value: string): void {
|
|
330
335
|
this.assignments.push({
|
|
331
|
-
t:
|
|
336
|
+
t: AssignmentType.Add,
|
|
332
337
|
s: this.getRefParam(ref),
|
|
333
338
|
k: undefined,
|
|
334
339
|
v: value,
|
|
@@ -337,7 +342,7 @@ export default abstract class BaseSerializerContext
|
|
|
337
342
|
|
|
338
343
|
protected createSetAssignment(ref: number, key: string, value: string): void {
|
|
339
344
|
this.assignments.push({
|
|
340
|
-
t:
|
|
345
|
+
t: AssignmentType.Set,
|
|
341
346
|
s: this.getRefParam(ref),
|
|
342
347
|
k: key,
|
|
343
348
|
v: value,
|
|
@@ -346,7 +351,7 @@ export default abstract class BaseSerializerContext
|
|
|
346
351
|
|
|
347
352
|
protected createDeleteAssignment(ref: number, key: string): void {
|
|
348
353
|
this.assignments.push({
|
|
349
|
-
t:
|
|
354
|
+
t: AssignmentType.Delete,
|
|
350
355
|
s: this.getRefParam(ref),
|
|
351
356
|
k: key,
|
|
352
357
|
v: undefined,
|
|
@@ -416,11 +421,11 @@ export default abstract class BaseSerializerContext
|
|
|
416
421
|
const id = node.i;
|
|
417
422
|
if (node.l) {
|
|
418
423
|
this.stack.push(id);
|
|
424
|
+
const list = node.a;
|
|
425
|
+
let values = this.serializeArrayItem(id, list[0], 0);
|
|
419
426
|
// This is different than Map and Set
|
|
420
427
|
// because we also need to serialize
|
|
421
428
|
// the holes of the Array
|
|
422
|
-
const list = node.a;
|
|
423
|
-
let values = this.serializeArrayItem(id, list[0], 0);
|
|
424
429
|
let isHoley = values === '';
|
|
425
430
|
for (let i = 1, len = node.l, item: string; i < len; i++) {
|
|
426
431
|
item = this.serializeArrayItem(id, list[i], i);
|
|
@@ -441,12 +446,24 @@ export default abstract class BaseSerializerContext
|
|
|
441
446
|
): string {
|
|
442
447
|
if (typeof key === 'string') {
|
|
443
448
|
const check = Number(key);
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
449
|
+
const isIdentifier = (
|
|
450
|
+
// Test if key is a valid positive number or JS identifier
|
|
451
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
452
|
+
check >= 0
|
|
453
|
+
// It's also important to consider that if the key is
|
|
454
|
+
// indeed numeric, we need to make sure that when
|
|
455
|
+
// converted back into a string, it's still the same
|
|
456
|
+
// to the original key. This allows us to differentiate
|
|
457
|
+
// keys that has numeric formats but in a different
|
|
458
|
+
// format, which can cause unintentional key declaration
|
|
459
|
+
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
460
|
+
&& check.toString() === key
|
|
461
|
+
) || isValidIdentifier(key);
|
|
447
462
|
if (this.isIndexedValueInStack(val)) {
|
|
448
463
|
const refParam = this.getRefParam((val as SerovalIndexedValueNode).i);
|
|
449
464
|
this.markRef(source.i);
|
|
465
|
+
// Strict identifier check, make sure
|
|
466
|
+
// that it isn't numeric (except NaN)
|
|
450
467
|
if (isIdentifier && check !== check) {
|
|
451
468
|
this.createObjectAssign(source.i, key, refParam);
|
|
452
469
|
} else {
|
|
@@ -469,9 +486,9 @@ export default abstract class BaseSerializerContext
|
|
|
469
486
|
): string {
|
|
470
487
|
const len = record.s;
|
|
471
488
|
if (len) {
|
|
472
|
-
this.stack.push(source.i);
|
|
473
489
|
const keys = record.k;
|
|
474
490
|
const values = record.v;
|
|
491
|
+
this.stack.push(source.i);
|
|
475
492
|
let result = this.serializeProperty(source, keys[0], values[0]);
|
|
476
493
|
for (let i = 1, item = result; i < len; i++) {
|
|
477
494
|
item = this.serializeProperty(source, keys[i], values[i]);
|
|
@@ -511,10 +528,22 @@ export default abstract class BaseSerializerContext
|
|
|
511
528
|
): void {
|
|
512
529
|
const serialized = this.serialize(value);
|
|
513
530
|
const check = Number(key);
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
531
|
+
const isIdentifier = (
|
|
532
|
+
// Test if key is a valid positive number or JS identifier
|
|
533
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
534
|
+
check >= 0
|
|
535
|
+
// It's also important to consider that if the key is
|
|
536
|
+
// indeed numeric, we need to make sure that when
|
|
537
|
+
// converted back into a string, it's still the same
|
|
538
|
+
// to the original key. This allows us to differentiate
|
|
539
|
+
// keys that has numeric formats but in a different
|
|
540
|
+
// format, which can cause unintentional key declaration
|
|
541
|
+
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
542
|
+
&& check.toString() === key
|
|
543
|
+
) || isValidIdentifier(key);
|
|
517
544
|
if (this.isIndexedValueInStack(value)) {
|
|
545
|
+
// Strict identifier check, make sure
|
|
546
|
+
// that it isn't numeric (except NaN)
|
|
518
547
|
if (isIdentifier && check !== check) {
|
|
519
548
|
this.createObjectAssign(source.i, key, serialized);
|
|
520
549
|
} else {
|
|
@@ -527,7 +556,7 @@ export default abstract class BaseSerializerContext
|
|
|
527
556
|
} else {
|
|
528
557
|
const parentAssignment = this.assignments;
|
|
529
558
|
this.assignments = mainAssignments;
|
|
530
|
-
if (isIdentifier) {
|
|
559
|
+
if (isIdentifier && check !== check) {
|
|
531
560
|
this.createObjectAssign(source.i, key, serialized);
|
|
532
561
|
} else {
|
|
533
562
|
this.createArrayAssign(
|
|
@@ -566,10 +595,10 @@ export default abstract class BaseSerializerContext
|
|
|
566
595
|
): string | undefined {
|
|
567
596
|
const len = node.s;
|
|
568
597
|
if (len) {
|
|
569
|
-
this.stack.push(source.i);
|
|
570
598
|
const mainAssignments: Assignment[] = [];
|
|
571
599
|
const keys = node.k;
|
|
572
600
|
const values = node.v;
|
|
601
|
+
this.stack.push(source.i);
|
|
573
602
|
for (let i = 0; i < len; i++) {
|
|
574
603
|
this.serializeAssignment(source, mainAssignments, keys[i], values[i]);
|
|
575
604
|
}
|
|
@@ -795,15 +824,17 @@ export default abstract class BaseSerializerContext
|
|
|
795
824
|
}
|
|
796
825
|
|
|
797
826
|
protected serializeAggregateError(node: SerovalAggregateErrorNode): string {
|
|
798
|
-
// Serialize the required arguments
|
|
799
827
|
const id = node.i;
|
|
800
|
-
this.stack.push(id);
|
|
801
|
-
const serialized = 'new AggregateError([],"' + node.m + '")';
|
|
802
|
-
this.stack.pop();
|
|
803
828
|
// `AggregateError` might've been extended
|
|
804
829
|
// either through class or custom properties
|
|
805
830
|
// Make sure to assign extra properties
|
|
806
|
-
|
|
831
|
+
this.stack.push(id);
|
|
832
|
+
const serialized = this.serializeDictionary(
|
|
833
|
+
node,
|
|
834
|
+
'new AggregateError([],"' + node.m + '")',
|
|
835
|
+
);
|
|
836
|
+
this.stack.pop();
|
|
837
|
+
return serialized;
|
|
807
838
|
}
|
|
808
839
|
|
|
809
840
|
protected serializeError(node: SerovalErrorNode): string {
|
|
@@ -846,21 +877,6 @@ export default abstract class BaseSerializerContext
|
|
|
846
877
|
return this.assignIndexedValue(node.i, SYMBOL_STRING[node.s]);
|
|
847
878
|
}
|
|
848
879
|
|
|
849
|
-
protected serializeFormDataEntry(
|
|
850
|
-
id: number,
|
|
851
|
-
key: string,
|
|
852
|
-
value: SerovalNode,
|
|
853
|
-
): string {
|
|
854
|
-
return (
|
|
855
|
-
this.getRefParam(id) +
|
|
856
|
-
'.append("' +
|
|
857
|
-
key +
|
|
858
|
-
'",' +
|
|
859
|
-
this.serialize(value) +
|
|
860
|
-
')'
|
|
861
|
-
);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
880
|
protected serializeBoxed(node: SerovalBoxedNode): string {
|
|
865
881
|
return this.assignIndexedValue(
|
|
866
882
|
node.i,
|
|
@@ -943,10 +959,10 @@ export default abstract class BaseSerializerContext
|
|
|
943
959
|
case SpecialReference.StreamConstructor:
|
|
944
960
|
return this.createFunction(
|
|
945
961
|
['b', 'a', 's', 'l', 'p', 'f', 'e', 'n'],
|
|
946
|
-
'(b=[],a=!0,s=!1,l=[],
|
|
962
|
+
'(b=[],a=!0,s=!1,l=[],p=0,f=' +
|
|
947
963
|
this.createEffectfulFunction(
|
|
948
964
|
['v', 'm', 'x'],
|
|
949
|
-
'for(x=0;x<
|
|
965
|
+
'for(x=0;x<p;x++)l[x]&&l[x][m](v)',
|
|
950
966
|
) +
|
|
951
967
|
',n=' +
|
|
952
968
|
this.createEffectfulFunction(
|