seroval 1.0.2 → 1.0.4
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 +339 -226
- package/dist/cjs/development/index.cjs.map +3 -3
- package/dist/cjs/production/index.cjs +17 -3
- package/dist/esm/development/index.mjs +339 -226
- package/dist/esm/development/index.mjs.map +3 -3
- package/dist/esm/production/index.mjs +17 -3
- package/dist/types/core/base-primitives.d.ts.map +1 -1
- package/dist/types/core/context/deserializer.d.ts.map +1 -1
- package/dist/types/core/context/parser/async.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.map +1 -1
- package/dist/types/core/context/serializer.d.ts.map +1 -1
- package/dist/types/core/errors.d.ts +38 -0
- package/dist/types/core/errors.d.ts.map +1 -0
- package/dist/types/core/reference.d.ts.map +1 -1
- package/dist/types/core/tree/serializer.d.ts.map +1 -1
- package/dist/types/core/utils/typed-array.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/base-primitives.ts +0 -5
- package/src/core/context/deserializer.ts +86 -76
- package/src/core/context/parser/async.ts +30 -26
- package/src/core/context/parser/sync.ts +30 -26
- package/src/core/context/parser.ts +3 -10
- package/src/core/context/serializer.ts +113 -80
- package/src/core/errors.ts +99 -0
- package/src/core/reference.ts +6 -2
- package/src/core/tree/serializer.ts +4 -3
- package/src/core/utils/typed-array.ts +3 -1
- package/src/index.ts +1 -0
- package/dist/types/core/UnsupportedTypeError.d.ts +0 -5
- package/dist/types/core/UnsupportedTypeError.d.ts.map +0 -1
- package/src/core/UnsupportedTypeError.ts +0 -7
|
@@ -6,6 +6,11 @@ import {
|
|
|
6
6
|
SerovalNodeType,
|
|
7
7
|
SerovalObjectFlags,
|
|
8
8
|
} from '../constants';
|
|
9
|
+
import {
|
|
10
|
+
SerovalMissingPluginError,
|
|
11
|
+
SerovalSerializationError,
|
|
12
|
+
SerovalUnsupportedNodeError,
|
|
13
|
+
} from '../errors';
|
|
9
14
|
import { REFERENCES_KEY } from '../keys';
|
|
10
15
|
import type { Plugin, PluginAccessOptions, SerovalMode } from '../plugin';
|
|
11
16
|
import { SpecialReference } from '../special-reference';
|
|
@@ -446,12 +451,24 @@ export default abstract class BaseSerializerContext
|
|
|
446
451
|
): string {
|
|
447
452
|
if (typeof key === 'string') {
|
|
448
453
|
const check = Number(key);
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
454
|
+
const isIdentifier =
|
|
455
|
+
// Test if key is a valid positive number or JS identifier
|
|
456
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
457
|
+
(check >= 0 &&
|
|
458
|
+
// It's also important to consider that if the key is
|
|
459
|
+
// indeed numeric, we need to make sure that when
|
|
460
|
+
// converted back into a string, it's still the same
|
|
461
|
+
// to the original key. This allows us to differentiate
|
|
462
|
+
// keys that has numeric formats but in a different
|
|
463
|
+
// format, which can cause unintentional key declaration
|
|
464
|
+
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
465
|
+
check.toString() === key) ||
|
|
466
|
+
isValidIdentifier(key);
|
|
452
467
|
if (this.isIndexedValueInStack(val)) {
|
|
453
468
|
const refParam = this.getRefParam((val as SerovalIndexedValueNode).i);
|
|
454
469
|
this.markRef(source.i);
|
|
470
|
+
// Strict identifier check, make sure
|
|
471
|
+
// that it isn't numeric (except NaN)
|
|
455
472
|
if (isIdentifier && check !== check) {
|
|
456
473
|
this.createObjectAssign(source.i, key, refParam);
|
|
457
474
|
} else {
|
|
@@ -516,10 +533,22 @@ export default abstract class BaseSerializerContext
|
|
|
516
533
|
): void {
|
|
517
534
|
const serialized = this.serialize(value);
|
|
518
535
|
const check = Number(key);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
536
|
+
const isIdentifier =
|
|
537
|
+
// Test if key is a valid positive number or JS identifier
|
|
538
|
+
// so that we don't have to serialize the key and wrap with brackets
|
|
539
|
+
(check >= 0 &&
|
|
540
|
+
// It's also important to consider that if the key is
|
|
541
|
+
// indeed numeric, we need to make sure that when
|
|
542
|
+
// converted back into a string, it's still the same
|
|
543
|
+
// to the original key. This allows us to differentiate
|
|
544
|
+
// keys that has numeric formats but in a different
|
|
545
|
+
// format, which can cause unintentional key declaration
|
|
546
|
+
// Example: { 0x1: 1 } vs { '0x1': 1 }
|
|
547
|
+
check.toString() === key) ||
|
|
548
|
+
isValidIdentifier(key);
|
|
522
549
|
if (this.isIndexedValueInStack(value)) {
|
|
550
|
+
// Strict identifier check, make sure
|
|
551
|
+
// that it isn't numeric (except NaN)
|
|
523
552
|
if (isIdentifier && check !== check) {
|
|
524
553
|
this.createObjectAssign(source.i, key, serialized);
|
|
525
554
|
} else {
|
|
@@ -532,7 +561,7 @@ export default abstract class BaseSerializerContext
|
|
|
532
561
|
} else {
|
|
533
562
|
const parentAssignment = this.assignments;
|
|
534
563
|
this.assignments = mainAssignments;
|
|
535
|
-
if (isIdentifier) {
|
|
564
|
+
if (isIdentifier && check !== check) {
|
|
536
565
|
this.createObjectAssign(source.i, key, serialized);
|
|
537
566
|
} else {
|
|
538
567
|
this.createArrayAssign(
|
|
@@ -875,7 +904,7 @@ export default abstract class BaseSerializerContext
|
|
|
875
904
|
}
|
|
876
905
|
}
|
|
877
906
|
}
|
|
878
|
-
throw new
|
|
907
|
+
throw new SerovalMissingPluginError(node.c);
|
|
879
908
|
}
|
|
880
909
|
|
|
881
910
|
private getConstructor(node: SerovalNodeWithID): string {
|
|
@@ -1131,78 +1160,82 @@ export default abstract class BaseSerializerContext
|
|
|
1131
1160
|
}
|
|
1132
1161
|
|
|
1133
1162
|
serialize(node: SerovalNode): string {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1163
|
+
try {
|
|
1164
|
+
switch (node.t) {
|
|
1165
|
+
case SerovalNodeType.Constant:
|
|
1166
|
+
return CONSTANT_STRING[node.s];
|
|
1167
|
+
case SerovalNodeType.Number:
|
|
1168
|
+
return '' + node.s;
|
|
1169
|
+
case SerovalNodeType.String:
|
|
1170
|
+
return '"' + node.s + '"';
|
|
1171
|
+
case SerovalNodeType.BigInt:
|
|
1172
|
+
return node.s + 'n';
|
|
1173
|
+
case SerovalNodeType.IndexedValue:
|
|
1174
|
+
return this.getRefParam(node.i);
|
|
1175
|
+
case SerovalNodeType.Reference:
|
|
1176
|
+
return this.serializeReference(node);
|
|
1177
|
+
case SerovalNodeType.Array:
|
|
1178
|
+
return this.serializeArray(node);
|
|
1179
|
+
case SerovalNodeType.Object:
|
|
1180
|
+
return this.serializeObject(node);
|
|
1181
|
+
case SerovalNodeType.NullConstructor:
|
|
1182
|
+
return this.serializeNullConstructor(node);
|
|
1183
|
+
case SerovalNodeType.Date:
|
|
1184
|
+
return this.serializeDate(node);
|
|
1185
|
+
case SerovalNodeType.RegExp:
|
|
1186
|
+
return this.serializeRegExp(node);
|
|
1187
|
+
case SerovalNodeType.Set:
|
|
1188
|
+
return this.serializeSet(node);
|
|
1189
|
+
case SerovalNodeType.Map:
|
|
1190
|
+
return this.serializeMap(node);
|
|
1191
|
+
case SerovalNodeType.ArrayBuffer:
|
|
1192
|
+
return this.serializeArrayBuffer(node);
|
|
1193
|
+
case SerovalNodeType.BigIntTypedArray:
|
|
1194
|
+
case SerovalNodeType.TypedArray:
|
|
1195
|
+
return this.serializeTypedArray(node);
|
|
1196
|
+
case SerovalNodeType.DataView:
|
|
1197
|
+
return this.serializeDataView(node);
|
|
1198
|
+
case SerovalNodeType.AggregateError:
|
|
1199
|
+
return this.serializeAggregateError(node);
|
|
1200
|
+
case SerovalNodeType.Error:
|
|
1201
|
+
return this.serializeError(node);
|
|
1202
|
+
case SerovalNodeType.Promise:
|
|
1203
|
+
return this.serializePromise(node);
|
|
1204
|
+
case SerovalNodeType.WKSymbol:
|
|
1205
|
+
return this.serializeWellKnownSymbol(node);
|
|
1206
|
+
case SerovalNodeType.Boxed:
|
|
1207
|
+
return this.serializeBoxed(node);
|
|
1208
|
+
case SerovalNodeType.PromiseConstructor:
|
|
1209
|
+
return this.serializePromiseConstructor(node);
|
|
1210
|
+
case SerovalNodeType.PromiseResolve:
|
|
1211
|
+
return this.serializePromiseResolve(node);
|
|
1212
|
+
case SerovalNodeType.PromiseReject:
|
|
1213
|
+
return this.serializePromiseReject(node);
|
|
1214
|
+
case SerovalNodeType.Plugin:
|
|
1215
|
+
return this.serializePlugin(node);
|
|
1216
|
+
case SerovalNodeType.SpecialReference:
|
|
1217
|
+
return this.serializeSpecialReference(node);
|
|
1218
|
+
case SerovalNodeType.IteratorFactory:
|
|
1219
|
+
return this.serializeIteratorFactory(node);
|
|
1220
|
+
case SerovalNodeType.IteratorFactoryInstance:
|
|
1221
|
+
return this.serializeIteratorFactoryInstance(node);
|
|
1222
|
+
case SerovalNodeType.AsyncIteratorFactory:
|
|
1223
|
+
return this.serializeAsyncIteratorFactory(node);
|
|
1224
|
+
case SerovalNodeType.AsyncIteratorFactoryInstance:
|
|
1225
|
+
return this.serializeAsyncIteratorFactoryInstance(node);
|
|
1226
|
+
case SerovalNodeType.StreamConstructor:
|
|
1227
|
+
return this.serializeStreamConstructor(node);
|
|
1228
|
+
case SerovalNodeType.StreamNext:
|
|
1229
|
+
return this.serializeStreamNext(node);
|
|
1230
|
+
case SerovalNodeType.StreamThrow:
|
|
1231
|
+
return this.serializeStreamThrow(node);
|
|
1232
|
+
case SerovalNodeType.StreamReturn:
|
|
1233
|
+
return this.serializeStreamReturn(node);
|
|
1234
|
+
default:
|
|
1235
|
+
throw new SerovalUnsupportedNodeError(node);
|
|
1236
|
+
}
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
throw new SerovalSerializationError(error);
|
|
1206
1239
|
}
|
|
1207
1240
|
}
|
|
1208
1241
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { serializeString } from './string';
|
|
2
|
+
import { SerovalNode } from './types';
|
|
3
|
+
|
|
4
|
+
const { toString: objectToString } = /* @__PURE__ */ Object.prototype;
|
|
5
|
+
|
|
6
|
+
function getErrorMessage(type: string, cause: any): string {
|
|
7
|
+
if (cause instanceof Error) {
|
|
8
|
+
return `Seroval caught an error during the ${type} process.
|
|
9
|
+
|
|
10
|
+
${cause.name}
|
|
11
|
+
${cause.message}
|
|
12
|
+
|
|
13
|
+
- For more information, please check the "cause" property of this error.
|
|
14
|
+
- If you believe this is an error in Seroval, please submit an issue at https://github.com/lxsmnsyc/seroval/issues/new`;
|
|
15
|
+
}
|
|
16
|
+
return `Seroval caught an error during the ${type} process.
|
|
17
|
+
|
|
18
|
+
"${objectToString.call(cause)}"
|
|
19
|
+
|
|
20
|
+
For more information, please check the "cause" property of this error.`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class SerovalError extends Error {
|
|
24
|
+
constructor(type: string, public cause: any) {
|
|
25
|
+
super(getErrorMessage(type, cause));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class SerovalParserError extends SerovalError {
|
|
30
|
+
constructor(cause: any) {
|
|
31
|
+
super('parsing', cause);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class SerovalSerializationError extends SerovalError {
|
|
36
|
+
constructor(cause: any) {
|
|
37
|
+
super('serialization', cause);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class SerovalDeserializationError extends SerovalError {
|
|
42
|
+
constructor(cause: any) {
|
|
43
|
+
super('deserialization', cause);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class SerovalUnsupportedTypeError extends Error {
|
|
48
|
+
constructor(public value: unknown) {
|
|
49
|
+
super(
|
|
50
|
+
`The value ${objectToString.call(value)} of type "${typeof value}" cannot be parsed/serialized.
|
|
51
|
+
|
|
52
|
+
There are few workarounds for this problem:
|
|
53
|
+
- Transform the value in a way that it can be serialized.
|
|
54
|
+
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class SerovalUnsupportedNodeError extends Error {
|
|
60
|
+
constructor(node: SerovalNode) {
|
|
61
|
+
super('Unsupported node type "' + node.t + '".');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class SerovalMissingPluginError extends Error {
|
|
66
|
+
constructor(tag: string) {
|
|
67
|
+
super('Missing plugin for tag "' + tag + '".');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export class SerovalMissingInstanceError extends Error {
|
|
72
|
+
constructor(tag: string) {
|
|
73
|
+
super('Missing "' + tag + '" instance.');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export class SerovalMissingReferenceError extends Error {
|
|
78
|
+
constructor(public value: unknown) {
|
|
79
|
+
super(
|
|
80
|
+
'Missing reference for the value "' +
|
|
81
|
+
objectToString.call(value) +
|
|
82
|
+
'" of type "' +
|
|
83
|
+
typeof value +
|
|
84
|
+
'"',
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class SerovalMissingReferenceForIdError extends Error {
|
|
90
|
+
constructor(id: string) {
|
|
91
|
+
super('Missing reference for id "' + serializeString(id) + '"');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class SerovalUnknownTypedArrayError extends Error {
|
|
96
|
+
constructor(name: string) {
|
|
97
|
+
super('Unknown TypedArray "' + name + '"');
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/core/reference.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import assert from './utils/assert';
|
|
2
2
|
import { REFERENCES_KEY } from './keys';
|
|
3
|
+
import {
|
|
4
|
+
SerovalMissingReferenceError,
|
|
5
|
+
SerovalMissingReferenceForIdError,
|
|
6
|
+
} from '..';
|
|
3
7
|
|
|
4
8
|
const REFERENCE = new Map<unknown, string>();
|
|
5
9
|
const INV_REFERENCE = new Map<string, unknown>();
|
|
@@ -19,12 +23,12 @@ export function hasReference(id: string): boolean {
|
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export function getReferenceID<T>(value: T): string {
|
|
22
|
-
assert(hasReferenceID(value), new
|
|
26
|
+
assert(hasReferenceID(value), new SerovalMissingReferenceError(value));
|
|
23
27
|
return REFERENCE.get(value)!;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
export function getReference<T>(id: string): T {
|
|
27
|
-
assert(hasReference(id), new
|
|
31
|
+
assert(hasReference(id), new SerovalMissingReferenceForIdError(id));
|
|
28
32
|
return INV_REFERENCE.get(id) as T;
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -9,6 +9,7 @@ import BaseSerializerContext from '../context/serializer';
|
|
|
9
9
|
import getIdentifier from '../utils/get-identifier';
|
|
10
10
|
import type { SerovalMode } from '../plugin';
|
|
11
11
|
import { SerovalNodeType } from '../constants';
|
|
12
|
+
import { SerovalUnsupportedNodeError } from '../errors';
|
|
12
13
|
|
|
13
14
|
export type VanillaSerializerContextOptions = BaseSerializerContextOptions;
|
|
14
15
|
|
|
@@ -61,15 +62,15 @@ export default class VanillaSerializerContext extends BaseSerializerContext {
|
|
|
61
62
|
protected serializePromiseConstructor(
|
|
62
63
|
node: SerovalPromiseConstructorNode,
|
|
63
64
|
): string {
|
|
64
|
-
throw new
|
|
65
|
+
throw new SerovalUnsupportedNodeError(node);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
protected serializePromiseResolve(node: SerovalPromiseResolveNode): string {
|
|
68
|
-
throw new
|
|
69
|
+
throw new SerovalUnsupportedNodeError(node);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
protected serializePromiseReject(node: SerovalPromiseRejectNode): string {
|
|
72
|
-
throw new
|
|
73
|
+
throw new SerovalUnsupportedNodeError(node);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
serializeTop(tree: SerovalNode): string {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { SerovalUnknownTypedArrayError } from '../errors';
|
|
2
|
+
|
|
1
3
|
type TypedArrayConstructor =
|
|
2
4
|
| Int8ArrayConstructor
|
|
3
5
|
| Int16ArrayConstructor
|
|
@@ -49,6 +51,6 @@ export function getTypedArrayConstructor(name: string): TypedArrayConstructor {
|
|
|
49
51
|
case 'BigUint64Array':
|
|
50
52
|
return BigUint64Array;
|
|
51
53
|
default:
|
|
52
|
-
throw new
|
|
54
|
+
throw new SerovalUnknownTypedArrayError(name);
|
|
53
55
|
}
|
|
54
56
|
}
|
package/src/index.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UnsupportedTypeError.d.ts","sourceRoot":"","sources":["../../../src/core/UnsupportedTypeError.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,KAAK;IAClC,KAAK,EAAE,OAAO;gBAAd,KAAK,EAAE,OAAO;CAGlC"}
|