CoolFace
Apppublic

sourav-das/stem-separator

sourceHugging Facemitupdated 6mo agoView on Hugging Face
3likes
index.js374 linesDownload Raw Back to gensync
1"use strict";2 3// These use the global symbol registry so that multiple copies of this4// library can work together in case they are not deduped.5const GENSYNC_START = Symbol.for("gensync:v1:start");6const GENSYNC_SUSPEND = Symbol.for("gensync:v1:suspend");7 8const GENSYNC_EXPECTED_START = "GENSYNC_EXPECTED_START";9const GENSYNC_EXPECTED_SUSPEND = "GENSYNC_EXPECTED_SUSPEND";10const GENSYNC_OPTIONS_ERROR = "GENSYNC_OPTIONS_ERROR";11const GENSYNC_RACE_NONEMPTY = "GENSYNC_RACE_NONEMPTY";12const GENSYNC_ERRBACK_NO_CALLBACK = "GENSYNC_ERRBACK_NO_CALLBACK";13 14module.exports = Object.assign(15  function gensync(optsOrFn) {16    let genFn = optsOrFn;17    if (typeof optsOrFn !== "function") {18      genFn = newGenerator(optsOrFn);19    } else {20      genFn = wrapGenerator(optsOrFn);21    }22 23    return Object.assign(genFn, makeFunctionAPI(genFn));24  },25  {26    all: buildOperation({27      name: "all",28      arity: 1,29      sync: function(args) {30        const items = Array.from(args[0]);31        return items.map(item => evaluateSync(item));32      },33      async: function(args, resolve, reject) {34        const items = Array.from(args[0]);35 36        if (items.length === 0) {37          Promise.resolve().then(() => resolve([]));38          return;39        }40 41        let count = 0;42        const results = items.map(() => undefined);43        items.forEach((item, i) => {44          evaluateAsync(45            item,46            val => {47              results[i] = val;48              count += 1;49 50              if (count === results.length) resolve(results);51            },52            reject53          );54        });55      },56    }),57    race: buildOperation({58      name: "race",59      arity: 1,60      sync: function(args) {61        const items = Array.from(args[0]);62        if (items.length === 0) {63          throw makeError("Must race at least 1 item", GENSYNC_RACE_NONEMPTY);64        }65 66        return evaluateSync(items[0]);67      },68      async: function(args, resolve, reject) {69        const items = Array.from(args[0]);70        if (items.length === 0) {71          throw makeError("Must race at least 1 item", GENSYNC_RACE_NONEMPTY);72        }73 74        for (const item of items) {75          evaluateAsync(item, resolve, reject);76        }77      },78    }),79  }80);81 82/**83 * Given a generator function, return the standard API object that executes84 * the generator and calls the callbacks.85 */86function makeFunctionAPI(genFn) {87  const fns = {88    sync: function(...args) {89      return evaluateSync(genFn.apply(this, args));90    },91    async: function(...args) {92      return new Promise((resolve, reject) => {93        evaluateAsync(genFn.apply(this, args), resolve, reject);94      });95    },96    errback: function(...args) {97      const cb = args.pop();98      if (typeof cb !== "function") {99        throw makeError(100          "Asynchronous function called without callback",101          GENSYNC_ERRBACK_NO_CALLBACK102        );103      }104 105      let gen;106      try {107        gen = genFn.apply(this, args);108      } catch (err) {109        cb(err);110        return;111      }112 113      evaluateAsync(gen, val => cb(undefined, val), err => cb(err));114    },115  };116  return fns;117}118 119function assertTypeof(type, name, value, allowUndefined) {120  if (121    typeof value === type ||122    (allowUndefined && typeof value === "undefined")123  ) {124    return;125  }126 127  let msg;128  if (allowUndefined) {129    msg = `Expected opts.${name} to be either a ${type}, or undefined.`;130  } else {131    msg = `Expected opts.${name} to be a ${type}.`;132  }133 134  throw makeError(msg, GENSYNC_OPTIONS_ERROR);135}136function makeError(msg, code) {137  return Object.assign(new Error(msg), { code });138}139 140/**141 * Given an options object, return a new generator that dispatches the142 * correct handler based on sync or async execution.143 */144function newGenerator({ name, arity, sync, async, errback }) {145  assertTypeof("string", "name", name, true /* allowUndefined */);146  assertTypeof("number", "arity", arity, true /* allowUndefined */);147  assertTypeof("function", "sync", sync);148  assertTypeof("function", "async", async, true /* allowUndefined */);149  assertTypeof("function", "errback", errback, true /* allowUndefined */);150  if (async && errback) {151    throw makeError(152      "Expected one of either opts.async or opts.errback, but got _both_.",153      GENSYNC_OPTIONS_ERROR154    );155  }156 157  if (typeof name !== "string") {158    let fnName;159    if (errback && errback.name && errback.name !== "errback") {160      fnName = errback.name;161    }162    if (async && async.name && async.name !== "async") {163      fnName = async.name.replace(/Async$/, "");164    }165    if (sync && sync.name && sync.name !== "sync") {166      fnName = sync.name.replace(/Sync$/, "");167    }168 169    if (typeof fnName === "string") {170      name = fnName;171    }172  }173 174  if (typeof arity !== "number") {175    arity = sync.length;176  }177 178  return buildOperation({179    name,180    arity,181    sync: function(args) {182      return sync.apply(this, args);183    },184    async: function(args, resolve, reject) {185      if (async) {186        async.apply(this, args).then(resolve, reject);187      } else if (errback) {188        errback.call(this, ...args, (err, value) => {189          if (err == null) resolve(value);190          else reject(err);191        });192      } else {193        resolve(sync.apply(this, args));194      }195    },196  });197}198 199function wrapGenerator(genFn) {200  return setFunctionMetadata(genFn.name, genFn.length, function(...args) {201    return genFn.apply(this, args);202  });203}204 205function buildOperation({ name, arity, sync, async }) {206  return setFunctionMetadata(name, arity, function*(...args) {207    const resume = yield GENSYNC_START;208    if (!resume) {209      // Break the tail call to avoid a bug in V8 v6.X with --harmony enabled.210      const res = sync.call(this, args);211      return res;212    }213 214    let result;215    try {216      async.call(217        this,218        args,219        value => {220          if (result) return;221 222          result = { value };223          resume();224        },225        err => {226          if (result) return;227 228          result = { err };229          resume();230        }231      );232    } catch (err) {233      result = { err };234      resume();235    }236 237    // Suspend until the callbacks run. Will resume synchronously if the238    // callback was already called.239    yield GENSYNC_SUSPEND;240 241    if (result.hasOwnProperty("err")) {242      throw result.err;243    }244 245    return result.value;246  });247}248 249function evaluateSync(gen) {250  let value;251  while (!({ value } = gen.next()).done) {252    assertStart(value, gen);253  }254  return value;255}256 257function evaluateAsync(gen, resolve, reject) {258  (function step() {259    try {260      let value;261      while (!({ value } = gen.next()).done) {262        assertStart(value, gen);263 264        // If this throws, it is considered to have broken the contract265        // established for async handlers. If these handlers are called266        // synchronously, it is also considered bad behavior.267        let sync = true;268        let didSyncResume = false;269        const out = gen.next(() => {270          if (sync) {271            didSyncResume = true;272          } else {273            step();274          }275        });276        sync = false;277 278        assertSuspend(out, gen);279 280        if (!didSyncResume) {281          // Callback wasn't called synchronously, so break out of the loop282          // and let it call 'step' later.283          return;284        }285      }286 287      return resolve(value);288    } catch (err) {289      return reject(err);290    }291  })();292}293 294function assertStart(value, gen) {295  if (value === GENSYNC_START) return;296 297  throwError(298    gen,299    makeError(300      `Got unexpected yielded value in gensync generator: ${JSON.stringify(301        value302      )}. Did you perhaps mean to use 'yield*' instead of 'yield'?`,303      GENSYNC_EXPECTED_START304    )305  );306}307function assertSuspend({ value, done }, gen) {308  if (!done && value === GENSYNC_SUSPEND) return;309 310  throwError(311    gen,312    makeError(313      done314        ? "Unexpected generator completion. If you get this, it is probably a gensync bug."315        : `Expected GENSYNC_SUSPEND, got ${JSON.stringify(316            value317          )}. If you get this, it is probably a gensync bug.`,318      GENSYNC_EXPECTED_SUSPEND319    )320  );321}322 323function throwError(gen, err) {324  // Call `.throw` so that users can step in a debugger to easily see which325  // 'yield' passed an unexpected value. If the `.throw` call didn't throw326  // back to the generator, we explicitly do it to stop the error327  // from being swallowed by user code try/catches.328  if (gen.throw) gen.throw(err);329  throw err;330}331 332function isIterable(value) {333  return (334    !!value &&335    (typeof value === "object" || typeof value === "function") &&336    !value[Symbol.iterator]337  );338}339 340function setFunctionMetadata(name, arity, fn) {341  if (typeof name === "string") {342    // This should always work on the supported Node versions, but for the343    // sake of users that are compiling to older versions, we check for344    // configurability so we don't throw.345    const nameDesc = Object.getOwnPropertyDescriptor(fn, "name");346    if (!nameDesc || nameDesc.configurable) {347      Object.defineProperty(348        fn,349        "name",350        Object.assign(nameDesc || {}, {351          configurable: true,352          value: name,353        })354      );355    }356  }357 358  if (typeof arity === "number") {359    const lengthDesc = Object.getOwnPropertyDescriptor(fn, "length");360    if (!lengthDesc || lengthDesc.configurable) {361      Object.defineProperty(362        fn,363        "length",364        Object.assign(lengthDesc || {}, {365          configurable: true,366          value: arity,367        })368      );369    }370  }371 372  return fn;373}374