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): [playground] parse eslint module config on paste and improve visual editor#5112

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 8 commits intomainfromfix/visaul-editor-and-paste
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
8 commits
Select commitHold shift + click to select a range
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
21 changes: 9 additions & 12 deletionspackages/website/src/components/config/ConfigEslint.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react';

import ConfigEditor, { ConfigOptionsType } from './ConfigEditor';
import type {
RulesRecord,
RuleDetails,
RuleEntry,
ConfigModel,
} from '../types';
import type { RuleDetails, RuleEntry, ConfigModel, EslintRC } from '../types';
import { shallowEqual } from '../lib/shallowEqual';
import { parseESLintRC,toJsonConfig } from '@site/src/components/config/utils';
import { parseESLintRC,toJson } from './utils';

export interface ConfigEslintProps {
readonly isOpen: boolean;
Expand All@@ -33,11 +28,11 @@ function checkOptions(rule: [string, unknown]): rule is [string, RuleEntry] {

function ConfigEslint(props: ConfigEslintProps): JSX.Element {
const [options, updateOptions] = useState<ConfigOptionsType[]>([]);
const [configObject, updateConfigObject] = useState<RulesRecord>({});
const [configObject, updateConfigObject] = useState<EslintRC>();

useEffect(() => {
if (props.isOpen) {
updateConfigObject(props.config ?parseESLintRC(props.config) : {});
updateConfigObject(parseESLintRC(props.config));
}
}, [props.isOpen, props.config]);

Expand DownExpand Up@@ -77,8 +72,10 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element {
)
.filter(checkOptions),
);
if (!shallowEqual(cfg, configObject)) {
props.onClose({ eslintrc: toJsonConfig(cfg, 'rules') });
if (!shallowEqual(cfg, configObject?.rules)) {
props.onClose({
eslintrc: toJson({ ...(configObject ?? {}), rules: cfg }),
});
} else {
props.onClose();
}
Expand All@@ -90,7 +87,7 @@ function ConfigEslint(props: ConfigEslintProps): JSX.Element {
<ConfigEditor
header="Eslint Config"
options={options}
values={configObject ?? {}}
values={configObject?.rules ?? {}}
isOpen={props.isOpen}
onClose={onClose}
/>
Expand Down
16 changes: 9 additions & 7 deletionspackages/website/src/components/config/ConfigTypeScript.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
import React, { useCallback, useEffect, useState } from 'react';

import ConfigEditor, { ConfigOptionsType } from './ConfigEditor';
import type {CompilerFlags, ConfigModel } from '../types';
import type {ConfigModel, TSConfig } from '../types';
import { shallowEqual } from '../lib/shallowEqual';
import { getTypescriptOptions, parseTSConfig,toJsonConfig } from './utils';
import { getTypescriptOptions, parseTSConfig,toJson } from './utils';

interface ConfigTypeScriptProps {
readonly isOpen: boolean;
Expand All@@ -17,11 +17,11 @@ function checkOptions(item: [string, unknown]): item is [string, boolean] {

function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element {
const [tsConfigOptions, updateOptions] = useState<ConfigOptionsType[]>([]);
const [configObject, updateConfigObject] = useState<CompilerFlags>({});
const [configObject, updateConfigObject] = useState<TSConfig>();

useEffect(() => {
if (props.isOpen) {
updateConfigObject(props.config ?parseTSConfig(props.config) : {});
updateConfigObject(parseTSConfig(props.config));
}
}, [props.isOpen, props.config]);

Expand DownExpand Up@@ -54,8 +54,10 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element {
const cfg = Object.fromEntries(
Object.entries(newConfig).filter(checkOptions),
);
if (!shallowEqual(cfg, configObject)) {
props.onClose({ tsconfig: toJsonConfig(cfg, 'compilerOptions') });
if (!shallowEqual(cfg, configObject?.compilerOptions)) {
props.onClose({
tsconfig: toJson({ ...(configObject ?? {}), compilerOptions: cfg }),
});
} else {
props.onClose();
}
Expand All@@ -67,7 +69,7 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): JSX.Element {
<ConfigEditor
header="TypeScript Config"
options={tsConfigOptions}
values={configObject ?? {}}
values={configObject?.compilerOptions ?? {}}
isOpen={props.isOpen}
onClose={onClose}
/>
Expand Down
78 changes: 53 additions & 25 deletionspackages/website/src/components/config/utils.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
import type {CompilerFlags, RulesRecord } from '@site/src/components/types';
import type {EslintRC, TSConfig } from '@site/src/components/types';

import { parse } from 'json5';
import { isRecord } from '@site/src/components/ast/utils';
Expand All@@ -10,48 +10,75 @@ export interface OptionDeclarations {
description?: { message: string };
}

export function parseESLintRC(code?: string):RulesRecord {
export function parseESLintRC(code?: string):EslintRC {
if (code) {
try {
const parsed: unknown = parse(code);
if (isRecord(parsed) && 'rules' in parsed && isRecord(parsed.rules)) {
return parsed.rules as RulesRecord;
if (isRecord(parsed)) {
if ('rules' in parsed && isRecord(parsed.rules)) {
return parsed as EslintRC;
}
return { ...parsed, rules: {} };
}
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
}
}
return {};
return { rules: {}};
}

export function parseTSConfig(code?: string):CompilerFlags {
export function parseTSConfig(code?: string):TSConfig {
if (code) {
try {
const parsed: unknown = parse(code);
if (
isRecord(parsed) &&
'compilerOptions' in parsed &&
isRecord(parsed.compilerOptions)
) {
return parsed.compilerOptions as CompilerFlags;
if (isRecord(parsed)) {
if ('compilerOptions' in parsed && isRecord(parsed.compilerOptions)) {
return parsed as TSConfig;
}
return { ...parsed, compilerOptions: {} };
}
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
}
}
return {};
return { compilerOptions: {} };
}

const moduleRegexp = /(module\.exports\s*=)/g;

function constrainedScopeEval(obj: string): unknown {
// eslint-disable-next-line @typescript-eslint/no-implied-eval
return new Function(`
"use strict";
var module = { exports: {} };
(${obj});
return module.exports
`)();
}

export function tryParseEslintModule(value: string): string {
try {
if (moduleRegexp.test(value)) {
const newValue = toJson(constrainedScopeEval(value));
if (newValue !== value) {
return newValue;
}
}
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
}
return value;
}

export function toJson(cfg: unknown): string {
return JSON.stringify(cfg, null, 2);
}

export function toJsonConfig(cfg: unknown, prop: string): string {
return JSON.stringify(
{
[prop]: cfg,
},
null,
2,
);
return toJson({ [prop]: cfg });
}

export function getTypescriptOptions(): OptionDeclarations[] {
Expand All@@ -76,11 +103,12 @@ export function getTypescriptOptions(): OptionDeclarations[] {
);
}

export const defaultTsConfig =toJsonConfig(
{
export const defaultTsConfig =toJson({
compilerOptions:{
strictNullChecks: true,
},
'compilerOptions',
);
});

export const defaultEslintConfig = toJsonConfig({}, 'rules');
export const defaultEslintConfig = toJson({
rules: {},
});
31 changes: 22 additions & 9 deletionspackages/website/src/components/editor/LoadedEditor.tsx
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,8 +24,7 @@ import {
LintCodeAction,
} from '../linter/utils';
import {
defaultEslintConfig,
defaultTsConfig,
tryParseEslintModule,
parseESLintRC,
parseTSConfig,
} from '../config/utils';
Expand DownExpand Up@@ -62,12 +61,12 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
const tabsDefault = {
code: sandboxInstance.editor.getModel()!,
tsconfig: sandboxInstance.monaco.editor.createModel(
defaultTsConfig,
tsconfig,
'json',
sandboxInstance.monaco.Uri.file('./tsconfig.json'),
),
eslintrc: sandboxInstance.monaco.editor.createModel(
defaultEslintConfig,
eslintrc,
'json',
sandboxInstance.monaco.Uri.file('./.eslintrc'),
),
Expand All@@ -83,7 +82,7 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
const markers = sandboxInstance.monaco.editor.getModelMarkers({
resource: model.uri,
});
onMarkersChange(parseMarkers(markers, codeActions,model));
onMarkersChange(parseMarkers(markers, codeActions,sandboxInstance.editor));
}, []);

useEffect(() => {
Expand All@@ -95,20 +94,25 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
sandboxInstance.monaco.Uri.file(newPath),
);
newModel.updateOptions({ tabSize: 2, insertSpaces: true });
sandboxInstance.editor.setModel(newModel);
if (tabs.code.isAttachedToEditor()) {
sandboxInstance.editor.setModel(newModel);
}
tabs.code.dispose();
tabs.code = newModel;
}
}, [jsx]);

useEffect(() => {
const config = createCompilerOptions(jsx, parseTSConfig(tsconfig));
const config = createCompilerOptions(
jsx,
parseTSConfig(tsconfig).compilerOptions,
);
webLinter.updateCompilerOptions(config);
sandboxInstance.setCompilerSettings(config);
}, [jsx, tsconfig]);

useEffect(() => {
webLinter.updateRules(parseESLintRC(eslintrc));
webLinter.updateRules(parseESLintRC(eslintrc).rules);
}, [eslintrc]);

useEffect(() => {
Expand DownExpand Up@@ -169,9 +173,18 @@ export const LoadedEditor: React.FC<LoadedEditorProps> = ({
'typescript',
createProvideCodeActions(codeActions),
),
sandboxInstance.editor.onDidPaste(() => {
if (tabs.eslintrc.isAttachedToEditor()) {
const value = tabs.eslintrc.getValue();
const newValue = tryParseEslintModule(value);
if (newValue !== value) {
tabs.eslintrc.setValue(newValue);
}
}
}),
sandboxInstance.editor.onDidChangeCursorPosition(
debounce(() => {
if (sandboxInstance.editor.getModel() === tabs.code) {
if (tabs.code.isAttachedToEditor()) {
const position = sandboxInstance.editor.getPosition();
if (position) {
// eslint-disable-next-line no-console
Expand Down
6 changes: 4 additions & 2 deletionspackages/website/src/components/linter/utils.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,7 +48,7 @@ export function createEditOperation(
export function parseMarkers(
markers: Monaco.editor.IMarker[],
fixes: Map<string, LintCodeAction[]>,
model: Monaco.editor.ITextModel,
editor: Monaco.editor.IStandaloneCodeEditor,
): ErrorItem[] {
return markers.map(marker => {
const code =
Expand All@@ -60,7 +60,9 @@ export function parseMarkers(
return {
message: item.message,
fix(): void {
model.applyEdits([createEditOperation(model, item)]);
editor.executeEdits('eslint', [
createEditOperation(editor.getModel()!, item),
]);
},
};
}) ?? [];
Expand Down
5 changes: 5 additions & 0 deletionspackages/website/src/components/types.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,3 +42,8 @@ export interface ErrorItem {
hasFixers: boolean;
fixers: { message: string; fix(): void }[];
}

export type EslintRC = Record<string, unknown> & { rules: RulesRecord };
export type TSConfig = Record<string, unknown> & {
compilerOptions: CompilerFlags;
};

[8]ページ先頭

©2009-2025 Movatter.jp