Skip to content

Commit aa72c30

Browse files
authored
chore: Migrate to eslint from tslint. (#297)
After this I can unblock the prettier dependabot.
1 parent df05386 commit aa72c30

14 files changed

+65
-85
lines changed

eslint.config.mjs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @ts-check
2+
3+
import eslint from '@eslint/js';
4+
import tseslint from 'typescript-eslint';
5+
6+
export default tseslint.config(
7+
eslint.configs.recommended,
8+
...tseslint.configs.recommended,
9+
...tseslint.configs.strict,
10+
...tseslint.configs.stylistic,
11+
{
12+
files: ['**/*.{ts,tsx,mts,cts}'],
13+
rules: {
14+
'no-undef': 'off',
15+
"@typescript-eslint/no-unused-vars": [
16+
"error",
17+
{
18+
"args": "all",
19+
"argsIgnorePattern": "^_",
20+
"caughtErrors": "all",
21+
"caughtErrorsIgnorePattern": "^_",
22+
"destructuredArrayIgnorePattern": "^_",
23+
"varsIgnorePattern": "^_",
24+
"ignoreRestSiblings": true
25+
}
26+
]
27+
},
28+
},
29+
);

package.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@
3232
"rb": "rollup -c --configPlugin typescript",
3333
"rbw": "npm run rb --watch",
3434
"build": "npm run clean && npm run rb",
35-
"lint": "tslint -p tsconfig.json 'src/**/*.ts*'",
36-
"lint:all": "npm run lint",
35+
"lint": "eslint ./src",
3736
"check-typescript": "tsc",
3837
"prepublishOnly": "npm run build",
3938
"prettier": "prettier --write 'src/*.@(js|ts|tsx|json|css)'",
@@ -47,12 +46,14 @@
4746
},
4847
"homepage": "https://github.com/launchdarkly/react-client-sdk",
4948
"devDependencies": {
49+
"@eslint/js": "^9.7.0",
5050
"@rollup/plugin-json": "^6.0.0",
5151
"@rollup/plugin-node-resolve": "^15.1.0",
5252
"@rollup/plugin-terser": "^0.4.3",
5353
"@rollup/plugin-typescript": "^11.1.2",
5454
"@testing-library/jest-dom": "^6.4.8",
5555
"@testing-library/react": "^15.0.7",
56+
"@types/eslint__js": "^8.42.3",
5657
"@types/hoist-non-react-statics": "^3.3.1",
5758
"@types/jest": "^29.5.12",
5859
"@types/lodash.camelcase": "^4.3.6",
@@ -61,7 +62,8 @@
6162
"@types/react": "^18.0.3",
6263
"@types/react-dom": "^18.0.0",
6364
"@types/react-test-renderer": "^18.0.0",
64-
"esbuild": "^0.21.3",
65+
"esbuild": "^0.21.3",
66+
"eslint": "^8.57.0",
6567
"jest": "^29.7.0",
6668
"jest-environment-jsdom": "^29.7.0",
6769
"jest-environment-jsdom-global": "^4.0.0",
@@ -76,10 +78,9 @@
7678
"rollup-plugin-esbuild": "^6.1.1",
7779
"ts-jest": "^29.2.2",
7880
"tslint": "^6.1.3",
79-
"tslint-config-prettier": "^1.18.0",
80-
"tslint-plugin-prettier": "^2.3.0",
81-
"typescript": "^4.5.3",
82-
"typedoc": "^0.25.13"
81+
"typedoc": "^0.25.13",
82+
"typescript": "^4.9.5",
83+
"typescript-eslint": "^7.17.0"
8384
},
8485
"dependencies": {
8586
"hoist-non-react-statics": "^3.3.2",

src/asyncWithLDProvider.test.tsx

+10-11
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ describe('asyncWithLDProvider', () => {
6060

6161
beforeEach(() => {
6262
mockLDClient = {
63-
on: jest.fn((e: string, cb: () => void) => {
63+
on: jest.fn((_e: string, cb: () => void) => {
6464
cb();
6565
}),
6666
off: jest.fn(),
67-
// tslint:disable-next-line: no-unsafe-any
6867
variation: jest.fn((_: string, v) => v),
6968
waitForInitialization: jest.fn(),
7069
};
@@ -210,7 +209,7 @@ describe('asyncWithLDProvider', () => {
210209
});
211210

212211
test('subscribe to changes with camelCase', async () => {
213-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
212+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
214213
cb({ 'test-flag': { current: false, previous: true } });
215214
});
216215

@@ -222,7 +221,7 @@ describe('asyncWithLDProvider', () => {
222221
});
223222

224223
test('subscribe to changes with kebab-case', async () => {
225-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
224+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
226225
cb({ 'another-test-flag': { current: false, previous: true }, 'test-flag': { current: false, previous: true } });
227226
});
228227
const receivedNode = await renderWithConfig({ clientSideID, reactOptions: { useCamelCaseFlagKeys: false } });
@@ -232,7 +231,7 @@ describe('asyncWithLDProvider', () => {
232231
});
233232

234233
test('consecutive flag changes gets stored in context correctly', async () => {
235-
mockLDClient.on.mockImplementationOnce((e: string, cb: (c: LDFlagChangeset) => void) => {
234+
mockLDClient.on.mockImplementationOnce((_e: string, cb: (c: LDFlagChangeset) => void) => {
236235
cb({ 'another-test-flag': { current: false, previous: true } });
237236

238237
// simulate second update
@@ -247,7 +246,7 @@ describe('asyncWithLDProvider', () => {
247246

248247
test('ldClient bootstraps correctly', async () => {
249248
// don't subscribe to changes to test bootstrap
250-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
249+
mockLDClient.on.mockImplementation((_e: string, _cb: (c: LDFlagChangeset) => void) => {
251250
return;
252251
});
253252
options = {
@@ -261,7 +260,7 @@ describe('asyncWithLDProvider', () => {
261260
});
262261

263262
test('undefined bootstrap', async () => {
264-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
263+
mockLDClient.on.mockImplementation((_e: string, _cb: (c: LDFlagChangeset) => void) => {
265264
return;
266265
});
267266
options = { ...options, bootstrap: undefined };
@@ -273,7 +272,7 @@ describe('asyncWithLDProvider', () => {
273272
});
274273

275274
test('bootstrap used if there is a timeout', async () => {
276-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
275+
mockLDClient.on.mockImplementation((_e: string, _cb: (c: LDFlagChangeset) => void) => {
277276
return;
278277
});
279278
rejectWaitForInitialization();
@@ -287,7 +286,7 @@ describe('asyncWithLDProvider', () => {
287286

288287
test('ldClient bootstraps with empty flags', async () => {
289288
// don't subscribe to changes to test bootstrap
290-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
289+
mockLDClient.on.mockImplementation((_e: string, _cb: (c: LDFlagChangeset) => void) => {
291290
return;
292291
});
293292
options = {
@@ -299,7 +298,7 @@ describe('asyncWithLDProvider', () => {
299298

300299
test('ldClient bootstraps correctly with kebab-case', async () => {
301300
// don't subscribe to changes to test bootstrap
302-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
301+
mockLDClient.on.mockImplementation((_e: string, _cb: (c: LDFlagChangeset) => void) => {
303302
return;
304303
});
305304
options = {
@@ -340,7 +339,7 @@ describe('asyncWithLDProvider', () => {
340339
});
341340

342341
test('only updates to subscribed flags are pushed to the Provider', async () => {
343-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
342+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
344343
cb({ 'test-flag': { current: false, previous: true }, 'another-test-flag': { current: false, previous: true } });
345344
});
346345
options = {};

src/asyncWithLDProvider.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect, ReactNode } from 'react';
2-
import { initialize, LDFlagChangeset, LDOptions } from 'launchdarkly-js-client-sdk';
2+
import { initialize, LDFlagChangeset } from 'launchdarkly-js-client-sdk';
33
import { AsyncProviderConfig, defaultReactOptions } from './types';
44
import { Provider } from './context';
55
import { fetchFlags, getContextOrUser, getFlattenedFlagsFromChangeset } from './utils';
@@ -8,7 +8,6 @@ import wrapperOptions from './wrapperOptions';
88
import ProviderState from './providerState';
99

1010
// Extend the expect with additional methods.
11-
// tslint:disable-next-line:no-import-side-effect
1211
import '@testing-library/jest-dom';
1312

1413
/**

src/getFlagsProxy.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ beforeEach(jest.clearAllMocks);
1919

2020
test('native Object functions should be ignored', () => {
2121
const { flags } = getFlagsProxy(ldClient, rawFlags);
22-
flags.hasOwnProperty('fooBar');
23-
flags.propertyIsEnumerable('bazQux');
22+
Object.prototype.hasOwnProperty.call(flags, 'fooBar');
23+
Object.prototype.propertyIsEnumerable.call(flags, 'bazQux');
2424
expect(ldClient.variation).not.toHaveBeenCalled();
2525
});
2626

src/provider.test.tsx

+6-8
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const mockInitialize = initialize as jest.Mock;
3333
const mockFetchFlags = fetchFlags as jest.Mock;
3434
const rawFlags = { 'test-flag': true, 'another-test-flag': true };
3535
const mockLDClient = {
36-
on: jest.fn((e: string, cb: () => void) => {
36+
on: jest.fn((_e: string, cb: () => void) => {
3737
cb();
3838
}),
3939
off: jest.fn(),
@@ -52,7 +52,6 @@ describe('LDProvider', () => {
5252
mockInitialize.mockImplementation(() => mockLDClient);
5353
mockFetchFlags.mockImplementation(() => rawFlags);
5454

55-
// tslint:disable-next-line: no-unsafe-any
5655
mockLDClient.variation.mockImplementation((_, v) => v);
5756
options = { ...wrapperOptions };
5857
previousState = {
@@ -142,10 +141,9 @@ describe('LDProvider', () => {
142141
});
143142

144143
test('ld client is used if passed in as promise', async () => {
145-
const context1: LDContext = { key: 'yus', kind: 'user', name: 'yus ng' };
146144
const context2: LDContext = { key: 'launch', kind: 'user', name: 'darkly' };
147145
options = { ...options, bootstrap: {} };
148-
const ldClient: Promise<LDClient> = new Promise(async (resolve) => {
146+
const ldClient = new Promise<LDClient>((resolve) => {
149147
resolve((mockLDClient as unknown) as LDClient);
150148

151149
return;
@@ -164,7 +162,7 @@ describe('LDProvider', () => {
164162

165163
test('ld client is created if passed in promise resolves as undefined', async () => {
166164
options = { ...options, bootstrap: {} };
167-
const ldClient: Promise<undefined> = new Promise(async (resolve) => {
165+
const ldClient = new Promise<undefined>((resolve) => {
168166
resolve(undefined);
169167

170168
return;
@@ -437,7 +435,7 @@ describe('LDProvider', () => {
437435
});
438436

439437
test('subscribe to changes with camelCase', async () => {
440-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
438+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
441439
cb({ 'test-flag': { current: false, previous: true } });
442440
});
443441
const props: ProviderConfig = { clientSideID };
@@ -461,7 +459,7 @@ describe('LDProvider', () => {
461459
});
462460

463461
test('subscribe to changes with kebab-case', async () => {
464-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
462+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
465463
cb({ 'another-test-flag': { current: false, previous: true }, 'test-flag': { current: false, previous: true } });
466464
});
467465
const props: ProviderConfig = { clientSideID, reactOptions: { useCamelCaseFlagKeys: false } };
@@ -515,7 +513,7 @@ describe('LDProvider', () => {
515513

516514
test('only updates to subscribed flags are pushed to the Provider', async () => {
517515
mockFetchFlags.mockImplementation(() => ({ 'test-flag': 2 }));
518-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
516+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
519517
cb({ 'test-flag': { current: 3, previous: 2 }, 'another-test-flag': { current: false, previous: true } });
520518
});
521519
options = {};

src/provider.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class LDProvider extends Component<PropsWithChildren<ProviderConfig>, ProviderSt
7272
});
7373
};
7474

75-
onFailed = (ldClient: LDClient, e: Error) => {
75+
onFailed = (_ldClient: LDClient, e: Error) => {
7676
this.setState((prevState) => ({ ...prevState, error: e }));
7777
};
7878

@@ -107,7 +107,7 @@ class LDProvider extends Component<PropsWithChildren<ProviderConfig>, ProviderSt
107107
if (error?.name.toLowerCase().includes('timeout')) {
108108
ldClient.on('failed', this.onFailed);
109109
ldClient.on('ready', () => {
110-
// tslint:disable-next-line:no-non-null-assertion
110+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
111111
this.onReady(ldClient!, reactOptions, targetFlags);
112112
});
113113
}
@@ -116,7 +116,7 @@ class LDProvider extends Component<PropsWithChildren<ProviderConfig>, ProviderSt
116116
this.setState((prevState) => ({
117117
...prevState,
118118
unproxiedFlags,
119-
// tslint:disable-next-line:no-non-null-assertion
119+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
120120
...getFlagsProxy(ldClient!, unproxiedFlags, reactOptions, targetFlags),
121121
ldClient,
122122
error,

src/types.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,7 @@ export type AsyncProviderConfig = Omit<ProviderConfig, 'deferInitialization'> &
121121
*/
122122
export interface EnhancedComponent extends React.Component {
123123
subscribeToChanges(ldClient: LDClient): void;
124-
// tslint:disable-next-line:invalid-void
125124
componentDidMount(): Promise<void>;
126-
// tslint:disable-next-line:invalid-void
127125
componentDidUpdate(prevProps: ProviderConfig): Promise<void>;
128126
}
129127

@@ -152,8 +150,6 @@ export interface AllFlagsLDClient {
152150
/**
153151
* Map of camelized flag keys to original unmodified flag keys.
154152
*/
155-
export interface LDFlagKeyMap {
156-
[camelCasedKey: string]: string;
157-
}
153+
export type LDFlagKeyMap = Record<string, string>;
158154

159155
export * from 'launchdarkly-js-client-sdk';

src/useLDClient.ts

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useContext } from 'react';
22
import context from './context';
33

4-
// tslint:disable:max-line-length
54
/**
65
* `useLDClient` is a custom hook which returns the underlying [LaunchDarkly JavaScript SDK client object](https://launchdarkly.github.io/js-client-sdk/interfaces/LDClient.html).
76
* Like the `useFlags` custom hook, `useLDClient` also uses the `useContext` primitive to access the LaunchDarkly
@@ -10,7 +9,6 @@ import context from './context';
109
*
1110
* @return The `launchdarkly-js-client-sdk` `LDClient` object
1211
*/
13-
// tslint:enable:max-line-length
1412
const useLDClient = () => {
1513
const { ldClient } = useContext(context);
1614

src/utils.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const camelCaseKeys = (rawFlags: LDFlagSet) => {
2020
for (const rawFlag in rawFlags) {
2121
// Exclude system keys
2222
if (rawFlag.indexOf('$') !== 0) {
23-
flags[camelCase(rawFlag)] = rawFlags[rawFlag]; // tslint:disable-line:no-unsafe-any
23+
flags[camelCase(rawFlag)] = rawFlags[rawFlag];
2424
}
2525
}
2626

@@ -76,7 +76,6 @@ export const fetchFlags = (ldClient: LDClient, targetFlags?: LDFlagSet) => {
7676
* @deprecated The `camelCaseKeys.camelCaseKeys` property will be removed in a future version,
7777
* please update your code to use the `camelCaseKeys` function directly.
7878
*/
79-
// tslint:disable-next-line deprecation
8079
camelCaseKeys.camelCaseKeys = camelCaseKeys;
8180

8281
export default { camelCaseKeys, getFlattenedFlagsFromChangeset, fetchFlags };

src/withLDConsumer.test.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ jest.mock('./context', () => {
1111
}
1212

1313
return {
14-
// tslint:disable-next-line:no-null-undefined-union
1514
Consumer(props: ConsumerChildren) {
1615
return props.children({ flags: { testFlag: true }, ldClient: { track: jest.fn() } });
1716
},

src/withLDProvider.test.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const mockInitialize = initialize as jest.Mock;
3333
const mockFetchFlags = fetchFlags as jest.Mock;
3434
const rawFlags = { 'test-flag': true, 'another-test-flag': true };
3535
const mockLDClient = {
36-
on: jest.fn((e: string, cb: () => void) => {
36+
on: jest.fn((_e: string, cb: () => void) => {
3737
cb();
3838
}),
3939
allFlags: jest.fn().mockReturnValue({}),
@@ -48,7 +48,6 @@ describe('withLDProvider', () => {
4848
beforeEach(() => {
4949
mockInitialize.mockImplementation(() => mockLDClient);
5050
mockFetchFlags.mockImplementation(() => rawFlags);
51-
// tslint:disable-next-line: no-unsafe-any
5251
mockLDClient.variation.mockImplementation((_, v) => v);
5352
options = { bootstrap: {}, ...wrapperOptions };
5453
previousState = {
@@ -123,7 +122,7 @@ describe('withLDProvider', () => {
123122
});
124123

125124
test('subscribe to changes with camelCase', async () => {
126-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
125+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
127126
cb({ 'test-flag': { current: false, previous: true } });
128127
});
129128
const LaunchDarklyApp = withLDProvider({ clientSideID })(App);
@@ -142,7 +141,7 @@ describe('withLDProvider', () => {
142141
});
143142

144143
test('subscribe to changes with kebab-case', async () => {
145-
mockLDClient.on.mockImplementation((e: string, cb: (c: LDFlagChangeset) => void) => {
144+
mockLDClient.on.mockImplementation((_e: string, cb: (c: LDFlagChangeset) => void) => {
146145
cb({ 'another-test-flag': { current: false, previous: true }, 'test-flag': { current: false, previous: true } });
147146
});
148147
const LaunchDarklyApp = withLDProvider({ clientSideID, reactOptions: { useCamelCaseFlagKeys: false } })(App);

src/withLDProvider.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import hoistNonReactStatics from 'hoist-non-react-statics';
2323
* @param config - The configuration used to initialize LaunchDarkly's JS SDK
2424
* @return A function which accepts your root React component and returns a HOC
2525
*/
26+
// eslint-disable-next-line @typescript-eslint/ban-types
2627
export function withLDProvider<T extends JSX.IntrinsicAttributes = {}>(
2728
config: ProviderConfig,
2829
): (WrappedComponent: React.ComponentType<T>) => React.ComponentType<T> {

0 commit comments

Comments
 (0)