diff --git a/rspack.config.ts b/rspack.config.ts index 607b5a1e9..f47bd96b0 100644 --- a/rspack.config.ts +++ b/rspack.config.ts @@ -108,11 +108,6 @@ export default defineConfig({ }, ], }, - { - type: "asset/source", - test: /\.d\.ts$/, - exclude: /node_modules/, - }, { type: "asset/source", test: /\.tpl$/, diff --git a/src/locales/ach-UG/translation.json b/src/locales/ach-UG/translation.json index ec678a48b..d543170be 100644 --- a/src/locales/ach-UG/translation.json +++ b/src/locales/ach-UG/translation.json @@ -460,5 +460,16 @@ "all": "crwdns10812:0crwdne10812:0", "normal-tabs": "crwdns10814:0crwdne10814:0", "incognito-tabs": "crwdns10816:0crwdne10816:0" - } + }, + "editor_config": "crwdns10818:0crwdne10818:0", + "editor_config_description": "crwdns10820:0crwdne10820:0", + "editor_type_definition": "crwdns10822:0crwdne10822:0", + "editor_type_definition_description": "crwdns10824:0crwdne10824:0", + "eslint_rules_reset": "crwdns10826:0crwdne10826:0", + "eslint_rules_saved": "crwdns10828:0crwdne10828:0", + "editor_config_reset": "crwdns10830:0crwdne10830:0", + "editor_config_saved": "crwdns10832:0crwdne10832:0", + "editor_config_format_error": "crwdns10834:0crwdne10834:0", + "editor_type_definition_reset": "crwdns10836:0crwdne10836:0", + "editor_type_definition_saved": "crwdns10838:0crwdne10838:0" } \ No newline at end of file diff --git a/src/locales/en-US/translation.json b/src/locales/en-US/translation.json index 181fd38c0..47ed4b2a5 100644 --- a/src/locales/en-US/translation.json +++ b/src/locales/en-US/translation.json @@ -460,5 +460,16 @@ "all": "All", "normal-tabs": "Normal tags", "incognito-tabs": "Incognito tags" - } + }, + "editor_config": "Editor Configuration", + "editor_config_description": "You can refer to the compilerOptions in jsconfig.js for configuration", + "editor_type_definition": "Editor Type Definition", + "editor_type_definition_description": "You can customize your own type definitions, and the script editor will automatically load these type definitions", + "eslint_rules_reset": "ESLint Rules Reset", + "eslint_rules_saved": "ESLint Rules Saved", + "editor_config_reset": "Editor Configuration Reset", + "editor_config_saved": "Editor Configuration Saved", + "editor_config_format_error": "Editor Configuration Format Error", + "editor_type_definition_reset": "Editor Type Definition Reset", + "editor_type_definition_saved": "Editor Type Definition Saved" } \ No newline at end of file diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json index 7c3c81f53..5aecb014a 100644 --- a/src/locales/zh-CN/translation.json +++ b/src/locales/zh-CN/translation.json @@ -460,5 +460,16 @@ "all": "所有标签", "normal-tabs": "普通标签", "incognito-tabs": "隐身标签" - } + }, + "editor_config": "", + "editor_config_description": "", + "editor_type_definition": "", + "editor_type_definition_description": "", + "eslint_rules_reset": "", + "eslint_rules_saved": "", + "editor_config_reset": "", + "editor_config_saved": "", + "editor_config_format_error": "", + "editor_type_definition_reset": "", + "editor_type_definition_saved": "" } \ No newline at end of file diff --git a/src/pages/components/CodeEditor/index.tsx b/src/pages/components/CodeEditor/index.tsx index f258dbe85..964f43920 100644 --- a/src/pages/components/CodeEditor/index.tsx +++ b/src/pages/components/CodeEditor/index.tsx @@ -1,7 +1,7 @@ -import { LinterWorker } from "@App/pkg/utils/monaco-editor"; import { editor, Range } from "monaco-editor"; import React, { useEffect, useImperativeHandle, useRef, useState } from "react"; import { globalCache, systemConfig } from "@App/pages/store/global"; +import { LinterWorker } from "@App/pkg/utils/monaco-editor"; type Props = { className?: string; diff --git a/src/pages/components/CustomTrans/index.tsx b/src/pages/components/CustomTrans/index.tsx index 53c73f68b..c0d9c28cb 100644 --- a/src/pages/components/CustomTrans/index.tsx +++ b/src/pages/components/CustomTrans/index.tsx @@ -4,8 +4,9 @@ import { useTranslation } from "react-i18next"; // 因为i18n的Trans组件打包后出现问题,所以自己实现一个 export const CustomTrans: React.FC<{ + className?: string; i18nKey: string; -}> = ({ i18nKey }) => { +}> = ({ className, i18nKey }) => { const { t } = useTranslation(); const children: (JSX.Element | string)[] = []; let content = t(i18nKey); @@ -39,7 +40,7 @@ export const CustomTrans: React.FC<{ } } - return
{children}
; + return
{children}
; }; export default CustomTrans; diff --git a/src/pages/options/main.tsx b/src/pages/options/main.tsx index ff8669784..068de478a 100644 --- a/src/pages/options/main.tsx +++ b/src/pages/options/main.tsx @@ -11,7 +11,7 @@ import "./index.css"; import LoggerCore from "@App/app/logger/core.ts"; import { LoggerDAO } from "@App/app/repo/logger.ts"; import DBWriter from "@App/app/logger/db_writer.ts"; -import registerEditor from "@App/pkg/utils/monaco-editor.ts"; +import registerEditor from "@App/pkg/utils/monaco-editor"; import storeSubscribe from "../store/subscribe.ts"; import migrate from "@App/app/migrate.ts"; diff --git a/src/pages/options/routes/Setting.tsx b/src/pages/options/routes/Setting.tsx index d4ecfdafb..173e4cb48 100644 --- a/src/pages/options/routes/Setting.tsx +++ b/src/pages/options/routes/Setting.tsx @@ -14,6 +14,7 @@ import FileSystemFactory from "@Packages/filesystem/factory"; import FileSystemParams from "@App/pages/components/FileSystemParams"; import { blackListSelfCheck } from "@App/pkg/utils/match"; import { obtainBlackList } from "@App/pkg/utils/utils"; +import CustomTrans from "@App/pages/components/CustomTrans"; function Setting() { const [syncDelete, setSyncDelete] = useState(); @@ -29,6 +30,8 @@ function Setting() { const [updateDisableScript, setUpdateDisableScript] = useState(false); const [silenceUpdateScript, setSilenceUpdateScript] = useState(false); const [enableEslint, setEnableEslint] = useState(false); + const [editorConfig, setEditorConfig] = useState(""); + const [editorTypeDefinition, setEditorTypeDefinition] = useState(""); const [eslintConfig, setEslintConfig] = useState(""); const [blacklist, setBlacklist] = useState(""); const [badgeNumberType, setBadgeNumberType] = useState<"none" | "run_count" | "script_count">("run_count"); @@ -67,6 +70,8 @@ function Setting() { systemConfig.getBadgeBackgroundColor(), systemConfig.getBadgeTextColor(), systemConfig.getScriptMenuDisplayType(), + systemConfig.getEditorConfig(), + systemConfig.getEditorTypeDefinition(), ]).then( ([ cloudSync, @@ -82,6 +87,8 @@ function Setting() { badgeBackgroundColor, badgeTextColor, scriptMenuDisplayType, + editorConfig, + editorTypeDefinition, ]) => { setSyncDelete(cloudSync.syncDelete); setSyncScriptStatus(cloudSync.syncStatus); @@ -100,6 +107,8 @@ function Setting() { setBadgeBackgroundColor(badgeBackgroundColor); setBadgeTextColor(badgeTextColor); setScriptMenuDisplayType(scriptMenuDisplayType); + setEditorConfig(editorConfig); + setEditorTypeDefinition(editorTypeDefinition); } ); }; @@ -445,14 +454,19 @@ function Setting() { onChange={(v) => { setEslintConfig(v); }} - onBlur={(v) => { + onBlur={() => { prettier .format(eslintConfig, { parser: "json", plugins: [prettierPluginEstree, babel], }) - .then(() => { - systemConfig.setEslintConfig(v.target.value); + .then((value) => { + if (value === "") { + Message.success(t("eslint_rules_reset")); + } else { + Message.success(t("eslint_rules_saved")); + } + systemConfig.setEslintConfig(value); }) .catch((e) => { Message.error(`${t("eslint_config_format_error")}: ${JSON.stringify(Logger.E(e))}`); @@ -461,6 +475,74 @@ function Setting() { /> )} +
+
+ {t("editor_config")} + +
+ { + setEditorConfig(v); + }} + onBlur={() => { + prettier + .format(editorConfig, { + parser: "json", + plugins: [prettierPluginEstree, babel], + }) + .then((value) => { + if (value === "") { + Message.success(t("editor_config_reset")); + } else { + Message.success(t("editor_config_saved")); + } + systemConfig.setEditorConfig(value); + }) + .catch((e) => { + Message.error(`${t("editor_config_format_error")}: ${JSON.stringify(Logger.E(e))}`); + }); + }} + /> +
+
+
+ {t("editor_type_definition")} + +
+ { + setEditorTypeDefinition(v); + }} + onBlur={() => { + if (editorTypeDefinition === "") { + Message.success(t("editor_type_definition_reset")); + } else { + Message.success(t("editor_type_definition_saved")); + } + systemConfig.setEditorTypeDefinition(editorTypeDefinition); + }} + /> +
diff --git a/src/pkg/config/config.ts b/src/pkg/config/config.ts index f7ee367ec..db99bac4b 100644 --- a/src/pkg/config/config.ts +++ b/src/pkg/config/config.ts @@ -1,10 +1,11 @@ -import { Message } from "@arco-design/web-react"; import ChromeStorage from "./chrome_storage"; import { defaultConfig } from "../../../packages/eslint/linter-config"; +import { defaultConfig as editorDefaultConfig } from "@App/pkg/utils/monaco-editor/config"; import type { FileSystemType } from "@Packages/filesystem/factory"; import type { MessageQueue, TKeyValue } from "@Packages/message/message_queue"; import { changeLanguage, matchLanguage } from "@App/locales/locales"; import { ExtVersion } from "@App/app/const"; +import defaultTypeDefinition from "@App/template/scriptcat.d.tpl"; export const SystemConfigChange = "systemConfigChange"; @@ -186,16 +187,37 @@ export class SystemConfig { setEslintConfig(v: string) { if (v === "") { this.set("eslint_config", undefined); - Message.success("ESLint规则已重置"); return; } - try { - JSON.parse(v); - this.set("eslint_config", v); - Message.success("ESLint规则已保存"); - } catch (err: any) { - Message.error(err.toString()); + JSON.parse(v); + return this.set("eslint_config", v); + } + + getEditorConfig() { + return this.get("editor_config", editorDefaultConfig); + } + + setEditorConfig(v: string) { + if (v === "") { + this.set("editor_config", undefined); + return; + } + JSON.parse(v); + return this.set("editor_config", v); + } + + // 获取typescript类型定义 + getEditorTypeDefinition() { + return localStorage.getItem("editor_type_definition") || defaultTypeDefinition; + } + + // 由于内容过大,只能存储到localStorage中 + setEditorTypeDefinition(v: string) { + if (v === "") { + delete localStorage["editor_type_definition"]; + return; } + localStorage.setItem("editor_type_definition", v); } // 日志清理周期 diff --git a/src/pkg/utils/monaco-editor/config.ts b/src/pkg/utils/monaco-editor/config.ts new file mode 100644 index 000000000..4db488342 --- /dev/null +++ b/src/pkg/utils/monaco-editor/config.ts @@ -0,0 +1,9 @@ +import type { languages } from "monaco-editor"; + +const config = { + noSemanticValidation: true, + noSyntaxValidation: false, + onlyVisible: false, +} as languages.typescript.CompilerOptions; + +export const defaultConfig = JSON.stringify(config, null, 2); diff --git a/src/pkg/utils/monaco-editor.ts b/src/pkg/utils/monaco-editor/index.ts similarity index 67% rename from src/pkg/utils/monaco-editor.ts rename to src/pkg/utils/monaco-editor/index.ts index 821ebffbb..f304435a2 100644 --- a/src/pkg/utils/monaco-editor.ts +++ b/src/pkg/utils/monaco-editor/index.ts @@ -1,5 +1,4 @@ -import { globalCache } from "@App/pages/store/global"; -import dts from "@App/template/scriptcat.d.tpl"; +import { globalCache, systemConfig } from "@App/pages/store/global"; import EventEmitter from "eventemitter3"; import { languages } from "monaco-editor"; @@ -16,8 +15,6 @@ export default function registerEditor() { }, }; - languages.typescript.javascriptDefaults.addExtraLib(dts, "scriptcat.d.ts"); - // 悬停提示 const prompt: { [key: string]: any } = { name: "脚本名称", @@ -92,6 +89,53 @@ export default function registerEditor() { isPreferred: true, }); } + // 添加eslint-disable-next-line和eslint-disable + actions.push({ + title: `添加 eslint-disable-next-line 注释`, + diagnostics: [val], + kind: "quickfix", + edit: { + edits: [ + { + resource: model.uri, + textEdit: { + range: { + startLineNumber: val.startLineNumber, + endLineNumber: val.startLineNumber, + startColumn: 1, + endColumn: 1, + }, + text: `// eslint-disable-next-line ${typeof val.code === "string" ? val.code : val.code!.value}\n`, + }, + versionId: undefined, + }, + ], + }, + isPreferred: true, + }); + actions.push({ + title: `添加 eslint-disable 注释`, + diagnostics: [val], + kind: "quickfix", + edit: { + edits: [ + { + resource: model.uri, + textEdit: { + range: { + startLineNumber: 1, + endLineNumber: 1, + startColumn: 1, + endColumn: 1, + }, + text: `/* eslint-disable ${typeof val.code === "string" ? val.code : val.code!.value} */\n`, + }, + versionId: undefined, + }, + ], + }, + isPreferred: true, + }); } // const actions = context.markers.map((error) => { @@ -119,6 +163,17 @@ export default function registerEditor() { }; }, }); + + Promise.all([systemConfig.getEditorConfig(), systemConfig.getEditorTypeDefinition()]).then( + ([editorConfig, typeDefinition]) => { + // 设置编辑器设置 + languages.typescript.javascriptDefaults.setCompilerOptions( + JSON.parse(editorConfig) as languages.typescript.CompilerOptions + ); + // 注册类型定义 + languages.typescript.javascriptDefaults.addExtraLib(typeDefinition, "scriptcat.d.ts"); + } + ); } export class LinterWorker { diff --git a/vitest.config.ts b/vitest.config.ts index 5172fa4d3..80250fbf1 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,4 +1,5 @@ import path from "path"; +import fs from "fs"; import { defineConfig } from "vitest/config"; export default defineConfig({ @@ -10,6 +11,18 @@ export default defineConfig({ "monaco-editor": path.resolve(__dirname, "./tests/mocks/monaco-editor.ts"), }, }, + plugins: [ + { + name: "handle-tpl-files", + load(id) { + if (id.endsWith(".tpl")) { + // Return the content as a string asset + const content = fs.readFileSync(id, "utf-8"); + return `export default ${JSON.stringify(content)};`; + } + }, + }, + ], test: { environment: "jsdom", // List setup file