diff --git a/eslint.config.mjs b/eslint.config.mjs index 11ca6d0516..698d1b9c07 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,7 @@ +import { defineConfig } from 'eslint/config'; import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; import tsParser from '@typescript-eslint/parser'; -import tsPlugin from '@typescript-eslint/eslint-plugin'; import babelPlugin from '@babel/eslint-plugin'; import reactPlugin from 'eslint-plugin-react'; import importPlugin from 'eslint-plugin-import'; @@ -11,7 +12,7 @@ import jestDomPlugin from 'eslint-plugin-jest-dom'; import prettierConfig from 'eslint-config-prettier'; import globals from 'globals'; -export default [ +export default defineConfig( // Global ignores { ignores: [ @@ -27,8 +28,8 @@ export default [ // Base JavaScript config js.configs.recommended, - // TypeScript config - ...tsPlugin.configs['flat/recommended'], + // TypeScript config with type checking + ...tseslint.configs.recommendedTypeChecked, // React config reactPlugin.configs.flat.recommended, @@ -50,6 +51,7 @@ export default [ ecmaFeatures: { jsx: true, }, + // Note: projectService is configured per file type below }, }, plugins: { @@ -178,6 +180,40 @@ export default [ }, ], '@typescript-eslint/no-require-imports': 'off', + + // Disable "no-unsafe" checks which complain about using "any" freely. + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + + // Disable this one due to false positives when narrowing return types, + // see https://github.com/typescript-eslint/typescript-eslint/issues/6951 + // (it can make `yarn ts` fail after `yarn lint-fix`) + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + + '@typescript-eslint/no-unnecessary-condition': [ + 'error', + { + allowConstantLoopConditions: 'only-allowed-literals', + checkTypePredicates: true, + }, + ], + + // Consider enabling these in the future + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/only-throw-error': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/await-thenable': 'off', + '@typescript-eslint/restrict-plus-operands': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/prefer-promise-reject-errors': 'off', + '@typescript-eslint/no-array-delete': 'off', }, linterOptions: { // This property is specified both here in addition to the command line in @@ -189,6 +225,23 @@ export default [ }, }, + // TypeScript files - enable type checking + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + + // JavaScript files - disable type-aware rules (they can't run on JS anyway) + { + files: ['**/*.js', '**/*.mjs', '**/*.cjs'], + ...tseslint.configs.disableTypeChecked, + }, + // Source files - enable stricter TypeScript rules { files: ['src/**/*.ts', 'src/**/*.tsx'], @@ -255,7 +308,7 @@ export default [ }, }, - // __mocks__ directory configuration + // __mocks__ directory configuration - globals { files: ['__mocks__/**/*'], languageOptions: { @@ -266,5 +319,5 @@ export default [ }, // Prettier config (must be last to override other formatting rules) - prettierConfig, -]; + prettierConfig +); diff --git a/package.json b/package.json index d39d446051..ccbf847dfb 100644 --- a/package.json +++ b/package.json @@ -184,6 +184,7 @@ "stylelint-config-idiomatic-order": "^10.0.0", "stylelint-config-standard": "^39.0.0", "typescript": "^5.8.3", + "typescript-eslint": "^8.44.0", "webpack": "^5.101.3", "webpack-cli": "^6.0.1", "webpack-dev-server": "^5.2.2", diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts index 43af88bb8b..675e2eb48d 100644 --- a/src/actions/profile-view.ts +++ b/src/actions/profile-view.ts @@ -1080,7 +1080,6 @@ export function isolateProcess( for (const localTrack of localTracks) { if ( localTrack.type === 'thread' && - localTrack.threadIndex !== undefined && oldSelectedThreadIndexes.has(localTrack.threadIndex) ) { newSelectedThreadIndexes.add(localTrack.threadIndex); diff --git a/src/actions/receive-profile.ts b/src/actions/receive-profile.ts index 0bd60fb0ec..0d2e704f2d 100644 --- a/src/actions/receive-profile.ts +++ b/src/actions/receive-profile.ts @@ -1096,7 +1096,7 @@ async function _extractJsonFromResponse( message = 'The network request to load the profile was aborted.'; } else if (fileType === 'application/json') { message = 'The profile’s JSON could not be decoded.'; - } else if (fileType === null && arrayBuffer !== null) { + } else if (arrayBuffer !== null) { // If the content type is not specified, use a raw array buffer // to fallback to other supported profile formats. return arrayBuffer; @@ -1163,10 +1163,6 @@ export function retrieveProfileOrZipFromUrl( serializedProfile, profileUrl ); - if (profile === undefined) { - throw new Error('Unable to parse the profile.'); - } - await dispatch(loadProfile(profile, {}, initialLoad)); break; } diff --git a/src/app-logic/url-handling.ts b/src/app-logic/url-handling.ts index df7b8adbae..571313bb48 100644 --- a/src/app-logic/url-handling.ts +++ b/src/app-logic/url-handling.ts @@ -892,7 +892,7 @@ const _upgraders: { // will not be preserved. const transforms = parseTransforms(query.transforms); - if (!transforms || transforms.length === 0) { + if (transforms.length === 0) { // We don't have any transforms to upgrade. return; } diff --git a/src/app-logic/web-channel.ts b/src/app-logic/web-channel.ts index 2dbe25fbf0..539ad6be73 100644 --- a/src/app-logic/web-channel.ts +++ b/src/app-logic/web-channel.ts @@ -96,6 +96,7 @@ export type ResponseFromBrowser = | GetSymbolTableResponse | QuerySymbolicationApiResponse | GetPageFaviconsResponse + // eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents | OpenScriptInTabDebuggerResponse; type StatusQueryResponse = { diff --git a/src/components/app/CompareHome.tsx b/src/components/app/CompareHome.tsx index 71a1923459..2eac84424c 100644 --- a/src/components/app/CompareHome.tsx +++ b/src/components/app/CompareHome.tsx @@ -23,7 +23,7 @@ type State = { }; class CompareHomeImpl extends PureComponent { - override state = { profile1: '', profile2: '' }; + override state: State = { profile1: '', profile2: '' }; handleInputChange = (event: React.ChangeEvent) => { const { name, value } = event.target; diff --git a/src/components/app/FooterLinks.tsx b/src/components/app/FooterLinks.tsx index d1fb2745c8..a570915cda 100644 --- a/src/components/app/FooterLinks.tsx +++ b/src/components/app/FooterLinks.tsx @@ -15,7 +15,7 @@ export class FooterLinks extends PureComponent<{}, State> { this.setState({ hide: true }); }; - override state = { + override state: State = { hide: false, }; diff --git a/src/components/app/Home.tsx b/src/components/app/Home.tsx index 99e4d67898..15045dfd18 100644 --- a/src/components/app/Home.tsx +++ b/src/components/app/Home.tsx @@ -54,7 +54,7 @@ class ActionButtons extends React.PureComponent< > { _fileInput: HTMLInputElement | null = null; - override state = { + override state: ActionButtonsState = { isLoadFromUrlPressed: false, }; @@ -129,7 +129,7 @@ class LoadFromUrl extends React.PureComponent< LoadFromUrlProps, LoadFromUrlState > { - override state = { + override state: LoadFromUrlState = { value: '', }; diff --git a/src/components/app/KeyboardShortcut.tsx b/src/components/app/KeyboardShortcut.tsx index 58ee157ca1..b0c648f658 100644 --- a/src/components/app/KeyboardShortcut.tsx +++ b/src/components/app/KeyboardShortcut.tsx @@ -23,7 +23,7 @@ type State = { * Display a list of shortcuts that overlays the screen. */ export class KeyboardShortcut extends React.PureComponent { - override state = { + override state: State = { isOpen: false, // The eslint error is a false positive due to how it's used, see the line: // `focusAfterClosed.focus()` diff --git a/src/components/app/ListOfPublishedProfiles.tsx b/src/components/app/ListOfPublishedProfiles.tsx index 650c87f432..574b89b709 100644 --- a/src/components/app/ListOfPublishedProfiles.tsx +++ b/src/components/app/ListOfPublishedProfiles.tsx @@ -49,7 +49,7 @@ class PublishedProfile extends React.PureComponent< PublishedProfileProps, PublishedProfileState > { - override state = { + override state: PublishedProfileState = { confirmDialogIsOpen: false, }; @@ -162,7 +162,7 @@ type State = { export class ListOfPublishedProfiles extends PureComponent { _isMounted = false; - override state = { + override state: State = { uploadedProfileInformationList: null, }; diff --git a/src/components/app/MenuButtons/MetaInfo.tsx b/src/components/app/MenuButtons/MetaInfo.tsx index f9b319342a..87fd9e7058 100644 --- a/src/components/app/MenuButtons/MetaInfo.tsx +++ b/src/components/app/MenuButtons/MetaInfo.tsx @@ -55,7 +55,7 @@ type Props = ConnectedProps<{}, StateProps, DispatchProps>; * This component formats the profile's meta information into a dropdown panel. */ class MetaInfoPanelImpl extends React.PureComponent { - override state = { showsMoreInfo: false }; + override state: State = { showsMoreInfo: false }; /** * This method provides information about the symbolication status, and a button diff --git a/src/components/app/MenuButtons/Permalink.tsx b/src/components/app/MenuButtons/Permalink.tsx index 42f165e726..f0748f66e2 100644 --- a/src/components/app/MenuButtons/Permalink.tsx +++ b/src/components/app/MenuButtons/Permalink.tsx @@ -30,7 +30,7 @@ export class MenuButtonsPermalink extends React.PureComponent { this._permalinkTextField = elem; }; - override state = { + override state: State = { fullUrl: '', shortUrl: '', }; diff --git a/src/components/app/ProfileName.tsx b/src/components/app/ProfileName.tsx index 12e78e7df9..ced242dd2e 100644 --- a/src/components/app/ProfileName.tsx +++ b/src/components/app/ProfileName.tsx @@ -37,7 +37,7 @@ type State = { * state), and then when active, it switches to an input, which is only fixed in size. */ class ProfileNameImpl extends React.PureComponent { - override state = { + override state: State = { focusedWithKey: null, focusGeneration: 0, }; diff --git a/src/components/js-tracer/Canvas.tsx b/src/components/js-tracer/Canvas.tsx index abed86ac95..a40c9928f3 100644 --- a/src/components/js-tracer/Canvas.tsx +++ b/src/components/js-tracer/Canvas.tsx @@ -90,7 +90,7 @@ const ROW_LABEL_OFFSET_LEFT: CssPixels = 5; const FONT_SIZE: CssPixels = 10; class JsTracerCanvasImpl extends React.PureComponent { - override state = { + override state: State = { hasFirstDraw: false, }; _textMeasurement: TextMeasurement | null = null; diff --git a/src/components/js-tracer/Chart.tsx b/src/components/js-tracer/Chart.tsx index c980c96d93..bbabf09c80 100644 --- a/src/components/js-tracer/Chart.tsx +++ b/src/components/js-tracer/Chart.tsx @@ -175,7 +175,7 @@ class JsTracerChartLoader extends React.PureComponent< ChartLoaderProps, ChartLoaderState > { - override state = { + override state: ChartLoaderState = { // The loader needs to be mounted before rendering the chart, as it has expensive // selectors. readyToRenderExpensiveChart: false, diff --git a/src/components/network-chart/NetworkChartRow.tsx b/src/components/network-chart/NetworkChartRow.tsx index e1bb62e180..2090b46c09 100644 --- a/src/components/network-chart/NetworkChartRow.tsx +++ b/src/components/network-chart/NetworkChartRow.tsx @@ -314,7 +314,7 @@ export class NetworkChartRow extends React.PureComponent< NetworkChartRowProps, State > { - override state = { + override state: State = { pageX: 0, pageY: 0, hovered: false, diff --git a/src/components/shared/ButtonWithPanel/ArrowPanel.tsx b/src/components/shared/ButtonWithPanel/ArrowPanel.tsx index 109ac54b84..7bc64f9a31 100644 --- a/src/components/shared/ButtonWithPanel/ArrowPanel.tsx +++ b/src/components/shared/ButtonWithPanel/ArrowPanel.tsx @@ -27,7 +27,7 @@ type State = { export class ArrowPanel extends React.PureComponent { closeTimeout: NodeJS.Timeout | null = null; - override state = { + override state: State = { open: false, isClosing: false, openGeneration: 0, diff --git a/src/components/shared/Draggable.tsx b/src/components/shared/Draggable.tsx index c463d035e6..c4648a2ed4 100644 --- a/src/components/shared/Draggable.tsx +++ b/src/components/shared/Draggable.tsx @@ -36,7 +36,7 @@ export class Draggable extends React.PureComponent, State> { mouseMoveHandler: (param: MouseEvent) => void; mouseUpHandler: (param: MouseEvent) => void; } | null = null; - override state = { + override state: State = { dragging: false, }; diff --git a/src/components/shared/MarkerSettings.tsx b/src/components/shared/MarkerSettings.tsx index d7f8383e2e..06dd707fd7 100644 --- a/src/components/shared/MarkerSettings.tsx +++ b/src/components/shared/MarkerSettings.tsx @@ -42,7 +42,7 @@ type State = { }; class MarkerSettingsImpl extends PureComponent { - override state = { + override state: State = { isMarkerFiltersMenuVisible: false, isFilterMenuVisibleOnMouseDown: false, }; diff --git a/src/components/shared/PanelSearch.tsx b/src/components/shared/PanelSearch.tsx index be4be2aef7..c1a93c8121 100644 --- a/src/components/shared/PanelSearch.tsx +++ b/src/components/shared/PanelSearch.tsx @@ -19,7 +19,7 @@ type Props = { type State = { searchFieldFocused: boolean }; export class PanelSearch extends React.PureComponent { - override state = { searchFieldFocused: false }; + override state: State = { searchFieldFocused: false }; _onSearchFieldIdleAfterChange = (value: string) => { this.props.onSearch(value); }; diff --git a/src/components/shared/Reorderable.tsx b/src/components/shared/Reorderable.tsx index ad287fca42..7165b11fde 100644 --- a/src/components/shared/Reorderable.tsx +++ b/src/components/shared/Reorderable.tsx @@ -65,7 +65,7 @@ export class Reorderable extends React.PureComponent { }, }; - override state = { + override state: State = { phase: 'RESTING' as const, manipulatingIndex: -1, destinationIndex: -1, diff --git a/src/components/shared/TreeView.tsx b/src/components/shared/TreeView.tsx index a6eb6e374d..8f3df2e829 100644 --- a/src/components/shared/TreeView.tsx +++ b/src/components/shared/TreeView.tsx @@ -485,7 +485,7 @@ export class TreeView< initialWidth: CssPixels; } | null = null; - override state = { + override state: TreeViewState = { // This contains the current widths, while or after the user resizes them. fixedColumnWidths: null, diff --git a/src/components/shared/VirtualList.tsx b/src/components/shared/VirtualList.tsx index bd01924cf2..bc634c9fc3 100644 --- a/src/components/shared/VirtualList.tsx +++ b/src/components/shared/VirtualList.tsx @@ -260,7 +260,7 @@ export class VirtualList extends React.PureComponent< VirtualListState > { _container: { current: HTMLDivElement | null } = React.createRef(); - override state = { scrollTop: 0, containerHeight: 0 }; + override state: VirtualListState = { scrollTop: 0, containerHeight: 0 }; override componentDidMount() { document.addEventListener('copy', this._onCopy, false); diff --git a/src/components/shared/Warning.tsx b/src/components/shared/Warning.tsx index de54bf4c76..9fc0827979 100644 --- a/src/components/shared/Warning.tsx +++ b/src/components/shared/Warning.tsx @@ -18,7 +18,7 @@ type State = { }; export class Warning extends PureComponent { - override state = { isNoticeDisplayed: true }; + override state: State = { isNoticeDisplayed: true }; _onHideClick = () => { this.setState({ diff --git a/src/components/shared/WithSize.tsx b/src/components/shared/WithSize.tsx index 596ddabba7..5c51da89c5 100644 --- a/src/components/shared/WithSize.tsx +++ b/src/components/shared/WithSize.tsx @@ -29,7 +29,7 @@ export function withSize( Wrapped: React.ComponentType> ): React.ComponentType { return class WithSizeWrapper extends React.PureComponent { - override state = { width: 0, height: 0 }; + override state: State = { width: 0, height: 0 }; _container: HTMLElement | null = null; override componentDidMount() { diff --git a/src/components/shared/thread/SampleGraph.tsx b/src/components/shared/thread/SampleGraph.tsx index 032e0bb35f..76f84afe23 100644 --- a/src/components/shared/thread/SampleGraph.tsx +++ b/src/components/shared/thread/SampleGraph.tsx @@ -243,7 +243,7 @@ class ThreadSampleGraphCanvas extends React.PureComponent { } export class ThreadSampleGraphImpl extends PureComponent { - override state = { + override state: State = { hoveredPixelState: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/FullTimeline.tsx b/src/components/timeline/FullTimeline.tsx index 32fa0629b2..b6c9921f5a 100644 --- a/src/components/timeline/FullTimeline.tsx +++ b/src/components/timeline/FullTimeline.tsx @@ -123,7 +123,7 @@ class TimelineSettingsHiddenTracks extends React.PureComponent<{ } class FullTimelineImpl extends React.PureComponent { - override state = { + override state: State = { initialSelected: null, }; diff --git a/src/components/timeline/Markers.tsx b/src/components/timeline/Markers.tsx index f75f72db74..6132a9770a 100644 --- a/src/components/timeline/Markers.tsx +++ b/src/components/timeline/Markers.tsx @@ -312,7 +312,7 @@ type State = { }; class TimelineMarkers extends React.PureComponent { - override state = { + override state: State = { hoveredMarkerIndex: null, mouseDownMarker: null, mouseX: 0, diff --git a/src/components/timeline/OverflowEdgeIndicator.tsx b/src/components/timeline/OverflowEdgeIndicator.tsx index b9c5bc0072..14f0c612df 100644 --- a/src/components/timeline/OverflowEdgeIndicator.tsx +++ b/src/components/timeline/OverflowEdgeIndicator.tsx @@ -28,7 +28,7 @@ class OverflowEdgeIndicator extends React.PureComponent { _contentsWrapper: HTMLDivElement | null = null; _scrolledToInitialSelected: boolean = false; - override state = { + override state: State = { overflowsOnTop: false, overflowsOnRight: false, overflowsOnBottom: false, diff --git a/src/components/timeline/TrackBandwidthGraph.tsx b/src/components/timeline/TrackBandwidthGraph.tsx index 6f05c80bd2..ab69a052a1 100644 --- a/src/components/timeline/TrackBandwidthGraph.tsx +++ b/src/components/timeline/TrackBandwidthGraph.tsx @@ -334,7 +334,7 @@ type State = { * graph in the timeline. */ class TrackBandwidthGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredCounter: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackContextMenu.tsx b/src/components/timeline/TrackContextMenu.tsx index d4939d3526..f90af33130 100644 --- a/src/components/timeline/TrackContextMenu.tsx +++ b/src/components/timeline/TrackContextMenu.tsx @@ -107,7 +107,7 @@ class TimelineTrackContextMenuImpl extends PureComponent< TimelineTrackContextMenuProps, TimelineTrackContextMenuState > { - override state = { searchFilter: '' }; + override state: TimelineTrackContextMenuState = { searchFilter: '' }; _globalTrackClickTimeout: NodeJS.Timeout | null = null; _trackSearchFieldElem: { current: TrackSearchField | null } = React.createRef(); diff --git a/src/components/timeline/TrackCustomMarkerGraph.tsx b/src/components/timeline/TrackCustomMarkerGraph.tsx index db5d254e00..67c4a8d3d7 100644 --- a/src/components/timeline/TrackCustomMarkerGraph.tsx +++ b/src/components/timeline/TrackCustomMarkerGraph.tsx @@ -358,7 +358,7 @@ type State = { * graph in the timeline. */ class TrackCustomMarkerGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredCounter: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackEventDelayGraph.tsx b/src/components/timeline/TrackEventDelayGraph.tsx index 85461b52c2..5dba93539f 100644 --- a/src/components/timeline/TrackEventDelayGraph.tsx +++ b/src/components/timeline/TrackEventDelayGraph.tsx @@ -197,7 +197,7 @@ type State = { * */ class TrackEventDelayGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredDelay: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackMemoryGraph.tsx b/src/components/timeline/TrackMemoryGraph.tsx index 8e1a0f74a6..e16edfe802 100644 --- a/src/components/timeline/TrackMemoryGraph.tsx +++ b/src/components/timeline/TrackMemoryGraph.tsx @@ -273,7 +273,7 @@ type State = { * graph in the timeline. */ class TrackMemoryGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredCounter: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackNetwork.tsx b/src/components/timeline/TrackNetwork.tsx index 04f6ffb664..339a4bc6ab 100644 --- a/src/components/timeline/TrackNetwork.tsx +++ b/src/components/timeline/TrackNetwork.tsx @@ -277,7 +277,7 @@ type State = { }; class Network extends PureComponent { - override state = { hoveredMarkerIndex: null, mouseX: 0, mouseY: 0 }; + override state: State = { hoveredMarkerIndex: null, mouseX: 0, mouseY: 0 }; _onHoveredMarkerChange = ( hoveredMarkerIndex: MarkerIndex | null, diff --git a/src/components/timeline/TrackPowerGraph.tsx b/src/components/timeline/TrackPowerGraph.tsx index c8613636f5..446eef23dc 100644 --- a/src/components/timeline/TrackPowerGraph.tsx +++ b/src/components/timeline/TrackPowerGraph.tsx @@ -304,7 +304,7 @@ type State = { * graph in the timeline. */ class TrackPowerGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredCounter: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackProcessCPUGraph.tsx b/src/components/timeline/TrackProcessCPUGraph.tsx index 0f6c7d7fe3..dbe9bfce8c 100644 --- a/src/components/timeline/TrackProcessCPUGraph.tsx +++ b/src/components/timeline/TrackProcessCPUGraph.tsx @@ -228,7 +228,7 @@ type State = { * graph in the timeline. */ class TrackProcessCPUGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredCounter: null, mouseX: 0, mouseY: 0, diff --git a/src/components/timeline/TrackScreenshots.tsx b/src/components/timeline/TrackScreenshots.tsx index 4ec906de4e..93a227301c 100644 --- a/src/components/timeline/TrackScreenshots.tsx +++ b/src/components/timeline/TrackScreenshots.tsx @@ -54,7 +54,7 @@ type State = { }; class Screenshots extends PureComponent { - override state = { + override state: State = { offsetX: null, pageX: null, containerTop: null, diff --git a/src/components/timeline/TrackVisualProgressGraph.tsx b/src/components/timeline/TrackVisualProgressGraph.tsx index bdf7f1d715..5aefdc4dd4 100644 --- a/src/components/timeline/TrackVisualProgressGraph.tsx +++ b/src/components/timeline/TrackVisualProgressGraph.tsx @@ -197,7 +197,7 @@ type State = { * graph in the timeline. */ class TrackVisualProgressGraphImpl extends React.PureComponent { - override state = { + override state: State = { hoveredVisualProgress: null, mouseX: 0, mouseY: 0, diff --git a/src/components/tooltip/DivWithTooltip.tsx b/src/components/tooltip/DivWithTooltip.tsx index bb430e9c79..aa1e0cef02 100644 --- a/src/components/tooltip/DivWithTooltip.tsx +++ b/src/components/tooltip/DivWithTooltip.tsx @@ -22,7 +22,7 @@ type State = { * a div. */ export class DivWithTooltip extends React.PureComponent { - override state = { + override state: State = { isMouseOver: false, mouseX: 0, mouseY: 0, diff --git a/src/profile-logic/profile-data.ts b/src/profile-logic/profile-data.ts index 76bff5aecf..fe16ff38dc 100644 --- a/src/profile-logic/profile-data.ts +++ b/src/profile-logic/profile-data.ts @@ -2773,15 +2773,11 @@ export function getThreadProcessDetails( ): string { let label = `${friendlyThreadName}\n`; label += `Thread: "${thread.name}"`; - if (thread.tid !== undefined) { - label += ` (${thread.tid})`; - } + label += ` (${thread.tid})`; if (thread.processType) { label += `\nProcess: "${thread.processType}"`; - if (thread.pid !== undefined) { - label += ` (${thread.pid})`; - } + label += ` (${thread.pid})`; } if (thread.isPrivateBrowsing) { diff --git a/src/profile-logic/tracks.ts b/src/profile-logic/tracks.ts index 44277e17b5..a4cf472a3c 100644 --- a/src/profile-logic/tracks.ts +++ b/src/profile-logic/tracks.ts @@ -144,10 +144,7 @@ function _getDefaultLocalTrackOrder( if (tracks[a].type === 'thread' && tracks[b].type === 'thread' && profile) { const idxA = tracks[a].threadIndex; const idxB = tracks[b].threadIndex; - if (idxA === undefined || idxB === undefined) { - return -1; - } - if (profile && profile.meta.keepProfileThreadOrder) { + if (profile.meta.keepProfileThreadOrder) { return idxA - idxB; } const nameA = profile.threads[idxA].name; diff --git a/src/reducers/app.ts b/src/reducers/app.ts index d3cff8785e..661071a1ae 100644 --- a/src/reducers/app.ts +++ b/src/reducers/app.ts @@ -176,7 +176,7 @@ const lastVisibleThreadTabSlug: Reducer = ( } }; -const trackThreadHeights: Reducer<{ [key: ThreadsKey]: CssPixels }> = ( +const trackThreadHeights: Reducer>> = ( state = {}, action ) => { diff --git a/src/selectors/app.tsx b/src/selectors/app.tsx index 65cb1d043e..496d2f4b4c 100644 --- a/src/selectors/app.tsx +++ b/src/selectors/app.tsx @@ -58,9 +58,9 @@ export const getPanelLayoutGeneration: Selector = (state) => getApp(state).panelLayoutGeneration; export const getLastVisibleThreadTabSlug: Selector = (state) => getApp(state).lastVisibleThreadTabSlug; -export const getTrackThreadHeights: Selector<{ - [key: ThreadsKey]: CssPixels; -}> = (state) => getApp(state).trackThreadHeights; +export const getTrackThreadHeights: Selector< + Partial> +> = (state) => getApp(state).trackThreadHeights; export const getIsNewlyPublished: Selector = (state) => getApp(state).isNewlyPublished; export const getExperimental: Selector = (state) => diff --git a/src/selectors/profile.ts b/src/selectors/profile.ts index 13ed4a647b..a596fb8ee2 100644 --- a/src/selectors/profile.ts +++ b/src/selectors/profile.ts @@ -274,7 +274,7 @@ export const getMarkerSchemaByName: Selector = type CounterSelectors = ReturnType; -const _counterSelectors: { [key: number]: CounterSelectors } = {}; +const _counterSelectors: Partial> = {}; export const getCounterSelectors = (index: CounterIndex): CounterSelectors => { let selectors = _counterSelectors[index]; if (!selectors) { @@ -629,11 +629,6 @@ export const getHiddenTrackCount: Selector = createSelector( if (globalTrackIndex === -1) { throw new Error('Unable to find a global track from the given pid.'); } - if (!hiddenLocalTracks) { - throw new Error( - 'Unable to find the hidden local tracks from the given pid' - ); - } if (hiddenGlobalTracks.has(globalTrackIndex)) { // The entire process group is hidden, count all of the tracks. @@ -805,10 +800,6 @@ export const getProfileFilterSortedPageData: Selector = } for (const threadIndex of threadIndexes.values()) { const threadScore = threadActivityScores[threadIndex]; - if (!threadScore) { - throw new Error('Failed to find the thread score!'); - } - tabScore += threadScore.boostedSampleScore; } pageDataWithScore.push({ diff --git a/src/selectors/zipped-profiles.tsx b/src/selectors/zipped-profiles.tsx index 3ed8cf16fb..c2c5f55005 100644 --- a/src/selectors/zipped-profiles.tsx +++ b/src/selectors/zipped-profiles.tsx @@ -74,10 +74,11 @@ export const getZipFileMaxDepth: Selector = createSelector( * render a file picker to load profiles from the zip file. */ export const getZipFileTreeOrNull: Selector = - createSelector(getZipFileTable, getProfileUrl, (zipFileTable, zipFileUrl) => - zipFileTable === null - ? null - : new ZipFiles.ZipFileTree(zipFileTable, zipFileUrl) + createSelector( + getZipFileTable, + getProfileUrl, + (zipFileTable, zipFileUrl) => + new ZipFiles.ZipFileTree(zipFileTable, zipFileUrl) ); /** diff --git a/src/symbolicator-cli/index.ts b/src/symbolicator-cli/index.ts index cf0ff1bb21..901b40098c 100644 --- a/src/symbolicator-cli/index.ts +++ b/src/symbolicator-cli/index.ts @@ -94,9 +94,6 @@ export async function run(options: CliOptions) { // Load the profile. const profile = await unserializeProfileOfArbitraryFormat(byteBufferCopy); - if (profile === undefined) { - throw new Error('Unable to parse the profile.'); - } const symbolStoreDB = new InMemorySymbolDB(); diff --git a/src/types/state.ts b/src/types/state.ts index 59a388782a..dcc9d193b2 100644 --- a/src/types/state.ts +++ b/src/types/state.ts @@ -67,7 +67,7 @@ export type TableViewOptions = { readonly fixedColumnWidths: Array | null; }; -export type TableViewOptionsPerTab = { [K in TabSlug]: TableViewOptions }; +export type TableViewOptionsPerTab = Partial>; export type RightClickedCallNode = { readonly threadsKey: ThreadsKey; @@ -180,7 +180,7 @@ export type AppState = { readonly sidebarOpenCategories: Map>; readonly panelLayoutGeneration: number; readonly lastVisibleThreadTabSlug: TabSlug; - readonly trackThreadHeights: Record; + readonly trackThreadHeights: Partial>; readonly isNewlyPublished: boolean; readonly isDragAndDropDragging: boolean; readonly isDragAndDropOverlayRegistered: boolean; diff --git a/src/types/transforms.ts b/src/types/transforms.ts index 4487a0c4ab..5017bfe5ab 100644 --- a/src/types/transforms.ts +++ b/src/types/transforms.ts @@ -350,4 +350,6 @@ export type Transform = TransformDefinitions[keyof TransformDefinitions]; export type TransformType = Transform['type']; export type TransformStack = Transform[]; -export type TransformStacksPerThread = { [key: ThreadsKey]: TransformStack }; +export type TransformStacksPerThread = Partial< + Record +>; diff --git a/tsconfig.json b/tsconfig.json index b8dab0ca32..28b14b261a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,6 +38,6 @@ // React & JSX "jsx": "react-jsx" }, - "include": ["src/**/*.ts", "src/**/*.tsx"], + "include": ["src/**/*.ts", "src/**/*.tsx", "__mocks__/**/*.ts"], "exclude": ["node_modules", "dist"] } diff --git a/yarn.lock b/yarn.lock index 6d38cbff50..4ec13446dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2492,6 +2492,21 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.0.tgz#d72bf8b2d3052afee919ba38f38c57138eee0396" + integrity sha512-EGDAOGX+uwwekcS0iyxVDmRV9HX6FLSM5kzrAToLTsr9OWCIKG/y3lQheCq18yZ5Xh78rRKJiEpP0ZaCs4ryOQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.44.0" + "@typescript-eslint/type-utils" "8.44.0" + "@typescript-eslint/utils" "8.44.0" + "@typescript-eslint/visitor-keys" "8.44.0" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + "@typescript-eslint/eslint-plugin@^8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz#42209e2ce3e2274de0f5f9b75c777deedacaa558" @@ -2507,6 +2522,17 @@ natural-compare "^1.4.0" ts-api-utils "^2.1.0" +"@typescript-eslint/parser@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.44.0.tgz#0436fbe0a72f86d3366d2d157d480524b0ab3f26" + integrity sha512-VGMpFQGUQWYT9LfnPcX8ouFojyrZ/2w3K5BucvxL/spdNehccKhB4jUyB1yBCXpr2XFm0jkECxgrpXBW2ipoAw== + dependencies: + "@typescript-eslint/scope-manager" "8.44.0" + "@typescript-eslint/types" "8.44.0" + "@typescript-eslint/typescript-estree" "8.44.0" + "@typescript-eslint/visitor-keys" "8.44.0" + debug "^4.3.4" + "@typescript-eslint/parser@^8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.41.0.tgz#677f5b2b3fa947ee1eac4129220c051b1990d898" @@ -2527,6 +2553,15 @@ "@typescript-eslint/types" "^8.41.0" debug "^4.3.4" +"@typescript-eslint/project-service@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.44.0.tgz#89060651dcecde946e758441fe94dceb6f769a29" + integrity sha512-ZeaGNraRsq10GuEohKTo4295Z/SuGcSq2LzfGlqiuEvfArzo/VRrT0ZaJsVPuKZ55lVbNk8U6FcL+ZMH8CoyVA== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.44.0" + "@typescript-eslint/types" "^8.44.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@8.41.0", "@typescript-eslint/scope-manager@^8.15.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.41.0.tgz#c8aba12129cb9cead1f1727f58e6a0fcebeecdb5" @@ -2535,11 +2570,24 @@ "@typescript-eslint/types" "8.41.0" "@typescript-eslint/visitor-keys" "8.41.0" +"@typescript-eslint/scope-manager@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.44.0.tgz#c37f1e786fd0e5b40607985c769a61c24c761c26" + integrity sha512-87Jv3E+al8wpD+rIdVJm/ItDBe/Im09zXIjFoipOjr5gHUhJmTzfFLuTJ/nPTMc2Srsroy4IBXwcTCHyRR7KzA== + dependencies: + "@typescript-eslint/types" "8.44.0" + "@typescript-eslint/visitor-keys" "8.44.0" + "@typescript-eslint/tsconfig-utils@8.41.0", "@typescript-eslint/tsconfig-utils@^8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.41.0.tgz#134dee36eb16cdd78095a20bca0516d10b5dda75" integrity sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw== +"@typescript-eslint/tsconfig-utils@8.44.0", "@typescript-eslint/tsconfig-utils@^8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.0.tgz#8c0601372bf889f0663a08df001ad666442aa3a8" + integrity sha512-x5Y0+AuEPqAInc6yd0n5DAcvtoQ/vyaGwuX5HE9n6qAefk1GaedqrLQF8kQGylLUb9pnZyLf+iEiL9fr8APDtQ== + "@typescript-eslint/type-utils@8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.41.0.tgz#68d401e38fccf239925447e97bdbd048a9891ae5" @@ -2551,11 +2599,27 @@ debug "^4.3.4" ts-api-utils "^2.1.0" +"@typescript-eslint/type-utils@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.44.0.tgz#5b875f8a961d15bb47df787cbfde50baea312613" + integrity sha512-9cwsoSxJ8Sak67Be/hD2RNt/fsqmWnNE1iHohG8lxqLSNY8xNfyY7wloo5zpW3Nu9hxVgURevqfcH6vvKCt6yg== + dependencies: + "@typescript-eslint/types" "8.44.0" + "@typescript-eslint/typescript-estree" "8.44.0" + "@typescript-eslint/utils" "8.44.0" + debug "^4.3.4" + ts-api-utils "^2.1.0" + "@typescript-eslint/types@8.41.0", "@typescript-eslint/types@^8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.41.0.tgz#9935afeaae65e535abcbcee95383fa649c64d16d" integrity sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag== +"@typescript-eslint/types@8.44.0", "@typescript-eslint/types@^8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.44.0.tgz#4b9154ab164a0beff22d3217ff0fdc8d10bce924" + integrity sha512-ZSl2efn44VsYM0MfDQe68RKzBz75NPgLQXuGypmym6QVOWL5kegTZuZ02xRAT9T+onqvM6T8CdQk0OwYMB6ZvA== + "@typescript-eslint/typescript-estree@8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.41.0.tgz#7c9cff8b4334ce96f14e9689692e8cf426ce4d59" @@ -2572,6 +2636,22 @@ semver "^7.6.0" ts-api-utils "^2.1.0" +"@typescript-eslint/typescript-estree@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.0.tgz#e23e9946c466cf5f53b7e46ecdd9789fd8192daa" + integrity sha512-lqNj6SgnGcQZwL4/SBJ3xdPEfcBuhCG8zdcwCPgYcmiPLgokiNDKlbPzCwEwu7m279J/lBYWtDYL+87OEfn8Jw== + dependencies: + "@typescript-eslint/project-service" "8.44.0" + "@typescript-eslint/tsconfig-utils" "8.44.0" + "@typescript-eslint/types" "8.44.0" + "@typescript-eslint/visitor-keys" "8.44.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.1.0" + "@typescript-eslint/utils@8.41.0", "@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.15.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.41.0.tgz#17cb3b766c1626311004ea41ffd8c27eb226b953" @@ -2582,6 +2662,16 @@ "@typescript-eslint/types" "8.41.0" "@typescript-eslint/typescript-estree" "8.41.0" +"@typescript-eslint/utils@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.44.0.tgz#2c0650a1e8a832ed15658e7ca3c7bd2818d92c7c" + integrity sha512-nktOlVcg3ALo0mYlV+L7sWUD58KG4CMj1rb2HUVOO4aL3K/6wcD+NERqd0rrA5Vg06b42YhF6cFxeixsp9Riqg== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.44.0" + "@typescript-eslint/types" "8.44.0" + "@typescript-eslint/typescript-estree" "8.44.0" + "@typescript-eslint/visitor-keys@8.41.0": version "8.41.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.41.0.tgz#16eb99b55d207f6688002a2cf425e039579aa9a9" @@ -2590,6 +2680,14 @@ "@typescript-eslint/types" "8.41.0" eslint-visitor-keys "^4.2.1" +"@typescript-eslint/visitor-keys@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.0.tgz#0d9d5647e005c2ff8acc391d1208ab37d08850aa" + integrity sha512-zaz9u8EJ4GBmnehlrpoKvj/E3dNbuQ7q0ucyZImm3cLqJ8INTc970B1qEqDX/Rzq65r3TvVTN7kHWPBoyW7DWw== + dependencies: + "@typescript-eslint/types" "8.44.0" + eslint-visitor-keys "^4.2.1" + "@ungap/structured-clone@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" @@ -11304,7 +11402,16 @@ string-length@^4.0.2: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -11426,7 +11533,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11440,6 +11547,13 @@ strip-ansi@^0.3.0: dependencies: ansi-regex "^0.2.1" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -12011,6 +12125,16 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== +typescript-eslint@^8.44.0: + version "8.44.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.44.0.tgz#5f052fa52af2420fdc488ab4cabd823f4f8594c8" + integrity sha512-ib7mCkYuIzYonCq9XWF5XNw+fkj2zg629PSa9KNIQ47RXFF763S5BIX4wqz1+FLPogTZoiw8KmCiRPRa8bL3qw== + dependencies: + "@typescript-eslint/eslint-plugin" "8.44.0" + "@typescript-eslint/parser" "8.44.0" + "@typescript-eslint/typescript-estree" "8.44.0" + "@typescript-eslint/utils" "8.44.0" + typescript@^5.8.3: version "5.9.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" @@ -12955,8 +13079,16 @@ workbox-window@7.3.0, workbox-window@^7.3.0: "@types/trusted-types" "^2.0.2" workbox-core "7.3.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==