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-03-07 21:12:22 +08:00
|
|
|
/** @typedef {TODO} Context */
|
2025-03-11 08:28:01 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @template LazyResult
|
2025-03-12 09:56:14 +08:00
|
|
|
* @typedef {() => LazyResult | Promise<LazyResult>} InternalLazyFunction
|
2025-03-11 08:28:01 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** @typedef {Record<string, any>} LazyOptions */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @template LazyResult
|
|
|
|
* @typedef {InternalLazyFunction<LazyResult> & { [LAZY_TARGET]: TODO, [LAZY_SERIALIZED_VALUE]?: TODO, options: LazyOptions }} LazyFunction
|
|
|
|
*/
|
2025-03-07 21:12:22 +08:00
|
|
|
|
2019-01-24 23:51:05 +08:00
|
|
|
/**
|
|
|
|
* @template DeserializedType
|
|
|
|
* @template SerializedType
|
|
|
|
*/
|
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");
|
|
|
|
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");
|
|
|
|
throw new AbstractMethodError();
|
2018-10-09 20:30:59 +08:00
|
|
|
}
|
2020-01-24 06:51:49 +08:00
|
|
|
|
|
|
|
/**
|
2025-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult
|
|
|
|
* @param {LazyFunction<LazyResult> | EXPECTED_ANY} value contained value or function to value
|
2020-01-24 06:51:49 +08:00
|
|
|
* @param {SerializerMiddleware<any, any>} target target middleware
|
2025-03-07 21:12:22 +08:00
|
|
|
* @param {LazyOptions=} options lazy options
|
2020-01-24 06:51:49 +08:00
|
|
|
* @param {any=} serializedValue serialized value
|
2025-03-11 08:28:01 +08:00
|
|
|
* @returns {LazyFunction<LazyResult>} lazy function
|
2020-01-24 06:51:49 +08:00
|
|
|
*/
|
2024-07-31 09:37:24 +08:00
|
|
|
static createLazy(value, target, options = {}, 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 =
|
|
|
|
/** @type {LazyFunction<LazyResult>} */
|
|
|
|
(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-03-11 08:28:01 +08:00
|
|
|
* @param {EXPECTED_ANY} fn lazy function
|
2020-01-24 06:51:49 +08:00
|
|
|
* @param {SerializerMiddleware<any, any>=} target target middleware
|
|
|
|
* @returns {boolean} true, when fn is a lazy function (optionally of that target)
|
|
|
|
*/
|
|
|
|
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-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult
|
|
|
|
* @param {LazyFunction<LazyResult>} 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;
|
2020-01-24 06:51:49 +08:00
|
|
|
return /** @type {any} */ (fn).options;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult
|
|
|
|
* @param {LazyFunction<LazyResult> | EXPECTED_ANY} fn lazy function
|
2024-08-08 02:59:26 +08:00
|
|
|
* @returns {any | 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-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult
|
|
|
|
* @param {LazyFunction<LazyResult>} fn lazy function
|
|
|
|
* @param {TODO} value serialized value
|
2020-01-24 06:51:49 +08:00
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
static setLazySerializedValue(fn, value) {
|
|
|
|
fn[LAZY_SERIALIZED_VALUE] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult, R
|
|
|
|
* @param {LazyFunction<LazyResult>} lazy lazy function
|
2025-03-12 09:56:14 +08:00
|
|
|
* @param {(lazyResult: LazyResult) => Promise<R> | R} serialize serialize function
|
2025-03-11 08:28:01 +08:00
|
|
|
* @returns {LazyFunction<R>} new lazy
|
2020-01-24 06:51:49 +08:00
|
|
|
*/
|
|
|
|
static serializeLazy(lazy, serialize) {
|
2025-03-11 08:28:01 +08:00
|
|
|
const fn = /** @type {LazyFunction<R>} */ (
|
|
|
|
memoize(() => {
|
|
|
|
const r = lazy();
|
|
|
|
if (
|
|
|
|
r &&
|
|
|
|
typeof (/** @type {Promise<LazyResult>} */ (r).then) === "function"
|
|
|
|
) {
|
|
|
|
return (
|
|
|
|
/** @type {Promise<LazyResult>} */
|
|
|
|
(r).then(data => data && serialize(data))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return serialize(/** @type {LazyResult} */ (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-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult, R
|
|
|
|
* @param {LazyFunction<LazyResult>} lazy lazy function
|
2025-03-12 09:56:14 +08:00
|
|
|
* @param {(lazyResult: LazyResult) => Promise<R> | R} deserialize deserialize function
|
2025-03-11 08:28:01 +08:00
|
|
|
* @returns {LazyFunction<R>} new lazy
|
2020-01-24 06:51:49 +08:00
|
|
|
*/
|
|
|
|
static deserializeLazy(lazy, deserialize) {
|
2025-03-11 08:28:01 +08:00
|
|
|
const fn = /** @type {LazyFunction<R>} */ (
|
|
|
|
memoize(() => {
|
|
|
|
const r = lazy();
|
|
|
|
if (
|
|
|
|
r &&
|
|
|
|
typeof (/** @type {Promise<LazyResult>} */ (r).then) === "function"
|
|
|
|
) {
|
|
|
|
return (
|
|
|
|
/** @type {Promise<LazyResult>} */
|
|
|
|
(r).then(data => deserialize(data))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return deserialize(/** @type {LazyResult} */ (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-03-11 08:28:01 +08:00
|
|
|
* @template LazyResult
|
|
|
|
* @param {LazyFunction<LazyResult> | EXPECTED_ANY} lazy lazy function
|
|
|
|
* @returns {LazyFunction<LazyResult> | EXPECTED_ANY} new lazy
|
2021-06-17 17:25:49 +08:00
|
|
|
*/
|
|
|
|
static unMemoizeLazy(lazy) {
|
|
|
|
if (!SerializerMiddleware.isLazy(lazy)) return lazy;
|
2025-03-11 08:28:01 +08:00
|
|
|
/** @type {LazyFunction<LazyResult>} */
|
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(
|
|
|
|
lazy[LAZY_SERIALIZED_VALUE]
|
|
|
|
);
|
|
|
|
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;
|