( integration: Base, extendedIntegration: Extended, )
| 204 | * ``` |
| 205 | */ |
| 206 | export function extendIntegration<Base extends Integration, Extended extends Partial<IntegrationWithOtherProperties>>( |
| 207 | integration: Base, |
| 208 | extendedIntegration: Extended, |
| 209 | ): ExtendedIntegration<Base, Extended> { |
| 210 | // The extension overrides the base for any shared key (object spread + the wrapping below), so the |
| 211 | // result type drops the overridden base keys rather than intersecting them — `Base & Extended` would |
| 212 | // wrongly intersect shared keys (e.g. a re-typed property collapses to `never`). |
| 213 | const wrappedIntegration = { |
| 214 | ...integration, |
| 215 | ...extendedIntegration, |
| 216 | } as ExtendedIntegration<Base, Extended>; |
| 217 | |
| 218 | // Make sure that functions that are extended also call the base functions, if defined |
| 219 | // oxlint-disable-next-line guard-for-in |
| 220 | for (const key in extendedIntegration) { |
| 221 | const baseValue = integration[key as keyof Base]; |
| 222 | const extendedValue = extendedIntegration[key]; |
| 223 | |
| 224 | type ValueType = typeof extendedValue; |
| 225 | |
| 226 | if (typeof baseValue === 'function' && typeof extendedValue === 'function') { |
| 227 | const wrappedFunction = new Proxy(baseValue, { |
| 228 | apply: (target, thisArg, args) => { |
| 229 | Reflect.apply(target, thisArg, args); |
| 230 | return Reflect.apply(extendedValue, thisArg, args); |
| 231 | }, |
| 232 | }) as ValueType; |
| 233 | |
| 234 | // We know this is OK, but typescript does not properly narrow/infer types here |
| 235 | // so instead of casting the wrappedFunction to some complicated type, we just make clear that we simply overwrite this |
| 236 | (wrappedIntegration as Record<string, unknown>)[key] = wrappedFunction; |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | return wrappedIntegration; |
| 241 | } |
no test coverage detected