zotero-plugin-scaffold 0.1.7 → 0.1.8-beta.2

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.
@@ -5,7 +5,7 @@ import { globbySync } from 'globby';
5
5
  import mime from 'mime';
6
6
  import { Octokit } from 'octokit';
7
7
  import { isCI } from 'std-env';
8
- import { a as Base } from '../shared/zotero-plugin-scaffold.b59b2bc7.mjs';
8
+ import { a as Base } from '../shared/zotero-plugin-scaffold.ac50adf5.mjs';
9
9
  import 'c12';
10
10
  import 'es-toolkit';
11
11
  import 'hookable';
@@ -19,6 +19,10 @@ import 'node:child_process';
19
19
  import 'bumpp';
20
20
  import 'chokidar';
21
21
  import 'node:fs';
22
+ import 'node:fs/promises';
23
+ import 'node:http';
24
+ import 'fs-extra/esm';
25
+ import 'xvfb-ts';
22
26
 
23
27
  var __defProp$1 = Object.defineProperty;
24
28
  var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
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.b59b2bc7.mjs';
5
+ import { L as Log, C as Config, B as Build, S as Serve, T as Test, R as Release } from './shared/zotero-plugin-scaffold.ac50adf5.mjs';
6
6
  import 'node:path';
7
7
  import 'c12';
8
8
  import 'es-toolkit';
@@ -20,13 +20,151 @@ import 'node:child_process';
20
20
  import 'bumpp';
21
21
  import 'chokidar';
22
22
  import 'node:fs';
23
+ import 'node:fs/promises';
24
+ import 'node:http';
25
+ import 'fs-extra/esm';
26
+ import 'xvfb-ts';
23
27
 
24
28
  const name = "zotero-plugin-scaffold";
25
- const version = "0.1.7";
29
+ const type = "module";
30
+ const version = "0.1.8-beta.2";
31
+ const packageManager = "pnpm@9.14.4";
32
+ const description = "A scaffold for Zotero plugin development.";
33
+ const author = "northword";
34
+ const license = "AGPL-3.0-or-later";
35
+ const homepage = "https://github.com/northword/zotero-plugin-scaffold#readme";
36
+ const repository = {
37
+ type: "git",
38
+ url: "https://github.com/northword/zotero-plugin-scaffold.git"
39
+ };
40
+ const bugs = {
41
+ url: "https://github.com/northword/zotero-plugin-scaffold/issues"
42
+ };
43
+ const keywords = [
44
+ "zotero",
45
+ "plugin",
46
+ "developer",
47
+ "scaffold",
48
+ "web-ext"
49
+ ];
50
+ const exports = {
51
+ ".": {
52
+ types: "./dist/index.d.ts",
53
+ "import": "./dist/index.mjs"
54
+ },
55
+ "./vendor": {
56
+ types: "./dist/vendor/index.d.ts",
57
+ "import": "./dist/vendor/index.mjs"
58
+ }
59
+ };
60
+ const main$1 = "./dist/index.mjs";
61
+ const module = "./dist/index.mjs";
62
+ const types = "./dist/index.d.ts";
63
+ const bin = {
64
+ "zotero-plugin": "./dist/cli.mjs"
65
+ };
66
+ const files = [
67
+ "dist"
68
+ ];
69
+ const engines = {
70
+ node: ">=18"
71
+ };
72
+ const scripts = {
73
+ dev: "unbuild --stub",
74
+ build: "tsc --noEmit && unbuild",
75
+ "lint:check": "eslint .",
76
+ "lint:fix": "eslint . --fix",
77
+ release: "bumpp --commit \"chore(release): publish v%s\"",
78
+ "update:deps": "pnpx taze minor -w -f -l",
79
+ test: "echo \"Error: no test specified\" && exit 1"
80
+ };
81
+ const publishConfig = {
82
+ access: "public",
83
+ registry: "https://registry.npmjs.org"
84
+ };
85
+ const directories = {
86
+ lib: "dist",
87
+ doc: "docs"
88
+ };
89
+ const peerDependencies = {
90
+ "conventional-changelog": "^6.0.0"
91
+ };
92
+ const peerDependenciesMeta = {
93
+ "conventional-changelog": {
94
+ optional: true
95
+ }
96
+ };
97
+ const dependencies = {
98
+ "@commander-js/extra-typings": "^12.1.0",
99
+ "@inquirer/prompts": "^7.0.0",
100
+ bumpp: "^9.7.1",
101
+ c12: "^2.0.1",
102
+ chalk: "^5.3.0",
103
+ chokidar: "^4.0.1",
104
+ commander: "^12.1.0",
105
+ "es-toolkit": "^1.25.2",
106
+ esbuild: "^0.24.0",
107
+ "fs-extra": "^11.2.0",
108
+ globby: "^14.0.2",
109
+ hookable: "^5.5.3",
110
+ mime: "^4.0.4",
111
+ octokit: "^4.0.2",
112
+ "replace-in-file": "^8.2.0",
113
+ "std-env": "^3.7.0",
114
+ "update-notifier": "^7.3.1",
115
+ "web-ext": "^8.3.0",
116
+ "xvfb-ts": "^1.1.0"
117
+ };
118
+ const devDependencies = {
119
+ "@antfu/eslint-config": "^3.8.0",
120
+ "@types/fs-extra": "^11.0.4",
121
+ "@types/node": "^22.0.0",
122
+ "@types/update-notifier": "^6.0.8",
123
+ eslint: "^9.12.0",
124
+ "eslint-plugin-format": "^0.1.2",
125
+ typescript: "^5.7.2",
126
+ unbuild: "^2.0.0"
127
+ };
128
+ const pnpm = {
129
+ peerDependencyRules: {
130
+ allowAny: [
131
+ "node-fetch"
132
+ ]
133
+ }
134
+ };
135
+ const pkg = {
136
+ name: name,
137
+ type: type,
138
+ version: version,
139
+ packageManager: packageManager,
140
+ description: description,
141
+ author: author,
142
+ license: license,
143
+ homepage: homepage,
144
+ repository: repository,
145
+ bugs: bugs,
146
+ keywords: keywords,
147
+ exports: exports,
148
+ main: main$1,
149
+ module: module,
150
+ types: types,
151
+ bin: bin,
152
+ files: files,
153
+ engines: engines,
154
+ scripts: scripts,
155
+ publishConfig: publishConfig,
156
+ directories: directories,
157
+ peerDependencies: peerDependencies,
158
+ peerDependenciesMeta: peerDependenciesMeta,
159
+ dependencies: dependencies,
160
+ devDependencies: devDependencies,
161
+ pnpm: pnpm
162
+ };
26
163
 
27
164
  const logger = new Log();
28
165
  async function main() {
29
166
  var _a;
167
+ const { name, version } = pkg;
30
168
  updateNotifier({ pkg: { name, version } }).notify();
31
169
  process.removeAllListeners("SIGINT");
32
170
  (_a = env).NODE_ENV ?? (_a.NODE_ENV = "development");
@@ -41,6 +179,18 @@ async function main() {
41
179
  cli.command("serve").alias("dev").description("Start development server").action((_options) => {
42
180
  Config.loadConfig({}).then((ctx) => new Serve(ctx).run());
43
181
  });
182
+ cli.command("test").description("Run tests").option("--abort-on-fail", "Abort the test suite on first failure").option("--exit-on-finish", "Exit the test suite after all tests have run").action((options) => {
183
+ env.NODE_ENV = "test";
184
+ Config.loadConfig({}).then((ctx) => {
185
+ if (options.abortOnFail) {
186
+ ctx.test.abortOnFail = true;
187
+ }
188
+ if (options.exitOnFinish) {
189
+ ctx.test.exitOnFinish = true;
190
+ }
191
+ new Test(ctx).run();
192
+ });
193
+ });
44
194
  cli.command("create").description("Create the plugin template").action((_options) => {
45
195
  logger.error("The create not yet implemented");
46
196
  });
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Hookable } from 'hookable';
2
2
  import * as esbuild from 'esbuild';
3
3
  import { BuildOptions } from 'esbuild';
4
+ import * as child_process from 'child_process';
4
5
 
5
6
  /**
6
7
  * Logger
@@ -10,6 +11,7 @@ declare class Log {
10
11
  constructor(config?: Config$1);
11
12
  private formatArgs;
12
13
  private logArgs;
14
+ log(...args: any[]): void;
13
15
  error(...args: any[]): void;
14
16
  warn(...args: any[]): void;
15
17
  tip(...args: any[]): void;
@@ -178,7 +180,7 @@ interface Config$1 {
178
180
  *
179
181
  * 一些可用的占位符请参阅 Context.templateData。
180
182
  *
181
- * @default `https://github.com/{{owner}}/{{repo}}/release/download/release/update.json`
183
+ * @default `https://github.com/{{owner}}/{{repo}}/releaser/download/release/{{updateJson}}`
182
184
  *
183
185
  * @see {@link Context.templateData}
184
186
  */
@@ -205,6 +207,14 @@ interface Config$1 {
205
207
  * 发布相关配置。
206
208
  */
207
209
  release: ReleaseConfig;
210
+ /**
211
+ * Configurations required to run the test.
212
+ *
213
+ * 测试相关配置。
214
+ *
215
+ * Test is a variant of server, so it is not a separate hooks.
216
+ */
217
+ test: TestConfig;
208
218
  /**
209
219
  * Level of the log.
210
220
  *
@@ -596,7 +606,90 @@ interface ReleaseHooks {
596
606
  "release:push": (ctx: Context) => void | Promise<void>;
597
607
  "release:done": (ctx: Context) => void | Promise<void>;
598
608
  }
599
- interface Hooks extends BuildHooks, ServeHooks, ReleaseHooks {
609
+ interface TestConfig {
610
+ /**
611
+ * The test source code directories, starting from the root directory of the project.
612
+ * All `*.spec.js` files in these directories will be executed.
613
+ * The files will be sorted by alphabetical order.
614
+ *
615
+ * 测试源码目录,从项目的根目录开始。
616
+ * 这些目录中的所有 `*.spec.js` 文件将被执行。
617
+ * 文件将按字母顺序排序。
618
+ *
619
+ * @default "test/"
620
+ */
621
+ entries: string | string[];
622
+ /**
623
+ * The default preferences for the test.
624
+ * These preferences will be set before the test starts.
625
+ *
626
+ * 测试的默认首选项。
627
+ * 这些首选项将在测试开始前设置。
628
+ */
629
+ prefs: Record<string, string | boolean | number>;
630
+ /**
631
+ * Port for the test server.
632
+ *
633
+ * 测试服务器的端口。
634
+ *
635
+ * @default 9876
636
+ */
637
+ port: number;
638
+ /**
639
+ * Abort the test when the first test fails.
640
+ *
641
+ * 当第一个测试失败时中止测试。
642
+ *
643
+ * @default false
644
+ */
645
+ abortOnFail: boolean;
646
+ /**
647
+ * Exit Zotero when the test is finished.
648
+ *
649
+ * 测试完成后退出 Zotero。
650
+ *
651
+ * @default false
652
+ */
653
+ exitOnFinish: boolean;
654
+ headless: boolean;
655
+ /**
656
+ * The delay time before running the test. Make sure the plugin is fully loaded before running the test.
657
+ *
658
+ * 运行测试前的延迟时间。确保插件在运行测试前完全加载。
659
+ *
660
+ * @default 1000
661
+ */
662
+ startupDelay: number;
663
+ /**
664
+ * Function string that returns the initialization status of the plugin.
665
+ *
666
+ * If set, the test will wait until the function returns true before running the test.
667
+ *
668
+ * 返回插件初始化状态的函数字符串。
669
+ *
670
+ * 如果设置,测试将等待函数返回 true 后再运行测试。
671
+ *
672
+ * @default "()=>true"
673
+ *
674
+ * @example
675
+ * ```js
676
+ * () => !!Zotero.BetterNotes.data.initialized
677
+ * ```
678
+ */
679
+ waitForPlugin: string;
680
+ hooks: Partial<TestHooks>;
681
+ }
682
+ interface TestHooks {
683
+ "test:init": (ctx: Context) => void | Promise<void>;
684
+ "test:prebuild": (ctx: Context) => void | Promise<void>;
685
+ "test:listen": (ctx: Context) => void | Promise<void>;
686
+ "test:mkdir": (ctx: Context) => void | Promise<void>;
687
+ "test:copyAssets": (ctx: Context) => void | Promise<void>;
688
+ "test:bundleTests": (ctx: Context) => void | Promise<void>;
689
+ "test:run": (ctx: Context) => void | Promise<void>;
690
+ "test:done": (ctx: Context) => void | Promise<void>;
691
+ }
692
+ interface Hooks extends BuildHooks, ServeHooks, ReleaseHooks, TestHooks {
600
693
  }
601
694
 
602
695
  type RecursivePartial<T> = {
@@ -708,9 +801,45 @@ declare class Serve extends Base {
708
801
  exit: () => never;
709
802
  }
710
803
 
804
+ declare class Test extends Base {
805
+ private builder;
806
+ private _profileDir?;
807
+ private _dataDir?;
808
+ private _testPluginDir?;
809
+ private _testPluginRef;
810
+ private _testPluginID;
811
+ private _testBuildDir?;
812
+ private _server?;
813
+ private _process?;
814
+ get startArgs(): string[];
815
+ constructor(ctx: Context);
816
+ run(): Promise<void>;
817
+ prepareDir(): Promise<void>;
818
+ createManifest(): Promise<void>;
819
+ createBootstrap(): Promise<void>;
820
+ createTestResources(): Promise<void>;
821
+ bundleTests(): Promise<void>;
822
+ startTestServer(): Promise<void>;
823
+ handleTestUpdate(body: {
824
+ type: "start" | "suite" | "suite end" | "pending" | "pass" | "fail" | "end";
825
+ data?: {
826
+ title: string;
827
+ str: string;
828
+ duration?: number;
829
+ stack?: string;
830
+ };
831
+ }): Promise<void>;
832
+ prepareHeadless(): Promise<void>;
833
+ installXvfb(): Promise<void>;
834
+ installZoteroLinux(): Promise<void>;
835
+ startZoteroHeadless(): Promise<void>;
836
+ startZotero(): Promise<child_process.ChildProcessWithoutNullStreams>;
837
+ exit(status?: number): Promise<void>;
838
+ }
839
+
711
840
  declare const Config: {
712
841
  defineConfig: typeof defineConfig;
713
842
  loadConfig: typeof loadConfig;
714
843
  };
715
844
 
716
- export { Build, Config, Release, Serve, defineConfig };
845
+ export { Build, Config, Release, Serve, Test, defineConfig };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Hookable } from 'hookable';
2
2
  import * as esbuild from 'esbuild';
3
3
  import { BuildOptions } from 'esbuild';
4
+ import * as child_process from 'child_process';
4
5
 
5
6
  /**
6
7
  * Logger
@@ -10,6 +11,7 @@ declare class Log {
10
11
  constructor(config?: Config$1);
11
12
  private formatArgs;
12
13
  private logArgs;
14
+ log(...args: any[]): void;
13
15
  error(...args: any[]): void;
14
16
  warn(...args: any[]): void;
15
17
  tip(...args: any[]): void;
@@ -178,7 +180,7 @@ interface Config$1 {
178
180
  *
179
181
  * 一些可用的占位符请参阅 Context.templateData。
180
182
  *
181
- * @default `https://github.com/{{owner}}/{{repo}}/release/download/release/update.json`
183
+ * @default `https://github.com/{{owner}}/{{repo}}/releaser/download/release/{{updateJson}}`
182
184
  *
183
185
  * @see {@link Context.templateData}
184
186
  */
@@ -205,6 +207,14 @@ interface Config$1 {
205
207
  * 发布相关配置。
206
208
  */
207
209
  release: ReleaseConfig;
210
+ /**
211
+ * Configurations required to run the test.
212
+ *
213
+ * 测试相关配置。
214
+ *
215
+ * Test is a variant of server, so it is not a separate hooks.
216
+ */
217
+ test: TestConfig;
208
218
  /**
209
219
  * Level of the log.
210
220
  *
@@ -596,7 +606,90 @@ interface ReleaseHooks {
596
606
  "release:push": (ctx: Context) => void | Promise<void>;
597
607
  "release:done": (ctx: Context) => void | Promise<void>;
598
608
  }
599
- interface Hooks extends BuildHooks, ServeHooks, ReleaseHooks {
609
+ interface TestConfig {
610
+ /**
611
+ * The test source code directories, starting from the root directory of the project.
612
+ * All `*.spec.js` files in these directories will be executed.
613
+ * The files will be sorted by alphabetical order.
614
+ *
615
+ * 测试源码目录,从项目的根目录开始。
616
+ * 这些目录中的所有 `*.spec.js` 文件将被执行。
617
+ * 文件将按字母顺序排序。
618
+ *
619
+ * @default "test/"
620
+ */
621
+ entries: string | string[];
622
+ /**
623
+ * The default preferences for the test.
624
+ * These preferences will be set before the test starts.
625
+ *
626
+ * 测试的默认首选项。
627
+ * 这些首选项将在测试开始前设置。
628
+ */
629
+ prefs: Record<string, string | boolean | number>;
630
+ /**
631
+ * Port for the test server.
632
+ *
633
+ * 测试服务器的端口。
634
+ *
635
+ * @default 9876
636
+ */
637
+ port: number;
638
+ /**
639
+ * Abort the test when the first test fails.
640
+ *
641
+ * 当第一个测试失败时中止测试。
642
+ *
643
+ * @default false
644
+ */
645
+ abortOnFail: boolean;
646
+ /**
647
+ * Exit Zotero when the test is finished.
648
+ *
649
+ * 测试完成后退出 Zotero。
650
+ *
651
+ * @default false
652
+ */
653
+ exitOnFinish: boolean;
654
+ headless: boolean;
655
+ /**
656
+ * The delay time before running the test. Make sure the plugin is fully loaded before running the test.
657
+ *
658
+ * 运行测试前的延迟时间。确保插件在运行测试前完全加载。
659
+ *
660
+ * @default 1000
661
+ */
662
+ startupDelay: number;
663
+ /**
664
+ * Function string that returns the initialization status of the plugin.
665
+ *
666
+ * If set, the test will wait until the function returns true before running the test.
667
+ *
668
+ * 返回插件初始化状态的函数字符串。
669
+ *
670
+ * 如果设置,测试将等待函数返回 true 后再运行测试。
671
+ *
672
+ * @default "()=>true"
673
+ *
674
+ * @example
675
+ * ```js
676
+ * () => !!Zotero.BetterNotes.data.initialized
677
+ * ```
678
+ */
679
+ waitForPlugin: string;
680
+ hooks: Partial<TestHooks>;
681
+ }
682
+ interface TestHooks {
683
+ "test:init": (ctx: Context) => void | Promise<void>;
684
+ "test:prebuild": (ctx: Context) => void | Promise<void>;
685
+ "test:listen": (ctx: Context) => void | Promise<void>;
686
+ "test:mkdir": (ctx: Context) => void | Promise<void>;
687
+ "test:copyAssets": (ctx: Context) => void | Promise<void>;
688
+ "test:bundleTests": (ctx: Context) => void | Promise<void>;
689
+ "test:run": (ctx: Context) => void | Promise<void>;
690
+ "test:done": (ctx: Context) => void | Promise<void>;
691
+ }
692
+ interface Hooks extends BuildHooks, ServeHooks, ReleaseHooks, TestHooks {
600
693
  }
601
694
 
602
695
  type RecursivePartial<T> = {
@@ -708,9 +801,45 @@ declare class Serve extends Base {
708
801
  exit: () => never;
709
802
  }
710
803
 
804
+ declare class Test extends Base {
805
+ private builder;
806
+ private _profileDir?;
807
+ private _dataDir?;
808
+ private _testPluginDir?;
809
+ private _testPluginRef;
810
+ private _testPluginID;
811
+ private _testBuildDir?;
812
+ private _server?;
813
+ private _process?;
814
+ get startArgs(): string[];
815
+ constructor(ctx: Context);
816
+ run(): Promise<void>;
817
+ prepareDir(): Promise<void>;
818
+ createManifest(): Promise<void>;
819
+ createBootstrap(): Promise<void>;
820
+ createTestResources(): Promise<void>;
821
+ bundleTests(): Promise<void>;
822
+ startTestServer(): Promise<void>;
823
+ handleTestUpdate(body: {
824
+ type: "start" | "suite" | "suite end" | "pending" | "pass" | "fail" | "end";
825
+ data?: {
826
+ title: string;
827
+ str: string;
828
+ duration?: number;
829
+ stack?: string;
830
+ };
831
+ }): Promise<void>;
832
+ prepareHeadless(): Promise<void>;
833
+ installXvfb(): Promise<void>;
834
+ installZoteroLinux(): Promise<void>;
835
+ startZoteroHeadless(): Promise<void>;
836
+ startZotero(): Promise<child_process.ChildProcessWithoutNullStreams>;
837
+ exit(status?: number): Promise<void>;
838
+ }
839
+
711
840
  declare const Config: {
712
841
  defineConfig: typeof defineConfig;
713
842
  loadConfig: typeof loadConfig;
714
843
  };
715
844
 
716
- export { Build, Config, Release, Serve, defineConfig };
845
+ export { Build, Config, Release, Serve, Test, defineConfig };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { B as Build, C as Config, R as Release, S as Serve, d as defineConfig } from './shared/zotero-plugin-scaffold.b59b2bc7.mjs';
1
+ export { B as Build, C as Config, R as Release, S as Serve, T as Test, d as defineConfig } from './shared/zotero-plugin-scaffold.ac50adf5.mjs';
2
2
  import 'node:path';
3
3
  import 'c12';
4
4
  import 'es-toolkit';
@@ -17,3 +17,7 @@ import 'node:child_process';
17
17
  import 'bumpp';
18
18
  import 'chokidar';
19
19
  import 'node:fs';
20
+ import 'node:fs/promises';
21
+ import 'node:http';
22
+ import 'fs-extra/esm';
23
+ import 'xvfb-ts';