index.cjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. 'use strict';
  2. const GET_IS_ASYNC = Symbol.for("quansync.getIsAsync");
  3. class QuansyncError extends Error {
  4. constructor(message = "Unexpected promise in sync context") {
  5. super(message);
  6. this.name = "QuansyncError";
  7. }
  8. }
  9. function isThenable(value) {
  10. return value && typeof value === "object" && typeof value.then === "function";
  11. }
  12. function isQuansyncGenerator(value) {
  13. return value && typeof value === "object" && typeof value[Symbol.iterator] === "function" && "__quansync" in value;
  14. }
  15. function fromObject(options) {
  16. const generator = function* (...args) {
  17. const isAsync = yield GET_IS_ASYNC;
  18. if (isAsync)
  19. return yield options.async.apply(this, args);
  20. return options.sync.apply(this, args);
  21. };
  22. function fn(...args) {
  23. const iter = generator.apply(this, args);
  24. iter.then = (...thenArgs) => options.async.apply(this, args).then(...thenArgs);
  25. iter.__quansync = true;
  26. return iter;
  27. }
  28. fn.sync = options.sync;
  29. fn.async = options.async;
  30. return fn;
  31. }
  32. function fromPromise(promise) {
  33. return fromObject({
  34. async: () => Promise.resolve(promise),
  35. sync: () => {
  36. if (isThenable(promise))
  37. throw new QuansyncError();
  38. return promise;
  39. }
  40. });
  41. }
  42. function unwrapYield(value, isAsync) {
  43. if (value === GET_IS_ASYNC)
  44. return isAsync;
  45. if (isQuansyncGenerator(value))
  46. return isAsync ? iterateAsync(value) : iterateSync(value);
  47. if (!isAsync && isThenable(value))
  48. throw new QuansyncError();
  49. return value;
  50. }
  51. const DEFAULT_ON_YIELD = (value) => value;
  52. function iterateSync(generator, onYield = DEFAULT_ON_YIELD) {
  53. let current = generator.next();
  54. while (!current.done) {
  55. try {
  56. current = generator.next(unwrapYield(onYield(current.value, false)));
  57. } catch (err) {
  58. current = generator.throw(err);
  59. }
  60. }
  61. return unwrapYield(current.value);
  62. }
  63. async function iterateAsync(generator, onYield = DEFAULT_ON_YIELD) {
  64. let current = generator.next();
  65. while (!current.done) {
  66. try {
  67. current = generator.next(await unwrapYield(onYield(current.value, true), true));
  68. } catch (err) {
  69. current = generator.throw(err);
  70. }
  71. }
  72. return current.value;
  73. }
  74. function fromGeneratorFn(generatorFn, options) {
  75. return fromObject({
  76. name: generatorFn.name,
  77. async(...args) {
  78. return iterateAsync(generatorFn.apply(this, args), options?.onYield);
  79. },
  80. sync(...args) {
  81. return iterateSync(generatorFn.apply(this, args), options?.onYield);
  82. }
  83. });
  84. }
  85. function quansync(input, options) {
  86. if (isThenable(input))
  87. return fromPromise(input);
  88. if (typeof input === "function")
  89. return fromGeneratorFn(input, options);
  90. else
  91. return fromObject(input);
  92. }
  93. function toGenerator(promise) {
  94. if (isQuansyncGenerator(promise))
  95. return promise;
  96. return fromPromise(promise)();
  97. }
  98. const getIsAsync = quansync({
  99. async: () => Promise.resolve(true),
  100. sync: () => false
  101. });
  102. exports.GET_IS_ASYNC = GET_IS_ASYNC;
  103. exports.QuansyncError = QuansyncError;
  104. exports.getIsAsync = getIsAsync;
  105. exports.quansync = quansync;
  106. exports.toGenerator = toGenerator;