zotero-plugin-scaffold 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,7 @@
4
4
  [![NPM Downloads](https://img.shields.io/npm/dm/zotero-plugin-scaffold)](https://www.npmjs.com/package/zotero-plugin-scaffold)
5
5
  ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/zotero-plugin-scaffold)
6
6
  ![GitHub License](https://img.shields.io/github/license/northword/zotero-plugin-scaffold)
7
+ [![code style](https://antfu.me/badge-code-style.svg)](https://github.com/antfu/eslint-config)
7
8
 
8
9
  This is an npm package designed to assist in the development of Zotero plugins. It provides features such as compiling plugins, starting Zotero and installing plugins from source code, reloading plugins when the source code changes, and releasing plugins, and so on.
9
10
 
@@ -0,0 +1,127 @@
1
+ import fs from 'node:fs';
2
+ import { join, basename } from 'node:path';
3
+ import { env } from 'node:process';
4
+ import { OpenAPI, RepositoriesService } from '@gitee/typescript-sdk-v5';
5
+ import { globbySync } from 'globby';
6
+ import { R as ReleaseBase } from '../shared/zotero-plugin-scaffold.3e58ced7.mjs';
7
+ import 'std-env';
8
+ import '../shared/zotero-plugin-scaffold.c7c8af0c.mjs';
9
+ import 'c12';
10
+ import 'es-toolkit';
11
+ import 'fs-extra';
12
+ import 'hookable';
13
+ import 'node:readline';
14
+ import 'chalk';
15
+ import 'esbuild';
16
+ import 'replace-in-file';
17
+ import 'web-ext';
18
+ import 'node:crypto';
19
+ import 'node:child_process';
20
+ import 'conventional-changelog';
21
+ import 'bumpp';
22
+ import 'chokidar';
23
+
24
+ var __defProp = Object.defineProperty;
25
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
26
+ var __publicField = (obj, key, value) => {
27
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
28
+ return value;
29
+ };
30
+ class Gitee extends ReleaseBase {
31
+ constructor() {
32
+ super(...arguments);
33
+ __publicField(this, "client", RepositoriesService);
34
+ }
35
+ async run() {
36
+ OpenAPI.TOKEN = env.GITEE_TOKEN;
37
+ if (!OpenAPI.TOKEN)
38
+ throw new Error("No GITEE_TOKEN provided!");
39
+ this.checkFiles();
40
+ this.logger.info("Uploading XPI to Gitee...");
41
+ await this.uploadXPI();
42
+ this.logger.info("Refreshing update manifest...");
43
+ await this.refreshUpdateManifest();
44
+ }
45
+ async uploadXPI() {
46
+ const { version, dist, xpiName } = this.ctx;
47
+ const release = await this.refreshRelease(
48
+ this.ctx.release.bumpp.tag.toString().replaceAll("%s", version),
49
+ `Release v${version}`,
50
+ this.ctx.release.gitee.releaseNote(this.ctx)
51
+ );
52
+ await this.refreshAttach(release.id, join(dist, `${xpiName}.xpi`));
53
+ }
54
+ async refreshUpdateManifest() {
55
+ const updater = this.ctx.release.gitee.updater;
56
+ if (!updater) {
57
+ this.logger.debug(
58
+ `Skip refresh update.json because release.gitee.updater = false`
59
+ );
60
+ return;
61
+ }
62
+ const { dist, version } = this.ctx;
63
+ const assets = globbySync(`${dist}/update*.json`).map((p) => basename(p));
64
+ const release = await this.refreshRelease(
65
+ updater,
66
+ "Zotero Auto Update Manifest",
67
+ `This release is used to host \`update.json\`, Updated in UTC ${( new Date()).toISOString()} for v${version}.`,
68
+ true
69
+ );
70
+ for (const asset of assets)
71
+ await this.refreshAttach(release.id, join(dist, asset));
72
+ }
73
+ async refreshRelease(tag, name, body, prerelease = false) {
74
+ const old = await this.client.getV5ReposOwnerRepoReleasesTagsTag({
75
+ ...this.remote,
76
+ tag
77
+ });
78
+ if (old?.id) {
79
+ return this.client.patchV5ReposOwnerRepoReleasesId({
80
+ ...this.remote,
81
+ name,
82
+ body,
83
+ prerelease,
84
+ id: old.id,
85
+ tagName: tag
86
+ });
87
+ }
88
+ return this.client.postV5ReposOwnerRepoReleases({
89
+ ...this.remote,
90
+ name,
91
+ body,
92
+ prerelease,
93
+ tagName: tag,
94
+ targetCommitish: "main"
95
+ });
96
+ }
97
+ async refreshAttach(releaseId, file) {
98
+ const assets = await this.client.getV5ReposOwnerRepoReleasesReleaseIdAttachFiles({
99
+ ...this.remote,
100
+ releaseId
101
+ });
102
+ const fileBuffer = fs.readFileSync(file);
103
+ for (const asset of assets) {
104
+ if (asset.name === basename(file)) {
105
+ await this.client.deleteV5ReposOwnerRepoReleasesReleaseIdAttachFilesAttachFileId({
106
+ ...this.remote,
107
+ releaseId,
108
+ attachFileId: asset.id
109
+ }).catch((e) => this.logger.error(e));
110
+ }
111
+ }
112
+ this.client.postV5ReposOwnerRepoReleasesReleaseIdAttachFiles({
113
+ ...this.remote,
114
+ releaseId,
115
+ file: new File([fileBuffer], basename(file), { type: "application/octet-stream" })
116
+ });
117
+ }
118
+ get remote() {
119
+ const [owner, repo] = this.ctx.release.gitee.repository.split("/");
120
+ return {
121
+ owner,
122
+ repo
123
+ };
124
+ }
125
+ }
126
+
127
+ export { Gitee as default };
@@ -0,0 +1,175 @@
1
+ import { join, basename } from 'node:path';
2
+ import { env } from 'node:process';
3
+ import fs from 'fs-extra';
4
+ import { globbySync } from 'globby';
5
+ import mime from 'mime';
6
+ import { Octokit } from 'octokit';
7
+ import { R as ReleaseBase } from '../shared/zotero-plugin-scaffold.3e58ced7.mjs';
8
+ import 'std-env';
9
+ import '../shared/zotero-plugin-scaffold.c7c8af0c.mjs';
10
+ import 'c12';
11
+ import 'es-toolkit';
12
+ import 'hookable';
13
+ import 'node:readline';
14
+ import 'chalk';
15
+ import 'esbuild';
16
+ import 'replace-in-file';
17
+ import 'web-ext';
18
+ import 'node:crypto';
19
+ import 'node:child_process';
20
+ import 'conventional-changelog';
21
+ import 'bumpp';
22
+ import 'chokidar';
23
+ import 'node:fs';
24
+
25
+ var __defProp = Object.defineProperty;
26
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
27
+ var __publicField = (obj, key, value) => {
28
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
29
+ return value;
30
+ };
31
+ class GitHub extends ReleaseBase {
32
+ constructor(ctx) {
33
+ super(ctx);
34
+ __publicField(this, "client");
35
+ this.client = this.getClient();
36
+ }
37
+ async run() {
38
+ this.checkFiles();
39
+ this.logger.info("Uploading XPI to GitHub...");
40
+ await this.uploadXPI();
41
+ this.logger.info("Refreshing update manifest...");
42
+ await this.refreshUpdateManifest();
43
+ return this.ctx;
44
+ }
45
+ /**
46
+ * Create new release and upload XPI to asset
47
+ */
48
+ async uploadXPI() {
49
+ const { version, dist, xpiName } = this.ctx;
50
+ const release = await this.createRelease({
51
+ ...this.remote,
52
+ tag_name: this.ctx.release.bumpp.tag.toString().replaceAll("%s", version),
53
+ name: `Release v${version}`,
54
+ body: await this.getChangelog(),
55
+ prerelease: version.includes("-"),
56
+ make_latest: "true"
57
+ });
58
+ if (!release)
59
+ throw new Error("Create release failed!");
60
+ this.logger.debug("Uploading xpi asset...");
61
+ await this.uploadAsset(release.id, join(dist, `${xpiName}.xpi`));
62
+ }
63
+ async getReleaseByTag(tag) {
64
+ return await this.client.rest.repos.getReleaseByTag({
65
+ ...this.remote,
66
+ tag
67
+ }).catch((e) => {
68
+ this.logger.debug(`Release with tag ${tag} not found. ${e}`);
69
+ return void 0;
70
+ }).then((res) => {
71
+ if (res && res.status === 200) {
72
+ this.logger.debug(`Found release with tag "${tag}", id=${res.data.id}.`);
73
+ return res.data;
74
+ }
75
+ });
76
+ }
77
+ async createRelease(options) {
78
+ this.logger.debug("Creating release...", options);
79
+ return await this.client.rest.repos.createRelease(options).catch((e) => {
80
+ this.logger.error(e);
81
+ throw new Error("Create release failed.");
82
+ }).then((res) => {
83
+ if (res.status === 201) {
84
+ this.logger.debug(`Create release "${res.data.tag_name}" success, id: ${res.data.id}.`);
85
+ return res.data;
86
+ }
87
+ });
88
+ }
89
+ async uploadAsset(releaseID, asset) {
90
+ this.logger.debug(`Uploading ${asset} to release ${releaseID}`);
91
+ return await this.client.rest.repos.uploadReleaseAsset({
92
+ ...this.remote,
93
+ release_id: releaseID,
94
+ data: fs.readFileSync(asset),
95
+ headers: {
96
+ "content-type": mime.getType(asset) || "application/octet-stream",
97
+ "content-length": fs.statSync(asset).size
98
+ },
99
+ name: basename(asset)
100
+ }).then((res) => {
101
+ this.logger.debug(`Upload "${res.data.name}" success, assetId: ${res.data.id}`);
102
+ return res.data;
103
+ });
104
+ }
105
+ async refreshUpdateManifest() {
106
+ const updater = this.ctx.release.github.updater;
107
+ if (!updater) {
108
+ this.logger.debug(`Skip refresh update.json because release.github.updater = false`);
109
+ return;
110
+ }
111
+ const { dist, version } = this.ctx;
112
+ const assets = globbySync(`${dist}/update*.json`).map((p) => basename(p));
113
+ const release = await this.getReleaseByTag(updater) ?? await this.createRelease({
114
+ ...this.remote,
115
+ tag_name: updater,
116
+ prerelease: true,
117
+ make_latest: "false"
118
+ });
119
+ if (!release)
120
+ throw new Error("Get or create 'release' failed.");
121
+ const existAssets = await this.client.rest.repos.listReleaseAssets({
122
+ ...this.remote,
123
+ release_id: release.id
124
+ }).then((res) => {
125
+ return res.data.filter((asset) => assets.includes(asset.name));
126
+ });
127
+ if (existAssets) {
128
+ for (const existAsset of existAssets) {
129
+ if (assets.includes(existAsset.name)) {
130
+ this.logger.debug(`Delete existed asset ${existAsset.name} in release ${updater}`);
131
+ await this.client.rest.repos.deleteReleaseAsset({
132
+ ...this.remote,
133
+ asset_id: existAsset.id
134
+ });
135
+ }
136
+ }
137
+ }
138
+ for (const asset of assets) {
139
+ await this.uploadAsset(release.id, join(dist, asset));
140
+ }
141
+ await this.client.rest.repos.updateRelease({
142
+ ...this.remote,
143
+ release_id: release.id,
144
+ name: "Release Manifest",
145
+ body: `This release is used to host \`update.json\`, please do not delete or modify it!
146
+ Updated in UTC ${( new Date()).toISOString()} for version ${version}`,
147
+ prerelease: true,
148
+ make_latest: "false"
149
+ });
150
+ }
151
+ async getChangelog() {
152
+ const { release } = this.ctx;
153
+ const { github } = release;
154
+ const { releaseNote } = github;
155
+ return releaseNote(this.ctx);
156
+ }
157
+ getClient() {
158
+ if (!env.GITHUB_TOKEN)
159
+ throw new Error("No GITHUB_TOKEN.");
160
+ const client = new Octokit({
161
+ auth: env.GITHUB_TOKEN,
162
+ userAgent: "zotero-plugin-scaffold"
163
+ });
164
+ return client;
165
+ }
166
+ get remote() {
167
+ const [owner, repo] = this.ctx.release.github.repository.split("/");
168
+ return {
169
+ owner,
170
+ repo
171
+ };
172
+ }
173
+ }
174
+
175
+ export { GitHub as default };
package/dist/cli.mjs CHANGED
@@ -2,12 +2,12 @@
2
2
  import process, { exit, env } from 'node:process';
3
3
  import { Command } from '@commander-js/extra-typings';
4
4
  import updateNotifier from 'update-notifier';
5
- import { L as Log, C as Config, B as Build, S as Serve, R as Release } from './shared/zotero-plugin-scaffold.2dde82f3.mjs';
5
+ import { L as Log, C as Config, a as Build, S as Serve, R as Release } from './shared/zotero-plugin-scaffold.c7c8af0c.mjs';
6
6
  import 'node:path';
7
7
  import 'c12';
8
+ import 'es-toolkit';
8
9
  import 'fs-extra';
9
10
  import 'hookable';
10
- import 'es-toolkit';
11
11
  import 'node:readline';
12
12
  import 'chalk';
13
13
  import 'std-env';
@@ -19,13 +19,11 @@ import 'node:crypto';
19
19
  import 'node:child_process';
20
20
  import 'conventional-changelog';
21
21
  import 'bumpp';
22
- import 'mime';
23
- import 'octokit';
24
22
  import 'chokidar';
25
23
  import 'node:fs';
26
24
 
27
25
  const name = "zotero-plugin-scaffold";
28
- const version = "0.1.2";
26
+ const version = "0.1.4";
29
27
 
30
28
  const logger = new Log();
31
29
  async function main() {
package/dist/index.d.mts CHANGED
@@ -158,17 +158,29 @@ interface Config$1 {
158
158
  /**
159
159
  * The download link of XPI.
160
160
  *
161
+ * Some placeholders are available, see Context.templateData.
162
+ *
161
163
  * XPI 文件的地址。
162
164
  *
165
+ * 一些可用的占位符请参阅 Context.templateData。
166
+ *
163
167
  * @default `https://github.com/{{owner}}/{{repo}}/release/download/v{{version}}/{{xpiName}}.xpi`
168
+ *
169
+ * @see {@link Context.templateData}
164
170
  */
165
171
  xpiDownloadLink: string;
166
172
  /**
167
173
  * The uri of update.json.
168
174
  *
175
+ * Some placeholders are available, see Context.templateData.
176
+ *
169
177
  * update.json 文件的地址。
170
178
  *
179
+ * 一些可用的占位符请参阅 Context.templateData。
180
+ *
171
181
  * @default `https://github.com/{{owner}}/{{repo}}/release/download/release/update.json`
182
+ *
183
+ * @see {@link Context.templateData}
172
184
  */
173
185
  updateURL: string;
174
186
  /**
@@ -233,6 +245,8 @@ interface BuildConfig {
233
245
  *
234
246
  * - 在构建时,脚手架使用占位符的 key 建立正则模式 `/__${key}__/g`,并将匹配到的内容替换为 `value`。
235
247
  * - 替换发生在 `assets` 下的所有文件。
248
+ *
249
+ * @see {@link Context.templateData}
236
250
  */
237
251
  define: {
238
252
  [key: string]: string;
@@ -533,6 +547,15 @@ interface ReleaseConfig {
533
547
  * @default "ci"
534
548
  */
535
549
  enable: "ci" | "local" | "always" | "false";
550
+ /**
551
+ * The information of remote repository.
552
+ *
553
+ * Will be extracted from the `repository` property in `package.json` by default.
554
+ *
555
+ * @default {{owner}}/{{repo}}
556
+ * @see {@link Context.templateData}
557
+ */
558
+ repository: string;
536
559
  /**
537
560
  * Upload update.json to release.
538
561
  *
@@ -557,15 +580,8 @@ interface ReleaseConfig {
557
580
  };
558
581
  /**
559
582
  * Release to Gitee
560
- *
561
- * @todo Not implemented yet
562
583
  */
563
- gitee: {
564
- enable: "ci" | "local" | "always" | "false";
565
- updater: string | false;
566
- comment: boolean;
567
- releaseNote: (ctx: Context) => string;
568
- };
584
+ gitee: ReleaseConfig["github"];
569
585
  hooks: Partial<ReleaseHooks>;
570
586
  }
571
587
  interface ReleaseHooks {
@@ -591,9 +607,19 @@ interface Context extends Config$1 {
591
607
  version: string;
592
608
  hooks: Hookable<Hooks>;
593
609
  logger: InstanceType<typeof Log>;
594
- templateDate: {
595
- [placeholder: string]: string;
596
- };
610
+ templateData: TemplateData;
611
+ }
612
+ interface TemplateData {
613
+ /**
614
+ * `owner` and `repo` will be extracted from the `repository` property in `package.json`.
615
+ */
616
+ owner: string;
617
+ repo: string;
618
+ version: string;
619
+ isPreRelease: string;
620
+ updateJson: "update-beta.json" | "update.json" | string;
621
+ xpiName: string;
622
+ buildTime: string;
597
623
  }
598
624
 
599
625
  /**
package/dist/index.d.ts CHANGED
@@ -158,17 +158,29 @@ interface Config$1 {
158
158
  /**
159
159
  * The download link of XPI.
160
160
  *
161
+ * Some placeholders are available, see Context.templateData.
162
+ *
161
163
  * XPI 文件的地址。
162
164
  *
165
+ * 一些可用的占位符请参阅 Context.templateData。
166
+ *
163
167
  * @default `https://github.com/{{owner}}/{{repo}}/release/download/v{{version}}/{{xpiName}}.xpi`
168
+ *
169
+ * @see {@link Context.templateData}
164
170
  */
165
171
  xpiDownloadLink: string;
166
172
  /**
167
173
  * The uri of update.json.
168
174
  *
175
+ * Some placeholders are available, see Context.templateData.
176
+ *
169
177
  * update.json 文件的地址。
170
178
  *
179
+ * 一些可用的占位符请参阅 Context.templateData。
180
+ *
171
181
  * @default `https://github.com/{{owner}}/{{repo}}/release/download/release/update.json`
182
+ *
183
+ * @see {@link Context.templateData}
172
184
  */
173
185
  updateURL: string;
174
186
  /**
@@ -233,6 +245,8 @@ interface BuildConfig {
233
245
  *
234
246
  * - 在构建时,脚手架使用占位符的 key 建立正则模式 `/__${key}__/g`,并将匹配到的内容替换为 `value`。
235
247
  * - 替换发生在 `assets` 下的所有文件。
248
+ *
249
+ * @see {@link Context.templateData}
236
250
  */
237
251
  define: {
238
252
  [key: string]: string;
@@ -533,6 +547,15 @@ interface ReleaseConfig {
533
547
  * @default "ci"
534
548
  */
535
549
  enable: "ci" | "local" | "always" | "false";
550
+ /**
551
+ * The information of remote repository.
552
+ *
553
+ * Will be extracted from the `repository` property in `package.json` by default.
554
+ *
555
+ * @default {{owner}}/{{repo}}
556
+ * @see {@link Context.templateData}
557
+ */
558
+ repository: string;
536
559
  /**
537
560
  * Upload update.json to release.
538
561
  *
@@ -557,15 +580,8 @@ interface ReleaseConfig {
557
580
  };
558
581
  /**
559
582
  * Release to Gitee
560
- *
561
- * @todo Not implemented yet
562
583
  */
563
- gitee: {
564
- enable: "ci" | "local" | "always" | "false";
565
- updater: string | false;
566
- comment: boolean;
567
- releaseNote: (ctx: Context) => string;
568
- };
584
+ gitee: ReleaseConfig["github"];
569
585
  hooks: Partial<ReleaseHooks>;
570
586
  }
571
587
  interface ReleaseHooks {
@@ -591,9 +607,19 @@ interface Context extends Config$1 {
591
607
  version: string;
592
608
  hooks: Hookable<Hooks>;
593
609
  logger: InstanceType<typeof Log>;
594
- templateDate: {
595
- [placeholder: string]: string;
596
- };
610
+ templateData: TemplateData;
611
+ }
612
+ interface TemplateData {
613
+ /**
614
+ * `owner` and `repo` will be extracted from the `repository` property in `package.json`.
615
+ */
616
+ owner: string;
617
+ repo: string;
618
+ version: string;
619
+ isPreRelease: string;
620
+ updateJson: "update-beta.json" | "update.json" | string;
621
+ xpiName: string;
622
+ buildTime: string;
597
623
  }
598
624
 
599
625
  /**
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- export { B as Build, C as Config, R as Release, S as Serve, d as defineConfig } from './shared/zotero-plugin-scaffold.2dde82f3.mjs';
1
+ export { a as Build, C as Config, R as Release, S as Serve, d as defineConfig } from './shared/zotero-plugin-scaffold.c7c8af0c.mjs';
2
2
  import 'node:path';
3
3
  import 'c12';
4
+ import 'es-toolkit';
4
5
  import 'fs-extra';
5
6
  import 'hookable';
6
- import 'es-toolkit';
7
- import 'node:readline';
8
7
  import 'node:process';
8
+ import 'node:readline';
9
9
  import 'chalk';
10
10
  import 'std-env';
11
11
  import 'esbuild';
@@ -16,7 +16,5 @@ import 'node:crypto';
16
16
  import 'node:child_process';
17
17
  import 'conventional-changelog';
18
18
  import 'bumpp';
19
- import 'mime';
20
- import 'octokit';
21
19
  import 'chokidar';
22
20
  import 'node:fs';
@@ -0,0 +1,25 @@
1
+ import { globbySync } from 'globby';
2
+ import { isCI } from 'std-env';
3
+ import { B as Base } from './zotero-plugin-scaffold.c7c8af0c.mjs';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __publicField = (obj, key, value) => {
8
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
9
+ return value;
10
+ };
11
+ class ReleaseBase extends Base {
12
+ constructor(ctx) {
13
+ super(ctx);
14
+ __publicField(this, "isCI");
15
+ this.isCI = isCI;
16
+ }
17
+ checkFiles() {
18
+ const { dist } = this.ctx;
19
+ if (globbySync(`${dist}/*.xpi`).length === 0) {
20
+ throw new Error("No xpi file found, are you sure you have run build?");
21
+ }
22
+ }
23
+ }
24
+
25
+ export { ReleaseBase as R };
@@ -1,10 +1,10 @@
1
- import path, { join, basename, resolve } from 'node:path';
1
+ import path, { join, resolve } from 'node:path';
2
2
  import { loadConfig as loadConfig$1 } from 'c12';
3
+ import { isPlainObject, kebabCase, mapValues, toMerged, escapeRegExp, debounce } from 'es-toolkit';
3
4
  import fs from 'fs-extra';
4
5
  import { createHooks } from 'hookable';
5
- import { isPlainObject, kebabCase, mapValues, toMerged, debounce } from 'es-toolkit';
6
+ import process, { env, platform, exit } from 'node:process';
6
7
  import readline from 'node:readline';
7
- import process, { env, exit, platform } from 'node:process';
8
8
  import chalk from 'chalk';
9
9
  import { isCI, isDebug, isWindows, isMacOS, isLinux } from 'std-env';
10
10
  import { build } from 'esbuild';
@@ -15,15 +15,13 @@ import * as crypto from 'node:crypto';
15
15
  import { execSync, spawn } from 'node:child_process';
16
16
  import conventionalChangelog from 'conventional-changelog';
17
17
  import { versionBump, ProgressEvent } from 'bumpp';
18
- import mime from 'mime';
19
- import { Octokit } from 'octokit';
20
18
  import chokidar from 'chokidar';
21
19
  import { existsSync } from 'node:fs';
22
20
 
23
- var __defProp$9 = Object.defineProperty;
24
- var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
25
- var __publicField$9 = (obj, key, value) => {
26
- __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+ var __defProp$6 = Object.defineProperty;
22
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
23
+ var __publicField$6 = (obj, key, value) => {
24
+ __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
27
25
  return value;
28
26
  };
29
27
  var LOG_LEVEL = /* @__PURE__ */ ((LOG_LEVEL2) => {
@@ -36,7 +34,7 @@ var LOG_LEVEL = /* @__PURE__ */ ((LOG_LEVEL2) => {
36
34
  })(LOG_LEVEL || {});
37
35
  class Log {
38
36
  constructor(config) {
39
- __publicField$9(this, "logLevel");
37
+ __publicField$6(this, "logLevel");
40
38
  if (!config || isCI || isDebug) {
41
39
  this.logLevel = 0 /* trace */;
42
40
  } else {
@@ -148,11 +146,6 @@ function template(str, data, regex = /\{\{(.+?)\}\}/g) {
148
146
  return acc.replace(match[0], data[match[1]]);
149
147
  }, str);
150
148
  }
151
- function escapeRegExp(string) {
152
- const reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
153
- const reHasRegExpChar = RegExp(reRegExpChar.source);
154
- return string && reHasRegExpChar.test(string) ? string.replace(reRegExpChar, "\\$&") : string || "";
155
- }
156
149
  function parseRepoUrl(url) {
157
150
  if (!url)
158
151
  throw new Error("Parse repository URL failed.");
@@ -190,7 +183,7 @@ function resolveConfig(config) {
190
183
  config.namespace || (config.namespace = config.name);
191
184
  config.xpiName || (config.xpiName = kebabCase(config.name));
192
185
  const isPreRelease = version.includes("-");
193
- const templateDate = {
186
+ const templateData = {
194
187
  owner,
195
188
  repo,
196
189
  version,
@@ -199,9 +192,11 @@ function resolveConfig(config) {
199
192
  xpiName: config.xpiName,
200
193
  buildTime: dateFormat("YYYY-mm-dd HH:MM:SS", /* @__PURE__ */ new Date())
201
194
  };
202
- config.updateURL = template(config.updateURL, templateDate);
203
- config.xpiDownloadLink = template(config.xpiDownloadLink, templateDate);
204
- config.build.define = mapValues(config.build.define, (v) => template(v, templateDate));
195
+ config.updateURL = template(config.updateURL, templateData);
196
+ config.xpiDownloadLink = template(config.xpiDownloadLink, templateData);
197
+ config.build.define = mapValues(config.build.define, (v) => template(v, templateData));
198
+ config.release.github.repository = template(config.release.github.repository, templateData);
199
+ config.release.gitee.repository = template(config.release.gitee.repository, templateData);
205
200
  const hooks = createHooks();
206
201
  hooks.addHooks(config.build.hooks);
207
202
  hooks.addHooks(config.server.hooks);
@@ -212,7 +207,7 @@ function resolveConfig(config) {
212
207
  version,
213
208
  hooks,
214
209
  logger,
215
- templateDate
210
+ templateData
216
211
  };
217
212
  return ctx;
218
213
  }
@@ -288,6 +283,7 @@ const defaultConfig = {
288
283
  changelog: "",
289
284
  github: {
290
285
  enable: "ci",
286
+ repository: "{{owner}}/{{repo}}",
291
287
  updater: "release",
292
288
  comment: false,
293
289
  releaseNote: (ctx) => {
@@ -296,6 +292,7 @@ const defaultConfig = {
296
292
  },
297
293
  gitee: {
298
294
  enable: "false",
295
+ repository: "{{owner}}/{{repo}}",
299
296
  updater: "release",
300
297
  comment: false,
301
298
  releaseNote: (ctx) => {
@@ -314,15 +311,15 @@ function generateHashSync(filePath, algorithm) {
314
311
  return `${algorithm}:${hash}`;
315
312
  }
316
313
 
317
- var __defProp$8 = Object.defineProperty;
318
- var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
319
- var __publicField$8 = (obj, key, value) => {
320
- __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
314
+ var __defProp$5 = Object.defineProperty;
315
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
316
+ var __publicField$5 = (obj, key, value) => {
317
+ __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
321
318
  return value;
322
319
  };
323
320
  class Base {
324
321
  constructor(ctx) {
325
- __publicField$8(this, "ctx");
322
+ __publicField$5(this, "ctx");
326
323
  this.ctx = ctx;
327
324
  }
328
325
  get logger() {
@@ -330,18 +327,18 @@ class Base {
330
327
  }
331
328
  }
332
329
 
333
- var __defProp$7 = Object.defineProperty;
334
- var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
335
- var __publicField$7 = (obj, key, value) => {
336
- __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
330
+ var __defProp$4 = Object.defineProperty;
331
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
332
+ var __publicField$4 = (obj, key, value) => {
333
+ __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
337
334
  return value;
338
335
  };
339
336
  class Build extends Base {
340
337
  constructor(ctx) {
341
338
  var _a;
342
339
  super(ctx);
343
- __publicField$7(this, "buildTime");
344
- __publicField$7(this, "isPreRelease");
340
+ __publicField$4(this, "buildTime");
341
+ __publicField$4(this, "isPreRelease");
345
342
  (_a = env).NODE_ENV ?? (_a.NODE_ENV = "production");
346
343
  this.buildTime = "";
347
344
  this.isPreRelease = this.ctx.version.includes("-");
@@ -588,33 +585,7 @@ class Build extends Base {
588
585
  }
589
586
  }
590
587
 
591
- var __defProp$6 = Object.defineProperty;
592
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
593
- var __publicField$6 = (obj, key, value) => {
594
- __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
595
- return value;
596
- };
597
- class ReleaseBase extends Base {
598
- constructor(ctx) {
599
- super(ctx);
600
- __publicField$6(this, "isCI");
601
- this.isCI = isCI;
602
- }
603
- checkFiles() {
604
- const { dist } = this.ctx;
605
- if (globbySync(`${dist}/*.xpi`).length === 0) {
606
- throw new Error("No xpi file found, are you sure you have run build?");
607
- }
608
- }
609
- get owner() {
610
- return this.ctx.templateDate.owner;
611
- }
612
- get repo() {
613
- return this.ctx.templateDate.repo;
614
- }
615
- }
616
-
617
- class Bump extends ReleaseBase {
588
+ class Bump extends Base {
618
589
  constructor(ctx) {
619
590
  super(ctx);
620
591
  }
@@ -674,181 +645,6 @@ class Bump extends ReleaseBase {
674
645
  }
675
646
  }
676
647
 
677
- var __defProp$5 = Object.defineProperty;
678
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
679
- var __publicField$5 = (obj, key, value) => {
680
- __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
681
- return value;
682
- };
683
- class GitHub extends ReleaseBase {
684
- constructor(ctx) {
685
- super(ctx);
686
- __publicField$5(this, "client");
687
- this.client = this.getClient();
688
- }
689
- async run() {
690
- this.checkFiles();
691
- this.logger.info("Uploading XPI to GitHub...");
692
- await this.uploadXPI();
693
- this.logger.info("Refreshing update manifest...");
694
- await this.refreshUpdateManifest();
695
- return this.ctx;
696
- }
697
- /**
698
- * Create new release and upload XPI to asset
699
- */
700
- async uploadXPI() {
701
- const { version, dist, xpiName } = this.ctx;
702
- const release = await this.createRelease({
703
- owner: this.owner,
704
- repo: this.repo,
705
- tag_name: this.ctx.release.bumpp.tag.toString().replaceAll("%s", version),
706
- name: `Release v${version}`,
707
- body: await this.getChangelog(),
708
- prerelease: version.includes("-"),
709
- make_latest: "true"
710
- });
711
- if (!release)
712
- throw new Error("Create release failed!");
713
- this.logger.debug("Uploading xpi asset...");
714
- await this.uploadAsset(release.id, join(dist, `${xpiName}.xpi`));
715
- }
716
- async getReleaseByTag(tag) {
717
- return await this.client.rest.repos.getReleaseByTag({
718
- owner: this.owner,
719
- repo: this.repo,
720
- tag
721
- }).catch((e) => {
722
- this.logger.debug(`Release with tag ${tag} not found. ${e}`);
723
- return void 0;
724
- }).then((res) => {
725
- if (res && res.status === 200) {
726
- this.logger.debug(`Found release with tag "${tag}", id=${res.data.id}.`);
727
- return res.data;
728
- }
729
- });
730
- }
731
- async createRelease(options) {
732
- this.logger.debug("Creating release...", options);
733
- return await this.client.rest.repos.createRelease(options).catch((e) => {
734
- this.logger.error(e);
735
- throw new Error("Create release failed.");
736
- }).then((res) => {
737
- if (res.status === 201) {
738
- this.logger.debug(`Create release "${res.data.tag_name}" success, id: ${res.data.id}.`);
739
- return res.data;
740
- }
741
- });
742
- }
743
- async uploadAsset(releaseID, asset) {
744
- this.logger.debug(`Uploading ${asset} to release ${releaseID}`);
745
- return await this.client.rest.repos.uploadReleaseAsset({
746
- owner: this.owner,
747
- repo: this.repo,
748
- release_id: releaseID,
749
- data: fs.readFileSync(asset),
750
- headers: {
751
- "content-type": mime.getType(asset) || "application/octet-stream",
752
- "content-length": fs.statSync(asset).size
753
- },
754
- name: basename(asset)
755
- }).then((res) => {
756
- this.logger.debug(`Upload "${res.data.name}" success, assetId: ${res.data.id}`);
757
- return res.data;
758
- });
759
- }
760
- async refreshUpdateManifest() {
761
- const updater = this.ctx.release.github.updater;
762
- if (!updater) {
763
- this.logger.debug(`Skip refresh update.json because release.github.updater = false`);
764
- return;
765
- }
766
- const { dist, version } = this.ctx;
767
- const assets = globbySync(`${dist}/update*.json`).map((p) => basename(p));
768
- const release = await this.getReleaseByTag(updater) ?? await this.createRelease({
769
- owner: this.owner,
770
- repo: this.repo,
771
- tag_name: updater,
772
- prerelease: true,
773
- make_latest: "false"
774
- });
775
- if (!release)
776
- throw new Error("Get or create 'release' failed.");
777
- const existAssets = await this.client.rest.repos.listReleaseAssets({
778
- owner: this.owner,
779
- repo: this.repo,
780
- release_id: release.id
781
- }).then((res) => {
782
- return res.data.filter((asset) => assets.includes(asset.name));
783
- });
784
- if (existAssets) {
785
- for (const existAsset of existAssets) {
786
- if (assets.includes(existAsset.name)) {
787
- this.logger.debug(`Delete existed asset ${existAsset.name} in release ${updater}`);
788
- await this.client.rest.repos.deleteReleaseAsset({
789
- owner: this.owner,
790
- repo: this.repo,
791
- asset_id: existAsset.id
792
- });
793
- }
794
- }
795
- }
796
- for (const asset of assets) {
797
- await this.uploadAsset(release.id, join(dist, asset));
798
- }
799
- await this.client.rest.repos.updateRelease({
800
- owner: this.owner,
801
- repo: this.repo,
802
- release_id: release.id,
803
- name: "Release Manifest",
804
- body: `This release is used to host \`update.json\`, please do not delete or modify it!
805
- Updated in UTC ${( new Date()).toISOString()} for version ${version}`,
806
- prerelease: true,
807
- make_latest: "false"
808
- });
809
- }
810
- async getChangelog() {
811
- const { release } = this.ctx;
812
- const { github } = release;
813
- const { releaseNote } = github;
814
- return releaseNote(this.ctx);
815
- }
816
- getClient() {
817
- if (!env.GITHUB_TOKEN)
818
- throw new Error("No GITHUB_TOKEN.");
819
- const client = new Octokit({
820
- auth: env.GITHUB_TOKEN,
821
- userAgent: "zotero-plugin-scaffold"
822
- });
823
- return client;
824
- }
825
- }
826
-
827
- var __defProp$4 = Object.defineProperty;
828
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
829
- var __publicField$4 = (obj, key, value) => {
830
- __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
831
- return value;
832
- };
833
- class Gitee extends ReleaseBase {
834
- constructor(ctx) {
835
- super(ctx);
836
- __publicField$4(this, "client");
837
- this.client = this.getClient();
838
- }
839
- async run() {
840
- this.checkFiles();
841
- this.logger.error("Release to Gitee has not yet been implemented.");
842
- }
843
- async uploadXPI() {
844
- }
845
- async refreshUpdateManifest() {
846
- }
847
- getClient() {
848
- return "";
849
- }
850
- }
851
-
852
648
  class Release extends Base {
853
649
  constructor(ctx) {
854
650
  super(ctx);
@@ -885,10 +681,14 @@ class Release extends Base {
885
681
  await new Bump(this.ctx).run();
886
682
  await this.ctx.hooks.callHook("release:push", this.ctx);
887
683
  this.ctx.release.changelog = this.getChangelog();
888
- if (isGitHubEnabled)
684
+ if (isGitHubEnabled) {
685
+ const { default: GitHub } = await import('../chunks/github.mjs');
889
686
  await new GitHub(this.ctx).run();
890
- if (isGiteeEnabled)
687
+ }
688
+ if (isGiteeEnabled) {
689
+ const { default: Gitee } = await import('../chunks/gitee.mjs');
891
690
  await new Gitee(this.ctx).run();
691
+ }
892
692
  await this.ctx.hooks.callHook("release:done", this.ctx);
893
693
  this.logger.success(
894
694
  `Done in ${(( new Date()).getTime() - t.getTime()) / 1e3} s.`
@@ -972,6 +772,53 @@ ${changelog}
972
772
  }
973
773
  }
974
774
 
775
+ function isRunning(query) {
776
+ let cmd = "";
777
+ switch (platform) {
778
+ case "win32":
779
+ cmd = `tasklist`;
780
+ break;
781
+ case "darwin":
782
+ cmd = `ps -ax | grep ${query}`;
783
+ break;
784
+ case "linux":
785
+ cmd = `ps -A`;
786
+ break;
787
+ }
788
+ try {
789
+ const stdout = execSync(cmd, { encoding: "utf8" });
790
+ return stdout.toLowerCase().includes(query.toLowerCase());
791
+ } catch {
792
+ return false;
793
+ }
794
+ }
795
+
796
+ function killZotero() {
797
+ const logger = new Log();
798
+ function kill() {
799
+ try {
800
+ if (env.ZOTERO_PLUGIN_KILL_COMMAND) {
801
+ execSync(env.ZOTERO_PLUGIN_KILL_COMMAND);
802
+ } else if (isWindows) {
803
+ execSync("taskkill /f /im zotero.exe");
804
+ } else if (isMacOS) {
805
+ execSync("kill -9 $(ps -x | grep zotero)");
806
+ } else if (isLinux) {
807
+ execSync("kill -9 $(ps -x | grep zotero)");
808
+ } else {
809
+ logger.error("No commands found for this operating system.");
810
+ }
811
+ } catch {
812
+ logger.fail("Kill Zotero failed.");
813
+ }
814
+ }
815
+ if (isRunning("zotero")) {
816
+ kill();
817
+ } else {
818
+ logger.fail("No Zotero instance is currently running.");
819
+ }
820
+ }
821
+
975
822
  var __defProp$3 = Object.defineProperty;
976
823
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
977
824
  var __publicField$3 = (obj, key, value) => {
@@ -1194,53 +1041,6 @@ class RunnerWebExt extends ServeBase {
1194
1041
  }
1195
1042
  }
1196
1043
 
1197
- function isRunning(query) {
1198
- let cmd = "";
1199
- switch (platform) {
1200
- case "win32":
1201
- cmd = `tasklist`;
1202
- break;
1203
- case "darwin":
1204
- cmd = `ps -ax | grep ${query}`;
1205
- break;
1206
- case "linux":
1207
- cmd = `ps -A`;
1208
- break;
1209
- }
1210
- try {
1211
- const stdout = execSync(cmd, { encoding: "utf8" });
1212
- return stdout.toLowerCase().includes(query.toLowerCase());
1213
- } catch {
1214
- return false;
1215
- }
1216
- }
1217
-
1218
- function killZotero() {
1219
- const logger = new Log();
1220
- function kill() {
1221
- try {
1222
- if (env.ZOTERO_PLUGIN_KILL_COMMAND) {
1223
- execSync(env.ZOTERO_PLUGIN_KILL_COMMAND);
1224
- } else if (isWindows) {
1225
- execSync("taskkill /f /im zotero.exe");
1226
- } else if (isMacOS) {
1227
- execSync("kill -9 $(ps -x | grep zotero)");
1228
- } else if (isLinux) {
1229
- execSync("kill -9 $(ps -x | grep zotero)");
1230
- } else {
1231
- logger.error("No commands found for this operating system.");
1232
- }
1233
- } catch {
1234
- logger.fail("Kill Zotero failed.");
1235
- }
1236
- }
1237
- if (isRunning("zotero")) {
1238
- kill();
1239
- } else {
1240
- logger.fail("No Zotero instance is currently running.");
1241
- }
1242
- }
1243
-
1244
1044
  var __defProp = Object.defineProperty;
1245
1045
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1246
1046
  var __publicField = (obj, key, value) => {
@@ -1325,4 +1125,4 @@ const Config = {
1325
1125
  loadConfig
1326
1126
  };
1327
1127
 
1328
- export { Build as B, Config as C, Log as L, Release as R, Serve as S, defineConfig as d };
1128
+ export { Base as B, Config as C, Log as L, Release as R, Serve as S, Build as a, defineConfig as d };
@@ -1,6 +1,6 @@
1
- import * as esm from 'fs-extra/esm';
2
- export { esm as fse };
3
1
  import * as esToolkit from 'es-toolkit';
4
2
  export { esToolkit };
3
+ import * as esm from 'fs-extra/esm';
4
+ export { esm as fse };
5
5
  import * as replaceInFile from 'replace-in-file';
6
6
  export { replaceInFile };
@@ -1,6 +1,6 @@
1
- import * as esm from 'fs-extra/esm';
2
- export { esm as fse };
3
1
  import * as esToolkit from 'es-toolkit';
4
2
  export { esToolkit };
3
+ import * as esm from 'fs-extra/esm';
4
+ export { esm as fse };
5
5
  import * as replaceInFile from 'replace-in-file';
6
6
  export { replaceInFile };
@@ -1,6 +1,6 @@
1
- import * as esm from 'fs-extra/esm';
2
- export { esm as fse };
3
1
  import * as esToolkit from 'es-toolkit';
4
2
  export { esToolkit };
3
+ import * as esm from 'fs-extra/esm';
4
+ export { esm as fse };
5
5
  import * as replaceInFile from 'replace-in-file';
6
6
  export { replaceInFile };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zotero-plugin-scaffold",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.1.4",
5
5
  "description": "A scaffold for Zotero plugin development.",
6
6
  "author": "northword",
7
7
  "license": "AGPL-3.0-or-later",
@@ -52,14 +52,15 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@commander-js/extra-typings": "^12.1.0",
55
- "@inquirer/prompts": "^5.3.8",
55
+ "@gitee/typescript-sdk-v5": "^5.4.85",
56
+ "@inquirer/prompts": "^5.5.0",
56
57
  "bumpp": "^9.5.2",
57
- "c12": "^1.11.1",
58
+ "c12": "^1.11.2",
58
59
  "chalk": "^5.3.0",
59
60
  "chokidar": "^3.6.0",
60
61
  "commander": "^12.1.0",
61
62
  "conventional-changelog": "^6.0.0",
62
- "es-toolkit": "^1.16.0",
63
+ "es-toolkit": "^1.18.0",
63
64
  "esbuild": "^0.23.1",
64
65
  "fs-extra": "^11.2.0",
65
66
  "globby": "^14.0.2",
@@ -68,17 +69,17 @@
68
69
  "octokit": "^4.0.2",
69
70
  "replace-in-file": "^8.1.0",
70
71
  "std-env": "^3.7.0",
71
- "update-notifier": "^7.2.0",
72
+ "update-notifier": "^7.3.1",
72
73
  "web-ext": "^8.2.0"
73
74
  },
74
75
  "devDependencies": {
75
- "@antfu/eslint-config": "^3.0.0",
76
+ "@antfu/eslint-config": "^3.6.0",
76
77
  "@types/fs-extra": "^11.0.4",
77
- "@types/node": "^20.16.1",
78
+ "@types/node": "^20.16.5",
78
79
  "@types/update-notifier": "^6.0.8",
79
- "eslint": "^9.9.1",
80
+ "eslint": "^9.10.0",
80
81
  "eslint-plugin-format": "^0.1.2",
81
- "typescript": "^5.5.4",
82
+ "typescript": "^5.6.2",
82
83
  "unbuild": "^2.0.0"
83
84
  },
84
85
  "scripts": {