Ver Fonte

ref: more post-build stuff

Sv443 há 1 semana atrás
pai
commit
44faae0f3d
1 ficheiros alterados com 148 adições e 135 exclusões
  1. 148 135
      src/tools/post-build.ts

+ 148 - 135
src/tools/post-build.ts

@@ -60,7 +60,13 @@ const genMeta = getCliArg<CliArg<"config-gen-meta">>("meta", "true") === "true";
 const envPort = Number(env.DEV_SERVER_PORT);
 /** HTTP port of the dev server */
 const devServerPort = isNaN(envPort) || envPort === 0 ? 8710 : envPort;
+/** Local URL of the userscript file when served by the dev server */
 const devServerUserscriptUrl = `http://localhost:${devServerPort}/${rollupCfgOutputFile}` as const;
+/** Extra `@grant` directives added when `mode` is `development` */
+const devGrants = [
+  "GM.registerMenuCommand",
+  "GM.listValues"
+] as const;
 
 const repo = "Sv443/BetterYTM" as const;
 const userscriptDistFile = `BetterYTM${suffix}.user.js` as const;
@@ -84,72 +90,16 @@ const ringBell = Boolean(env.RING_BELL && (env.RING_BELL.length > 0 && env.RING_
 /** Directives that are only added in dev mode */
 const devDirectives = mode !== "development"
   ? undefined
-  : `// @grant             GM.registerMenuCommand
-// @grant             GM.listValues` as const;
+  : devGrants.reduce((a, c) => `${a}// @grant             ${c}\n`, "");
 
 //#region main
 
+/** Main function that transforms the code built by rollup into the final userscript */
 async function main() {
   const buildNbr = await getLastCommitSha();
 
-  const resourcesDirectives = await getResourceDirectives(buildNbr);
-  const requireDirectives = await getRequireDirectives();
-  const localizedDescriptions = getLocalizedDescriptions();
-
-  const header = `\
-// ==UserScript==
-// @name              ${pkg.userscriptName}
-// @namespace         ${pkg.homepage}
-// @version           ${pkg.version}
-// @description       ${pkg.description}
-// @homepageURL       ${pkg.homepage}#readme
-// @supportURL        ${pkg.bugs.url}
-// @license           ${pkg.license}
-// @author            ${pkg.author.name}
-// @copyright         ${pkg.author.name} (${pkg.author.url})
-// @icon              ${getResourceUrl(`images/logo/logo${mode === "development" ? "_dev" : ""}_48.png`, buildNbr)}
-// @match             https://music.youtube.com/*
-// @match             https://www.youtube.com/*
-// @run-at            document-start\
-${localizedDescriptions ? "\n" + localizedDescriptions : ""}\
-// @connect           api.sv443.net
-// @connect           github.com
-// @connect           raw.githubusercontent.com
-// @connect           youtube.com
-// @connect           returnyoutubedislikeapi.com
-// @noframes
-// @updateURL         ${hostMetaUrl}
-// @downloadURL       ${hostScriptUrl}
-// @grant             GM.getValue
-// @grant             GM.setValue
-// @grant             GM.deleteValue
-// @grant             GM.getResourceUrl
-// @grant             GM.setClipboard
-// @grant             GM.xmlHttpRequest
-// @grant             GM.openInTab
-// @grant             unsafeWindow\
-${resourcesDirectives ? "\n" + resourcesDirectives : ""}\
-${requireDirectives ? "\n" + requireDirectives : ""}\
-${devDirectives ? "\n" + devDirectives : ""}
-// ==/UserScript==
-/*
-▄▄▄      ▄   ▄         ▄   ▄▄▄▄▄▄   ▄
-█  █ ▄▄▄ █   █   ▄█▄ ▄ ▄█ █  █  █▀▄▀█
-█▀▀▄ █▄█ █▀  █▀  █▄█ █▀  █   █  █   █
-█▄▄▀ ▀▄▄ ▀▄▄ ▀▄▄ ▀▄▄ █   █   █  █   █
-
-        Made with ❤️ by Sv443
-I welcome every contribution on GitHub!
-  https://github.com/Sv443/BetterYTM
-*/
-` as const;
-
-  const footer = `
-/* Disclaimer: I am not affiliated with or endorsed by YouTube, Google, Alphabet, Genius or anyone else */
-/* C&D this 🖕 */
-` as const;
-
   try {
+    const [header, subHeader] = await getHeaders(buildNbr);
     const rootPath = join(dirname(fileURLToPath(import.meta.url)), "../../");
 
     const scriptPath = join(rootPath, distFolderPath, userscriptDistFile);
@@ -173,7 +123,7 @@ I welcome every contribution on GitHub!
       userscript = userscript.replace(/sourceMappingURL=/gm, `sourceMappingURL=http://localhost:${devServerPort}/`);
 
     // insert userscript header and final newline
-    const finalUserscript = `${header}${footer}\n${await getLinkedPkgs()}${userscript}${userscript.endsWith("\n") ? "" : "\n"}`;
+    const finalUserscript = `${header}${subHeader}\n${await getLinkedPkgs()}${userscript}${userscript.endsWith("\n") ? "" : "\n"}`;
 
     // write userscript
     await writeFile(scriptPath, finalUserscript);
@@ -238,25 +188,7 @@ I welcome every contribution on GitHub!
   }
 };
 
-//#region process
-
-/** Returns the value of a CLI argument (in the format `--arg=<value>`) or the value of `defaultVal` if it doesn't exist */
-function getCliArg<TReturn extends string = string>(name: string, defaultVal: TReturn | (string & {})): TReturn
-/** Returns the value of a CLI argument (in the format `--arg=<value>`) or undefined if it doesn't exist */
-function getCliArg<TReturn extends string = string>(name: string, defaultVal?: TReturn | (string & {})): TReturn | undefined
-/** Returns the value of a CLI argument (in the format `--arg=<value>`) or the value of `defaultVal` if it doesn't exist */
-function getCliArg<TReturn extends string = string>(name: string, defaultVal?: TReturn | (string & {})): TReturn | undefined {
-  const arg = argv.find((v) => v.trim().match(new RegExp(`^(--)?${name}=.+$`, "i")));
-  const val = arg?.split("=")?.[1];
-  return (val && val.length > 0 ? val : defaultVal)?.trim() as TReturn | undefined;
-}
-
-/** Schedules an exit after I/O events finish */
-function schedExit(code: number) {
-  setImmediate(() => exit(code));
-}
-
-//#region modify userscript
+//#region string replacements
 
 /** Replaces tokens in the format `#{{key}}` or `/⋆#{{key}}⋆/` of the `replacements` param with their respective value */
 function insertValues(userscript: string, replacements: Record<string, Stringifiable>) {
@@ -271,63 +203,67 @@ function removeSourcemapComments(userscript: string) {
     .replace(/\/\/\s?#\s?sourceMappingURL\s?=\s?.+$/gm, "");
 }
 
-//#region git
+//#region headers
 
-/**
- * Used as a kind of "build number", though note it is always behind by at least one commit,
- * as the act of putting this number in the userscript and committing it changes the hash again, indefinitely
- */
-function getLastCommitSha() {
-  return new Promise<string>((res, rej) => {
-    exec("git rev-parse --short HEAD", (err, stdout, stderr) => {
-      if(err) {
-        console.error(k.red("Error while checking for last Git commit. Do you have Git installed?\n"), stderr);
-        return rej(err);
-      }
-      return res(String(stdout).replace(/\r?\n/gm, "").trim());
-    });
-  });
-}
-
-//#region fs
-
-/** Checks if the given path exists and is readable and writable by the process */
-async function exists(path: string) {
-  try {
-    await access(path, fsconst.R_OK | fsconst.W_OK);
-    return true;
-  }
-  catch {
-    return false;
-  }
-}
+/** Returns the header and subheader for the userscript */
+async function getHeaders(buildNbr: string) {
+  const resourcesDirectives = await getResourceDirectives(buildNbr);
+  const requireDirectives = await getRequireDirectives();
+  const localizedDescriptions = getLocalizedDescriptions();
 
-/**
- * Calculates the SHA-256 hash of the file at the given path.  
- * Uses {@linkcode resolveResourcePath()} to resolve the path, meaning paths prefixed with a slash are relative to the repository root, otherwise they are relative to the `assets` directory.
- */
-function getFileHashSha256(path: string): Promise<string> {
-  path = resolveResourcePath(path);
+  const header = `\
+// ==UserScript==
+// @name              ${pkg.userscriptName}
+// @namespace         ${pkg.homepage}
+// @version           ${pkg.version}
+// @description       ${pkg.description}
+// @homepageURL       ${pkg.homepage}#readme
+// @supportURL        ${pkg.bugs.url}
+// @license           ${pkg.license}
+// @author            ${pkg.author.name}
+// @copyright         ${pkg.author.name} (${pkg.author.url})
+// @icon              ${getResourceUrl(`images/logo/logo${mode === "development" ? "_dev" : ""}_48.png`, buildNbr)}
+// @match             https://music.youtube.com/*
+// @match             https://www.youtube.com/*
+// @run-at            document-start\
+${localizedDescriptions ? "\n" + localizedDescriptions : ""}\
+// @connect           api.sv443.net
+// @connect           github.com
+// @connect           raw.githubusercontent.com
+// @connect           youtube.com
+// @connect           returnyoutubedislikeapi.com
+// @noframes
+// @updateURL         ${hostMetaUrl}
+// @downloadURL       ${hostScriptUrl}
+// @grant             GM.getValue
+// @grant             GM.setValue
+// @grant             GM.deleteValue
+// @grant             GM.getResourceUrl
+// @grant             GM.setClipboard
+// @grant             GM.xmlHttpRequest
+// @grant             GM.openInTab
+// @grant             unsafeWindow\
+${resourcesDirectives ? "\n" + resourcesDirectives : ""}\
+${requireDirectives ? "\n" + requireDirectives : ""}\
+${devDirectives ? "\n" + devDirectives : ""}
+// ==/UserScript==
+/*
+▄▄▄      ▄   ▄         ▄   ▄▄▄▄▄▄   ▄
+█  █ ▄▄▄ █   █   ▄█▄ ▄ ▄█ █  █  █▀▄▀█
+█▀▀▄ █▄█ █▀  █▀  █▄█ █▀  █   █  █   █
+█▄▄▀ ▀▄▄ ▀▄▄ ▀▄▄ ▀▄▄ █   █   █  █   █
 
-  return new Promise((res, rej) => {
-    const hash = createHash("sha256");
-    const stream = createReadStream(resolve(path));
-    stream.on("data", data => hash.update(data));
-    stream.on("end", () => res(hash.digest("base64")));
-    stream.on("error", rej);
-  });
-}
+        Made with ❤️ by Sv443
+I welcome every contribution on GitHub!
+  https://github.com/Sv443/BetterYTM
+*/
+` as const;
 
-/** Calculates the SHA-256 hash of a ReadableStream, like the `body` prop of a `fetch()` call */
-function getStreamHashSha256(rStream: ReadableStream): Promise<string> {
-  return new Promise((res, rej) => {
-    const hash = createHash("sha256");
-    rStream.pipeTo(new WritableStream({
-      write(chunk) {
-        hash.update(chunk);
-      },
-    })).then(() => res(hash.digest("base64"))).catch(rej);
-  });
+  const subHeader = `
+/* Disclaimer: I am not affiliated with or endorsed by YouTube, Google, Alphabet, Genius or anyone else */
+/* C&D this 🖕 */
+` as const;
+  return [header, subHeader];
 }
 
 //#region @resource
@@ -430,7 +366,7 @@ async function getResourceDirectives(ref: string) {
   }
 }
 
-//#region svg spritesheet
+//#region @resource SVG spritesheet
 
 /** Compiles all `icon-*` assets into a single SVG spritesheet file and writes it to `assets/spritesheet.svg` */
 async function createSvgSpritesheet() {
@@ -496,7 +432,7 @@ function getRequireEntry(entry: RequireObjPkg) {
   return `// @require           ${baseUrl}${entry.pkgName}@${version}${entry.path ? `${entry.path.startsWith("/") ? "" : "/"}${entry.path}` : ""}`;
 }
 
-//#region locally linked packages
+//#region @require (local link)
 
 /** Returns all packages set as locally linked (similar to [`npm link`](https://docs.npmjs.com/cli/v9/commands/npm-link)) in `assets/require.json` */
 async function getLinkedPkgs() {
@@ -584,7 +520,84 @@ function resolveResourcePath(path: string): string {
   return `assets/${path}`;
 }
 
-//#region misc
+//#region utils/process
+
+/** Returns the value of a CLI argument (in the format `--arg=<value>`) or the value of `defaultVal` if it doesn't exist */
+function getCliArg<TReturn extends string = string>(name: string, defaultVal: TReturn | (string & {})): TReturn
+/** Returns the value of a CLI argument (in the format `--arg=<value>`) or undefined if it doesn't exist */
+function getCliArg<TReturn extends string = string>(name: string, defaultVal?: TReturn | (string & {})): TReturn | undefined
+/** Returns the value of a CLI argument (in the format `--arg=<value>`) or the value of `defaultVal` if it doesn't exist */
+function getCliArg<TReturn extends string = string>(name: string, defaultVal?: TReturn | (string & {})): TReturn | undefined {
+  const arg = argv.find((v) => v.trim().match(new RegExp(`^(--)?${name}=.+$`, "i")));
+  const val = arg?.split("=")?.[1];
+  return (val && val.length > 0 ? val : defaultVal)?.trim() as TReturn | undefined;
+}
+
+/** Schedules an exit after I/O events finish */
+function schedExit(code: number) {
+  setImmediate(() => exit(code));
+}
+
+//#region utils/git
+
+/**
+ * Used as a kind of "build number", though note it is always behind by at least one commit,
+ * as the act of putting this number in the userscript and committing it changes the hash again, indefinitely
+ */
+function getLastCommitSha() {
+  return new Promise<string>((res, rej) => {
+    exec("git rev-parse --short HEAD", (err, stdout, stderr) => {
+      if(err) {
+        console.error(k.red("\nError while checking for latest Git commit.\nPlease ensure you have Git installed and set up properly.\n"), stderr);
+        return rej(err);
+      }
+      return res(String(stdout).replace(/\r?\n/gm, "").trim());
+    });
+  });
+}
+
+//#region utils/fs
+
+/** Checks if the given path exists and is readable and writable by the process */
+async function exists(path: string) {
+  try {
+    await access(path, fsconst.R_OK | fsconst.W_OK);
+    return true;
+  }
+  catch {
+    return false;
+  }
+}
+
+/**
+ * Calculates the SHA-256 hash of the file at the given path.  
+ * Uses {@linkcode resolveResourcePath()} to resolve the path, meaning paths prefixed with a slash are relative to the repository root, otherwise they are relative to the `assets` directory.
+ */
+function getFileHashSha256(path: string): Promise<string> {
+  path = resolveResourcePath(path);
+
+  return new Promise((res, rej) => {
+    const hash = createHash("sha256");
+    const stream = createReadStream(resolve(path));
+    stream.on("data", data => hash.update(data));
+    stream.on("end", () => res(hash.digest("base64")));
+    stream.on("error", rej);
+  });
+}
+
+/** Calculates the SHA-256 hash of a ReadableStream, like the `body` prop of a `fetch()` call */
+function getStreamHashSha256(rStream: ReadableStream): Promise<string> {
+  return new Promise((res, rej) => {
+    const hash = createHash("sha256");
+    rStream.pipeTo(new WritableStream({
+      write(chunk) {
+        hash.update(chunk);
+      },
+    })).then(() => res(hash.digest("base64"))).catch(rej);
+  });
+}
+
+//#region utils/misc
 
 /** Generates a random ID of the given {@linkcode length} and {@linkcode radix} */
 function randomId(length = 16, radix = 16, randomCase = true) {