Bundle dependencies with extensions for webstore rule compliance (#1740)

This commit is contained in:
V 2023-09-19 04:07:24 +02:00
parent efb88a4df8
commit 41f5d71e38
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
46 changed files with 1633 additions and 73 deletions

View file

@ -0,0 +1,74 @@
/*
* 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 { ILanguageRegistration } from "@vap/shiki";
export const VPC_REPO = "Vap0r1ze/vapcord";
export const VPC_REPO_COMMIT = "88a7032a59cca40da170926651b08201ea3b965a";
export const vpcRepoAssets = `https://raw.githubusercontent.com/${VPC_REPO}/${VPC_REPO_COMMIT}/assets/shiki-codeblocks`;
export const vpcRepoGrammar = (fileName: string) => `${vpcRepoAssets}/${fileName}`;
export const vpcRepoLanguages = `${vpcRepoAssets}/languages.json`;
export interface Language {
name: string;
id: string;
devicon?: string;
grammarUrl: string,
grammar?: ILanguageRegistration["grammar"];
scopeName: string;
aliases?: string[];
custom?: boolean;
}
export interface LanguageJson {
name: string;
id: string;
fileName: string;
devicon?: string;
scopeName: string;
aliases?: string[];
}
export const languages: Record<string, Language> = {};
export const loadLanguages = async () => {
const langsJson: LanguageJson[] = await fetch(vpcRepoLanguages).then(res => res.json());
const loadedLanguages = Object.fromEntries(
langsJson.map(lang => [lang.id, {
...lang,
grammarUrl: vpcRepoGrammar(lang.fileName),
}])
);
Object.assign(languages, loadedLanguages);
};
export const getGrammar = (lang: Language): Promise<NonNullable<ILanguageRegistration["grammar"]>> => {
if (lang.grammar) return Promise.resolve(lang.grammar);
return fetch(lang.grammarUrl).then(res => res.json());
};
const aliasCache = new Map<string, Language>();
export function resolveLang(idOrAlias: string) {
if (Object.prototype.hasOwnProperty.call(languages, idOrAlias)) return languages[idOrAlias];
const lang = Object.values(languages).find(lang => lang.aliases?.includes(idOrAlias));
if (!lang) return null;
aliasCache.set(idOrAlias, lang);
return lang;
}

View file

@ -0,0 +1,118 @@
/*
* 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 { shikiOnigasmSrc, shikiWorkerSrc } from "@utils/dependencies";
import { WorkerClient } from "@vap/core/ipc";
import type { IShikiTheme, IThemedToken } from "@vap/shiki";
import { dispatchTheme } from "../hooks/useTheme";
import type { ShikiSpec } from "../types";
import { getGrammar, languages, loadLanguages, resolveLang } from "./languages";
import { themes } from "./themes";
const themeUrls = Object.values(themes);
let resolveClient: (client: WorkerClient<ShikiSpec>) => void;
export const shiki = {
client: null as WorkerClient<ShikiSpec> | null,
currentTheme: null as IShikiTheme | null,
currentThemeUrl: null as string | null,
timeoutMs: 10000,
languages,
themes,
loadedThemes: new Set<string>(),
loadedLangs: new Set<string>(),
clientPromise: new Promise<WorkerClient<ShikiSpec>>(resolve => resolveClient = resolve),
init: async (initThemeUrl: string | undefined) => {
/** https://stackoverflow.com/q/58098143 */
const workerBlob = await fetch(shikiWorkerSrc).then(res => res.blob());
const client = shiki.client = new WorkerClient<ShikiSpec>(
"shiki-client",
"shiki-host",
workerBlob,
{ name: "ShikiWorker" },
);
await client.init();
const themeUrl = initThemeUrl || themeUrls[0];
await loadLanguages();
await client.run("setOnigasm", { wasm: shikiOnigasmSrc });
await client.run("setHighlighter", { theme: themeUrl, langs: [] });
shiki.loadedThemes.add(themeUrl);
await shiki._setTheme(themeUrl);
resolveClient(client);
},
_setTheme: async (themeUrl: string) => {
shiki.currentThemeUrl = themeUrl;
const { themeData } = await shiki.client!.run("getTheme", { theme: themeUrl });
shiki.currentTheme = JSON.parse(themeData);
dispatchTheme({ id: themeUrl, theme: shiki.currentTheme });
},
loadTheme: async (themeUrl: string) => {
const client = await shiki.clientPromise;
if (shiki.loadedThemes.has(themeUrl)) return;
await client.run("loadTheme", { theme: themeUrl });
shiki.loadedThemes.add(themeUrl);
},
setTheme: async (themeUrl: string) => {
await shiki.clientPromise;
themeUrl ||= themeUrls[0];
if (!shiki.loadedThemes.has(themeUrl)) await shiki.loadTheme(themeUrl);
await shiki._setTheme(themeUrl);
},
loadLang: async (langId: string) => {
const client = await shiki.clientPromise;
const lang = resolveLang(langId);
if (!lang || shiki.loadedLangs.has(lang.id)) return;
await client.run("loadLanguage", {
lang: {
...lang,
grammar: lang.grammar ?? await getGrammar(lang),
}
});
shiki.loadedLangs.add(lang.id);
},
tokenizeCode: async (code: string, langId: string): Promise<IThemedToken[][]> => {
const client = await shiki.clientPromise;
const lang = resolveLang(langId);
if (!lang) return [];
if (!shiki.loadedLangs.has(lang.id)) await shiki.loadLang(lang.id);
return await client.run("codeToThemedTokens", {
code,
lang: langId,
theme: shiki.currentThemeUrl ?? themeUrls[0],
});
},
destroy() {
shiki.currentTheme = null;
shiki.currentThemeUrl = null;
dispatchTheme({ id: null, theme: null });
shiki.client?.destroy();
}
};

View file

@ -0,0 +1,67 @@
/*
* 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 { IShikiTheme } from "@vap/shiki";
export const SHIKI_REPO = "shikijs/shiki";
export const SHIKI_REPO_COMMIT = "0b28ad8ccfbf2615f2d9d38ea8255416b8ac3043";
export const shikiRepoTheme = (name: string) => `https://raw.githubusercontent.com/${SHIKI_REPO}/${SHIKI_REPO_COMMIT}/packages/shiki/themes/${name}.json`;
export const themes = {
// Default
DarkPlus: shikiRepoTheme("dark-plus"),
// Dev Choices
MaterialCandy: "https://raw.githubusercontent.com/millsp/material-candy/master/material-candy.json",
// More from Shiki repo
DraculaSoft: shikiRepoTheme("dracula-soft"),
Dracula: shikiRepoTheme("dracula"),
GithubDarkDimmed: shikiRepoTheme("github-dark-dimmed"),
GithubDark: shikiRepoTheme("github-dark"),
GithubLight: shikiRepoTheme("github-light"),
LightPlus: shikiRepoTheme("light-plus"),
MaterialDarker: shikiRepoTheme("material-darker"),
MaterialDefault: shikiRepoTheme("material-default"),
MaterialLighter: shikiRepoTheme("material-lighter"),
MaterialOcean: shikiRepoTheme("material-ocean"),
MaterialPalenight: shikiRepoTheme("material-palenight"),
MinDark: shikiRepoTheme("min-dark"),
MinLight: shikiRepoTheme("min-light"),
Monokai: shikiRepoTheme("monokai"),
Nord: shikiRepoTheme("nord"),
OneDarkPro: shikiRepoTheme("one-dark-pro"),
Poimandres: shikiRepoTheme("poimandres"),
RosePineDawn: shikiRepoTheme("rose-pine-dawn"),
RosePineMoon: shikiRepoTheme("rose-pine-moon"),
RosePine: shikiRepoTheme("rose-pine"),
SlackDark: shikiRepoTheme("slack-dark"),
SlackOchin: shikiRepoTheme("slack-ochin"),
SolarizedDark: shikiRepoTheme("solarized-dark"),
SolarizedLight: shikiRepoTheme("solarized-light"),
VitesseDark: shikiRepoTheme("vitesse-dark"),
VitesseLight: shikiRepoTheme("vitesse-light"),
CssVariables: shikiRepoTheme("css-variables"),
};
export const themeCache = new Map<string, IShikiTheme>();
export const getTheme = (url: string): Promise<IShikiTheme> => {
if (themeCache.has(url)) return Promise.resolve(themeCache.get(url)!);
return fetch(url).then(res => res.json());
};