| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:55:22 +08:00
										 |  |  | const ArraySerializer = require("./ArraySerializer"); | 
					
						
							| 
									
										
										
										
											2020-06-02 22:09:48 +08:00
										 |  |  | const DateObjectSerializer = require("./DateObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | const ErrorObjectSerializer = require("./ErrorObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const MapObjectSerializer = require("./MapObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-12-26 05:07:51 +08:00
										 |  |  | const NullPrototypeObjectSerializer = require("./NullPrototypeObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const PlainObjectSerializer = require("./PlainObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-10-18 18:34:54 +08:00
										 |  |  | const RegExpObjectSerializer = require("./RegExpObjectSerializer"); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const SerializerMiddleware = require("./SerializerMiddleware"); | 
					
						
							|  |  |  | const SetObjectSerializer = require("./SetObjectSerializer"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | /** @typedef {import("./types").ComplexSerializableType} ComplexSerializableType */ | 
					
						
							|  |  |  | /** @typedef {import("./types").PrimitiveSerializableType} PrimitiveSerializableType */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | /** @typedef {new (...params: any[]) => any} Constructor */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Format: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | File -> Section* | 
					
						
							|  |  |  | Section -> ObjectSection | ReferenceSection | EscapeSection | OtherSection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ObjectSection -> ESCAPE ( | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 	number:relativeOffset (number > 0) | | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	string:request (string|null):export | 
					
						
							|  |  |  | ) Section:value* ESCAPE ESCAPE_END_OBJECT | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | ReferenceSection -> ESCAPE number:relativeOffset (number < 0) | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | EscapeSection -> ESCAPE ESCAPE_ESCAPE_VALUE (escaped value ESCAPE) | 
					
						
							|  |  |  | EscapeSection -> ESCAPE ESCAPE_UNDEFINED (escaped value ESCAPE) | 
					
						
							|  |  |  | OtherSection -> any (except ESCAPE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Why using null as escape value? | 
					
						
							|  |  |  | Multiple null values can merged by the BinaryMiddleware, which makes it very efficient | 
					
						
							|  |  |  | Technically any value can be used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ObjectSerializerContext | 
					
						
							|  |  |  |  * @property {function(any): void} write | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ObjectDeserializerContext | 
					
						
							|  |  |  |  * @property {function(): any} read | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ObjectSerializer | 
					
						
							|  |  |  |  * @property {function(any, ObjectSerializerContext): void} serialize | 
					
						
							|  |  |  |  * @property {function(ObjectDeserializerContext): any} deserialize | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 17:31:20 +08:00
										 |  |  | const setSetSize = (set, size) => { | 
					
						
							|  |  |  | 	let i = 0; | 
					
						
							|  |  |  | 	for (const item of set) { | 
					
						
							|  |  |  | 		if (i++ >= size) { | 
					
						
							|  |  |  | 			set.delete(item); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const setMapSize = (map, size) => { | 
					
						
							|  |  |  | 	let i = 0; | 
					
						
							|  |  |  | 	for (const item of map.keys()) { | 
					
						
							|  |  |  | 		if (i++ >= size) { | 
					
						
							|  |  |  | 			map.delete(item); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | const ESCAPE = null; | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | const ESCAPE_ESCAPE_VALUE = null; | 
					
						
							|  |  |  | const ESCAPE_END_OBJECT = true; | 
					
						
							|  |  |  | const ESCAPE_UNDEFINED = false; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-26 05:07:51 +08:00
										 |  |  | const CURRENT_VERSION = 2; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const serializers = new Map(); | 
					
						
							|  |  |  | const serializerInversed = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const loadedRequests = new Set(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | const NOT_SERIALIZABLE = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 04:23:35 +08:00
										 |  |  | const jsTypes = new Map(); | 
					
						
							| 
									
										
										
										
											2020-01-28 15:55:22 +08:00
										 |  |  | jsTypes.set(Object, new PlainObjectSerializer()); | 
					
						
							|  |  |  | jsTypes.set(Array, new ArraySerializer()); | 
					
						
							| 
									
										
										
										
											2018-12-26 05:07:51 +08:00
										 |  |  | jsTypes.set(null, new NullPrototypeObjectSerializer()); | 
					
						
							| 
									
										
										
										
											2018-10-25 04:23:35 +08:00
										 |  |  | jsTypes.set(Map, new MapObjectSerializer()); | 
					
						
							|  |  |  | jsTypes.set(Set, new SetObjectSerializer()); | 
					
						
							| 
									
										
										
										
											2020-06-02 22:09:48 +08:00
										 |  |  | jsTypes.set(Date, new DateObjectSerializer()); | 
					
						
							| 
									
										
										
										
											2018-10-25 04:23:35 +08:00
										 |  |  | jsTypes.set(RegExp, new RegExpObjectSerializer()); | 
					
						
							|  |  |  | jsTypes.set(Error, new ErrorObjectSerializer(Error)); | 
					
						
							|  |  |  | jsTypes.set(EvalError, new ErrorObjectSerializer(EvalError)); | 
					
						
							|  |  |  | jsTypes.set(RangeError, new ErrorObjectSerializer(RangeError)); | 
					
						
							|  |  |  | jsTypes.set(ReferenceError, new ErrorObjectSerializer(ReferenceError)); | 
					
						
							|  |  |  | jsTypes.set(SyntaxError, new ErrorObjectSerializer(SyntaxError)); | 
					
						
							|  |  |  | jsTypes.set(TypeError, new ErrorObjectSerializer(TypeError)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | // If in a sandboxed environment (e. g. jest), this escapes the sandbox and registers
 | 
					
						
							|  |  |  | // real Object and Array types to. These types may occur in the wild too, e. g. when
 | 
					
						
							|  |  |  | // using Structured Clone in postMessage.
 | 
					
						
							|  |  |  | if (exports.constructor !== Object) { | 
					
						
							|  |  |  | 	const Obj = /** @type {typeof Object} */ (exports.constructor); | 
					
						
							|  |  |  | 	const Fn = /** @type {typeof Function} */ (Obj.constructor); | 
					
						
							|  |  |  | 	for (const [type, config] of Array.from(jsTypes)) { | 
					
						
							|  |  |  | 		if (type) { | 
					
						
							|  |  |  | 			const Type = new Fn(`return ${type.name};`)(); | 
					
						
							|  |  |  | 			jsTypes.set(Type, config); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-25 04:23:35 +08:00
										 |  |  | { | 
					
						
							|  |  |  | 	let i = 1; | 
					
						
							|  |  |  | 	for (const [type, serializer] of jsTypes) { | 
					
						
							|  |  |  | 		serializers.set(type, { | 
					
						
							|  |  |  | 			request: "", | 
					
						
							|  |  |  | 			name: i++, | 
					
						
							|  |  |  | 			serializer | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | for (const { request, name, serializer } of serializers.values()) { | 
					
						
							|  |  |  | 	serializerInversed.set(`${request}/${name}`, serializer); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-20 16:05:32 +08:00
										 |  |  | /** @type {Map<RegExp, (request: string) => boolean>} */ | 
					
						
							|  |  |  | const loaders = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {ComplexSerializableType[]} DeserializedType | 
					
						
							|  |  |  |  * @typedef {PrimitiveSerializableType[]} SerializedType | 
					
						
							|  |  |  |  * @extends {SerializerMiddleware<DeserializedType, SerializedType>} | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | class ObjectMiddleware extends SerializerMiddleware { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	constructor(extendContext) { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 		this.extendContext = extendContext; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-12-20 16:05:32 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {RegExp} regExp RegExp for which the request is tested | 
					
						
							|  |  |  | 	 * @param {function(string): boolean} loader loader to load the request, returns true when successful | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	static registerLoader(regExp, loader) { | 
					
						
							|  |  |  | 		loaders.set(regExp, loader); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Constructor} Constructor the constructor | 
					
						
							|  |  |  | 	 * @param {string} request the request which will be required when deserializing | 
					
						
							|  |  |  | 	 * @param {string} name the name to make multiple serializer unique when sharing a request | 
					
						
							|  |  |  | 	 * @param {ObjectSerializer} serializer the serializer | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	static register(Constructor, request, name, serializer) { | 
					
						
							|  |  |  | 		const key = request + "/" + name; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		if (serializers.has(Constructor)) { | 
					
						
							|  |  |  | 			throw new Error( | 
					
						
							| 
									
										
										
										
											2019-06-13 16:51:12 +08:00
										 |  |  | 				`ObjectMiddleware.register: serializer for ${Constructor.name} is already registered` | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		if (serializerInversed.has(key)) { | 
					
						
							|  |  |  | 			throw new Error( | 
					
						
							|  |  |  | 				`ObjectMiddleware.register: serializer for ${key} is already registered` | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		serializers.set(Constructor, { | 
					
						
							|  |  |  | 			request, | 
					
						
							|  |  |  | 			name, | 
					
						
							|  |  |  | 			serializer | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		serializerInversed.set(key, serializer); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {Constructor} Constructor the constructor | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	static registerNotSerializable(Constructor) { | 
					
						
							|  |  |  | 		if (serializers.has(Constructor)) { | 
					
						
							|  |  |  | 			throw new Error( | 
					
						
							| 
									
										
										
										
											2019-06-13 16:51:12 +08:00
										 |  |  | 				`ObjectMiddleware.registerNotSerializable: serializer for ${Constructor.name} is already registered` | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 			); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 		serializers.set(Constructor, NOT_SERIALIZABLE); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	static getSerializerFor(object) { | 
					
						
							| 
									
										
										
										
											2018-12-26 05:07:51 +08:00
										 |  |  | 		let c = object.constructor; | 
					
						
							|  |  |  | 		if (!c) { | 
					
						
							|  |  |  | 			if (Object.getPrototypeOf(object) === null) { | 
					
						
							|  |  |  | 				// Object created with Object.create(null)
 | 
					
						
							|  |  |  | 				c = null; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				throw new Error( | 
					
						
							|  |  |  | 					"Serialization of objects with prototype without valid constructor property not possible" | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		const config = serializers.get(c); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		if (!config) throw new Error(`No serializer registered for ${c.name}`); | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 		if (config === NOT_SERIALIZABLE) throw NOT_SERIALIZABLE; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		return config; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static getDeserializerFor(request, name) { | 
					
						
							|  |  |  | 		const key = request + "/" + name; | 
					
						
							|  |  |  | 		const serializer = serializerInversed.get(key); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		if (serializer === undefined) { | 
					
						
							|  |  |  | 			throw new Error(`No deserializer registered for ${key}`); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		return serializer; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 	 * @param {DeserializedType} data data | 
					
						
							|  |  |  | 	 * @param {Object} context context object | 
					
						
							|  |  |  | 	 * @returns {SerializedType|Promise<SerializedType>} serialized data | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	serialize(data, context) { | 
					
						
							|  |  |  | 		/** @type {any[]} */ | 
					
						
							|  |  |  | 		const result = [CURRENT_VERSION]; | 
					
						
							|  |  |  | 		let currentPos = 0; | 
					
						
							|  |  |  | 		const referenceable = new Map(); | 
					
						
							|  |  |  | 		const addReferenceable = item => { | 
					
						
							|  |  |  | 			referenceable.set(item, currentPos++); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		let currentPosTypeLookup = 0; | 
					
						
							|  |  |  | 		const objectTypeLookup = new Map(); | 
					
						
							| 
									
										
										
										
											2018-10-17 20:04:38 +08:00
										 |  |  | 		const cycleStack = new Set(); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		const stackToString = item => { | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 			const arr = Array.from(cycleStack); | 
					
						
							|  |  |  | 			arr.push(item); | 
					
						
							|  |  |  | 			return arr | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				.map(item => { | 
					
						
							|  |  |  | 					if (typeof item === "string") { | 
					
						
							|  |  |  | 						if (item.length > 100) { | 
					
						
							|  |  |  | 							return `String ${JSON.stringify(item.slice(0, 100)).slice( | 
					
						
							|  |  |  | 								0, | 
					
						
							|  |  |  | 								-1 | 
					
						
							|  |  |  | 							)}..."`;
 | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return `String ${JSON.stringify(item)}`; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 					try { | 
					
						
							|  |  |  | 						const { request, name } = ObjectMiddleware.getSerializerFor(item); | 
					
						
							|  |  |  | 						if (request) { | 
					
						
							|  |  |  | 							return `${request}${name ? `.${name}` : ""}`; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} catch (e) { | 
					
						
							|  |  |  | 						// ignore -> fallback
 | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-06-02 22:09:48 +08:00
										 |  |  | 					if (typeof item === "object" && item !== null) { | 
					
						
							|  |  |  | 						if (item.constructor) { | 
					
						
							|  |  |  | 							if (item.constructor === Object) | 
					
						
							|  |  |  | 								return `Object { ${Object.keys(item).join(", ")} }`; | 
					
						
							|  |  |  | 							if (item.constructor === Map) return `Map { ${item.size} items }`; | 
					
						
							|  |  |  | 							if (item.constructor === Array) | 
					
						
							|  |  |  | 								return `Array { ${item.length} items }`; | 
					
						
							|  |  |  | 							if (item.constructor === Set) return `Set { ${item.size} items }`; | 
					
						
							|  |  |  | 							if (item.constructor === RegExp) return item.toString(); | 
					
						
							|  |  |  | 							return `${item.constructor.name}`; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return `Object [null prototype] { ${Object.keys(item).join( | 
					
						
							|  |  |  | 							", " | 
					
						
							|  |  |  | 						)} }`;
 | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					try { | 
					
						
							|  |  |  | 						return `${item}`; | 
					
						
							|  |  |  | 					} catch (e) { | 
					
						
							|  |  |  | 						return `(${e.message})`; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.join(" -> "); | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 		let hasDebugInfoAttached; | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 		const ctx = { | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 			write(value, key) { | 
					
						
							|  |  |  | 				try { | 
					
						
							|  |  |  | 					process(value); | 
					
						
							|  |  |  | 				} catch (e) { | 
					
						
							|  |  |  | 					if (hasDebugInfoAttached === undefined) | 
					
						
							|  |  |  | 						hasDebugInfoAttached = new WeakSet(); | 
					
						
							|  |  |  | 					if (!hasDebugInfoAttached.has(e)) { | 
					
						
							|  |  |  | 						e.message += `\nwhile serializing ${stackToString(value)}`; | 
					
						
							|  |  |  | 						hasDebugInfoAttached.add(e); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					throw e; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			snapshot() { | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					length: result.length, | 
					
						
							|  |  |  | 					cycleStackSize: cycleStack.size, | 
					
						
							|  |  |  | 					referenceableSize: referenceable.size, | 
					
						
							|  |  |  | 					currentPos, | 
					
						
							|  |  |  | 					objectTypeLookupSize: objectTypeLookup.size, | 
					
						
							|  |  |  | 					currentPosTypeLookup | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			rollback(snapshot) { | 
					
						
							|  |  |  | 				result.length = snapshot.length; | 
					
						
							|  |  |  | 				setSetSize(cycleStack, snapshot.cycleStackSize); | 
					
						
							|  |  |  | 				setMapSize(referenceable, snapshot.referenceableSize); | 
					
						
							|  |  |  | 				currentPos = snapshot.currentPos; | 
					
						
							|  |  |  | 				setMapSize(objectTypeLookup, snapshot.objectTypeLookupSize); | 
					
						
							|  |  |  | 				currentPosTypeLookup = snapshot.currentPosTypeLookup; | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 			...context | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		this.extendContext(ctx); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		const process = item => { | 
					
						
							| 
									
										
										
										
											2018-10-10 16:24:44 +08:00
										 |  |  | 			// check if we can emit a reference
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			const ref = referenceable.get(item); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			if (ref !== undefined) { | 
					
						
							|  |  |  | 				result.push(ESCAPE, ref - currentPos); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 04:16:15 +08:00
										 |  |  | 			if (Buffer.isBuffer(item)) { | 
					
						
							|  |  |  | 				addReferenceable(item); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 04:16:15 +08:00
										 |  |  | 				result.push(item); | 
					
						
							|  |  |  | 			} else if (typeof item === "object" && item !== null) { | 
					
						
							| 
									
										
										
										
											2018-10-17 20:04:38 +08:00
										 |  |  | 				if (cycleStack.has(item)) { | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 					throw new Error(`Circular references can't be serialized`); | 
					
						
							| 
									
										
										
										
											2018-10-17 20:04:38 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				const { request, name, serializer } = ObjectMiddleware.getSerializerFor( | 
					
						
							|  |  |  | 					item | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 				const key = `${request}/${name}`; | 
					
						
							|  |  |  | 				const lastIndex = objectTypeLookup.get(key); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				if (lastIndex === undefined) { | 
					
						
							|  |  |  | 					objectTypeLookup.set(key, currentPosTypeLookup++); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					result.push(ESCAPE, request, name); | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 					result.push(ESCAPE, currentPosTypeLookup - lastIndex); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-17 20:04:38 +08:00
										 |  |  | 				cycleStack.add(item); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 				try { | 
					
						
							|  |  |  | 					serializer.serialize(item, ctx); | 
					
						
							|  |  |  | 				} finally { | 
					
						
							|  |  |  | 					cycleStack.delete(item); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				result.push(ESCAPE, ESCAPE_END_OBJECT); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				addReferenceable(item); | 
					
						
							|  |  |  | 			} else if (typeof item === "string") { | 
					
						
							| 
									
										
										
										
											2018-10-10 16:24:44 +08:00
										 |  |  | 				if (item !== "") { | 
					
						
							|  |  |  | 					// empty strings are shorter when not emitting a reference (this saves 1 byte per empty string)
 | 
					
						
							|  |  |  | 					addReferenceable(item); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				if (item.length > 102400 && context.logger) { | 
					
						
							|  |  |  | 					context.logger.warn( | 
					
						
							|  |  |  | 						`Serializing big strings (${Math.round( | 
					
						
							|  |  |  | 							item.length / 1024 | 
					
						
							| 
									
										
										
										
											2020-01-28 15:42:49 +08:00
										 |  |  | 						)}kiB) impacts deserialization performance (consider using Buffer instead and decode when needed)`
 | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				result.push(item); | 
					
						
							|  |  |  | 			} else if (item === ESCAPE) { | 
					
						
							|  |  |  | 				result.push(ESCAPE, ESCAPE_ESCAPE_VALUE); | 
					
						
							|  |  |  | 			} else if (typeof item === "function") { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				if (!SerializerMiddleware.isLazy(item)) | 
					
						
							|  |  |  | 					throw new Error("Unexpected function " + item); | 
					
						
							|  |  |  | 				/** @type {SerializedType} */ | 
					
						
							|  |  |  | 				const serializedData = SerializerMiddleware.getLazySerializedValue( | 
					
						
							|  |  |  | 					item | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 				if (serializedData !== undefined) { | 
					
						
							|  |  |  | 					if (typeof serializedData === "function") { | 
					
						
							|  |  |  | 						result.push(serializedData); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						throw new Error("Not implemented"); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else if (SerializerMiddleware.isLazy(item, this)) { | 
					
						
							|  |  |  | 					throw new Error("Not implemented"); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					result.push( | 
					
						
							|  |  |  | 						SerializerMiddleware.serializeLazy(item, data => | 
					
						
							|  |  |  | 							this.serialize([data], context) | 
					
						
							|  |  |  | 						) | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			} else if (item === undefined) { | 
					
						
							|  |  |  | 				result.push(ESCAPE, ESCAPE_UNDEFINED); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				result.push(item); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 		try { | 
					
						
							|  |  |  | 			for (const item of data) { | 
					
						
							|  |  |  | 				process(item); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} catch (e) { | 
					
						
							|  |  |  | 			if (e === NOT_SERIALIZABLE) return null; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 21:52:22 +08:00
										 |  |  | 			throw e; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 	 * @param {SerializedType} data data | 
					
						
							|  |  |  | 	 * @param {Object} context context object | 
					
						
							|  |  |  | 	 * @returns {DeserializedType|Promise<DeserializedType>} deserialized data | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	deserialize(data, context) { | 
					
						
							|  |  |  | 		let currentDataPos = 0; | 
					
						
							|  |  |  | 		const read = () => { | 
					
						
							|  |  |  | 			if (currentDataPos >= data.length) | 
					
						
							|  |  |  | 				throw new Error("Unexpected end of stream"); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			return data[currentDataPos++]; | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		if (read() !== CURRENT_VERSION) | 
					
						
							| 
									
										
										
										
											2020-03-13 00:51:26 +08:00
										 |  |  | 			throw new Error("Version mismatch, serializer changed"); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		let currentPos = 0; | 
					
						
							| 
									
										
										
										
											2019-08-13 22:48:28 +08:00
										 |  |  | 		const referenceable = []; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		const addReferenceable = item => { | 
					
						
							| 
									
										
										
										
											2019-08-13 22:48:28 +08:00
										 |  |  | 			referenceable.push(item); | 
					
						
							|  |  |  | 			currentPos++; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 		let currentPosTypeLookup = 0; | 
					
						
							| 
									
										
										
										
											2019-11-13 19:18:04 +08:00
										 |  |  | 		const objectTypeLookup = []; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		const result = []; | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 		const ctx = { | 
					
						
							|  |  |  | 			read() { | 
					
						
							|  |  |  | 				return decodeValue(); | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2019-06-19 19:16:05 +08:00
										 |  |  | 			...context | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		this.extendContext(ctx); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		const decodeValue = () => { | 
					
						
							|  |  |  | 			const item = read(); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			if (item === ESCAPE) { | 
					
						
							|  |  |  | 				const nextItem = read(); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				if (nextItem === ESCAPE_ESCAPE_VALUE) { | 
					
						
							|  |  |  | 					return ESCAPE; | 
					
						
							|  |  |  | 				} else if (nextItem === ESCAPE_UNDEFINED) { | 
					
						
							|  |  |  | 					return undefined; | 
					
						
							|  |  |  | 				} else if (nextItem === ESCAPE_END_OBJECT) { | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 					throw new Error( | 
					
						
							|  |  |  | 						`Unexpected end of object at position ${currentDataPos - 1}` | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} else if (typeof nextItem === "number" && nextItem < 0) { | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					// relative reference
 | 
					
						
							| 
									
										
										
										
											2019-08-13 22:48:28 +08:00
										 |  |  | 					return referenceable[currentPos + nextItem]; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 					const request = nextItem; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					let serializer; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 					if (typeof request === "number") { | 
					
						
							| 
									
										
										
										
											2019-11-13 19:18:04 +08:00
										 |  |  | 						serializer = objectTypeLookup[currentPosTypeLookup - request]; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 						if (typeof request !== "string") { | 
					
						
							|  |  |  | 							throw new Error( | 
					
						
							|  |  |  | 								`Unexpected type (${typeof request}) of request ` + | 
					
						
							|  |  |  | 									`at position ${currentDataPos - 1}` | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-10 15:55:06 +08:00
										 |  |  | 						const name = read(); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 						if (request && !loadedRequests.has(request)) { | 
					
						
							| 
									
										
										
										
											2018-12-20 16:05:32 +08:00
										 |  |  | 							let loaded = false; | 
					
						
							|  |  |  | 							for (const [regExp, loader] of loaders) { | 
					
						
							|  |  |  | 								if (regExp.test(request)) { | 
					
						
							|  |  |  | 									if (loader(request)) { | 
					
						
							|  |  |  | 										loaded = true; | 
					
						
							|  |  |  | 										break; | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 							if (!loaded) { | 
					
						
							|  |  |  | 								require(request); | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 							loadedRequests.add(request); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 						serializer = ObjectMiddleware.getDeserializerFor(request, name); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-13 19:18:04 +08:00
										 |  |  | 						objectTypeLookup.push(serializer); | 
					
						
							|  |  |  | 						currentPosTypeLookup++; | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-11-01 19:19:27 +08:00
										 |  |  | 					try { | 
					
						
							|  |  |  | 						const item = serializer.deserialize(ctx); | 
					
						
							|  |  |  | 						const end1 = read(); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 19:19:27 +08:00
										 |  |  | 						if (end1 !== ESCAPE) { | 
					
						
							|  |  |  | 							throw new Error("Expected end of object"); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 19:19:27 +08:00
										 |  |  | 						const end2 = read(); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 19:19:27 +08:00
										 |  |  | 						if (end2 !== ESCAPE_END_OBJECT) { | 
					
						
							|  |  |  | 							throw new Error("Expected end of object"); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 19:19:27 +08:00
										 |  |  | 						addReferenceable(item); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return item; | 
					
						
							|  |  |  | 					} catch (err) { | 
					
						
							|  |  |  | 						// As this is only for error handling, we omit creating a Map for
 | 
					
						
							|  |  |  | 						// faster access to this information, as this would affect performance
 | 
					
						
							|  |  |  | 						// in the good case
 | 
					
						
							|  |  |  | 						let serializerEntry; | 
					
						
							|  |  |  | 						for (const entry of serializers) { | 
					
						
							|  |  |  | 							if (entry[1].serializer === serializer) { | 
					
						
							|  |  |  | 								serializerEntry = entry; | 
					
						
							|  |  |  | 								break; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						const name = !serializerEntry | 
					
						
							|  |  |  | 							? "unknown" | 
					
						
							|  |  |  | 							: !serializerEntry[1].request | 
					
						
							|  |  |  | 							? serializerEntry[0].name | 
					
						
							|  |  |  | 							: serializerEntry[1].name | 
					
						
							|  |  |  | 							? `${serializerEntry[1].request} ${serializerEntry[1].name}` | 
					
						
							|  |  |  | 							: serializerEntry[1].request; | 
					
						
							|  |  |  | 						err.message += `\n(during deserialization of ${name})`; | 
					
						
							|  |  |  | 						throw err; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else if (typeof item === "string") { | 
					
						
							| 
									
										
										
										
											2018-10-10 16:24:44 +08:00
										 |  |  | 				if (item !== "") { | 
					
						
							|  |  |  | 					addReferenceable(item); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				return item; | 
					
						
							|  |  |  | 			} else if (Buffer.isBuffer(item)) { | 
					
						
							|  |  |  | 				addReferenceable(item); | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 				return item; | 
					
						
							|  |  |  | 			} else if (typeof item === "function") { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 				return SerializerMiddleware.deserializeLazy( | 
					
						
							|  |  |  | 					item, | 
					
						
							|  |  |  | 					data => this.deserialize(data, context)[0] | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				return item; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		while (currentDataPos < data.length) { | 
					
						
							|  |  |  | 			result.push(decodeValue()); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-10-20 00:24:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = ObjectMiddleware; | 
					
						
							| 
									
										
										
										
											2019-01-19 18:47:19 +08:00
										 |  |  | module.exports.NOT_SERIALIZABLE = NOT_SERIALIZABLE; |