subsiphon
Version:
RxJS subscription manager
1 lines • 9.52 kB
Source Map (JSON)
{"version":3,"file":"index.modern.mjs","sources":["../src/subsiphon.ts","../src/siphon.pipe.ts","../src/siphon.decorator.ts"],"sourcesContent":["import { Subscription } from \"rxjs\";\n\nexport class SubSiphon {\n private subs: Record<PropertyKey, Subscription> = {};\n private index: number = 0;\n\n constructor() {\n return new Proxy(this, {\n set(self: SubSiphon, prop: PropertyKey, sub: any): boolean {\n if (prop in self) {\n if (prop === \"add\") {\n self.add = sub;\n return true;\n }\n console.error(\n `Attempted to add Subscription value to SubSiphon class methods: ${String(prop)} =`,\n sub,\n );\n return false;\n }\n if (!(sub instanceof Subscription)) {\n console.error(`Attempted to add non-Subscription value to SubSiphon: ${String(prop)} =`, sub);\n return false;\n }\n if (prop in self.subs) {\n self.subs[prop].unsubscribe();\n delete self.subs[prop];\n }\n self.subs[prop] = sub;\n\n return true;\n },\n get(self: SubSiphon, prop: PropertyKey): any {\n if (prop in self) {\n return (self as any)[prop];\n }\n if (self.subs.hasOwnProperty(prop)) {\n return self.subs[prop];\n }\n return undefined;\n },\n has: (self: SubSiphon, prop: PropertyKey): boolean => prop in self.subs,\n deleteProperty: (self: SubSiphon, prop: PropertyKey): boolean => {\n if (self.subs[prop]) {\n self.subs[prop].unsubscribe();\n delete self.subs[prop];\n }\n return true;\n },\n ownKeys: (self: SubSiphon): ArrayLike<string | symbol> => Object.keys(self.subs),\n getOwnPropertyDescriptor(self: SubSiphon, prop: PropertyKey) {\n if (prop in self.subs) {\n return {\n configurable: true,\n enumerable: true,\n writable: true,\n value: self.subs[prop],\n };\n }\n return undefined;\n },\n }) as SubSiphon & Record<PropertyKey, Subscription>;\n }\n\n public set add(sub: Subscription) {\n let index = this.index;\n while (index in this.subs) {\n index += 1;\n }\n this.index = index;\n this.subs[index] = sub;\n }\n\n public unsubscribe(): void {\n for (const key in this.subs) {\n this.subs[key].unsubscribe();\n }\n }\n\n public destroy(): void {\n for (const key in this.subs) {\n this.subs[key].unsubscribe();\n delete this.subs[key];\n }\n }\n}\n\nexport function createSubSiphon(): SubSiphon & Record<PropertyKey, Subscription> {\n return new SubSiphon() as any;\n}\n","import { MonoTypeOperatorFunction, Subject, takeUntil } from 'rxjs';\n\nconst destroySubjects = new WeakMap<object, Subject<void>>();\n\nexport function siphon<T>(instance: object): MonoTypeOperatorFunction<T> {\n if (!destroySubjects.has(instance)) {\n const destroy$ = new Subject<void>();\n destroySubjects.set(instance, destroy$);\n\n const originalDestroy = (instance as any).ngOnDestroy;\n\n (instance as any).ngOnDestroy = function () {\n destroy$.next();\n destroy$.complete();\n destroySubjects.delete(instance);\n if (typeof originalDestroy === 'function') {\n originalDestroy.apply(this);\n }\n };\n }\n\n return takeUntil<T>(destroySubjects.get(instance)!);\n}","import { Unsubscribable } from \"rxjs\";\n\nexport interface SiphonOptions {\n include?: string[];\n exclude?: string[];\n log?: boolean;\n}\n\nconst isUnsubscribable = (value: any): value is Unsubscribable => value && typeof value.unsubscribe === \"function\";\n\nconst tryUnsubscribe = (value: any, key: string, options: SiphonOptions): void => {\n if (isUnsubscribable(value)) {\n try {\n value.unsubscribe();\n if (options.log) {\n console.debug(`[Siphon] Unsubscribed: ${key}`);\n }\n } catch (err) {\n console.error(`[Siphon] Error unsubscribing ${key}`, err);\n }\n } else if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n if (isUnsubscribable(item)) {\n try {\n item.unsubscribe();\n if (options.log) {\n console.debug(`[Siphon] Unsubscribed: ${key}[${i}]`);\n }\n } catch (err) {\n console.error(`[Siphon] Error unsubscribing ${key}[${i}]`, err);\n }\n } else if (options.log) {\n console.warn(`[Siphon] Skipped non-unsubscribable item in ${key}[${i}]`);\n }\n }\n } else if (options.log) {\n console.warn(`[Siphon] ${key} is not unsubscribable`);\n }\n};\n\nexport function Siphon(options: SiphonOptions = {}): ClassDecorator {\n return function (target: any) {\n const originalDestroy = target.prototype.ngOnDestroy;\n\n target.prototype.ngOnDestroy = function () {\n const instance = this;\n const allKeys = Object.keys(instance);\n const keysToCheck = options.include\n ? options.include\n : allKeys.filter((key) => !options.exclude?.includes(key));\n\n for (const key of keysToCheck) {\n if (!allKeys.includes(key)) {\n console.warn(`[Siphon] Property \"${key}\" does not exist on instance.`);\n continue;\n }\n\n tryUnsubscribe(instance[key], key, options);\n }\n\n if (typeof originalDestroy === \"function\") {\n originalDestroy.apply(this);\n }\n };\n };\n}\n"],"names":["SubSiphon","constructor","subs","index","Proxy","this","set","self","prop","sub","add","console","error","String","Subscription","unsubscribe","get","hasOwnProperty","has","deleteProperty","ownKeys","Object","keys","getOwnPropertyDescriptor","configurable","enumerable","writable","value","key","destroy","createSubSiphon","destroySubjects","WeakMap","siphon","instance","destroy$","Subject","originalDestroy","ngOnDestroy","next","complete","delete","apply","takeUntil","isUnsubscribable","tryUnsubscribe","options","log","debug","err","Array","isArray","i","length","item","warn","Siphon","target","prototype","allKeys","keysToCheck","include","filter","_options$exclude","exclude","includes"],"mappings":"gEAEa,MAAAA,EAITC,WAAAA,GACI,OAJIC,KAAAA,KAA0C,CAAA,OAC1CC,MAAgB,EAGb,IAAIC,MAAMC,KAAM,CACnBC,IAAGA,CAACC,EAAiBC,EAAmBC,IAChCD,KAAQD,EACK,QAATC,GACAD,EAAKG,IAAMD,GACJ,IAEXE,QAAQC,MACJ,mEAAmEC,OAAOL,OAC1EC,IAEG,GAELA,aAAeK,GAIjBN,KAAQD,EAAKL,OACbK,EAAKL,KAAKM,GAAMO,qBACTR,EAAKL,KAAKM,IAErBD,EAAKL,KAAKM,GAAQC,OAPdE,QAAQC,MAAM,yDAAyDC,OAAOL,OAAWC,IAE7F,GASJO,IAAGA,CAACT,EAAiBC,IACbA,KAAQD,EACAA,EAAaC,GAErBD,EAAKL,KAAKe,eAAeT,GAClBD,EAAKL,KAAKM,QADrB,EAKJU,IAAKA,CAACX,EAAiBC,IAA+BA,KAAQD,EAAKL,KACnEiB,eAAgBA,CAACZ,EAAiBC,KAC1BD,EAAKL,KAAKM,KACVD,EAAKL,KAAKM,GAAMO,qBACTR,EAAKL,KAAKM,KAEd,GAEXY,QAAUb,GAAgDc,OAAOC,KAAKf,EAAKL,MAC3EqB,wBAAAA,CAAyBhB,EAAiBC,GACtC,GAAIA,KAAQD,EAAKL,KACb,MAAO,CACHsB,cAAc,EACdC,YAAY,EACZC,UAAU,EACVC,MAAOpB,EAAKL,KAAKM,GAI7B,GAER,CAEA,OAAWE,CAAID,GACX,IAAIN,EAAQE,KAAKF,MACjB,KAAOA,KAAaE,KAACH,MACjBC,GAAS,EAEbE,KAAKF,MAAQA,EACbE,KAAKH,KAAKC,GAASM,CACvB,CAEOM,WAAAA,GACH,IAAK,MAAMa,KAAWvB,KAACH,KACnBG,KAAKH,KAAK0B,GAAKb,aAEvB,CAEOc,OAAAA,GACH,IAAK,MAAMD,KAAOvB,KAAKH,KACnBG,KAAKH,KAAK0B,GAAKb,0BACHb,KAAK0B,EAEzB,EAGY,SAAAE,IACZ,OAAW,IAAA9B,CACf,CCvFA,MAAM+B,EAAkB,IAAIC,QAEZ,SAAAC,EAAUC,GACtB,IAAKH,EAAgBb,IAAIgB,GAAW,CAChC,MAAMC,EAAW,IAAIC,EACrBL,EAAgBzB,IAAI4B,EAAUC,GAE9B,MAAME,EAAmBH,EAAiBI,YAEzCJ,EAAiBI,YAAc,WAC5BH,EAASI,OACTJ,EAASK,WACTT,EAAgBU,OAAOP,GACQ,mBAApBG,GACPA,EAAgBK,MAAMrC,KAE9B,CACJ,CAEA,OAAOsC,EAAaZ,EAAgBf,IAAIkB,GAC5C,CCdA,MAAMU,EAAoBjB,GAAwCA,GAAsC,mBAAtBA,EAAMZ,YAElF8B,EAAiBA,CAAClB,EAAYC,EAAakB,KAC7C,GAAIF,EAAiBjB,GACjB,IACIA,EAAMZ,cACF+B,EAAQC,KACRpC,QAAQqC,MAAM,0BAA0BpB,IAEhD,CAAE,MAAOqB,GACLtC,QAAQC,MAAM,gCAAgCgB,IAAOqB,EACzD,SACOC,MAAMC,QAAQxB,GACrB,IAAK,IAAIyB,EAAI,EAAGA,EAAIzB,EAAM0B,OAAQD,IAAK,CACnC,MAAME,EAAO3B,EAAMyB,GACnB,GAAIR,EAAiBU,GACjB,IACIA,EAAKvC,cACD+B,EAAQC,KACRpC,QAAQqC,MAAM,0BAA0BpB,KAAOwB,KAEvD,CAAE,MAAOH,GACLtC,QAAQC,MAAM,gCAAgCgB,KAAOwB,KAAMH,EAC/D,MACOH,EAAQC,KACfpC,QAAQ4C,KAAK,+CAA+C3B,KAAOwB,KAE3E,MACON,EAAQC,KACfpC,QAAQ4C,KAAK,YAAY3B,qCAIjB4B,EAAOV,EAAyB,CAAA,GAC5C,gBAAiBW,GACb,MAAMpB,EAAkBoB,EAAOC,UAAUpB,YAEzCmB,EAAOC,UAAUpB,YAAc,WAC3B,MAAMJ,EAAW7B,KACXsD,EAAUtC,OAAOC,KAAKY,GACtB0B,EAAcd,EAAQe,QACtBf,EAAQe,QACRF,EAAQG,OAAQlC,IAAG,IAAAmC,EAAA,eAAKA,EAACjB,EAAQkB,UAARD,EAAiBE,SAASrC,MAEzD,IAAK,MAAMA,KAAOgC,EACTD,EAAQM,SAASrC,GAKtBiB,EAAeX,EAASN,GAAMA,EAAKkB,GAJ/BnC,QAAQ4C,KAAK,sBAAsB3B,kCAOZ,mBAApBS,GACPA,EAAgBK,MAAMrC,KAE9B,CACJ,CACJ"}