{"version":3,"file":"withConcurrentAbruptClose.js","sourceRoot":"","sources":["../../src/execution/withConcurrentAbruptClose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iCAAgC;AAIpD,MAAM,YAAY,GAChB,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAe3D,MAAM,UAAU,yBAAyB,CACvC,SAAwC,EACxC,YAAwC,EACxC,cAAyD,YAAY;IAErE,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,oBAAoB,GAAG,KAAK,CAAC;IAEjC,MAAM,gBAAgB,GAAG,CAAC,EAA8B,EAAE,EAAE;QAC1D,IAAI,SAAS,IAAI,oBAAoB,EAAE,CAAC;YACtC,OAAO;QACT,CAAC;QACD,oBAAoB,GAAG,IAAI,CAAC;QAC5B,OAAO,YAAY,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,OAAO;QACL,CAAC,MAAM,CAAC,aAAa,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI;YACF,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM;iBACH,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;gBAClB,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;oBACnB,SAAS,GAAG,IAAI,CAAC;gBACnB,CAAC;YACH,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC1B,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,CAAC,MAAM;YACV,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;YACrC,OAAO,SAAS,CAAC,MAAM,EAAE,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,KAAe;YACzB,MAAM,gBAAgB,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;YACjD,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;QACD,KAAK,CAAC,CAAC,YAAY,CAAC;YAClB,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAC;YACrC,IAAI,OAAO,SAAS,CAAC,YAAY,CAAC,KAAK,UAAU,EAAE,CAAC;gBAClD,MAAM,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,EAAiC;IAEjC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,EAAE,EAAE,CAAC;QACpB,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YACtB,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YAEzB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;IAET,CAAC;AACH,CAAC","sourcesContent":["import { isPromise } from '../jsutils/isPromise.ts';\nimport type { PromiseOrValue } from '../jsutils/PromiseOrValue.ts';\n\n/* node:coverage ignore next 2 */\nconst asyncDispose: typeof Symbol.asyncDispose =\n  Symbol.asyncDispose ?? Symbol.for('Symbol.asyncDispose');\n\n/**\n * Given an AsyncGenerator and provided functions, return an AsyncGenerator\n * which calls the given functions when the generator is abruptly closed,\n * calling the functions immediately even if the generator is paused.\n *\n * This is useful for allowing return and throw to trigger logic even if the\n * generator is paused on a pending await within a `next()` call (including\n * if that logic can cause that hanging `next()` call to return early).\n *\n * Errors from the provided functions are ignored.\n *\n * @internal\n */\nexport function withConcurrentAbruptClose<T>(\n  generator: AsyncGenerator<T, void, void>,\n  beforeReturn: () => PromiseOrValue<void>,\n  beforeThrow: (error?: unknown) => PromiseOrValue<void> = beforeReturn,\n): AsyncGenerator<T, void, void> {\n  let completed = false;\n  let abruptCloseRequested = false;\n\n  const runAbruptCloseFn = (fn: () => PromiseOrValue<void>) => {\n    if (completed || abruptCloseRequested) {\n      return;\n    }\n    abruptCloseRequested = true;\n    return ignoreErrors(fn);\n  };\n\n  return {\n    [Symbol.asyncIterator]() {\n      return this;\n    },\n    next() {\n      const result = generator.next();\n      result\n        .then((iteration) => {\n          if (iteration.done) {\n            completed = true;\n          }\n        })\n        .catch(() => undefined);\n      return result;\n    },\n    async return() {\n      await runAbruptCloseFn(beforeReturn);\n      return generator.return();\n    },\n    async throw(error?: unknown) {\n      await runAbruptCloseFn(() => beforeThrow(error));\n      return generator.throw(error);\n    },\n    async [asyncDispose]() {\n      await runAbruptCloseFn(beforeReturn);\n      if (typeof generator[asyncDispose] === 'function') {\n        await generator[asyncDispose]();\n      }\n    },\n  };\n}\n\nfunction ignoreErrors(\n  fn: () => PromiseOrValue<unknown>,\n): PromiseOrValue<unknown> {\n  try {\n    const result = fn();\n    if (isPromise(result)) {\n      return result.catch(() => {\n        // ignore error\n      });\n    }\n  } catch {\n    // ignore error\n  }\n}\n"]}