Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 18f5b51

Browse files
committed
fix: improve design of error messages and refactor code
1 parent a7f17a9 commit 18f5b51

File tree

6 files changed

+127
-96
lines changed

6 files changed

+127
-96
lines changed
Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,41 @@
11
import type { TSESTree } from '@typescript-eslint/utils';
2+
import type * as ESQuery from 'esquery';
23
import React, { useMemo } from 'react';
34

45
import ASTViewer from './ast/ASTViewer';
56
import { serialize } from './ast/serializer/serializer';
67
import { createESTreeSerializer } from './ast/serializer/serializerESTree';
78
import type { ASTViewerBaseProps } from './ast/types';
8-
import Text from './inputs/Text';
9-
import styles from './ASTViewerESTree.module.css';
109

1110
export interface ASTESTreeViewerProps extends ASTViewerBaseProps {
1211
readonly value: TSESTree.BaseNode;
13-
readonly filter: string;
14-
readonly onChangeFilter: (filter: string) => void;
12+
readonly filter?: ESQuery.Selector;
13+
}
14+
15+
function tryToApplyFilter<T>(value: T, filter?: ESQuery.Selector): T {
16+
try {
17+
if (window.esquery && filter) {
18+
// @ts-expect-error - esquery is not correctly typed
19+
return window.esquery.match(value, filter);
20+
}
21+
} catch (e: unknown) {
22+
// eslint-disable-next-line no-console
23+
console.error(e);
24+
}
25+
return value;
1526
}
1627

1728
export default function ASTViewerESTree({
1829
value,
1930
position,
2031
onSelectNode,
2132
filter,
22-
onChangeFilter,
2333
}: ASTESTreeViewerProps): JSX.Element {
2434
const model = useMemo(() => {
25-
if (window.esquery && filter.length > 0) {
26-
try {
27-
const queryParsed = window.esquery.parse(filter);
28-
const match = window.esquery.match(value, queryParsed);
29-
return serialize(match, createESTreeSerializer());
30-
} catch (e: unknown) {
31-
if (e instanceof Error) {
32-
return e;
33-
}
34-
return String(e);
35-
}
36-
} else {
37-
return serialize(value, createESTreeSerializer());
38-
}
35+
return serialize(tryToApplyFilter(value, filter), createESTreeSerializer());
3936
}, [value, filter]);
4037

4138
return (
42-
<>
43-
<div className={styles.searchContainer}>
44-
<Text
45-
value={filter}
46-
name="esquery"
47-
onChange={onChangeFilter}
48-
className={styles.search}
49-
placeholder="ESQuery filter"
50-
/>
51-
</div>
52-
<>
53-
{model instanceof Error ? (
54-
<div className={styles.errorContainer}>
55-
<div className="admonition alert alert--danger">
56-
<div className="admonition-content">
57-
<div>{model.message}</div>
58-
</div>
59-
</div>
60-
</div>
61-
) : (
62-
<ASTViewer
63-
value={model}
64-
position={position}
65-
onSelectNode={onSelectNode}
66-
/>
67-
)}
68-
</>
69-
</>
39+
<ASTViewer value={model} position={position} onSelectNode={onSelectNode} />
7040
);
7141
}

packages/website/src/components/ASTViewerESTree.module.css renamed to packages/website/src/components/ESQueryFilter.module.css

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,3 @@
2525
.search::placeholder {
2626
color: var(--ifm-navbar-search-input-placeholder-color);
2727
}
28-
29-
.errorContainer {
30-
word-wrap: break-word;
31-
white-space: break-spaces;
32-
padding: 20px;
33-
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { Selector } from 'esquery';
2+
import React, { useState } from 'react';
3+
4+
import styles from './ESQueryFilter.module.css';
5+
import Text from './inputs/Text';
6+
7+
export interface ESQueryFilterProps {
8+
readonly onChange: (value: Selector) => void;
9+
readonly onError: (value?: Error) => void;
10+
}
11+
12+
export function ESQueryFilter({
13+
onChange,
14+
onError,
15+
}: ESQueryFilterProps): JSX.Element {
16+
const [value, setValue] = useState('');
17+
const changeEvent = (value: string): void => {
18+
setValue(value);
19+
try {
20+
const queryParsed = window.esquery.parse(value);
21+
onChange(queryParsed);
22+
onError(undefined);
23+
} catch (e: unknown) {
24+
onError(e instanceof Error ? e : new Error(String(e)));
25+
}
26+
};
27+
28+
return (
29+
<div className={styles.searchContainer}>
30+
<Text
31+
value={value}
32+
name="esquery"
33+
onChange={changeEvent}
34+
className={styles.search}
35+
placeholder="ESQuery filter"
36+
/>
37+
</div>
38+
);
39+
}

packages/website/src/components/ErrorsViewer.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
font-feature-settings: 'liga' 0, 'calt' 0;
1111
box-sizing: border-box;
1212
margin: 0;
13+
white-space: break-spaces;
1314
}
1415

1516
.fixerContainer {

packages/website/src/components/ErrorsViewer.tsx

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ export interface ErrorsViewerProps {
1111
readonly value?: ErrorGroup[] | Error;
1212
}
1313

14-
export interface ErrorBlockProps {
14+
interface AlertBlockProps {
15+
readonly type: 'danger' | 'warning' | 'note' | 'info' | 'success';
16+
readonly children: React.ReactNode;
17+
readonly fixer?: boolean;
18+
}
19+
20+
interface ErrorBlockProps {
1521
readonly item: ErrorItem;
1622
readonly setIsLocked: (value: boolean) => void;
1723
readonly isLocked: boolean;
@@ -23,7 +29,9 @@ export interface FixButtonProps {
2329
readonly disabled: boolean;
2430
}
2531

26-
function severityClass(severity: Monaco.MarkerSeverity): string {
32+
function severityClass(
33+
severity: Monaco.MarkerSeverity,
34+
): AlertBlockProps['type'] {
2735
switch (severity) {
2836
case 8:
2937
return 'danger';
@@ -50,57 +58,61 @@ function FixButton(props: FixButtonProps): JSX.Element {
5058
);
5159
}
5260

61+
function AlertBlock(props: AlertBlockProps): JSX.Element {
62+
return (
63+
<div className={`admonition alert alert--${props.type}`}>
64+
<div className="admonition-content">{props.children}</div>
65+
</div>
66+
);
67+
}
68+
5369
function ErrorBlock({
5470
item,
5571
setIsLocked,
5672
isLocked,
5773
}: ErrorBlockProps): JSX.Element {
5874
return (
59-
<div className={`admonition alert alert--${severityClass(item.severity)}`}>
60-
<div className="admonition-content">
61-
<div className={clsx(!!item.fixer && styles.fixerContainer)}>
62-
<div>
63-
{item.message} {item.location}
64-
</div>
65-
{item.fixer && (
66-
<FixButton
67-
disabled={isLocked}
68-
fix={item.fixer.fix}
69-
setIsLocked={setIsLocked}
70-
/>
71-
)}
75+
<AlertBlock type={severityClass(item.severity)}>
76+
<div className={clsx(!!item.fixer && styles.fixerContainer)}>
77+
<div>
78+
{item.message} {item.location}
7279
</div>
73-
{item.suggestions.length > 0 && (
74-
<div>
75-
{item.suggestions.map((fixer, index) => (
76-
<div
77-
key={index}
78-
className={clsx(styles.fixerContainer, styles.fixer)}
79-
>
80-
<span>&gt; {fixer.message}</span>
81-
<FixButton
82-
disabled={isLocked}
83-
fix={fixer.fix}
84-
setIsLocked={setIsLocked}
85-
/>
86-
</div>
87-
))}
88-
</div>
80+
{item.fixer && (
81+
<FixButton
82+
disabled={isLocked}
83+
fix={item.fixer.fix}
84+
setIsLocked={setIsLocked}
85+
/>
8986
)}
9087
</div>
91-
</div>
88+
{item.suggestions.length > 0 && (
89+
<div>
90+
{item.suggestions.map((fixer, index) => (
91+
<div
92+
key={index}
93+
className={clsx(styles.fixerContainer, styles.fixer)}
94+
>
95+
<span>&gt; {fixer.message}</span>
96+
<FixButton
97+
disabled={isLocked}
98+
fix={fixer.fix}
99+
setIsLocked={setIsLocked}
100+
/>
101+
</div>
102+
))}
103+
</div>
104+
)}
105+
</AlertBlock>
92106
);
93107
}
94108

95109
function SuccessBlock(): JSX.Element {
96110
return (
97-
<div className="admonition alert alert--success">
98-
<div className="admonition-content">
99-
<div className={styles.fixerContainer}>
100-
<div>All is ok!</div>
101-
</div>
111+
<AlertBlock type="success">
112+
<div className={styles.fixerContainer}>
113+
<div>All is ok!</div>
102114
</div>
103-
</div>
115+
</AlertBlock>
104116
);
105117
}
106118

@@ -116,9 +128,13 @@ export default function ErrorsViewer({
116128
if (value && !Array.isArray(value)) {
117129
return (
118130
<div className={styles.list}>
119-
<div className="margin-top--sm">
120-
<h4>ESLint internal error</h4>
121-
{value?.stack}
131+
<div className="margin-top--md">
132+
<AlertBlock type="danger">
133+
<div className={styles.fixerContainer}>
134+
<h4>Internal error</h4>
135+
</div>
136+
{value?.stack}
137+
</AlertBlock>
122138
</div>
123139
</div>
124140
);

packages/website/src/components/Playground.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import {
77
} from '@site/src/components/config/utils';
88
import EditorTabs from '@site/src/components/EditorTabs';
99
import ErrorsViewer from '@site/src/components/ErrorsViewer';
10+
import { ESQueryFilter } from '@site/src/components/ESQueryFilter';
1011
import type { TSESTree } from '@typescript-eslint/utils';
1112
import clsx from 'clsx';
13+
import type * as ESQuery from 'esquery';
1214
import type Monaco from 'monaco-editor';
1315
import React, { useCallback, useReducer, useState } from 'react';
1416
import type { SourceFile } from 'typescript';
@@ -69,7 +71,8 @@ function Playground(): JSX.Element {
6971
const [position, setPosition] = useState<Monaco.Position | null>(null);
7072
const [activeTab, setTab] = useState<TabType>('code');
7173
const [showModal, setShowModal] = useState<TabType | false>(false);
72-
const [esQueryFilter, setEsQueryFilter] = useState<string>('');
74+
const [esQueryFilter, setEsQueryFilter] = useState<ESQuery.Selector>();
75+
const [esQueryError, setEsQueryError] = useState<Error>();
7376
const enableSplitPanes = useMediaQuery('(min-width: 996px)');
7477

7578
const updateModal = useCallback(
@@ -162,6 +165,12 @@ function Playground(): JSX.Element {
162165
/>
163166
</div>
164167
<div className={styles.astViewer}>
168+
{state.showAST === 'es' && (
169+
<ESQueryFilter
170+
onChange={setEsQueryFilter}
171+
onError={setEsQueryError}
172+
/>
173+
)}
165174
{(state.showAST === 'ts' && tsAst && (
166175
<ASTViewerTS
167176
value={tsAst}
@@ -176,12 +185,14 @@ function Playground(): JSX.Element {
176185
onSelectNode={setSelectedRange}
177186
/>
178187
)) ||
188+
(state.showAST === 'es' && esQueryError && (
189+
<ErrorsViewer value={esQueryError} />
190+
)) ||
179191
(state.showAST === 'es' && esAst && (
180192
<ASTViewerESTree
181193
value={esAst}
182194
position={position}
183195
filter={esQueryFilter}
184-
onChangeFilter={setEsQueryFilter}
185196
onSelectNode={setSelectedRange}
186197
/>
187198
)) || <ErrorsViewer value={markers} />}

0 commit comments

Comments
 (0)