import * as React from 'react' ; const PolicyContext = React . createContext < any > ( null ) ; interface Props < Context > { context : Context ; } export class Provider < C = any > extends React . Component < Props < C > > { render ( ) { return React . createElement ( PolicyContext . Provider , { value : this . props . context } , this . props . children ) ; } } export function usePolicy < P > ( policyClass ) { const policyContext = React . useContext ( PolicyContext ) ; return new policyClass ( policyContext ) ; } export function withPolicies < PolicyProps extends { [ name ] : { new ( context ) : any ; } ; } > ( policyClasses ) { return < T > ( WrappedComponent ) => { const componentWithPolicy = props => { const policyContext = React . useContext ( PolicyContext ) ; const policies = Object . keys ( policyClasses ) . reduce ( ( acc , name ) => { const policyClass = policyClasses [ name as keyof PolicyProps ] ; acc [ name as keyof PolicyProps ] = new policyClass ( policyContext ) ; return acc ; } , { } ) ; return React . createElement ( WrappedComponent , { ... ( props as T ) , ... policies , } ) ; } ; const displayName = WrappedComponent . displayName || WrappedComponent . name || 'Component' ; componentWithPolicy . displayName = `withPolicies(${ displayName })` ; return componentWithPolicy ; } ; } export function authorize < P > ( policyClass , check , fallback ? ) { return < T > ( WrappedComponent ) => { const componentWithPolicy = props => { const policyContext = React . useContext ( PolicyContext ) ; const policy = new policyClass ( policyContext ) ; if ( check ( { policy , props } ) ) { return React . createElement ( WrappedComponent , props ) ; } return fallback ?? null ; } ; const displayName = WrappedComponent . displayName || WrappedComponent . name || 'Component' ; componentWithPolicy . displayName = `authorize(${ displayName })` ; return componentWithPolicy ; } ; } export function Authorize < P > ( props ) { const { with : policyClass , if : check , children , fallback } = props ; const policyContext = React . useContext ( PolicyContext ) ; const policy = new policyClass ( policyContext ) ; if ( check ( policy ) ) { return React . createElement ( React . Fragment , null , children ) ; } return React . createElement ( React . Fragment , null , fallback ) ; }