diff --git a/.eslintrc.js b/.eslintrc.js index 5cd8c3e..13d2f3b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -55,7 +55,7 @@ module.exports = { 'compat/compat': ['error', 'defaults, not ie < 11'], 'no-throw-literal': 'error', 'import/no-self-import': 'error', - // 'import/no-default-export': 'error', // Default exports are a common practice in React + 'import/no-default-export': 'error', } }] } diff --git a/package.json b/package.json index b0999f3..d46f51f 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ }, "husky": { "hooks": { - "pre-commit": "npm run check", + "pre-commit": "npm run check && npm run build", "pre-push": "npm test && npm run build" } } diff --git a/src/SplitClient.tsx b/src/SplitClient.tsx index 0441342..90726ab 100644 --- a/src/SplitClient.tsx +++ b/src/SplitClient.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import SplitContext from './SplitContext'; +import { SplitContext } from './SplitContext'; import { ISplitClientProps, ISplitContextValues, IUpdateProps } from './types'; import { ERROR_SC_NO_FACTORY } from './constants'; import { getStatus, getSplitSharedClient, initAttributes } from './utils'; @@ -119,11 +119,13 @@ export class SplitComponent extends React.Component{ - typeof children === 'function' ? - children({ ...this.state }) : - children - } + + { + typeof children === 'function' ? + children({ ...this.state }) : + children + } + ); } } @@ -138,19 +140,17 @@ export class SplitComponent extends React.Component{ - (splitContext: ISplitContextValues) => { + + {(splitContext: ISplitContextValues) => { const { factory } = splitContext; // getSplitSharedClient is idempotent like factory.client: it returns the same client given the same factory, Split Key and TT const client = factory ? getSplitSharedClient(factory, props.splitKey, props.trafficType, props.attributes) : null; return ( ); - } - } + }} + ); } - -export default SplitClient; diff --git a/src/SplitContext.ts b/src/SplitContext.ts index ad71513..9d98c02 100644 --- a/src/SplitContext.ts +++ b/src/SplitContext.ts @@ -4,12 +4,7 @@ import { EXCEPTION_NO_REACT_OR_CREATECONTEXT } from './constants'; if (!React || !React.createContext) throw new Error(EXCEPTION_NO_REACT_OR_CREATECONTEXT); -/** - * Split Context is the React Context instance that represents our SplitIO global state. - * It contains Split SDK objects, such as a factory instance, a client and its status (isReady, isTimedout, lastUpdate) - * The context is created with default empty values, that eventually SplitFactory and SplitClient access and update. - */ -const SplitContext = React.createContext({ +export const INITIAL_CONTEXT: ISplitContextValues = { client: null, factory: null, isReady: false, @@ -18,7 +13,11 @@ const SplitContext = React.createContext({ hasTimedout: false, lastUpdate: 0, isDestroyed: false, -}); +} -export default SplitContext; -export { ISplitContextValues }; +/** + * Split Context is the React Context instance that represents our SplitIO global state. + * It contains Split SDK objects, such as a factory instance, a client and its status (isReady, isTimedout, lastUpdate) + * The context is created with default empty values, that eventually SplitFactory and SplitClient access and update. + */ +export const SplitContext = React.createContext(INITIAL_CONTEXT); diff --git a/src/SplitFactory.tsx b/src/SplitFactory.tsx index b7acef3..a0c51d2 100644 --- a/src/SplitFactory.tsx +++ b/src/SplitFactory.tsx @@ -15,7 +15,7 @@ import { getSplitFactory, destroySplitFactory, IFactoryWithClients } from './uti * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK} */ -class SplitFactory extends React.Component { +export class SplitFactory extends React.Component { static defaultProps: ISplitFactoryProps = { updateOnSdkUpdate: false, @@ -77,5 +77,3 @@ class SplitFactory extends React.Component { +export class SplitTreatments extends React.Component { private logWarning?: boolean; @@ -62,5 +62,3 @@ class SplitTreatments extends React.Component { } } - -export default SplitTreatments; diff --git a/src/__tests__/SplitClient.test.tsx b/src/__tests__/SplitClient.test.tsx index 7e77f72..91638c2 100644 --- a/src/__tests__/SplitClient.test.tsx +++ b/src/__tests__/SplitClient.test.tsx @@ -11,9 +11,9 @@ import { sdkBrowser } from './testUtils/sdkConfigs'; /** Test target */ import { ISplitClientChildProps } from '../types'; -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import SplitContext, { ISplitContextValues } from '../SplitContext'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { SplitContext } from '../SplitContext'; import { ERROR_SC_NO_FACTORY } from '../constants'; import { testAttributesBinding, TestComponentProps } from './testUtils/utils'; @@ -121,7 +121,8 @@ describe('SplitClient', () => { return null; }} - ); + + ); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_FROM_CACHE)); @@ -171,7 +172,8 @@ describe('SplitClient', () => { return null; }} - ); + + ); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY)); @@ -216,7 +218,8 @@ describe('SplitClient', () => { return null; }} - ); + + ); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY)); @@ -229,14 +232,16 @@ describe('SplitClient', () => { const Component = () => { return ( - {(value: ISplitContextValues) => { - expect(value.client).toBe(outerFactory.client('user2')); - expect(value.isReady).toBe(false); - expect(value.isTimedout).toBe(false); - expect(value.lastUpdate).toBe(0); - done(); - return null; - }} + + {(value) => { + expect(value.client).toBe(outerFactory.client('user2')); + expect(value.isReady).toBe(false); + expect(value.isTimedout).toBe(false); + expect(value.lastUpdate).toBe(0); + done(); + return null; + }} + ); }; @@ -245,7 +250,8 @@ describe('SplitClient', () => { - ); + + ); }); test('logs error and passes null client if rendered outside an SplitProvider component.', () => { @@ -256,7 +262,8 @@ describe('SplitClient', () => { expect(client).toBe(null); return null; }} - ); + + ); expect(errorSpy).toBeCalledWith(ERROR_SC_NO_FACTORY); }); @@ -355,7 +362,8 @@ describe('SplitClient', () => { const wrapper = render( - ); + + ); }); test('attributes binding test with utility', (done) => { diff --git a/src/__tests__/SplitContext.test.tsx b/src/__tests__/SplitContext.test.tsx index 09650d3..0a1b140 100644 --- a/src/__tests__/SplitContext.test.tsx +++ b/src/__tests__/SplitContext.test.tsx @@ -1,20 +1,24 @@ import React from 'react'; import { render } from '@testing-library/react'; -import SplitContext, { ISplitContextValues } from '../SplitContext'; +import { SplitContext } from '../SplitContext'; /** * Test default SplitContext value */ test('SplitContext.Consumer shows default value', () => { - render({(value: ISplitContextValues) => { - expect(value.factory).toBe(null); - expect(value.client).toBe(null); - expect(value.isReady).toBe(false); - expect(value.isReadyFromCache).toBe(false); - expect(value.hasTimedout).toBe(false); - expect(value.isTimedout).toBe(false); - expect(value.isDestroyed).toBe(false); - expect(value.lastUpdate).toBe(0); - return null; - }}); + render( + + {(value) => { + expect(value.factory).toBe(null); + expect(value.client).toBe(null); + expect(value.isReady).toBe(false); + expect(value.isReadyFromCache).toBe(false); + expect(value.hasTimedout).toBe(false); + expect(value.isTimedout).toBe(false); + expect(value.isDestroyed).toBe(false); + expect(value.lastUpdate).toBe(0); + return null; + }} + + ); }); diff --git a/src/__tests__/SplitFactory.test.tsx b/src/__tests__/SplitFactory.test.tsx index 2b70ec2..68bf307 100644 --- a/src/__tests__/SplitFactory.test.tsx +++ b/src/__tests__/SplitFactory.test.tsx @@ -12,9 +12,9 @@ const logSpy = jest.spyOn(console, 'log'); /** Test target */ import { ISplitFactoryChildProps } from '../types'; -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import SplitContext, { ISplitContextValues } from '../SplitContext'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { SplitContext } from '../SplitContext'; import { __factories } from '../utils'; import { WARN_SF_CONFIG_AND_FACTORY, ERROR_SF_NO_CONFIG_AND_FACTORY } from '../constants'; @@ -34,7 +34,8 @@ describe('SplitFactory', () => { expect((factory as SplitIO.ISDK).settings.version).toContain('react-'); return null; }} - ); + + ); }); test('passes ready props to the child if initialized with a ready factory.', async () => { @@ -57,7 +58,8 @@ describe('SplitFactory', () => { expect((factory as SplitIO.ISDK).settings.version).toBe(outerFactory.settings.version); return null; }} - ); + + ); }); test('rerenders child on SDK_READY_TIMEDOUT, SDK_READY_FROM_CACHE, SDK_READY and SDK_UPDATE events.', async () => { @@ -95,7 +97,8 @@ describe('SplitFactory', () => { previousLastUpdate = lastUpdate; return null; }} - ); + + ); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_FROM_CACHE)); @@ -137,7 +140,8 @@ describe('SplitFactory', () => { previousLastUpdate = lastUpdate; return null; }} - ); + + ); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY)); @@ -175,7 +179,8 @@ describe('SplitFactory', () => { previousLastUpdate = lastUpdate; return null; }} - ); + + ); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY_TIMED_OUT)); act(() => (outerFactory as any).client().__emitter__.emit(Event.SDK_READY)); @@ -186,22 +191,25 @@ describe('SplitFactory', () => { test('renders a passed JSX.Element with a new SplitContext value.', (done) => { const Component = () => { return ( - {(value: ISplitContextValues) => { - expect(value.factory).toBeInstanceOf(Object); - expect(value.client).toBe(value.factory?.client()); - expect(value.isReady).toBe(false); - expect(value.isTimedout).toBe(false); - expect(value.lastUpdate).toBe(0); - done(); - return null; - }} + + {(value) => { + expect(value.factory).toBeInstanceOf(Object); + expect(value.client).toBe(value.factory?.client()); + expect(value.isReady).toBe(false); + expect(value.isTimedout).toBe(false); + expect(value.lastUpdate).toBe(0); + done(); + return null; + }} + ); }; render( - ); + + ); }); test('logs warning if both a config and factory are passed as props.', () => { @@ -213,7 +221,8 @@ describe('SplitFactory', () => { expect(factory).toBe(outerFactory); return null; }} - ); + + ); expect(logSpy).toBeCalledWith(WARN_SF_CONFIG_AND_FACTORY); logSpy.mockRestore(); @@ -227,7 +236,8 @@ describe('SplitFactory', () => { expect(factory).toBe(null); return null; }} - ); + + ); expect(errorSpy).toBeCalledWith(ERROR_SF_NO_CONFIG_AND_FACTORY); }); @@ -240,15 +250,16 @@ describe('SplitFactory', () => { expect(__factories.size).toBe(1); destroyMainClientSpy = jest.spyOn((factory as SplitIO.ISDK).client(), 'destroy'); return ( - { - ({ client }) => { + + {({ client }) => { destroySharedClientSpy = jest.spyOn(client as SplitIO.IClient, 'destroy'); return null; - } - } + }} + ); }} - ); + + ); wrapper.unmount(); // the factory created by the component is removed from `factories` cache and its clients are destroyed expect(__factories.size).toBe(0); @@ -267,15 +278,16 @@ describe('SplitFactory', () => { expect(__factories.size).toBe(0); destroyMainClientSpy = jest.spyOn((factory as SplitIO.ISDK).client(), 'destroy'); return ( - { - ({ client }) => { + + {({ client }) => { destroySharedClientSpy = jest.spyOn(client as SplitIO.IClient, 'destroy'); return null; - } - } + }} + ); }} - ); + + ); wrapper.unmount(); expect(destroyMainClientSpy).not.toBeCalled(); expect(destroySharedClientSpy).not.toBeCalled(); diff --git a/src/__tests__/SplitTreatments.test.tsx b/src/__tests__/SplitTreatments.test.tsx index 9aecb1e..ce558e8 100644 --- a/src/__tests__/SplitTreatments.test.tsx +++ b/src/__tests__/SplitTreatments.test.tsx @@ -12,9 +12,9 @@ const logSpy = jest.spyOn(console, 'log'); /** Test target */ import { ISplitTreatmentsChildProps, ISplitTreatmentsProps, ISplitClientProps } from '../types'; -import SplitTreatments from '../SplitTreatments'; -import SplitClient from '../SplitClient'; -import SplitFactory from '../SplitFactory'; +import { SplitTreatments } from '../SplitTreatments'; +import { SplitClient } from '../SplitClient'; +import { SplitFactory } from '../SplitFactory'; jest.mock('../constants', () => { const actual = jest.requireActual('../constants'); return { @@ -33,8 +33,8 @@ describe('SplitTreatments', () => { it('passes as treatments prop the value returned by the function "getControlTreatmentsWithConfig" if the SDK is not ready.', (done) => { const featureFlagNames = ['split1', 'split2']; render( - { - ({ factory }) => { + + {({ factory }) => { return ( @@ -46,10 +46,11 @@ describe('SplitTreatments', () => { return null; }} - ); - } - } - ); + + ); + }} + + ); }); it('passes as treatments prop the value returned by the method "client.getTreatmentsWithConfig" if the SDK is ready.', (done) => { @@ -58,8 +59,8 @@ describe('SplitTreatments', () => { (outerFactory as any).client().__emitter__.emit(Event.SDK_READY); render( - { - ({ factory, isReady }) => { + + {({ factory, isReady }) => { expect(getStatus(outerFactory.client()).isReady).toBe(isReady); expect(isReady).toBe(true); return ( @@ -73,10 +74,11 @@ describe('SplitTreatments', () => { done(); return null; }} - ); - } - } - ); + + ); + }} + + ); }); it('logs error and passes control treatments ("getControlTreatmentsWithConfig") if rendered outside an SplitProvider component.', () => { @@ -88,7 +90,8 @@ describe('SplitTreatments', () => { passedTreatments = treatments; return null; }} - ); + + ); expect(logSpy).toBeCalledWith(WARN_ST_NO_CLIENT); expect(getControlTreatmentsWithConfig).toBeCalledWith(featureFlagNames); expect(getControlTreatmentsWithConfig).toHaveReturnedWith(passedTreatments); @@ -102,8 +105,8 @@ describe('SplitTreatments', () => { const featureFlagNames = ['split1', 'split2']; render( - { - () => { + + {() => { return ( <> {/* @ts-expect-error Test error handling */} @@ -129,9 +132,9 @@ describe('SplitTreatments', () => { ); - } - } - ); + }} + + ); expect(logSpy).toBeCalledWith('[ERROR] split names must be a non-empty array.'); expect(logSpy).toBeCalledWith('[ERROR] you passed an invalid split name, split name must be a non-empty string.'); @@ -270,7 +273,8 @@ describe('SplitTreatments optimization', () => { return null; }} - ); + + ); // test context updates on SplitClient render( @@ -283,7 +287,8 @@ describe('SplitTreatments optimization', () => { }} - ); + + ); expect(renderTimesComp1).toBe(1); expect(renderTimesComp2).toBe(1); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 3146481..647dbd8 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -12,18 +12,18 @@ import { useTrack as exportedUseTrack, useTreatments as exportedUseTreatments, } from '../index'; -import SplitContext from '../SplitContext'; +import { SplitContext } from '../SplitContext'; import { SplitFactory as SplitioEntrypoint } from '@splitsoftware/splitio/client'; -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import SplitTreatments from '../SplitTreatments'; -import withSplitFactory from '../withSplitFactory'; -import withSplitClient from '../withSplitClient'; -import withSplitTreatments from '../withSplitTreatments'; -import useClient from '../useClient'; -import useManager from '../useManager'; -import useTrack from '../useTrack'; -import useTreatments from '../useTreatments'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { SplitTreatments } from '../SplitTreatments'; +import { withSplitFactory } from '../withSplitFactory'; +import { withSplitClient } from '../withSplitClient'; +import { withSplitTreatments } from '../withSplitTreatments'; +import { useClient } from '../useClient'; +import { useManager } from '../useManager'; +import { useTrack } from '../useTrack'; +import { useTreatments } from '../useTreatments'; describe('index', () => { diff --git a/src/__tests__/useClient.test.tsx b/src/__tests__/useClient.test.tsx index 7964d09..72e3b47 100644 --- a/src/__tests__/useClient.test.tsx +++ b/src/__tests__/useClient.test.tsx @@ -10,9 +10,9 @@ import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; /** Test target */ -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import useClient from '../useClient'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { useClient } from '../useClient'; import { testAttributesBinding, TestComponentProps } from './testUtils/utils'; describe('useClient', () => { @@ -21,11 +21,12 @@ describe('useClient', () => { const outerFactory = SplitSdk(sdkBrowser); let client; render( - { - React.createElement(() => { + + {React.createElement(() => { client = useClient(); return null; - })}, + })} + ); expect(client).toBe(outerFactory.client()); }); @@ -35,13 +36,13 @@ describe('useClient', () => { let client; render( - { - React.createElement(() => { + + {React.createElement(() => { client = useClient(); return null; })} - , + ); expect(client).toBe(outerFactory.client('user2')); }); @@ -50,13 +51,13 @@ describe('useClient', () => { const outerFactory = SplitSdk(sdkBrowser); let client; render( - { - React.createElement(() => { + + {React.createElement(() => { (outerFactory.client as jest.Mock).mockClear(); client = useClient('user2', 'user'); return null; })} - , + ); expect(outerFactory.client as jest.Mock).toBeCalledWith('user2', 'user'); expect(outerFactory.client as jest.Mock).toHaveReturnedWith(client); @@ -66,12 +67,11 @@ describe('useClient', () => { let client; let sharedClient; render( - React.createElement( - () => { - client = useClient(); - sharedClient = useClient('user2', 'user'); - return null; - }), + React.createElement(() => { + client = useClient(); + sharedClient = useClient('user2', 'user'); + return null; + }) ); expect(client).toBe(null); expect(sharedClient).toBe(null); @@ -81,18 +81,17 @@ describe('useClient', () => { function Component({ attributesFactory, attributesClient, splitKey, testSwitch, factory }: TestComponentProps) { return ( - { - React.createElement(() => { + + {React.createElement(() => { useClient(splitKey, 'user', attributesClient); testSwitch(done, splitKey); return null; - }) - } + })} + ); } testAttributesBinding(Component); - }); }); diff --git a/src/__tests__/useManager.test.tsx b/src/__tests__/useManager.test.tsx index 369dc96..041c7b4 100644 --- a/src/__tests__/useManager.test.tsx +++ b/src/__tests__/useManager.test.tsx @@ -10,8 +10,8 @@ import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; /** Test target */ -import SplitFactory from '../SplitFactory'; -import useManager from '../useManager'; +import { SplitFactory } from '../SplitFactory'; +import { useManager } from '../useManager'; describe('useManager', () => { @@ -19,11 +19,12 @@ describe('useManager', () => { const outerFactory = SplitSdk(sdkBrowser); let manager; render( - { - React.createElement(() => { + + {React.createElement(() => { manager = useManager(); return null; - })}, + })} + ); expect(manager).toBe(outerFactory.manager()); }); @@ -31,11 +32,10 @@ describe('useManager', () => { test('returns null if invoked outside Split context.', () => { let manager; render( - React.createElement( - () => { - manager = useManager(); - return null; - }), + React.createElement(() => { + manager = useManager(); + return null; + }) ); expect(manager).toBe(null); }); diff --git a/src/__tests__/useTrack.test.tsx b/src/__tests__/useTrack.test.tsx index 6ea18d2..317af05 100644 --- a/src/__tests__/useTrack.test.tsx +++ b/src/__tests__/useTrack.test.tsx @@ -10,9 +10,9 @@ import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; /** Test target */ -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import useTrack from '../useTrack'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { useTrack } from '../useTrack'; describe('useTrack', () => { @@ -27,12 +27,13 @@ describe('useTrack', () => { let trackResult; render( - { - React.createElement(() => { + + {React.createElement(() => { bindedTrack = useTrack(); trackResult = bindedTrack(tt, eventType, value, properties); return null; - })}, + })} + , ); const track = outerFactory.client().track as jest.Mock; expect(track).toBeCalledWith(tt, eventType, value, properties); @@ -46,14 +47,14 @@ describe('useTrack', () => { render( - { - React.createElement(() => { + + {React.createElement(() => { bindedTrack = useTrack(); trackResult = bindedTrack(tt, eventType, value, properties); return null; })} - , + ); const track = outerFactory.client('user2').track as jest.Mock; expect(track).toBeCalledWith(tt, eventType, value, properties); @@ -66,8 +67,8 @@ describe('useTrack', () => { let trackResult; render( - { - React.createElement(() => { + + {React.createElement(() => { bindedTrack = useTrack('user2', tt); trackResult = bindedTrack(eventType, value, properties); return null; @@ -83,12 +84,11 @@ describe('useTrack', () => { test('returns a false function (`() => false`) if invoked outside Split context.', () => { let trackResult; render( - React.createElement( - () => { - const track = useTrack('user2', tt); - trackResult = track(eventType, value, properties); - return null; - }), + React.createElement(() => { + const track = useTrack('user2', tt); + trackResult = track(eventType, value, properties); + return null; + }), ); expect(trackResult).toBe(false); }); diff --git a/src/__tests__/useTreatments.test.tsx b/src/__tests__/useTreatments.test.tsx index 295d165..1671948 100644 --- a/src/__tests__/useTreatments.test.tsx +++ b/src/__tests__/useTreatments.test.tsx @@ -19,9 +19,9 @@ import { CONTROL_WITH_CONFIG, getControlTreatmentsWithConfig } from '../constant const logSpy = jest.spyOn(console, 'log'); /** Test target */ -import SplitFactory from '../SplitFactory'; -import SplitClient from '../SplitClient'; -import useTreatments from '../useTreatments'; +import { SplitFactory } from '../SplitFactory'; +import { SplitClient } from '../SplitClient'; +import { useTreatments } from '../useTreatments'; describe('useTreatments', () => { @@ -34,11 +34,12 @@ describe('useTreatments', () => { let treatments: SplitIO.TreatmentsWithConfig; render( - { - React.createElement(() => { + + {React.createElement(() => { treatments = useTreatments(featureFlagNames, attributes); return null; - })}, + })} + ); // returns control treatment if not operational (SDK not ready or destroyed), without calling `getTreatmentsWithConfig` method @@ -59,13 +60,13 @@ describe('useTreatments', () => { render( - { - React.createElement(() => { + + {React.createElement(() => { treatments = useTreatments(featureFlagNames, attributes); return null; })} - , + ); // returns control treatment if not operational (SDK not ready or destroyed), without calling `getTreatmentsWithConfig` method @@ -88,12 +89,12 @@ describe('useTreatments', () => { await client.destroy(); render( - { - React.createElement(() => { + + {React.createElement(() => { treatments = useTreatments(featureFlagNames, attributes, 'user2'); return null; })} - , + ); // returns control treatment if not operational (SDK not ready or destroyed), without calling `getTreatmentsWithConfig` method @@ -106,11 +107,10 @@ describe('useTreatments', () => { let treatments; render( - React.createElement( - () => { - treatments = useTreatments(featureFlagNames, attributes); - return null; - }), + React.createElement(() => { + treatments = useTreatments(featureFlagNames, attributes); + return null; + }) ); expect(getControlTreatmentsWithConfig).toBeCalledWith(featureFlagNames); expect(getControlTreatmentsWithConfig).toHaveReturnedWith(treatments); @@ -122,18 +122,17 @@ describe('useTreatments', () => { */ test('Input validation: invalid "names" and "attributes" params in useTreatments.', (done) => { render( - React.createElement( - () => { - // @ts-expect-error Test error handling - let treatments = useTreatments('split1'); - expect(treatments).toEqual({}); - // @ts-expect-error Test error handling - treatments = useTreatments([true]); - expect(treatments).toEqual({}); - - done(); - return null; - }), + React.createElement(() => { + // @ts-expect-error Test error handling + let treatments = useTreatments('split1'); + expect(treatments).toEqual({}); + // @ts-expect-error Test error handling + treatments = useTreatments([true]); + expect(treatments).toEqual({}); + + done(); + return null; + }) ); expect(logSpy).toBeCalledWith('[ERROR] split names must be a non-empty array.'); expect(logSpy).toBeCalledWith('[ERROR] you passed an invalid split name, split name must be a non-empty string.'); diff --git a/src/__tests__/withSplitClient.test.tsx b/src/__tests__/withSplitClient.test.tsx index 02e4924..85ba3ad 100644 --- a/src/__tests__/withSplitClient.test.tsx +++ b/src/__tests__/withSplitClient.test.tsx @@ -9,12 +9,12 @@ jest.mock('@splitsoftware/splitio/client', () => { import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; import * as SplitClient from '../SplitClient'; -const SplitClientSpy = jest.spyOn(SplitClient, 'default'); +const SplitClientSpy = jest.spyOn(SplitClient, 'SplitClient'); import { testAttributesBinding, TestComponentProps } from './testUtils/utils'; /** Test target */ -import withSplitFactory from '../withSplitFactory'; -import withSplitClient from '../withSplitClient'; +import { withSplitFactory } from '../withSplitFactory'; +import { withSplitClient } from '../withSplitClient'; describe('SplitClient', () => { @@ -25,7 +25,9 @@ describe('SplitClient', () => { expect(client).not.toBe(null); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([false, false, false, false, false, 0]); return null; - })); + } + ) + ); render(); }); @@ -40,7 +42,9 @@ describe('SplitClient', () => { expect(client).toBe(outerFactory.client('user1')); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([false, false, false, false, false, 0]); return null; - })); + } + ) + ); render(); done(); }); @@ -55,7 +59,9 @@ describe('SplitClient', () => { expect(client).not.toBe(null); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([false, false, false, false, false, 0]); return null; - })); + } + ) + ); render(); }); @@ -65,7 +71,8 @@ describe('SplitClient', () => { const updateOnSdkReady = true; const updateOnSdkReadyFromCache = false; const Component = withSplitClient('user1')<{ outerProp1: string, outerProp2: number }>( - () => null, updateOnSdkUpdate, updateOnSdkTimedout, updateOnSdkReady, updateOnSdkReadyFromCache); + () => null, updateOnSdkUpdate, updateOnSdkTimedout, updateOnSdkReady, updateOnSdkReadyFromCache + ); render(); expect(SplitClientSpy).toHaveBeenLastCalledWith( @@ -90,12 +97,12 @@ describe('SplitClient', () => { return null; }) return ; - }) + } + ) return } testAttributesBinding(Component); - }); }); diff --git a/src/__tests__/withSplitFactory.test.tsx b/src/__tests__/withSplitFactory.test.tsx index cee72f5..32813b0 100644 --- a/src/__tests__/withSplitFactory.test.tsx +++ b/src/__tests__/withSplitFactory.test.tsx @@ -8,12 +8,12 @@ jest.mock('@splitsoftware/splitio/client', () => { }); import { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; import { sdkBrowser } from './testUtils/sdkConfigs'; -import SplitFactory from '../SplitFactory'; +import { SplitFactory } from '../SplitFactory'; jest.mock('../SplitFactory'); /** Test target */ import { ISplitFactoryChildProps } from '../types'; -import withSplitFactory from '../withSplitFactory'; +import { withSplitFactory } from '../withSplitFactory'; describe('SplitFactory', () => { @@ -23,7 +23,8 @@ describe('SplitFactory', () => { expect(factory).toBeInstanceOf(Object); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([false, false, false, false, false, 0]); return null; - }); + } + ); render(); }); @@ -37,7 +38,8 @@ describe('SplitFactory', () => { expect(factory).toBe(outerFactory); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([true, false, false, false, false, 0]); return null; - }); + } + ); render(); done(); }); @@ -51,7 +53,8 @@ describe('SplitFactory', () => { expect(factory).toBeInstanceOf(Object); expect([isReady, isReadyFromCache, hasTimedout, isTimedout, isDestroyed, lastUpdate]).toStrictEqual([false, false, false, false, false, 0]); return null; - }); + } + ); render(); }); @@ -61,7 +64,8 @@ describe('SplitFactory', () => { const updateOnSdkReady = true; const updateOnSdkReadyFromCache = false; const Component = withSplitFactory(sdkBrowser)<{ outerProp1: string, outerProp2: number }>( - () => null, updateOnSdkUpdate, updateOnSdkTimedout, updateOnSdkReady, updateOnSdkReadyFromCache); + () => null, updateOnSdkUpdate, updateOnSdkTimedout, updateOnSdkReady, updateOnSdkReadyFromCache + ); render(); diff --git a/src/__tests__/withSplitTreatments.test.tsx b/src/__tests__/withSplitTreatments.test.tsx index 0d402a9..b7210c9 100644 --- a/src/__tests__/withSplitTreatments.test.tsx +++ b/src/__tests__/withSplitTreatments.test.tsx @@ -9,9 +9,9 @@ jest.mock('@splitsoftware/splitio/client', () => { import { sdkBrowser } from './testUtils/sdkConfigs'; /** Test target */ -import withSplitFactory from '../withSplitFactory'; -import withSplitClient from '../withSplitClient'; -import withSplitTreatments from '../withSplitTreatments'; +import { withSplitFactory } from '../withSplitFactory'; +import { withSplitClient } from '../withSplitClient'; +import { withSplitTreatments } from '../withSplitTreatments'; import { ISplitTreatmentsChildProps } from '../types'; import { getControlTreatmentsWithConfig } from '../constants'; @@ -39,7 +39,9 @@ describe('withSplitTreatments', () => { expect(props.lastUpdate).toBe(0); done(); return null; - })); + } + ) + ); return ; }); render(); diff --git a/src/index.ts b/src/index.ts index ee4dd60..52a0de8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,20 +2,20 @@ export { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; // HOC functions -export { default as withSplitFactory } from './withSplitFactory'; -export { default as withSplitClient } from './withSplitClient'; -export { default as withSplitTreatments } from './withSplitTreatments'; +export { withSplitFactory } from './withSplitFactory'; +export { withSplitClient } from './withSplitClient'; +export { withSplitTreatments } from './withSplitTreatments'; // Render props components -export { default as SplitTreatments } from './SplitTreatments'; -export { default as SplitClient } from './SplitClient'; -export { default as SplitFactory } from './SplitFactory'; +export { SplitTreatments } from './SplitTreatments'; +export { SplitClient } from './SplitClient'; +export { SplitFactory } from './SplitFactory'; // helper functions/hooks -export { default as useClient } from './useClient'; -export { default as useTreatments } from './useTreatments'; -export { default as useTrack } from './useTrack'; -export { default as useManager } from './useManager'; +export { useClient } from './useClient'; +export { useTreatments } from './useTreatments'; +export { useTrack } from './useTrack'; +export { useManager } from './useManager'; // SplitContext -export { default as SplitContext } from './SplitContext'; +export { SplitContext } from './SplitContext'; diff --git a/src/useClient.ts b/src/useClient.ts index a714e7a..ddafee0 100644 --- a/src/useClient.ts +++ b/src/useClient.ts @@ -1,25 +1,13 @@ -import React from 'react'; -import SplitContext from './SplitContext'; -import { ERROR_UC_NO_USECONTEXT } from './constants'; -import { getSplitSharedClient, checkHooks, initAttributes } from './utils'; +import { useSplitClient } from './useSplitClient'; /** - * 'useClient' is a custom hook that returns a client from the Split context. + * 'useClient' is a hook that returns a client from the Split context. * It uses the 'useContext' hook to access the context, which is updated by * SplitFactory and SplitClient components in the hierarchy of components. * * @return A Split Client instance, or null if used outside the scope of SplitFactory * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ -const useClient = (key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): SplitIO.IBrowserClient | null => { - if (!checkHooks(ERROR_UC_NO_USECONTEXT)) return null; - - let { factory, client } = React.useContext(SplitContext); - if (key && factory) { - client = getSplitSharedClient(factory, key, trafficType, attributes); - } - if (client) initAttributes(client, attributes); - return client; -}; - -export default useClient; +export function useClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): SplitIO.IBrowserClient | null { + return useSplitClient(key, trafficType, attributes).client; +} diff --git a/src/useManager.ts b/src/useManager.ts index 8c21d90..0a9b497 100644 --- a/src/useManager.ts +++ b/src/useManager.ts @@ -1,20 +1,18 @@ import React from 'react'; -import SplitContext from './SplitContext'; +import { SplitContext } from './SplitContext'; import { ERROR_UM_NO_USECONTEXT } from './constants'; import { checkHooks } from './utils'; /** - * 'useManager' is a custom hook that returns the Manager instance from the Split factory. + * 'useManager' is a hook that returns the Manager instance from the Split factory. * It uses the 'useContext' hook to access the factory at Split context, which is updated by * the SplitFactory component. * * @return A Split Manager instance, or null if used outside the scope of SplitFactory * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#manager} */ -const useManager = (): SplitIO.IManager | null => { +export function useManager(): SplitIO.IManager | null { if (!checkHooks(ERROR_UM_NO_USECONTEXT)) return null; const { factory } = React.useContext(SplitContext); return factory ? factory.manager() : null; -}; - -export default useManager; +} diff --git a/src/useSplitClient.ts b/src/useSplitClient.ts new file mode 100644 index 0000000..afde12d --- /dev/null +++ b/src/useSplitClient.ts @@ -0,0 +1,26 @@ +import React from 'react'; +import { SplitContext, INITIAL_CONTEXT } from './SplitContext'; +import { ERROR_UC_NO_USECONTEXT } from './constants'; +import { getSplitSharedClient, checkHooks, initAttributes, IClientWithContext } from './utils'; +import { ISplitContextValues } from './types'; + +/** + * 'useSplitClient' is a hook that returns an Split Context object with the client and its status corresponding to the provided key and trafficType. + * It uses the 'useContext' hook to access the context, which is updated by SplitFactory and SplitClient components in the hierarchy of components. + * + * @return A Split Context object + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} + */ +export function useSplitClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): ISplitContextValues { + if (!checkHooks(ERROR_UC_NO_USECONTEXT)) return INITIAL_CONTEXT; + + const context = React.useContext(SplitContext); + let { factory, client } = context; + if (key && factory) { + client = getSplitSharedClient(factory, key, trafficType, attributes); + } + if (client) initAttributes(client, attributes); + return client === context.client ? context : { + ...context, client, ...(client as IClientWithContext).__getStatus() + }; +} diff --git a/src/useSplitTreatments.ts b/src/useSplitTreatments.ts new file mode 100644 index 0000000..14cab24 --- /dev/null +++ b/src/useSplitTreatments.ts @@ -0,0 +1,25 @@ +import { getControlTreatmentsWithConfig, ERROR_UT_NO_USECONTEXT } from './constants'; +import { checkHooks, IClientWithContext } from './utils'; +import { ISplitTreatmentsChildProps } from './types'; +import { INITIAL_CONTEXT } from './SplitContext'; +import { useSplitClient } from './useSplitClient'; + +/** + * 'useSplitTreatments' is a hook that returns an SplitContext object extended with a `treatments` property containing an object of feature flag evaluations (i.e., treatments). + * It uses the 'useSplitClient' hook to access the client from the Split context, and invokes the 'getTreatmentsWithConfig' method. + * + * @return A Split Context object extended with a TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if split names do not exist. + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations} + */ +export function useSplitTreatments(splitNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): ISplitTreatmentsChildProps { + const context = checkHooks(ERROR_UT_NO_USECONTEXT) ? useSplitClient(key) : INITIAL_CONTEXT; + const client = context.client; + const treatments = client && (client as IClientWithContext).__getStatus().isOperational ? + client.getTreatmentsWithConfig(splitNames, attributes) : + getControlTreatmentsWithConfig(splitNames); + + return { + ...context, + treatments, + }; +} diff --git a/src/useTrack.ts b/src/useTrack.ts index 423b516..adea31e 100644 --- a/src/useTrack.ts +++ b/src/useTrack.ts @@ -1,4 +1,4 @@ -import useClient from './useClient'; +import { useClient } from './useClient'; import { ERROR_UTRACK_NO_USECONTEXT } from './constants'; import { checkHooks } from './utils'; @@ -6,15 +6,13 @@ import { checkHooks } from './utils'; const noOpFalse = () => false; /** - * 'useTrack' is a custom hook that returns the track method from a Split client. + * 'useTrack' is a hook that returns the track method from a Split client. * It uses the 'useContext' hook to access the client from the Split context. * * @return A track function binded to a Split client. If the client is not available, the result is a no-op function that returns false. * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track} */ -const useTrack = (key?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track'] => { +export function useTrack(key?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track'] { const client = checkHooks(ERROR_UTRACK_NO_USECONTEXT) ? useClient(key, trafficType) : null; return client ? client.track.bind(client) : noOpFalse; -}; - -export default useTrack; +} diff --git a/src/useTreatments.ts b/src/useTreatments.ts index 55373ec..4aed7d8 100644 --- a/src/useTreatments.ts +++ b/src/useTreatments.ts @@ -1,20 +1,13 @@ -import useClient from './useClient'; -import { getControlTreatmentsWithConfig, ERROR_UT_NO_USECONTEXT } from './constants'; -import { checkHooks, IClientWithContext } from './utils'; +import { useSplitTreatments } from './useSplitTreatments'; /** - * 'useTreatments' is a custom hook that returns a list of treatments. + * 'useTreatments' is a hook that returns an object of feature flag evaluations (i.e., treatments). * It uses the 'useContext' hook to access the client from the Split context, * and invokes the 'getTreatmentsWithConfig' method. * * @return A TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if feature flag names do not exist. * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations} */ -const useTreatments = (featureFlagNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): SplitIO.TreatmentsWithConfig => { - const client = checkHooks(ERROR_UT_NO_USECONTEXT) ? useClient(key) : null; - return client && (client as IClientWithContext).__getStatus().isOperational ? - client.getTreatmentsWithConfig(featureFlagNames, attributes) : - getControlTreatmentsWithConfig(featureFlagNames); -}; - -export default useTreatments; +export function useTreatments(featureFlagNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): SplitIO.TreatmentsWithConfig { + return useSplitTreatments(featureFlagNames, attributes, key).treatments; +} diff --git a/src/withSplitClient.tsx b/src/withSplitClient.tsx index 7ebd714..f6689f4 100644 --- a/src/withSplitClient.tsx +++ b/src/withSplitClient.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ISplitClientChildProps } from './types'; -import SplitClient from './SplitClient'; +import { SplitClient } from './SplitClient'; /** * High-Order Component for SplitClient. @@ -10,7 +10,7 @@ import SplitClient from './SplitClient'; * @param splitKey The customer identifier. * @param trafficType Traffic type associated with the customer identifier. If no provided here or at the config object, it will be required on the client.track() calls. */ -function withSplitClient(splitKey: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes) { +export function withSplitClient(splitKey: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes) { return function withSplitClientHoc( WrappedComponent: React.ComponentType, @@ -41,5 +41,3 @@ function withSplitClient(splitKey: SplitIO.SplitKey, trafficType?: string, attri }; }; } - -export default withSplitClient; diff --git a/src/withSplitFactory.tsx b/src/withSplitFactory.tsx index 4efe6b9..bd939e2 100644 --- a/src/withSplitFactory.tsx +++ b/src/withSplitFactory.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ISplitFactoryChildProps } from './types'; -import SplitFactory from './SplitFactory'; +import { SplitFactory } from './SplitFactory'; /** * High-Order Component for SplitFactory. @@ -41,5 +41,3 @@ export function withSplitFactory(config?: SplitIO.IBrowserSettings, factory?: Sp }; }; } - -export default withSplitFactory; diff --git a/src/withSplitTreatments.tsx b/src/withSplitTreatments.tsx index 4ec0c0d..6d0607a 100644 --- a/src/withSplitTreatments.tsx +++ b/src/withSplitTreatments.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ISplitTreatmentsChildProps } from './types'; -import SplitTreatments from './SplitTreatments'; +import { SplitTreatments } from './SplitTreatments'; /** * High-Order Component for SplitTreatments. @@ -10,7 +10,7 @@ import SplitTreatments from './SplitTreatments'; * @param names list of feature flag names * @param attributes An object of type Attributes used to evaluate the feature flags. */ -function withSplitTreatments(names: string[], attributes?: SplitIO.Attributes) { +export function withSplitTreatments(names: string[], attributes?: SplitIO.Attributes) { return function withSplitTreatmentsHoc( WrappedComponent: React.ComponentType, @@ -32,5 +32,3 @@ function withSplitTreatments(names: string[], attributes?: SplitIO.Attributes) { }; }; } - -export default withSplitTreatments; diff --git a/types/SplitClient.d.ts b/types/SplitClient.d.ts index a6de207..3a7cb42 100644 --- a/types/SplitClient.d.ts +++ b/types/SplitClient.d.ts @@ -60,5 +60,4 @@ export declare class SplitComponent extends React.Component; -export default SplitContext; -export { ISplitContextValues }; +export declare const SplitContext: React.Context; diff --git a/types/SplitFactory.d.ts b/types/SplitFactory.d.ts index 6d2f588..34f8d5a 100644 --- a/types/SplitFactory.d.ts +++ b/types/SplitFactory.d.ts @@ -10,7 +10,7 @@ import { ISplitFactoryProps } from './types'; * * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK} */ -declare class SplitFactory extends React.Component { @@ -24,4 +24,3 @@ declare class SplitFactory extends React.Component { +export declare class SplitTreatments extends React.Component { private logWarning?; private evaluateFeatureFlags; render(): JSX.Element; componentDidMount(): void; } -export default SplitTreatments; diff --git a/types/index.d.ts b/types/index.d.ts index b32d413..91b8d2a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,12 +1,12 @@ export { SplitFactory as SplitSdk } from '@splitsoftware/splitio/client'; -export { default as withSplitFactory } from './withSplitFactory'; -export { default as withSplitClient } from './withSplitClient'; -export { default as withSplitTreatments } from './withSplitTreatments'; -export { default as SplitTreatments } from './SplitTreatments'; -export { default as SplitClient } from './SplitClient'; -export { default as SplitFactory } from './SplitFactory'; -export { default as useClient } from './useClient'; -export { default as useTreatments } from './useTreatments'; -export { default as useTrack } from './useTrack'; -export { default as useManager } from './useManager'; -export { default as SplitContext } from './SplitContext'; +export { withSplitFactory } from './withSplitFactory'; +export { withSplitClient } from './withSplitClient'; +export { withSplitTreatments } from './withSplitTreatments'; +export { SplitTreatments } from './SplitTreatments'; +export { SplitClient } from './SplitClient'; +export { SplitFactory } from './SplitFactory'; +export { useClient } from './useClient'; +export { useTreatments } from './useTreatments'; +export { useTrack } from './useTrack'; +export { useManager } from './useManager'; +export { SplitContext } from './SplitContext'; diff --git a/types/useClient.d.ts b/types/useClient.d.ts index 370e31d..75284f7 100644 --- a/types/useClient.d.ts +++ b/types/useClient.d.ts @@ -1,10 +1,9 @@ /** - * 'useClient' is a custom hook that returns a client from the Split context. + * 'useClient' is a hook that returns a client from the Split context. * It uses the 'useContext' hook to access the context, which is updated by * SplitFactory and SplitClient components in the hierarchy of components. * * @return A Split Client instance, or null if used outside the scope of SplitFactory * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} */ -declare const useClient: (key?: import("@splitsoftware/splitio/types/splitio").SplitKey | undefined, trafficType?: string | undefined, attributes?: import("@splitsoftware/splitio/types/splitio").Attributes | undefined) => SplitIO.IBrowserClient | null; -export default useClient; +export declare function useClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): SplitIO.IBrowserClient | null; diff --git a/types/useManager.d.ts b/types/useManager.d.ts index cc87232..68257aa 100644 --- a/types/useManager.d.ts +++ b/types/useManager.d.ts @@ -1,10 +1,9 @@ /** - * 'useManager' is a custom hook that returns the Manager instance from the Split factory. + * 'useManager' is a hook that returns the Manager instance from the Split factory. * It uses the 'useContext' hook to access the factory at Split context, which is updated by * the SplitFactory component. * * @return A Split Manager instance, or null if used outside the scope of SplitFactory * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#manager} */ -declare const useManager: () => SplitIO.IManager | null; -export default useManager; +export declare function useManager(): SplitIO.IManager | null; diff --git a/types/useSplitClient.d.ts b/types/useSplitClient.d.ts new file mode 100644 index 0000000..64297af --- /dev/null +++ b/types/useSplitClient.d.ts @@ -0,0 +1,9 @@ +import { ISplitContextValues } from './types'; +/** + * 'useSplitClient' is a hook that returns an Split Context object with the client and its status corresponding to the provided key and trafficType. + * It uses the 'useContext' hook to access the context, which is updated by SplitFactory and SplitClient components in the hierarchy of components. + * + * @return A Split Context object + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients} + */ +export declare function useSplitClient(key?: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): ISplitContextValues; diff --git a/types/useSplitTreatments.d.ts b/types/useSplitTreatments.d.ts new file mode 100644 index 0000000..b83b813 --- /dev/null +++ b/types/useSplitTreatments.d.ts @@ -0,0 +1,9 @@ +import { ISplitTreatmentsChildProps } from './types'; +/** + * 'useSplitTreatments' is a hook that returns an SplitContext object extended with a `treatments` property containing an object of feature flag evaluations (i.e., treatments). + * It uses the 'useSplitClient' hook to access the client from the Split context, and invokes the 'getTreatmentsWithConfig' method. + * + * @return A Split Context object extended with a TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if split names do not exist. + * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations} + */ +export declare function useSplitTreatments(splitNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): ISplitTreatmentsChildProps; diff --git a/types/useTrack.d.ts b/types/useTrack.d.ts index ba2d82f..6479f79 100644 --- a/types/useTrack.d.ts +++ b/types/useTrack.d.ts @@ -1,9 +1,8 @@ /** - * 'useTrack' is a custom hook that returns the track method from a Split client. + * 'useTrack' is a hook that returns the track method from a Split client. * It uses the 'useContext' hook to access the client from the Split context. * * @return A track function binded to a Split client. If the client is not available, the result is a no-op function that returns false. * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#track} */ -declare const useTrack: (key?: import("@splitsoftware/splitio/types/splitio").SplitKey | undefined, trafficType?: string | undefined) => SplitIO.IBrowserClient['track']; -export default useTrack; +export declare function useTrack(key?: SplitIO.SplitKey, trafficType?: string): SplitIO.IBrowserClient['track']; diff --git a/types/useTreatments.d.ts b/types/useTreatments.d.ts index fc6f28c..6b688e7 100644 --- a/types/useTreatments.d.ts +++ b/types/useTreatments.d.ts @@ -1,10 +1,9 @@ /** - * 'useTreatments' is a custom hook that returns a list of treatments. + * 'useTreatments' is a hook that returns an object of feature flag evaluations (i.e., treatments). * It uses the 'useContext' hook to access the client from the Split context, * and invokes the 'getTreatmentsWithConfig' method. * * @return A TreatmentsWithConfig instance, that might contain control treatments if the client is not available or ready, or if feature flag names do not exist. * @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations} */ -declare const useTreatments: (featureFlagNames: string[], attributes?: import("@splitsoftware/splitio/types/splitio").Attributes | undefined, key?: import("@splitsoftware/splitio/types/splitio").SplitKey | undefined) => SplitIO.TreatmentsWithConfig; -export default useTreatments; +export declare function useTreatments(featureFlagNames: string[], attributes?: SplitIO.Attributes, key?: SplitIO.SplitKey): SplitIO.TreatmentsWithConfig; diff --git a/types/withSplitClient.d.ts b/types/withSplitClient.d.ts index 449aecc..5a98bcf 100644 --- a/types/withSplitClient.d.ts +++ b/types/withSplitClient.d.ts @@ -8,5 +8,4 @@ import { ISplitClientChildProps } from './types'; * @param splitKey The customer identifier. * @param trafficType Traffic type associated with the customer identifier. If no provided here or at the config object, it will be required on the client.track() calls. */ -declare function withSplitClient(splitKey: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): (WrappedComponent: React.ComponentType, updateOnSdkUpdate?: boolean, updateOnSdkTimedout?: boolean, updateOnSdkReady?: boolean, updateOnSdkReadyFromCache?: boolean) => (props: OuterProps) => JSX.Element; -export default withSplitClient; +export declare function withSplitClient(splitKey: SplitIO.SplitKey, trafficType?: string, attributes?: SplitIO.Attributes): (WrappedComponent: React.ComponentType, updateOnSdkUpdate?: boolean, updateOnSdkTimedout?: boolean, updateOnSdkReady?: boolean, updateOnSdkReadyFromCache?: boolean) => (props: OuterProps) => JSX.Element; diff --git a/types/withSplitFactory.d.ts b/types/withSplitFactory.d.ts index 3dfdf50..183ac37 100644 --- a/types/withSplitFactory.d.ts +++ b/types/withSplitFactory.d.ts @@ -9,4 +9,3 @@ import { ISplitFactoryChildProps } from './types'; * @param factory Split factory instance to use instead of creating a new one with the config object. */ export declare function withSplitFactory(config?: SplitIO.IBrowserSettings, factory?: SplitIO.IBrowserSDK, attributes?: SplitIO.Attributes): (WrappedComponent: React.ComponentType, updateOnSdkUpdate?: boolean, updateOnSdkTimedout?: boolean, updateOnSdkReady?: boolean, updateOnSdkReadyFromCache?: boolean) => (props: OuterProps) => JSX.Element; -export default withSplitFactory; diff --git a/types/withSplitTreatments.d.ts b/types/withSplitTreatments.d.ts index cc51c49..848c42e 100644 --- a/types/withSplitTreatments.d.ts +++ b/types/withSplitTreatments.d.ts @@ -8,5 +8,4 @@ import { ISplitTreatmentsChildProps } from './types'; * @param names list of feature flag names * @param attributes An object of type Attributes used to evaluate the feature flags. */ -declare function withSplitTreatments(names: string[], attributes?: SplitIO.Attributes): (WrappedComponent: React.ComponentType) => (props: OuterProps) => JSX.Element; -export default withSplitTreatments; +export declare function withSplitTreatments(names: string[], attributes?: SplitIO.Attributes): (WrappedComponent: React.ComponentType) => (props: OuterProps) => JSX.Element;