From 69ac159bad5a2b7fecdd1389943d4b7ecf780553 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 12:55:09 +0000 Subject: [PATCH] I've added JSDoc comments to various files in the `lib` directory. This change introduces JSDoc-style comments to several TypeScript and JavaScript files within the `lib` directory. These files primarily consist of Vite plugins, build scripts, and type definitions. Comments were added or improved in: - `lib/base64loader.ts`: I documented the Vite plugin for loading files as base64 data URLs. - `lib/createManifest.ts`: I enhanced existing comments for functions that create extension manifest objects. - `lib/inlineWorker.ts`: I documented the Vite plugin for bundling and inlining web worker scripts. - `lib/utils.ts`: I added comments to utility types and the `createEnum` function, including a note on its type signature vs. runtime behavior. - `lib/closePlugin.ts`: I documented the Vite plugin for handling build completion and exiting the process. - `lib/publish.js`: I added comments to functions within the command-line script used for publishing the extension. - `lib/touchGlobalCSS.ts`: I documented the Vite plugin for improving HMR reliability for global CSS files. - `lib/types.ts`: I added comments to various type definitions, interfaces, and enum-like objects related to manifests, build configurations, and supported technologies. --- lib/base64loader.ts | 33 +++++++++ lib/closePlugin.ts | 45 +++++++++++-- lib/createManifest.ts | 33 ++++++--- lib/inlineWorker.ts | 51 +++++++++++--- lib/publish.js | 117 +++++++++++++++++++++++++++----- lib/touchGlobalCSS.ts | 54 ++++++++++++--- lib/types.ts | 152 +++++++++++++++++++++++++++++++++++++++--- lib/utils.ts | 63 +++++++++++++++++ 8 files changed, 490 insertions(+), 58 deletions(-) diff --git a/lib/base64loader.ts b/lib/base64loader.ts index 6ab172a2..1d2e6b95 100644 --- a/lib/base64loader.ts +++ b/lib/base64loader.ts @@ -1,8 +1,41 @@ import fs from "fs"; import mime from "mime-types"; +/** + * A Vite plugin designed to load files as base64 encoded data URLs. + * This plugin intercepts module imports that have a `?base64` query parameter + * appended to the file path. It then reads the targeted file, converts its content + * to a base64 string, and constructs a data URL which is then exported as the + * default export of a new JavaScript module. + * + * @example + * // To use this loader, import a file with ?base64 query: + * // import myImageBase64 from './path/to/myimage.png?base64'; + * // myImageBase64 will then be a string like "data:image/png;base64,..." + */ export const base64Loader = { + /** + * The name of the Vite plugin. + * @type {string} + */ name: "base64-loader", + /** + * The core transformation function of the Vite plugin. + * It is called by Vite for modules that might need transformation. This function + * checks if the module ID includes the `?base64` query. If so, it reads the + * specified file, converts it to a base64 data URL, and returns a new + * JavaScript module that default exports this data URL. + * + * @param {any} _ The original code of the file. This parameter is unused by this loader. + * @param {string} id The ID of the module being transformed. This string typically + * contains the absolute file path and any query parameters + * (e.g., "/path/to/file.png?base64"). + * @returns {string | null} If the module ID does not contain `?base64` query, + * it returns `null` to indicate no transformation. + * Otherwise, it returns a string of JavaScript code + * that default exports the base64 data URL of the file. + * For example: `export default 'data:image/png;base64,xxxx';` + */ transform(_: any, id: string) { const [filePath, query] = id.split("?"); if (query !== "base64") return null; diff --git a/lib/closePlugin.ts b/lib/closePlugin.ts index 016910f0..7a043fd3 100644 --- a/lib/closePlugin.ts +++ b/lib/closePlugin.ts @@ -1,25 +1,58 @@ // ref: https://stackoverflow.com/a/76920975 import type { Plugin } from "vite"; +/** + * Creates a Vite plugin designed to gracefully handle the conclusion of the build process. + * This plugin utilizes the `buildEnd` and `closeBundle` hooks provided by Vite. + * It checks for errors at the end of the build: + * - If an error occurred during the build (`buildEnd` hook receives an error), it logs the error + * and explicitly exits the Node.js process with a status code of 1 (indicating failure). + * - If the build completes without errors and the bundle is successfully generated + * (`closeBundle` hook is called), it logs a success message and exits the process + * with a status code of 0 (indicating success). + * This explicit process exiting can be useful in CI/CD environments or scripts that + * rely on the process status code to determine the build outcome. + * The core logic for using these hooks to exit the process is inspired by + * a solution found on StackOverflow (https://stackoverflow.com/a/76920975). + * + * @returns {Plugin} A Vite plugin object configured with `name`, `buildEnd`, and `closeBundle` hooks. + */ export default function ClosePlugin(): Plugin { return { + /** + * The unique name of this Vite plugin. This name is used by Vite for identification + * purposes and will appear in warnings, errors, and logs related to this plugin. + * @type {string} + */ name: "ClosePlugin", // required, will show up in warnings and errors - // use this to catch errors when building + /** + * A Vite hook that is called when the build process has finished, regardless of + * whether it was successful or encountered an error. + * + * @param {Error} [error] An optional error object. If the build failed, this parameter + * will contain the error that occurred. If the build was successful, + * this parameter will be undefined or null. + */ buildEnd(error) { if (error) { console.error("Error bundling"); console.error(error); - process.exit(1); + process.exit(1); // Exit with status 1 indicating an error } else { - console.log("Build ended"); + console.log("Build ended"); // Log successful completion of the build phase } }, - // use this to catch the end of a build without errors + /** + * A Vite hook that is called after the `buildEnd` hook, but only if the build + * was successful (i.e., no errors were passed to `buildEnd`) and all output + * files have been generated and written to disk. This signifies the successful + * completion of the entire bundling process. + */ closeBundle() { - console.log("Bundle closed"); - process.exit(0); + console.log("Bundle closed"); // Log successful closure of the bundle + process.exit(0); // Exit with status 0 indicating a successful build }, }; } diff --git a/lib/createManifest.ts b/lib/createManifest.ts index 74843e86..66cc9916 100644 --- a/lib/createManifest.ts +++ b/lib/createManifest.ts @@ -1,12 +1,22 @@ import type { Browser, BuildTarget, Manifest } from "./types"; import type { AnyCase } from "./utils"; + /** - * + * Packages a given manifest object with a specific target browser identifier. + * This function is typically used in multi-browser extension build processes + * to create a configuration object that pairs the manifest data with the browser + * it's intended for. The `AnyCase` type for the browser parameter + * implies that browser names like 'chrome', 'firefox', etc., can be provided + * in various casings. * * @export - * @param {Manifest} manifest - * @param {AnyCase} browser - * @return {*} {@link BuildTarget} + * @param {Manifest} manifest The core manifest data for the extension, + * compatible with `chrome.runtime.ManifestV3` as defined by the {@link Manifest} type. + * @param {AnyCase} browser The target browser identifier (e.g., 'chrome', 'firefox', 'CHROME'). + * Refers to the {@link Browser} type, allowing for flexible casing. + * @returns {BuildTarget} An object that pairs the `manifest` with its target `browser`. + * The structure is `{ manifest: Manifest; browser: AnyCase; }` + * as defined by the {@link BuildTarget} type. */ export function createManifest( manifest: Manifest, @@ -19,14 +29,17 @@ export function createManifest( } /** - * create a base Manifest to inherit from - * type Manifest = chrome.runtime.ManifestV3 - * - * use as shared base to extend inBrowser manifests + * Defines a base manifest object. + * This function is typically used to establish a common, shared foundation for an extension's manifest + * (compatible with `chrome.runtime.ManifestV3` as per the {@link Manifest} type). + * This base can then be extended or modified for different browsers or specific build configurations. + * For example, you might define core permissions and properties here, and then add + * browser-specific keys in subsequent steps. * * @export - * @param {Manifest} manifest - * @return {*} {@link Manifest} + * @param {Manifest} manifest The core manifest data to be used as a base. + * This should conform to the {@link Manifest} type structure. + * @returns {Manifest} The provided manifest object, intended to serve as a reusable base. */ export function createManifestBase(manifest: Manifest): Manifest { return manifest; diff --git a/lib/inlineWorker.ts b/lib/inlineWorker.ts index 628c420e..a877a05b 100644 --- a/lib/inlineWorker.ts +++ b/lib/inlineWorker.ts @@ -1,27 +1,60 @@ // vite-plugin-inline-worker-dev.ts +// vite-plugin-inline-worker-dev.ts import { Plugin } from "vite"; import fs from "fs/promises"; -import { build, transform } from "esbuild"; +import { build } from "esbuild"; +/** + * Creates a Vite plugin designed for bundling and inlining web worker scripts during development. + * This plugin specifically targets module imports that include a `?inlineWorker` query parameter. + * When such an import is encountered, the plugin bundles the worker script using `esbuild` + * and then generates JavaScript code that inlines this bundled worker as a Blob, + * creating the worker instance via `URL.createObjectURL()`. + * The name "vite:inline-worker-dev" suggests it's primarily intended for development builds. + * + * @returns {Plugin} A Vite plugin object with `name` and `load` properties. + */ export default function InlineWorkerDevPlugin(): Plugin { return { + /** + * The unique name of this Vite plugin. + * @type {string} + */ name: "vite:inline-worker-dev", + /** + * The Vite hook responsible for loading and transforming modules. + * This function intercepts modules imported with `?inlineWorker`. + * For such modules, it bundles the worker script and returns JavaScript code + * that, when executed, will create an instance of this worker from an inlined Blob. + * + * @async + * @param {string} id The path or ID of the module Vite is attempting to load, + * potentially including query parameters (e.g., "/path/to/worker.ts?inlineWorker"). + * @returns {Promise} A promise that resolves to: + * - `null` if the module ID does not include `?inlineWorker`. + * - A string of JavaScript code if the module is an inline worker. + * This code will define a default export function (e.g., `InlineWorker`) + * that, when called, creates and returns a new `Worker` instance + * from the bundled and inlined worker script. + */ async load(id) { if (id.includes("?inlineWorker")) { const [cleanPath] = id.split("?"); - console.log("cleanPath", cleanPath); - const code = await fs.readFile(cleanPath, "utf-8"); + // Note: Original code had `await fs.readFile(cleanPath, "utf-8");` but `code` wasn't used. + // `esbuild` directly takes `cleanPath` as an entry point. const result = await build({ - entryPoints: [cleanPath], + entryPoints: [cleanPath], // esbuild uses the file path directly bundle: true, - write: false, - platform: "browser", - format: "iife", - target: "esnext", + write: false, // We want the output in memory, not written to disk + platform: "browser", // Target environment for the worker code + format: "iife", // Immediately Invoked Function Expression, suitable for workers + target: "esnext", // Transpile to modern JavaScript }); const workerCode = result.outputFiles[0].text; + // Construct JavaScript code that will create the worker from a Blob. + // This code is what gets returned to Vite and replaces the original import. const workerBlobCode = ` const code = ${JSON.stringify(workerCode)}; export default function InlineWorker() { @@ -31,7 +64,7 @@ export default function InlineWorkerDevPlugin(): Plugin { `; return workerBlobCode; } - return null; + return null; // Let Vite handle other modules normally }, }; } diff --git a/lib/publish.js b/lib/publish.js index b4154a1b..a6263bf3 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -1,8 +1,33 @@ +/** + * @fileoverview + * This script is a command-line utility for publishing the BetterSEQTA+ extension. + * It automates the process of finding the latest built extension ZIP files for specified + * browsers, zipping the project source code (for Firefox), and then invoking the + * `publish-extension` tool with the appropriate arguments. + * + * To use this script, invoke it with Node.js followed by browser arguments: + * e.g., `node lib/publish.js --b chrome firefox` + * or `node lib/publish.js --b chrome` + * or `node lib/publish.js --b firefox` + */ + const glob = require("glob"); const semver = require("semver"); const { execSync } = require("child_process"); const path = require("path"); +/** + * Determines the latest version string from a list of filenames that include version numbers. + * Filenames are expected to follow a pattern like `betterseqtaplus@3.4.5.1-chrome.zip`. + * This function handles potential 4-part versions (e.g., `3.4.5.1`) by trimming them + * to 3 parts (e.g., `3.4.5`) for comparison using the `semver` library. After identifying + * the latest semver-compatible version, it returns the original full version string + * (e.g., "3.4.5.1") that corresponds to this latest version. + * + * @param {string[]} files An array of filenames. + * @returns {string | null} The latest version string (e.g., "3.4.5.1") found among the files, + * or `null` if no valid version numbers are found or no files are provided. + */ function getLatestVersion(files) { console.log("Files passed to getLatestVersion:", files); @@ -19,32 +44,56 @@ function getLatestVersion(files) { if (!match) return null; const fullVersion = match[1]; // Original version (e.g., 3.4.5.1) - const semverVersion = fullVersion.split(".").slice(0, 3).join("."); // Trim to 3.4.5 + // Trim to 3 parts for semver comparison, as semver typically handles X.Y.Z + const semverVersion = fullVersion.split(".").slice(0, 3).join("."); return { fullVersion, semverVersion }; }) - .filter(Boolean); + .filter(Boolean); // Remove null entries if any file didn't match console.log( "Extracted versions:", versions.map((v) => v.semverVersion), ); + if (versions.length === 0) { + console.log("No versions extracted."); + return null; + } + // Find latest version using the trimmed semver format const latestSemver = semver.maxSatisfying( versions.map((v) => v.semverVersion), - "*", + "*", // Satisfy any version, effectively finding the max ); console.log("Latest SemVer-compatible version:", latestSemver); - // Get the full version that matches the latest SemVer version - const latestVersion = - versions.find((v) => v.semverVersion === latestSemver)?.fullVersion || null; + if (!latestSemver) { + console.log("Could not determine latest semver version."); + return null; + } - console.log("Final selected latest version:", latestVersion); - return latestVersion; + // Get the original full version string that matches the identified latest SemVer version + const latestVersionData = versions.find( + (v) => v.semverVersion === latestSemver, + ); + const latestFullVersion = latestVersionData ? latestVersionData.fullVersion : null; + + console.log("Final selected latest version:", latestFullVersion); + return latestFullVersion; } +/** + * Finds the path to the latest built ZIP file for a specific browser. + * It constructs a glob pattern based on the browser name (e.g., `dist/betterseqtaplus@*-*chrome.zip`), + * finds all matching files, and then uses `getLatestVersion` to identify the version string + * of the most recent file. Finally, it returns the full path to that specific file. + * + * @param {string} browser A string indicating the target browser (e.g., "chrome", "firefox"). + * @returns {string | undefined} The filepath string to the latest ZIP file for the specified browser, + * or `undefined` if no matching file is found or if the latest version + * cannot be determined. + */ function getLatestFiles(browser) { const pattern = `dist/betterseqtaplus@*-*${browser}.zip`; console.log("Glob pattern:", pattern); @@ -52,15 +101,32 @@ function getLatestFiles(browser) { const files = glob.sync(pattern); console.log("Files found for browser", browser, ":", files); - const latestVersion = getLatestVersion(files); + if (files.length === 0) { + console.log("No files found for browser", browser); + return undefined; + } - // Find the exact file by matching the original full version + const latestVersion = getLatestVersion(files); + if (!latestVersion) { + console.log("Could not determine latest version for browser", browser); + return undefined; + } + + // Find the exact file by matching the original full version string const latestFile = files.find((file) => file.includes(`@${latestVersion}-`)); console.log("Latest file for browser", browser, ":", latestFile); return latestFile; } +/** + * Creates a ZIP file of the project's source code, excluding specified development-related + * files and directories such as `node_modules`, `dist`, `.git`, etc. + * It uses the `7z` command-line tool to perform the archiving. + * The output filename is fixed as `dist/betterseqtaplus@latest-sources.zip`. + * + * @returns {string} The filename of the created ZIP file (e.g., `dist/betterseqtaplus@latest-sources.zip`). + */ function zipSources() { const zipFileName = `dist/betterseqtaplus@latest-sources.zip`; @@ -74,17 +140,31 @@ function zipSources() { "LICENSE", "package.json", ] - .map((pattern) => `-x!${pattern}`) + .map((pattern) => `-x!${pattern}`) // Format for 7z exclude syntax .join(" "); + // Command to zip the current directory's contents into zipFileName, applying exclude patterns const zipCommand = `7z a ${zipFileName} . ${excludePatterns}`; console.log("Zipping project sources with command:", zipCommand); - execSync(zipCommand, { stdio: "inherit" }); + execSync(zipCommand, { stdio: "inherit" }); // Execute synchronously and show output return zipFileName; } +/** + * Orchestrates the extension publishing process for the specified browsers. + * This function performs the following steps: + * 1. Calls `getLatestFiles` to find the latest built ZIP for Chrome if "chrome" is in `browsers`. + * 2. Calls `getLatestFiles` to find the latest built ZIP for Firefox if "firefox" is in `browsers`. + * 3. Calls `zipSources` to create a source code ZIP if "firefox" is in `browsers` (required for Mozilla Add-ons). + * 4. Validates that all required files were found and that at least one browser was specified. Exits if not. + * 5. Constructs the `publish-extension` command-line string with the appropriate arguments + * based on the found ZIP files for the specified browsers. + * 6. Executes the constructed `publish-extension` command. + * + * @param {string[]} browsers An array of browser strings (e.g., ["chrome", "firefox"]) for which to publish the extension. + */ function runPublishCommand(browsers) { const chromeZip = browsers.includes("chrome") ? getLatestFiles("chrome") @@ -92,6 +172,7 @@ function runPublishCommand(browsers) { const firefoxZip = browsers.includes("firefox") ? getLatestFiles("firefox") : null; + // Sources are typically only needed for Firefox submissions const firefoxSourcesZip = browsers.includes("firefox") ? zipSources() : null; console.log("Chrome zip:", chromeZip); @@ -100,15 +181,16 @@ function runPublishCommand(browsers) { if (browsers.length === 0) { console.log("No browsers specified. Exiting."); - process.exit(0); + process.exit(0); // Exit gracefully if no action is needed } + // Check if required files are missing for the specified browsers if ( (browsers.includes("chrome") && !chromeZip) || (browsers.includes("firefox") && (!firefoxZip || !firefoxSourcesZip)) ) { console.error("Could not find required zip files for specified browsers."); - process.exit(1); + process.exit(1); // Exit with error status } let command = "publish-extension"; @@ -120,12 +202,13 @@ function runPublishCommand(browsers) { } console.log("Running command:", command); - execSync(command, { stdio: "inherit" }); + execSync(command, { stdio: "inherit" }); // Execute and show output } -// Parse command-line arguments +// Parse command-line arguments to determine which browsers to publish for const args = process.argv.slice(2); -const browserIndex = args.indexOf("--b"); +const browserIndex = args.indexOf("--b"); // Find the --b flag +// If --b is found, take all subsequent arguments as browser names const browsers = browserIndex !== -1 ? args.slice(browserIndex + 1) : []; runPublishCommand(browsers); diff --git a/lib/touchGlobalCSS.ts b/lib/touchGlobalCSS.ts index 644ec3fe..0c6fc281 100644 --- a/lib/touchGlobalCSS.ts +++ b/lib/touchGlobalCSS.ts @@ -1,17 +1,55 @@ import fs from "fs"; +/** + * Creates a Vite plugin designed to improve the reliability of Hot Module Replacement (HMR) + * for global CSS files. + * + * When a JavaScript/TypeScript module that imports a CSS file is updated, Vite's HMR + * might not always reliably update the styles injected by that global CSS. This plugin + * attempts to mitigate this by listening for hot updates. If an updated module + * has direct importers that are CSS files (e.g., a JS file imports a global CSS file), + * this plugin will "touch" those CSS files by updating their access and modification + * timestamps using `fs.utimesSync`. This action can help signal to Vite or the browser + * that the CSS file has changed, potentially triggering a more reliable style reload. + * + * @returns {import('vite').Plugin} A Vite plugin object configured with `name` and `handleHotUpdate` hooks. + */ export default function touchGlobalCSSPlugin() { return { + /** + * The unique name of this Vite plugin. + * This name is used by Vite for identification purposes and will appear in logs. + * @type {string} + */ name: "touch-global-css", + /** + * A Vite hook that is called when a module is hot-updated. + * This function inspects the importers of the updated module. If any of these + * importers are CSS files, their filesystem timestamps are updated ("touched"). + * + * @param {object} context The context object provided by Vite's `handleHotUpdate` hook. + * @param {Array} context.modules An array of `ModuleNode` instances that have been updated. + * This plugin specifically accesses `modules[0]._clientModule.importers` + * to find CSS files that import the updated module. + */ handleHotUpdate({ modules }) { - // log all of the staticImportedUrls - const importers = modules[0]._clientModule.importers; - importers.forEach((importer) => { - if (importer.file.includes(".css")) { - console.log("touching", importer.file); - fs.utimesSync(importer.file, new Date(), new Date()); - } - }); + // It's assumed `modules[0]` is the primary updated module of interest. + // `_clientModule` and `importers` might be internal or less stable Vite APIs. + const importers = modules[0]?._clientModule?.importers; + if (importers) { + importers.forEach((importer) => { + // Check if the importer is a CSS file + if (importer.file && importer.file.includes(".css")) { + console.log("[touch-global-css] touching", importer.file); + try { + // Update the access and modification times of the CSS file to the current time + fs.utimesSync(importer.file, new Date(), new Date()); + } catch (err) { + console.error(`[touch-global-css] Error touching file ${importer.file}:`, err); + } + } + }); + } }, }; } diff --git a/lib/types.ts b/lib/types.ts index 7d06f5a9..4b58a93f 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,6 +1,9 @@ import type { ManifestV3Export } from "@crxjs/vite-plugin"; -import { type AnyCase, createEnum } from "./utils"; +import { type AnyCase, createEnum, ObjectValues } from "./utils"; +/** + * Enumerates supported JavaScript frameworks for project generation or configuration. + */ export const FrameworkEnum = { React: "React", Vanilla: "Vanilla", @@ -10,6 +13,9 @@ export const FrameworkEnum = { Vue: "Vue", } as const; +/** + * Enumerates supported web browsers, typically for targeting builds or configurations. + */ export const BrowserEnum = { Chrome: "Chrome", Brave: "Brave", @@ -19,15 +25,26 @@ export const BrowserEnum = { Safari: "Safari", } as const; +/** + * @private + * Enumerates supported programming languages for project setup. + * This enum is not exported, suggesting it's for internal use within this module or related modules. + */ const LanguageEnum = { TypeScript: "TypeScript", JavaScript: "JavaScript", } as const; +/** + * Enumerates supported styling options or libraries. + */ export const StyleEnum = { Tailwind: "Tailwind", } as const; +/** + * Enumerates supported package managers. + */ export const PackageManagerEnum = { Bun: "Bun", PnPm: "PnPm", @@ -35,7 +52,21 @@ export const PackageManagerEnum = { Yarn: "Yarn", } as const; -// see: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/firefox-webext-browser/index.d.ts +/** + * Defines the structure for browser-specific settings within a web extension manifest. + * This is particularly used for Firefox (gecko) extensions to specify properties like + * an extension ID, and minimum/maximum supported browser versions. + * The structure is based on common manifest extensions for Firefox. + * See: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings + * The link in the original code (// see: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/firefox-webext-browser/index.d.ts) + * also points to type definitions that include this structure. + * + * @property {object} [browser_specific_settings] - Container for browser-specific settings. + * @property {object} [browser_specific_settings.gecko] - Settings specific to Gecko-based browsers (e.g., Firefox). + * @property {string} [browser_specific_settings.gecko.id] - The unique identifier for the extension in Firefox. + * @property {string} [browser_specific_settings.gecko.strict_min_version] - The minimum version of Firefox the extension is compatible with. + * @property {string} [browser_specific_settings.gecko.strict_max_version] - The maximum version of Firefox the extension is compatible with. + */ export type BrowserSpecificSettings = { browser_specific_settings?: { gecko?: { @@ -46,59 +77,164 @@ export type BrowserSpecificSettings = { }; }; +/** + * Represents the structure of a Chrome Manifest V3 file. + * This type is an alias for `ManifestV3Export` from the `@crxjs/vite-plugin`, + * which provides a comprehensive definition for Chrome extension manifests. + */ export type Manifest = ManifestV3Export; + +/** Alias for the `icons` property within a Chrome Manifest V3. */ export type ManifestIcons = chrome.runtime.ManifestIcons; +/** Alias for the `background` property within a Chrome Manifest V3. */ export type ManifestBackground = chrome.runtime.ManifestV3["background"]; +/** Alias for the `content_scripts` property within a Chrome Manifest V3. */ export type ManifestContentScripts = chrome.runtime.ManifestV3["content_scripts"]; +/** Alias for the `web_accessible_resources` property within a Chrome Manifest V3. */ export type ManifestWebAccessibleResources = chrome.runtime.ManifestV3["web_accessible_resources"]; +/** Alias for the `commands` property within a Chrome Manifest V3. */ export type ManifestCommands = chrome.runtime.ManifestV3["commands"]; +/** Alias for the `action` property (or `browser_action`/`page_action`) within a Chrome Manifest V3. */ export type ManifestAction = chrome.runtime.ManifestV3["action"]; +/** Alias for the `permissions` property within a Chrome Manifest V3. */ export type ManifestPermissions = chrome.runtime.ManifestV3["permissions"]; +/** Alias for the `options_ui` property within a Chrome Manifest V3. */ export type ManifestOptionsUI = chrome.runtime.ManifestV3["options_ui"]; +/** Alias for the `chrome_url_overrides` property within a Chrome Manifest V3. */ export type ManifestURLOverrides = chrome.runtime.ManifestV3["chrome_url_overrides"]; +/** + * Creates a type that accepts a string literal `T` in either its capitalized or lowercase form. + * Useful for defining types that should be case-insensitive for specific known strings. + * @template T - A string literal type. + */ export type BrowserName = Capitalize | Lowercase; + +/** + * Creates a record type where both keys and values are derived from a string literal `T`, + * specifically using `BrowserName` which allows for capitalized or lowercase forms. + * This could be used to define an object where, for example, keys are 'Chrome' or 'chrome' + * and values are also 'Chrome' or 'chrome'. + * @template T - A string literal type, typically representing a browser name. + */ export type BrowserEnumType = { [browser in BrowserName]: BrowserName; }; +/** + * Represents the target browser for a build, allowing for various casings of browser names + * (e.g., "chrome", "Chrome", "CHROME") through the `AnyCase` utility type. + * `Browser` itself is a union of specific browser name strings (e.g., "Chrome" | "Firefox"). + */ export type BuildMode = AnyCase; + +/** + * Defines an object structure that pairs a web extension `Manifest` + * with its target `browser` (represented as `AnyCase`). + * This is commonly used in build processes to manage configurations for different browsers. + */ export type BuildTarget = { manifest: Manifest; browser: AnyCase; }; + +/** + * Defines the configuration options for a build process. + * @property {"build" | "serve"} [command] - The type of build command (e.g., 'build' for production, 'serve' for development). + * @property {AnyCase | string | undefined} [mode] - The target build mode, typically a browser name (allowing various casings) + * or potentially other custom mode strings. + */ export type BuildConfig = { command?: "build" | "serve"; mode?: AnyCase | string | undefined; }; +/** + * Defines the structure for repository information, commonly found in `package.json`. + * @property {string} type - The type of the repository (e.g., "git"). + * @property {string} [url] - The URL of the repository. + * @property {Bugs} [bugs] - An object containing information about where to report bugs. + */ export interface Repository { type: string; url?: string; bugs?: Bugs; } +/** + * Defines the structure for bug reporting information, often part of the `Repository` interface. + * @property {string} [url] - The URL of the issue tracker. + * @property {string} [email] - The email address for reporting bugs. + */ export interface Bugs { url?: string; email?: string; } -export type Browser = (typeof BrowserEnum)[keyof typeof BrowserEnum]; +/** + * A string literal union type representing supported browser names, derived from the values of `BrowserEnum`. + * e.g., "Chrome" | "Firefox" | ... + */ +export type Browser = ObjectValues; + +/** + * A constant intended to provide access to browser names, potentially in various casings. + * Its type `AnyCase` suggests it can be used where case-insensitivity for browser names is needed. + * The `createEnum(BrowserEnum)` call aims to produce a representation of browser names from `BrowserEnum`. + * Note: `createEnum` from `lib/utils.ts` has a declared return type of `ObjectValues` (a union of values), + * while its implementation uses `Object.values()` which returns an array. This constant will hold the + * runtime array value, but its JSDoc type refers to the more restrictive `AnyCase` union type. + */ export const Browser: AnyCase = createEnum(BrowserEnum); -export type PackageManager = - (typeof PackageManagerEnum)[keyof typeof PackageManagerEnum]; +/** + * A string literal union type representing supported package managers, derived from the values of `PackageManagerEnum`. + * e.g., "Bun" | "PnPm" | "Npm" | "Yarn" + */ +export type PackageManager = ObjectValues; +/** + * A constant intended to provide access to package manager names, potentially in various casings. + * Its type `AnyCase` suggests it can be used where case-insensitivity for package manager names is needed. + * Utilizes `createEnum(PackageManagerEnum)`. Refer to notes on `Browser` constant regarding `createEnum` behavior. + */ export const PackageManager: AnyCase = createEnum(PackageManagerEnum); -export type Framework = (typeof FrameworkEnum)[keyof typeof FrameworkEnum]; +/** + * A string literal union type representing supported JavaScript frameworks, derived from the values of `FrameworkEnum`. + * e.g., "React" | "Vanilla" | ... + */ +export type Framework = ObjectValues; +/** + * A constant intended to provide access to framework names, potentially in various casings. + * Its type `AnyCase` suggests it can be used where case-insensitivity for framework names is needed. + * Utilizes `createEnum(FrameworkEnum)`. Refer to notes on `Browser` constant regarding `createEnum` behavior. + */ export const Framework: AnyCase = createEnum(FrameworkEnum); -export type Style = (typeof StyleEnum)[keyof typeof StyleEnum]; +/** + * A string literal union type representing supported styling options, derived from the values of `StyleEnum`. + * e.g., "Tailwind" + */ +export type Style = ObjectValues; +/** + * A constant intended to provide access to style option names, potentially in various casings. + * Its type `AnyCase