SerializerMiddleware.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. */
  4. "use strict";
  5. const memoize = require("../util/memoize");
  6. const LAZY_TARGET = Symbol("lazy serialization target");
  7. const LAZY_SERIALIZED_VALUE = Symbol("lazy serialization data");
  8. /** @typedef {TODO} Context */
  9. /**
  10. * @template LazyResult
  11. * @typedef {() => LazyResult | Promise<LazyResult>} InternalLazyFunction
  12. */
  13. /** @typedef {Record<string, any>} LazyOptions */
  14. /**
  15. * @template LazyResult
  16. * @typedef {InternalLazyFunction<LazyResult> & { [LAZY_TARGET]: TODO, [LAZY_SERIALIZED_VALUE]?: TODO, options: LazyOptions }} LazyFunction
  17. */
  18. /**
  19. * @template DeserializedType
  20. * @template SerializedType
  21. */
  22. class SerializerMiddleware {
  23. /* istanbul ignore next */
  24. /**
  25. * @abstract
  26. * @param {DeserializedType} data data
  27. * @param {Context} context context object
  28. * @returns {SerializedType | Promise<SerializedType> | null} serialized data
  29. */
  30. serialize(data, context) {
  31. const AbstractMethodError = require("../AbstractMethodError");
  32. throw new AbstractMethodError();
  33. }
  34. /* istanbul ignore next */
  35. /**
  36. * @abstract
  37. * @param {SerializedType} data data
  38. * @param {Context} context context object
  39. * @returns {DeserializedType | Promise<DeserializedType>} deserialized data
  40. */
  41. deserialize(data, context) {
  42. const AbstractMethodError = require("../AbstractMethodError");
  43. throw new AbstractMethodError();
  44. }
  45. /**
  46. * @template LazyResult
  47. * @param {LazyFunction<LazyResult> | EXPECTED_ANY} value contained value or function to value
  48. * @param {SerializerMiddleware<any, any>} target target middleware
  49. * @param {LazyOptions=} options lazy options
  50. * @param {any=} serializedValue serialized value
  51. * @returns {LazyFunction<LazyResult>} lazy function
  52. */
  53. static createLazy(value, target, options = {}, serializedValue = undefined) {
  54. if (SerializerMiddleware.isLazy(value, target)) return value;
  55. const fn =
  56. /** @type {LazyFunction<LazyResult>} */
  57. (typeof value === "function" ? value : () => value);
  58. fn[LAZY_TARGET] = target;
  59. fn.options = options;
  60. fn[LAZY_SERIALIZED_VALUE] = serializedValue;
  61. return fn;
  62. }
  63. /**
  64. * @param {EXPECTED_ANY} fn lazy function
  65. * @param {SerializerMiddleware<any, any>=} target target middleware
  66. * @returns {boolean} true, when fn is a lazy function (optionally of that target)
  67. */
  68. static isLazy(fn, target) {
  69. if (typeof fn !== "function") return false;
  70. const t = fn[LAZY_TARGET];
  71. return target ? t === target : Boolean(t);
  72. }
  73. /**
  74. * @template LazyResult
  75. * @param {LazyFunction<LazyResult>} fn lazy function
  76. * @returns {LazyOptions | undefined} options
  77. */
  78. static getLazyOptions(fn) {
  79. if (typeof fn !== "function") return;
  80. return /** @type {any} */ (fn).options;
  81. }
  82. /**
  83. * @template LazyResult
  84. * @param {LazyFunction<LazyResult> | EXPECTED_ANY} fn lazy function
  85. * @returns {any | undefined} serialized value
  86. */
  87. static getLazySerializedValue(fn) {
  88. if (typeof fn !== "function") return;
  89. return fn[LAZY_SERIALIZED_VALUE];
  90. }
  91. /**
  92. * @template LazyResult
  93. * @param {LazyFunction<LazyResult>} fn lazy function
  94. * @param {TODO} value serialized value
  95. * @returns {void}
  96. */
  97. static setLazySerializedValue(fn, value) {
  98. fn[LAZY_SERIALIZED_VALUE] = value;
  99. }
  100. /**
  101. * @template LazyResult, R
  102. * @param {LazyFunction<LazyResult>} lazy lazy function
  103. * @param {(lazyResult: LazyResult) => Promise<R> | R} serialize serialize function
  104. * @returns {LazyFunction<R>} new lazy
  105. */
  106. static serializeLazy(lazy, serialize) {
  107. const fn = /** @type {LazyFunction<R>} */ (
  108. memoize(() => {
  109. const r = lazy();
  110. if (
  111. r &&
  112. typeof (/** @type {Promise<LazyResult>} */ (r).then) === "function"
  113. ) {
  114. return (
  115. /** @type {Promise<LazyResult>} */
  116. (r).then(data => data && serialize(data))
  117. );
  118. }
  119. return serialize(/** @type {LazyResult} */ (r));
  120. })
  121. );
  122. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  123. fn.options = lazy.options;
  124. lazy[LAZY_SERIALIZED_VALUE] = fn;
  125. return fn;
  126. }
  127. /**
  128. * @template LazyResult, R
  129. * @param {LazyFunction<LazyResult>} lazy lazy function
  130. * @param {(lazyResult: LazyResult) => Promise<R> | R} deserialize deserialize function
  131. * @returns {LazyFunction<R>} new lazy
  132. */
  133. static deserializeLazy(lazy, deserialize) {
  134. const fn = /** @type {LazyFunction<R>} */ (
  135. memoize(() => {
  136. const r = lazy();
  137. if (
  138. r &&
  139. typeof (/** @type {Promise<LazyResult>} */ (r).then) === "function"
  140. ) {
  141. return (
  142. /** @type {Promise<LazyResult>} */
  143. (r).then(data => deserialize(data))
  144. );
  145. }
  146. return deserialize(/** @type {LazyResult} */ (r));
  147. })
  148. );
  149. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  150. fn.options = lazy.options;
  151. fn[LAZY_SERIALIZED_VALUE] = lazy;
  152. return fn;
  153. }
  154. /**
  155. * @template LazyResult
  156. * @param {LazyFunction<LazyResult> | EXPECTED_ANY} lazy lazy function
  157. * @returns {LazyFunction<LazyResult> | EXPECTED_ANY} new lazy
  158. */
  159. static unMemoizeLazy(lazy) {
  160. if (!SerializerMiddleware.isLazy(lazy)) return lazy;
  161. /** @type {LazyFunction<LazyResult>} */
  162. const fn = () => {
  163. throw new Error(
  164. "A lazy value that has been unmemorized can't be called again"
  165. );
  166. };
  167. fn[LAZY_SERIALIZED_VALUE] = SerializerMiddleware.unMemoizeLazy(
  168. lazy[LAZY_SERIALIZED_VALUE]
  169. );
  170. fn[LAZY_TARGET] = lazy[LAZY_TARGET];
  171. fn.options = lazy.options;
  172. return fn;
  173. }
  174. }
  175. module.exports = SerializerMiddleware;