UNPKG

equicord-companion

Version:

Equicord Companion is a vscode extension to test Equicord patches & webpack finds right from the comfort of your IDE

128 lines (111 loc) 3.87 kB
import { DisablePluginData } from "@type/server"; import { createSourceFile, isCallExpression, isExportAssignment, isIdentifier, isObjectLiteralExpression, isPropertyAssignment, isStringLiteral, Node, ObjectLiteralExpression, ScriptTarget, StringLiteral, } from "typescript"; import { CodeLens, CodeLensProvider, ProviderResult, Range, TextDocument } from "vscode"; enum ParseResult { INVALID, NOT_FOUND, } function isSerialziable(node: Node): asserts node is StringLiteral { if (!isStringLiteral(node)) throw new Error("node is not serializable"); } function parseObjLiteralExpr< T extends readonly string[], >(expr: ObjectLiteralExpression, search: [...T]): { [key in T[number]]: string } { const toRet: Record<string, string> = {}; for (const node of expr.properties) { if (!isPropertyAssignment(node)) continue; if (!isIdentifier(node.name)) continue; if (!search.includes(node.name.text)) continue; isSerialziable(node.initializer); toRet[node.name.text] = node.initializer.text; } if (search.some((v) => !toRet[v])) throw new Error("Not all search values found"); return toRet as any; } function parsePossiblePatches(node: Node): { posStart: number; posEnd: number; pluginName: string; } | ParseResult { if (!isExportAssignment(node)) return ParseResult.NOT_FOUND; if (!isCallExpression(node.expression)) return ParseResult.NOT_FOUND; if (!isIdentifier(node.expression.expression)) return ParseResult.NOT_FOUND; if (node.expression.expression.text !== "definePlugin") return ParseResult.NOT_FOUND; if (!isObjectLiteralExpression(node.expression.arguments[0])) return ParseResult.INVALID; let pluginDef; try { pluginDef = parseObjLiteralExpr(node.expression.arguments[0], ["name"]); } catch { return ParseResult.INVALID; } return { pluginName: pluginDef.name, posStart: node.expression.pos, posEnd: node.expression.end, }; } export class PluginDefCodeLensProvider implements CodeLensProvider { check(text: string) { return text.includes("definePlugin") && text.includes("name:"); } provideCodeLenses(doc: TextDocument): ProviderResult<CodeLens[]> { const text = doc.getText(); if (!this.check(text)) return []; const file = createSourceFile(doc.fileName, text, ScriptTarget.Latest); const children = file.getChildAt(0) .getChildren(); const lenses: CodeLens[] = []; for (const node of children) { const patchesArray = parsePossiblePatches(node); if (patchesArray === ParseResult.INVALID) return []; if (patchesArray === ParseResult.NOT_FOUND) continue; const range = new Range(doc.positionAt(patchesArray.posStart), doc.positionAt(patchesArray.posEnd)); lenses.push(new CodeLens(range, { title: "Disable Plugin", command: "equicord-companion.disablePlugin", arguments: [ { pluginName: patchesArray.pluginName, enabled: false, } satisfies DisablePluginData, ], })); lenses.push(new CodeLens(range, { title: "Enable Plugin", command: "equicord-companion.disablePlugin", arguments: [ { pluginName: patchesArray.pluginName, enabled: true, } satisfies DisablePluginData, ], })); } return lenses; } }