{"version":3,"sources":["../src/createChainOfResponsibility.tsx","../src/isReactComponent.ts"],"sourcesContent":["import { applyMiddleware } from 'handler-chain';\nimport React, {\n  createContext,\n  isValidElement,\n  memo,\n  useCallback,\n  useContext,\n  useMemo,\n  type ComponentType,\n  type PropsWithChildren\n} from 'react';\n\nimport isReactComponent from './isReactComponent.ts';\nimport { type ComponentEnhancer, type ComponentMiddleware } from './types.ts';\n\n// TODO: Simplify to ComponentType<Props> | undefined.\ntype ResultComponent<Props> = ComponentType<Props> | false | null | undefined;\n\ntype UseBuildComponentCallbackOptions<Props> = {\n  fallbackComponent?: ResultComponent<Props> | undefined;\n};\n\ninterface UseBuildComponentCallback<Request, Props> {\n  (request: Request, options?: undefined | UseBuildComponentCallbackOptions<Props>): ComponentType<Props> | undefined;\n}\n\ntype ProviderContext<Request, Props> = {\n  get enhancer(): ComponentEnhancer<Request, Props> | undefined;\n  useBuildComponentCallback: UseBuildComponentCallback<Request, Props>;\n};\n\ntype ProviderProps<Request, Props, Init> = PropsWithChildren<{\n  middleware: readonly ComponentMiddleware<Request, Props, Init>[];\n}> &\n  (Init extends never | void\n    ? { readonly init?: undefined }\n    : Init extends undefined | void\n      ? { readonly init?: Init }\n      : { readonly init: Init });\n\ntype ProxyProps<Request, Props extends object> = Props & {\n  readonly fallbackComponent?: ComponentType<Props> | undefined;\n  readonly request: Request;\n};\n\ntype CreateChainOfResponsibilityOptions = {\n  /**\n   * Allows a middleware to pass another request object when calling its next middleware. Default is false.\n   *\n   * However, middleware could modify the request object before calling its next middleware. It is recommended\n   * to use Object.freeze() to prevent middleware from modifying the request object.\n   */\n  readonly passModifiedRequest?: boolean | undefined;\n};\n\ntype AsMiddlewareProps<Request, Props, Init> = {\n  readonly init: Init;\n  readonly Next: ComponentType<Partial<Props>>;\n  readonly request: Request;\n};\n\ntype AsMiddlewareComponentProps<Request, Props, Init> = Props & {\n  readonly middleware: AsMiddlewareProps<Request, Props, Init>;\n};\n\ntype ChainOfResponsibility<Request, Props extends object, Init> = {\n  readonly asMiddleware: (\n    middlewareComponent: ComponentType<AsMiddlewareComponentProps<Request, Props, Init>>\n  ) => ComponentMiddleware<Request, Props, Init>;\n  readonly Provider: ComponentType<ProviderProps<Request, Props, Init>>;\n  readonly Proxy: ComponentType<ProxyProps<Request, Props>>;\n  readonly types: {\n    readonly init: Init;\n    readonly middleware: ComponentMiddleware<Request, Props, Init>;\n    readonly middlewareComponentProps: AsMiddlewareComponentProps<Request, Props, Init>;\n    readonly props: Props;\n    readonly proxyProps: ProxyProps<Request, Props>;\n    readonly request: Request;\n  };\n  readonly useBuildComponentCallback: () => UseBuildComponentCallback<Request, Props>;\n};\n\nfunction createChainOfResponsibility<Request = void, Props extends object = { readonly children?: never }, Init = void>(\n  options: CreateChainOfResponsibilityOptions = {}\n): ChainOfResponsibility<Request, Props, Init> {\n  const defaultUseBuildComponentCallback: ProviderContext<Request, Props> = {\n    get enhancer() {\n      return undefined;\n    },\n    useBuildComponentCallback(_request, options): ComponentType<Props> {\n      if (!options?.fallbackComponent) {\n        throw new Error('This component/hook cannot be used outside of its corresponding <Provider>');\n      }\n\n      return options.fallbackComponent;\n    }\n  };\n\n  const context = createContext<ProviderContext<Request, Props>>(defaultUseBuildComponentCallback);\n\n  function ChainOfResponsibilityProvider({ children, init, middleware }: ProviderProps<Request, Props, Init>) {\n    // TODO: Related to https://github.com/microsoft/TypeScript/issues/17002.\n    //       typescript@5.2.2 has a bug, Array.isArray() is a type predicate but only works with mutable array, not readonly array.\n    //       After removing \"as unknown\", `middleware` on the next line become `any[]`.\n    if (!Array.isArray(middleware as unknown) || middleware.some(middleware => typeof middleware !== 'function')) {\n      throw new Error('middleware prop must be an array of functions');\n    }\n\n    const patchedMiddleware: readonly ComponentMiddleware<Request, Props, Init>[] = Object.freeze(\n      middleware\n        ? middleware.map(fn => (init: Init) => {\n            const enhancer = fn(init);\n\n            return (next: (request: Request) => ComponentType<Props> | false | null | undefined) =>\n              (originalRequest: Request) => {\n                // False positive: although we did not re-assign the variable from true, it was initialized as undefined.\n                // eslint-disable-next-line prefer-const\n                let hasReturned: boolean;\n\n                const returnValue = enhancer(nextRequest => {\n                  if (hasReturned) {\n                    throw new Error('next() cannot be called after the function had returned synchronously');\n                  }\n\n                  !options.passModifiedRequest &&\n                    nextRequest !== originalRequest &&\n                    console.warn(\n                      'react-chain-of-responsibility: \"options.passModifiedRequest\" must be set to true to pass a different request object to next().'\n                    );\n\n                  return next(options.passModifiedRequest ? nextRequest : originalRequest);\n                })(originalRequest);\n\n                hasReturned = true;\n\n                if (isValidElement(returnValue)) {\n                  throw new Error('middleware must not return React element directly');\n                } else if (\n                  returnValue !== false &&\n                  returnValue !== null &&\n                  typeof returnValue !== 'undefined' &&\n                  !isReactComponent(returnValue)\n                ) {\n                  throw new Error(\n                    'middleware must return false, null, undefined, function component, or class component'\n                  );\n                }\n\n                return returnValue;\n              };\n          })\n        : []\n    );\n\n    const { enhancer: parentEnhancer } = useContext(context);\n\n    const enhancer = useMemo(\n      () =>\n        // We are reversing because it is easier to read:\n        // - With reverse, [a, b, c] will become a(b(c(fn)))\n        // - Without reverse, [a, b, c] will become c(b(a(fn)))\n        applyMiddleware<ResultComponent<Props>, Request, Init>(\n          ...[...patchedMiddleware, ...(parentEnhancer ? [() => parentEnhancer] : [])]\n        )(init as Init),\n      [init, middleware, parentEnhancer]\n    );\n\n    const useBuildComponentCallback = useCallback<UseBuildComponentCallback<Request, Props>>(\n      (request, options = {}) => enhancer(() => options.fallbackComponent)(request) || undefined,\n      [enhancer]\n    );\n\n    const contextValue = useMemo<ProviderContext<Request, Props>>(\n      () => ({ enhancer, useBuildComponentCallback }),\n      [enhancer, useBuildComponentCallback]\n    );\n\n    return <context.Provider value={contextValue}>{children}</context.Provider>;\n  }\n\n  const useBuildComponentCallback = () => useContext(context).useBuildComponentCallback;\n\n  function Proxy({ fallbackComponent, request, ...props }: ProxyProps<Request, Props>) {\n    const enhancer = useBuildComponentCallback();\n\n    const Component = enhancer(request as Request, { fallbackComponent });\n\n    return Component ? <Component {...(props as Props)} /> : null;\n  }\n\n  const asMiddleware: (\n    middlewareComponent: ComponentType<AsMiddlewareComponentProps<Request, Props, Init>>\n  ) => ComponentMiddleware<Request, Props, Init> =\n    (\n      MiddlewareComponent: ComponentType<AsMiddlewareComponentProps<Request, Props, Init>>\n    ): ComponentMiddleware<Request, Props, Init> =>\n    init =>\n    next =>\n    request => {\n      const RawNextComponent = next(request);\n\n      // TODO: Can we pre-build this component during init?\n      const MiddlewareOf = (props: Props) => {\n        const middleware = useMemo(\n          () =>\n            Object.freeze({\n              init,\n              Next: memo<Partial<Props>>(\n                RawNextComponent\n                  ? (overridingProps: Partial<Props>) => <RawNextComponent {...props} {...overridingProps} />\n                  : () => null\n              ),\n              request\n            }),\n          []\n        );\n\n        return <MiddlewareComponent {...props} middleware={middleware} />;\n      };\n\n      MiddlewareOf.displayName = `MiddlewareOf<${MiddlewareComponent.displayName || ''}>`;\n\n      return memo<Props>(MiddlewareOf);\n    };\n\n  return Object.freeze({\n    asMiddleware,\n    Provider: memo<ProviderProps<Request, Props, Init>>(ChainOfResponsibilityProvider),\n    Proxy: memo<ProxyProps<Request, Props>>(Proxy),\n    types: Object.freeze({\n      middlewareComponentProps: undefined as unknown as AsMiddlewareComponentProps<Request, Props, Init>,\n      init: undefined as unknown as Init,\n      middleware: undefined as unknown as ComponentMiddleware<Request, Props, Init>,\n      props: undefined as unknown as Props,\n      proxyProps: undefined as unknown as ProxyProps<Request, Props>,\n      request: undefined as unknown as Request\n    }),\n    useBuildComponentCallback\n  });\n}\n\nexport default createChainOfResponsibility;\nexport {\n  type ChainOfResponsibility,\n  type CreateChainOfResponsibilityOptions,\n  type ProxyProps,\n  type UseBuildComponentCallback\n};\n","import {\n  type ComponentClass,\n  type ComponentType,\n  type Consumer,\n  type Fragment,\n  type FunctionComponent,\n  type Provider\n} from 'react';\nimport { custom } from 'valibot';\n\nfunction isConsumer(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is Consumer<unknown> {\n  return component?.$$typeof?.toString() === 'Symbol(react.context)';\n}\n\nfunction isProvider(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is Provider<unknown> {\n  return component?.$$typeof?.toString() === 'Symbol(react.provider)';\n}\n\nfunction isFragment(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is typeof Fragment {\n  return component?.toString() === 'Symbol(react.fragment)';\n}\n\nfunction isFunctionComponent(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is FunctionComponent {\n  if (typeof component === 'function') {\n    return true;\n  }\n\n  return isPureFunctionComponent(component);\n}\n\nfunction isPureFunctionComponent(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is FunctionComponent {\n  return component?.$$typeof?.toString() === 'Symbol(react.memo)' && isFunctionComponent(component.type);\n}\n\nfunction isComponentClass(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is ComponentClass {\n  return typeof component === 'object' && typeof component?.['render'] === 'function';\n}\n\n// There are no definitive ways to check if an object is a React component or not.\n// We are checking if the object has a render function (classic component).\n// Note: \"forwardRef()\" returns plain object, not class instance.\nfunction isReactComponent(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  component: any\n): component is ComponentType {\n  return (\n    isFunctionComponent(component) ||\n    isComponentClass(component) ||\n    isFragment(component) ||\n    isConsumer(component) ||\n    isProvider(component)\n  );\n}\n\nconst reactComponent = () =>\n  custom<ComponentType<unknown>>(value => isReactComponent(value), 'not a valid React component');\n\nexport default isReactComponent;\nexport { reactComponent };\n"],"mappings":"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","names":["options","middleware","init","enhancer","useBuildComponentCallback"]}