| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-27 05:32:57 +08:00
										 |  |  | const memoize = require("../util/memoize"); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const LAZY_TARGET = Symbol("lazy serialization target"); | 
					
						
							|  |  |  | const LAZY_SERIALIZED_VALUE = Symbol("lazy serialization data"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | /** @typedef {SerializerMiddleware<EXPECTED_ANY, EXPECTED_ANY, Record<string, EXPECTED_ANY>>} LazyTarget */ | 
					
						
							|  |  |  | /** @typedef {Record<string, EXPECTED_ANY>} LazyOptions */ | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  |  * @template InputValue | 
					
						
							|  |  |  |  * @template OutputValue | 
					
						
							|  |  |  |  * @template {LazyTarget} InternalLazyTarget | 
					
						
							|  |  |  |  * @template {LazyOptions | undefined} InternalLazyOptions | 
					
						
							|  |  |  |  * @typedef {(() => InputValue | Promise<InputValue>) & Partial<{ [LAZY_TARGET]: InternalLazyTarget, options: InternalLazyOptions, [LAZY_SERIALIZED_VALUE]?: OutputValue | LazyFunction<OutputValue, InputValue, InternalLazyTarget, InternalLazyOptions> | undefined }>} LazyFunction | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-03-07 21:12:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template DeserializedType | 
					
						
							|  |  |  |  * @template SerializedType | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  |  * @template Context | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | class SerializerMiddleware { | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 	/* istanbul ignore next */ | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 	 * @abstract | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 	 * @param {DeserializedType} data data | 
					
						
							| 
									
										
										
										
											2025-03-07 21:12:22 +08:00
										 |  |  | 	 * @param {Context} context context object | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 	 * @returns {SerializedType | Promise<SerializedType> | null} serialized data | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	serialize(data, context) { | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 		const AbstractMethodError = require("../AbstractMethodError"); | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 		throw new AbstractMethodError(); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 	/* istanbul ignore next */ | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 	 * @abstract | 
					
						
							| 
									
										
										
										
											2019-01-24 23:51:05 +08:00
										 |  |  | 	 * @param {SerializedType} data data | 
					
						
							| 
									
										
										
										
											2025-03-07 21:12:22 +08:00
										 |  |  | 	 * @param {Context} context context object | 
					
						
							|  |  |  | 	 * @returns {DeserializedType | Promise<DeserializedType>} deserialized data | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	deserialize(data, context) { | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 		const AbstractMethodError = require("../AbstractMethodError"); | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 15:37:11 +08:00
										 |  |  | 		throw new AbstractMethodError(); | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions | undefined} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {TLazyInputValue | (() => TLazyInputValue)} value contained value or function to value | 
					
						
							|  |  |  | 	 * @param {TLazyTarget} target target middleware | 
					
						
							|  |  |  | 	 * @param {TLazyOptions=} options lazy options | 
					
						
							|  |  |  | 	 * @param {TLazyOutputValue=} serializedValue serialized value | 
					
						
							|  |  |  | 	 * @returns {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} lazy function | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	static createLazy( | 
					
						
							|  |  |  | 		value, | 
					
						
							|  |  |  | 		target, | 
					
						
							|  |  |  | 		options = /** @type {TLazyOptions} */ ({}), | 
					
						
							|  |  |  | 		serializedValue = undefined | 
					
						
							|  |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		if (SerializerMiddleware.isLazy(value, target)) return value; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		const fn = | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 			/** @type {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} */ | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 			(typeof value === "function" ? value : () => value); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		fn[LAZY_TARGET] = target; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		fn.options = options; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		fn[LAZY_SERIALIZED_VALUE] = serializedValue; | 
					
						
							|  |  |  | 		return fn; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 	 * @param {EXPECTED_ANY} fn lazy function | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @param {TLazyTarget=} target target middleware | 
					
						
							|  |  |  | 	 * @returns {fn is LazyFunction<EXPECTED_ANY, EXPECTED_ANY, TLazyTarget, EXPECTED_ANY>} true, when fn is a lazy function (optionally of that target) | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static isLazy(fn, target) { | 
					
						
							|  |  |  | 		if (typeof fn !== "function") return false; | 
					
						
							|  |  |  | 		const t = fn[LAZY_TARGET]; | 
					
						
							| 
									
										
										
										
											2024-07-31 11:11:11 +08:00
										 |  |  | 		return target ? t === target : Boolean(t); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {Record<string, EXPECTED_ANY>} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} fn lazy function | 
					
						
							| 
									
										
										
										
											2025-03-07 21:12:22 +08:00
										 |  |  | 	 * @returns {LazyOptions | undefined} options | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static getLazyOptions(fn) { | 
					
						
							| 
									
										
										
										
											2024-08-02 02:36:27 +08:00
										 |  |  | 		if (typeof fn !== "function") return; | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 		return fn.options; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions> | EXPECTED_ANY} fn lazy function | 
					
						
							|  |  |  | 	 * @returns {TLazyOutputValue | undefined} serialized value | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static getLazySerializedValue(fn) { | 
					
						
							| 
									
										
										
										
											2024-08-02 02:36:27 +08:00
										 |  |  | 		if (typeof fn !== "function") return; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		return fn[LAZY_SERIALIZED_VALUE]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions} TLazyOptions | 
					
						
							| 
									
										
										
										
											2025-09-08 19:58:12 +08:00
										 |  |  | 	 * @param {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} fn lazy function | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @param {TLazyOutputValue} value serialized value | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	static setLazySerializedValue(fn, value) { | 
					
						
							|  |  |  | 		fn[LAZY_SERIALIZED_VALUE] = value; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue DeserializedValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue SerializedValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions | undefined} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} lazy lazy function | 
					
						
							|  |  |  | 	 * @param {(value: TLazyInputValue) => TLazyOutputValue} serialize serialize function | 
					
						
							|  |  |  | 	 * @returns {LazyFunction<TLazyOutputValue, TLazyInputValue, TLazyTarget, TLazyOptions>} new lazy | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static serializeLazy(lazy, serialize) { | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 		const fn = | 
					
						
							|  |  |  | 			/** @type {LazyFunction<TLazyOutputValue, TLazyInputValue, TLazyTarget, TLazyOptions>} */ | 
					
						
							|  |  |  | 			( | 
					
						
							|  |  |  | 				memoize(() => { | 
					
						
							|  |  |  | 					const r = lazy(); | 
					
						
							|  |  |  | 					if ( | 
					
						
							|  |  |  | 						r && | 
					
						
							|  |  |  | 						typeof (/** @type {Promise<TLazyInputValue>} */ (r).then) === | 
					
						
							|  |  |  | 							"function" | 
					
						
							|  |  |  | 					) { | 
					
						
							|  |  |  | 						return ( | 
					
						
							|  |  |  | 							/** @type {Promise<TLazyInputValue>} */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 							(r).then((data) => data && serialize(data)) | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 						); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return serialize(/** @type {TLazyInputValue} */ (r)); | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		fn[LAZY_TARGET] = lazy[LAZY_TARGET]; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		fn.options = lazy.options; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		lazy[LAZY_SERIALIZED_VALUE] = fn; | 
					
						
							|  |  |  | 		return fn; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue SerializedValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue DeserializedValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions | undefined} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {LazyFunction<TLazyInputValue, TLazyOutputValue, TLazyTarget, TLazyOptions>} lazy lazy function | 
					
						
							|  |  |  | 	 * @param {(data: TLazyInputValue) => TLazyOutputValue} deserialize deserialize function | 
					
						
							|  |  |  | 	 * @returns {LazyFunction<TLazyOutputValue, TLazyInputValue, TLazyTarget, TLazyOptions>} new lazy | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static deserializeLazy(lazy, deserialize) { | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 		const fn = | 
					
						
							|  |  |  | 			/** @type {LazyFunction<TLazyOutputValue, TLazyInputValue, TLazyTarget, TLazyOptions>} */ ( | 
					
						
							|  |  |  | 				memoize(() => { | 
					
						
							|  |  |  | 					const r = lazy(); | 
					
						
							|  |  |  | 					if ( | 
					
						
							|  |  |  | 						r && | 
					
						
							|  |  |  | 						typeof (/** @type {Promise<TLazyInputValue>} */ (r).then) === | 
					
						
							|  |  |  | 							"function" | 
					
						
							|  |  |  | 					) { | 
					
						
							|  |  |  | 						return ( | 
					
						
							|  |  |  | 							/** @type {Promise<TLazyInputValue>} */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 							(r).then((data) => deserialize(data)) | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 						); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return deserialize(/** @type {TLazyInputValue} */ (r)); | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		fn[LAZY_TARGET] = lazy[LAZY_TARGET]; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		fn.options = lazy.options; | 
					
						
							| 
									
										
										
										
											2020-01-24 06:51:49 +08:00
										 |  |  | 		fn[LAZY_SERIALIZED_VALUE] = lazy; | 
					
						
							|  |  |  | 		return fn; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-17 17:25:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 	 * @template TLazyInputValue | 
					
						
							|  |  |  | 	 * @template TLazyOutputValue | 
					
						
							|  |  |  | 	 * @template {LazyTarget} TLazyTarget | 
					
						
							|  |  |  | 	 * @template {LazyOptions} TLazyOptions | 
					
						
							|  |  |  | 	 * @param {LazyFunction<TLazyInputValue | TLazyOutputValue, TLazyInputValue | TLazyOutputValue, TLazyTarget, TLazyOptions> | undefined} lazy lazy function | 
					
						
							|  |  |  | 	 * @returns {LazyFunction<TLazyInputValue | TLazyOutputValue, TLazyInputValue | TLazyOutputValue, TLazyTarget, TLazyOptions> | undefined} new lazy | 
					
						
							| 
									
										
										
										
											2021-06-17 17:25:49 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	static unMemoizeLazy(lazy) { | 
					
						
							|  |  |  | 		if (!SerializerMiddleware.isLazy(lazy)) return lazy; | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 		/** @type {LazyFunction<TLazyInputValue | TLazyOutputValue, TLazyInputValue | TLazyOutputValue, TLazyTarget, TLazyOptions>} */ | 
					
						
							| 
									
										
										
										
											2021-06-17 17:25:49 +08:00
										 |  |  | 		const fn = () => { | 
					
						
							|  |  |  | 			throw new Error( | 
					
						
							|  |  |  | 				"A lazy value that has been unmemorized can't be called again" | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		fn[LAZY_SERIALIZED_VALUE] = SerializerMiddleware.unMemoizeLazy( | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  | 			/** @type {LazyFunction<TLazyInputValue | TLazyOutputValue, TLazyInputValue | TLazyOutputValue, TLazyTarget, TLazyOptions>} */ | 
					
						
							|  |  |  | 			(lazy[LAZY_SERIALIZED_VALUE]) | 
					
						
							| 
									
										
										
										
											2021-06-17 17:25:49 +08:00
										 |  |  | 		); | 
					
						
							|  |  |  | 		fn[LAZY_TARGET] = lazy[LAZY_TARGET]; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		fn.options = lazy.options; | 
					
						
							| 
									
										
										
										
											2021-06-17 17:25:49 +08:00
										 |  |  | 		return fn; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-10-09 20:30:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = SerializerMiddleware; |