Skip to content

Commit

Permalink
fix: stricter linting, improved handling of plugin errrors (#795)
Browse files Browse the repository at this point in the history
Co-authored-by: Alan Charles <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: semantic-release-bot <[email protected]>
Co-authored-by: Alan Charles <[email protected]>
fix: bump kotlin version in advertisingId plugin (#799)
fix: fix product Id to match ecommerce spec (#803)
fix: add firebase/app to dev dependencies (#802)
  • Loading branch information
5 people authored Apr 12, 2023
1 parent f8e0e39 commit 1ddb4d5
Show file tree
Hide file tree
Showing 116 changed files with 1,455 additions and 647 deletions.
7 changes: 7 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
node_modules/
coverage/
lib/
e2e/
example/


**/*.config.js
.eslintrc.js
constants-generator.js
38 changes: 37 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
module.exports = {
extends: ['@react-native-community', 'prettier'],
extends: [
'@react-native-community',
'prettier',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking'
],
plugins: ['@typescript-eslint'],
rules: {
'prettier/prettier': [
'error',
Expand All @@ -11,13 +17,43 @@ module.exports = {
useTabs: false,
},
],
"no-void": [
"error",
{ "allowAsStatement": true }
],
"@typescript-eslint/restrict-template-expressions": ["warn", {
allowNumber: true,
allowBoolean: true,
allowAny: true,
allowNullish: true
}],
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/strict-boolean-expressions": "error"
},
overrides: [
// Detox tests
{
files: ['*.e2e.js'],
env: {
jest: true,
},
},
// Jest
{
files: ['**/__tests__/**', '**/__mocks__/**'],
plugins: ['jest'],

rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error"],
"@typescript-eslint/unbound-method": "warn",
"@typescript-eslint/no-unsafe-assignment": "warn",
"@typescript-eslint/no-unsafe-member-access": "warn",
"@typescript-eslint/ban-ts-comment": "warn"
},
},
],
parserOptions: {
project: ['./tsconfig.json'],
},
};
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ jobs:
cache: 'yarn'
- name: Install
run: yarn install --frozen-lockfile
- name: Lint
run: yarn lint
- name: Build
run: yarn build
# Linter has to run after the build because it relies on TS types
- name: Lint
run: yarn lint
- name: Test
run: yarn test --coverage

Expand Down
23 changes: 5 additions & 18 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import 'react-native-gesture-handler';
import * as React from 'react';
import RNBootSplash from 'react-native-bootsplash';
Expand All @@ -20,28 +21,14 @@ import { useState } from 'react';
import { Logger } from './plugins/Logger';

//To see an example Consent Manager uncomment the following
//@ts-ignore
// import { ConsentManager } from './plugins/ConsentManager';

// @ts-ignore
import { AmplitudeSessionPlugin } from '@segment/analytics-react-native-plugin-amplitude-session';
// import { ConsentManager } from './plugins/ConsentManager';
// import { FirebasePlugin } from '@segment/analytics-react-native-plugin-firebase';

// @ts-ignore
// import { FacebookAppEventsPlugin } from '@segment/analytics-react-native-plugin-facebook-app-events';

// @ts-ignore
// import { IdfaPlugin } from '@segment/analytics-react-native-plugin-idfa';

// @ts-ignore
import { AmplitudeSessionPlugin } from '@segment/analytics-react-native-plugin-amplitude-session';

//@ts-ignore
// import { AdvertisingIdPlugin } from '@segment/analytics-react-native-plugin-advertising-id';

//@ts-ignore
// import { ClevertapPlugin } from '@segment/analytics-react-native-plugin-clevertap';

//@ts-ignore
// import { BrazePlugin } from '@segment/analytics-react-native-plugin-braze';

const segmentClient = createClient({
Expand Down Expand Up @@ -130,7 +117,7 @@ const getActiveRouteName = (

const App = () => {
React.useEffect(() => {
RNBootSplash.hide();
void RNBootSplash.hide();
}, []);

const [routeName, setRouteName] = useState('Unknown');
Expand All @@ -142,7 +129,7 @@ const App = () => {
const newRouteName = getActiveRouteName(state);

if (routeName !== newRouteName) {
segmentClient.screen(newRouteName);
void segmentClient.screen(newRouteName);

setRouteName(newRouteName);
}
Expand Down
33 changes: 24 additions & 9 deletions example/src/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useAnalytics } from '@segment/analytics-react-native';

const screenWidth = Dimensions.get('screen').width;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Home = ({ navigation }: { navigation: any }) => {
const { screen, track, identify, group, alias, reset, flush } =
useAnalytics();
Expand All @@ -24,36 +25,40 @@ const Home = ({ navigation }: { navigation: any }) => {
name: 'Track',
testID: 'BUTTON_TRACK',
onPress: () => {
track('Track pressed', { foo: 'bar' });
void track('Track pressed', { foo: 'bar' });
},
},
{
color: colors.darkGreen,
name: 'Screen',
testID: 'BUTTON_SCREEN',
onPress: () => {
screen('Home Screen', { foo: 'bar' });
void screen('Home Screen', { foo: 'bar' });
},
},
{
color: colors.purple,
name: 'Identify',
testID: 'BUTTON_IDENTIFY',
onPress: () => {
identify('user_2', { username: 'simplyTheBest' });
void identify('user_2', { username: 'simplyTheBest' });
},
},
{
color: colors.lightPurple,
name: 'Group',
testID: 'BUTTON_GROUP',
onPress: () => group('best-group', { companyId: 'Lala' }),
onPress: () => {
void group('best-group', { companyId: 'Lala' });
},
},
{
color: colors.indigo,
name: 'Alias',
testID: 'BUTTON_ALIAS',
onPress: () => alias('new-id'),
onPress: () => {
void alias('new-id');
},
},
];
}, []);
Expand All @@ -63,13 +68,17 @@ const Home = ({ navigation }: { navigation: any }) => {
color: colors.pink,
name: 'Flush',
testID: 'BUTTON_FLUSH',
onPress: () => flush(),
onPress: () => {
void flush();
},
},
{
color: colors.orange,
name: 'Reset',
testID: 'BUTTON_RESET',
onPress: () => reset(),
onPress: () => {
void reset();
},
},
];

Expand Down Expand Up @@ -111,7 +120,10 @@ const Home = ({ navigation }: { navigation: any }) => {
styles.button,
{ backgroundColor: colors.purple, width: screenWidth / 2 - 40 },
]}
onPress={() => navigation.navigate('SecondPage')}
onPress={() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
navigation.navigate('SecondPage');
}}
>
<Text style={styles.text}>Page</Text>
</TouchableOpacity>
Expand All @@ -120,7 +132,10 @@ const Home = ({ navigation }: { navigation: any }) => {
styles.button,
{ backgroundColor: colors.acai, width: screenWidth / 2 - 40 },
]}
onPress={() => navigation.navigate('Modal')}
onPress={() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
navigation.navigate('Modal');
}}
>
<Text style={styles.text}>Modal</Text>
</TouchableOpacity>
Expand Down
4 changes: 2 additions & 2 deletions example/src/plugins/ConsentManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class ConsentManager extends Plugin {
if (status === true) {
this.consentStatus = true;
this.sendQueued();
this.analytics?.track('Consent Authorized');
void this.analytics?.track('Consent Authorized');
}
if (status === false) {
this.queuedEvents = [];
Expand All @@ -68,7 +68,7 @@ export class ConsentManager extends Plugin {

sendQueued() {
this.queuedEvents.forEach((event) => {
this.analytics?.process(event);
void this.analytics?.process(event);
});
this.queuedEvents = [];
}
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
"@changesets/cli": "^2.16.0",
"@commitlint/config-conventional": "^16.2.4",
"@react-native-community/eslint-config": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^5.54.1",
"@typescript-eslint/parser": "^5.54.1",
"commitlint": "^16.2.4",
"eslint": "^7.2.0",
"eslint-config-prettier": "^7.0.0",
"eslint-plugin-jest": "^27.2.1",
"eslint-plugin-prettier": "^3.1.3",
"husky": "^8.0.0",
"jest": "^27.5.1",
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"semantic-release-monorepo": "^7.0.5",
"ts-jest": "^27.0.7",
"typescript": "^4.4.4",
"type-fest": "^3.6.1",
"@react-native-async-storage/async-storage": "^1.0"
},
"react-native-builder-bob": {
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/__mocks__/react-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const Platform = {
};

export class NativeEventEmitter {
constructor() {}
addListener = () => jest.fn();
removeListener = () => jest.fn();
removeAllListeners = () => jest.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { DestinationPlugin } from '../../plugin';

export const getMockDestinationPlugin = () => {
const destinationPlugin = new DestinationPlugin();
destinationPlugin.flush = jest.fn() as jest.MockedFunction<any>;
destinationPlugin.flush = jest.fn() as jest.MockedFunction<never>;
return destinationPlugin;
};
8 changes: 6 additions & 2 deletions packages/core/src/__tests__/__helpers__/mockEventStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ export class MockEventStore {

constructor(initialData?: SegmentEvent[]) {
this.events = [...(initialData ?? [])];
this.initialData = JSON.parse(JSON.stringify(initialData ?? []));
this.initialData = JSON.parse(
JSON.stringify(initialData ?? [])
) as SegmentEvent[];
}

reset = () => {
this.events = JSON.parse(JSON.stringify(this.initialData));
this.events = JSON.parse(
JSON.stringify(this.initialData)
) as SegmentEvent[];
};

getState = createMockStoreGetter(() => ({ events: this.events }));
Expand Down
14 changes: 9 additions & 5 deletions packages/core/src/__tests__/__helpers__/mockSegmentStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ export class MockSegmentStore implements Storage {
private initialData: StoreData;

reset = () => {
this.data = JSON.parse(JSON.stringify(this.initialData));
this.data = JSON.parse(JSON.stringify(this.initialData)) as StoreData;
};

constructor(initialData?: Partial<StoreData>) {
this.data = { ...INITIAL_VALUES, ...initialData };
this.initialData = JSON.parse(
JSON.stringify({ ...INITIAL_VALUES, ...initialData })
);
) as StoreData;
}

private callbacks = {
Expand All @@ -81,7 +81,9 @@ export class MockSegmentStore implements Storage {
return this.data.isReady;
}),
onChange: (_callback: (value: boolean) => void) => {
return () => {};
return () => {
return;
};
},
};

Expand All @@ -102,7 +104,7 @@ export class MockSegmentStore implements Storage {

readonly settings: Watchable<SegmentAPIIntegrations | undefined> &
Settable<SegmentAPIIntegrations> &
Dictionary<string, IntegrationSettings> = {
Dictionary<string, IntegrationSettings, SegmentAPIIntegrations> = {
get: createMockStoreGetter(() => this.data.settings),
onChange: (callback: (value?: SegmentAPIIntegrations) => void) =>
this.callbacks.settings.register(callback),
Expand All @@ -117,12 +119,13 @@ export class MockSegmentStore implements Storage {
add: (key: string, value: IntegrationSettings) => {
this.data.settings[key] = value;
this.callbacks.settings.run(this.data.settings);
return Promise.resolve(this.data.settings);
},
};

readonly filters: Watchable<DestinationFilters | undefined> &
Settable<DestinationFilters> &
Dictionary<string, RoutingRule> = {
Dictionary<string, RoutingRule, DestinationFilters> = {
get: createMockStoreGetter(() => this.data.filters),
onChange: (callback: (value?: DestinationFilters) => void) =>
this.callbacks.filters.register(callback),
Expand All @@ -137,6 +140,7 @@ export class MockSegmentStore implements Storage {
add: (key: string, value: RoutingRule) => {
this.data.filters[key] = value;
this.callbacks.filters.run(this.data.filters);
return Promise.resolve(this.data.filters);
},
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/__tests__/__helpers__/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ jest.mock('react-native');
jest.mock('uuid');
jest.mock('react-native-get-random-values');
jest.mock('@react-native-async-storage/async-storage', () =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
require('@react-native-async-storage/async-storage/jest/async-storage-mock')
);
8 changes: 4 additions & 4 deletions packages/core/src/__tests__/__helpers__/setupSegmentClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export const createTestClient = (
class ObservablePlugin extends UtilityPlugin {
type = PluginType.after;

override execute(
execute = async (
event: SegmentEvent
): SegmentEvent | Promise<SegmentEvent | undefined> | undefined {
super.execute(event);
): Promise<SegmentEvent | undefined> => {
await super.execute(event);
return event;
}
};
}

const mockPlugin = new ObservablePlugin();
Expand Down
Loading

0 comments on commit 1ddb4d5

Please sign in to comment.