From c13593bc7e448aa1b961be2603828e844fc6cac5 Mon Sep 17 00:00:00 2001 From: Yann Noutary Date: Wed, 22 Jul 2020 00:59:25 -0700 Subject: [PATCH] Convert to TypeScript Summary: Converted the Crash Reporter plugin to Typescript while fixing all linting errors Reviewed By: jknoxville Differential Revision: D22571332 fbshipit-source-id: d3092ffc480827b5eb1beb5c3cc91dad6993e267 --- ...de.js => testCrashReporterPlugin.node.tsx} | 116 +++++++----- .../crash_reporter/{index.js => index.tsx} | 168 ++++++++++-------- desktop/plugins/crash_reporter/package.json | 2 +- .../crash_reporter/unicode-substring.d.tsx | 17 ++ 4 files changed, 182 insertions(+), 121 deletions(-) rename desktop/plugins/crash_reporter/__tests__/{testCrashReporterPlugin.node.js => testCrashReporterPlugin.node.tsx} (82%) rename desktop/plugins/crash_reporter/{index.js => index.tsx} (87%) create mode 100644 desktop/plugins/crash_reporter/unicode-substring.d.tsx diff --git a/desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.js b/desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.tsx similarity index 82% rename from desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.js rename to desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.tsx index b8ef5fa71..4112e47cb 100644 --- a/desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.js +++ b/desktop/plugins/crash_reporter/__tests__/testCrashReporterPlugin.node.tsx @@ -12,7 +12,7 @@ import CrashReporterPlugin from '..'; import type {PersistedState, Crash} from '..'; import { parseCrashLog, - getNewPersisitedStateFromCrashLog, + getNewPersistedStateFromCrashLog, parsePath, shouldShowCrashNotification, } from '..'; @@ -70,7 +70,7 @@ afterAll(() => { test('test the parsing of the date and crash info for the log which matches the predefined regex', () => { const log = 'Blaa Blaaa \n Blaa Blaaa \n Exception Type: SIGSEGV \n Blaa Blaa \n Blaa Blaa Date/Time: 2019-03-21 12:07:00.861 +0000 \n Blaa balaaa'; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', null); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('SIGSEGV'); expect(crash.name).toEqual('SIGSEGV'); @@ -80,7 +80,7 @@ test('test the parsing of the date and crash info for the log which matches the test('test the parsing of the reason for crash when log matches the crash regex, but there is no mention of date', () => { const log = 'Blaa Blaaa \n Blaa Blaaa \n Exception Type: SIGSEGV \n Blaa Blaa \n Blaa Blaa'; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', undefined); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('SIGSEGV'); expect(crash.name).toEqual('SIGSEGV'); @@ -89,7 +89,7 @@ test('test the parsing of the reason for crash when log matches the crash regex, test('test the parsing of the crash log when log does not match the predefined regex but is alphanumeric', () => { const log = 'Blaa Blaaa \n Blaa Blaaa \n Blaa Blaaa'; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', undefined); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('Cannot figure out the cause'); @@ -98,7 +98,7 @@ test('test the parsing of the crash log when log does not match the predefined r test('test the parsing of the reason for crash when log does not match the predefined regex contains unicode character', () => { const log = 'Blaa Blaaa \n Blaa Blaaa \n Exception Type: 🍕🐬 \n Blaa Blaa \n Blaa Blaa'; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', undefined); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('Cannot figure out the cause'); @@ -106,7 +106,7 @@ test('test the parsing of the reason for crash when log does not match the prede }); test('test the parsing of the reason for crash when log is empty', () => { const log = ''; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', undefined); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('Cannot figure out the cause'); @@ -126,7 +126,7 @@ test('test the parsing of the Android crash log for the proper android crash for }); test('test the parsing of the Android crash log for the unknown crash format and no date', () => { const log = 'Blaa Blaa Blaa'; - const crash = parseCrashLog(log, 'Android'); + const crash = parseCrashLog(log, 'Android', undefined); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('Cannot figure out the cause'); @@ -134,7 +134,7 @@ test('test the parsing of the Android crash log for the unknown crash format and }); test('test the parsing of the Android crash log for the partial format matching the crash format', () => { const log = 'First Line Break \n Blaa Blaa \n Blaa Blaa '; - const crash = parseCrashLog(log, 'Android'); + const crash = parseCrashLog(log, 'Android', null); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('First Line Break '); @@ -142,26 +142,26 @@ test('test the parsing of the Android crash log for the partial format matching test('test the parsing of the Android crash log with os being iOS', () => { const log = 'FATAL EXCEPTION: main\nProcess: com.facebook.flipper.sample, PID: 27026\njava.lang.IndexOutOfBoundsException: Index: 190, Size: 0\n\tat java.util.ArrayList.get(ArrayList.java:437)\n\tat com.facebook.flipper.sample.RootComponentSpec.hitGetRequest(RootComponentSpec.java:72)\n\tat com.facebook.flipper.sample.RootComponent.hitGetRequest(RootComponent.java:46)\n'; - const crash = parseCrashLog(log, 'iOS'); + const crash = parseCrashLog(log, 'iOS', null); expect(crash.callstack).toEqual(log); expect(crash.reason).toEqual('Cannot figure out the cause'); expect(crash.name).toEqual('Cannot figure out the cause'); }); test('test the getter of pluginKey with proper input', () => { - const device = new BaseDevice('serial', 'emulator', 'test device'); + const device = new BaseDevice('serial', 'emulator', 'test device', 'iOS'); const pluginKey = getPluginKey(null, device, 'CrashReporter'); expect(pluginKey).toEqual('serial#CrashReporter'); }); test('test the getter of pluginKey with undefined input', () => { - const pluginKey = getPluginKey(null, undefined, 'CrashReporter'); + const pluginKey = getPluginKey(null, null, 'CrashReporter'); expect(pluginKey).toEqual('unknown#CrashReporter'); }); test('test the getter of pluginKey with defined selected app', () => { - const pluginKey = getPluginKey('selectedApp', undefined, 'CrashReporter'); + const pluginKey = getPluginKey('selectedApp', null, 'CrashReporter'); expect(pluginKey).toEqual('selectedApp#CrashReporter'); }); test('test the getter of pluginKey with defined selected app and defined base device', () => { - const device = new BaseDevice('serial', 'emulator', 'test device'); + const device = new BaseDevice('serial', 'emulator', 'test device', 'iOS'); const pluginKey = getPluginKey('selectedApp', device, 'CrashReporter'); expect(pluginKey).toEqual('selectedApp#CrashReporter'); }); @@ -177,12 +177,12 @@ test('test getPersistedState for non-empty defaultPersistedState and undefined p const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); setDefaultPersistedState({crashes: [crash]}); const pluginStates = {}; - const perisistedState = getPersistedState( + const persistedState = getPersistedState( getPluginKey(null, null, CrashReporterPlugin.id), CrashReporterPlugin, pluginStates, ); - expect(perisistedState).toEqual({crashes: [crash]}); + expect(persistedState).toEqual({crashes: [crash]}); }); test('test getPersistedState for non-empty defaultPersistedState and defined pluginState', () => { const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); @@ -190,40 +190,42 @@ test('test getPersistedState for non-empty defaultPersistedState and defined plu setDefaultPersistedState({crashes: [crash]}); const pluginStateCrash = getCrash(1, 'callstack', 'crash1', 'crash1'); const pluginStates = {'unknown#CrashReporter': {crashes: [pluginStateCrash]}}; - const perisistedState = getPersistedState( + const persistedState = getPersistedState( pluginKey, CrashReporterPlugin, pluginStates, ); - expect(perisistedState).toEqual({crashes: [pluginStateCrash]}); + expect(persistedState).toEqual({crashes: [pluginStateCrash]}); }); -test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState and defined pluginState', () => { +test('test getNewPersistedStateFromCrashLog for non-empty defaultPersistedState and defined pluginState', () => { const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); const pluginKey = getPluginKey(null, null, CrashReporterPlugin.id); setDefaultPersistedState({crashes: [crash]}); const pluginStateCrash = getCrash(1, 'callstack', 'crash1', 'crash1'); const pluginStates = {'unknown#CrashReporter': {crashes: [pluginStateCrash]}}; - const perisistedState = getPersistedState( + const persistedState = getPersistedState( pluginKey, CrashReporterPlugin, pluginStates, ); const content = 'Blaa Blaaa \n Blaa Blaaa \n Exception Type: SIGSEGV \n Blaa Blaa \n Blaa Blaa'; - expect(perisistedState).toBeDefined(); - const {crashes} = perisistedState; + expect(persistedState).toBeDefined(); + const definedState = persistedState as PersistedState; + const {crashes} = definedState; expect(crashes).toBeDefined(); expect(crashes.length).toEqual(1); expect(crashes[0]).toEqual(pluginStateCrash); - const newPersistedState = getNewPersisitedStateFromCrashLog( - perisistedState, + const newPersistedState = getNewPersistedStateFromCrashLog( + definedState, CrashReporterPlugin, content, 'iOS', + null, ); expect(newPersistedState).toBeDefined(); - // $FlowFixMe: Checked if perisistedState is defined or not - const newPersistedStateCrashes = newPersistedState.crashes; + const newDefinedState = newPersistedState as PersistedState; + const newPersistedStateCrashes = newDefinedState.crashes; expect(newPersistedStateCrashes).toBeDefined(); expect(newPersistedStateCrashes.length).toEqual(2); assertCrash(newPersistedStateCrashes[0], pluginStateCrash); @@ -232,34 +234,35 @@ test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState getCrash(1, content, 'SIGSEGV', 'SIGSEGV'), ); }); -test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState and undefined pluginState', () => { +test('test getNewPersistedStateFromCrashLog for non-empty defaultPersistedState and undefined pluginState', () => { setNotificationID(0); const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); const pluginKey = getPluginKey(null, null, CrashReporterPlugin.id); setDefaultPersistedState({crashes: [crash]}); const pluginStates = {}; - const perisistedState = getPersistedState( + const persistedState = getPersistedState( pluginKey, CrashReporterPlugin, pluginStates, ); const content = 'Blaa Blaaa \n Blaa Blaaa \n Exception Type: SIGSEGV'; - expect(perisistedState).toEqual({crashes: [crash]}); - const newPersistedState = getNewPersisitedStateFromCrashLog( - perisistedState, + expect(persistedState).toEqual({crashes: [crash]}); + const newPersistedState = getNewPersistedStateFromCrashLog( + persistedState as PersistedState, CrashReporterPlugin, content, 'iOS', + null, ); expect(newPersistedState).toBeDefined(); // $FlowFixMe: Checked if perisistedState is defined or not - const {crashes} = newPersistedState; + const {crashes} = newPersistedState as PersistedState; expect(crashes).toBeDefined(); expect(crashes.length).toEqual(2); assertCrash(crashes[0], crash); assertCrash(crashes[1], getCrash(1, content, 'SIGSEGV', 'SIGSEGV')); }); -test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState and defined pluginState and improper crash log', () => { +test('test getNewPersistedStateFromCrashLog for non-empty defaultPersistedState and defined pluginState and improper crash log', () => { setNotificationID(0); const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); const pluginKey = getPluginKey(null, null, CrashReporterPlugin.id); @@ -273,15 +276,16 @@ test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState ); const content = 'Blaa Blaaa \n Blaa Blaaa'; expect(perisistedState).toEqual({crashes: [pluginStateCrash]}); - const newPersistedState = getNewPersisitedStateFromCrashLog( - perisistedState, + const newPersistedState = getNewPersistedStateFromCrashLog( + perisistedState as PersistedState, CrashReporterPlugin, content, 'iOS', + null, ); expect(newPersistedState).toBeDefined(); // $FlowFixMe: Checked if perisistedState is defined or not - const {crashes} = newPersistedState; + const {crashes} = newPersistedState as PersistedState; expect(crashes).toBeDefined(); expect(crashes.length).toEqual(2); assertCrash(crashes[0], pluginStateCrash); @@ -295,23 +299,25 @@ test('test getNewPersisitedStateFromCrashLog for non-empty defaultPersistedState ), ); }); -test('test getNewPersisitedStateFromCrashLog when os is undefined', () => { +test('test getNewPersistedStateFromCrashLog when os is undefined', () => { setNotificationID(0); const crash = getCrash(0, 'callstack', 'crash0', 'crash0'); const pluginKey = getPluginKey(null, null, CrashReporterPlugin.id); setDefaultPersistedState({crashes: [crash]}); const pluginStateCrash = getCrash(1, 'callstack', 'crash1', 'crash1'); const pluginStates = {'unknown#CrashReporter': {crashes: [pluginStateCrash]}}; - const perisistedState = getPersistedState( + const persistedState = getPersistedState( pluginKey, CrashReporterPlugin, pluginStates, ); const content = 'Blaa Blaaa \n Blaa Blaaa'; - const newPersistedState = getNewPersisitedStateFromCrashLog( - perisistedState, + const newPersistedState = getNewPersistedStateFromCrashLog( + persistedState as PersistedState, CrashReporterPlugin, content, + undefined, + null, ); expect(newPersistedState).toEqual(null); }); @@ -347,22 +353,44 @@ test('test parsing of path when a regex is not present', () => { expect(id).toEqual(null); }); test('test shouldShowCrashNotification function for all correct inputs', () => { - const device = new BaseDevice('TH1S-15DEV1CE-1D', 'emulator', 'test device'); + const device = new BaseDevice( + 'TH1S-15DEV1CE-1D', + 'emulator', + 'test device', + 'iOS', + ); const content = 'Blaa Blaaa \n Blaa Blaaa \n Path: path/to/simulator/TH1S-15DEV1CE-1D/App Name.app/App Name \n Blaa Blaa \n Blaa Blaa'; - const shouldShowNotification = shouldShowCrashNotification(device, content); + const shouldShowNotification = shouldShowCrashNotification( + device, + content, + 'iOS', + ); expect(shouldShowNotification).toEqual(true); }); test('test shouldShowCrashNotification function for all correct inputs but incorrect id', () => { - const device = new BaseDevice('TH1S-15DEV1CE-1D', 'emulator', 'test device'); + const device = new BaseDevice( + 'TH1S-15DEV1CE-1D', + 'emulator', + 'test device', + 'iOS', + ); const content = 'Blaa Blaaa \n Blaa Blaaa \n Path: path/to/simulator/TH1S-1598DEV1CE-2D/App Name.app/App Name \n Blaa Blaa \n Blaa Blaa'; - const shouldShowNotification = shouldShowCrashNotification(device, content); + const shouldShowNotification = shouldShowCrashNotification( + device, + content, + 'iOS', + ); expect(shouldShowNotification).toEqual(false); }); test('test shouldShowCrashNotification function for undefined device', () => { const content = 'Blaa Blaaa \n Blaa Blaaa \n Path: path/to/simulator/TH1S-1598DEV1CE-2D/App Name.app/App Name \n Blaa Blaa \n Blaa Blaa'; - const shouldShowNotification = shouldShowCrashNotification(null, content); + const shouldShowNotification = shouldShowCrashNotification( + null, + content, + 'iOS', + ); expect(shouldShowNotification).toEqual(false); }); diff --git a/desktop/plugins/crash_reporter/index.js b/desktop/plugins/crash_reporter/index.tsx similarity index 87% rename from desktop/plugins/crash_reporter/index.js rename to desktop/plugins/crash_reporter/index.tsx index 6130e67a5..bab95312f 100644 --- a/desktop/plugins/crash_reporter/index.js +++ b/desktop/plugins/crash_reporter/index.tsx @@ -9,6 +9,7 @@ */ import { + FlipperBasePlugin, FlipperDevicePlugin, Device, View, @@ -37,57 +38,63 @@ import path from 'path'; import {promisify} from 'util'; import type {Notification} from 'flipper'; import type {Store, DeviceLogEntry, OS, Props} from 'flipper'; +import React from 'react'; import {Component} from 'react'; +type Maybe = T | null | undefined; + type HeaderRowProps = { - title: string, - value: string, + title: string; + value: string; }; type openLogsCallbackType = () => void; -type CrashReporterBarProps = {| - openLogsCallback?: openLogsCallbackType, - crashSelector: CrashSelectorProps, -|}; +type CrashReporterBarProps = { + openLogsCallback?: openLogsCallbackType; + crashSelector: CrashSelectorProps; +}; -type CrashSelectorProps = {| - crashes: ?{[key: string]: string}, - orderedIDs: ?Array, - selectedCrashID: ?string, - onCrashChange: ?(string) => void, -|}; +type CrashSelectorProps = { + crashes?: {[key: string]: string}; + orderedIDs?: Array; + selectedCrashID?: string; + onCrashChange: (name: Maybe) => void; +}; -export type Crash = {| - notificationID: string, - callstack: ?string, - reason: string, - name: string, - date: Date, -|}; +export type Crash = { + notificationID: string; + callstack?: string; + reason: string; + name: string; + date: Date; +}; -export type CrashLog = {| - callstack: string, - reason: string, - name: string, - date: ?Date, -|}; +export type CrashLog = { + callstack: string; + reason: string; + name: string; + date: Maybe; +}; export type PersistedState = { - crashes: Array, + crashes: Array; }; type State = { - crash: ?Crash, + crash?: Crash; }; -const Padder = styled.div( - ({paddingLeft, paddingRight, paddingBottom, paddingTop}) => ({ - paddingLeft: paddingLeft || 0, - paddingRight: paddingRight || 0, - paddingBottom: paddingBottom || 0, - paddingTop: paddingTop || 0, - }), -); +const Padder = styled.div<{ + paddingLeft?: number; + paddingRight?: number; + paddingBottom?: number; + paddingTop?: number; +}>(({paddingLeft, paddingRight, paddingBottom, paddingTop}) => ({ + paddingLeft: paddingLeft || 0, + paddingRight: paddingRight || 0, + paddingBottom: paddingBottom || 0, + paddingTop: paddingTop || 0, +})); const Title = styled(Text)({ fontWeight: 'bold', @@ -183,13 +190,13 @@ const StackTraceContainer = styled(FlexColumn)({ const UNKNOWN_CRASH_REASON = 'Cannot figure out the cause'; -export function getNewPersisitedStateFromCrashLog( - persistedState: ?PersistedState, - persistingPlugin: Class | FlipperPlugin<>>, +export function getNewPersistedStateFromCrashLog( + persistedState: Maybe, + persistingPlugin: typeof FlipperBasePlugin, content: string, - os: ?OS, - logDate: ?Date, -): ?PersistedState { + os: Maybe, + logDate: Maybe, +): Maybe { const persistedStateReducer = persistingPlugin.persistedStateReducer; if (!os || !persistedStateReducer) { return null; @@ -208,9 +215,9 @@ export function parseCrashLogAndUpdateState( content: string, setPersistedState: ( pluginKey: string, - newPluginState: ?PersistedState, + newPluginState: Maybe, ) => void, - logDate: ?Date, + logDate: Maybe, ) { const os = store.getState().connections.selectedDevice?.os; if ( @@ -228,9 +235,11 @@ export function parseCrashLogAndUpdateState( store.getState().connections.selectedDevice, pluginID, ); - const persistingPlugin: ?Class< - FlipperDevicePlugin<> | FlipperPlugin<>, - > = store.getState().plugins.devicePlugins.get(CrashReporterPlugin.id); + const persistingPlugin: + | typeof FlipperBasePlugin + | undefined = store + .getState() + .plugins.devicePlugins.get(CrashReporterPlugin.id); if (!persistingPlugin) { return; } @@ -240,8 +249,11 @@ export function parseCrashLogAndUpdateState( persistingPlugin, pluginStates, ); - const newPluginState = getNewPersisitedStateFromCrashLog( - persistedState, + if (!persistedState) { + return; + } + const newPluginState = getNewPersistedStateFromCrashLog( + persistedState as PersistedState, persistingPlugin, content, os, @@ -251,9 +263,9 @@ export function parseCrashLogAndUpdateState( } export function shouldShowCrashNotification( - baseDevice: ?BaseDevice, + baseDevice: Maybe, content: string, - os: ?OS, + os: Maybe, ): boolean { if (os && os === 'Android') { return true; @@ -270,7 +282,7 @@ export function shouldShowCrashNotification( export function parseCrashLog( content: string, os: OS, - logDate: ?Date, + logDate: Maybe, ): CrashLog { const fallbackReason = UNKNOWN_CRASH_REASON; switch (os) { @@ -289,12 +301,12 @@ export function parseCrashLog( const dateString = dateArr ? dateArr[0] : ''; const dateRegex2 = /[\w\s\.:-]*$/; const tmp1 = dateRegex2.exec(dateString); - const extractedDateString: ?string = + const extractedDateString: Maybe = tmp1 && tmp1[0].length ? tmp1[0] : null; date = extractedDateString ? new Date(extractedDateString) : logDate; } - const crash = { + const crash: CrashLog = { callstack: content, name: exception, reason: exception, @@ -314,14 +326,15 @@ export function parseCrashLog( if (remainingString[remainingString.length - 1] === '\n') { remainingString = remainingString.slice(0, -1); } - const reason = + const reasonText = remainingString.length > 0 ? remainingString.split('\n').pop() : fallbackReason; + const reason = reasonText ? reasonText : fallbackReason; if (name[name.length - 1] === '\n') { name = name.slice(0, -1); } - const crash = { + const crash: CrashLog = { callstack: content, name: name, reason: reason, @@ -343,7 +356,7 @@ function truncate(baseString: string, numOfChars: number): string { return truncated_string + '\u2026'; } -export function parsePath(content: string): ?string { +export function parsePath(content: string): Maybe { const regex = /Path: *[\w\-\/\.\t\ \_\%]*\n/; const arr = regex.exec(content); if (!arr || arr.length <= 0) { @@ -363,7 +376,7 @@ function addFileWatcherForiOSCrashLogs( store: Store, setPersistedState: ( pluginKey: string, - newPluginState: ?PersistedState, + newPluginState: Maybe, ) => void, ) { const dir = path.join(os.homedir(), 'Library', 'Logs', 'DiagnosticReports'); @@ -395,6 +408,7 @@ function addFileWatcherForiOSCrashLogs( store, util.format(data), setPersistedState, + null, ); }); }); @@ -412,8 +426,8 @@ class CrashSelector extends Component { disabled={Boolean(!orderedIDs || orderedIDs.length <= 1)} compact={true} onClick={() => { - if (onCrashChange && orderedIDs) { - const index = orderedIDs.indexOf(selectedCrashID); + if (onCrashChange && orderedIDs && selectedCrashID) { + const index = orderedIDs.indexOf(selectedCrashID as string); const nextIndex = index < 1 ? orderedIDs.length - 1 : index - 1; const nextID = orderedIDs[nextIndex]; @@ -430,8 +444,8 @@ class CrashSelector extends Component { disabled={Boolean(!orderedIDs || orderedIDs.length <= 1)} compact={true} onClick={() => { - if (onCrashChange && orderedIDs) { - const index = orderedIDs.indexOf(selectedCrashID); + if (onCrashChange && orderedIDs && selectedCrashID) { + const index = orderedIDs.indexOf(selectedCrashID as string); const nextIndex = index >= orderedIDs.length - 1 ? 0 : index + 1; const nextID = orderedIDs[nextIndex]; @@ -506,7 +520,7 @@ class HeaderRow extends Component { } type StackTraceComponentProps = { - stacktrace: string, + stacktrace: string; }; class StackTraceComponent extends Component { @@ -525,10 +539,12 @@ class StackTraceComponent extends Component { export default class CrashReporterPlugin extends FlipperDevicePlugin< State, - void, - PersistedState, + any, + PersistedState > { - static defaultPersistedState = {crashes: []}; + static defaultPersistedState: PersistedState = { + crashes: [], + }; static supportsDevice(device: Device) { return ( @@ -544,7 +560,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< static persistedStateReducer = ( persistedState: PersistedState, method: string, - payload: Object, + payload: CrashLog | Crash, ): PersistedState => { if (method === 'crash-report' || method === 'flipper-crash-report') { CrashReporterPlugin.notificationID++; @@ -615,7 +631,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< baseDevice: BaseDevice, setPersistedState: ( pluginKey: string, - newPluginState: ?PersistedState, + newPluginState: Maybe, ) => void, ): void => { if (baseDevice.os.includes('iOS')) { @@ -627,12 +643,12 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< date: Date, setPersistedState: ( pluginKey: string, - newPluginState: ?PersistedState, + newPluginState: Maybe, ) => void, ) { let androidLog: string = ''; let androidLogUnderProcess = false; - let timer = null; + let timer: Maybe = null; baseDevice.addLogListener((entry: DeviceLogEntry) => { if (shouldParseAndroidLog(entry, referenceDate)) { if (androidLogUnderProcess) { @@ -669,7 +685,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< constructor(props: Props) { // Required step: always call the parent class' constructor super(props); - let crash: ?Crash = null; + let crash: Crash | undefined = undefined; if ( this.props.persistedState.crashes && this.props.persistedState.crashes.length > 0 @@ -679,7 +695,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< ]; } - let deeplinkedCrash = null; + let deeplinkedCrash: Crash | undefined = undefined; if (this.props.deepLinkPayload) { const id = this.props.deepLinkPayload; const index = this.props.persistedState.crashes.findIndex((elem) => { @@ -720,7 +736,7 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< (persistedCrash) => persistedCrash.notificationID, ); const selectedCrashID = crash.notificationID; - const onCrashChange = (id) => { + const onCrashChange = (id: Maybe) => { const newSelectedCrash = crashes.find( (element) => element.notificationID === id, ); @@ -784,10 +800,10 @@ export default class CrashReporterPlugin extends FlipperDevicePlugin< ); } const crashSelector = { - crashes: null, - orderedIDs: null, - selectedCrashID: null, - onCrashChange: null, + crashes: undefined, + orderedIDs: undefined, + selectedCrashID: undefined, + onCrashChange: () => void {}, }; return ( diff --git a/desktop/plugins/crash_reporter/package.json b/desktop/plugins/crash_reporter/package.json index 3a532c5db..8b5bc3748 100644 --- a/desktop/plugins/crash_reporter/package.json +++ b/desktop/plugins/crash_reporter/package.json @@ -5,7 +5,7 @@ "version": "0.50.0", "description": "A plugin which will display a crash", "main": "dist/bundle.js", - "flipperBundlerEntry": "index.js", + "flipperBundlerEntry": "index.tsx", "repository": "https://github.com/facebook/flipper", "license": "MIT", "keywords": [ diff --git a/desktop/plugins/crash_reporter/unicode-substring.d.tsx b/desktop/plugins/crash_reporter/unicode-substring.d.tsx new file mode 100644 index 000000000..1b8b15576 --- /dev/null +++ b/desktop/plugins/crash_reporter/unicode-substring.d.tsx @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +declare module 'unicode-substring' { + const unicodeSubstring: ( + string: string, + start: number, + end: number, + ) => string; + export default unicodeSubstring; +}