Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 16 additions & 2 deletions src/pkg/utils/monaco-editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
contentChangeCanAffectMetadataMarkers,
getMetadataAlignmentBlocks,
getMetadataAlignmentTargetColumn,
getMetadataValueToken,
getUndefinedMetadataTagMatches,
getUnsupportedGrantMatches,
isMetadataAlignmentBlockAligned,
metadataHoverPattern,
type MetadataAlignmentBlock,
Expand Down Expand Up @@ -115,6 +117,7 @@ const scriptcatReplaceMatchTldWildcardRuleId = "scriptcat/replace-match-tld-wild
const scriptcatReplaceIncludeWithMatchRuleId = "scriptcat/replace-include-with-match";
const scriptcatGrantNoneConflictRuleId = "scriptcat/grant-none-conflict";
const scriptcatUndefinedMetadataTagRuleId = "scriptcat/undefined-metadata-tag";
const scriptcatUnsupportedGrantRuleId = "scriptcat/unsupported-grant";
const quickfixKind = "quickfix";
const noop = () => {};
const metadataFixPattern = /^(\s*\/\/[ \t]*@)(connect|match|include)([ \t]+)(\S+)(.*)$/i;
Expand Down Expand Up @@ -169,8 +172,6 @@ const getGrantValueHoverPrompt = (lineText: string, column: number) => {
return `\`${grantValue}\`<br>${prompt}`;
};

const getMetadataValueToken = (value: string) => /^\S+/.exec(value)?.[0] || "";

const createTextEditAction = (
model: editor.ITextModel,
title: string,
Expand Down Expand Up @@ -669,6 +670,18 @@ const getUndefinedMetadataTagMarkers = (
endColumn: match.endColumn,
}));

const getUnsupportedGrantMarkers = (blocks: MetadataAlignmentBlock[]): editor.IMarkerData[] =>
getUnsupportedGrantMatches(blocks).map((match) => ({
severity: MarkerSeverity.Warning,
message: currentEditorLang.unsupportedGrant.replace("{0}", match.grant),
source: scriptcatMarkerOwner,
code: scriptcatUnsupportedGrantRuleId,
startLineNumber: match.lineNumber,
startColumn: match.startColumn,
endLineNumber: match.lineNumber,
endColumn: match.endColumn,
}));

const updateScriptcatMetadataMarkers = (model: editor.ITextModel) => {
if (model.getLanguageId() !== "javascript") {
editor.setModelMarkers(model, scriptcatMarkerOwner, []);
Expand All @@ -687,6 +700,7 @@ const updateScriptcatMetadataMarkers = (model: editor.ITextModel) => {
const markers: editor.IMarkerData[] = [];
markers.push(...getGrantNoneConflictMarkers(metadataBlocks));
markers.push(...getUndefinedMetadataTagMarkers(model, metadataBlocks));
markers.push(...getUnsupportedGrantMarkers(metadataBlocks));

for (const block of metadataBlocks) {
if (isMetadataAlignmentBlockAligned(block)) continue;
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/de-DE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default {
replaceMatchTldWildcardWithInclude: "@match-TLD-Wildcard durch @include {0} ersetzen",
replaceIncludeWithMatch: "@include durch @match {0} ersetzen",
grantConflict: "@grant none kann nicht zusammen mit GM-APIs verwendet werden. Entfernen Sie none oder alle GM-APIs.",
unsupportedGrant: "@grant {0} wird von ScriptCat nicht unterstützt und hat keine Wirkung.",
grantValuePrompts,
prompt: {
name: "Skriptname",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "Replace @match TLD wildcard with @include {0}",
replaceIncludeWithMatch: "Replace @include with @match {0}",
grantConflict: "@grant none cannot be used with GM APIs. Remove none or all GM APIs.",
unsupportedGrant: "@grant {0} is not supported by ScriptCat and will not take effect.",
grantValuePrompts,
prompt: {
name: "Script name",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/ja-JP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default {
replaceMatchTldWildcardWithInclude: "@match の TLD ワイルドカードを @include {0} に置換",
replaceIncludeWithMatch: "@include を @match {0} に置換",
grantConflict: "@grant none は GM API と同時に使えません。none またはすべての GM API を削除してください。",
unsupportedGrant: "@grant {0} は ScriptCat では未対応のため、有効になりません。",
grantValuePrompts,
prompt: {
name: "スクリプト名",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/ko-KR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "@match 최상위 도메인 와일드카드를 @include {0}으로 바꾸기",
replaceIncludeWithMatch: "@include를 @match {0}으로 바꾸기",
grantConflict: "@grant none은 GM API와 함께 사용할 수 없습니다. none 또는 모든 GM API를 제거하세요.",
unsupportedGrant: "@grant {0}은(는) ScriptCat에서 지원되지 않으며 적용되지 않습니다.",
grantValuePrompts,
prompt: {
name: "스크립트 이름",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default {
replaceMatchTldWildcardWithInclude: "Substituir curinga de TLD em @match por @include {0}",
replaceIncludeWithMatch: "Substituir @include por @match {0}",
grantConflict: "@grant none não pode ser usado junto com GM APIs. Remova none ou todas as GM APIs.",
unsupportedGrant: "@grant {0} não é suportado pelo ScriptCat e não terá efeito.",
grantValuePrompts,
prompt: {
name: "Nome do script",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/ru-RU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "Заменить TLD wildcard @match на @include {0}",
replaceIncludeWithMatch: "Заменить @include на @match {0}",
grantConflict: "@grant none нельзя использовать вместе с GM API. Удалите none или все GM API.",
unsupportedGrant: "@grant {0} не поддерживается ScriptCat и не будет работать.",
grantValuePrompts,
prompt: {
name: "Имя скрипта",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/tr-TR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default {
replaceMatchTldWildcardWithInclude: "@match TLD joker karakterini @include {0} ile değiştir",
replaceIncludeWithMatch: "@include yerine @match {0} kullan",
grantConflict: "@grant none, GM API'leriyle birlikte kullanılamaz. none değerini veya tüm GM API'lerini kaldırın.",
unsupportedGrant: "@grant {0}, ScriptCat tarafından desteklenmiyor ve etkisi olmayacak.",
grantValuePrompts,
prompt: {
name: "Betik adı",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/vi-VN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "Thay wildcard TLD @match bằng @include {0}",
replaceIncludeWithMatch: "Thay @include bằng @match {0}",
grantConflict: "@grant none không thể dùng cùng GM API. Hãy xóa none hoặc tất cả GM API.",
unsupportedGrant: "@grant {0} không được ScriptCat hỗ trợ nên sẽ không có tác dụng.",
grantValuePrompts,
prompt: {
name: "Tên script",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "将 @match 顶级域名通配符改为 @include {0}",
replaceIncludeWithMatch: "将 @include 改为 @match {0}",
grantConflict: "@grant none 不能和 GM API 同时使用;请移除 none 或所有 GM API。",
unsupportedGrant: "@grant {0} 不受 ScriptCat 支持,不会生效。",
grantValuePrompts,
prompt: {
name: "脚本名称",
Expand Down
1 change: 1 addition & 0 deletions src/pkg/utils/monaco-editor/langs/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default {
replaceMatchTldWildcardWithInclude: "將 @match 頂級網域萬用字元改為 @include {0}",
replaceIncludeWithMatch: "將 @include 改為 @match {0}",
grantConflict: "@grant none 不能和 GM API 同時使用;請移除 none 或所有 GM API。",
unsupportedGrant: "@grant {0} 不受 ScriptCat 支援,不會生效。",
grantValuePrompts,
prompt: {
name: "腳本名稱",
Expand Down
67 changes: 67 additions & 0 deletions src/pkg/utils/monaco-editor/metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
contentChangeCanAffectMetadataMarkers,
getMetadataAlignmentBlocks,
getUndefinedMetadataTagMatches,
getUnsupportedGrantMatches,
isKnownMetadataTag,
} from "./metadata";

Expand Down Expand Up @@ -98,6 +99,72 @@ describe("getUndefinedMetadataTagMatches", () => {
});
});

describe("getUnsupportedGrantMatches", () => {
it.each(["GM_webRequest", "GM_audio", "GM_addScript", "GM_createObjectURL"])(
"应标记脚本猫不支持的 @grant %s",
(grant) => {
const model = createMockModel(["// ==UserScript==", `// @grant ${grant}`, "// ==/UserScript=="]);
const blocks = getMetadataAlignmentBlocks(model);
const matches = getUnsupportedGrantMatches(blocks);
expect(matches).toHaveLength(1);
expect(matches[0].grant).toBe(grant);
}
);

it.each([
"GM_setValue",
"GM.setValue",
"GM_xmlhttpRequest",
"GM.xmlHttpRequest",
"CAT_fileStorage",
"unsafeWindow",
"GM_info",
"none",
])("不应标记脚本猫支持的 @grant %s", (grant) => {
const model = createMockModel(["// ==UserScript==", `// @grant ${grant}`, "// ==/UserScript=="]);
const blocks = getMetadataAlignmentBlocks(model);
expect(getUnsupportedGrantMatches(blocks)).toEqual([]);
});

it("应返回精确的列范围", () => {
const model = createMockModel(["// ==UserScript==", "// @grant GM_webRequest", "// ==/UserScript=="]);
const blocks = getMetadataAlignmentBlocks(model);
const matches = getUnsupportedGrantMatches(blocks);
expect(matches).toEqual([{ lineNumber: 2, startColumn: 11, endColumn: 24, grant: "GM_webRequest" }]);
});

it("将 @grant 改为受支持的取值后应不再标记", () => {
const before = createMockModel(["// ==UserScript==", "// @grant GM_webRequest", "// ==/UserScript=="]);
expect(getUnsupportedGrantMatches(getMetadataAlignmentBlocks(before))).toHaveLength(1);

const after = createMockModel(["// ==UserScript==", "// @grant GM_setValue", "// ==/UserScript=="]);
expect(getUnsupportedGrantMatches(getMetadataAlignmentBlocks(after))).toEqual([]);
});

it("删除该 metadata 行后应不再标记", () => {
const before = createMockModel(["// ==UserScript==", "// @grant GM_webRequest", "// ==/UserScript=="]);
expect(getUnsupportedGrantMatches(getMetadataAlignmentBlocks(before))).toHaveLength(1);

const after = createMockModel(["// ==UserScript==", "// ==/UserScript=="]);
expect(getUnsupportedGrantMatches(getMetadataAlignmentBlocks(after))).toEqual([]);
});

it("区块内新增一行不支持的 @grant 后应正确重新计算,不影响其它诊断", () => {
const before = createMockModel(["// ==UserScript==", "// @grant GM_setValue", "// ==/UserScript=="]);
expect(getUnsupportedGrantMatches(getMetadataAlignmentBlocks(before))).toEqual([]);

const after = createMockModel([
"// ==UserScript==",
"// @grant GM_setValue",
"// @grant GM_audio",
"// ==/UserScript==",
]);
const matches = getUnsupportedGrantMatches(getMetadataAlignmentBlocks(after));
expect(matches).toHaveLength(1);
expect(matches[0]).toMatchObject({ lineNumber: 3, grant: "GM_audio" });
});
});

const createChangeEvent = (
changes: Array<{ startLineNumber: number; endLineNumber: number; text: string; rangeLength: number }>
): editor.IModelContentChangedEvent =>
Expand Down
34 changes: 33 additions & 1 deletion src/pkg/utils/monaco-editor/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { editor } from "monaco-editor";
import { resolveMetadataTagBase } from "@App/pkg/utils/script_compat";
import { isSupportedGrant, resolveMetadataTagBase } from "@App/pkg/utils/script_compat";

export type MetadataAlignmentLine = {
lineNumber: number;
Expand Down Expand Up @@ -28,6 +28,13 @@ export type UndefinedMetadataTagMatch = {
endColumn: number;
};

export type UnsupportedGrantMatch = {
lineNumber: number;
startColumn: number;
endColumn: number;
grant: string;
};

export const metadataHoverPattern = /^(\s*\/\/[ \t]*@)(\S+)([ \t]*)(.*)$/;
export const metadataLineStartPattern = /^\s*\/\/[ \t]*@/;
export const userscriptHeaderPattern = /^\s*\/\/[ \t]*==UserScript==[ \t]*$/;
Expand Down Expand Up @@ -122,6 +129,31 @@ export const getUndefinedMetadataTagMatches = (
return matches;
};

export const getMetadataValueToken = (value: string): string => /^\S+/.exec(value)?.[0] || "";

/** 只看已识别的 metadata 区块里的 @grant 行,取值判定复用运行时同一套 isSupportedGrant */
export const getUnsupportedGrantMatches = (blocks: MetadataAlignmentBlock[]): UnsupportedGrantMatch[] => {
const matches: UnsupportedGrantMatch[] = [];

for (const block of blocks) {
for (const line of block.lines) {
if (line.tag.toLowerCase() !== "grant") continue;

const grant = getMetadataValueToken(line.value);
if (!grant || isSupportedGrant(grant)) continue;

matches.push({
lineNumber: line.lineNumber,
startColumn: line.valueColumn + 1,
endColumn: line.valueColumn + 1 + grant.length,
grant,
});
}
}

return matches;
};

const lineCanAffectMetadataMarkers = (lineText: string) =>
metadataLineStartPattern.test(lineText) ||
userscriptHeaderPattern.test(lineText) ||
Expand Down
Loading