zotero-plugin-scaffold
Version:
A scaffold for Zotero plugin development.
1,320 lines (1,296 loc) • 166 kB
JavaScript
import { loadConfig as loadConfig$1, setupDotenv } from 'c12';
import { kebabCase, mapValues, toMerged, escapeRegExp, debounce, delay } from 'es-toolkit';
import { readJsonSync, copy, move, outputFile, readJSON, outputJSON, writeJson, emptyDir, pathExists, ensureDir, remove } from 'fs-extra/esm';
import { createHooks } from 'hookable';
import { l as logger, p as parseRepoUrl, d as dateFormat, t as template, b as toArray, s as styleText, c as replaceDefine, L as LOG_LEVEL } from './zotero-plugin-scaffold.CzBjWbS8.mjs';
import process$1 from 'node:process';
import { glob, globSync } from 'tinyglobby';
import path, { resolve as resolve$1, dirname, basename, join as join$1, isAbsolute as isAbsolute$1, extname as extname$1 } from 'node:path';
import { build, context } from 'esbuild';
import { readFile, writeFile, stat } from 'node:fs/promises';
import { parse, serialize, Transformer } from '@fluent/syntax';
import fs, { existsSync, createReadStream, lstatSync, realpathSync, statSync, promises } from 'node:fs';
import { parseSync, printSync } from '@swc/core';
import { createHash } from 'node:crypto';
import AdmZip from 'adm-zip';
import { execSync, spawn } from 'node:child_process';
import { isCI, isWindows as isWindows$1, isMacOS, isLinux, isDebug } from 'std-env';
import { versionBump, ProgressEvent } from 'bumpp';
import 'node:os';
import { fileURLToPath, pathToFileURL, URL as URL$1 } from 'node:url';
import assert from 'node:assert';
import v8 from 'node:v8';
import { format, inspect } from 'node:util';
import { Octokit } from 'octokit';
import chokidar from 'chokidar';
import net from 'node:net';
import { Buffer } from 'node:buffer';
import domain from 'node:domain';
import EventEmitter from 'node:events';
import { Xvfb } from 'xvfb-ts';
import http from 'node:http';
function defineConfig(userConfig) {
return userConfig;
}
async function loadConfig(overrides) {
const result = await loadConfig$1({
name: "zotero-plugin",
dotenv: true,
packageJson: true,
// eslint-disable-next-line ts/no-use-before-define
defaults: getDefaultConfig$1(),
overrides
});
return resolveConfig$1(result.config);
}
function resolveConfig$1(config) {
logger.setLogLevel(config.logLevel);
const pkgUser = readJsonSync("package.json", {
encoding: "utf-8"
});
const { name, version } = pkgUser;
const { owner, repo } = parseRepoUrl(pkgUser.repository?.url);
config.name ||= name;
config.id ||= config.name;
config.namespace ||= config.name;
config.xpiName ||= kebabCase(config.name);
config.build.prefs.prefix ||= pkgUser.config.prefsPrefix || `extensions.${config.namespace}`;
const isPreRelease = version.includes("-");
const templateData = {
owner,
repo,
version,
isPreRelease,
updateJson: isPreRelease ? "update-beta.json" : "update.json",
xpiName: config.xpiName,
buildTime: dateFormat("YYYY-mm-dd HH:MM:SS", /* @__PURE__ */ new Date())
};
config.updateURL = template(config.updateURL, templateData);
config.xpiDownloadLink = template(config.xpiDownloadLink, templateData);
config.build.define = mapValues(config.build.define, (v) => template(v, templateData));
config.release.github.repository = template(config.release.github.repository, templateData);
const hooks = createHooks();
hooks.addHooks(config.build.hooks);
hooks.addHooks(config.server.hooks);
hooks.addHooks(config.release.hooks);
hooks.addHooks(config.test.hooks);
const ctx = {
...config,
pkgUser,
version,
hooks,
logger,
templateData
};
return ctx;
}
const defaultConfig = {
source: "src",
watchIgnore: [],
dist: ".scaffold/build",
name: "",
id: "",
namespace: "",
xpiName: "",
xpiDownloadLink: "https://github.com/{{owner}}/{{repo}}/releases/download/v{{version}}/{{xpiName}}.xpi",
updateURL: "https://github.com/{{owner}}/{{repo}}/releases/download/release/{{updateJson}}",
build: {
assets: "addon/**/*.*",
define: {},
fluent: {
prefixFluentMessages: true,
prefixLocaleFiles: true,
ignore: [],
dts: "typings/i10n.d.ts"
},
prefs: {
prefix: "",
prefixPrefKeys: true,
dts: "typings/prefs.d.ts"
},
esbuildOptions: [],
makeManifest: {
enable: true,
template: {
manifest_version: 2,
name: "",
version: "",
applications: {
zotero: {
id: "",
update_url: ""
}
}
}
},
makeUpdateJson: {
updates: [],
hash: true
},
hooks: {}
},
server: {
devtools: true,
startArgs: [],
asProxy: false,
prebuild: true,
// keepProfileChanges: true,
createProfileIfMissing: true,
hooks: {}
},
addonLint: {},
release: {
bumpp: {
release: "prompt",
preid: "beta",
confirm: true,
execute: "",
all: false,
commit: "chore(publish): release v%s",
noVerify: false,
tag: "v%s"
},
changelog: "",
github: {
enable: "ci",
repository: "{{owner}}/{{repo}}",
updater: "release",
comment: false,
releaseNote: (ctx) => {
return ctx.release.changelog;
}
},
hooks: {}
},
test: {
entries: "test",
prefs: {},
mocha: {
timeout: 1e4
},
abortOnFail: false,
headless: false,
startupDelay: 1e3,
waitForPlugin: "() => true",
watch: true,
hooks: {}
},
logLevel: "INFO"
};
const getDefaultConfig$1 = () => defaultConfig;
class Base {
ctx;
constructor(ctx) {
this.ctx = ctx;
}
get logger() {
return this.ctx.logger;
}
}
const DEFAULT_IGNORE = ["node_modules", ".git"];
async function copyAssets(source, dist, assets) {
const sourceArr = toArray(source);
const paths = await glob(assets, {
ignore: [...DEFAULT_IGNORE, dist]
});
for (const file of paths) {
const newPath = getNewPath(sourceArr, dist, file);
await copy(file, newPath);
logger.debug(`Copy ${file} to ${newPath}`);
}
}
function getNewPath(sources, dist, path) {
const pattern = new RegExp(sources.join("|"));
const relativePath = path.replace(pattern, "");
return `${dist}/addon/${relativePath}`;
}
function resolveConfig(dist, esbuildOptions) {
const distAbsolute = resolve$1(dist);
return esbuildOptions.map((option, i) => {
if (option.outfile && !resolve$1(option.outfile).startsWith(distAbsolute)) {
logger.debug(`'outfile' of esbuildOptions[${i}] is not in dist folder, it will be overwritten.`);
option.outfile = `${dist}/${option.outfile}`;
}
if (option.outdir && !resolve$1(option.outdir).startsWith(distAbsolute)) {
logger.debug(`'outdir' of esbuildOptions[${i}] is not in dist folder, it will be overwritten.`);
option.outdir = `${dist}/${option.outdir}`;
}
return option;
});
}
async function esbuild(dist, esbuildOptions) {
if (esbuildOptions.length === 0)
return;
const options = resolveConfig(dist, esbuildOptions);
return await Promise.all(
options.map(
(esbuildOption) => build(esbuildOption)
)
);
}
async function buildLocale(dist, namespace, options) {
const ignores = toArray(options.ignore);
const localeNames = await getLocales(dist);
const messageManager = new MessageManager(ignores);
await Promise.all(localeNames.map(async (locale) => {
const paths = await glob(`${dist}/addon/locale/${locale}/**/*.ftl`);
await Promise.all(paths.map(async (path) => {
const fm = new FluentManager();
await fm.read(path);
messageManager.addMessages(locale, fm.getMessages());
if (options.prefixFluentMessages) {
fm.prefixMessages(namespace);
await fm.write(path);
}
if (options.prefixLocaleFiles) {
const newPath = `${dirname(path)}/${namespace}-${basename(path)}`;
await move(path, newPath);
logger.debug(`Renamed FTL: ${path} \u2192 ${newPath}`);
}
}));
}));
const htmlPaths = await glob([`${dist}/addon/**/*.xhtml`, `${dist}/addon/**/*.html`]);
await Promise.all(htmlPaths.map(async (htmlPath) => {
const content = await readFile(htmlPath, "utf-8");
const { processedContent, foundMessages } = processHTMLFile(
content,
namespace,
messageManager.getFTLMessages(),
ignores,
htmlPath
);
messageManager.addMessages("html", foundMessages);
if (options.prefixFluentMessages) {
await writeFile(htmlPath, processedContent);
}
}));
messageManager.validateMessages();
if (options.dts) {
const dtsContent = generateFluentDts([...messageManager.getFTLMessages()]);
await outputFile(options.dts, dtsContent, "utf-8");
}
}
async function getLocales(dist) {
const localePaths = await glob(`${dist}/addon/locale/*`, { onlyDirectories: true });
return localePaths.map((p) => basename(p));
}
class FluentManager {
source;
resource;
messages = [];
constructor() {
}
// Parse Fluent source into an AST and extract messages
parse(source) {
this.source = source;
this.resource = parse(source, {});
}
// Read a file, parse its content, and extract messages
async read(path) {
const content = await readFile(path, "utf-8");
this.parse(content);
}
// Extract message IDs from the parsed resource
getMessages() {
if (!this.resource) {
throw new Error("Resource must be parsed first.");
}
this.messages.length = 0;
this.messages.push(
...this.resource.body.filter((entry) => entry.type === "Message").map((message) => message.id.name)
);
return this.messages;
}
// Apply namespace prefix to message IDs in the resource
prefixMessages(namespace) {
if (!this.resource) {
throw new Error("Resource must be parsed before applying prefix.");
}
new FluentTransformer(namespace).genericVisit(this.resource);
}
// Serialize the resource back into a string
serialize() {
if (!this.resource) {
throw new Error("Resource not parsed. Cannot serialize.");
}
return serialize(this.resource, {});
}
// Write the serialized resource to a file
async write(path) {
const result = this.serialize();
if (result !== this.source)
await writeFile(path, this.serialize());
}
}
class FluentTransformer extends Transformer {
constructor(prefix) {
super();
this.prefix = prefix;
}
needsPrefix(name) {
return !!this.prefix && !name.startsWith(this.prefix);
}
visitMessage(node) {
if (this.needsPrefix(node.id.name)) {
node.id.name = `${this.prefix}-${node.id.name}`;
}
return this.genericVisit(node);
}
visitMessageReference(node) {
if (this.needsPrefix(node.id.name)) {
node.id.name = `${this.prefix}-${node.id.name}`;
}
return this.genericVisit(node);
}
}
class MessageManager {
ftlMessages = /* @__PURE__ */ new Map();
htmlMessages = /* @__PURE__ */ new Set();
ignores;
constructor(ignores) {
this.ignores = ignores;
}
// Add a set of messages (FTL or HTML) for a specific locale or for HTML globally
addMessages(target, messages) {
if (target === "html") {
messages.forEach((msg) => this.htmlMessages.add(msg));
} else {
let ftlLocaleMessages = this.ftlMessages.get(target);
if (!ftlLocaleMessages) {
ftlLocaleMessages = /* @__PURE__ */ new Set();
this.ftlMessages.set(target, ftlLocaleMessages);
}
messages.forEach((msg) => ftlLocaleMessages.add(msg));
}
}
validateMessages() {
this.htmlMessages.forEach((msg) => {
if (this.ignores.includes(msg))
return;
const missingLocales = [...this.ftlMessages.entries()].filter(([_, messages]) => !messages.has(msg)).map(([locale]) => locale);
if (missingLocales.length > 0)
logger.warn(`I10N id ${styleText.blue(msg)} missing in locale: ${missingLocales.join(", ")}`);
});
}
getFTLMessages() {
const allMessages = /* @__PURE__ */ new Set();
this.ftlMessages.forEach((messages) => messages.forEach((msg) => allMessages.add(msg)));
return allMessages;
}
// Get all FTL messages for a specific locale
getFTLMessagesByLocale(locale) {
return this.ftlMessages.get(locale) || /* @__PURE__ */ new Set();
}
// Get all HTML messages
getHTMLMessages() {
return this.htmlMessages;
}
}
function processHTMLFile(content, namespace, allMessages, ignores, filePath) {
const foundMessages = /* @__PURE__ */ new Set();
const L10N_PATTERN = new RegExp(`(data-l10n-id)="((?!${namespace})\\S*)"`, "g");
const processed = content.replace(L10N_PATTERN, (match, attr, id) => {
foundMessages.add(id);
if (ignores.includes(id)) {
logger.debug(`Skipped ignored ID: ${styleText.blue(id)} in ${styleText.gray(filePath)}`);
return match;
}
if (!allMessages.has(id)) {
logger.warn(`I10N id ${styleText.blue(id)} in path ${styleText.gray(filePath)} does not exist in any locale, skip renaming it.`);
return match;
}
return `${attr}="${namespace}-${id}"`;
});
return { processedContent: processed, foundMessages: [...foundMessages] };
}
function generateFluentDts(messages) {
return `// Generated by zotero-plugin-scaffold
/* prettier-ignore */
/* eslint-disable */
// @ts-nocheck
export type FluentMessageId =
${Array.from(messages).sort().map((id) => ` | '${id}'`).join("\n")};
`;
}
async function buildManifest(ctx) {
if (!ctx.build.makeManifest.enable)
return;
const { name, id, updateURL, dist, version } = ctx;
const userData = await readJSON(
`${dist}/addon/manifest.json`
);
const template = {
...userData,
...!userData.name && name && { name },
...version && { version },
manifest_version: 2,
applications: {
zotero: {
id,
update_url: updateURL
}
}
};
const data = toMerged(userData, template);
logger.debug(`manifest: ${JSON.stringify(data, null, 2)}`);
outputJSON(`${dist}/addon/manifest.json`, data, { spaces: 2 });
}
function is32BitNumber(n) {
return Number.isInteger(n) && n >= -2147483648 && n <= 2147483647;
}
class PrefsManager {
namespace;
prefs = {};
constructor(namespace) {
this.namespace = namespace;
}
/**
* Parse Method 3 - Using AST
*/
parse(content) {
const _map = {};
const ast = parseSync(content, { syntax: "ecmascript" });
for (const node of ast.body) {
if (node.type !== "ExpressionStatement" || node.expression.type !== "CallExpression" || node.expression.callee.type !== "Identifier" || node.expression.callee.value !== this.namespace || node.expression.arguments.length !== 2) {
throw new Error("Invalid prefs.js file.");
}
const [arg1, arg2] = node.expression.arguments;
if (arg1.expression.type !== "StringLiteral") {
throw new Error("Invalid prefs.js file - unsupported key type.");
}
const key = arg1.expression.value.trim();
let value;
switch (arg2.expression.type) {
// https://babeljs.io/docs/babel-parser#output
case "StringLiteral":
case "NumericLiteral":
case "BooleanLiteral":
value = arg2.expression.value;
break;
// https://github.com/estree/estree/blob/master/es5.md#unaryexpression
// https://github.com/northword/zotero-plugin-scaffold/issues/98
case "UnaryExpression":
if (arg2.expression.argument.type !== "NumericLiteral")
throw new Error("Invalid prefs.js file - unsupported value type.");
if (arg2.expression.operator === "-")
value = -arg2.expression.argument.value;
else if (arg2.expression.operator === "+")
value = arg2.expression.argument.value;
else
throw new Error("Invalid prefs.js file - unsupported value type.");
break;
case "TemplateLiteral":
value = arg2.expression.quasis[0]?.cooked ?? "";
break;
default:
throw new Error("Invalid prefs.js file - unsupported value type.");
}
_map[key] = value;
}
return _map;
}
/**
* Parse Method 1 - Using RegExp
* @deprecated
*/
parseByRegExp(content) {
const _map = {};
const prefPattern = /^(pref|user_pref)\s*\(\s*["']([^"']+)["']\s*,\s*(.+)\s*,?\s*\)\s*;?$/gm;
const matches = content.matchAll(prefPattern);
for (const match of matches) {
const key = match[2].trim();
const value = match[3].trim();
_map[key] = this.cleanValue(value);
}
return _map;
}
/**
* Parse Method 2 - Using eval
* @deprecated
*/
// private parseByEval(content: string) {
// const _map: Prefs = {};
// // eslint-disable-next-line unused-imports/no-unused-vars
// const pref = (key: any, value: any) => {
// _map[key.trim()] = this.cleanValue(value.trim());
// };
// // eslint-disable-next-line no-eval
// eval(content);
// return _map;
// }
cleanValue(value) {
if (value === "true")
return true;
else if (value === "false")
return false;
else if (!Number.isNaN(Number(value)))
return Number(value);
else if (value.match(/^["'](.*)["']$/))
return value.replace(/^["'](.*)["']$/, "$1");
else
return value;
}
/**
* Render Method 2 - Using swc
*/
render() {
const span = { start: 0, end: 0, ctxt: 0 };
function getExpression(value) {
switch (typeof value) {
case "string":
return {
type: "StringLiteral",
span,
value
};
case "boolean":
return {
type: "BooleanLiteral",
span,
value
};
case "number":
if (value < 0) {
return {
type: "UnaryExpression",
span,
operator: "-",
argument: {
type: "NumericLiteral",
span,
value: Math.abs(value)
}
};
}
return {
type: "NumericLiteral",
span,
value
};
default:
throw new Error(`Unsupported value type: ${typeof value}`);
}
}
const ast = {
type: "Module",
span,
// @ts-expect-error no raw property
body: Object.entries(this.prefs).map(([key, value]) => ({
type: "ExpressionStatement",
span,
expression: {
type: "CallExpression",
span,
ctxt: 0,
callee: {
type: "Identifier",
span,
ctxt: 0,
value: this.namespace,
optional: false
},
arguments: [
{ expression: getExpression(key) },
{ expression: getExpression(value) }
]
}
}))
};
const { code } = printSync(ast);
return code;
}
/**
* Render Method 1 - Using string
* @deprecated
*/
renderByString() {
return Object.entries(this.prefs).map(([key, value]) => {
const _v = typeof value === "string" ? `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"` : value;
return `${this.namespace}("${key}", ${_v});`;
}).join("\n");
}
async read(path) {
const content = await readFile(path, "utf-8");
const map = this.parse(content);
this.setPrefs(map);
}
async write(path) {
const content = this.render();
await outputFile(path, content, "utf-8");
logger.debug("The prefs.js has been modified.");
}
setPref(key, value) {
if (value === null || value === void 0) {
if (key in this.prefs)
delete this.prefs[key];
return;
}
this.prefs[key] = value;
}
setPrefs(prefs) {
Object.entries(prefs).forEach(([key, value]) => {
this.setPref(key, value);
});
}
getPref(key) {
return this.prefs[key] ?? void 0;
}
getPrefs() {
return this.prefs;
}
clearPrefs() {
this.prefs = {};
}
getPrefsWithPrefix(prefix) {
const _prefs = {};
for (const pref in this.prefs) {
if (pref.startsWith(prefix))
_prefs[pref] = this.prefs[pref];
else
_prefs[`${prefix}.${pref}`] = this.prefs[pref];
}
return _prefs;
}
getPrefsWithoutPrefix(prefix) {
const _prefs = {};
for (const pref in this.prefs) {
_prefs[pref.replace(`${prefix}.`, "")] = this.prefs[pref];
}
return _prefs;
}
}
async function buildPrefs(dist, options) {
const { dts, prefixPrefKeys, prefix } = options;
if (!prefixPrefKeys && !dts)
return;
const prefsFilePath = join$1(dist, "addon", "prefs.js");
if (!existsSync(prefsFilePath))
return;
const prefsManager = new PrefsManager("pref");
await prefsManager.read(prefsFilePath);
const prefsWithPrefix = prefsManager.getPrefsWithPrefix(prefix);
const prefsWithoutPrefix = prefsManager.getPrefsWithoutPrefix(prefix);
const prefs = prefsManager.getPrefs();
Object.entries(prefs).forEach(([key, value]) => {
if (typeof value === "number") {
if (!is32BitNumber(value)) {
logger.warn(`Pref key '${styleText.blue(key)}' is a number, but is more than 4 bytes, which can be problematic on some OS.`);
}
}
});
if (dts) {
const dtsContent = renderPluginPrefsDts(prefsWithoutPrefix);
await outputFile(dts, dtsContent, "utf-8");
}
if (prefixPrefKeys) {
prefsManager.clearPrefs();
prefsManager.setPrefs(prefsWithPrefix);
await prefsManager.write(prefsFilePath);
}
if (prefixPrefKeys) {
const HTML_PREFERENCE_PATTERN = /preference="(\S*)"/g;
const xhtmlPaths = await glob(`${dist}/addon/**/*.xhtml`);
await Promise.all(xhtmlPaths.map(async (path) => {
let content = await readFile(path, "utf-8");
const matchs = [...content.matchAll(HTML_PREFERENCE_PATTERN)];
for (const match of matchs) {
const [matched, key] = match;
if (key.startsWith(prefix)) {
logger.debug(`Pref key '${styleText.blue(key)}' is already starts with '${prefix}', skip prefixing it.`);
continue;
} else if (key.startsWith("extensions.")) {
logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} starts with 'extensions.' but not '${styleText.blue(prefix)}', skip prefixing it.`);
continue;
} else if (!(key in prefsWithPrefix) && !(key in prefsWithoutPrefix)) {
logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is not found in prefs.js, skip prefixing it.`);
continue;
} else {
const prefixed = `${prefix}.${key}`;
logger.debug(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is prefixed to ${styleText.blue(prefixed)}.`);
content = content.replace(matched, `preference="${prefixed}"`);
}
}
await outputFile(path, content, "utf-8");
}));
}
}
function renderPluginPrefsDts(prefs) {
return `// Generated by zotero-plugin-scaffold
/* prettier-ignore */
/* eslint-disable */
// @ts-nocheck
// prettier-ignore
declare namespace _ZoteroTypes {
interface Prefs {
PluginPrefsMap: {
${Object.entries(prefs).map(([key, value]) => {
return `"${key}": ${typeof value};`;
}).join("\n ")}
};
}
}
`;
}
function generateHash(filePath, algorithm) {
return new Promise((resolve, reject) => {
const hash = createHash(algorithm);
const stream = createReadStream(filePath);
stream.on("data", (data) => {
hash.update(data);
});
stream.on("end", () => {
const fileHash = hash.digest("hex");
resolve(`${algorithm}:${fileHash}`);
});
stream.on("error", (error) => {
reject(error);
});
});
}
async function buildUpdateJson(ctx) {
const { dist, xpiName, id, version, xpiDownloadLink, build } = ctx;
const manifest = await readJSON(
`${dist}/addon/manifest.json`
);
const min = manifest.applications?.zotero?.strict_min_version;
const max = manifest.applications?.zotero?.strict_max_version;
const updateHash = await generateHash(`${dist}/${xpiName}.xpi`, "sha512");
const data = {
addons: {
[id]: {
updates: [
...build.makeUpdateJson.updates,
{
version,
update_link: xpiDownloadLink,
...build.makeUpdateJson.hash && {
update_hash: updateHash
},
applications: {
zotero: {
...min && { strict_min_version: min },
...max && { strict_max_version: max }
}
}
}
]
}
}
};
await writeJson(`${dist}/update-beta.json`, data, { spaces: 2 });
if (!ctx.templateData.isPreRelease)
await writeJson(`${dist}/update.json`, data, { spaces: 2 });
logger.debug(
`Prepare Update.json for ${ctx.templateData.isPreRelease ? "\x1B[31m Prerelease \x1B[0m" : "\x1B[32m Release \x1B[0m"}`
);
}
async function pack(dist, xpiName) {
const zip = new AdmZip();
zip.addLocalFolder(`${dist}/addon`);
zip.writeZip(`${dist}/${xpiName}.xpi`);
}
class Build extends Base {
buildTime;
constructor(ctx) {
super(ctx);
process$1.env.NODE_ENV ??= "production";
this.buildTime = "";
}
/**
* Default build runner
*/
async run() {
const { dist, version } = this.ctx;
const t = /* @__PURE__ */ new Date();
this.buildTime = dateFormat("YYYY-mm-dd HH:MM:SS", t);
this.logger.info(`Building version ${styleText.blue(version)} to ${styleText.blue(dist)} at ${styleText.blue(this.buildTime)} in ${styleText.blue(process$1.env.NODE_ENV)} mode.`);
await this.ctx.hooks.callHook("build:init", this.ctx);
this.logger.tip("Preparing static assets", { space: 1 });
await this.prepareAssets();
this.logger.tip("Bundling scripts", { space: 1 });
await this.bundle();
if (process$1.env.NODE_ENV === "production") {
this.logger.tip("Packing plugin", { space: 1 });
this.buildInProduction();
}
await this.ctx.hooks.callHook("build:done", this.ctx);
this.logger.success(`Build finished in ${((/* @__PURE__ */ new Date()).getTime() - t.getTime()) / 1e3} s.`);
}
async prepareAssets() {
const { source, namespace, dist, build } = this.ctx;
await emptyDir(dist);
await this.ctx.hooks.callHook("build:mkdir", this.ctx);
await copyAssets(source, dist, build.assets);
await replaceDefine(dist, build.define);
await this.ctx.hooks.callHook("build:copyAssets", this.ctx);
this.logger.debug("Preparing manifest", { space: 2 });
await buildManifest(this.ctx);
await this.ctx.hooks.callHook("build:makeManifest", this.ctx);
this.logger.debug("Preparing locale files", { space: 2 });
await buildLocale(dist, namespace, build.fluent);
await this.ctx.hooks.callHook("build:fluent", this.ctx);
this.logger.debug("Preparing preference files", { space: 2 });
await buildPrefs(dist, build.prefs);
}
async bundle() {
const { dist, build: { esbuildOptions } } = this.ctx;
await esbuild(dist, esbuildOptions);
await this.ctx.hooks.callHook("build:bundle", this.ctx);
}
async buildInProduction() {
const { dist, xpiName } = this.ctx;
await pack(dist, xpiName);
await this.ctx.hooks.callHook("build:pack", this.ctx);
await buildUpdateJson(this.ctx);
await this.ctx.hooks.callHook("build:makeUpdateJSON", this.ctx);
}
exit() {
}
}
class ReleaseBase {
isCI;
ctx;
constructor(ctx) {
this.ctx = ctx;
this.isCI = isCI;
}
checkFiles() {
const { dist } = this.ctx;
if (globSync(`${dist}/*.xpi`).length === 0) {
throw new Error("No xpi file found, are you sure you have run build?");
}
}
get logger() {
return this.ctx.logger;
}
}
class Bump extends ReleaseBase {
constructor(ctx) {
super(ctx);
}
async run() {
const bumppConfig = {
...this.ctx.release.bumpp,
push: true,
progress: this.bumppProgress
};
const { version } = this.ctx;
if (bumppConfig.release === version) {
this.logger.debug("Commit, tag, and push are disabled because new version = old version.");
bumppConfig.commit = false;
bumppConfig.tag = false;
bumppConfig.push = false;
}
const result = await versionBump(bumppConfig);
this.ctx.version = result.newVersion;
this.ctx.release.bumpp.tag = result.tag || this.ctx.release.bumpp.tag.toString().replace("%s", result.newVersion);
this.ctx.release.bumpp.commit = result.commit || this.ctx.release.bumpp.commit.toString().replace("%s", result.newVersion);
this.logger.debug(`The release context after bump: ", ${this.ctx.release}`);
}
/**
* bumpp 显示进度的回调
*
* @see https://github.com/antfu/bumpp/blob/main/src/cli/index.ts
*/
get bumppProgress() {
return ({
event,
script,
updatedFiles,
skippedFiles,
newVersion
}) => {
switch (event) {
case ProgressEvent.FileUpdated:
this.logger.success(`Updated ${updatedFiles.pop()} to ${newVersion}`);
break;
case ProgressEvent.FileSkipped:
this.logger.info(`${skippedFiles.pop()} did not need to be updated`);
break;
case ProgressEvent.GitCommit:
this.logger.success("Git commit");
break;
case ProgressEvent.GitTag:
this.logger.success("Git tag");
break;
case ProgressEvent.GitPush:
this.logger.success("Git push");
break;
case ProgressEvent.NpmScript:
this.logger.success(`Npm run ${script}`);
break;
}
};
}
}
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
function normalizeWindowsPath(input = "") {
if (!input) {
return input;
}
return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
}
const _UNC_REGEX = /^[/\\]{2}/;
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
const normalize = function(path) {
if (path.length === 0) {
return ".";
}
path = normalizeWindowsPath(path);
const isUNCPath = path.match(_UNC_REGEX);
const isPathAbsolute = isAbsolute(path);
const trailingSeparator = path[path.length - 1] === "/";
path = normalizeString(path, !isPathAbsolute);
if (path.length === 0) {
if (isPathAbsolute) {
return "/";
}
return trailingSeparator ? "./" : ".";
}
if (trailingSeparator) {
path += "/";
}
if (_DRIVE_LETTER_RE.test(path)) {
path += "/";
}
if (isUNCPath) {
if (!isPathAbsolute) {
return `//./${path}`;
}
return `//${path}`;
}
return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
};
const join = function(...segments) {
let path = "";
for (const seg of segments) {
if (!seg) {
continue;
}
if (path.length > 0) {
const pathTrailing = path[path.length - 1] === "/";
const segLeading = seg[0] === "/";
const both = pathTrailing && segLeading;
if (both) {
path += seg.slice(1);
} else {
path += pathTrailing || segLeading ? seg : `/${seg}`;
}
} else {
path += seg;
}
}
return normalize(path);
};
function cwd() {
if (typeof process !== "undefined" && typeof process.cwd === "function") {
return process.cwd().replace(/\\/g, "/");
}
return "/";
}
const resolve = function(...arguments_) {
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
let resolvedPath = "";
let resolvedAbsolute = false;
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
const path = index >= 0 ? arguments_[index] : cwd();
if (!path || path.length === 0) {
continue;
}
resolvedPath = `${path}/${resolvedPath}`;
resolvedAbsolute = isAbsolute(path);
}
resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
return `/${resolvedPath}`;
}
return resolvedPath.length > 0 ? resolvedPath : ".";
};
function normalizeString(path, allowAboveRoot) {
let res = "";
let lastSegmentLength = 0;
let lastSlash = -1;
let dots = 0;
let char = null;
for (let index = 0; index <= path.length; ++index) {
if (index < path.length) {
char = path[index];
} else if (char === "/") {
break;
} else {
char = "/";
}
if (char === "/") {
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
if (res.length > 2) {
const lastSlashIndex = res.lastIndexOf("/");
if (lastSlashIndex === -1) {
res = "";
lastSegmentLength = 0;
} else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
}
lastSlash = index;
dots = 0;
continue;
} else if (res.length > 0) {
res = "";
lastSegmentLength = 0;
lastSlash = index;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
res += res.length > 0 ? "/.." : "..";
lastSegmentLength = 2;
}
} else {
if (res.length > 0) {
res += `/${path.slice(lastSlash + 1, index)}`;
} else {
res = path.slice(lastSlash + 1, index);
}
lastSegmentLength = index - lastSlash - 1;
}
lastSlash = index;
dots = 0;
} else if (char === "." && dots !== -1) {
++dots;
} else {
dots = -1;
}
}
return res;
}
const isAbsolute = function(p) {
return _IS_ABSOLUTE_RE.test(p);
};
function upperFirst(str) {
return str ? str[0].toUpperCase() + str.slice(1) : "";
}
const gitmojis = {
":art:": "\u{1F3A8}",
":zap:": "\u26A1\uFE0F",
":fire:": "\u{1F525}",
":bug:": "\u{1F41B}",
":ambulance:": "\u{1F691}\uFE0F",
":sparkles:": "\u2728",
":memo:": "\u{1F4DD}",
":rocket:": "\u{1F680}",
":lipstick:": "\u{1F484}",
":tada:": "\u{1F389}",
":white_check_mark:": "\u2705",
":lock:": "\u{1F512}\uFE0F",
":closed_lock_with_key:": "\u{1F510}",
":bookmark:": "\u{1F516}",
":rotating_light:": "\u{1F6A8}",
":construction:": "\u{1F6A7}",
":green_heart:": "\u{1F49A}",
":arrow_down:": "\u2B07\uFE0F",
":arrow_up:": "\u2B06\uFE0F",
":pushpin:": "\u{1F4CC}",
":construction_worker:": "\u{1F477}",
":chart_with_upwards_trend:": "\u{1F4C8}",
":recycle:": "\u267B\uFE0F",
":heavy_plus_sign:": "\u2795",
":heavy_minus_sign:": "\u2796",
":wrench:": "\u{1F527}",
":hammer:": "\u{1F528}",
":globe_with_meridians:": "\u{1F310}",
":pencil2:": "\u270F\uFE0F",
":pencil:": "\u270F\uFE0F",
":poop:": "\u{1F4A9}",
":rewind:": "\u23EA\uFE0F",
":twisted_rightwards_arrows:": "\u{1F500}",
":package:": "\u{1F4E6}\uFE0F",
":alien:": "\u{1F47D}\uFE0F",
":truck:": "\u{1F69A}",
":page_facing_up:": "\u{1F4C4}",
":boom:": "\u{1F4A5}",
":bento:": "\u{1F371}",
":wheelchair:": "\u267F\uFE0F",
":bulb:": "\u{1F4A1}",
":beers:": "\u{1F37B}",
":speech_balloon:": "\u{1F4AC}",
":card_file_box:": "\u{1F5C3}\uFE0F",
":loud_sound:": "\u{1F50A}",
":mute:": "\u{1F507}",
":busts_in_silhouette:": "\u{1F465}",
":children_crossing:": "\u{1F6B8}",
":building_construction:": "\u{1F3D7}\uFE0F",
":iphone:": "\u{1F4F1}",
":clown_face:": "\u{1F921}",
":egg:": "\u{1F95A}",
":see_no_evil:": "\u{1F648}",
":camera_flash:": "\u{1F4F8}",
":alembic:": "\u2697\uFE0F",
":mag:": "\u{1F50D}\uFE0F",
":label:": "\u{1F3F7}\uFE0F",
":seedling:": "\u{1F331}",
":triangular_flag_on_post:": "\u{1F6A9}",
":goal_net:": "\u{1F945}",
":dizzy:": "\u{1F4AB}",
":wastebasket:": "\u{1F5D1}\uFE0F",
":passport_control:": "\u{1F6C2}",
":adhesive_bandage:": "\u{1FA79}",
":monocle_face:": "\u{1F9D0}",
":coffin:": "\u26B0\uFE0F",
":test_tube:": "\u{1F9EA}",
":necktie:": "\u{1F454}",
":stethoscope:": "\u{1FA7A}",
":bricks:": "\u{1F9F1}",
":technologist:": "\u{1F9D1}\u200D\u{1F4BB}",
":money_with_wings:": "\u{1F4B8}",
":thread:": "\u{1F9F5}",
":safety_vest:": "\u{1F9BA}"
};
function convert(content, withSpace) {
const re = new RegExp(Object.keys(gitmojis).join("|"), "gi");
return content.replace(re, function(matched) {
switch (withSpace) {
case true:
case "trailing":
return `${gitmojis[matched.toLowerCase()]} `;
case "leading":
return ` ${gitmojis[matched.toLowerCase()]}`;
case "both":
return ` ${gitmojis[matched.toLowerCase()]} `;
default:
return gitmojis[matched.toLowerCase()];
}
});
}
const l=globalThis.fetch||(()=>{throw new Error("[node-fetch-native] Failed to fetch: `globalThis.fetch` is not available!")});
const m=Symbol.for("__confbox_fmt__"),k=/^(\s+)/,v=/(\s+)$/;function x$1(e,t={}){const n=t.indent===void 0&&t.preserveIndentation!==false&&e.slice(0,t?.sampleSize||1024),s=t.preserveWhitespace===false?void 0:{start:k.exec(e)?.[0]||"",end:v.exec(e)?.[0]||""};return {sample:n,whiteSpace:s}}function N$1(e,t,n){!t||typeof t!="object"||Object.defineProperty(t,m,{enumerable:false,configurable:true,writable:true,value:x$1(e,n)});}
function $(n,l=false){const g=n.length;let e=0,u="",p=0,k=16,A=0,o=0,O=0,B=0,b=0;function I(i,T){let s=0,c=0;for(;s<i;){let t=n.charCodeAt(e);if(t>=48&&t<=57)c=c*16+t-48;else if(t>=65&&t<=70)c=c*16+t-65+10;else if(t>=97&&t<=102)c=c*16+t-97+10;else break;e++,s++;}return s<i&&(c=-1),c}function V(i){e=i,u="",p=0,k=16,b=0;}function F(){let i=e;if(n.charCodeAt(e)===48)e++;else for(e++;e<n.length&&L(n.charCodeAt(e));)e++;if(e<n.length&&n.charCodeAt(e)===46)if(e++,e<n.length&&L(n.charCodeAt(e)))for(e++;e<n.length&&L(n.charCodeAt(e));)e++;else return b=3,n.substring(i,e);let T=e;if(e<n.length&&(n.charCodeAt(e)===69||n.charCodeAt(e)===101))if(e++,(e<n.length&&n.charCodeAt(e)===43||n.charCodeAt(e)===45)&&e++,e<n.length&&L(n.charCodeAt(e))){for(e++;e<n.length&&L(n.charCodeAt(e));)e++;T=e;}else b=3;return n.substring(i,T)}function a(){let i="",T=e;for(;;){if(e>=g){i+=n.substring(T,e),b=2;break}const s=n.charCodeAt(e);if(s===34){i+=n.substring(T,e),e++;break}if(s===92){if(i+=n.substring(T,e),e++,e>=g){b=2;break}switch(n.charCodeAt(e++)){case 34:i+='"';break;case 92:i+="\\";break;case 47:i+="/";break;case 98:i+="\b";break;case 102:i+="\f";break;case 110:i+=`
`;break;case 114:i+="\r";break;case 116:i+=" ";break;case 117:const t=I(4);t>=0?i+=String.fromCharCode(t):b=4;break;default:b=5;}T=e;continue}if(s>=0&&s<=31)if(r(s)){i+=n.substring(T,e),b=2;break}else b=6;e++;}return i}function w(){if(u="",b=0,p=e,o=A,B=O,e>=g)return p=g,k=17;let i=n.charCodeAt(e);if(J(i)){do e++,u+=String.fromCharCode(i),i=n.charCodeAt(e);while(J(i));return k=15}if(r(i))return e++,u+=String.fromCharCode(i),i===13&&n.charCodeAt(e)===10&&(e++,u+=`
`),A++,O=e,k=14;switch(i){case 123:return e++,k=1;case 125:return e++,k=2;case 91:return e++,k=3;case 93:return e++,k=4;case 58:return e++,k=6;case 44:return e++,k=5;case 34:return e++,u=a(),k=10;case 47:const T=e-1;if(n.charCodeAt(e+1)===47){for(e+=2;e<g&&!r(n.charCodeAt(e));)e++;return u=n.substring(T,e),k=12}if(n.charCodeAt(e+1)===42){e+=2;const s=g-1;let c=false;for(;e<s;){const t=n.charCodeAt(e);if(t===42&&n.charCodeAt(e+1)===47){e+=2,c=true;break}e++,r(t)&&(t===13&&n.charCodeAt(e)===10&&e++,A++,O=e);}return c||(e++,b=1),u=n.substring(T,e),k=13}return u+=String.fromCharCode(i),e++,k=16;case 45:if(u+=String.fromCharCode(i),e++,e===g||!L(n.charCodeAt(e)))return k=16;case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return u+=F(),k=11;default:for(;e<g&&v(i);)e++,i=n.charCodeAt(e);if(p!==e){switch(u=n.substring(p,e),u){case "true":return k=8;case "false":return k=9;case "null":return k=7}return k=16}return u+=String.fromCharCode(i),e++,k=16}}function v(i){if(J(i)||r(i))return false;switch(i){case 125:case 93:case 123:case 91:case 34:case 58:case 44:case 47:return false}return true}function j(){let i;do i=w();while(i>=12&&i<=15);return i}return {setPosition:V,getPosition:()=>e,scan:l?j:w,getToken:()=>k,getTokenValue:()=>u,getTokenOffset:()=>p,getTokenLength:()=>e-p,getTokenStartLine:()=>o,getTokenStartCharacter:()=>p-B,getTokenError:()=>b}}function J(n){return n===32||n===9}function r(n){return n===10||n===13}function L(n){return n>=48&&n<=57}var Q;((function(n){n[n.lineFeed=10]="lineFeed",n[n.carriageReturn=13]="carriageReturn",n[n.space=32]="space",n[n._0=48]="_0",n[n._1=49]="_1",n[n._2=50]="_2",n[n._3=51]="_3",n[n._4=52]="_4",n[n._5=53]="_5",n[n._6=54]="_6",n[n._7=55]="_7",n[n._8=56]="_8",n[n._9=57]="_9",n[n.a=97]="a",n[n.b=98]="b",n[n.c=99]="c",n[n.d=100]="d",n[n.e=101]="e",n[n.f=102]="f",n[n.g=103]="g",n[n.h=104]="h",n[n.i=105]="i",n[n.j=106]="j",n[n.k=107]="k",n[n.l=108]="l",n[n.m=109]="m",n[n.n=110]="n",n[n.o=111]="o",n[n.p=112]="p",n[n.q=113]="q",n[n.r=114]="r",n[n.s=115]="s",n[n.t=116]="t",n[n.u=117]="u",n[n.v=118]="v",n[n.w=119]="w",n[n.x=120]="x",n[n.y=121]="y",n[n.z=122]="z",n[n.A=65]="A",n[n.B=66]="B",n[n.C=67]="C",n[n.D=68]="D",n[n.E=69]="E",n[n.F=70]="F",n[n.G=71]="G",n[n.H=72]="H",n[n.I=73]="I",n[n.J=74]="J",n[n.K=75]="K",n[n.L=76]="L",n[n.M=77]="M",n[n.N=78]="N",n[n.O=79]="O",n[n.P=80]="P",n[n.Q=81]="Q",n[n.R=82]="R",n[n.S=83]="S",n[n.T=84]="T",n[n.U=85]="U",n[n.V=86]="V",n[n.W=87]="W",n[n.X=88]="X",n[n.Y=89]="Y",n[n.Z=90]="Z",n[n.asterisk=42]="asterisk",n[n.backslash=92]="backslash",n[n.closeBrace=125]="closeBrace",n[n.closeBracket=93]="closeBracket",n[n.colon=58]="colon",n[n.comma=44]="comma",n[n.dot=46]="dot",n[n.doubleQuote=34]="doubleQuote",n[n.minus=45]="minus",n[n.openBrace=123]="openBrace",n[n.openBracket=91]="openBracket",n[n.plus=43]="plus",n[n.slash=47]="slash",n[n.formFeed=12]="formFeed",n[n.tab=9]="tab";}))(Q||(Q={})),new Array(20).fill(0).map((n,l)=>" ".repeat(l));const N=200;new Array(N).fill(0).map((n,l)=>`
`+" ".repeat(l)),new Array(N).fill(0).map((n,l)=>"\r"+" ".repeat(l)),new Array(N).fill(0).map((n,l)=>`\r
`+" ".repeat(l)),new Array(N).fill(0).map((n,l)=>`
`+" ".repeat(l)),new Array(N).fill(0).map((n,l)=>"\r"+" ".repeat(l)),new Array(N).fill(0).map((n,l)=>`\r
`+" ".repeat(l));var U;(function(n){n.DEFAULT={allowTrailingComma:false};})(U||(U={}));function S(n,l=[],g=U.DEFAULT){let e=null,u=[];const p=[];function k(o){Array.isArray(u)?u.push(o):e!==null&&(u[e]=o);}return P(n,{onObjectBegin:()=>{const o={};k(o),p.push(u),u=o,e=null;},onObjectProperty:o=>{e=o;},onObjectEnd:()=>{u=p.pop();},onArrayBegin:()=>{const o=[];k(o),p.push(u),u=o,e=null;},onArrayEnd:()=>{u=p.pop();},onLiteralValue:k,onError:(o,O,B)=>{l.push({error:o,offset:O,length:B});}},g),u[0]}function P(n,l,g=U.DEFAULT){const e=$(n,false),u=[];let p=0;function k(f){return f?()=>p===0&&f(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>true}function A(f){return f?m=>p===0&&f(m,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter()):()=>true}function o(f){return f?m=>p===0&&f(m,e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>u.slice()):()=>true}function O(f){return f?()=>{p>0?p++:f(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter(),()=>u.slice())===false&&(p=1);}:()=>true}function B(f){return f?()=>{p>0&&p--,p===0&&f(e.getTokenOffset(),e.getTokenLength(),e.getTokenStartLine(),e.getTokenStartCharacter());}:()=>true}const b=O(l.onObjectBegin),I=o(l.onObjectProperty),V=B(l.onObjectEnd),F=O(l.onArrayBegin),a=B(l.onArrayEnd),w=o(l.onLiteralValue),v=A(l.onSeparator),j=k(l.onComment),i=A(l.onError),T=g&&g.disallowComments,s=g&&g.allowTrailingComma;function c(){for(;;){const f=e.scan();switch(e.getTokenError()){case 4:t(14);break;case 5:t(15);break;case 3:t(13);break;case 1:T||t(11);break;case 2:t(12);break;case 6:t(16);break}switch(f){case 12:case 13:T?t(10):j();break;case 16:t(1);break;case 15:case 14:break;default:return f}}}function t(f,m=[],y=[]){if(i(f),m.length+y.length>0){let _=e.getToken();for(;_!==17;){if(m.indexOf(_)!==-1){c();break}else if(y.indexOf(_)!==-1)break;_=c();}}}function D(f){const m=e.getTokenValue();return f?w(m):(I(m),u.push(m)),c(),true}function G(){switch(e.getToken()){case 11:const f=e.getTokenValue();let m=Number(f);isNaN(m)&&(t(2),m=0),w(m);break;case 7:w(null);break;case 8:w(true);break;case 9:w(false);break;default:return false}return c(),true}function M(){return e.getToken()!==10?(t(3,[],[2,5]),false):(D(false),e.getToken()===6?(v(":"),c(),E()||t(4,[],[2,5])):t(5,[],[2,5]),u.pop(),true)}function X(){b(),c();let f=false;for(;e.getToken()!==2&&e.getToken()!==17;){if(e.getToken()===5){if(f||t(4,[],[]),v(","),c(),e.getToken()===2&&s)break}else f&&t(6,[],[]);M()||t(4,[],[2,5]),f=true;}return V(),e.getToken()!==2?t(7,[2],[]):c(),true}function Y(){F(),c();let f=true,m=false;for(;e.getToken()!==4&&e.getToken()!==17;){if(e.getToken()===5){if(m||t(4,[],[]),v(","),c(),e.getToken()===4&&s)break}else m&&t(6,[],[]);f?(u.push(0),f=false):u[u.length-1]++,E()||t(4,[],[4,5]),m=true;}return a(),f||u.pop(),e.getToken()!==4?t(8,[4],[]):c(),true}function E(){switch(e.getToken()){case 3:return Y();case 1:return X();case 10:return D(true);default:return G()}}return c(),e.getToken()===17?g.allowEmptyContent?true:(t(4,[],[]),false):E()?(e.getToken()!==17&&t(9,[],[]),true):(t(4,[],[]),false)}var W;(function(n){n[n.None=0]="None",n[n.UnexpectedEndOfComment=1]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=2]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=3]="UnexpectedEndOfNumber",n[n.InvalidUnicode=4]="InvalidUnicode",n[n.InvalidEscapeCharacter=5]="InvalidEscapeCharacter",n[n.InvalidCharacter=6]="InvalidCharacter";})(W||(W={}));var H;(function(n){n[n.OpenBraceToken=1]="OpenBraceToken",n[n.CloseBraceToken=2]="CloseBraceToken",n[n.OpenBracketToken=3]="OpenBracketToken",n[n.CloseBracketToken=4]="CloseBracketToken",n[n.CommaToken=5]="CommaToken",n[n.ColonToken=6]="ColonToken",n[n.NullKeyword=7]="NullKeyword",n[n.TrueKeyword=8]="TrueKeyword",n[n.FalseKeyword=9]="FalseKeyword",n[n.StringLiteral=10]="StringLiteral",n[n.NumericLiteral=11]="NumericLiteral",n[n.LineCommentTrivia=12]="LineCommentTrivia",n[n.BlockCommentTrivia=13]="BlockCommentTrivia",n[n.LineBreakTrivia=14]="LineBreakTrivia",n[n.Trivia=15]="Trivia",n[n.Unknown=16]="Unknown",n[n.EOF=17]="EOF";})(H||(H={}));const K=S;var q;(function(n){n[n.InvalidSymbol=1]="InvalidSymbol",n[n.InvalidNumberFormat=2]="InvalidNumberFormat",n[n.PropertyNameExpected=3]="PropertyNameExpected",n[n.ValueExpected=4]="ValueExpected",n[n.ColonExpected=5]="ColonExpected",n[n.CommaExpected=6]="CommaExpected",n[n.CloseBraceExpected=7]="CloseBraceExpected",n[n.CloseBracketExpected=8]="CloseBracketExpected",n[n.EndOfFileExpected=9]="EndOfFileExpected",n[n.InvalidCommentToken=10]="InvalidCommentToken",n[n.UnexpectedEndOfComment=11]="UnexpectedEndOfComment",n[n.UnexpectedEndOfString=12]="UnexpectedEndOfString",n[n.UnexpectedEndOfNumber=13]="UnexpectedEndOfNumber",n[n.InvalidUnicode=14]="InvalidUnicode",n[n.InvalidEscapeCharacter=15]="InvalidEscapeCharacter",n[n.InvalidCharacter=16]="InvalidCharacter";})(q||(q={}));function x(n,l){const g=JSON.parse(n,l?.reviver);return N$1(n,g,l),g}function h(n,l){const g=K(n,l?.errors,l);return N$1(n,g,l),g}
const nodeBuiltins = [
"_http_agent",
"_http_client",
"_http_common",
"_http_incoming",
"_http_outgoing",
"_http_server",
"_stream_duplex",
"_stream_passthrough",
"_stream_readable",
"_stream_transform",
"_stream_wrap",
"_stream_writable",
"_tls_common",
"_tls_wrap",
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"inspector/promises",
"module",
"net",
"os",
"path",
"path/posix",
"path/win32",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"readline/promises",
"repl",
"stream",
"stream/consumers",
"stream/promises",
"stream/web",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"url",
"util",
"util/types",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib"
];
const own$1 = {}.hasOwnProperty;
const classRegExp = /^([A-Z][a-z\d]*)+$/;
const kTypes = /* @__PURE__ */ new Set([
"string",
"function",
"number",
"object",
// Accept 'Function' and 'Object' as alternative to the lower cased version.
"Function",
"Object",
"boolean",
"bigint",
"symbol"
]);
const messages = /* @__PURE__ */ new Map();
const nodeInternalPrefix = "__node_internal_";
let userStackTraceLimit;
function formatList(array, type = "and") {
return array.length < 3 ? array.join(` ${type} `) : `${array.slice(0, -1).join(", ")}, ${type} ${array.at(-1)}`;
}
function createError(sym, value, constructor) {
messages.set(sym, value);
return makeNodeErrorWithCode(constructor, sym);
}
function makeNodeErrorWithCode(Base, key) {
return function NodeError(...parameters) {
const limit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
const error = new Base();
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit;
const message = getMessage(key, parameters, error);
Object.defineProperties(error, {
// Note: no need to implement `kIsNodeError` symbol, would be hard,
// probably.
message: {
value: message,
enumerable: false,
writable: true,
configurable: true
},
toString: {
/** @this {Error} */
value() {
return `${this.name} [${key}]: ${this.message}`;
},
enumerable: false,
writable: true,
configurable: true
}
});
captur