aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json4
-rw-r--r--package.json3
-rw-r--r--patches/eslint@8.28.0.patch45
-rw-r--r--pnpm-lock.yaml26
-rw-r--r--src/components/PatchHelper.tsx23
-rw-r--r--src/plugins/shikiCodeblocks/index.ts6
-rw-r--r--src/plugins/shikiCodeblocks/shiki.css (renamed from src/plugins/shikiCodeblocks/style.css)9
-rw-r--r--src/utils/patches.ts55
-rw-r--r--src/utils/types.ts4
-rw-r--r--src/webpack/patchWebpack.ts12
10 files changed, 157 insertions, 30 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index 9bbe4f5..4cb86e0 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -84,7 +84,9 @@
"no-extra-semi": "error",
"consistent-return": ["warn", { "treatUndefinedAsUnspecified": true }],
"dot-notation": "error",
- "no-useless-escape": "error",
+ "no-useless-escape": ["error", {
+ "extra": "i"
+ }],
"no-fallthrough": "error",
"for-direction": "error",
"no-async-promise-executor": "error",
diff --git a/package.json b/package.json
index f0c3103..fe83c6a 100644
--- a/package.json
+++ b/package.json
@@ -62,7 +62,8 @@
"packageManager": "pnpm@7.13.4",
"pnpm": {
"patchedDependencies": {
- "eslint-plugin-path-alias@1.0.0": "patches/eslint-plugin-path-alias@1.0.0.patch"
+ "eslint-plugin-path-alias@1.0.0": "patches/eslint-plugin-path-alias@1.0.0.patch",
+ "eslint@8.28.0": "patches/eslint@8.28.0.patch"
}
},
"webExt": {
diff --git a/patches/eslint@8.28.0.patch b/patches/eslint@8.28.0.patch
new file mode 100644
index 0000000..994481b
--- /dev/null
+++ b/patches/eslint@8.28.0.patch
@@ -0,0 +1,45 @@
+diff --git a/lib/rules/no-useless-escape.js b/lib/rules/no-useless-escape.js
+index 2046a148a17fd1d5f3a4bbc9f45f7700259d11fa..f4898c6b57355a4fd72c43a9f32bf1a36a6ccf4a 100644
+--- a/lib/rules/no-useless-escape.js
++++ b/lib/rules/no-useless-escape.js
+@@ -97,12 +97,30 @@ module.exports = {
+ escapeBackslash: "Replace the `\\` with `\\\\` to include the actual backslash character."
+ },
+
+- schema: []
++ schema: [{
++ type: "object",
++ properties: {
++ extra: {
++ type: "string",
++ default: ""
++ },
++ extraCharClass: {
++ type: "string",
++ default: ""
++ },
++ },
++ additionalProperties: false
++ }]
+ },
+
+ create(context) {
++ const options = context.options[0] || {};
++ const { extra, extraCharClass } = options || ''
+ const sourceCode = context.getSourceCode();
+
++ const NON_CHARCLASS_ESCAPES = union(REGEX_NON_CHARCLASS_ESCAPES, new Set(extra))
++ const CHARCLASS_ESCAPES = union(REGEX_GENERAL_ESCAPES, new Set(extraCharClass))
++
+ /**
+ * Reports a node
+ * @param {ASTNode} node The node to report
+@@ -238,7 +256,7 @@ module.exports = {
+ .filter(charInfo => charInfo.escaped)
+
+ // Filter out characters that are valid to escape, based on their position in the regular expression.
+- .filter(charInfo => !(charInfo.inCharClass ? REGEX_GENERAL_ESCAPES : REGEX_NON_CHARCLASS_ESCAPES).has(charInfo.text))
++ .filter(charInfo => !(charInfo.inCharClass ? CHARCLASS_ESCAPES : NON_CHARCLASS_ESCAPES).has(charInfo.text))
+
+ // Report all the remaining characters.
+ .forEach(charInfo => report(node, charInfo.index, charInfo.text)); \ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6f76ff3..bca41ba 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,6 +4,9 @@ patchedDependencies:
eslint-plugin-path-alias@1.0.0:
hash: m6sma4g6bh67km3q6igf6uxaja
path: patches/eslint-plugin-path-alias@1.0.0.patch
+ eslint@8.28.0:
+ hash: 7wc6icvgtg3uswirb5tpsbjnbe
+ path: patches/eslint@8.28.0.patch
specifiers:
'@types/diff': ^5.0.2
@@ -50,7 +53,7 @@ devDependencies:
diff: 5.1.0
discord-types: 1.3.26
esbuild: 0.15.16
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
eslint-import-resolver-alias: 1.1.2
eslint-plugin-header: 3.1.1_eslint@8.28.0
eslint-plugin-path-alias: 1.0.0_m6sma4g6bh67km3q6igf6uxaja_eslint@8.28.0
@@ -216,7 +219,7 @@ packages:
'@typescript-eslint/type-utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a
'@typescript-eslint/utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a
debug: 4.3.4
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
ignore: 5.2.0
natural-compare-lite: 1.4.0
regexpp: 3.2.0
@@ -241,7 +244,7 @@ packages:
'@typescript-eslint/types': 5.45.0
'@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3
debug: 4.3.4
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
typescript: 4.9.3
transitivePeerDependencies:
- supports-color
@@ -268,7 +271,7 @@ packages:
'@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3
'@typescript-eslint/utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a
debug: 4.3.4
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
tsutils: 3.21.0_typescript@4.9.3
typescript: 4.9.3
transitivePeerDependencies:
@@ -312,7 +315,7 @@ packages:
'@typescript-eslint/scope-manager': 5.45.0
'@typescript-eslint/types': 5.45.0
'@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.28.0
semver: 7.3.7
@@ -894,7 +897,7 @@ packages:
peerDependencies:
eslint: '>=7.7.0'
dependencies:
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
dev: true
/eslint-plugin-path-alias/1.0.0_m6sma4g6bh67km3q6igf6uxaja_eslint@8.28.0:
@@ -902,7 +905,7 @@ packages:
peerDependencies:
eslint: ^7
dependencies:
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
nanomatch: 1.2.13
transitivePeerDependencies:
- supports-color
@@ -914,7 +917,7 @@ packages:
peerDependencies:
eslint: '>=5.0.0'
dependencies:
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
dev: true
/eslint-plugin-unused-imports/2.0.0_5am2datodjm2qi4eijrjrnoz54:
@@ -928,7 +931,7 @@ packages:
optional: true
dependencies:
'@typescript-eslint/eslint-plugin': 5.45.0_czs5uoqkd3podpy6vgtsxfc7au
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
eslint-rule-composer: 0.3.0
dev: true
@@ -959,7 +962,7 @@ packages:
peerDependencies:
eslint: '>=5'
dependencies:
- eslint: 8.28.0
+ eslint: 8.28.0_7wc6icvgtg3uswirb5tpsbjnbe
eslint-visitor-keys: 2.1.0
dev: true
@@ -973,7 +976,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
- /eslint/8.28.0:
+ /eslint/8.28.0_7wc6icvgtg3uswirb5tpsbjnbe:
resolution: {integrity: sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
@@ -1020,6 +1023,7 @@ packages:
transitivePeerDependencies:
- supports-color
dev: true
+ patched: true
/espree/9.4.0:
resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==}
diff --git a/src/components/PatchHelper.tsx b/src/components/PatchHelper.tsx
index 22c2b4d..cb60980 100644
--- a/src/components/PatchHelper.tsx
+++ b/src/components/PatchHelper.tsx
@@ -18,6 +18,7 @@
import { debounce } from "@utils/debounce";
import { makeCodeblock } from "@utils/misc";
+import { canonicalizeMatch, canonicalizeReplace, ReplaceFn } from "@utils/patches";
import { search } from "@webpack";
import { Button, Clipboard, Forms, Margins, Parser, React, Switch, Text, TextInput } from "@webpack/common";
@@ -41,20 +42,29 @@ const findCandidates = debounce(function ({ find, setModule, setError }) {
setModule([keys[0], candidates[keys[0]]]);
});
-function ReplacementComponent({ module, match, replacement, setReplacementError }) {
+interface ReplacementComponentProps {
+ module: [id: number, factory: Function];
+ match: string | RegExp;
+ replacement: string | ReplaceFn;
+ setReplacementError(error: any): void;
+}
+
+function ReplacementComponent({ module, match, replacement, setReplacementError }: ReplacementComponentProps) {
const [id, fact] = module;
const [compileResult, setCompileResult] = React.useState<[boolean, string]>();
const [patchedCode, matchResult, diff] = React.useMemo(() => {
const src: string = fact.toString().replaceAll("\n", "");
+ const canonicalMatch = canonicalizeMatch(match);
try {
- var patched = src.replace(match, replacement);
+ const canonicalReplace = canonicalizeReplace(replacement, "YourPlugin");
+ var patched = src.replace(canonicalMatch, canonicalReplace as string);
setReplacementError(void 0);
} catch (e) {
setReplacementError((e as Error).message);
return ["", [], []];
}
- const m = src.match(match);
+ const m = src.match(canonicalMatch);
return [patched, m, makeDiff(src, patched, m)];
}, [id, match, replacement]);
@@ -179,9 +189,10 @@ function ReplacementInput({ replacement, setReplacement, replacementError }) {
{Object.entries({
"$$": "Insert a $",
"$&": "Insert the entire match",
- "$`​": "Insert the substring before the match",
+ "$`\u200b": "Insert the substring before the match",
"$'": "Insert the substring after the match",
- "$n": "Insert the nth capturing group ($1, $2...)"
+ "$n": "Insert the nth capturing group ($1, $2...)",
+ "$self": "Insert the plugin instance",
}).map(([placeholder, desc]) => (
<Forms.FormText key={placeholder}>
{Parser.parse("`" + placeholder + "`")}: {desc}
@@ -206,7 +217,7 @@ function ReplacementInput({ replacement, setReplacement, replacementError }) {
function PatchHelper() {
const [find, setFind] = React.useState<string>("");
const [match, setMatch] = React.useState<string>("");
- const [replacement, setReplacement] = React.useState<string | Function>("");
+ const [replacement, setReplacement] = React.useState<string | ReplaceFn>("");
const [replacementError, setReplacementError] = React.useState<string>();
diff --git a/src/plugins/shikiCodeblocks/index.ts b/src/plugins/shikiCodeblocks/index.ts
index fd6b04b..58e0048 100644
--- a/src/plugins/shikiCodeblocks/index.ts
+++ b/src/plugins/shikiCodeblocks/index.ts
@@ -22,7 +22,7 @@ import { wordsFromPascal, wordsToTitle } from "@utils/text";
import definePlugin, { OptionType } from "@utils/types";
import previewExampleText from "~fileContent/previewExample.tsx";
-import cssText from "~fileContent/style.css";
+import cssText from "~fileContent/shiki.css";
import { Settings } from "../../Vencord";
import { shiki } from "./api/shiki";
@@ -44,8 +44,8 @@ export default definePlugin({
{
find: "codeBlock:{react:function",
replacement: {
- match: /codeBlock:\{react:function\((.),(.),(.)\)\{/,
- replace: "$&return Vencord.Plugins.plugins.ShikiCodeblocks.renderHighlighter($1,$2,$3);",
+ match: /codeBlock:\{react:function\((\i),(\i),(\i)\)\{/,
+ replace: "$&return $self.renderHighlighter($1,$2,$3);",
},
},
],
diff --git a/src/plugins/shikiCodeblocks/style.css b/src/plugins/shikiCodeblocks/shiki.css
index b246db4..b871d99 100644
--- a/src/plugins/shikiCodeblocks/style.css
+++ b/src/plugins/shikiCodeblocks/shiki.css
@@ -1,10 +1,13 @@
-.shiki-root {
- border-radius: 4px;
-
+.shiki-container {
+ border: 4px;
/* fallback background */
background-color: var(--background-secondary);
}
+.shiki-root {
+ border-radius: 4px;
+}
+
.shiki-root code {
display: block;
overflow-x: auto;
diff --git a/src/utils/patches.ts b/src/utils/patches.ts
new file mode 100644
index 0000000..8ecd68e
--- /dev/null
+++ b/src/utils/patches.ts
@@ -0,0 +1,55 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 Vendicated and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+import { PatchReplacement } from "./types";
+
+export type ReplaceFn = (match: string, ...groups: string[]) => string;
+
+export function canonicalizeMatch(match: RegExp | string) {
+ if (typeof match === "string") return match;
+ const canonSource = match.source
+ .replaceAll("\\i", "[A-Za-z_$][\\w$]*");
+ return new RegExp(canonSource, match.flags);
+}
+
+export function canonicalizeReplace(replace: string | ReplaceFn, pluginName: string) {
+ if (typeof replace === "function") return replace;
+ return replace.replaceAll("$self", `Vencord.Plugins.plugins.${pluginName}`);
+}
+
+export function canonicalizeDescriptor<T>(descriptor: TypedPropertyDescriptor<T>, canonicalize: (value: T) => T) {
+ if (descriptor.get) {
+ const original = descriptor.get;
+ descriptor.get = function () {
+ return canonicalize(original.call(this));
+ };
+ } else if (descriptor.value) {
+ descriptor.value = canonicalize(descriptor.value);
+ }
+ return descriptor;
+}
+
+export function canonicalizeReplacement(replacement: Pick<PatchReplacement, "match" | "replace">, plugin: string) {
+ const descriptors = Object.getOwnPropertyDescriptors(replacement);
+ descriptors.match = canonicalizeDescriptor(descriptors.match, canonicalizeMatch);
+ descriptors.replace = canonicalizeDescriptor(
+ descriptors.replace,
+ replace => canonicalizeReplace(replace, plugin),
+ );
+ Object.defineProperties(replacement, descriptors);
+}
diff --git a/src/utils/types.ts b/src/utils/types.ts
index fd8f02b..d3083fc 100644
--- a/src/utils/types.ts
+++ b/src/utils/types.ts
@@ -19,6 +19,8 @@
import { Command } from "@api/Commands";
import { Promisable } from "type-fest";
+import type { ReplaceFn } from "./patches";
+
// exists to export default definePlugin({...})
export default function definePlugin<P extends PluginDef>(p: P & Record<string, any>) {
return p;
@@ -26,7 +28,7 @@ export default function definePlugin<P extends PluginDef>(p: P & Record<string,
export interface PatchReplacement {
match: string | RegExp;
- replace: string | ((match: string, ...groups: string[]) => string);
+ replace: string | ReplaceFn;
predicate?(): boolean;
}
diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts
index 8f11b63..7b318b2 100644
--- a/src/webpack/patchWebpack.ts
+++ b/src/webpack/patchWebpack.ts
@@ -18,6 +18,8 @@
import { WEBPACK_CHUNK } from "@utils/constants";
import Logger from "@utils/Logger";
+import { canonicalizeReplacement } from "@utils/patches";
+import { PatchReplacement } from "@utils/types";
import { _initWebpack } from ".";
@@ -135,15 +137,17 @@ function patchPush() {
if (code.includes(patch.find)) {
patchedBy.add(patch.plugin);
- // @ts-ignore we change all patch.replacement to array in plugins/index
- for (const replacement of patch.replacement) {
+ // we change all patch.replacement to array in plugins/index
+ for (const replacement of patch.replacement as PatchReplacement[]) {
if (replacement.predicate && !replacement.predicate()) continue;
const lastMod = mod;
const lastCode = code;
+ canonicalizeReplacement(replacement, patch.plugin);
+
try {
- const newCode = code.replace(replacement.match, replacement.replace);
- if (newCode === code && !replacement.noWarn) {
+ const newCode = code.replace(replacement.match, replacement.replace as string);
+ if (newCode === code && !patch.noWarn) {
logger.warn(`Patch by ${patch.plugin} had no effect (Module id is ${id}): ${replacement.match}`);
if (IS_DEV) {
logger.debug("Function Source:\n", code);