CoolFace
Apppublic

AK-21/Graphite-Industrial-Intelligence

sourceHugging Faceupdated 3mo agoView on Hugging Face
0likes
index.js207 linesDownload Raw Back to lib
1// To do: remove `void`s2// To do: remove `null` from output of our APIs, allow it as user APIs.3 4/**5 * @typedef {(error?: Error | null | undefined, ...output: Array<any>) => void} Callback6 *   Callback.7 *8 * @typedef {(...input: Array<any>) => any} Middleware9 *   Ware.10 *11 * @typedef Pipeline12 *   Pipeline.13 * @property {Run} run14 *   Run the pipeline.15 * @property {Use} use16 *   Add middleware.17 *18 * @typedef {(...input: Array<any>) => void} Run19 *   Call all middleware.20 *21 *   Calls `done` on completion with either an error or the output of the22 *   last middleware.23 *24 *   > 👉 **Note**: as the length of input defines whether async functions get a25 *   > `next` function,26 *   > it’s recommended to keep `input` at one value normally.27 28 *29 * @typedef {(fn: Middleware) => Pipeline} Use30 *   Add middleware.31 */32 33/**34 * Create new middleware.35 *36 * @returns {Pipeline}37 *   Pipeline.38 */39export function trough() {40  /** @type {Array<Middleware>} */41  const fns = []42  /** @type {Pipeline} */43  const pipeline = {run, use}44 45  return pipeline46 47  /** @type {Run} */48  function run(...values) {49    let middlewareIndex = -150    /** @type {Callback} */51    const callback = values.pop()52 53    if (typeof callback !== 'function') {54      throw new TypeError('Expected function as last argument, not ' + callback)55    }56 57    next(null, ...values)58 59    /**60     * Run the next `fn`, or we’re done.61     *62     * @param {Error | null | undefined} error63     * @param {Array<any>} output64     */65    function next(error, ...output) {66      const fn = fns[++middlewareIndex]67      let index = -168 69      if (error) {70        callback(error)71        return72      }73 74      // Copy non-nullish input into values.75      while (++index < values.length) {76        if (output[index] === null || output[index] === undefined) {77          output[index] = values[index]78        }79      }80 81      // Save the newly created `output` for the next call.82      values = output83 84      // Next or done.85      if (fn) {86        wrap(fn, next)(...output)87      } else {88        callback(null, ...output)89      }90    }91  }92 93  /** @type {Use} */94  function use(middelware) {95    if (typeof middelware !== 'function') {96      throw new TypeError(97        'Expected `middelware` to be a function, not ' + middelware98      )99    }100 101    fns.push(middelware)102    return pipeline103  }104}105 106/**107 * Wrap `middleware` into a uniform interface.108 *109 * You can pass all input to the resulting function.110 * `callback` is then called with the output of `middleware`.111 *112 * If `middleware` accepts more arguments than the later given in input,113 * an extra `done` function is passed to it after that input,114 * which must be called by `middleware`.115 *116 * The first value in `input` is the main input value.117 * All other input values are the rest input values.118 * The values given to `callback` are the input values,119 * merged with every non-nullish output value.120 *121 * * if `middleware` throws an error,122 *   returns a promise that is rejected,123 *   or calls the given `done` function with an error,124 *   `callback` is called with that error125 * * if `middleware` returns a value or returns a promise that is resolved,126 *   that value is the main output value127 * * if `middleware` calls `done`,128 *   all non-nullish values except for the first one (the error) overwrite the129 *   output values130 *131 * @param {Middleware} middleware132 *   Function to wrap.133 * @param {Callback} callback134 *   Callback called with the output of `middleware`.135 * @returns {Run}136 *   Wrapped middleware.137 */138export function wrap(middleware, callback) {139  /** @type {boolean} */140  let called141 142  return wrapped143 144  /**145   * Call `middleware`.146   * @this {any}147   * @param {Array<any>} parameters148   * @returns {void}149   */150  function wrapped(...parameters) {151    const fnExpectsCallback = middleware.length > parameters.length152    /** @type {any} */153    let result154 155    if (fnExpectsCallback) {156      parameters.push(done)157    }158 159    try {160      result = middleware.apply(this, parameters)161    } catch (error) {162      const exception = /** @type {Error} */ (error)163 164      // Well, this is quite the pickle.165      // `middleware` received a callback and called it synchronously, but that166      // threw an error.167      // The only thing left to do is to throw the thing instead.168      if (fnExpectsCallback && called) {169        throw exception170      }171 172      return done(exception)173    }174 175    if (!fnExpectsCallback) {176      if (result && result.then && typeof result.then === 'function') {177        result.then(then, done)178      } else if (result instanceof Error) {179        done(result)180      } else {181        then(result)182      }183    }184  }185 186  /**187   * Call `callback`, only once.188   *189   * @type {Callback}190   */191  function done(error, ...output) {192    if (!called) {193      called = true194      callback(error, ...output)195    }196  }197 198  /**199   * Call `done` with one value.200   *201   * @param {any} [value]202   */203  function then(value) {204    done(null, value)205  }206}207