From b3edb00d9d810581e4dfeaf0061f19e4a45a5e03 Mon Sep 17 00:00:00 2001 From: SMJSGaming Date: Thu, 26 Sep 2024 02:04:03 +0200 Subject: [PATCH 1/3] Fixed fonts not properly indicating optionals --- src/project/mod.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/project/mod.ts b/src/project/mod.ts index 535b0aa..f926c02 100644 --- a/src/project/mod.ts +++ b/src/project/mod.ts @@ -16,13 +16,13 @@ export interface Font { * @pattern [0-9]+(-[0-9]+)?(,([0-9]+(-[0-9]+)?))* * @default 32-126,8226 */ - charset: string, + charset?: string | null, /** * If specified, will generate a black outline of the provided size around * the font's characters. Experimental! * @minimum 0 */ - outline: number, + outline?: number | null, } export interface Resources { From 677ae5a52a31a37850827a8ba08dc793f5868caf Mon Sep 17 00:00:00 2001 From: SMJSGaming Date: Thu, 26 Sep 2024 02:04:43 +0200 Subject: [PATCH 2/3] Added more linters and fixed existing linters --- src/project/lint.ts | 170 ++++++++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 76 deletions(-) diff --git a/src/project/lint.ts b/src/project/lint.ts index aa4b7d2..82a4dff 100644 --- a/src/project/lint.ts +++ b/src/project/lint.ts @@ -1,110 +1,127 @@ import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, CodeActionProvider, Command, Diagnostic, DiagnosticCollection, DiagnosticSeverity, ExtensionContext, languages, Position, ProviderResult, Range, Selection, TextDocument, Uri, workspace, WorkspaceEdit } from "vscode"; import { getProjectFromDocument } from "./project"; -import { getOutputChannel } from "../config"; import { readFile } from "fs/promises"; -import { readFileSync } from "fs"; - -type Binding = "inline" | "link" | number | null; -type Bindings = { - classes: { - name: string, - functions: { - name: string, - args: { type: string, name: string }[], - const: boolean, - virtual: boolean, - static: boolean, - bindings: { - win: Binding, - imac: Binding, - m1: Binding, - ios: Binding, - android32: Binding, - android64: Binding, - } - }[], - }[] -}; -let LOADED_BINDINGS: Bindings | undefined = undefined; +// type Binding = "inline" | "link" | number | null; +// type Bindings = { +// classes: { +// name: string, +// functions: { +// name: string, +// args: { type: string, name: string }[], +// const: boolean, +// virtual: boolean, +// static: boolean, +// bindings: { +// win: Binding, +// imac: Binding, +// m1: Binding, +// ios: Binding, +// android32: Binding, +// android64: Binding, +// } +// }[], +// }[] +// }; +// +// let LOADED_BINDINGS: Bindings | undefined = undefined; interface MaybeDocument { uri: Uri, data: string, } +const TYPE_LOOKUPS: Record = { + bool: "bool", + int: "int64_t", + float: "double", + string: "std::string", + file: "std::filesystem::path", + folder: "std::filesystem::path", + color: "cocos2d::ccColor3B", + rgb: "cocos2d::ccColor3B", + rgba: "cocos2d::ccColor4B" +}; + function lint( document: MaybeDocument, diagnostics: Diagnostic[], code: string, regex: RegExp, - condition: (match: { text: string, range: Range }) => string | undefined, - startLine: number = 0, - endLine?: number, + condition: (match: { text: string, groups: Record | undefined, range: Range }) => { msg: string, level: DiagnosticSeverity } | string | undefined, ) { - const lines = document.data.split("\n"); + const ignoreRanges: { from: number, to: number }[] = []; - let ignoring: "next" | "until-end" | undefined; - for (let line = startLine; line < lines.length; line++) { - if (endLine && line > endLine) { - break; + for (const match of document.data.matchAll(new RegExp(`(?:\\/\\/\\s*@geode-begin-ignore\\(${code}\\).*?$)(?:(?!\\/\\/\\s*@geode-end-ignore\\(${code}\\))(?:\\s|.))*`, "gm"))) { + if (match.index != undefined) { + ignoreRanges.push({ from: match.index, to: match.index + match[0].length }); } + } - const lineData = lines[line]; - - // Allow ignoring lints via comments - if (lineData.includes(`geode-ignore-${code}`) || lineData.includes("geode-ignore-all")) { - ignoring = "next"; - continue; - } - else if (lineData.includes(`geode-begin-ignore-${code}`) || lineData.includes("geode-begin-ignore-all")) { - ignoring = "until-end"; + // Look for matches for the regex + for (const match of document.data.matchAll(new RegExp( + `(?\\/\\/\\s*@geode-ignore\\(${code}\\).*?$\\r?\\s+^.*?)?${regex.source}`, + regex.flags.includes("m") ? regex.flags : regex.flags + "m" + ))) { + if (match.index == undefined || match.groups?.ignore || ignoreRanges.some(range => range.from <= match.index! && range.to >= match.index!)) { continue; } - else if (lineData.includes(`geode-end-ignore-${code}`) || lineData.includes("geode-end-ignore-all")) { - ignoring = undefined; - } - // Skip if we're ignoring stuff - else if (ignoring !== undefined) { - if (ignoring === "next") { - ignoring = undefined; - } - continue; + + const priorLines = document.data.substring(0, match.index).split("\n"); + const range = new Range( + new Position(priorLines.length - 1, priorLines.at(-1)!.length), + new Position(priorLines.length + match[0].split("\n").length - 2, match.index + match[0].length), + ); + const result = condition({ text: match[0], groups: match.groups, range }); + + if (result !== undefined) { + const isString = typeof result == "string"; + const diagnostic = new Diagnostic(range, isString ? result : result.msg, isString ? DiagnosticSeverity.Warning : result.level); + diagnostic.code = code; + diagnostic.source = "geode"; + diagnostics.push(diagnostic); } + } +} - // Look for matches for the regex - for (const match of lineData.matchAll(regex)) { - if (!match.index) { - continue; - } - const range = new Range( - new Position(line, match.index), - new Position(line, match.index + match[0].length), - ); - const msg = condition({ text: match[0], range }); - if (msg !== undefined) { - const diagnostic = new Diagnostic(range, msg, DiagnosticSeverity.Warning); - diagnostic.code = code; - diagnostic.source = "geode"; - diagnostics.push(diagnostic); - } - } - } +function lintDumbStuff(document: MaybeDocument, diagnostics: Diagnostic[]) { + lint(document, diagnostics, "no", /using\s+namespace\s+std\s*;/g, () => { + return { msg: "NO GOD! NO GOD PLEASE NO! NO! NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!", level: DiagnosticSeverity.Error }; + }); + lint(document, diagnostics, "geode-alternative", /std\s*::\s*cout/g, () => { + return "Use the logging methods from the \"geode::log\" namespace instead of \"std::cout\""; + }); + lint( + document, diagnostics, + "recursive-hook", + /hook\s*\(\s*(?:(?:\w+_cast|as)\s*<\s*.+?\s*>\s*\(|\(\s*.+?\s*\))\s*addresser\s*::\s*getNonVirtual\s*\(\s*&\s*web\s*::\s*WebRequest\s*::\s*send(?:\s|[^;])+?/g, + () => { + return "Do not hook \"web::WebRequest::send\". This will easily cause infinite loops between mods."; + } + ); } function lintSettings(document: MaybeDocument, diagnostics: Diagnostic[]) { - const project = getProjectFromDocument(document.uri); - if (!project || !project.modJson.settings) { + const settings = getProjectFromDocument(document.uri)?.modJson.settings; + if (!settings) { return; } lint( document, diagnostics, "unknown-setting", - /(?<=[gs]etSettingValue.*?\(\s*")[a-z0-9\-]+(?="[^\)]*\))/g, - ({ text }) => { - if (!(text in project.modJson.settings!)) { - return `Unknown setting ${text}`; + /[gs]etSettingValue<\s*(?[^>]+?)\s*>\s*\(\s*"(?(?:[^"\\]|\\.)+?)\"\s*\)/g, + ({ groups }) => { + const setting = settings[groups!.name]; + const types = TYPE_LOOKUPS[setting.type]?.split("::").reverse(); + + if (!setting) { + return `Unknown setting ${groups!.name}`; + } else if (setting.type == "title") { + return "Titles can't be used as a setting value"; + } else if (!setting.type.startsWith("custom:") && !groups!.type.split("::").reverse().every((part, i) => part.trim() == types?.[i])) { + return `Setting ${groups!.name} is of type ${setting.type}, not ${groups!.type}`; } + return undefined; } ); @@ -148,6 +165,7 @@ function applyGeodeLints(document: MaybeDocument, diagnosticCollection: Diagnost const diagnostics: Diagnostic[] = []; // Add more linters here if needed + lintDumbStuff(document, diagnostics); lintSettings(document, diagnostics); // lintOverrides(document, diagnostics); @@ -157,7 +175,7 @@ function applyGeodeLints(document: MaybeDocument, diagnosticCollection: Diagnost } class SuppressDiagnosticProvider implements CodeActionProvider { - provideCodeActions(document: TextDocument, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult<(Command | CodeAction)[]> { + provideCodeActions(document: TextDocument, _1: Range | Selection, context: CodeActionContext, _2: CancellationToken): ProviderResult<(Command | CodeAction)[]> { const actions: CodeAction[] = []; context.diagnostics.forEach(diagnostic => { // Add a Quick Fix for dismissing Geode diagnostics From a1343c5c5b5872ec564ffc9d84a18b4f518a87c6 Mon Sep 17 00:00:00 2001 From: SMJSGaming Date: Thu, 26 Sep 2024 09:19:36 +0200 Subject: [PATCH 3/3] Removed the joke lint and specific hook lint --- src/project/lint.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/project/lint.ts b/src/project/lint.ts index 82a4dff..032f820 100644 --- a/src/project/lint.ts +++ b/src/project/lint.ts @@ -84,21 +84,10 @@ function lint( } } -function lintDumbStuff(document: MaybeDocument, diagnostics: Diagnostic[]) { - lint(document, diagnostics, "no", /using\s+namespace\s+std\s*;/g, () => { - return { msg: "NO GOD! NO GOD PLEASE NO! NO! NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!", level: DiagnosticSeverity.Error }; - }); +function lintAlternative(document: MaybeDocument, diagnostics: Diagnostic[]) { lint(document, diagnostics, "geode-alternative", /std\s*::\s*cout/g, () => { return "Use the logging methods from the \"geode::log\" namespace instead of \"std::cout\""; }); - lint( - document, diagnostics, - "recursive-hook", - /hook\s*\(\s*(?:(?:\w+_cast|as)\s*<\s*.+?\s*>\s*\(|\(\s*.+?\s*\))\s*addresser\s*::\s*getNonVirtual\s*\(\s*&\s*web\s*::\s*WebRequest\s*::\s*send(?:\s|[^;])+?/g, - () => { - return "Do not hook \"web::WebRequest::send\". This will easily cause infinite loops between mods."; - } - ); } function lintSettings(document: MaybeDocument, diagnostics: Diagnostic[]) { @@ -165,7 +154,7 @@ function applyGeodeLints(document: MaybeDocument, diagnosticCollection: Diagnost const diagnostics: Diagnostic[] = []; // Add more linters here if needed - lintDumbStuff(document, diagnostics); + lintAlternative(document, diagnostics); lintSettings(document, diagnostics); // lintOverrides(document, diagnostics);