zotero-plugin-scaffold
Version:
A scaffold for Zotero plugin development.
873 lines (863 loc) • 26.2 kB
text/typescript
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 };