Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

chore(website): error viewer in playground#5061

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
bradzacher merged 14 commits intomainfromchore/errors-view-in-playground
May 26, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
14 commits
Select commitHold shift + click to select a range
e122a08
chore(website): add POC for error viewer in playground
armano2May 23, 2022
236a440
chore(website): correct colors
armano2May 23, 2022
0471e16
chore(website): correct issue with optional fixers
armano2May 23, 2022
d541bcb
chore(website): expose fixers to errors-viewer
armano2May 24, 2022
44206d1
chore(website): add simple locking system for fixers
armano2May 24, 2022
164f254
Merge remote-tracking branch 'origin/main' into chore/errors-view-in-…
armano2May 24, 2022
d7c249a
chore(website): change label apply to fix
armano2May 24, 2022
9790b65
Merge remote-tracking branch 'origin/main' into chore/errors-view-in-…
armano2May 25, 2022
f7691a0
fix: correct small issue with compilerOptions not updating in eslint
armano2May 25, 2022
f0ae860
fix: apply changes requested in code review
armano2May 25, 2022
85ad1b8
Merge remote-tracking branch 'origin/main' into chore/errors-view-in-…
armano2May 25, 2022
b7d93c7
fix: apply changes from code review
armano2May 25, 2022
59ca8ca
fix: add useMemo to cache model
armano2May 25, 2022
3694da2
Update packages/website/src/components/ErrorsViewer.tsx
armano2May 26, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletionpackages/website/data/sponsors.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -229,4 +229,4 @@
"totalDonations": 1500,
"website": "https://www.mysportsinjury.co.uk"
}
]
]
21 changes: 21 additions & 0 deletionspackages/website/src/components/ErrorsViewer.module.css
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
.list {
font-family: var(--ifm-font-family-monospace);
background: transparent;
border: none;
padding-left: 1.5rem;
padding-right: 1.5rem;
font-size: 13px;
line-height: 18px;
letter-spacing: 0;
font-feature-settings: 'liga' 0, 'calt' 0;
box-sizing: border-box;
white-space: break-spaces;
margin: 0;
}

.fixer {
margin: 0.5rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
111 changes: 111 additions & 0 deletionspackages/website/src/components/ErrorsViewer.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
import React, { useEffect, useMemo, useState } from 'react';
import type Monaco from 'monaco-editor';
import type { ErrorItem } from './types';

import styles from './ErrorsViewer.module.css';

export interface ErrorsViewerProps {
readonly value?: ErrorItem[];
}

export interface ErrorBlockProps {
readonly item: ErrorItem;
readonly setIsLocked: (value: boolean) => void;
readonly isLocked: boolean;
}

function severityClass(severity: Monaco.MarkerSeverity): string {
switch (severity) {
case 8:
return 'danger';
case 4:
return 'caution';
case 2:
return 'note';
}
return 'info';
}

function groupErrorItems(items: ErrorItem[]): [string, ErrorItem[]][] {
return Object.entries(
items.reduce<Record<string, ErrorItem[]>>((acc, obj) => {
if (!acc[obj.group]) {
acc[obj.group] = [];
}
acc[obj.group].push(obj);
return acc;
}, {}),
).sort(([a], [b]) => a.localeCompare(b));
}

function ErrorBlock({
item,
setIsLocked,
isLocked,
}: ErrorBlockProps): JSX.Element {
return (
<div className={`admonition alert alert--${severityClass(item.severity)}`}>
<div className="admonition-content">
<div className="row row--no-gutters">
<div className="col col--12">
{item.message} {item.location}
</div>
{item.hasFixers && (
<div className="col col--12">
{item.fixers.map((fixer, index) => (
<div key={index} className={styles.fixer}>
<span>&gt; {fixer.message}</span>
<button
className="button button--primary button--sm"
disabled={isLocked}
onClick={(): void => {
fixer.fix();
setIsLocked(true);
}}
>
fix
</button>
</div>
))}
</div>
)}
</div>
</div>
</div>
);
}

export default function ErrorsViewer({
value,
}: ErrorsViewerProps): JSX.Element {
const model = useMemo(
() => (value ? groupErrorItems(value) : undefined),
[value],
);

const [isLocked, setIsLocked] = useState(false);

useEffect(() => {
setIsLocked(false);
}, [value]);

return (
<div className={styles.list}>
{model?.map(([group, data]) => {
return (
<div className="margin-top--sm" key={group}>
<h4>{group}</h4>
{data.map((item, index) => (
<ErrorBlock
isLocked={isLocked}
setIsLocked={setIsLocked}
item={item}
key={index}
/>
))}
</div>
);
})}
</div>
);
}
4 changes: 0 additions & 4 deletionspackages/website/src/components/Playground.module.css
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,10 +10,6 @@
border: 1px solid var(--ifm-color-emphasis-100);
}

.sourceCodeStandalone {
width: 100%;
}

.codeBlocks {
display: flex;
flex-direction: row;
Expand Down
50 changes: 23 additions & 27 deletionspackages/website/src/components/Playground.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,6 +20,7 @@ import type { RuleDetails, SelectedRange } from './types';
import type { TSESTree } from '@typescript-eslint/utils';
import type { SourceFile } from 'typescript';
import ASTViewerScope from '@site/src/components/ASTViewerScope';
import ErrorsViewer from '@site/src/components/ErrorsViewer';

function rangeReducer<T extends SelectedRange | null>(
prevState: T,
Expand DownExpand Up@@ -52,6 +53,7 @@ function Playground(): JSX.Element {
const [esAst, setEsAst] = useState<TSESTree.Program | string | null>();
const [tsAst, setTsAST] = useState<SourceFile | string | null>();
const [scope, setScope] = useState<Record<string, unknown> | string | null>();
const [markers, setMarkers] = useState<Monaco.editor.IMarker[]>();
const [ruleNames, setRuleNames] = useState<RuleDetails[]>([]);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [tsVersions, setTSVersion] = useState<readonly string[]>([]);
Expand All@@ -70,12 +72,7 @@ function Playground(): JSX.Element {
/>
</div>
<div className={styles.codeBlocks}>
<div
className={clsx(
styles.sourceCode,
state.showAST ? '' : styles.sourceCodeStandalone,
)}
>
<div className={clsx(styles.sourceCode)}>
{isLoading && <Loader />}
<EditorEmbed />
<LoadingEditor
Expand All@@ -90,6 +87,7 @@ function Playground(): JSX.Element {
onEsASTChange={setEsAst}
onTsASTChange={setTsAST}
onScopeChange={setScope}
onMarkersChange={setMarkers}
decoration={selectedRange}
onChange={(code): void => setState({ code: code })}
onLoaded={(ruleNames, tsVersions): void => {
Expand All@@ -100,31 +98,29 @@ function Playground(): JSX.Element {
onSelect={setPosition}
/>
</div>
{state.showAST && (
<div className={styles.astViewer}>
{(tsAst && state.showAST === 'ts' && (
<ASTViewerTS
value={tsAst}
<div className={styles.astViewer}>
{(tsAst && state.showAST === 'ts' && (
<ASTViewerTS
value={tsAst}
position={position}
onSelectNode={setSelectedRange}
/>
)) ||
(state.showAST === 'scope' && scope && (
<ASTViewerScope
value={scope}
position={position}
onSelectNode={setSelectedRange}
/>
)) ||
(state.showAST === 'scope' && scope && (
<ASTViewerScope
value={scope}
position={position}
onSelectNode={setSelectedRange}
/>
)) ||
(esAst && (
<ASTViewerESTree
value={esAst}
position={position}
onSelectNode={setSelectedRange}
/>
))}
</div>
)}
(state.showAST === 'es' && esAst && (
<ASTViewerESTree
value={esAst}
position={position}
onSelectNode={setSelectedRange}
/>
)) || <ErrorsViewer value={markers} />}
</div>
</div>
</div>
);
Expand Down
8 changes: 7 additions & 1 deletionpackages/website/src/components/editor/LoadedEditor.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,7 @@ import type { WebLinter } from '../linter/WebLinter';
import { debounce } from '../lib/debounce';
import { lintCode, LintCodeAction } from '../linter/lintCode';
import { createProvideCodeActions } from './createProvideCodeActions';
import { parseMarkers } from '../linter/utils';

export interface LoadedEditorProps extends CommonEditorProps {
readonly main: typeof Monaco;
Expand All@@ -24,6 +25,7 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
onEsASTChange,
onScopeChange,
onTsASTChange,
onMarkersChange,
onChange,
onSelect,
rules,
Expand All@@ -34,7 +36,7 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
webLinter,
}) => {
const [decorations, setDecorations] = useState<string[]>([]);
const fixes = useRef(new Map<string, LintCodeAction>()).current;
const fixes = useRef(new Map<string, LintCodeAction[]>()).current;

useEffect(() => {
const config = {
Expand DownExpand Up@@ -112,6 +114,10 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
onChange(sandboxInstance.getModel().getValue());
}, 500),
),
sandboxInstance.monaco.editor.onDidChangeMarkers(() => {
const markers = sandboxInstance.monaco.editor.getModelMarkers({});
onMarkersChange(parseMarkers(markers, fixes, sandboxInstance.editor));
}),
];

return (): void => {
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import type { LintCodeAction } from '../linter/lintCode';
import { createURI } from '../linter/utils';

export function createProvideCodeActions(
fixes: Map<string, LintCodeAction>,
fixes: Map<string, LintCodeAction[]>,
): Monaco.languages.CodeActionProvider {
return {
provideCodeActions(
Expand All@@ -22,8 +22,8 @@ export function createProvideCodeActions(
}
const actions: Monaco.languages.CodeAction[] = [];
for (const marker of context.markers) {
constmessage = fixes.get(createURI(marker));
if (message) {
constmessages = fixes.get(createURI(marker)) ?? [];
for (constmessage of messages) {
const start = model.getPositionAt(message.fix.range[0]);
const end = model.getPositionAt(message.fix.range[1]);
actions.push({
Expand Down
3 changes: 2 additions & 1 deletionpackages/website/src/components/editor/types.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import type Monaco from 'monaco-editor';
import type { ConfigModel, SelectedRange } from '../types';
import type { ConfigModel, SelectedRange, ErrorItem } from '../types';
import type { TSESTree } from '@typescript-eslint/utils';
import type { SourceFile } from 'typescript';

Expand All@@ -10,5 +10,6 @@ export interface CommonEditorProps extends ConfigModel {
readonly onTsASTChange: (value: string | SourceFile) => void;
readonly onEsASTChange: (value: string | TSESTree.Program) => void;
readonly onScopeChange: (value: string | Record<string, unknown>) => void;
readonly onMarkersChange: (value: ErrorItem[]) => void;
readonly onSelect: (position: Monaco.Position | null) => void;
}
5 changes: 2 additions & 3 deletionspackages/website/src/components/linter/WebLinter.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,7 +40,7 @@ export class WebLinter {

this.linter.defineParser(PARSER_NAME, {
parseForESLint: (text, options?: ParserOptions) => {
return this.eslintParse(text,compilerOptions,options);
return this.eslintParse(text, options);
},
});

Expand DownExpand Up@@ -70,7 +70,6 @@ export class WebLinter {

eslintParse(
code: string,
compilerOptions: CompilerOptions,
eslintOptions: ParserOptions = {},
): TSESLint.Linter.ESLintParseResult {
const isJsx = eslintOptions?.ecmaFeatures?.jsx ?? false;
Expand All@@ -80,7 +79,7 @@ export class WebLinter {

const program = window.ts.createProgram(
[fileName],
compilerOptions,
this.compilerOptions,
this.host,
);
const tsAst = program.getSourceFile(fileName)!;
Expand Down
29 changes: 13 additions & 16 deletionspackages/website/src/components/linter/lintCode.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,7 +11,7 @@ export interface LintCodeAction {
};
}

export type LintCodeActionGroup = [string, LintCodeAction];
export type LintCodeActionGroup = [string, LintCodeAction[]];

export function lintCode(
linter: WebLinter,
Expand DownExpand Up@@ -59,27 +59,24 @@ export function lintCode(
};
const markerUri = createURI(marker);

const fixes: LintCodeAction[] = [];
if (message.fix) {
codeActions.push([
markerUri,
{
message: `Fix this ${message.ruleId ?? 'unknown'} problem`,
fix: message.fix,
},
]);
fixes.push({
message: `Fix this ${message.ruleId ?? 'unknown'} problem`,
fix: message.fix,
});
}
if (message.suggestions) {
for (const suggestion of message.suggestions) {
codeActions.push([
markerUri,
{
message: `${suggestion.desc} (${message.ruleId ?? 'unknown'})`,
fix: suggestion.fix,
},
]);
fixes.push({
message: `${suggestion.desc} (${message.ruleId ?? 'unknown'})`,
fix: suggestion.fix,
});
}
}

if (fixes.length > 0) {
codeActions.push([markerUri, fixes]);
}
markers.push(marker);
}

Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp