Skip to content

Commit bb83870

Browse files
Merge pull request #155 from splitio/development
Release v1.9.0
2 parents 645d2ab + 9e358da commit bb83870

51 files changed

Lines changed: 642 additions & 516 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ module.exports = {
3535
'@typescript-eslint/no-explicit-any': 'off',
3636
'@typescript-eslint/no-non-null-assertion': 'off',
3737
'@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_' }],
38+
'prefer-const': ['error', {
39+
'destructuring': 'all'
40+
}]
3841
},
3942
'overrides': [{
4043
'files': ['src/**/*.ts', 'src/**/*.tsx'],
@@ -52,7 +55,7 @@ module.exports = {
5255
'compat/compat': ['error', 'defaults, not ie < 11'],
5356
'no-throw-literal': 'error',
5457
'import/no-self-import': 'error',
55-
// 'import/no-default-export': 'error', // Default exports are a common practice in React
58+
'import/no-default-export': 'error',
5659
}
5760
}]
5861
}

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @splitio/sdk

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
1.9.0 (July 18, 2023)
2+
- Updated some transitive dependencies for vulnerability fixes.
3+
- Updated @splitsoftware/splitio package to version 10.23.0 that includes:
4+
- Updated streaming architecture implementation to apply feature flag updates from the notification received which is now enhanced, improving efficiency and reliability of the whole update system.
5+
16
1.8.3 (May 16, 2023)
27
- Updated @splitsoftware/splitio package to version 10.22.5 that includes:
38
- Updated terminology on the SDKs codebase to be more aligned with current standard without causing a breaking change. The core change is the term split for feature flag on things like logs and IntelliSense comments.

package-lock.json

Lines changed: 218 additions & 168 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@splitsoftware/splitio-react",
3-
"version": "1.8.3",
3+
"version": "1.9.0",
44
"description": "A React library to easily integrate and use Split JS SDK",
55
"main": "lib/index.js",
66
"module": "es/index.js",
@@ -62,7 +62,7 @@
6262
},
6363
"homepage": "https://github.com/splitio/react-client#readme",
6464
"dependencies": {
65-
"@splitsoftware/splitio": "10.22.5",
65+
"@splitsoftware/splitio": "10.23.0",
6666
"memoize-one": "^5.1.1",
6767
"shallowequal": "^1.1.0"
6868
},
@@ -100,7 +100,7 @@
100100
},
101101
"husky": {
102102
"hooks": {
103-
"pre-commit": "npm run check",
103+
"pre-commit": "npm run check && npm run build",
104104
"pre-push": "npm test && npm run build"
105105
}
106106
}

src/SplitClient.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import SplitContext from './SplitContext';
2+
import { SplitContext } from './SplitContext';
33
import { ISplitClientProps, ISplitContextValues, IUpdateProps } from './types';
44
import { ERROR_SC_NO_FACTORY } from './constants';
55
import { getStatus, getSplitSharedClient, initAttributes } from './utils';
@@ -26,7 +26,7 @@ export class SplitComponent extends React.Component<IUpdateProps & { factory: Sp
2626
static getDerivedStateFromProps(props: ISplitClientProps & { factory: SplitIO.IBrowserSDK | null, client: SplitIO.IBrowserClient | null }, state: ISplitContextValues) {
2727
const { client, factory, attributes } = props;
2828
// initAttributes can be called in the `render` method too, but it is better here for separation of concerns
29-
if (client) initAttributes(client, attributes);
29+
initAttributes(client, attributes);
3030
const status = getStatus(client);
3131
// no need to compare status.isTimedout, since it derives from isReady and hasTimedout
3232
if (client !== state.client ||
@@ -119,11 +119,13 @@ export class SplitComponent extends React.Component<IUpdateProps & { factory: Sp
119119
render() {
120120
const { children } = this.props;
121121
return (
122-
<SplitContext.Provider value={this.state} >{
123-
typeof children === 'function' ?
124-
children({ ...this.state }) :
125-
children
126-
}</SplitContext.Provider>
122+
<SplitContext.Provider value={this.state} >
123+
{
124+
typeof children === 'function' ?
125+
children({ ...this.state }) :
126+
children
127+
}
128+
</SplitContext.Provider>
127129
);
128130
}
129131
}
@@ -138,19 +140,17 @@ export class SplitComponent extends React.Component<IUpdateProps & { factory: Sp
138140
*
139141
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#advanced-instantiate-multiple-sdk-clients}
140142
*/
141-
function SplitClient(props: ISplitClientProps) {
143+
export function SplitClient(props: ISplitClientProps) {
142144
return (
143-
<SplitContext.Consumer>{
144-
(splitContext: ISplitContextValues) => {
145+
<SplitContext.Consumer>
146+
{(splitContext: ISplitContextValues) => {
145147
const { factory } = splitContext;
146148
// getSplitSharedClient is idempotent like factory.client: it returns the same client given the same factory, Split Key and TT
147-
const client = factory ? getSplitSharedClient(factory, props.splitKey, props.trafficType, props.attributes) : null;
149+
const client = factory ? getSplitSharedClient(factory, props.splitKey, props.trafficType) : null;
148150
return (
149151
<SplitComponent {...props} factory={factory} client={client} attributes={props.attributes} />
150152
);
151-
}
152-
}</SplitContext.Consumer>
153+
}}
154+
</SplitContext.Consumer>
153155
);
154156
}
155-
156-
export default SplitClient;

src/SplitContext.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ import { EXCEPTION_NO_REACT_OR_CREATECONTEXT } from './constants';
44

55
if (!React || !React.createContext) throw new Error(EXCEPTION_NO_REACT_OR_CREATECONTEXT);
66

7-
/**
8-
* Split Context is the React Context instance that represents our SplitIO global state.
9-
* It contains Split SDK objects, such as a factory instance, a client and its status (isReady, isTimedout, lastUpdate)
10-
* The context is created with default empty values, that eventually SplitFactory and SplitClient access and update.
11-
*/
12-
const SplitContext = React.createContext<ISplitContextValues>({
7+
export const INITIAL_CONTEXT: ISplitContextValues = {
138
client: null,
149
factory: null,
1510
isReady: false,
@@ -18,7 +13,11 @@ const SplitContext = React.createContext<ISplitContextValues>({
1813
hasTimedout: false,
1914
lastUpdate: 0,
2015
isDestroyed: false,
21-
});
16+
}
2217

23-
export default SplitContext;
24-
export { ISplitContextValues };
18+
/**
19+
* Split Context is the React Context instance that represents our SplitIO global state.
20+
* It contains Split SDK objects, such as a factory instance, a client and its status (isReady, isTimedout, lastUpdate)
21+
* The context is created with default empty values, that eventually SplitFactory and SplitClient access and update.
22+
*/
23+
export const SplitContext = React.createContext<ISplitContextValues>(INITIAL_CONTEXT);

src/SplitFactory.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22

33
import { SplitComponent } from './SplitClient';
44
import { ISplitFactoryProps } from './types';
5-
import { VERSION, WARN_SF_CONFIG_AND_FACTORY, ERROR_SF_NO_CONFIG_AND_FACTORY } from './constants';
5+
import { WARN_SF_CONFIG_AND_FACTORY, ERROR_SF_NO_CONFIG_AND_FACTORY } from './constants';
66
import { getSplitFactory, destroySplitFactory, IFactoryWithClients } from './utils';
77

88
/**
@@ -15,7 +15,7 @@ import { getSplitFactory, destroySplitFactory, IFactoryWithClients } from './uti
1515
*
1616
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK}
1717
*/
18-
class SplitFactory extends React.Component<ISplitFactoryProps, { factory: SplitIO.IBrowserSDK | null, client: SplitIO.IBrowserClient | null }> {
18+
export class SplitFactory extends React.Component<ISplitFactoryProps, { factory: SplitIO.IBrowserSDK | null, client: SplitIO.IBrowserClient | null }> {
1919

2020
static defaultProps: ISplitFactoryProps = {
2121
updateOnSdkUpdate: false,
@@ -46,16 +46,14 @@ class SplitFactory extends React.Component<ISplitFactoryProps, { factory: SplitI
4646
factory = propFactory;
4747
} else {
4848
if (config) {
49-
// Don't try this at home. Used to overwrite the settings version when we create our own factory.
50-
(config as any).version = VERSION;
5149
// We use an idempotent variant of the Split factory builder (i.e., given the same config, it returns the same already
5250
// created instance), since React component constructors is part of render-phase and can be invoked multiple times.
5351
factory = getSplitFactory(config);
5452
}
5553
}
5654
this.isFactoryExternal = propFactory ? true : false;
5755

58-
// Instantiate main client.
56+
// Instantiate main client. Attributes are set on `SplitComponent.getDerivedStateFromProps`
5957
const client = factory ? factory.client() : null;
6058

6159
this.state = {
@@ -79,5 +77,3 @@ class SplitFactory extends React.Component<ISplitFactoryProps, { factory: SplitI
7977
);
8078
}
8179
}
82-
83-
export default SplitFactory;

src/SplitTreatments.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import memoizeOne from 'memoize-one';
33
import shallowEqual from 'shallowequal';
4-
import SplitContext from './SplitContext';
4+
import { SplitContext } from './SplitContext';
55
import { ISplitTreatmentsProps, ISplitContextValues } from './types';
66
import { getControlTreatmentsWithConfig, WARN_ST_NO_CLIENT } from './constants';
77

@@ -23,7 +23,7 @@ function evaluateFeatureFlags(client: SplitIO.IBrowserClient, lastUpdate: number
2323
*
2424
* @see {@link https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK#get-treatments-with-configurations}
2525
*/
26-
class SplitTreatments extends React.Component<ISplitTreatmentsProps> {
26+
export class SplitTreatments extends React.Component<ISplitTreatmentsProps> {
2727

2828
private logWarning?: boolean;
2929

@@ -62,5 +62,3 @@ class SplitTreatments extends React.Component<ISplitTreatmentsProps> {
6262
}
6363

6464
}
65-
66-
export default SplitTreatments;

src/__tests__/SplitClient.test.tsx

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { render, RenderResult, act } from '@testing-library/react';
2+
import { render, act } from '@testing-library/react';
33

44
/** Mocks and test utils */
55
import { mockSdk, Event, assertNoListeners, clientListenerCount } from './testUtils/mockSplitSdk';
@@ -11,9 +11,9 @@ import { sdkBrowser } from './testUtils/sdkConfigs';
1111

1212
/** Test target */
1313
import { ISplitClientChildProps } from '../types';
14-
import SplitFactory from '../SplitFactory';
15-
import SplitClient from '../SplitClient';
16-
import SplitContext, { ISplitContextValues } from '../SplitContext';
14+
import { SplitFactory } from '../SplitFactory';
15+
import { SplitClient } from '../SplitClient';
16+
import { SplitContext } from '../SplitContext';
1717
import { ERROR_SC_NO_FACTORY } from '../constants';
1818
import { testAttributesBinding, TestComponentProps } from './testUtils/utils';
1919

@@ -121,7 +121,8 @@ describe('SplitClient', () => {
121121
return null;
122122
}}
123123
</SplitClient>
124-
</SplitFactory>);
124+
</SplitFactory>
125+
);
125126

126127
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT));
127128
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_FROM_CACHE));
@@ -171,7 +172,8 @@ describe('SplitClient', () => {
171172
return null;
172173
}}
173174
</SplitClient>
174-
</SplitFactory>);
175+
</SplitFactory>
176+
);
175177

176178
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT));
177179
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY));
@@ -216,7 +218,8 @@ describe('SplitClient', () => {
216218
return null;
217219
}}
218220
</SplitClient>
219-
</SplitFactory>);
221+
</SplitFactory>
222+
);
220223

221224
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY_TIMED_OUT));
222225
act(() => (outerFactory as any).client('user2').__emitter__.emit(Event.SDK_READY));
@@ -229,14 +232,16 @@ describe('SplitClient', () => {
229232

230233
const Component = () => {
231234
return (
232-
<SplitContext.Consumer>{(value: ISplitContextValues) => {
233-
expect(value.client).toBe(outerFactory.client('user2'));
234-
expect(value.isReady).toBe(false);
235-
expect(value.isTimedout).toBe(false);
236-
expect(value.lastUpdate).toBe(0);
237-
done();
238-
return null;
239-
}}</SplitContext.Consumer>
235+
<SplitContext.Consumer>
236+
{(value) => {
237+
expect(value.client).toBe(outerFactory.client('user2'));
238+
expect(value.isReady).toBe(false);
239+
expect(value.isTimedout).toBe(false);
240+
expect(value.lastUpdate).toBe(0);
241+
done();
242+
return null;
243+
}}
244+
</SplitContext.Consumer>
240245
);
241246
};
242247

@@ -245,7 +250,8 @@ describe('SplitClient', () => {
245250
<SplitClient splitKey='user2' >
246251
<Component />
247252
</SplitClient>
248-
</SplitFactory>);
253+
</SplitFactory>
254+
);
249255
});
250256

251257
test('logs error and passes null client if rendered outside an SplitProvider component.', () => {
@@ -256,15 +262,15 @@ describe('SplitClient', () => {
256262
expect(client).toBe(null);
257263
return null;
258264
}}
259-
</SplitClient>);
265+
</SplitClient>
266+
);
260267
expect(errorSpy).toBeCalledWith(ERROR_SC_NO_FACTORY);
261268
});
262269

263270
test(`passes a new client if re-rendered with a different splitKey.
264271
Only updates the state if the new client triggers an event, but not the previous one.`, (done) => {
265272
const outerFactory = SplitSdk(sdkBrowser);
266-
let renderTimes = 0; // eslint-disable-next-line prefer-const
267-
let wrapper: RenderResult;
273+
let renderTimes = 0;
268274

269275
class InnerComponent extends React.Component<any, { splitKey: string }> {
270276

@@ -294,6 +300,7 @@ describe('SplitClient', () => {
294300
expect(renderTimes).toBe(6);
295301

296302
// check that outerFactory's clients have no event listeners
303+
// eslint-disable-next-line no-use-before-define
297304
wrapper.unmount();
298305
assertNoListeners(outerFactory);
299306
done();
@@ -352,10 +359,11 @@ describe('SplitClient', () => {
352359
}
353360
}
354361

355-
wrapper = render(
362+
const wrapper = render(
356363
<SplitFactory factory={outerFactory} >
357364
<InnerComponent />
358-
</SplitFactory>);
365+
</SplitFactory>
366+
);
359367
});
360368

361369
test('attributes binding test with utility', (done) => {

0 commit comments

Comments
 (0)