[v1.3] 优化 Monaco Editor 设定,加 `/* global xxx */` 修正 by cyfung1031 · Pull Request #1012 · scriptscat/scriptcat

@cyfung1031

概述 Descriptions

变更内容 Changes

截图 Screenshots

Screenshot 2025-11-22 at 14 20 08 Screenshot 2025-11-22 at 17 22 28

@cyfung1031

@cyfung1031 cyfung1031 changed the title 优化 Monaco Editor 设定,加 /* global xxx */ 修正 [v1.3] 优化 Monaco Editor 设定,加 /* global xxx */ 修正

Nov 22, 2025

@cyfung1031

CodFrm

accessibilitySupport: "off",
largeFileOptimizations: true,
colorDecorators: true,
} as const;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

加这么多设置主要是为了什么?,😵‍💫虽然体验了一下新的编辑器,看起来不错。感觉可以再优化优化 编辑器配置 功能让用户也可以自定义这部分

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以改成 让用户也可以自定义这部分。 没意见。
自定义的话 同时能解决 换行 wrap 的问题吧

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,可能就为 编辑器配置 再增加几个层级,类似:

{
"editor":{
xxxxx
},
"tsconfig":{
  "noSemanticValidation": true,
  "noSyntaxValidation": false,
  "onlyVisible": false,
  "allowNonTsExtensions": true,
  "allowJs": true,
  "strict": true
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

这个 PR 为 Monaco Editor 添加了 ESLint no-undef 错误的 /* global xxx */ 快速修复功能,并优化了编辑器的配置选项。

主要变更包括:

  • 实现了自动添加/更新 /* global */ 注释的 quick fix 功能
  • 优化了 TypeScript 编译器选项以提供更好的智能提示
  • 重构了编辑器配置,提取公共选项以消除重复代码

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 12 comments.

File Description
src/pkg/utils/monaco-editor/index.ts 新增 findGlobalInsertionInfoupdateGlobalCommentLine 函数,实现 /* global */ 注释的自动插入和更新逻辑;为 no-undef 错误添加快速修复功能
src/pkg/utils/monaco-editor/config.ts 新增 checkJsnoUnusedLocalsnoFallthroughCasesInSwitchnoImplicitThis 配置选项,优化 JavaScript 代码的类型检查行为
src/pages/components/CodeEditor/index.tsx 重构编辑器配置,将重复的配置选项提取为 commonEditorOptions,并添加了更多编辑器功能选项(如智能提示、参数提示、括号着色等)

Comment on lines +149 to +173

const updateGlobalCommentLine = (oldLine: string, globalName: string) => {
// if already present, do nothing
const nameRegex = new RegExp("\\b" + escapeRegExp(globalName) + "\\b");
if (nameRegex.test(oldLine)) {
return oldLine;
}

const endIdx = oldLine.lastIndexOf("*/");
if (endIdx === -1) {
// weird / malformed, just append
return oldLine + ", " + globalName;
}

const before = oldLine.slice(0, endIdx).trimEnd(); // up to before */
const after = oldLine.slice(endIdx); // "*/" and whatever after

// decide separator
const needsComma =
!/global\s*$/.test(before) && // not just "/* global"
!/[, ]$/.test(before); // doesn't already end with , or space

const sep = needsComma ? ", " : " ";

return before + sep + globalName + " " + after;
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增的 updateGlobalCommentLine 函数缺少测试覆盖。该函数处理向现有 /* global */ 注释行添加新变量名的逻辑,应该添加单元测试来验证:

  1. 变量名已存在时不重复添加
  2. /* global */ 末尾正确添加变量名
  3. /* global a, b */ 格式中正确添加分隔符
  4. 处理格式错误的注释行(缺少 */)
  5. 正确转义特殊字符的变量名

建议添加测试来确保边界情况得到正确处理。

Copilot uses AI. Check for mistakes.

Comment on lines +218 to +219

const match = message.match(/^[^']*'([^']+)'[^']*$/);
const globalName = match && match[1];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

正则表达式 /^[^']*'([^']+)'[^']*$/ 假设消息格式中始终使用单引号,但ESLint的消息格式可能因语言环境而异。例如中文环境下可能使用其他引号。建议使用更robust的方式提取变量名:

const match = message.match(/^['"]([^'"]+)['"]/) || message.match(/^([^\s]+)\s+is not defined/);
const globalName = match && match[1];

或者直接使用 val.sourceval.relatedInformation 如果Monaco/ESLint提供了更结构化的数据。

const match = message.match(/^[^']*'([^']+)'[^']*$/);
const globalName = match && match[1];
// 优先使用结构化数据,其次更健壮的正则
let globalName: string | undefined;
if (val.source) {
globalName = val.source;
} else if (val.relatedInformation && Array.isArray(val.relatedInformation) && val.relatedInformation[0]?.message) {
// 某些 ESLint/Monaco 版本会把变量名放在 relatedInformation
globalName = val.relatedInformation[0].message;
} else {
// 支持多种引号和格式
const match =
message.match(/^['"`]([^'"`]+)['"`]/) ||
message.match(/^([^\s]+)\s+is not defined/) ||
message.match(/([^\s"']+)[\s\S]*/); // 中文兜底
globalName = match && match[1];
}

Copilot uses AI. Check for mistakes.

if (globalLine != null) {
// there is already a /* global ... */ line → update it
const oldLine = model.getLineContent(globalLine);
const newLine = updateGlobalCommentLine(oldLine, globalName);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当更新现有的 /* global */ 行时,如果 updateGlobalCommentLine 返回的 newLineoldLine 相同(变量名已存在),仍然会创建一个不必要的编辑操作。建议在创建 textEdit 之前检查:

const newLine = updateGlobalCommentLine(oldLine, globalName);
if (newLine === oldLine) {
  continue; // 或者跳过添加这个action
}

这样可以避免在代码已经正确时提供无意义的quick fix选项。

const newLine = updateGlobalCommentLine(oldLine, globalName);
const newLine = updateGlobalCommentLine(oldLine, globalName);
if (newLine === oldLine) {
continue; // 已存在该变量名, 跳过无意义的编辑操作
}

Copilot uses AI. Check for mistakes.

Comment on lines +94 to +143

const findGlobalInsertionInfo = (model: editor.ITextModel) => {
const lineCount = model.getLineCount();

let insertLine = 1; // first non-comment line
let globalLine: number | null = null;

let line = 1;
while (line <= lineCount) {
const raw = model.getLineContent(line);
const text = raw.trim();

// empty line
if (text === "") {
line += 1;
continue;
}

// single-line comment
if (text.startsWith("//")) {
line += 1;
continue;
}

// block comment
if (text.startsWith("/*")) {
// check if this is a /* global ... */ comment
if (/^\/\*\s*global\b/.test(text)) {
globalLine = line;
}

// skip the whole block comment
while (line <= lineCount && !model.getLineContent(line).includes("*/")) {
line += 1;
}
line += 1;
continue;
}

// first non-comment, non-empty line = insertion point
insertLine = line;
break;
}

// fallback (file all comments / empty)
if (insertLine > lineCount) {
insertLine = lineCount + 1;
}

return { insertLine, globalLine };
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增的 findGlobalInsertionInfo 函数缺少测试覆盖。该函数包含复杂的逻辑来处理单行注释、多行注释和查找 /* global */ 注释行,应该添加单元测试来验证:

  1. 空文件的处理
  2. 只有注释的文件
  3. 单行 /* global */ 注释的检测
  4. 多行块注释的跳过逻辑
  5. 混合注释和代码的情况

建议在 tests/ 目录下创建 monaco-editor.test.ts 文件来测试这些工具函数。

Copilot uses AI. Check for mistakes.

@cyfung1031

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@CodFrm