zotero-plugin-scaffold 0.0.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 ADDED
@@ -0,0 +1,168 @@
1
+ # Zotero Plugin Development Scaffold
2
+
3
+ Working in progress.
4
+
5
+ Create a standalone npm package for scripts in the zotero-plugin-template repository, so that downstream developers can follow along.
6
+
7
+ This repository serves only as a proof-of-concept for the above.
8
+
9
+ ## Using in a blank project
10
+
11
+ > WIP
12
+
13
+ ```bash
14
+ # npm
15
+ npx zotero-plugin create
16
+ # pnpm
17
+ pnpm dlx zotero-plugin create
18
+ ```
19
+
20
+ ## Using in an existing project
21
+
22
+ ### 01. Install
23
+
24
+ #### From NPM
25
+
26
+ > WIP
27
+
28
+ ```bash
29
+ npm install -D zotero-plugin-scaffold
30
+
31
+ yarn add -D zotero-plugin-scaffold
32
+
33
+ pnpm add -D zotero-plugin-scaffold
34
+ ```
35
+
36
+ #### From source code
37
+
38
+ ```bash
39
+ # clone this repo
40
+ git clone https://github.com/northword/zotero-plugin-scaffold.git zotero-plugin-scaffold/
41
+ cd zotero-plugin-scaffold/
42
+
43
+ # build
44
+ pnpm install
45
+ pnpm run build
46
+
47
+ # npm link
48
+ cd your-plugin-work-dir/
49
+ pnpm link ../zotero-plugin-scaffold
50
+ ```
51
+
52
+ ### 02. Create a config file
53
+
54
+ The configuration file needs to be stored in the following location. If the configuration file is not found, an error will be thrown.
55
+
56
+ ```bash
57
+ zotero-plugin.config.ts
58
+ # also avaliable in *.js *.mjs *.cjs *.ts
59
+ # Or The `zotero-plugin`` property in `package.json`
60
+ # see https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#usage-for-end-users
61
+ ```
62
+
63
+ You can import `defineConfig` in js module to get type hints. If no value is specified for an optional property, the default value will be used.
64
+
65
+ ```ts
66
+ import { defineConfig } from "zotero-plugin-scaffold";
67
+
68
+ export default defineConfig({
69
+ placeholders: {
70
+ addonName: "Test Addon for Zotero",
71
+ addonID: "",
72
+ addonRef: "",
73
+ addonInstance: "",
74
+ updateJSON: "",
75
+ releasePage: ""
76
+ },
77
+ });
78
+ ```
79
+
80
+ Full config please refrence in [src/types.ts](./src/types.ts).
81
+
82
+ ### 03. Create a env file
83
+
84
+ This file defines Zotero's runtime configuration such as binary paths, profile paths, and environment variables required for Node scripts to run.
85
+
86
+ NOTE: Do not check-in this file to the repository!
87
+
88
+ ```bash
89
+ .env
90
+ ```
91
+
92
+ ```ini
93
+ # Please input the path of the Zotero binary file in `zoteroBinPath`.
94
+ # The path delimiter should be escaped as `\\` for win32. The path is `*/Zotero.app/Contents/MacOS/zotero` for MacOS.
95
+ zoteroBinPath = /path/to/zotero.exe
96
+
97
+ # Please input the path of the profile used for development in `profilePath`.
98
+ # Start the profile manager by `/path/to/zotero.exe -p` to create a profile for development
99
+ # https://www.zotero.org/support/kb/profile_directory
100
+ profilePath = /path/to/profile
101
+
102
+ # Please input the directory where the database is located in dataDir
103
+ # If this field is kept empty, Zotero will start with the default data.
104
+ # https://www.zotero.org/support/zotero_data
105
+ dataDir =
106
+
107
+ # Other environment variables (optional)
108
+ # GITHUB_TOKEN =
109
+ ```
110
+
111
+ ### 04. Add scripts to package.json
112
+
113
+ ```json
114
+ {
115
+ "scripts": {
116
+ "start": "zotero-plugin server",
117
+ "build": "zotero-plugin build",
118
+ "release": "zotero-plugin release"
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### 05. Run
124
+
125
+ ```bash
126
+ pnpm run start
127
+ pnpm run build
128
+
129
+ # Or, run cmd in terminal
130
+ pnpm exec zotero-plugin build
131
+ ```
132
+
133
+ ## Using in NodeJS code
134
+
135
+ ```ts
136
+ import { Build, Config } from "zotero-plugin-scaffold";
137
+
138
+ const config = await Config.loadConfig();
139
+
140
+ const Builder = new Build(config, "production");
141
+ await Builder.run();
142
+ ```
143
+
144
+ ## Contributing
145
+
146
+ ```bash
147
+ # Git Clone
148
+ git clone https://github.com/northword/zotero-plugin-scaffold.git zotero-plugin-scaffold
149
+ cd zotero-plugin-scaffold/
150
+
151
+ # Install deps
152
+ pnpm install
153
+
154
+ # Watch
155
+ pnpm run dev
156
+
157
+ # Build
158
+ pnpm run build
159
+
160
+ # Lint and Prettier
161
+ pnpm run lint:fix
162
+ ```
163
+
164
+ ## Acknowledgements
165
+
166
+ This project references the design and code of the [Zotero Plugin Template](https://github.com/windingwind/zotero-plugin-template).
167
+
168
+ This project would not be possible without the support of the [open source community](https://github.com/northword/zotero-plugin-scaffold/network/dependencies).
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import cli from "../dist/cli.js";
3
+ import Log from "../dist/utils/log.js";
4
+
5
+ const Logger = new Log();
6
+
7
+ cli();
8
+
9
+ process.on("unhandledRejection", (err) => {
10
+ Logger.log("");
11
+ Logger.error(err);
12
+ Logger.log("");
13
+
14
+ process.exit(1);
15
+ });
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export default function main(): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,81 @@
1
+ import { Build, Config, Create, Release, Serve } from "./index.js";
2
+ import Log from "./utils/log.js";
3
+ import { Command } from "commander";
4
+ import { default as fs } from "fs-extra";
5
+ import _ from "lodash";
6
+ import path from "path";
7
+ import updateNotifier from "update-notifier";
8
+ import { fileURLToPath } from "url";
9
+ export default async function main() {
10
+ const Logger = new Log();
11
+ // Use readFileSync instead of import json to avoid loging warning
12
+ const pkg = fs.readJsonSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "../package.json"), {
13
+ encoding: "utf-8",
14
+ });
15
+ updateNotifier({ pkg: pkg }).notify();
16
+ // Env variables are initialized to dev, but can be overridden by each command
17
+ // For example, "zotero-plugin build" overrides them to "production"
18
+ process.env.NODE_ENV ??= "development";
19
+ const cli = new Command();
20
+ cli.version(pkg.version).usage("<command> [options]");
21
+ cli
22
+ .command("build")
23
+ .description("Build the plugin.")
24
+ .option("--dev", "Builds the plugin in dev mode.")
25
+ .option("--dist <dir>", "the full path for the new output directory, relative to the current workspace (default: build)")
26
+ .option("--config <config>", "path to zotero-plugin config file (default: `zotero-plugin.config.ts`)")
27
+ .action(async (options) => {
28
+ process.env.NODE_ENV = options.dev ? "development" : "production";
29
+ const configFile = await Config.loadConfig(options.config);
30
+ const configCli = {
31
+ dist: options.dist,
32
+ };
33
+ const configMerged = _.merge(configFile, configCli);
34
+ new Build(configMerged).run();
35
+ });
36
+ cli
37
+ .command("serve")
38
+ .description("Start development server.")
39
+ .option("--config <config>", "path to zotero-plugin config file (default: `zotero-plugin.config.ts`)")
40
+ // .option(
41
+ // "--skip-build",
42
+ // "skip building website before deploy it (default: false)",
43
+ // )
44
+ // .option(
45
+ // "--only-start",
46
+ // "skip building website before deploy it (default: false)",
47
+ // )
48
+ .action(async (options) => {
49
+ const configFile = await Config.loadConfig(options.config);
50
+ const configCli = {
51
+ //
52
+ };
53
+ const configMerged = _.merge(configFile, configCli);
54
+ new Serve(configMerged).run();
55
+ });
56
+ cli
57
+ .command("create")
58
+ .description("Create the plugin template.")
59
+ .action((options) => {
60
+ console.log("The create not yet implemented");
61
+ new Create().run();
62
+ });
63
+ cli
64
+ .command("release")
65
+ .description("Release.")
66
+ .option("--config <config>", "path to zotero-plugin config file (default: `zotero-plugin.config.ts`)")
67
+ .action(async (options) => {
68
+ process.env.NODE_ENV = "production";
69
+ const configFile = await Config.loadConfig(options.config);
70
+ const configCli = {
71
+ //
72
+ };
73
+ const configMerged = _.merge(configFile, configCli);
74
+ new Release(configMerged).run();
75
+ });
76
+ cli.arguments("<command>").action((cmd) => {
77
+ cli.outputHelp();
78
+ Logger.error(`Unknown command name=${cmd}.`);
79
+ });
80
+ cli.parse(process.argv);
81
+ }
@@ -0,0 +1,15 @@
1
+ import { Config, UserConfig } from "./types";
2
+ /**
3
+ * Define the configuration.
4
+ *
5
+ * Defines the configuration in the parameters of this function to provide type checking for user configurations.
6
+ * @param [userConfig]
7
+ * @returns Config with userDefined.
8
+ */
9
+ export declare const defineConfig: (userConfig: UserConfig) => UserConfig;
10
+ /**
11
+ * Loads config
12
+ * @param [file="zotero-plugin.config.{ts,js,mjs,cjs}"] The path of config file.
13
+ * @returns Config with userDefined and defaultConfig merged.
14
+ */
15
+ export declare function loadConfig(file?: string): Promise<Config>;
package/dist/config.js ADDED
@@ -0,0 +1,174 @@
1
+ import { cosmiconfig } from "cosmiconfig";
2
+ import * as dotenv from "dotenv";
3
+ import { default as fs } from "fs-extra";
4
+ import _ from "lodash";
5
+ import path from "path";
6
+ import { fileURLToPath } from "url";
7
+ /**
8
+ * Define the configuration.
9
+ *
10
+ * Defines the configuration in the parameters of this function to provide type checking for user configurations.
11
+ * @param [userConfig]
12
+ * @returns Config with userDefined.
13
+ */
14
+ export const defineConfig = (userConfig) => {
15
+ return userConfig;
16
+ };
17
+ /**
18
+ * Loads config
19
+ * @param [file="zotero-plugin.config.{ts,js,mjs,cjs}"] The path of config file.
20
+ * @returns Config with userDefined and defaultConfig merged.
21
+ */
22
+ export async function loadConfig(file) {
23
+ // load user defined config file
24
+ // Do not use the sync method, as the sync method only supports compiling configuration files into cjs modules.
25
+ const explorer = cosmiconfig("zotero-plugin"), result = await explorer.search(file);
26
+ const userConfig = result?.config ?? {};
27
+ // load `.env` file.
28
+ const dotenvResult = dotenv.config({
29
+ path: path.resolve(process.cwd(), userConfig.dotEnvPath ?? ".env"),
30
+ }).parsed;
31
+ if (!dotenvResult)
32
+ throw new Error(".env file not found");
33
+ // Load user's package.json
34
+ const pkg = fs.readJsonSync(path.join("package.json"), {
35
+ encoding: "utf-8",
36
+ });
37
+ // define addon config 防呆
38
+ const addonName = userConfig.define?.addonName ||
39
+ pkg.config?.addonName ||
40
+ _.startCase(pkg.name) ||
41
+ "", addonRef = userConfig.define?.addonRef ||
42
+ pkg.config?.addonRef ||
43
+ _.kebabCase(addonName), xpiName = userConfig.define?.xpiName || pkg.name || _.kebabCase(addonName), [, owner, repo] = (pkg.repository?.url ?? "").match(/:\/\/github.com\/([^/]+)\/([^.]+)\.git$/), releasePage = userConfig.define?.releasePage ||
44
+ (owner && repo ? `https://github.com/${owner}/${repo}/release` : ""), isPreRelease = pkg.version.includes("-");
45
+ // define default config.
46
+ const defaultConfig = {
47
+ source: ["src"],
48
+ dist: "build",
49
+ assets: ["src/**/*.*", "!src/**/*.ts"],
50
+ define: {
51
+ addonName: addonName,
52
+ addonID: pkg.config?.addonID || "",
53
+ description: pkg.description || "",
54
+ homepage: pkg.homepage,
55
+ author: pkg.author,
56
+ ghOwner: owner,
57
+ ghRepo: repo,
58
+ addonRef: pkg.config?.addonRef || _.kebabCase(addonName),
59
+ addonInstance: pkg.config?.addonInstence || _.camelCase(addonName),
60
+ prefsPrefix: `extensions.zotero.${addonRef}`,
61
+ xpiName: xpiName,
62
+ releasePage: releasePage,
63
+ updateURL: `${releasePage}/download/${userConfig.makeUpdateJson?.tagName || "release"}/${isPreRelease ? "update-beta" : "update"}.json`,
64
+ updateLink: `${releasePage}/download/v${pkg.version}/${xpiName}.xpi`,
65
+ buildVersion: pkg.version,
66
+ },
67
+ fluent: {
68
+ prefixFluentMessages: true,
69
+ prefixLocaleFiles: true,
70
+ },
71
+ esbuildOptions: [
72
+ {
73
+ entryPoints: ["src/index.ts"],
74
+ define: {
75
+ __env__: `"${process.env.NODE_ENV}"`,
76
+ },
77
+ bundle: true,
78
+ target: "firefox102",
79
+ outfile: path.join(process.cwd(), userConfig.dist || "build", `addon/${addonRef || "index"}.js`),
80
+ minify: process.env.NODE_ENV === "production",
81
+ },
82
+ ],
83
+ makeBootstrap: true,
84
+ makeManifest: {
85
+ enable: true,
86
+ template: {
87
+ manifest_version: 2,
88
+ name: "__addonName__",
89
+ version: "__buildVersion__",
90
+ description: "__description__",
91
+ homepage_url: "__homepage__",
92
+ author: "__author__",
93
+ icons: {
94
+ "48": "content/icons/favicon@0.5x.png",
95
+ "96": "content/icons/favicon.png",
96
+ },
97
+ applications: {
98
+ zotero: {
99
+ id: "__addonID__",
100
+ update_url: "__updateURL__",
101
+ strict_min_version: "6.999",
102
+ strict_max_version: "7.0.*",
103
+ },
104
+ gecko: {
105
+ id: "__addonID__",
106
+ update_url: "__updateURL__",
107
+ strict_min_version: "102",
108
+ },
109
+ },
110
+ },
111
+ },
112
+ makeUpdateJson: {
113
+ enable: true,
114
+ tagName: "release",
115
+ template: {
116
+ addons: {
117
+ __addonID__: {
118
+ updates: [
119
+ {
120
+ version: "__version__",
121
+ update_link: "__updateLink__",
122
+ update_hash: "__updateHash__",
123
+ applications: {
124
+ zotero: {
125
+ strict_min_version: "6.999",
126
+ },
127
+ },
128
+ },
129
+ ],
130
+ },
131
+ },
132
+ },
133
+ },
134
+ extraServer: () => { },
135
+ extraBuilder: () => { },
136
+ addonLint: {},
137
+ release: {
138
+ releaseIt: {
139
+ preReleaseId: "beta",
140
+ git: {
141
+ tagName: "v${version}",
142
+ requireCleanWorkingDir: false,
143
+ },
144
+ npm: {
145
+ publish: false,
146
+ },
147
+ github: {
148
+ assets: [`${userConfig.dist}/*.xpi`],
149
+ },
150
+ },
151
+ bumpp: {
152
+ release: "prompt",
153
+ preid: "beta",
154
+ // execute: "npm run build",
155
+ all: true,
156
+ commit: "Release v%s",
157
+ tag: "v%s",
158
+ push: true,
159
+ },
160
+ },
161
+ logLevel: "info",
162
+ dotEnvPath: ".env",
163
+ cmd: {
164
+ zoteroBinPath: dotenvResult["zoteroBinPath"],
165
+ profilePath: dotenvResult["profilePath"],
166
+ dataDir: dotenvResult["dataDir"],
167
+ },
168
+ pkgUser: pkg,
169
+ pkgAbsolute: path.join(path.dirname(fileURLToPath(import.meta.url)), "../"),
170
+ };
171
+ // merge config
172
+ const config = _.defaultsDeep(userConfig, defaultConfig);
173
+ return config;
174
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig, loadConfig } from "./config.js";
2
+ import Build from "./lib/build.js";
3
+ import Create from "./lib/create.js";
4
+ import Release from "./lib/release.js";
5
+ import Serve from "./lib/serve.js";
6
+ declare const Config: {
7
+ defineConfig: (userConfig: import("./types.js").UserConfig) => import("./types.js").UserConfig;
8
+ loadConfig: typeof loadConfig;
9
+ };
10
+ export { defineConfig, Config, Create, Build, Serve, Release };
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { defineConfig, loadConfig } from "./config.js";
2
+ import Build from "./lib/build.js";
3
+ import Create from "./lib/create.js";
4
+ import Release from "./lib/release.js";
5
+ import Serve from "./lib/serve.js";
6
+ const Config = {
7
+ defineConfig,
8
+ loadConfig,
9
+ };
10
+ export { defineConfig, Config, Create, Build, Serve, Release };
@@ -0,0 +1,25 @@
1
+ import { Config } from "../types.js";
2
+ import { LibBase } from "../utils/libBase.js";
3
+ export default class Build extends LibBase {
4
+ private buildTime;
5
+ private isPreRelease;
6
+ constructor(config: Config);
7
+ /**
8
+ * Default build runner
9
+ */
10
+ run(): Promise<void>;
11
+ /**
12
+ * Copys files in `Config.assets` to `Config.dist`
13
+ */
14
+ copyAssets(): void;
15
+ makeManifest(): void;
16
+ makebootstrap(): void;
17
+ /**
18
+ * Replace all `placeholder.key` to `placeholder.value` for all files in `dist`
19
+ */
20
+ replaceString(): void;
21
+ prepareLocaleFiles(): void;
22
+ esbuild(): void;
23
+ makeUpdateJson(): void;
24
+ pack(): Promise<void>;
25
+ }