{"version":3,"sources":["../../../../../../src/server/route-matcher-providers/dev/helpers/file-reader/batched-file-reader.ts"],"sourcesContent":["import type { FileReader } from './file-reader'\n\ninterface FileReaderBatch {\n  completed: boolean\n  directories: Array<string>\n  callbacks: Array<{\n    resolve: (value: ReadonlyArray<string>) => void\n    reject: (err: any) => void\n  }>\n}\n\n/**\n * CachedFileReader will deduplicate requests made to the same folder structure\n * to scan for files.\n */\nexport class BatchedFileReader implements FileReader {\n  private batch?: FileReaderBatch\n\n  constructor(private readonly reader: FileReader) {}\n\n  // This allows us to schedule the batches after all the promises associated\n  // with loading files.\n  private schedulePromise?: Promise<void>\n  private schedule(callback: Function) {\n    if (!this.schedulePromise) {\n      this.schedulePromise = Promise.resolve()\n    }\n    this.schedulePromise.then(() => {\n      process.nextTick(callback)\n    })\n  }\n\n  private getOrCreateBatch(): FileReaderBatch {\n    // If there is an existing batch and it's not completed, then reuse it.\n    if (this.batch && !this.batch.completed) {\n      return this.batch\n    }\n\n    const batch: FileReaderBatch = {\n      completed: false,\n      directories: [],\n      callbacks: [],\n    }\n\n    this.batch = batch\n\n    this.schedule(async () => {\n      batch.completed = true\n      if (batch.directories.length === 0) return\n\n      // Collect all the results for each of the directories. If any error\n      // occurs, send the results back to the loaders.\n      let values: ReadonlyArray<ReadonlyArray<string> | Error>\n      try {\n        values = await this.load(batch.directories)\n      } catch (err) {\n        // Reject all the callbacks.\n        for (const { reject } of batch.callbacks) {\n          reject(err)\n        }\n        return\n      }\n\n      // Loop over all the callbacks and send them their results.\n      for (let i = 0; i < batch.callbacks.length; i++) {\n        const value = values[i]\n        if (value instanceof Error) {\n          batch.callbacks[i].reject(value)\n        } else {\n          batch.callbacks[i].resolve(value)\n        }\n      }\n    })\n\n    return batch\n  }\n\n  private async load(\n    directories: ReadonlyArray<string>\n  ): Promise<ReadonlyArray<ReadonlyArray<string> | Error>> {\n    // Make a unique array of directories. This is what lets us de-duplicate\n    // loads for the same directory.\n    const unique = [...new Set(directories)]\n\n    const results = await Promise.all(\n      unique.map(async (directory) => {\n        let files: ReadonlyArray<string> | undefined\n        let error: Error | undefined\n        try {\n          files = await this.reader.read(directory)\n        } catch (err) {\n          if (err instanceof Error) error = err\n        }\n\n        return { directory, files, error }\n      })\n    )\n\n    return directories.map((directory) => {\n      const found = results.find((result) => result.directory === directory)\n      if (!found) return []\n\n      if (found.files) return found.files\n      if (found.error) return found.error\n\n      return []\n    })\n  }\n\n  public async read(dir: string): Promise<ReadonlyArray<string>> {\n    // Get or create a new file reading batch.\n    const batch = this.getOrCreateBatch()\n\n    // Push this directory into the batch to resolve.\n    batch.directories.push(dir)\n\n    // Push the promise handles into the batch (under the same index) so it can\n    // be resolved later when it's scheduled.\n    const promise = new Promise<ReadonlyArray<string>>((resolve, reject) => {\n      batch.callbacks.push({ resolve, reject })\n    })\n\n    return promise\n  }\n}\n"],"names":["BatchedFileReader","constructor","reader","schedule","callback","schedulePromise","Promise","resolve","then","process","nextTick","getOrCreateBatch","batch","completed","directories","callbacks","length","values","load","err","reject","i","value","Error","unique","Set","results","all","map","directory","files","error","read","found","find","result","dir","push","promise"],"mappings":";;;;+BAeaA;;;eAAAA;;;AAAN,MAAMA;IAGXC,YAAY,AAAiBC,MAAkB,CAAE;aAApBA,SAAAA;IAAqB;IAK1CC,SAASC,QAAkB,EAAE;QACnC,IAAI,CAAC,IAAI,CAACC,eAAe,EAAE;YACzB,IAAI,CAACA,eAAe,GAAGC,QAAQC,OAAO;QACxC;QACA,IAAI,CAACF,eAAe,CAACG,IAAI,CAAC;YACxBC,QAAQC,QAAQ,CAACN;QACnB;IACF;IAEQO,mBAAoC;QAC1C,uEAAuE;QACvE,IAAI,IAAI,CAACC,KAAK,IAAI,CAAC,IAAI,CAACA,KAAK,CAACC,SAAS,EAAE;YACvC,OAAO,IAAI,CAACD,KAAK;QACnB;QAEA,MAAMA,QAAyB;YAC7BC,WAAW;YACXC,aAAa,EAAE;YACfC,WAAW,EAAE;QACf;QAEA,IAAI,CAACH,KAAK,GAAGA;QAEb,IAAI,CAACT,QAAQ,CAAC;YACZS,MAAMC,SAAS,GAAG;YAClB,IAAID,MAAME,WAAW,CAACE,MAAM,KAAK,GAAG;YAEpC,oEAAoE;YACpE,gDAAgD;YAChD,IAAIC;YACJ,IAAI;gBACFA,SAAS,MAAM,IAAI,CAACC,IAAI,CAACN,MAAME,WAAW;YAC5C,EAAE,OAAOK,KAAK;gBACZ,4BAA4B;gBAC5B,KAAK,MAAM,EAAEC,MAAM,EAAE,IAAIR,MAAMG,SAAS,CAAE;oBACxCK,OAAOD;gBACT;gBACA;YACF;YAEA,2DAA2D;YAC3D,IAAK,IAAIE,IAAI,GAAGA,IAAIT,MAAMG,SAAS,CAACC,MAAM,EAAEK,IAAK;gBAC/C,MAAMC,QAAQL,MAAM,CAACI,EAAE;gBACvB,IAAIC,iBAAiBC,OAAO;oBAC1BX,MAAMG,SAAS,CAACM,EAAE,CAACD,MAAM,CAACE;gBAC5B,OAAO;oBACLV,MAAMG,SAAS,CAACM,EAAE,CAACd,OAAO,CAACe;gBAC7B;YACF;QACF;QAEA,OAAOV;IACT;IAEA,MAAcM,KACZJ,WAAkC,EACqB;QACvD,wEAAwE;QACxE,gCAAgC;QAChC,MAAMU,SAAS;eAAI,IAAIC,IAAIX;SAAa;QAExC,MAAMY,UAAU,MAAMpB,QAAQqB,GAAG,CAC/BH,OAAOI,GAAG,CAAC,OAAOC;YAChB,IAAIC;YACJ,IAAIC;YACJ,IAAI;gBACFD,QAAQ,MAAM,IAAI,CAAC5B,MAAM,CAAC8B,IAAI,CAACH;YACjC,EAAE,OAAOV,KAAK;gBACZ,IAAIA,eAAeI,OAAOQ,QAAQZ;YACpC;YAEA,OAAO;gBAAEU;gBAAWC;gBAAOC;YAAM;QACnC;QAGF,OAAOjB,YAAYc,GAAG,CAAC,CAACC;YACtB,MAAMI,QAAQP,QAAQQ,IAAI,CAAC,CAACC,SAAWA,OAAON,SAAS,KAAKA;YAC5D,IAAI,CAACI,OAAO,OAAO,EAAE;YAErB,IAAIA,MAAMH,KAAK,EAAE,OAAOG,MAAMH,KAAK;YACnC,IAAIG,MAAMF,KAAK,EAAE,OAAOE,MAAMF,KAAK;YAEnC,OAAO,EAAE;QACX;IACF;IAEA,MAAaC,KAAKI,GAAW,EAAkC;QAC7D,0CAA0C;QAC1C,MAAMxB,QAAQ,IAAI,CAACD,gBAAgB;QAEnC,iDAAiD;QACjDC,MAAME,WAAW,CAACuB,IAAI,CAACD;QAEvB,2EAA2E;QAC3E,yCAAyC;QACzC,MAAME,UAAU,IAAIhC,QAA+B,CAACC,SAASa;YAC3DR,MAAMG,SAAS,CAACsB,IAAI,CAAC;gBAAE9B;gBAASa;YAAO;QACzC;QAEA,OAAOkB;IACT;AACF","ignoreList":[0]}