feat: publish development scripts as independent npm packages (#109)
* feat!: use zotero-plugin-scaffold * fix: tsc error * docs: update readme and comment * fix: clean code, remove useless file * fix: update zotero-plugin-scaffold * fix: set esbuild target to ff115 * chore: clean and update deps * fix: Simplify config files and update dep * fix: update deps * chore: update renovate config * fix: default use proxy mode to install plugin * chore: bump scaffold to 0.0.19 resolve: #113 * fix: bump scaffold to 0.0.20 * fix: use new devtools hack
This commit is contained in:
		
							parent
							
								
									8b1c82681d
								
							
						
					
					
						commit
						0d76086064
					
				
							
								
								
									
										29
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								.env.example
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					# Usage: 
 | 
				
			||||||
 | 
					# Copy this file as `.env` and fill in the variables below as instructed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If you are developing more than one plugin, you can store the bin path and 
 | 
				
			||||||
 | 
					# profile path in the system environment variables, which can be omitted here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The path of the Zotero binary file.
 | 
				
			||||||
 | 
					# The path delimiter should be escaped as `\\` for win32. 
 | 
				
			||||||
 | 
					# The path is `*/Zotero.app/Contents/MacOS/zotero` for MacOS.
 | 
				
			||||||
 | 
					ZOTERO_PLUGIN_ZOTERO_BIN_PATH = /path/to/zotero.exe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The path of the profile used for development.
 | 
				
			||||||
 | 
					# Start the profile manager by `/path/to/zotero.exe -p` to create a profile for development.
 | 
				
			||||||
 | 
					# @see https://www.zotero.org/support/kb/profile_directory
 | 
				
			||||||
 | 
					ZOTERO_PLUGIN_PROFILE_PATH = /path/to/profile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The directory where the database is located.
 | 
				
			||||||
 | 
					# If this field is kept empty, Zotero will start with the default data.
 | 
				
			||||||
 | 
					# @see https://www.zotero.org/support/zotero_data
 | 
				
			||||||
 | 
					ZOTERO_PLUGIN_DATA_DIR =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Custom commands to kill Zotero processes.
 | 
				
			||||||
 | 
					# Commands for different platforms are already built into zotero-plugin, 
 | 
				
			||||||
 | 
					# if the built-in commands are not suitable for your needs, please modify this variable.
 | 
				
			||||||
 | 
					# ZOTERO_PLUGIN_KILL_COMMAND = 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# GitHub Token
 | 
				
			||||||
 | 
					# For release-it auto create release and upload assets
 | 
				
			||||||
 | 
					# GITHUB_TOKEN =
 | 
				
			||||||
							
								
								
									
										11
									
								
								.github/renovate.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/renovate.json
									
									
									
									
										vendored
									
									
								
							@ -7,11 +7,18 @@
 | 
				
			|||||||
    ":prConcurrentLimitNone",
 | 
					    ":prConcurrentLimitNone",
 | 
				
			||||||
    ":enableVulnerabilityAlerts",
 | 
					    ":enableVulnerabilityAlerts",
 | 
				
			||||||
    ":dependencyDashboard",
 | 
					    ":dependencyDashboard",
 | 
				
			||||||
    "schedule:weekends"
 | 
					    "group:allNonMajor",
 | 
				
			||||||
 | 
					    "schedule:weekly"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
					  "labels": ["dependencies"],
 | 
				
			||||||
  "packageRules": [
 | 
					  "packageRules": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "matchPackageNames": ["zotero-plugin-toolkit", "zotero-types"],
 | 
					      "matchPackageNames": [
 | 
				
			||||||
 | 
					        "zotero-plugin-toolkit",
 | 
				
			||||||
 | 
					        "zotero-types",
 | 
				
			||||||
 | 
					        "zotero-plugin-scaffold"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "schedule": ["at any time"],
 | 
				
			||||||
      "automerge": true
 | 
					      "automerge": true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@ -29,9 +29,19 @@ jobs:
 | 
				
			|||||||
      - name: Install deps
 | 
					      - name: Install deps
 | 
				
			||||||
        run: npm install
 | 
					        run: npm install
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Build
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          npm run build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Release to GitHub
 | 
					      - name: Release to GitHub
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          npm run release -- --no-increment --no-git --github.release --ci --VV
 | 
					          npm run release
 | 
				
			||||||
 | 
					          # cp build/update.json update.json
 | 
				
			||||||
 | 
					          # cp build/update-beta.json update-beta.json
 | 
				
			||||||
 | 
					          # git add update.json
 | 
				
			||||||
 | 
					          # git add update-beta.json
 | 
				
			||||||
 | 
					          # git commit -m 'chore(publish): synchronizing `update.json`'
 | 
				
			||||||
 | 
					          # git push
 | 
				
			||||||
          sleep 1s
 | 
					          sleep 1s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Notify release
 | 
					      - name: Notify release
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -5,4 +5,5 @@ package-lock.json
 | 
				
			|||||||
pnpm-lock.yaml
 | 
					pnpm-lock.yaml
 | 
				
			||||||
yarn.lock
 | 
					yarn.lock
 | 
				
			||||||
zotero-cmd.json
 | 
					zotero-cmd.json
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
 | 
					.env
 | 
				
			||||||
							
								
								
									
										36
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								README.md
									
									
									
									
									
								
							@ -65,12 +65,9 @@ If you are using this repo, I recommended that you put the following badge on yo
 | 
				
			|||||||
- Plugin develop/build/release workflow:
 | 
					- Plugin develop/build/release workflow:
 | 
				
			||||||
  - Automatically generate/update plugin id/version, update configrations, and set environment variables (`development` / `production`);
 | 
					  - Automatically generate/update plugin id/version, update configrations, and set environment variables (`development` / `production`);
 | 
				
			||||||
  - Automatically build and reload code in Zotero;
 | 
					  - Automatically build and reload code in Zotero;
 | 
				
			||||||
  - Automatically release to GitHub (using [release-it](https://github.com/release-it/release-it));
 | 
					  - Automatically release to GitHub;
 | 
				
			||||||
- Prettier and ES Lint integration.
 | 
					- Prettier and ES Lint integration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!warning]
 | 
					 | 
				
			||||||
> The localization system is upgraded (`dtd` is deprecated and we do not use `.properties` anymore). Only supports Zotero 7.0.0-beta.12 or higher now. If you want to support Zotero 6, you may need to use `dtd`, `properties`, and `ftl` at the same time. See the staled branch `zotero6-bootstrap`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Examples
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This repo provides examples for [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit) APIs.
 | 
					This repo provides examples for [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit) APIs.
 | 
				
			||||||
@ -178,8 +175,6 @@ Activate with `Shift+P`.
 | 
				
			|||||||
       addonRef: "", // e.g. Element ID prefix
 | 
					       addonRef: "", // e.g. Element ID prefix
 | 
				
			||||||
       addonInstance: "", // the plugin's root instance: Zotero.${addonInstance}
 | 
					       addonInstance: "", // the plugin's root instance: Zotero.${addonInstance}
 | 
				
			||||||
       prefsPrefix: "extensions.zotero.${addonRef}", // the prefix of prefs
 | 
					       prefsPrefix: "extensions.zotero.${addonRef}", // the prefix of prefs
 | 
				
			||||||
       releasePage: "", // URL to releases
 | 
					 | 
				
			||||||
       updateJSON: "", // URL to update.json
 | 
					 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   ```
 | 
					   ```
 | 
				
			||||||
@ -187,18 +182,20 @@ Activate with `Shift+P`.
 | 
				
			|||||||
   > [!warning]
 | 
					   > [!warning]
 | 
				
			||||||
   > Be careful to set the addonID and addonRef to avoid conflict.
 | 
					   > Be careful to set the addonID and addonRef to avoid conflict.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   If you need to host your XPI packages outside of GitHub, remove `releasePage` and add `updateLink` with the value set to your XPI download URL.
 | 
					   If you need to host your XPI packages outside of GitHub, moidify `updateURL` and add `xpiDownloadLink` in `zotero-plugin.config.ts`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. Copy zotero command line config file. Modify the commands that starts your installation of the beta Zotero.
 | 
					2. Copy the environment variable file. Modify the commands that starts your installation of the beta Zotero.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   > (Optional) Do this only once: Start the beta Zotero with `/path/to/zotero -p`. Create a new profile and use it as your development profile.
 | 
					   > Create a development profile (Optional)  
 | 
				
			||||||
   > Put the path of the profile into the `profilePath` in `zotero-cmd.json` to specify which profile to use.
 | 
					   > Start the beta Zotero with `/path/to/zotero -p`. Create a new profile and use it as your development profile. Do this only once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   ```sh
 | 
					   ```sh
 | 
				
			||||||
   cp ./scripts/zotero-cmd-template.json ./scripts/zotero-cmd.json
 | 
					   cp .env.example .env
 | 
				
			||||||
   vim ./scripts/zotero-cmd.json
 | 
					   vim .env
 | 
				
			||||||
   ```
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   If you are developing more than one plugin, you can store the bin path and profile path in the system environment variables, which can be omitted here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. Install dependencies with `npm install`
 | 
					3. Install dependencies with `npm install`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   > If you are using `pnpm` as the package manager for your project, you need to add `public-hoist-pattern[]=*@types/bluebird*` to `.npmrc`, see <https://github.com/windingwind/zotero-types?tab=readme-ov-file#usage>.
 | 
					   > If you are using `pnpm` as the package manager for your project, you need to add `public-hoist-pattern[]=*@types/bluebird*` to `.npmrc`, see <https://github.com/windingwind/zotero-types?tab=readme-ov-file#usage>.
 | 
				
			||||||
@ -209,7 +206,6 @@ Start development server with `npm start`, it will:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- Prebuild the plugin in development mode
 | 
					- Prebuild the plugin in development mode
 | 
				
			||||||
- Start Zotero with plugin loaded from `build/`
 | 
					- Start Zotero with plugin loaded from `build/`
 | 
				
			||||||
- Open devtool
 | 
					 | 
				
			||||||
- Watch `src/**` and `addon/**`.
 | 
					- Watch `src/**` and `addon/**`.
 | 
				
			||||||
  - If `src/**` changed, run esbuild and reload
 | 
					  - If `src/**` changed, run esbuild and reload
 | 
				
			||||||
  - If `addon/**` has changed, rebuild the plugin (in development mode) and reload
 | 
					  - If `addon/**` has changed, rebuild the plugin (in development mode) and reload
 | 
				
			||||||
@ -226,10 +222,7 @@ When file changes are detected in `src` or `addon`, the plugin will be automatic
 | 
				
			|||||||
<details style="text-indent: 2em">
 | 
					<details style="text-indent: 2em">
 | 
				
			||||||
<summary>💡 Steps to add this feature to an existing plugin</summary>
 | 
					<summary>💡 Steps to add this feature to an existing plugin</summary>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Copy `scripts/**.mjs`
 | 
					Please see [zotero-plugin-scaffold](https://github.com/northword/zotero-plugin-scaffold).
 | 
				
			||||||
2. Copy `server`, `build`, and `stop` commands in `package.json`
 | 
					 | 
				
			||||||
3. Run `npm install --save-dev chokidar`
 | 
					 | 
				
			||||||
4. Done.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
</details>
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -246,7 +239,7 @@ You can also:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Run `npm run build` to build the plugin in production mode, and the xpi for installation and the built code is under `build` folder.
 | 
					Run `npm run build` to build the plugin in production mode, and the xpi for installation and the built code is under `build` folder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Steps in `scripts/build.mjs`:
 | 
					Steps of build:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Create/empty `build/`.
 | 
					- Create/empty `build/`.
 | 
				
			||||||
- Copy `addon/**` to `build/addon/**`
 | 
					- Copy `addon/**` to `build/addon/**`
 | 
				
			||||||
@ -254,7 +247,7 @@ Steps in `scripts/build.mjs`:
 | 
				
			|||||||
- Prepare locale files to [avoid conflict](https://www.zotero.org/support/dev/zotero_7_for_developers#avoiding_localization_conflicts)
 | 
					- Prepare locale files to [avoid conflict](https://www.zotero.org/support/dev/zotero_7_for_developers#avoiding_localization_conflicts)
 | 
				
			||||||
  - Rename `**/*.flt` to `**/${addonRef}-*.flt`
 | 
					  - Rename `**/*.flt` to `**/${addonRef}-*.flt`
 | 
				
			||||||
  - Prefix each fluent message with `addonRef-`
 | 
					  - Prefix each fluent message with `addonRef-`
 | 
				
			||||||
- Use Esbuild to build `.ts` source code to `.js`, build `src/index.ts` to `./build/addon/chrome/content/scripts`.
 | 
					- Use ESBuild to build `.ts` source code to `.js`, build `src/index.ts` to `./build/addon/chrome/content/scripts`.
 | 
				
			||||||
- (Production mode only) Zip the `./build/addon` to `./build/*.xpi`
 | 
					- (Production mode only) Zip the `./build/addon` to `./build/*.xpi`
 | 
				
			||||||
- (Production mode only) Prepare `update.json` or `update-beta.json`
 | 
					- (Production mode only) Prepare `update.json` or `update-beta.json`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -271,15 +264,14 @@ Steps in `scripts/build.mjs`:
 | 
				
			|||||||
To build and release, use
 | 
					To build and release, use
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
# A release-it command: version increase, npm run build, git push, and GitHub release
 | 
					# version increase, git add, commit and push
 | 
				
			||||||
# release-it: https://github.com/release-it/release-it
 | 
					# then on ci, npm run build, and release to GitHub
 | 
				
			||||||
npm run release
 | 
					npm run release
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!note]
 | 
					> [!note]
 | 
				
			||||||
> In this template, release-it is configured to locally bump the version, build, and push commits and git.tags, subsequently GitHub Action will rebuild the plugin and publish the XPI to GitHub Release.
 | 
					> In this template, release-it is configured to locally bump the version, build, and push commits and git.tags, subsequently GitHub Action will rebuild the plugin and publish the XPI to GitHub Release.
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
> If you need to release a locally built XPI, set `release-it.github.release` to `true` in `package.json` and remove `.github/workflows/release.yml`. Besides that, you need to set the environment variable `GITHUB_TOKEN`, get it in <https://github.com/settings/tokens>.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### About Prerelease
 | 
					#### About Prerelease
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -57,18 +57,15 @@
 | 
				
			|||||||
- 事件驱动、函数式编程的可扩展框架;
 | 
					- 事件驱动、函数式编程的可扩展框架;
 | 
				
			||||||
- 简单易用,开箱即用;
 | 
					- 简单易用,开箱即用;
 | 
				
			||||||
- ⭐[新特性!]自动热重载!每当修改源码时,都会自动编译并重新加载插件;[详情请跳转→](#自动热重载)
 | 
					- ⭐[新特性!]自动热重载!每当修改源码时,都会自动编译并重新加载插件;[详情请跳转→](#自动热重载)
 | 
				
			||||||
- `src/modules/examples.ts` 中有丰富的示例,涵盖了插件中常用的大部分API (使用的插件工具包 zotero-plugin-toolkit,仓库地址 https://github.com/windingwind/zotero-plugin-toolkit);
 | 
					- `src/modules/examples.ts` 中有丰富的示例,涵盖了插件中常用的大部分API (使用 [zotero-plugin-toolkit](https://github.com/windingwind/zotero-plugin-toolkit);
 | 
				
			||||||
- TypeScript 支持:
 | 
					- TypeScript 支持:
 | 
				
			||||||
  - 为使用 JavaScript 编写的Zotero源码提供全面的类型定义支持 (使用类型定义包 zotero-types,仓库地址 https://github.com/windingwind/zotero-types);
 | 
					  - 为使用 JavaScript 编写的 Zotero 源码提供全面的类型定义支持 (使用 [zotero-types](https://github.com/windingwind/zotero-types));
 | 
				
			||||||
  - 全局变量和环境设置;
 | 
					  - 全局变量和环境设置;
 | 
				
			||||||
- 插件开发/构建/发布工作流:
 | 
					- 插件开发/构建/发布工作流:
 | 
				
			||||||
  - 自动生成/更新插件id和版本、更新配置和设置环境变量 (`development`/`production`);
 | 
					  - 自动生成/更新插件版本、更新配置和设置环境变量 (`development`/`production`);
 | 
				
			||||||
  - 自动在 Zotero 中构建和重新加载代码;
 | 
					  - 自动在 Zotero 中构建和重新加载代码;
 | 
				
			||||||
  - 自动发布到GitHub (使用[release-it](https://github.com/release-it/release-it));
 | 
					  - 自动发布到 GitHub ;
 | 
				
			||||||
- 集成Prettier和ES Lint;
 | 
					- 集成 Prettier 和 ES Lint;
 | 
				
			||||||
 | 
					 | 
				
			||||||
> [!warning]
 | 
					 | 
				
			||||||
> Zotero本地化已升级(`dtd` 已弃用,我们将不再使用 `.properties`). 主分支将只支持 Zotero 7.0.0-beta.12 或更高版本. 如果需要支持 Zotero 6,你可能需要同时使用`dtd`、`properties` 和`ftl`. 请参考此库的 `zotero6-bootstrap` 分支.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Examples 示例
 | 
					## Examples 示例
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -133,15 +130,15 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- registerAlertPromptExample
 | 
					- registerAlertPromptExample
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Quick Start Guide 快速入门指南
 | 
					## 快速上手
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 0 前置要求(Requirement)
 | 
					### 0 环境要求
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. 安装测试版 Zotero:https://www.zotero.org/support/beta_builds
 | 
					1. 安装 [beta 版 Zotero](https://www.zotero.org/support/beta_builds)
 | 
				
			||||||
2. 安装 Node.js(https://nodejs.org/en/)和 Git(https://git-scm.com/)
 | 
					2. 安装 [Node.js](https://nodejs.org/en/) 和 [Git](https://git-scm.com/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!note]
 | 
					> [!note]
 | 
				
			||||||
> 本指南假定你已经对 Zotero 插件的基本结构和工作原理有初步的了解. 如果你还不了解,请先参考官方文档(https://www.zotero.org/support/dev/zotero_7_for_developers)和官方插件样例 Make It Red(仓库地址 https://github.com/zotero/make-it-red).
 | 
					> 本指南假定你已经对 Zotero 插件的基本结构和工作原理有初步的了解. 如果你还不了解,请先参考[官方文档](https://www.zotero.org/support/dev/zotero_7_for_developers) 和[官方插件样例 Make It Red](https://github.com/zotero/make-it-red)。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 1 创建你的仓库(Create Your Repo)
 | 
					### 1 创建你的仓库(Create Your Repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -167,18 +164,16 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
   ```json5
 | 
					   ```json5
 | 
				
			||||||
   {
 | 
					   {
 | 
				
			||||||
     version: "", // to 0.0.0
 | 
					     version: "", // 修改为 0.0.0
 | 
				
			||||||
     author: "",
 | 
					     author: "",
 | 
				
			||||||
     description: "",
 | 
					     description: "",
 | 
				
			||||||
     homepage: "",
 | 
					     homepage: "",
 | 
				
			||||||
     config: {
 | 
					     config: {
 | 
				
			||||||
       addonName: "", // name to be displayed in the plugin manager
 | 
					       addonName: "", // 插件名称
 | 
				
			||||||
       addonID: "", // ID to avoid conflict. IMPORTANT!
 | 
					       addonID: "", // 插件 ID 【重要:防止冲突】
 | 
				
			||||||
       addonRef: "", // e.g. Element ID prefix
 | 
					       addonRef: "", // 插件命名空间:元素前缀等
 | 
				
			||||||
       addonInstance: "", // the plugin's root instance: Zotero.${addonInstance}
 | 
					       addonInstance: "", // 注册在 Zotero 根下的实例名
 | 
				
			||||||
       prefsPrefix: "extensions.zotero.${addonRef}", // the prefix of prefs
 | 
					       prefsPrefix: "extensions.zotero.${addonRef}", // 首选项的前缀
 | 
				
			||||||
       releasePage: "", // URL to releases
 | 
					 | 
				
			||||||
       updateJSON: "", // URL to update.json
 | 
					 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   ```
 | 
					   ```
 | 
				
			||||||
@ -186,23 +181,26 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
   > [!warning]
 | 
					   > [!warning]
 | 
				
			||||||
   > 注意设置 addonID 和 addonRef 以避免冲突.
 | 
					   > 注意设置 addonID 和 addonRef 以避免冲突.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果你需要在GitHub以外的地方托管你的 XPI 包,请删除 `releasePage` 并添加 `updateLink`,并将值设置为你的 XPI 下载地址.
 | 
					    如果你需要在 GitHub 以外的地方托管你的 XPI 包,请修改 `zotero-plugin.config.ts` 中的 `updateURL` 和 `xpiDownloadLink`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. 复制 Zotero 启动配置,填入 Zotero 可执行文件路径和 profile 路径.
 | 
					2. 复制 Zotero 启动配置,填入 Zotero 可执行文件路径和 profile 路径.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   > (可选项) 此操作仅需执行一次: 使用 `/path/to/zotero -p` 启动 Zotero,创建一个新的配置文件并用作开发配置文件.
 | 
					   > (可选项) 创建开发用 profile 目录:
 | 
				
			||||||
   > 将配置文件的路径 `profilePath` 放入 `zotero-cmd.json` 中,以指定要使用的配置文件.
 | 
					   >
 | 
				
			||||||
 | 
					   > 此操作仅需执行一次: 使用 `/path/to/zotero -p` 启动 Zotero,创建一个新的配置文件并用作开发配置文件。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   ```sh
 | 
					   ```sh
 | 
				
			||||||
   cp ./scripts/zotero-cmd-template.json ./scripts/zotero-cmd.json
 | 
					   cp .env.example .env
 | 
				
			||||||
   vim ./scripts/zotero-cmd.json
 | 
					   vim .env
 | 
				
			||||||
   ```
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   如果你维护了多个插件,可以将这些内容存入系统环境变量,以避免在每个插件中都需要重复设置。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. 运行 `npm install` 以安装相关依赖
 | 
					3. 运行 `npm install` 以安装相关依赖
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   > 如果你使用 `pnpm` 作为包管理器,你需要添加 `public-hoist-pattern[]=*@types/bluebird*` 到`.npmrc`, 详情请查看 zotero-types(https://github.com/windingwind/zotero-types?tab=readme-ov-file#usage)的文档.
 | 
					   > 如果你使用 `pnpm` 作为包管理器,你需要添加 `public-hoist-pattern[]=*@types/bluebird*` 到`.npmrc`, 详情请查看 zotero-types(<https://github.com/windingwind/zotero-types?tab=readme-ov-file#usage)的文档>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 3 开始开发(Coding)
 | 
					### 3 开发插件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
使用 `npm start` 启动开发服务器,它将:
 | 
					使用 `npm start` 启动开发服务器,它将:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -225,14 +223,11 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
<details style="text-indent: 2em">
 | 
					<details style="text-indent: 2em">
 | 
				
			||||||
<summary>💡 将此功能添加到现有插件的步骤</summary>
 | 
					<summary>💡 将此功能添加到现有插件的步骤</summary>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. 复制 `scripts/**.mjs`
 | 
					请参阅:[zotero-plugin-scaffold](https://github.com/northword/zotero-plugin-scaffold)。
 | 
				
			||||||
2. 复制 `server` 、`build` 和 `stop` 命令到 `package.json`
 | 
					 | 
				
			||||||
3. 运行 `npm install --save-dev chokidar`
 | 
					 | 
				
			||||||
4. 结束.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
</details>
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 在 Zotero 中 Debug
 | 
					#### 调试代码
 | 
				
			||||||
 | 
					
 | 
				
			||||||
你还可以:
 | 
					你还可以:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -244,16 +239,16 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  > XUL 文档: <http://www.devdoc.net/web/developer.mozilla.org/en-US/docs/XUL.html>
 | 
					  > XUL 文档: <http://www.devdoc.net/web/developer.mozilla.org/en-US/docs/XUL.html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 4 构建(Build)
 | 
					### 4 构建插件
 | 
				
			||||||
 | 
					
 | 
				
			||||||
运行 `npm run build` 在生产模式下构建插件,构建的结果位于 `build/` 目录中.
 | 
					运行 `npm run build` 在生产模式下构建插件,构建的结果位于 `build/` 目录中.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
`scripts/build.mjs` 的运行步骤:
 | 
					构建步骤:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- 创建/清空 `build/`
 | 
					- 创建/清空 `build/`
 | 
				
			||||||
- 复制 `addon/**` 到 `build/addon/**`
 | 
					- 复制 `addon/**` 到 `build/addon/**`
 | 
				
			||||||
- 替换占位符:使用 `replace-in-file` 去替换在 `package.json` 中定义的关键字和配置 (`xhtml`、`.flt` 等)
 | 
					- 替换占位符:使用 `replace-in-file` 去替换在 `package.json` 中定义的关键字和配置 (`xhtml`、`.flt` 等)
 | 
				
			||||||
- 准备本地化文件以避免冲突,查看官方文档了解更多(https://www.zotero.org/support/dev/zotero_7_for_developers#avoiding_localization_conflicts)
 | 
					- 准备本地化文件以避免冲突,查看官方文档了解更多(<https://www.zotero.org/support/dev/zotero_7_for_developers#avoiding_localization_conflicts)>
 | 
				
			||||||
  - 重命名`**/*.flt` 为 `**/${addonRef}-*.flt`
 | 
					  - 重命名`**/*.flt` 为 `**/${addonRef}-*.flt`
 | 
				
			||||||
  - 在每个消息前加上 `addonRef-`
 | 
					  - 在每个消息前加上 `addonRef-`
 | 
				
			||||||
- 使用 Esbuild 来将 `.ts` 源码构建为 `.js`,从 `src/index.ts` 构建到`./build/addon/chrome/content/scripts`
 | 
					- 使用 Esbuild 来将 `.ts` 源码构建为 `.js`,从 `src/index.ts` 构建到`./build/addon/chrome/content/scripts`
 | 
				
			||||||
@ -268,27 +263,25 @@ Obsidian风格的指令输入模块,它通过接受文本来运行插件,并
 | 
				
			|||||||
> - 你可以根据此变量决定用户无法查看/使用的内容.
 | 
					> - 你可以根据此变量决定用户无法查看/使用的内容.
 | 
				
			||||||
> - 在生产模式下,构建脚本将自动打包插件并更新 `update.json`.
 | 
					> - 在生产模式下,构建脚本将自动打包插件并更新 `update.json`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 5 发布(Release)
 | 
					### 5 发布
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如果要构建和发布插件,运行如下指令:
 | 
					如果要构建和发布插件,运行如下指令:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```shell
 | 
					```shell
 | 
				
			||||||
# A release-it command: version increase, npm run build, git push, and GitHub release
 | 
					# version increase, git add, commit and push
 | 
				
			||||||
# release-it: https://github.com/release-it/release-it
 | 
					# then on ci, npm run build, and release to GitHub
 | 
				
			||||||
npm run release
 | 
					npm run release
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!note]
 | 
					> [!note]
 | 
				
			||||||
> 在此模板中,release-it 被配置为在本地升级版本、构建、推送提交和 git 标签,随后GitHub Action 将重新构建插件并将 XPI 发布到 GitHub Release.
 | 
					> 在此模板中,release-it 被配置为在本地更新版本号、提交并推送标签,随后 GitHub Action 将重新构建插件并将 XPI 发布到 GitHub Release.
 | 
				
			||||||
>
 | 
					 | 
				
			||||||
> 如果你需要发布一个本地构建的 XPI,将 `package.json` 中的 `release-it.github.release` 设置为 `true`,然后移除 `.github/workflows/release.yml`. 此外,你还需要设置环境变量 `GITHUB_TOKEN`,获取 GitHub Token(https://github.com/settings/tokens).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 关于预发布
 | 
					#### 关于预发布
 | 
				
			||||||
 | 
					
 | 
				
			||||||
该模板将 `prerelease` 定义为插件的测试版,当你在 release-it 中选择 `prerelease` 版本 (版本号中带有 `-` ),构建脚本将创建一个 `update-beta.json` 给预发布版本使用,这将确保常规版本的用户不会自动更新到测试版,只有手动下载并安装了测试版的用户才能自动更新到下一个测试版. 当下一个正式版本更新时,脚本将同步更新 `update.json` 和 `update-beta.json`,这将使正式版和测试版用户都可以更新到最新的正式版.
 | 
					该模板将 `prerelease` 定义为插件的测试版,当你在 release-it 中选择 `prerelease` 版本 (版本号中带有 `-` ),构建脚本将创建一个 `update-beta.json` 给预发布版本使用,这将确保常规版本的用户不会自动更新到测试版,只有手动下载并安装了测试版的用户才能自动更新到下一个测试版. 当下一个正式版本更新时,脚本将同步更新 `update.json` 和 `update-beta.json`,这将使正式版和测试版用户都可以更新到最新的正式版.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> [!warning]
 | 
					> [!warning]
 | 
				
			||||||
> 严格来说,区分 Zotero 6 和 Zotero 7 兼容的插件版本应该通过 `update.json` 的 `addons.__addonID__.updates[]` 中分别配置 `applications.zotero.strict_min_version`,这样 Zotero 才能正确识别,详情在 Zotero 7 开发文档(https://www.zotero.org/support/dev/zotero_7_for_developers#updaterdf_updatesjson)获取.
 | 
					> 严格来说,区分 Zotero 6 和 Zotero 7 兼容的插件版本应该通过 `update.json` 的 `addons.__addonID__.updates[]` 中分别配置 `applications.zotero.strict_min_version`,这样 Zotero 才能正确识别,详情在 Zotero 7 开发文档(<https://www.zotero.org/support/dev/zotero_7_for_developers#updaterdf_updatesjson)获取>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Details 更多细节
 | 
					## Details 更多细节
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -333,7 +326,7 @@ createElement(document, "button", { namespace: "xul" }); // manually set namespa
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### 关于 Zotero API(About Zotero API)
 | 
					### 关于 Zotero API(About Zotero API)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Zotero 文档已过时且不完整,克隆 https://github.com/zotero/zotero 并全局搜索关键字.
 | 
					Zotero 文档已过时且不完整,克隆 <https://github.com/zotero/zotero> 并全局搜索关键字.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> ⭐[zotero-types](https://github.com/windingwind/zotero-types) 提供了最常用的 Zotero API,在默认情况下它被包含在此模板中. 你的 IDE 将为大多数的 API 提供提醒.
 | 
					> ⭐[zotero-types](https://github.com/windingwind/zotero-types) 提供了最常用的 Zotero API,在默认情况下它被包含在此模板中. 你的 IDE 将为大多数的 API 提供提醒.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										58
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								package.json
									
									
									
									
									
								
							@ -7,47 +7,39 @@
 | 
				
			|||||||
    "addonID": "addontemplate@euclpts.com",
 | 
					    "addonID": "addontemplate@euclpts.com",
 | 
				
			||||||
    "addonRef": "addontemplate",
 | 
					    "addonRef": "addontemplate",
 | 
				
			||||||
    "addonInstance": "AddonTemplate",
 | 
					    "addonInstance": "AddonTemplate",
 | 
				
			||||||
    "prefsPrefix": "extensions.zotero.addontemplate",
 | 
					    "prefsPrefix": "extensions.zotero.addontemplate"
 | 
				
			||||||
    "releasePage": "https://github.com/windingwind/zotero-addon-template/releases",
 | 
					 | 
				
			||||||
    "updateJSON": "https://raw.githubusercontent.com/windingwind/zotero-addon-template/main/update.json"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "main": "src/index.ts",
 | 
					 | 
				
			||||||
  "scripts": {
 | 
					 | 
				
			||||||
    "start": "node scripts/server.mjs",
 | 
					 | 
				
			||||||
    "build": "tsc --noEmit && node scripts/build.mjs production",
 | 
					 | 
				
			||||||
    "stop": "node scripts/stop.mjs",
 | 
					 | 
				
			||||||
    "lint": "prettier --write . && eslint . --ext .ts --fix",
 | 
					 | 
				
			||||||
    "test": "echo \"Error: no test specified\" && exit 1",
 | 
					 | 
				
			||||||
    "release": "release-it --only-version --preReleaseId=beta",
 | 
					 | 
				
			||||||
    "update-deps": "npm update --save"
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repository": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
    "url": "git+https://github.com/windingwind/zotero-addon-template.git"
 | 
					    "url": "git+https://github.com/windingwind/zotero-addon-template.git"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "author": "windingwind",
 | 
					  "author": "windingwind",
 | 
				
			||||||
  "license": "AGPL-3.0-or-later",
 | 
					 | 
				
			||||||
  "bugs": {
 | 
					  "bugs": {
 | 
				
			||||||
    "url": "https://github.com/windingwind/zotero-addon-template/issues"
 | 
					    "url": "https://github.com/windingwind/zotero-addon-template/issues"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "homepage": "https://github.com/windingwind/zotero-addon-template#readme",
 | 
					  "homepage": "https://github.com/windingwind/zotero-addon-template#readme",
 | 
				
			||||||
 | 
					  "license": "AGPL-3.0-or-later",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "start": "zotero-plugin serve",
 | 
				
			||||||
 | 
					    "build": "tsc --noEmit && zotero-plugin build",
 | 
				
			||||||
 | 
					    "lint": "prettier --write . && eslint . --ext .ts --fix",
 | 
				
			||||||
 | 
					    "release": "zotero-plugin release",
 | 
				
			||||||
 | 
					    "test": "echo \"Error: no test specified\" && exit 1",
 | 
				
			||||||
 | 
					    "update-deps": "npm update --save"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "zotero-plugin-toolkit": "^2.3.30"
 | 
					    "zotero-plugin-toolkit": "^2.3.31"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@types/node": "^20.12.8",
 | 
					    "@types/node": "^20.12.12",
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^7.8.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^7.9.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^7.8.0",
 | 
					    "@typescript-eslint/parser": "^7.9.0",
 | 
				
			||||||
    "chokidar": "^3.6.0",
 | 
					 | 
				
			||||||
    "compressing": "^1.10.0",
 | 
					 | 
				
			||||||
    "esbuild": "^0.20.2",
 | 
					 | 
				
			||||||
    "eslint": "^8.57.0",
 | 
					    "eslint": "^8.57.0",
 | 
				
			||||||
    "eslint-config-prettier": "^9.1.0",
 | 
					    "eslint-config-prettier": "^9.1.0",
 | 
				
			||||||
    "prettier": "^3.2.5",
 | 
					    "prettier": "^3.2.5",
 | 
				
			||||||
    "release-it": "^17.2.1",
 | 
					 | 
				
			||||||
    "replace-in-file": "^7.1.0",
 | 
					 | 
				
			||||||
    "typescript": "^5.4.5",
 | 
					    "typescript": "^5.4.5",
 | 
				
			||||||
    "zotero-types": "^2.0.0"
 | 
					    "zotero-plugin-scaffold": "^0.0.21",
 | 
				
			||||||
 | 
					    "zotero-types": "^1.3.24"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "eslintConfig": {
 | 
					  "eslintConfig": {
 | 
				
			||||||
    "env": {
 | 
					    "env": {
 | 
				
			||||||
@ -113,23 +105,5 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "release-it": {
 | 
					 | 
				
			||||||
    "git": {
 | 
					 | 
				
			||||||
      "tagName": "v${version}"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "npm": {
 | 
					 | 
				
			||||||
      "publish": false
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "github": {
 | 
					 | 
				
			||||||
      "release": false,
 | 
					 | 
				
			||||||
      "assets": [
 | 
					 | 
				
			||||||
        "build/*.xpi"
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    "hooks": {
 | 
					 | 
				
			||||||
      "before:init": "npm run lint",
 | 
					 | 
				
			||||||
      "after:bump": "npm run build"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,243 +0,0 @@
 | 
				
			|||||||
import details from "../package.json" with { type: "json" };
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  Logger,
 | 
					 | 
				
			||||||
  clearFolder,
 | 
					 | 
				
			||||||
  copyFileSync,
 | 
					 | 
				
			||||||
  copyFolderRecursiveSync,
 | 
					 | 
				
			||||||
  dateFormat,
 | 
					 | 
				
			||||||
} from "./utils.mjs";
 | 
					 | 
				
			||||||
import { zip } from "compressing";
 | 
					 | 
				
			||||||
import { build } from "esbuild";
 | 
					 | 
				
			||||||
import { existsSync, readdirSync, renameSync } from "fs";
 | 
					 | 
				
			||||||
import path from "path";
 | 
					 | 
				
			||||||
import { env, exit } from "process";
 | 
					 | 
				
			||||||
import replaceInFile from "replace-in-file";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { replaceInFileSync } = replaceInFile;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
process.env.NODE_ENV =
 | 
					 | 
				
			||||||
  process.argv[2] === "production" ? "production" : "development";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const buildDir = "build";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { name, author, description, homepage, version, config } = details;
 | 
					 | 
				
			||||||
const isPreRelease = version.includes("-");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function replaceString(buildTime) {
 | 
					 | 
				
			||||||
  const replaceFrom = [
 | 
					 | 
				
			||||||
    /__author__/g,
 | 
					 | 
				
			||||||
    /__description__/g,
 | 
					 | 
				
			||||||
    /__homepage__/g,
 | 
					 | 
				
			||||||
    /__buildVersion__/g,
 | 
					 | 
				
			||||||
    /__buildTime__/g,
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
  const replaceTo = [author, description, homepage, version, buildTime];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  config.updateURL = isPreRelease
 | 
					 | 
				
			||||||
    ? config.updateJSON.replace("update.json", "update-beta.json")
 | 
					 | 
				
			||||||
    : config.updateJSON;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  replaceFrom.push(
 | 
					 | 
				
			||||||
    ...Object.keys(config).map((k) => new RegExp(`__${k}__`, "g")),
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  replaceTo.push(...Object.values(config));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const replaceResult = replaceInFileSync({
 | 
					 | 
				
			||||||
    files: [
 | 
					 | 
				
			||||||
      `${buildDir}/addon/**/*.xhtml`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/**/*.html`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/**/*.css`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/**/*.json`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/prefs.js`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/manifest.json`,
 | 
					 | 
				
			||||||
      `${buildDir}/addon/bootstrap.js`,
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    from: replaceFrom,
 | 
					 | 
				
			||||||
    to: replaceTo,
 | 
					 | 
				
			||||||
    countMatches: true,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Logger.debug(
 | 
					 | 
				
			||||||
  //     "[Build] Run replace in ",
 | 
					 | 
				
			||||||
  //     replaceResult.filter((f) => f.hasChanged).map((f) => `${f.file} : ${f.numReplacements} / ${f.numMatches}`),
 | 
					 | 
				
			||||||
  // );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function prepareLocaleFiles() {
 | 
					 | 
				
			||||||
  // Prefix Fluent messages in xhtml
 | 
					 | 
				
			||||||
  const MessagesInHTML = new Set();
 | 
					 | 
				
			||||||
  replaceInFileSync({
 | 
					 | 
				
			||||||
    files: [`${buildDir}/addon/**/*.xhtml`, `${buildDir}/addon/**/*.html`],
 | 
					 | 
				
			||||||
    processor: (input) => {
 | 
					 | 
				
			||||||
      const matchs = [...input.matchAll(/(data-l10n-id)="(\S*)"/g)];
 | 
					 | 
				
			||||||
      matchs.map((match) => {
 | 
					 | 
				
			||||||
        input = input.replace(
 | 
					 | 
				
			||||||
          match[0],
 | 
					 | 
				
			||||||
          `${match[1]}="${config.addonRef}-${match[2]}"`,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        MessagesInHTML.add(match[2]);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      return input;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Walk the sub folders of `build/addon/locale`
 | 
					 | 
				
			||||||
  const localesPath = path.join(buildDir, "addon/locale"),
 | 
					 | 
				
			||||||
    localeNames = readdirSync(localesPath, { withFileTypes: true })
 | 
					 | 
				
			||||||
      .filter((dirent) => dirent.isDirectory())
 | 
					 | 
				
			||||||
      .map((dirent) => dirent.name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (const localeName of localeNames) {
 | 
					 | 
				
			||||||
    const localePath = path.join(localesPath, localeName);
 | 
					 | 
				
			||||||
    const ftlFiles = readdirSync(localePath, {
 | 
					 | 
				
			||||||
      withFileTypes: true,
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
      .filter((dirent) => dirent.isFile())
 | 
					 | 
				
			||||||
      .map((dirent) => dirent.name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // rename *.ftl to addonRef-*.ftl
 | 
					 | 
				
			||||||
    for (const ftlFile of ftlFiles) {
 | 
					 | 
				
			||||||
      if (ftlFile.endsWith(".ftl")) {
 | 
					 | 
				
			||||||
        renameSync(
 | 
					 | 
				
			||||||
          path.join(localePath, ftlFile),
 | 
					 | 
				
			||||||
          path.join(localePath, `${config.addonRef}-${ftlFile}`),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Prefix Fluent messages in each ftl
 | 
					 | 
				
			||||||
    const MessageInThisLang = new Set();
 | 
					 | 
				
			||||||
    replaceInFileSync({
 | 
					 | 
				
			||||||
      files: [`${buildDir}/addon/locale/${localeName}/*.ftl`],
 | 
					 | 
				
			||||||
      processor: (fltContent) => {
 | 
					 | 
				
			||||||
        const lines = fltContent.split("\n");
 | 
					 | 
				
			||||||
        const prefixedLines = lines.map((line) => {
 | 
					 | 
				
			||||||
          // https://regex101.com/r/lQ9x5p/1
 | 
					 | 
				
			||||||
          const match = line.match(
 | 
					 | 
				
			||||||
            /^(?<message>[a-zA-Z]\S*)([ ]*=[ ]*)(?<pattern>.*)$/m,
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
          if (match) {
 | 
					 | 
				
			||||||
            MessageInThisLang.add(match.groups.message);
 | 
					 | 
				
			||||||
            return `${config.addonRef}-${line}`;
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            return line;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return prefixedLines.join("\n");
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // If a message in xhtml but not in ftl of current language, log it
 | 
					 | 
				
			||||||
    MessagesInHTML.forEach((message) => {
 | 
					 | 
				
			||||||
      if (!MessageInThisLang.has(message)) {
 | 
					 | 
				
			||||||
        Logger.error(`[Build] ${message} don't exist in ${localeName}`);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function prepareUpdateJson() {
 | 
					 | 
				
			||||||
  // If it is a pre-release, use update-beta.json
 | 
					 | 
				
			||||||
  if (!isPreRelease) {
 | 
					 | 
				
			||||||
    copyFileSync("scripts/update-template.json", "update.json");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (existsSync("update-beta.json") || isPreRelease) {
 | 
					 | 
				
			||||||
    copyFileSync("scripts/update-template.json", "update-beta.json");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const updateLink =
 | 
					 | 
				
			||||||
    config.updateLink ?? isPreRelease
 | 
					 | 
				
			||||||
      ? `${config.releasePage}/download/v${version}/${name}.xpi`
 | 
					 | 
				
			||||||
      : `${config.releasePage}/latest/download/${name}.xpi`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const replaceResult = replaceInFileSync({
 | 
					 | 
				
			||||||
    files: [
 | 
					 | 
				
			||||||
      "update-beta.json",
 | 
					 | 
				
			||||||
      isPreRelease ? "pass" : "update.json",
 | 
					 | 
				
			||||||
      `${buildDir}/addon/manifest.json`,
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    from: [
 | 
					 | 
				
			||||||
      /__addonID__/g,
 | 
					 | 
				
			||||||
      /__buildVersion__/g,
 | 
					 | 
				
			||||||
      /__updateLink__/g,
 | 
					 | 
				
			||||||
      /__updateURL__/g,
 | 
					 | 
				
			||||||
    ],
 | 
					 | 
				
			||||||
    to: [config.addonID, version, updateLink, config.updateURL],
 | 
					 | 
				
			||||||
    countMatches: true,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.debug(
 | 
					 | 
				
			||||||
    `[Build] Prepare Update.json for ${
 | 
					 | 
				
			||||||
      isPreRelease
 | 
					 | 
				
			||||||
        ? "\u001b[31m Prerelease \u001b[0m"
 | 
					 | 
				
			||||||
        : "\u001b[32m Release \u001b[0m"
 | 
					 | 
				
			||||||
    }`,
 | 
					 | 
				
			||||||
    replaceResult
 | 
					 | 
				
			||||||
      .filter((f) => f.hasChanged)
 | 
					 | 
				
			||||||
      .map((f) => `${f.file} : ${f.numReplacements} / ${f.numMatches}`),
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const esbuildOptions = {
 | 
					 | 
				
			||||||
  entryPoints: ["src/index.ts"],
 | 
					 | 
				
			||||||
  define: {
 | 
					 | 
				
			||||||
    __env__: `"${env.NODE_ENV}"`,
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  bundle: true,
 | 
					 | 
				
			||||||
  target: "firefox102",
 | 
					 | 
				
			||||||
  outfile: path.join(
 | 
					 | 
				
			||||||
    buildDir,
 | 
					 | 
				
			||||||
    `addon/chrome/content/scripts/${config.addonRef}.js`,
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
  // Don't turn minify on
 | 
					 | 
				
			||||||
  minify: env.NODE_ENV === "production",
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export async function main() {
 | 
					 | 
				
			||||||
  const t = new Date();
 | 
					 | 
				
			||||||
  const buildTime = dateFormat("YYYY-mm-dd HH:MM:SS", new Date());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.info(
 | 
					 | 
				
			||||||
    `[Build] BUILD_DIR=${buildDir}, VERSION=${version}, BUILD_TIME=${buildTime}, ENV=${[
 | 
					 | 
				
			||||||
      env.NODE_ENV,
 | 
					 | 
				
			||||||
    ]}`,
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  clearFolder(buildDir);
 | 
					 | 
				
			||||||
  copyFolderRecursiveSync("addon", buildDir);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.debug("[Build] Replacing");
 | 
					 | 
				
			||||||
  replaceString(buildTime);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.debug("[Build] Preparing locale files");
 | 
					 | 
				
			||||||
  prepareLocaleFiles();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.debug("[Build] Running esbuild");
 | 
					 | 
				
			||||||
  await build(esbuildOptions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Logger.debug("[Build] Addon prepare OK");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (process.env.NODE_ENV === "production") {
 | 
					 | 
				
			||||||
    Logger.debug("[Build] Packing Addon");
 | 
					 | 
				
			||||||
    await zip.compressDir(
 | 
					 | 
				
			||||||
      path.join(buildDir, "addon"),
 | 
					 | 
				
			||||||
      path.join(buildDir, `${name}.xpi`),
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        ignoreBase: true,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    prepareUpdateJson();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Logger.debug(
 | 
					 | 
				
			||||||
      `[Build] Finished in ${(new Date().getTime() - t.getTime()) / 1000} s.`,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (process.env.NODE_ENV === "production") {
 | 
					 | 
				
			||||||
  main().catch((err) => {
 | 
					 | 
				
			||||||
    Logger.error(err);
 | 
					 | 
				
			||||||
    exit(1);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,75 +0,0 @@
 | 
				
			|||||||
import details from "../package.json" assert { type: "json" };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { addonID, addonName } = details.config;
 | 
					 | 
				
			||||||
const { version } = details;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const reloadScript = `
 | 
					 | 
				
			||||||
(async () => {
 | 
					 | 
				
			||||||
Services.obs.notifyObservers(null, "startupcache-invalidate", null);
 | 
					 | 
				
			||||||
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 | 
					 | 
				
			||||||
const addon = await AddonManager.getAddonByID("${addonID}");
 | 
					 | 
				
			||||||
await addon.reload();
 | 
					 | 
				
			||||||
const progressWindow = new Zotero.ProgressWindow({ closeOnClick: true });
 | 
					 | 
				
			||||||
progressWindow.changeHeadline("${addonName} Hot Reload");
 | 
					 | 
				
			||||||
progressWindow.progress = new progressWindow.ItemProgress(
 | 
					 | 
				
			||||||
    "chrome://zotero/skin/tick.png",
 | 
					 | 
				
			||||||
    "VERSION=${version}, BUILD=${new Date().toLocaleString()}. By zotero-plugin-toolkit"
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
progressWindow.progress.setProgress(100);
 | 
					 | 
				
			||||||
progressWindow.show();
 | 
					 | 
				
			||||||
progressWindow.startCloseTimer(5000);
 | 
					 | 
				
			||||||
})()`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const openDevToolScript = `
 | 
					 | 
				
			||||||
(async () => {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// const { BrowserToolboxLauncher } = ChromeUtils.import(
 | 
					 | 
				
			||||||
//   "resource://devtools/client/framework/browser-toolbox/Launcher.jsm",
 | 
					 | 
				
			||||||
// );
 | 
					 | 
				
			||||||
// BrowserToolboxLauncher.init();
 | 
					 | 
				
			||||||
// TODO: Use the above code to open the devtool after https://github.com/zotero/zotero/pull/3387
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Zotero.Prefs.set("devtools.debugger.remote-enabled", true, true);
 | 
					 | 
				
			||||||
Zotero.Prefs.set("devtools.debugger.remote-port", 6100, true);
 | 
					 | 
				
			||||||
Zotero.Prefs.set("devtools.debugger.prompt-connection", false, true);
 | 
					 | 
				
			||||||
Zotero.Prefs.set("devtools.debugger.chrome-debugging-websocket", false, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
env =
 | 
					 | 
				
			||||||
    Services.env ||
 | 
					 | 
				
			||||||
    Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
env.set("MOZ_BROWSER_TOOLBOX_PORT", 6100);
 | 
					 | 
				
			||||||
Zotero.openInViewer(
 | 
					 | 
				
			||||||
    "chrome://devtools/content/framework/browser-toolbox/window.html",
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    onLoad: (doc) => {
 | 
					 | 
				
			||||||
        doc.querySelector("#status-message-container").style.visibility =
 | 
					 | 
				
			||||||
        "collapse";
 | 
					 | 
				
			||||||
        let toolboxBody;
 | 
					 | 
				
			||||||
        waitUntil(
 | 
					 | 
				
			||||||
        () => {
 | 
					 | 
				
			||||||
            toolboxBody = doc
 | 
					 | 
				
			||||||
            .querySelector(".devtools-toolbox-browsertoolbox-iframe")
 | 
					 | 
				
			||||||
            ?.contentDocument?.querySelector(".theme-body");
 | 
					 | 
				
			||||||
            return toolboxBody;
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        () => {
 | 
					 | 
				
			||||||
            toolboxBody.style = "pointer-events: all !important";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function waitUntil(condition, callback, interval = 100, timeout = 10000) {
 | 
					 | 
				
			||||||
    const start = Date.now();
 | 
					 | 
				
			||||||
    const intervalId = setInterval(() => {
 | 
					 | 
				
			||||||
    if (condition()) {
 | 
					 | 
				
			||||||
        clearInterval(intervalId);
 | 
					 | 
				
			||||||
        callback();
 | 
					 | 
				
			||||||
    } else if (Date.now() - start > timeout) {
 | 
					 | 
				
			||||||
        clearInterval(intervalId);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    }, interval);
 | 
					 | 
				
			||||||
}  
 | 
					 | 
				
			||||||
})()`;
 | 
					 | 
				
			||||||
@ -1,87 +0,0 @@
 | 
				
			|||||||
import { main as build, esbuildOptions } from "./build.mjs";
 | 
					 | 
				
			||||||
import { openDevToolScript, reloadScript } from "./scripts.mjs";
 | 
					 | 
				
			||||||
import { main as startZotero } from "./start.mjs";
 | 
					 | 
				
			||||||
import { Logger } from "./utils.mjs";
 | 
					 | 
				
			||||||
import cmd from "./zotero-cmd.json" assert { type: "json" };
 | 
					 | 
				
			||||||
import { execSync } from "child_process";
 | 
					 | 
				
			||||||
import chokidar from "chokidar";
 | 
					 | 
				
			||||||
import { context } from "esbuild";
 | 
					 | 
				
			||||||
import { exit } from "process";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
process.env.NODE_ENV = "development";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { zoteroBinPath, profilePath } = cmd.exec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const startZoteroCmd = `"${zoteroBinPath}" --debugger --purgecaches -profile "${profilePath}"`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function watch() {
 | 
					 | 
				
			||||||
  const watcher = chokidar.watch(["src/**", "addon/**"], {
 | 
					 | 
				
			||||||
    ignored: /(^|[\/\\])\../, // ignore dotfiles
 | 
					 | 
				
			||||||
    persistent: true,
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let esbuildCTX = await context(esbuildOptions);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  watcher
 | 
					 | 
				
			||||||
    .on("ready", () => {
 | 
					 | 
				
			||||||
      Logger.info("Server Ready! \n");
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .on("change", async (path) => {
 | 
					 | 
				
			||||||
      Logger.info(`${path} changed.`);
 | 
					 | 
				
			||||||
      if (path.startsWith("src")) {
 | 
					 | 
				
			||||||
        await esbuildCTX.rebuild();
 | 
					 | 
				
			||||||
      } else if (path.startsWith("addon")) {
 | 
					 | 
				
			||||||
        await build()
 | 
					 | 
				
			||||||
          // Do not abort the watcher when errors occur in builds triggered by the watcher.
 | 
					 | 
				
			||||||
          .catch((err) => {
 | 
					 | 
				
			||||||
            Logger.error(err);
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      // reload
 | 
					 | 
				
			||||||
      reload();
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
    .on("error", (err) => {
 | 
					 | 
				
			||||||
      Logger.error("Server start failed!", err);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function reload() {
 | 
					 | 
				
			||||||
  Logger.debug("Reloading...");
 | 
					 | 
				
			||||||
  const url = `zotero://ztoolkit-debug/?run=${encodeURIComponent(
 | 
					 | 
				
			||||||
    reloadScript,
 | 
					 | 
				
			||||||
  )}`;
 | 
					 | 
				
			||||||
  const command = `${startZoteroCmd} -url "${url}"`;
 | 
					 | 
				
			||||||
  execSync(command);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function openDevTool() {
 | 
					 | 
				
			||||||
  Logger.debug("Open dev tools...");
 | 
					 | 
				
			||||||
  const url = `zotero://ztoolkit-debug/?run=${encodeURIComponent(
 | 
					 | 
				
			||||||
    openDevToolScript,
 | 
					 | 
				
			||||||
  )}`;
 | 
					 | 
				
			||||||
  const command = `${startZoteroCmd} -url "${url}"`;
 | 
					 | 
				
			||||||
  execSync(command);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async function main() {
 | 
					 | 
				
			||||||
  // build
 | 
					 | 
				
			||||||
  await build();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // start Zotero
 | 
					 | 
				
			||||||
  startZotero(openDevTool);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // watch
 | 
					 | 
				
			||||||
  await watch();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
main().catch((err) => {
 | 
					 | 
				
			||||||
  Logger.error(err);
 | 
					 | 
				
			||||||
  // execSync("node scripts/stop.mjs");
 | 
					 | 
				
			||||||
  exit(1);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
process.on("SIGINT", (code) => {
 | 
					 | 
				
			||||||
  execSync("node scripts/stop.mjs");
 | 
					 | 
				
			||||||
  Logger.info(`Server terminated with signal ${code}.`);
 | 
					 | 
				
			||||||
  exit(0);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,119 +0,0 @@
 | 
				
			|||||||
import details from "../package.json" assert { type: "json" };
 | 
					 | 
				
			||||||
import { Logger } from "./utils.mjs";
 | 
					 | 
				
			||||||
import cmd from "./zotero-cmd.json" assert { type: "json" };
 | 
					 | 
				
			||||||
import { spawn } from "child_process";
 | 
					 | 
				
			||||||
import { existsSync, readFileSync, writeFileSync, rmSync } from "fs";
 | 
					 | 
				
			||||||
import { clearFolder } from "./utils.mjs";
 | 
					 | 
				
			||||||
import path from "path";
 | 
					 | 
				
			||||||
import { exit } from "process";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { addonID } = details.config;
 | 
					 | 
				
			||||||
const { zoteroBinPath, profilePath, dataDir } = cmd.exec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Keep in sync with the addon's onStartup
 | 
					 | 
				
			||||||
const loadDevToolWhen = `Plugin ${addonID} startup`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const logPath = "logs";
 | 
					 | 
				
			||||||
const logFilePath = path.join(logPath, "zotero.log");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (!existsSync(zoteroBinPath)) {
 | 
					 | 
				
			||||||
  throw new Error("Zotero binary does not exist.");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if (!existsSync(profilePath)) {
 | 
					 | 
				
			||||||
  throw new Error("The given Zotero profile does not exist.");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function prepareDevEnv() {
 | 
					 | 
				
			||||||
  const addonProxyFilePath = path.join(profilePath, `extensions/${addonID}`);
 | 
					 | 
				
			||||||
  const buildPath = path.resolve("build/addon");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  function writeAddonProxyFile() {
 | 
					 | 
				
			||||||
    writeFileSync(addonProxyFilePath, buildPath);
 | 
					 | 
				
			||||||
    Logger.debug(
 | 
					 | 
				
			||||||
      `Addon proxy file has been updated. 
 | 
					 | 
				
			||||||
          File path: ${addonProxyFilePath} 
 | 
					 | 
				
			||||||
          Addon path: ${buildPath} `,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (existsSync(addonProxyFilePath)) {
 | 
					 | 
				
			||||||
    if (readFileSync(addonProxyFilePath, "utf-8") !== buildPath) {
 | 
					 | 
				
			||||||
      writeAddonProxyFile();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    writeAddonProxyFile();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const addonXpiFilePath = path.join(profilePath, `extensions/${addonID}.xpi`);
 | 
					 | 
				
			||||||
  if (existsSync(addonXpiFilePath)) {
 | 
					 | 
				
			||||||
    rmSync(addonXpiFilePath);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const prefsPath = path.join(profilePath, "prefs.js");
 | 
					 | 
				
			||||||
  if (existsSync(prefsPath)) {
 | 
					 | 
				
			||||||
    const PrefsLines = readFileSync(prefsPath, "utf-8").split("\n");
 | 
					 | 
				
			||||||
    const filteredLines = PrefsLines.map((line) => {
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        line.includes("extensions.lastAppBuildId") ||
 | 
					 | 
				
			||||||
        line.includes("extensions.lastAppVersion")
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (line.includes("extensions.zotero.dataDir") && dataDir !== "") {
 | 
					 | 
				
			||||||
        return `user_pref("extensions.zotero.dataDir", "${dataDir.replace(/\\\\?/g, "\\\\")}");`;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return line;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    const updatedPrefs = filteredLines.join("\n");
 | 
					 | 
				
			||||||
    writeFileSync(prefsPath, updatedPrefs, "utf-8");
 | 
					 | 
				
			||||||
    Logger.debug("The <profile>/prefs.js has been modified.");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function prepareLog() {
 | 
					 | 
				
			||||||
  clearFolder(logPath);
 | 
					 | 
				
			||||||
  writeFileSync(logFilePath, "");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function main(callback) {
 | 
					 | 
				
			||||||
  let isZoteroReady = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  prepareDevEnv();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  prepareLog();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const zoteroProcess = spawn(zoteroBinPath, [
 | 
					 | 
				
			||||||
    "--debugger",
 | 
					 | 
				
			||||||
    "--purgecaches",
 | 
					 | 
				
			||||||
    "-profile",
 | 
					 | 
				
			||||||
    profilePath,
 | 
					 | 
				
			||||||
  ]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  zoteroProcess.stdout.on("data", (data) => {
 | 
					 | 
				
			||||||
    if (!isZoteroReady && data.toString().includes(loadDevToolWhen)) {
 | 
					 | 
				
			||||||
      isZoteroReady = true;
 | 
					 | 
				
			||||||
      callback();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    writeFileSync(logFilePath, data, {
 | 
					 | 
				
			||||||
      flag: "a",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  zoteroProcess.stderr.on("data", (data) => {
 | 
					 | 
				
			||||||
    writeFileSync(logFilePath, data, {
 | 
					 | 
				
			||||||
      flag: "a",
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  zoteroProcess.on("close", (code) => {
 | 
					 | 
				
			||||||
    Logger.info(`Zotero terminated with code ${code}.`);
 | 
					 | 
				
			||||||
    exit(0);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  process.on("SIGINT", () => {
 | 
					 | 
				
			||||||
    // Handle interrupt signal (Ctrl+C) to gracefully terminate Zotero process
 | 
					 | 
				
			||||||
    zoteroProcess.kill();
 | 
					 | 
				
			||||||
    exit();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,26 +0,0 @@
 | 
				
			|||||||
import { Logger, isRunning } from "./utils.mjs";
 | 
					 | 
				
			||||||
import cmd from "./zotero-cmd.json" assert { type: "json" };
 | 
					 | 
				
			||||||
import { execSync } from "child_process";
 | 
					 | 
				
			||||||
import process from "process";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { killZoteroWindows, killZoteroUnix } = cmd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
isRunning("zotero", (status) => {
 | 
					 | 
				
			||||||
  if (status) {
 | 
					 | 
				
			||||||
    killZotero();
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    Logger.warn("No Zotero running.");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function killZotero() {
 | 
					 | 
				
			||||||
  try {
 | 
					 | 
				
			||||||
    if (process.platform === "win32") {
 | 
					 | 
				
			||||||
      execSync(killZoteroWindows);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      execSync(killZoteroUnix);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } catch (e) {
 | 
					 | 
				
			||||||
    Logger.error(e);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,17 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "addons": {
 | 
					 | 
				
			||||||
    "__addonID__": {
 | 
					 | 
				
			||||||
      "updates": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "version": "__buildVersion__",
 | 
					 | 
				
			||||||
          "update_link": "__updateLink__",
 | 
					 | 
				
			||||||
          "applications": {
 | 
					 | 
				
			||||||
            "zotero": {
 | 
					 | 
				
			||||||
              "strict_min_version": "6.999"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,129 +0,0 @@
 | 
				
			|||||||
import { exec } from "child_process";
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  existsSync,
 | 
					 | 
				
			||||||
  lstatSync,
 | 
					 | 
				
			||||||
  mkdirSync,
 | 
					 | 
				
			||||||
  readFileSync,
 | 
					 | 
				
			||||||
  readdirSync,
 | 
					 | 
				
			||||||
  rmSync,
 | 
					 | 
				
			||||||
  writeFileSync,
 | 
					 | 
				
			||||||
} from "fs";
 | 
					 | 
				
			||||||
import path from "path";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function copyFileSync(source, target) {
 | 
					 | 
				
			||||||
  var targetFile = target;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // If target is a directory, a new file with the same name will be created
 | 
					 | 
				
			||||||
  if (existsSync(target)) {
 | 
					 | 
				
			||||||
    if (lstatSync(target).isDirectory()) {
 | 
					 | 
				
			||||||
      targetFile = path.join(target, path.basename(source));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  writeFileSync(targetFile, readFileSync(source));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function copyFolderRecursiveSync(source, target) {
 | 
					 | 
				
			||||||
  var files = [];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check if folder needs to be created or integrated
 | 
					 | 
				
			||||||
  var targetFolder = path.join(target, path.basename(source));
 | 
					 | 
				
			||||||
  if (!existsSync(targetFolder)) {
 | 
					 | 
				
			||||||
    mkdirSync(targetFolder);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Copy
 | 
					 | 
				
			||||||
  if (lstatSync(source).isDirectory()) {
 | 
					 | 
				
			||||||
    files = readdirSync(source);
 | 
					 | 
				
			||||||
    files.forEach(function (file) {
 | 
					 | 
				
			||||||
      var curSource = path.join(source, file);
 | 
					 | 
				
			||||||
      if (lstatSync(curSource).isDirectory()) {
 | 
					 | 
				
			||||||
        copyFolderRecursiveSync(curSource, targetFolder);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        copyFileSync(curSource, targetFolder);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function clearFolder(target) {
 | 
					 | 
				
			||||||
  if (existsSync(target)) {
 | 
					 | 
				
			||||||
    rmSync(target, { recursive: true, force: true });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mkdirSync(target, { recursive: true });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function dateFormat(fmt, date) {
 | 
					 | 
				
			||||||
  let ret;
 | 
					 | 
				
			||||||
  const opt = {
 | 
					 | 
				
			||||||
    "Y+": date.getFullYear().toString(),
 | 
					 | 
				
			||||||
    "m+": (date.getMonth() + 1).toString(),
 | 
					 | 
				
			||||||
    "d+": date.getDate().toString(),
 | 
					 | 
				
			||||||
    "H+": date.getHours().toString(),
 | 
					 | 
				
			||||||
    "M+": date.getMinutes().toString(),
 | 
					 | 
				
			||||||
    "S+": date.getSeconds().toString(),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  for (let k in opt) {
 | 
					 | 
				
			||||||
    ret = new RegExp("(" + k + ")").exec(fmt);
 | 
					 | 
				
			||||||
    if (ret) {
 | 
					 | 
				
			||||||
      fmt = fmt.replace(
 | 
					 | 
				
			||||||
        ret[1],
 | 
					 | 
				
			||||||
        ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0"),
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return fmt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export class Logger {
 | 
					 | 
				
			||||||
  static log(...args) {
 | 
					 | 
				
			||||||
    console.log(...args);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // red
 | 
					 | 
				
			||||||
  static error(...args) {
 | 
					 | 
				
			||||||
    console.error("\u001b[31m [ERROR]", ...args, "\u001b[0m");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // yellow
 | 
					 | 
				
			||||||
  static warn(...args) {
 | 
					 | 
				
			||||||
    console.warn("\u001b[33m [WARN]", ...args, "\u001b[0m");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // blue
 | 
					 | 
				
			||||||
  static debug(...args) {
 | 
					 | 
				
			||||||
    console.log("\u001b[34m [DEBUG]\u001b[0m", ...args);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // green
 | 
					 | 
				
			||||||
  static info(...args) {
 | 
					 | 
				
			||||||
    console.log("\u001b[32m [INFO]", ...args, "\u001b[0m");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // cyan
 | 
					 | 
				
			||||||
  static trace(...args) {
 | 
					 | 
				
			||||||
    console.log("\u001b[36m [TRACE]\u001b[0m", ...args);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function isRunning(query, cb) {
 | 
					 | 
				
			||||||
  let platform = process.platform;
 | 
					 | 
				
			||||||
  let cmd = "";
 | 
					 | 
				
			||||||
  switch (platform) {
 | 
					 | 
				
			||||||
    case "win32":
 | 
					 | 
				
			||||||
      cmd = `tasklist`;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case "darwin":
 | 
					 | 
				
			||||||
      cmd = `ps -ax | grep ${query}`;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case "linux":
 | 
					 | 
				
			||||||
      cmd = `ps -A`;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  exec(cmd, (err, stdout, stderr) => {
 | 
					 | 
				
			||||||
    cb(stdout.toLowerCase().indexOf(query.toLowerCase()) > -1);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,20 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "usage": "Copy and rename this file to zotero-cmd.json. Edit the cmd.",
 | 
					 | 
				
			||||||
  "killZoteroWindows": "taskkill /f /im zotero.exe",
 | 
					 | 
				
			||||||
  "killZoteroUnix": "kill -9 $(ps -x | grep '[z]otero' | awk '{print $1}')",
 | 
					 | 
				
			||||||
  "exec": {
 | 
					 | 
				
			||||||
    "@comment-zoteroBinPath": "Please input the path of the Zotero binary file in `zoteroBinPath`.",
 | 
					 | 
				
			||||||
    "@comment-zoteroBinPath-tip": "The path delimiter should be escaped as `\\` for win32. The path is `*/Zotero.app/Contents/MacOS/zotero` for MacOS.",
 | 
					 | 
				
			||||||
    "zoteroBinPath": "/path/to/zotero.exe",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    "@comment-profilePath": "Please input the path of the profile used for development in `profilePath`.",
 | 
					 | 
				
			||||||
    "@comment-profilePath-tip": "Start the profile manager by `/path/to/zotero.exe -p` to create a profile for development",
 | 
					 | 
				
			||||||
    "@comment-profilePath-see": "https://www.zotero.org/support/kb/profile_directory",
 | 
					 | 
				
			||||||
    "profilePath": "/path/to/profile",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    "@comment-dataDir": "Please input the directory where the database is located in dataDir",
 | 
					 | 
				
			||||||
    "@comment-dataDir-tip": "If this field is kept empty, Zotero will start with the default data.",
 | 
					 | 
				
			||||||
    "@comment-dataDir-see": "https://www.zotero.org/support/zotero_data",
 | 
					 | 
				
			||||||
    "dataDir": ""
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -17,13 +17,6 @@ async function onStartup() {
 | 
				
			|||||||
    Zotero.uiReadyPromise,
 | 
					    Zotero.uiReadyPromise,
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: Remove this after zotero#3387 is merged
 | 
					 | 
				
			||||||
  if (__env__ === "development") {
 | 
					 | 
				
			||||||
    // Keep in sync with the scripts/startup.mjs
 | 
					 | 
				
			||||||
    const loadDevToolWhen = `Plugin ${config.addonID} startup`;
 | 
					 | 
				
			||||||
    ztoolkit.log(loadDevToolWhen);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  initLocale();
 | 
					  initLocale();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BasicExampleFactory.registerPrefs();
 | 
					  BasicExampleFactory.registerPrefs();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										17
									
								
								update.json
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								update.json
									
									
									
									
									
								
							@ -1,17 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "addons": {
 | 
					 | 
				
			||||||
    "addontemplate@euclpts.com": {
 | 
					 | 
				
			||||||
      "updates": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "version": "1.1.2",
 | 
					 | 
				
			||||||
          "update_link": "https://github.com/windingwind/zotero-addon-template/releases/latest/download/zotero-addon-template.xpi",
 | 
					 | 
				
			||||||
          "applications": {
 | 
					 | 
				
			||||||
            "zotero": {
 | 
					 | 
				
			||||||
              "strict_min_version": "6.999"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										61
									
								
								zotero-plugin.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								zotero-plugin.config.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					import { defineConfig } from "zotero-plugin-scaffold";
 | 
				
			||||||
 | 
					import pkg from "./package.json";
 | 
				
			||||||
 | 
					import { copyFileSync } from "fs";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineConfig({
 | 
				
			||||||
 | 
					  source: ["src", "addon"],
 | 
				
			||||||
 | 
					  dist: "build",
 | 
				
			||||||
 | 
					  name: pkg.config.addonName,
 | 
				
			||||||
 | 
					  id: pkg.config.addonID,
 | 
				
			||||||
 | 
					  namespace: pkg.config.addonRef,
 | 
				
			||||||
 | 
					  updateURL: `https://github.com/{{owner}}/{{repo}}/releases/download/release/${
 | 
				
			||||||
 | 
					    pkg.version.includes("-") ? "update-beta.json" : "update.json"
 | 
				
			||||||
 | 
					  }`,
 | 
				
			||||||
 | 
					  xpiDownloadLink:
 | 
				
			||||||
 | 
					    "https://github.com/{{owner}}/{{repo}}/releases/download/v{{version}}/{{xpiName}}.xpi",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  server: {
 | 
				
			||||||
 | 
					    asProxy: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build: {
 | 
				
			||||||
 | 
					    assets: ["addon/**/*.*"],
 | 
				
			||||||
 | 
					    define: {
 | 
				
			||||||
 | 
					      ...pkg.config,
 | 
				
			||||||
 | 
					      author: pkg.author,
 | 
				
			||||||
 | 
					      description: pkg.description,
 | 
				
			||||||
 | 
					      homepage: pkg.homepage,
 | 
				
			||||||
 | 
					      buildVersion: pkg.version,
 | 
				
			||||||
 | 
					      buildTime: "{{buildTime}}",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    esbuildOptions: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        entryPoints: ["src/index.ts"],
 | 
				
			||||||
 | 
					        define: {
 | 
				
			||||||
 | 
					          __env__: `"${process.env.NODE_ENV}"`,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        bundle: true,
 | 
				
			||||||
 | 
					        target: "firefox115",
 | 
				
			||||||
 | 
					        outfile: `build/addon/chrome/content/scripts/${pkg.config.addonRef}.js`,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    // If you want to checkout update.json into the repository, uncomment the following lines:
 | 
				
			||||||
 | 
					    // makeUpdateJson: {
 | 
				
			||||||
 | 
					    //   hash: false,
 | 
				
			||||||
 | 
					    // },
 | 
				
			||||||
 | 
					    // hooks: {
 | 
				
			||||||
 | 
					    //   "build:makeUpdateJSON": (ctx) => {
 | 
				
			||||||
 | 
					    //     copyFileSync("build/update.json", "update.json");
 | 
				
			||||||
 | 
					    //     copyFileSync("build/update-beta.json", "update-beta.json");
 | 
				
			||||||
 | 
					    //   },
 | 
				
			||||||
 | 
					    // },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  // release: {
 | 
				
			||||||
 | 
					  //   bumpp: {
 | 
				
			||||||
 | 
					  //     execute: "npm run build",
 | 
				
			||||||
 | 
					  //   },
 | 
				
			||||||
 | 
					  // },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // If you need to see a more detailed build log, uncomment the following line:
 | 
				
			||||||
 | 
					  // logLevel: "trace",
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user