seroval 0.11.6 → 0.12.0

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 (122) hide show
  1. package/README.md +29 -16
  2. package/dist/cjs/development/index.cjs +3072 -4875
  3. package/dist/cjs/development/index.cjs.map +4 -4
  4. package/dist/cjs/production/index.cjs +3 -3
  5. package/dist/esm/development/index.mjs +3069 -4874
  6. package/dist/esm/development/index.mjs.map +4 -4
  7. package/dist/esm/production/index.mjs +3 -3
  8. package/dist/types/core/Serializer.d.ts +2 -0
  9. package/dist/types/core/Serializer.d.ts.map +1 -0
  10. package/dist/types/core/UnsupportedTypeError.d.ts +1 -0
  11. package/dist/types/core/UnsupportedTypeError.d.ts.map +1 -0
  12. package/dist/types/core/assert.d.ts +1 -0
  13. package/dist/types/core/assert.d.ts.map +1 -0
  14. package/dist/types/core/base/async.d.ts +30 -0
  15. package/dist/types/core/base/async.d.ts.map +1 -0
  16. package/dist/types/core/base/stream.d.ts +40 -0
  17. package/dist/types/core/base/stream.d.ts.map +1 -0
  18. package/dist/types/core/base/sync.d.ts +32 -0
  19. package/dist/types/core/base/sync.d.ts.map +1 -0
  20. package/dist/types/core/base-primitives.d.ts +3 -1
  21. package/dist/types/core/base-primitives.d.ts.map +1 -0
  22. package/dist/types/core/compat.d.ts +1 -0
  23. package/dist/types/core/compat.d.ts.map +1 -0
  24. package/dist/types/core/constants.d.ts +19 -4
  25. package/dist/types/core/constants.d.ts.map +1 -0
  26. package/dist/types/core/constructors.d.ts +1 -0
  27. package/dist/types/core/constructors.d.ts.map +1 -0
  28. package/dist/types/core/cross/async.d.ts +8 -3
  29. package/dist/types/core/cross/async.d.ts.map +1 -0
  30. package/dist/types/core/cross/cross-parser.d.ts +8 -0
  31. package/dist/types/core/cross/cross-parser.d.ts.map +1 -0
  32. package/dist/types/core/cross/index.d.ts +12 -5
  33. package/dist/types/core/cross/index.d.ts.map +1 -0
  34. package/dist/types/core/cross/serialize.d.ts +23 -5
  35. package/dist/types/core/cross/serialize.d.ts.map +1 -0
  36. package/dist/types/core/cross/stream.d.ts +8 -3
  37. package/dist/types/core/cross/stream.d.ts.map +1 -0
  38. package/dist/types/core/cross/sync.d.ts +8 -3
  39. package/dist/types/core/cross/sync.d.ts.map +1 -0
  40. package/dist/types/core/get-identifier.d.ts +1 -0
  41. package/dist/types/core/get-identifier.d.ts.map +1 -0
  42. package/dist/types/core/keys.d.ts +1 -0
  43. package/dist/types/core/keys.d.ts.map +1 -0
  44. package/dist/types/core/literals.d.ts +1 -0
  45. package/dist/types/core/literals.d.ts.map +1 -0
  46. package/dist/types/core/parser-context.d.ts +23 -0
  47. package/dist/types/core/parser-context.d.ts.map +1 -0
  48. package/dist/types/core/plugin.d.ts +26 -0
  49. package/dist/types/core/plugin.d.ts.map +1 -0
  50. package/dist/types/core/promise-to-result.d.ts +1 -0
  51. package/dist/types/core/promise-to-result.d.ts.map +1 -0
  52. package/dist/types/core/reference.d.ts +1 -0
  53. package/dist/types/core/reference.d.ts.map +1 -0
  54. package/dist/types/core/serializer-context.old.d.ts +165 -0
  55. package/dist/types/core/serializer-context.old.d.ts.map +1 -0
  56. package/dist/types/core/shared.d.ts +4 -7
  57. package/dist/types/core/shared.d.ts.map +1 -0
  58. package/dist/types/core/string.d.ts +1 -0
  59. package/dist/types/core/string.d.ts.map +1 -0
  60. package/dist/types/core/tree/async.d.ts +8 -3
  61. package/dist/types/core/tree/async.d.ts.map +1 -0
  62. package/dist/types/core/tree/deserialize.d.ts +49 -2
  63. package/dist/types/core/tree/deserialize.d.ts.map +1 -0
  64. package/dist/types/core/tree/index.d.ts +10 -7
  65. package/dist/types/core/tree/index.d.ts.map +1 -0
  66. package/dist/types/core/tree/serialize.d.ts +37 -4
  67. package/dist/types/core/tree/serialize.d.ts.map +1 -0
  68. package/dist/types/core/tree/sync.d.ts +8 -3
  69. package/dist/types/core/tree/sync.d.ts.map +1 -0
  70. package/dist/types/core/types.d.ts +10 -3
  71. package/dist/types/core/types.d.ts.map +1 -0
  72. package/dist/types/core/web-api.d.ts +1 -0
  73. package/dist/types/core/web-api.d.ts.map +1 -0
  74. package/dist/types/index.d.ts +3 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/types.d.ts +1 -0
  77. package/dist/types/types.d.ts.map +1 -0
  78. package/package.json +2 -2
  79. package/src/core/Serializer.ts +2 -0
  80. package/src/core/base/async.ts +804 -0
  81. package/src/core/base/stream.ts +496 -0
  82. package/src/core/base/sync.ts +675 -0
  83. package/src/core/base-primitives.ts +22 -0
  84. package/src/core/constants.ts +61 -45
  85. package/src/core/cross/async.ts +6 -751
  86. package/src/core/cross/cross-parser.ts +9 -0
  87. package/src/core/cross/index.ts +62 -84
  88. package/src/core/cross/serialize.ts +71 -862
  89. package/src/core/cross/stream.ts +6 -873
  90. package/src/core/cross/sync.ts +6 -624
  91. package/src/core/is-serializable.new.ts +208 -0
  92. package/src/core/keys.ts +1 -1
  93. package/src/core/parser-context.ts +131 -0
  94. package/src/core/plugin.ts +55 -0
  95. package/src/core/serializer-context.new.ts +1168 -0
  96. package/src/core/serializer-context.old.ts +1126 -0
  97. package/src/core/shared.ts +46 -123
  98. package/src/core/tree/async.ts +6 -750
  99. package/src/core/tree/deserialize.ts +423 -420
  100. package/src/core/tree/index.ts +49 -91
  101. package/src/core/tree/parser.ts +45 -0
  102. package/src/core/tree/serialize.ts +122 -828
  103. package/src/core/tree/sync.ts +6 -624
  104. package/src/core/types.ts +13 -2
  105. package/src/example.ts +28 -0
  106. package/src/index.ts +3 -0
  107. package/dist/types/core/assignments.d.ts +0 -33
  108. package/dist/types/core/context.d.ts +0 -9
  109. package/dist/types/core/cross/context.d.ts +0 -37
  110. package/dist/types/core/cross/primitives.d.ts +0 -9
  111. package/dist/types/core/cross/web-api.d.ts +0 -4
  112. package/dist/types/core/tree/context.d.ts +0 -44
  113. package/dist/types/core/tree/primitives.d.ts +0 -9
  114. package/dist/types/core/tree/web-api.d.ts +0 -4
  115. package/src/core/assignments.ts +0 -159
  116. package/src/core/context.ts +0 -15
  117. package/src/core/cross/context.ts +0 -102
  118. package/src/core/cross/primitives.ts +0 -128
  119. package/src/core/cross/web-api.ts +0 -50
  120. package/src/core/tree/context.ts +0 -125
  121. package/src/core/tree/primitives.ts +0 -123
  122. package/src/core/tree/web-api.ts +0 -50
@@ -0,0 +1,208 @@
1
+ import { ALL_ENABLED, BIGINT_FLAG, Feature } from './compat';
2
+ import { INV_SYMBOL_REF, UNIVERSAL_SENTINEL } from './constants';
3
+ import type { Plugin, PluginAccessOptions } from './plugin';
4
+ import { hasReferenceID } from './reference';
5
+ import { getErrorOptions } from './shared';
6
+
7
+ export type SerializationMode = 'sync' | 'async' | 'stream';
8
+
9
+ export interface IsSerializableOptions extends PluginAccessOptions {
10
+ mode: SerializationMode;
11
+ disabledFeatures?: number;
12
+ }
13
+
14
+ class IsSerializableContext implements PluginAccessOptions {
15
+ plugins?: Plugin<any, any>[] | undefined;
16
+
17
+ mode: SerializationMode;
18
+
19
+ features: number;
20
+
21
+ constructor(options: IsSerializableOptions) {
22
+ this.mode = options.mode;
23
+ this.plugins = options.plugins;
24
+ this.features = ALL_ENABLED ^ (options.disabledFeatures || 0);
25
+ }
26
+
27
+ checkArray(values: unknown[]): boolean {
28
+ if (!this.check(values[0])) {
29
+ return false;
30
+ }
31
+ for (let i = 1, len = values.length; i < len; i++) {
32
+ if (!this.check(values[i])) {
33
+ return false;
34
+ }
35
+ }
36
+ return true;
37
+ }
38
+
39
+ checkPlainObject(value: object): boolean {
40
+ return this.checkArray(Object.values(value));
41
+ }
42
+
43
+ checkError(value: Error): boolean {
44
+ const options = getErrorOptions(value, this.features);
45
+ if (options) {
46
+ return this.checkPlainObject(options);
47
+ }
48
+ return true;
49
+ }
50
+
51
+ checkPlugin(value: unknown): boolean {
52
+ const current = this.plugins;
53
+ if (current) {
54
+ for (let i = 0, len = current.length; i < len; i++) {
55
+ const plugin = current[i];
56
+ if (plugin.test(value) && plugin.isSerializable && plugin.isSerializable(value)) {
57
+ return true;
58
+ }
59
+ }
60
+ }
61
+ return true;
62
+ }
63
+
64
+ checkObject(value: object | null): boolean {
65
+ if (!value) {
66
+ return true;
67
+ }
68
+ if (Array.isArray(value)) {
69
+ return this.checkArray(value);
70
+ }
71
+ const currentClass = value.constructor;
72
+ switch (currentClass) {
73
+ case Date:
74
+ case RegExp:
75
+ case Number:
76
+ case Boolean:
77
+ case String:
78
+ case BigInt:
79
+ return true;
80
+ case Object:
81
+ case undefined:
82
+ return this.checkPlainObject(value);
83
+ case Error:
84
+ case EvalError:
85
+ case RangeError:
86
+ case ReferenceError:
87
+ case SyntaxError:
88
+ case TypeError:
89
+ case URIError:
90
+ return this.checkError(value as unknown as Error);
91
+ default:
92
+ break;
93
+ }
94
+ const currentFeatures = this.features;
95
+ // Promises
96
+ if (
97
+ (currentFeatures & Feature.Promise)
98
+ && (currentClass === Promise || value instanceof Promise)
99
+ ) {
100
+ return this.mode === 'async' || this.mode === 'stream';
101
+ }
102
+ // Typed Arrays
103
+ if (currentFeatures & Feature.TypedArray) {
104
+ switch (currentClass) {
105
+ case ArrayBuffer:
106
+ case Int8Array:
107
+ case Int16Array:
108
+ case Int32Array:
109
+ case Uint8Array:
110
+ case Uint16Array:
111
+ case Uint32Array:
112
+ case Uint8ClampedArray:
113
+ case Float32Array:
114
+ case Float64Array:
115
+ case DataView:
116
+ return true;
117
+ default:
118
+ break;
119
+ }
120
+ }
121
+ // BigInt Typed Arrays
122
+ if ((currentFeatures & BIGINT_FLAG) === BIGINT_FLAG) {
123
+ switch (currentClass) {
124
+ case BigInt64Array:
125
+ case BigUint64Array:
126
+ return true;
127
+ default:
128
+ break;
129
+ }
130
+ }
131
+ // ES Collection
132
+ if (currentFeatures & Feature.Map && currentClass === Map) {
133
+ return true;
134
+ }
135
+ if (currentFeatures & Feature.Set && currentClass === Set) {
136
+ return true;
137
+ }
138
+ // Web APIs
139
+ if (currentFeatures & Feature.WebAPI) {
140
+ switch (currentClass) {
141
+ case (typeof URL !== 'undefined' ? URL : UNIVERSAL_SENTINEL):
142
+ case (typeof URLSearchParams !== 'undefined' ? URLSearchParams : UNIVERSAL_SENTINEL):
143
+ case (typeof Headers !== 'undefined' ? Headers : UNIVERSAL_SENTINEL):
144
+ case (typeof FormData !== 'undefined' ? FormData : UNIVERSAL_SENTINEL):
145
+ case (typeof Event !== 'undefined' ? Event : UNIVERSAL_SENTINEL):
146
+ case (typeof CustomEvent !== 'undefined' ? CustomEvent : UNIVERSAL_SENTINEL):
147
+ case (typeof DOMException !== 'undefined' ? DOMException : UNIVERSAL_SENTINEL):
148
+ return true;
149
+ case (typeof Request !== 'undefined' ? Request : UNIVERSAL_SENTINEL):
150
+ case (typeof Response !== 'undefined' ? Response : UNIVERSAL_SENTINEL):
151
+ return this.mode === 'async' || this.mode === 'stream';
152
+ case (typeof Blob !== 'undefined' ? Blob : UNIVERSAL_SENTINEL):
153
+ case (typeof File !== 'undefined' ? File : UNIVERSAL_SENTINEL):
154
+ return this.mode === 'async';
155
+ case (typeof ReadableStream !== 'undefined' ? ReadableStream : UNIVERSAL_SENTINEL):
156
+ return this.mode === 'stream';
157
+ default:
158
+ break;
159
+ }
160
+ }
161
+ const parsed = this.checkPlugin(value);
162
+ if (parsed) {
163
+ return parsed;
164
+ }
165
+ if (
166
+ (currentFeatures & Feature.AggregateError)
167
+ && typeof AggregateError !== 'undefined'
168
+ && (currentClass === AggregateError || value instanceof AggregateError)
169
+ ) {
170
+ return true;
171
+ }
172
+ // Slow path. We only need to handle Errors and Iterators
173
+ // since they have very broad implementations.
174
+ if (value instanceof Error) {
175
+ return true;
176
+ }
177
+ // Generator functions don't have a global constructor
178
+ // despite existing
179
+ if (currentFeatures & Feature.Symbol && Symbol.iterator in value) {
180
+ return true;
181
+ }
182
+ return false;
183
+ }
184
+
185
+ check(value: unknown): boolean {
186
+ switch (typeof value) {
187
+ case 'string':
188
+ case 'number':
189
+ case 'boolean':
190
+ case 'undefined':
191
+ return true;
192
+ case 'bigint':
193
+ return !!(this.features & Feature.BigInt);
194
+ case 'object':
195
+ return this.checkObject(value);
196
+ case 'symbol':
197
+ return !!(this.features & Feature.Symbol) && value in INV_SYMBOL_REF;
198
+ case 'function':
199
+ return hasReferenceID(value);
200
+ default:
201
+ return false;
202
+ }
203
+ }
204
+ }
205
+
206
+ export function isSerializable<T>(value: T, options: IsSerializableOptions): boolean {
207
+ return new IsSerializableContext(options).check(value);
208
+ }
package/src/core/keys.ts CHANGED
@@ -37,5 +37,5 @@ export function getCrossReferenceHeader(id?: string): string {
37
37
  if (id == null) {
38
38
  return `self.${GLOBAL_CONTEXT_REFERENCES}=self.${GLOBAL_CONTEXT_REFERENCES}||[];`;
39
39
  }
40
- return `(self.${GLOBAL_CONTEXT_REFERENCES}=self.${GLOBAL_CONTEXT_REFERENCES}||{})["${serializeString(id)}"]=[]`;
40
+ return `(self.${GLOBAL_CONTEXT_REFERENCES}=self.${GLOBAL_CONTEXT_REFERENCES}||{})["${serializeString(id)}"]=[];`;
41
41
  }
@@ -0,0 +1,131 @@
1
+ import { createIndexedValueNode, createReferenceNode } from './base-primitives';
2
+ import { ALL_ENABLED, BIGINT_FLAG, Feature } from './compat';
3
+ import type { Plugin, PluginAccessOptions, SerovalMode } from './plugin';
4
+ import { hasReferenceID } from './reference';
5
+ import type { SerovalIndexedValueNode, SerovalReferenceNode } from './types';
6
+
7
+ export interface BaseParserContextOptions extends PluginAccessOptions {
8
+ disabledFeatures?: number;
9
+ refs?: Map<unknown, number>;
10
+ }
11
+
12
+ export abstract class BaseParserContext implements PluginAccessOptions {
13
+ abstract readonly mode: SerovalMode;
14
+
15
+ features: number;
16
+
17
+ marked = new Set<number>();
18
+
19
+ refs: Map<unknown, number>;
20
+
21
+ plugins?: Plugin<any, any>[] | undefined;
22
+
23
+ constructor(options: BaseParserContextOptions) {
24
+ this.plugins = options.plugins;
25
+ this.features = ALL_ENABLED ^ (options.disabledFeatures || 0);
26
+ this.refs = options.refs || new Map<unknown, number>();
27
+ }
28
+
29
+ protected markRef(id: number): void {
30
+ this.marked.add(id);
31
+ }
32
+
33
+ protected isMarked(id: number): boolean {
34
+ return this.marked.has(id);
35
+ }
36
+
37
+ protected getReference<T>(current: T): number | SerovalIndexedValueNode | SerovalReferenceNode {
38
+ const registeredID = this.refs.get(current);
39
+ if (registeredID != null) {
40
+ this.markRef(registeredID);
41
+ return createIndexedValueNode(registeredID);
42
+ }
43
+ const id = this.refs.size;
44
+ this.refs.set(current, id);
45
+ if (hasReferenceID(current)) {
46
+ return createReferenceNode(id, current);
47
+ }
48
+ return id;
49
+ }
50
+
51
+ protected getStrictReference<T>(current: T): SerovalIndexedValueNode | SerovalReferenceNode {
52
+ const registeredID = this.refs.get(current);
53
+ if (registeredID != null) {
54
+ this.markRef(registeredID);
55
+ return createIndexedValueNode(registeredID);
56
+ }
57
+ const id = this.refs.size;
58
+ this.refs.set(current, id);
59
+ return createReferenceNode(id, current);
60
+ }
61
+
62
+ /**
63
+ * @private
64
+ */
65
+ protected isIterable(
66
+ value: unknown,
67
+ ): value is Iterable<unknown> {
68
+ if (!value || typeof value !== 'object') {
69
+ return false;
70
+ }
71
+ if (Array.isArray(value)) {
72
+ return false;
73
+ }
74
+ const currentClass = value.constructor;
75
+ const currentFeatures = this.features;
76
+ if (currentFeatures & Feature.TypedArray) {
77
+ switch (currentClass) {
78
+ case Int8Array:
79
+ case Int16Array:
80
+ case Int32Array:
81
+ case Uint8Array:
82
+ case Uint16Array:
83
+ case Uint32Array:
84
+ case Uint8ClampedArray:
85
+ case Float32Array:
86
+ case Float64Array:
87
+ return false;
88
+ default:
89
+ break;
90
+ }
91
+ }
92
+ // BigInt Typed Arrays
93
+ if ((currentFeatures & BIGINT_FLAG) === BIGINT_FLAG) {
94
+ switch (currentClass) {
95
+ case BigInt64Array:
96
+ case BigUint64Array:
97
+ return false;
98
+ default:
99
+ break;
100
+ }
101
+ }
102
+ // ES Collection
103
+ if (currentFeatures & Feature.Map && currentClass === Map) {
104
+ return false;
105
+ }
106
+ if (currentFeatures & Feature.Set && currentClass === Set) {
107
+ return false;
108
+ }
109
+ if (currentFeatures & Feature.WebAPI) {
110
+ if (typeof Headers !== 'undefined' && currentClass === Headers) {
111
+ return false;
112
+ }
113
+ if (typeof File !== 'undefined' && currentClass === File) {
114
+ return false;
115
+ }
116
+ }
117
+ const currentPlugins = this.plugins;
118
+ if (currentPlugins) {
119
+ for (let i = 0, len = currentPlugins.length; i < len; i++) {
120
+ const plugin = currentPlugins[i];
121
+ if (plugin.test(value) && plugin.isIterable && plugin.isIterable(value)) {
122
+ return false;
123
+ }
124
+ }
125
+ }
126
+ if (currentFeatures & Feature.Symbol) {
127
+ return Symbol.iterator in value;
128
+ }
129
+ return false;
130
+ }
131
+ }
@@ -0,0 +1,55 @@
1
+ import type BaseAsyncParserContext from './base/async';
2
+ import type BaseStreamParserContext from './base/stream';
3
+ import type BaseSyncParserContext from './base/sync';
4
+ import type BaseSerializerContext from './serializer-context.old';
5
+ import type VanillaDeserializerContext from './tree/deserialize';
6
+
7
+ export type SerovalMode = 'vanilla' | 'cross';
8
+
9
+ export interface PluginData {
10
+ id: number;
11
+ }
12
+
13
+ export interface Plugin<Value, Node> {
14
+ tag: string;
15
+ test(value: unknown): boolean;
16
+ parse: {
17
+ sync?: (
18
+ value: Value,
19
+ ctx: BaseSyncParserContext,
20
+ data: PluginData,
21
+ ) => Node;
22
+ async?: (
23
+ value: Value,
24
+ ctx: BaseAsyncParserContext,
25
+ data: PluginData,
26
+ ) => Promise<Node>;
27
+ stream?: (
28
+ value: Value,
29
+ ctx: BaseStreamParserContext,
30
+ data: PluginData,
31
+ ) => Node;
32
+ };
33
+ serialize(
34
+ node: Node,
35
+ ctx: BaseSerializerContext,
36
+ data: PluginData,
37
+ ): string;
38
+ deserialize(
39
+ node: Node,
40
+ ctx: VanillaDeserializerContext,
41
+ data: PluginData,
42
+ ): Value;
43
+ isIterable?: (value: Value) => boolean;
44
+ // isSerializable?: (value: Value) => boolean;
45
+ }
46
+
47
+ export function createPlugin<Value, Node>(
48
+ plugin: Plugin<Value, Node>,
49
+ ): Plugin<Value, Node> {
50
+ return plugin;
51
+ }
52
+
53
+ export interface PluginAccessOptions {
54
+ plugins?: Plugin<any, any>[];
55
+ }