UNPKG

zotero-plugin-scaffold

Version:
873 lines (863 loc) 26.2 kB
import { Hookable } from 'hookable'; import { BuildOptions } from 'esbuild'; /** * Log level enumeration */ declare enum LOG_LEVEL { TRACE = 0, DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4 } type LogLevelType = keyof typeof LOG_LEVEL; interface LoggerOptions { space?: number; newLine?: boolean; } declare class Logger { private static instance; private currentLogLevel; private constructor(); /** * Determine the appropriate log level */ private determineLogLevel; static getInstance(): Logger; setLogLevel(level: LogLevelType): void; get level(): LOG_LEVEL; /** * Generic log formatting logic */ private formatContent; private formatError; /** * Core logging method */ private logInternal; error(content: unknown, options?: LoggerOptions): void; warn(content: unknown, options?: LoggerOptions): void; tip(content: unknown, options?: LoggerOptions): void; info(content: unknown, options?: LoggerOptions): void; debug(content: unknown, options?: LoggerOptions): void; success(content: unknown, options?: LoggerOptions): void; fail(content: unknown, options?: LoggerOptions): void; ready(content: string): void; log(content: unknown, options?: LoggerOptions): void; clear(): void; newLine(): void; } interface GitCommitAuthor { name: string; email: string; } interface RawGitCommit { message: string; body: string; shortHash: string; author: GitCommitAuthor; } interface Reference { type: "hash" | "issue" | "pull-request"; value: string; } interface GitCommit extends RawGitCommit { description: string; type: string; scope: string; references: Reference[]; authors: GitCommitAuthor[]; isBreaking: boolean; } interface Manifest { [key: string]: any; manifest_version: number; name: string; version: string; description?: string; homepage_url?: string; author?: string; icons?: Record<string, string>; applications: { zotero: { id: string; update_url: string; strict_min_version?: string; strict_max_version?: string; }; }; } /** * Update json * @see https://extensionworkshop.com/documentation/manage/updating-your-extension/ */ interface UpdateJSON { addons: { [addonID: string]: { updates: Array<{ version: string; update_link?: string; /** * A cryptographic hash of the file pointed to by `update_link`. * This must be provided if `update_link` is not a secure URL. * If present, this must be a string beginning with either `sha256:` or `sha512:`, * followed by the hexadecimal-encoded hash of the matching type. */ update_hash?: string; applications: { zotero: { strict_min_version?: string; strict_max_version?: string; }; [application: string]: { strict_min_version?: string; strict_max_version?: string; }; }; }>; }; }; } interface Config { /** * Source root directory or directories for the plugin. * * These paths are: * - Watched during development to trigger rebuilds on changes. * - Used to remove the top-level asset directory (e.g. `assets/`) during build, * so that only its contents are copied directly to the output root. * * 插件的源码根目录(可为字符串或字符串数组)。 * * 用于以下两个目的: * - 在开发模式下监听这些目录,以便在文件变更时触发重建; * - 在构建阶段中,用于识别 assets 所在的顶层目录,以移除该目录本身,仅将其内容复制到输出目录的根部。 * * @example ["src", "addon"] * @default "src" */ source: string | string[]; /** * The files to ignore when watching. * * 忽略的监听文件。 * * @default [] */ watchIgnore: string | string[] | RegExp | RegExp[]; /** * The build directories. * * Scaffold will store the code before packaging after the build at `${dist}/addon`. * Store the packaging results at `${dist}/${package_json.name}.xpi`. * * 构建目录。 * * 脚手架将在 `${dist}/addon` 存放构建后打包前的代码。 * 在 `${dist}/${xpiName}.xpi` 存放打包结果。 * * @default ".scaffold/build" */ dist: string; /** * The name of plugin. * * 插件名。 * * @default package-json.name * */ name: string; /** * The ID of plugin. * * Usually in the form of an email address or UUID. * * 插件 ID。 * * 通常是邮箱地址或UUID的形式。 * * @default package-json.name */ id: string; /** * namespace of plugin. * * This attribute is also used to prevent plugin conflicts, * it may be used for plugin HTML element ids, preference prefixes, * fluent filename prefixes, fluent message prefixes, etc. * * Unlike the plugin id, this value should be HTML ID and Fluent Message compliant, * i.e.: contain at least one character and only letters and dashes. * * 插件命名空间。 * * 这个属性也用于防止插件冲突,它可能被用于插件的 HTML 元素 id, * 首选项前缀,Fluent 文件名前缀、Fluent message 前缀等。 * * 与插件 ID 不同的是,这个值应是符合 HTML ID 和 Fluent Message 规范的, * 即:至少包含一个字符,仅包含字母和短横线。 * * @default kebabCase(name) */ namespace: string; /** * XPI filename. * * XPI 文件名。 * * @default kebabCase(name) */ xpiName: string; /** * The download link of XPI. * * Some placeholders are available, see Context.templateData. * * XPI 文件的地址。 * * 一些可用的占位符请参阅 Context.templateData。 * * @default `https://github.com/{{owner}}/{{repo}}/release/download/v{{version}}/{{xpiName}}.xpi` * * @see {@link Context.templateData} */ xpiDownloadLink: string; /** * The uri of update.json. * * Some placeholders are available, see Context.templateData. * * update.json 文件的地址。 * * 一些可用的占位符请参阅 Context.templateData。 * * @default `https://github.com/{{owner}}/{{repo}}/releaser/download/release/{{updateJson}}` * * @see {@link Context.templateData} */ updateURL: string; /** * Configurations required to run the build. * * 构建所需的配置。 */ build: BuildConfig; /** * Configurations required to run the server. * * serve 所需的配置。 */ server: ServerConfig; /** * @todo Use addonLint package to lint XPI. */ addonLint: object; /** * Configurations required to run the release. * * 发布相关配置。 */ release: ReleaseConfig; /** * Configurations required to run the test. * * 测试相关配置。 * * Test is a variant of server, so it is not a separate hooks. */ test: TestConfig; /** * Level of the log. * * 日志等级。 * * @default "info" */ logLevel: LogLevelType; } interface BuildConfig { /** * The static assets. * * - Typically includes icons, ftl files, 3rd party JavaScript files, CSS files, XHTML files, etc. * - is an array of `glob` modes and supports negation modes. * - Do not add an entire directory unless it has no files to exclude. * * 静态资源文件。 * * - 通常包括图标、ftl 文件、第三方 JavaScript 文件、CSS 文件、XHTML 文件等。 * - 是一个 `glob` 模式数组,支持否定模式。 * - 除非一个目录没有需要排除的文件,否则不要添加整个目录。 * * @see {@link https://github.com/sindresorhus/globby?tab=readme-ov-file#globbing-patterns | Pattern syntax | 语法说明 } * * @example `["src/**\/*.*", "!src/**\/*.ts"]` (no `\`) * * @default "addon/**\/*.*" (no `\`) */ assets: string | string[]; /** * The placeholders to replace in static assets. * * - At build time, scaffolding uses the key of the placeholder to build the regular pattern `/__${key}__/g` and replaces matches with `value`. * - Replacement happens for all files under `assets`. * * 静态资源文本占位符。 * * - 在构建时,脚手架使用占位符的 key 建立正则模式 `/__${key}__/g`,并将匹配到的内容替换为 `value`。 * - 替换发生在 `assets` 下的所有文件。 * * @see {@link Context.templateData} */ define: { [key: string]: string; }; fluent: { /** * Add plugin namespace prefixes to all FTL files to avoid conflicts. * * The default prefix is `${namespace}-`. * * 为所有 FTL 文件添加插件前缀以避免冲突。 * * 默认前缀为 `${namespace}-`。 * * @default true */ prefixLocaleFiles: boolean; /** * Add plugin namespace prefixes to all FTL messages to avoid conflicts. * * The default prefix is `${namespace}-`. * * 为所有 FTL message 添加插件前缀以避免冲突。 * * 默认前缀为 `${namespace}-`。 * * @default true */ prefixFluentMessages: boolean; /** * Messages to ignore. * * 需要忽略的 Fluent Messages。 * * @default [] */ ignore: string[]; /** * Generate i10n.d.ts form fluent messages. * * - false: disable * - string: path of dts file * * 为 Fluent messages 生成类型声明文件。 * * - false: 禁用 * - string:dts 文件路径 * * @default 'typings/i10n.d.ts' */ dts: string | false; }; prefs: { /** * Prefixes the keys of preferences in `prefs.js` and * the value of the `preference` attribute in XHTML files. * * 为 `prefs.js` 中的首选项键和 XHTML 文件中的 `preference` 属性的值 * 添加前缀。 * * @default true */ prefixPrefKeys: boolean; /** * Prefixes for Preference Keys, no dot at the end. * * 首选项键的前缀,结尾不需要加点号。 * * @default 'extensions.${namespace}' */ prefix: string; /** * Generate prefs.d.ts form prefs.js. * * - false: disable * - string: path of dts file * * 为首选项生成类型声明文件。 * * - false: 禁用 * - string:dts 文件路径 * * @default 'typings/prefs.d.ts' */ dts: false | string; }; /** * Configurations of esbuild. * * Paths should be relative to the root directory of the project. * And if `outfile` and `outdir` not start with `dist`, * `dist/` will be automatically added as a prefix. * * esbuild 配置。 * * 路径应相对于项目根目录。 * 其中“outfile”和“outdir”若不以 `dist` 开头, * 则会自动添加 `dist/` 前缀。 * * @default [] * */ esbuildOptions: BuildOptions[]; /** * Make manifest.json. * */ makeManifest: { /** * 是否自动管理 manifest.json。 * 如果此项为 false,则开发者应自行准备 manifest.json。 * * @default true */ enable: boolean; /** * template of manifest. * * @deprecated * * @default * * ```json * { * manifest_version: 2, * name: "${name}", * version: "${version}", * applications: { * zotero: { * id: "${id}", * update_url: "${updateURL}", * strict_min_version: "6.999", * strict_max_version: "7.0.*", * }, * gecko: { * id: "${id}", * update_url: "${updateURL}", * strict_min_version: "102", * }; * }; * }; * ``` */ template: Manifest; }; /** * Make update manifest. * * 生成 `update.json`。 * */ makeUpdateJson: { /** * Historical update data. * * This can be useful if you need to distribute different plugin versions * for different versions of Zotero. * * 已有的更新数据。 * * 如果你需要为不同版本的 Zotero 分发不同的插件版本,这可能会很有用。 * * @see {@link https://www.zotero.org/support/dev/zotero_7_for_developers#updaterdf_updatesjson | Zotero 7 for developers} * @see {@link https://extensionworkshop.com/documentation/manage/updating-your-extension/ | Updating your extension} * @see {@link https://zotero-chinese.com/plugin-dev-guide/reference/update | 更新清单 (In chinese)} * * @default [] */ updates: UpdateJSON["addons"][string]["updates"]; /** * Whether or not to write the hash of the xpi file to update.json. * * 是否向 update.json 中写入 xpi 文件的 hash。 * * @default true */ hash: boolean; }; /** * The lifecycle hooks. */ hooks: Partial<BuildHooks>; } interface BuildHooks { "build:init": (ctx: Context) => void | Promise<void>; "build:mkdir": (ctx: Context) => void | Promise<void>; "build:copyAssets": (ctx: Context) => void | Promise<void>; "build:makeManifest": (ctx: Context) => void | Promise<void>; "build:fluent": (ctx: Context) => void | Promise<void>; "build:bundle": (ctx: Context) => void | Promise<void>; "build:pack": (ctx: Context) => void | Promise<void>; "build:makeUpdateJSON": (ctx: Context) => void | Promise<void>; "build:done": (ctx: Context) => void | Promise<void>; } interface ServerConfig { /** * Open devtool on Zotero start. * * 在 Zotero 启动时打开 devtool。 * * @default true */ devtools: boolean; /** * Additional command line arguments when starting Zotero. * * 启动 Zotero 时附加的命令行参数。 * * @default [] */ startArgs: string[]; /** * Install the plugin as a Proxy File mode. * * 以 Proxy File 方式载入插件 * * @default false */ asProxy: boolean; prebuild: boolean; createProfileIfMissing: boolean; /** * The lifecycle hook. */ hooks: Partial<ServeHooks>; } interface ServeHooks { "serve:init": (ctx: Context) => void | Promise<void>; "serve:prebuild": (ctx: Context) => void | Promise<void>; "serve:ready": (ctx: Context) => void | Promise<void>; "serve:onChanged": (ctx: Context, path: string) => void | Promise<void>; "serve:onReloaded": (ctx: Context) => void | Promise<void>; "serve:exit": (ctx: Context) => void; } interface ReleaseConfig { /** * Configurations of bumpp * * bumpp 包的部分配置。 */ bumpp: { /** * The release version or type. Can be one of the following: * * - A release type (e.g. "major", "minor", "patch", "prerelease", etc.) * - "prompt" to prompt the user for the version number * * In general, it is recommended to set this to “prompt”. * If you need a command that always releases a certain type, * you can override this option on the command line. * * 发布的类型,可以是以下其中之一: * * - 版本类型(如 “major”、“minor”、“patch”、“prerelease”等) * - “prompt” 以选择版本号 * * 通常来说,建议将此项设置为“prompt”。 * 如果需要一个始终发布某类型的命令,可以在命令行中覆盖该选项。 * * @default "prompt" */ release: string; /** * The prerelease type (e.g. "alpha", "beta", "next"). * * 预发布的类型,如 alpha,beta,next 等。 * * @default "beta" */ preid: string; /** * The commit message. * * Any `%s` placeholders in the message string will be replaced with the new version number. * If the message string does _not_ contain any `%s` placeholders, * then the new version number will be appended to the message. * * 提交说明模板。 * * 模板中的 `%s` 占位符将被替换为新版本号。 * 如果模板中不包含任何 `%s` 占位符,则新版本号将附加到模板末端。 * * @default "chore(publish): release %s" */ commit: string; /** * The tag template. * * Any `%s` placeholders in the tag string will be replaced with the new version number. * If the tag string does _not_ contain any `%s` placeholders, * then the new version number will be appended to the tag. * * 标签模板。 * * 模板中的 `%s` 占位符将被替换为新版本号。 * 如果模板中不包含任何 `%s` 占位符,则新版本号将附加到模板末端。 * * @default "v%s" */ tag: string; /** * Indicates whether the git commit should include ALL files (`git commit --all`) * rather than just the files that were modified by `versionBump()`. * * 表示 git 提交是否应包括所有文件(`git commit --all`), * 而不是只包含被 `versionBump()` 修改过的文件。 * * @default false * */ all: boolean; /** * Prompt for confirmation. * * 选择版本号后是否要求二次确认。 * * @default true */ confirm: boolean; /** * Indicates whether to bypass git commit hooks (`git commit --no-verify`). * * 表示是否绕过 git commit hooks(`git commit --no-verify` )。 * * @default false */ noVerify: boolean; /** * Excute additional command after bumping and before commiting. * * 在提升版本号之后,提交之前运行的额外命令。 * * @default "npm run build" * */ execute: string; }; /** * Changelog. * * - '': Use convention-based changelogs to generate changelogs grouped * by type when the first commit is a convention-based commit. * Otherwise, a list of commit messages. * - string: a command line with changelog output to stdout. * - function: a function that returns the changelog. * * 变更日志。 * * - "": 使用约定式变更日志,当第一次提交是约定式提交时,将按类型分组生成变更日志。 * 否则,则为提交消息的列表。 * - string: 命令行,变更日志输出到 stdout * - function: 一个函数,返回变更日志。 * * @default "" */ changelog: string | ((ctx: Context, commits: GitCommit[]) => string); /** * Release to GitHub. */ github: { /** * Enable release to GitHub. * * Include uploading XPI asset to GitHub release and all following steps. * * - "ci" to only enable in ci * - "local" to only enable in non-ci * - "always" to always enable * - "false" to always disable * * @default "ci" */ enable: "ci" | "local" | "always" | "false"; /** * The information of remote repository. * * Will be extracted from the `repository` property in `package.json` by default. * * @default {{owner}}/{{repo}} * @see {@link Context.templateData} */ repository: string; /** * Upload update.json to release. * * This is the tagName of the release when the value is a string. * * 将 update.json 上传到指定的 GitHub release。 * * 当值为字符串时,其为 release 的tagName。 * * @default "release" */ updater: string | false; /** * Comment to issues and prs inlcuded in release. * * @todo Not implemented yet * * @default false */ comment: boolean; releaseNote: (ctx: Context) => string; }; hooks: Partial<ReleaseHooks>; } interface ReleaseHooks { "release:init": (ctx: Context) => void | Promise<void>; "release:push": (ctx: Context) => void | Promise<void>; "release:done": (ctx: Context) => void | Promise<void>; } interface TestConfig { /** * The test source code directories, starting from the root directory of the project. * All `*.spec.js` files in these directories will be executed. * The files will be sorted by alphabetical order. * * 测试源码目录,从项目的根目录开始。 * 这些目录中的所有 `*.spec.js` 文件将被执行。 * 文件将按字母顺序排序。 * * @default "test" */ entries: string | string[]; /** * The default preferences for the test. * These preferences will be set before the test starts. * * 测试的默认首选项。 * 这些首选项将在测试开始前设置。 */ prefs: Record<string, string | boolean | number>; mocha: { /** * The timeout of the test. * * 测试的超时时间。 * * @default 10000 */ timeout: number; }; /** * Abort the test when the first test fails. * * 当第一个测试失败时中止测试。 * * @default false */ abortOnFail: boolean; /** * Watch source and test file changes, * and re-run tests when files change. * * If this set to false, Zotero will exit * when test complated. * * 当源码或测试代码变更时自动重新运行测试。 * * 若此选项设置为 false,Zotero 将在测试结束后立即退出。 * * @default true (false in ci) */ watch: boolean; /** * Run Zotero in deadless mode. * * - Supported for Linux only. * - Default to true when in CI environments. * * 使用无头模式运行 Zotero。 * * - 仅支持 Linux * - 在 CI 模式下,默认为 true * * @default false (true in ci) */ headless: boolean; /** * The delay time before running the test. Make sure the plugin is fully loaded before running the test. * * 运行测试前的延迟时间。确保插件在运行测试前完全加载。 * * @default 1000 */ startupDelay: number; /** * Function string that returns the initialization status of the plugin. * * If set, the test will wait until the function returns true before running the test. * * 返回插件初始化状态的函数字符串。 * * 如果设置,测试将等待函数返回 true 后再运行测试。 * * @default "() => true" * * @example * ```js * () => !!Zotero.BetterNotes.data.initialized * ``` */ waitForPlugin: string; hooks: Partial<TestHooks>; } interface TestHooks { "test:init": (ctx: Context) => void | Promise<void>; "test:prebuild": (ctx: Context) => void | Promise<void>; "test:bundleTests": (ctx: Context) => void | Promise<void>; "test:run": (ctx: Context) => void | Promise<void>; "test:exit": (ctx: Context) => void; } interface Hooks extends BuildHooks, ServeHooks, ReleaseHooks, TestHooks { } type RecursivePartial<T> = { [P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P]; }; /** * User config */ interface UserConfig extends RecursivePartial<Config> { } interface OverrideConfig extends RecursivePartial<Config> { } interface Context extends Config { pkgUser: any; version: string; hooks: Hookable<Hooks>; logger: Logger; templateData: TemplateData; } interface TemplateData { /** * `owner` and `repo` will be extracted from the `repository` property in `package.json`. */ owner: string; repo: string; version: string; isPreRelease: string; updateJson: "update-beta.json" | "update.json" | string; xpiName: string; buildTime: string; } declare abstract class Base { ctx: Context; constructor(ctx: Context); abstract run(): void | Promise<void>; abstract exit(): void; get logger(): Logger; } export { Base as B }; export type { Context as C, OverrideConfig as O, UserConfig as U };