caching.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.assertSimpleType = assertSimpleType;
  6. exports.makeStrongCache = makeStrongCache;
  7. exports.makeStrongCacheSync = makeStrongCacheSync;
  8. exports.makeWeakCache = makeWeakCache;
  9. exports.makeWeakCacheSync = makeWeakCacheSync;
  10. function _gensync() {
  11. const data = require("gensync");
  12. _gensync = function () {
  13. return data;
  14. };
  15. return data;
  16. }
  17. var _async = require("../gensync-utils/async.js");
  18. var _util = require("./util.js");
  19. const synchronize = gen => {
  20. return _gensync()(gen).sync;
  21. };
  22. function* genTrue() {
  23. return true;
  24. }
  25. function makeWeakCache(handler) {
  26. return makeCachedFunction(WeakMap, handler);
  27. }
  28. function makeWeakCacheSync(handler) {
  29. return synchronize(makeWeakCache(handler));
  30. }
  31. function makeStrongCache(handler) {
  32. return makeCachedFunction(Map, handler);
  33. }
  34. function makeStrongCacheSync(handler) {
  35. return synchronize(makeStrongCache(handler));
  36. }
  37. function makeCachedFunction(CallCache, handler) {
  38. const callCacheSync = new CallCache();
  39. const callCacheAsync = new CallCache();
  40. const futureCache = new CallCache();
  41. return function* cachedFunction(arg, data) {
  42. const asyncContext = yield* (0, _async.isAsync)();
  43. const callCache = asyncContext ? callCacheAsync : callCacheSync;
  44. const cached = yield* getCachedValueOrWait(asyncContext, callCache, futureCache, arg, data);
  45. if (cached.valid) return cached.value;
  46. const cache = new CacheConfigurator(data);
  47. const handlerResult = handler(arg, cache);
  48. let finishLock;
  49. let value;
  50. if ((0, _util.isIterableIterator)(handlerResult)) {
  51. value = yield* (0, _async.onFirstPause)(handlerResult, () => {
  52. finishLock = setupAsyncLocks(cache, futureCache, arg);
  53. });
  54. } else {
  55. value = handlerResult;
  56. }
  57. updateFunctionCache(callCache, cache, arg, value);
  58. if (finishLock) {
  59. futureCache.delete(arg);
  60. finishLock.release(value);
  61. }
  62. return value;
  63. };
  64. }
  65. function* getCachedValue(cache, arg, data) {
  66. const cachedValue = cache.get(arg);
  67. if (cachedValue) {
  68. for (const {
  69. value,
  70. valid
  71. } of cachedValue) {
  72. if (yield* valid(data)) return {
  73. valid: true,
  74. value
  75. };
  76. }
  77. }
  78. return {
  79. valid: false,
  80. value: null
  81. };
  82. }
  83. function* getCachedValueOrWait(asyncContext, callCache, futureCache, arg, data) {
  84. const cached = yield* getCachedValue(callCache, arg, data);
  85. if (cached.valid) {
  86. return cached;
  87. }
  88. if (asyncContext) {
  89. const cached = yield* getCachedValue(futureCache, arg, data);
  90. if (cached.valid) {
  91. const value = yield* (0, _async.waitFor)(cached.value.promise);
  92. return {
  93. valid: true,
  94. value
  95. };
  96. }
  97. }
  98. return {
  99. valid: false,
  100. value: null
  101. };
  102. }
  103. function setupAsyncLocks(config, futureCache, arg) {
  104. const finishLock = new Lock();
  105. updateFunctionCache(futureCache, config, arg, finishLock);
  106. return finishLock;
  107. }
  108. function updateFunctionCache(cache, config, arg, value) {
  109. if (!config.configured()) config.forever();
  110. let cachedValue = cache.get(arg);
  111. config.deactivate();
  112. switch (config.mode()) {
  113. case "forever":
  114. cachedValue = [{
  115. value,
  116. valid: genTrue
  117. }];
  118. cache.set(arg, cachedValue);
  119. break;
  120. case "invalidate":
  121. cachedValue = [{
  122. value,
  123. valid: config.validator()
  124. }];
  125. cache.set(arg, cachedValue);
  126. break;
  127. case "valid":
  128. if (cachedValue) {
  129. cachedValue.push({
  130. value,
  131. valid: config.validator()
  132. });
  133. } else {
  134. cachedValue = [{
  135. value,
  136. valid: config.validator()
  137. }];
  138. cache.set(arg, cachedValue);
  139. }
  140. }
  141. }
  142. class CacheConfigurator {
  143. constructor(data) {
  144. this._active = true;
  145. this._never = false;
  146. this._forever = false;
  147. this._invalidate = false;
  148. this._configured = false;
  149. this._pairs = [];
  150. this._data = void 0;
  151. this._data = data;
  152. }
  153. simple() {
  154. return makeSimpleConfigurator(this);
  155. }
  156. mode() {
  157. if (this._never) return "never";
  158. if (this._forever) return "forever";
  159. if (this._invalidate) return "invalidate";
  160. return "valid";
  161. }
  162. forever() {
  163. if (!this._active) {
  164. throw new Error("Cannot change caching after evaluation has completed.");
  165. }
  166. if (this._never) {
  167. throw new Error("Caching has already been configured with .never()");
  168. }
  169. this._forever = true;
  170. this._configured = true;
  171. }
  172. never() {
  173. if (!this._active) {
  174. throw new Error("Cannot change caching after evaluation has completed.");
  175. }
  176. if (this._forever) {
  177. throw new Error("Caching has already been configured with .forever()");
  178. }
  179. this._never = true;
  180. this._configured = true;
  181. }
  182. using(handler) {
  183. if (!this._active) {
  184. throw new Error("Cannot change caching after evaluation has completed.");
  185. }
  186. if (this._never || this._forever) {
  187. throw new Error("Caching has already been configured with .never or .forever()");
  188. }
  189. this._configured = true;
  190. const key = handler(this._data);
  191. const fn = (0, _async.maybeAsync)(handler, `You appear to be using an async cache handler, but Babel has been called synchronously`);
  192. if ((0, _async.isThenable)(key)) {
  193. return key.then(key => {
  194. this._pairs.push([key, fn]);
  195. return key;
  196. });
  197. }
  198. this._pairs.push([key, fn]);
  199. return key;
  200. }
  201. invalidate(handler) {
  202. this._invalidate = true;
  203. return this.using(handler);
  204. }
  205. validator() {
  206. const pairs = this._pairs;
  207. return function* (data) {
  208. for (const [key, fn] of pairs) {
  209. if (key !== (yield* fn(data))) return false;
  210. }
  211. return true;
  212. };
  213. }
  214. deactivate() {
  215. this._active = false;
  216. }
  217. configured() {
  218. return this._configured;
  219. }
  220. }
  221. function makeSimpleConfigurator(cache) {
  222. function cacheFn(val) {
  223. if (typeof val === "boolean") {
  224. if (val) cache.forever();else cache.never();
  225. return;
  226. }
  227. return cache.using(() => assertSimpleType(val()));
  228. }
  229. cacheFn.forever = () => cache.forever();
  230. cacheFn.never = () => cache.never();
  231. cacheFn.using = cb => cache.using(() => assertSimpleType(cb()));
  232. cacheFn.invalidate = cb => cache.invalidate(() => assertSimpleType(cb()));
  233. return cacheFn;
  234. }
  235. function assertSimpleType(value) {
  236. if ((0, _async.isThenable)(value)) {
  237. throw new Error(`You appear to be using an async cache handler, ` + `which your current version of Babel does not support. ` + `We may add support for this in the future, ` + `but if you're on the most recent version of @babel/core and still ` + `seeing this error, then you'll need to synchronously handle your caching logic.`);
  238. }
  239. if (value != null && typeof value !== "string" && typeof value !== "boolean" && typeof value !== "number") {
  240. throw new Error("Cache keys must be either string, boolean, number, null, or undefined.");
  241. }
  242. return value;
  243. }
  244. class Lock {
  245. constructor() {
  246. this.released = false;
  247. this.promise = void 0;
  248. this._resolve = void 0;
  249. this.promise = new Promise(resolve => {
  250. this._resolve = resolve;
  251. });
  252. }
  253. release(value) {
  254. this.released = true;
  255. this._resolve(value);
  256. }
  257. }
  258. 0 && 0;
  259. //# sourceMappingURL=caching.js.map