zotero-plugin-scaffold 0.4.2 → 0.6.0

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/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import process from 'node:process';
2
2
  import { Command } from 'commander';
3
- import { l as logger, E as ExitSignals, C as Config, B as Build, S as Serve, T as Test, R as Release } from './shared/zotero-plugin-scaffold.DGHktPRh.mjs';
3
+ import { l as logger, E as ExitSignals, C as Config, B as Build, S as Serve, T as Test, R as Release } from './shared/zotero-plugin-scaffold.C-SXQX4J.mjs';
4
4
  import { readFile } from 'node:fs/promises';
5
5
  import { pathExists } from 'fs-extra';
6
6
  import tinyUpdateNotifier from 'tiny-update-notifier';
@@ -13,11 +13,12 @@ import 'node:util';
13
13
  import 'std-env';
14
14
  import './shared/zotero-plugin-scaffold.v8dJZZ-v.mjs';
15
15
  import 'tinyglobby';
16
- import 'node:fs';
17
16
  import 'node:path';
18
17
  import 'adm-zip';
19
18
  import 'esbuild';
20
19
  import 'node:crypto';
20
+ import 'node:fs';
21
+ import '@fluent/syntax';
21
22
  import '@swc/core';
22
23
  import 'node:child_process';
23
24
  import 'bumpp';
@@ -31,7 +32,7 @@ import 'xvfb-ts';
31
32
  import 'node:http';
32
33
 
33
34
  const name = "zotero-plugin-scaffold";
34
- const version = "0.4.2";
35
+ const version = "0.6.0";
35
36
  const pkg = {
36
37
  name: name,
37
38
  version: version};
package/dist/index.d.mts CHANGED
@@ -315,6 +315,20 @@ interface BuildConfig {
315
315
  * @default []
316
316
  */
317
317
  ignore: string[];
318
+ /**
319
+ * Generate i10n.d.ts form fluent messages.
320
+ *
321
+ * - false: disable
322
+ * - string: path of dts file
323
+ *
324
+ * 为 Fluent messages 生成类型声明文件。
325
+ *
326
+ * - false: 禁用
327
+ * - string:dts 文件路径
328
+ *
329
+ * @default 'typings/i10n.d.ts'
330
+ */
331
+ dts: string | false;
318
332
  };
319
333
  prefs: {
320
334
  /**
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
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.DGHktPRh.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.C-SXQX4J.mjs';
2
2
  import 'c12';
3
3
  import 'es-toolkit';
4
4
  import 'fs-extra/esm';
@@ -10,11 +10,12 @@ import 'std-env';
10
10
  import './shared/zotero-plugin-scaffold.v8dJZZ-v.mjs';
11
11
  import 'node:fs/promises';
12
12
  import 'tinyglobby';
13
- import 'node:fs';
14
13
  import 'node:path';
15
14
  import 'adm-zip';
16
15
  import 'esbuild';
17
16
  import 'node:crypto';
17
+ import 'node:fs';
18
+ import '@fluent/syntax';
18
19
  import '@swc/core';
19
20
  import 'node:child_process';
20
21
  import 'bumpp';
@@ -1,19 +1,20 @@
1
1
  import { loadConfig as loadConfig$1 } from 'c12';
2
2
  import { isPlainObject, kebabCase, mapValues, toMerged, escapeRegExp, debounce, delay } from 'es-toolkit';
3
- import { readJsonSync, outputFile, emptyDir, copy, readJSON, outputJSON, move, writeJson, pathExists, ensureDir, remove } from 'fs-extra/esm';
3
+ import { readJsonSync, move, outputFile, emptyDir, copy, readJSON, outputJSON, writeJson, pathExists, ensureDir, remove } from 'fs-extra/esm';
4
4
  import { createHooks } from 'hookable';
5
5
  import process from 'node:process';
6
6
  import readline from 'node:readline';
7
7
  import util from 'node:util';
8
8
  import { isDebug, isCI, isWindows, isMacOS, isLinux } from 'std-env';
9
9
  import { p as parseRepoUrl, d as dateFormat, t as template, b as toArray, a as replaceInFile } from './zotero-plugin-scaffold.v8dJZZ-v.mjs';
10
- import { createReadStream, existsSync } from 'node:fs';
11
- import { readFile, writeFile, stat } from 'node:fs/promises';
12
- import { basename, dirname, join, resolve, extname } from 'node:path';
10
+ import { dirname, basename, join, resolve, extname } from 'node:path';
13
11
  import AdmZip from 'adm-zip';
14
12
  import { build, context } from 'esbuild';
15
13
  import { glob, globSync } from 'tinyglobby';
16
14
  import { createHash } from 'node:crypto';
15
+ import { createReadStream, existsSync } from 'node:fs';
16
+ import { readFile, writeFile, stat } from 'node:fs/promises';
17
+ import { parse, serialize, Transformer } from '@fluent/syntax';
17
18
  import { parseSync, printSync } from '@swc/core';
18
19
  import { execSync, spawn } from 'node:child_process';
19
20
  import { versionBump, ProgressEvent } from 'bumpp';
@@ -264,7 +265,8 @@ const defaultConfig = {
264
265
  fluent: {
265
266
  prefixFluentMessages: true,
266
267
  prefixLocaleFiles: true,
267
- ignore: []
268
+ ignore: [],
269
+ dts: "typings/i10n.d.ts"
268
270
  },
269
271
  prefs: {
270
272
  prefix: "",
@@ -359,6 +361,205 @@ function generateHash(filePath, algorithm) {
359
361
  });
360
362
  }
361
363
 
364
+ class Base {
365
+ ctx;
366
+ constructor(ctx) {
367
+ this.ctx = ctx;
368
+ }
369
+ get logger() {
370
+ return this.ctx.logger;
371
+ }
372
+ }
373
+
374
+ async function buildLocale(dist, namespace, options) {
375
+ const ignores = toArray(options.ignore);
376
+ const localeNames = await getLocales(dist);
377
+ const messageManager = new MessageManager(ignores);
378
+ await Promise.all(localeNames.map(async (locale) => {
379
+ const paths = await glob(`${dist}/addon/locale/${locale}/**/*.ftl`);
380
+ await Promise.all(paths.map(async (path) => {
381
+ const fm = new FluentManager();
382
+ await fm.read(path);
383
+ messageManager.addMessages(locale, fm.getMessages());
384
+ if (options.prefixFluentMessages) {
385
+ fm.prefixMessages(namespace);
386
+ await fm.write(path);
387
+ }
388
+ if (options.prefixLocaleFiles) {
389
+ const newPath = `${dirname(path)}/${namespace}-${basename(path)}`;
390
+ await move(path, newPath);
391
+ logger.debug(`Renamed FTL: ${path} \u2192 ${newPath}`);
392
+ }
393
+ }));
394
+ }));
395
+ const htmlPaths = await glob([`${dist}/addon/**/*.xhtml`, `${dist}/addon/**/*.html`]);
396
+ await Promise.all(htmlPaths.map(async (htmlPath) => {
397
+ const content = await readFile(htmlPath, "utf-8");
398
+ const { processedContent, foundMessages } = processHTMLFile(
399
+ content,
400
+ namespace,
401
+ messageManager.getFTLMessages(),
402
+ ignores,
403
+ htmlPath
404
+ );
405
+ messageManager.addMessages("html", foundMessages);
406
+ if (options.prefixFluentMessages) {
407
+ await writeFile(htmlPath, processedContent);
408
+ }
409
+ }));
410
+ messageManager.validateMessages();
411
+ if (options.dts) {
412
+ const dtsContent = generateFluentDts([...messageManager.getFTLMessages()]);
413
+ await outputFile(options.dts, dtsContent, "utf-8");
414
+ }
415
+ }
416
+ async function getLocales(dist) {
417
+ const localePaths = await glob(`${dist}/addon/locale/*`, { onlyDirectories: true });
418
+ return localePaths.map((p) => basename(p));
419
+ }
420
+ class FluentManager {
421
+ source;
422
+ resource;
423
+ messages = [];
424
+ constructor() {
425
+ }
426
+ // Parse Fluent source into an AST and extract messages
427
+ parse(source) {
428
+ this.source = source;
429
+ this.resource = parse(source, {});
430
+ }
431
+ // Read a file, parse its content, and extract messages
432
+ async read(path) {
433
+ const content = await readFile(path, "utf-8");
434
+ this.parse(content);
435
+ }
436
+ // Extract message IDs from the parsed resource
437
+ getMessages() {
438
+ if (!this.resource) {
439
+ throw new Error("Resource must be parsed first.");
440
+ }
441
+ this.messages.length = 0;
442
+ this.messages.push(
443
+ ...this.resource.body.filter((entry) => entry.type === "Message").map((message) => message.id.name)
444
+ );
445
+ return this.messages;
446
+ }
447
+ // Apply namespace prefix to message IDs in the resource
448
+ prefixMessages(namespace) {
449
+ if (!this.resource) {
450
+ throw new Error("Resource must be parsed before applying prefix.");
451
+ }
452
+ new FluentTransformer(namespace).genericVisit(this.resource);
453
+ }
454
+ // Serialize the resource back into a string
455
+ serialize() {
456
+ if (!this.resource) {
457
+ throw new Error("Resource not parsed. Cannot serialize.");
458
+ }
459
+ return serialize(this.resource, {});
460
+ }
461
+ // Write the serialized resource to a file
462
+ async write(path) {
463
+ const result = this.serialize();
464
+ if (result !== this.source)
465
+ await writeFile(path, this.serialize());
466
+ }
467
+ }
468
+ class FluentTransformer extends Transformer {
469
+ constructor(prefix) {
470
+ super();
471
+ this.prefix = prefix;
472
+ }
473
+ needsPrefix(name) {
474
+ return !!this.prefix && !name.startsWith(this.prefix);
475
+ }
476
+ visitMessage(node) {
477
+ if (this.needsPrefix(node.id.name)) {
478
+ node.id.name = `${this.prefix}-${node.id.name}`;
479
+ }
480
+ return this.genericVisit(node);
481
+ }
482
+ visitMessageReference(node) {
483
+ if (this.needsPrefix(node.id.name)) {
484
+ node.id.name = `${this.prefix}-${node.id.name}`;
485
+ }
486
+ return this.genericVisit(node);
487
+ }
488
+ }
489
+ class MessageManager {
490
+ ftlMessages = /* @__PURE__ */ new Map();
491
+ htmlMessages = /* @__PURE__ */ new Set();
492
+ ignores;
493
+ constructor(ignores) {
494
+ this.ignores = ignores;
495
+ }
496
+ // Add a set of messages (FTL or HTML) for a specific locale or for HTML globally
497
+ addMessages(target, messages) {
498
+ if (target === "html") {
499
+ messages.forEach((msg) => this.htmlMessages.add(msg));
500
+ } else {
501
+ let ftlLocaleMessages = this.ftlMessages.get(target);
502
+ if (!ftlLocaleMessages) {
503
+ ftlLocaleMessages = /* @__PURE__ */ new Set();
504
+ this.ftlMessages.set(target, ftlLocaleMessages);
505
+ }
506
+ messages.forEach((msg) => ftlLocaleMessages.add(msg));
507
+ }
508
+ }
509
+ validateMessages() {
510
+ this.htmlMessages.forEach((msg) => {
511
+ if (this.ignores.includes(msg))
512
+ return;
513
+ const missingLocales = [...this.ftlMessages.entries()].filter(([_, messages]) => !messages.has(msg)).map(([locale]) => locale);
514
+ if (missingLocales.length > 0)
515
+ logger.warn(`I10N id ${styleText.blue(msg)} missing in locale: ${missingLocales.join(", ")}`);
516
+ });
517
+ }
518
+ getFTLMessages() {
519
+ const allMessages = /* @__PURE__ */ new Set();
520
+ this.ftlMessages.forEach((messages) => messages.forEach((msg) => allMessages.add(msg)));
521
+ return allMessages;
522
+ }
523
+ // Get all FTL messages for a specific locale
524
+ getFTLMessagesByLocale(locale) {
525
+ return this.ftlMessages.get(locale) || /* @__PURE__ */ new Set();
526
+ }
527
+ // Get all HTML messages
528
+ getHTMLMessages() {
529
+ return this.htmlMessages;
530
+ }
531
+ }
532
+ function processHTMLFile(content, namespace, allMessages, ignores, filePath) {
533
+ const foundMessages = /* @__PURE__ */ new Set();
534
+ const L10N_PATTERN = new RegExp(`(data-l10n-id)="((?!${namespace})\\S*)"`, "g");
535
+ const processed = content.replace(L10N_PATTERN, (match, attr, id) => {
536
+ foundMessages.add(id);
537
+ if (ignores.includes(id)) {
538
+ logger.debug(`Skipped ignored ID: ${styleText.blue(id)} in ${styleText.gray(filePath)}`);
539
+ return match;
540
+ }
541
+ if (!allMessages.has(id)) {
542
+ logger.warn(`I10N id ${styleText.blue(id)} in path ${styleText.gray(filePath)} does not exist in any locale, skip renaming it.`);
543
+ return match;
544
+ }
545
+ return `${attr}="${namespace}-${id}"`;
546
+ });
547
+ return { processedContent: processed, foundMessages: [...foundMessages] };
548
+ }
549
+ function generateFluentDts(messages) {
550
+ return `// Generated by zotero-plugin-scaffold
551
+ /* prettier-ignore */
552
+ /* eslint-disable */
553
+ // @ts-nocheck
554
+ export type FluentMessageId =
555
+ ${Array.from(messages).sort().map((id) => ` | '${id}'`).join("\n")};
556
+ `;
557
+ }
558
+
559
+ function is32BitNumber(n) {
560
+ return Number.isInteger(n) && n >= -2147483648 && n <= 2147483647;
561
+ }
562
+
362
563
  class PrefsManager {
363
564
  namespace;
364
565
  prefs = {};
@@ -580,6 +781,62 @@ class PrefsManager {
580
781
  return _prefs;
581
782
  }
582
783
  }
784
+
785
+ async function buildPrefs(dist, options) {
786
+ const { dts, prefixPrefKeys, prefix } = options;
787
+ if (!prefixPrefKeys && !dts)
788
+ return;
789
+ const prefsFilePath = join(dist, "addon", "prefs.js");
790
+ if (!existsSync(prefsFilePath))
791
+ return;
792
+ const prefsManager = new PrefsManager("pref");
793
+ await prefsManager.read(prefsFilePath);
794
+ const prefsWithPrefix = prefsManager.getPrefsWithPrefix(prefix);
795
+ const prefsWithoutPrefix = prefsManager.getPrefsWithoutPrefix(prefix);
796
+ const prefs = prefsManager.getPrefs();
797
+ Object.entries(prefs).forEach(([key, value]) => {
798
+ if (typeof value === "number") {
799
+ if (!is32BitNumber(value)) {
800
+ logger.warn(`Pref key '${styleText.blue(key)}' is a number, but is more than 4 bytes, which can be problematic on some OS.`);
801
+ }
802
+ }
803
+ });
804
+ if (dts) {
805
+ const dtsContent = renderPluginPrefsDts(prefsWithoutPrefix);
806
+ await outputFile(dts, dtsContent, "utf-8");
807
+ }
808
+ if (prefixPrefKeys) {
809
+ prefsManager.clearPrefs();
810
+ prefsManager.setPrefs(prefsWithPrefix);
811
+ await prefsManager.write(prefsFilePath);
812
+ }
813
+ if (prefixPrefKeys) {
814
+ const HTML_PREFERENCE_PATTERN = /preference="(\S*)"/g;
815
+ const xhtmlPaths = await glob(`${dist}/addon/**/*.xhtml`);
816
+ await Promise.all(xhtmlPaths.map(async (path) => {
817
+ let content = await readFile(path, "utf-8");
818
+ const matchs = [...content.matchAll(HTML_PREFERENCE_PATTERN)];
819
+ for (const match of matchs) {
820
+ const [matched, key] = match;
821
+ if (key.startsWith(prefix)) {
822
+ logger.debug(`Pref key '${styleText.blue(key)}' is already starts with '${prefix}', skip prefixing it.`);
823
+ continue;
824
+ } else if (key.startsWith("extensions.")) {
825
+ logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} starts with 'extensions.' but not '${styleText.blue(prefix)}', skip prefixing it.`);
826
+ continue;
827
+ } else if (!(key in prefsWithPrefix) && !(key in prefsWithoutPrefix)) {
828
+ logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is not found in prefs.js, skip prefixing it.`);
829
+ continue;
830
+ } else {
831
+ const prefixed = `${prefix}.${key}`;
832
+ logger.debug(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is prefixed to ${styleText.blue(prefixed)}.`);
833
+ content = content.replace(matched, `preference="${prefixed}"`);
834
+ }
835
+ }
836
+ await outputFile(path, content, "utf-8");
837
+ }));
838
+ }
839
+ }
583
840
  function renderPluginPrefsDts(prefs) {
584
841
  return `// Generated by zotero-plugin-scaffold
585
842
  /* prettier-ignore */
@@ -599,16 +856,6 @@ declare namespace _ZoteroTypes {
599
856
  `;
600
857
  }
601
858
 
602
- class Base {
603
- ctx;
604
- constructor(ctx) {
605
- this.ctx = ctx;
606
- }
607
- get logger() {
608
- return this.ctx.logger;
609
- }
610
- }
611
-
612
859
  class Build extends Base {
613
860
  buildTime;
614
861
  isPreRelease;
@@ -711,119 +958,11 @@ class Build extends Base {
711
958
  }
712
959
  async prepareLocaleFiles() {
713
960
  const { dist, namespace, build } = this.ctx;
714
- const ignores = toArray(build.fluent.ignore);
715
- const FTL_MESSAGE_PATTERN = /^(?<message>[a-z]\S*)( *= *)(?<pattern>.*)$/gim;
716
- const HTML_DATAI10NID_PATTERN = new RegExp(`(data-l10n-id)="((?!${namespace})\\S*)"`, "g");
717
- const localePaths = await glob(`${dist}/addon/locale/*`, { onlyDirectories: true });
718
- const localeNames = localePaths.map((locale) => basename(locale));
719
- this.logger.debug(`Locale names:", ${localeNames}`);
720
- const allMessages = /* @__PURE__ */ new Set();
721
- const messagesByLocale = /* @__PURE__ */ new Map();
722
- for (const localeName of localeNames) {
723
- const localeMessages = /* @__PURE__ */ new Set();
724
- const ftlPaths = await glob(`${dist}/addon/locale/${localeName}/**/*.ftl`);
725
- await Promise.all(ftlPaths.map(async (ftlPath) => {
726
- let ftlContent = await readFile(ftlPath, "utf-8");
727
- const matches = [...ftlContent.matchAll(FTL_MESSAGE_PATTERN)];
728
- for (const match of matches) {
729
- const [matched, message, _pattern] = match;
730
- if (message) {
731
- localeMessages.add(message);
732
- allMessages.add(message);
733
- ftlContent = ftlContent.replace(new RegExp(`^${escapeRegExp(matched)}`, "gm"), `${namespace}-${matched}`);
734
- }
735
- }
736
- if (build.fluent.prefixFluentMessages)
737
- await writeFile(ftlPath, ftlContent);
738
- if (build.fluent.prefixLocaleFiles === true) {
739
- await move(ftlPath, `${dirname(ftlPath)}/${namespace}-${basename(ftlPath)}`);
740
- this.logger.debug(`FTL file '${ftlPath}' is renamed to '${namespace}-${basename(ftlPath)}'.`);
741
- }
742
- }));
743
- messagesByLocale.set(localeName, localeMessages);
744
- }
745
- const messagesInHTML = /* @__PURE__ */ new Set();
746
- const htmlPaths = await glob([
747
- `${dist}/addon/**/*.xhtml`,
748
- `${dist}/addon/**/*.html`
749
- ]);
750
- await Promise.all(htmlPaths.map(async (htmlPath) => {
751
- let htmlContent = await readFile(htmlPath, "utf-8");
752
- const matches = [...htmlContent.matchAll(HTML_DATAI10NID_PATTERN)];
753
- for (const match of matches) {
754
- const [matched, attrKey, attrVal] = match;
755
- if (ignores.includes(attrVal)) {
756
- this.logger.debug(`HTML data-i10n-id ${attrVal} is in ignore list, skip to namespace`);
757
- continue;
758
- }
759
- if (!allMessages.has(attrVal)) {
760
- this.logger.warn(`HTML data-i10n-id '${styleText.blue(attrVal)}' in ${styleText.gray(htmlPath)} do not exist in any FTL message, skip to namespace it.`);
761
- continue;
762
- }
763
- messagesInHTML.add(attrVal);
764
- const namespacedAttr = `${namespace}-${attrVal}`;
765
- htmlContent = htmlContent.replace(matched, `${attrKey}="${namespacedAttr}"`);
766
- this.logger.debug(`HTML data-i10n-id '${styleText.blue(attrVal)}' in ${styleText.gray(htmlPath)} is namespaced to ${styleText.blue(namespacedAttr)}.`);
767
- }
768
- if (build.fluent.prefixFluentMessages)
769
- await writeFile(htmlPath, htmlContent);
770
- }));
771
- messagesInHTML.forEach((messageInHTML) => {
772
- if (ignores.includes(messageInHTML))
773
- return;
774
- const missingLocales = [...messagesByLocale.entries()].filter(([_, messages]) => !messages.has(messageInHTML)).map(([locale]) => locale);
775
- if (missingLocales.length > 0) {
776
- this.logger.warn(`HTML data-l10n-id '${styleText.blue(messageInHTML)}' is missing in locales: ${missingLocales.join(", ")}.`);
777
- }
778
- });
961
+ await buildLocale(dist, namespace, build.fluent);
779
962
  }
780
963
  async preparePrefs() {
781
- const { dts, prefixPrefKeys, prefix } = this.ctx.build.prefs;
782
964
  const { dist } = this.ctx;
783
- if (!prefixPrefKeys && !dts)
784
- return;
785
- const prefsFilePath = join(dist, "addon", "prefs.js");
786
- if (!existsSync(prefsFilePath))
787
- return;
788
- const prefsManager = new PrefsManager("pref");
789
- await prefsManager.read(prefsFilePath);
790
- const prefsWithPrefix = prefsManager.getPrefsWithPrefix(prefix);
791
- const prefsWithoutPrefix = prefsManager.getPrefsWithoutPrefix(prefix);
792
- if (dts) {
793
- const dtsContent = renderPluginPrefsDts(prefsWithoutPrefix);
794
- await outputFile(dts, dtsContent, "utf-8");
795
- }
796
- if (prefixPrefKeys) {
797
- prefsManager.clearPrefs();
798
- prefsManager.setPrefs(prefsWithPrefix);
799
- await prefsManager.write(prefsFilePath);
800
- }
801
- if (prefixPrefKeys) {
802
- const HTML_PREFERENCE_PATTERN = /preference="(\S*)"/g;
803
- const xhtmlPaths = await glob(`${dist}/addon/**/*.xhtml`);
804
- await Promise.all(xhtmlPaths.map(async (path) => {
805
- let content = await readFile(path, "utf-8");
806
- const matchs = [...content.matchAll(HTML_PREFERENCE_PATTERN)];
807
- for (const match of matchs) {
808
- const [matched, key] = match;
809
- if (key.startsWith(prefix)) {
810
- this.logger.debug(`Pref key '${styleText.blue(key)}' is already starts with '${prefix}', skip prefixing it.`);
811
- continue;
812
- } else if (key.startsWith("extensions.")) {
813
- this.logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} starts with 'extensions.' but not '${styleText.blue(prefix)}', skip prefixing it.`);
814
- continue;
815
- } else if (!(key in prefsWithPrefix) && !(key in prefsWithoutPrefix)) {
816
- this.logger.warn(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is not found in prefs.js, skip prefixing it.`);
817
- continue;
818
- } else {
819
- const prefixed = `${prefix}.${key}`;
820
- this.logger.debug(`Pref key '${styleText.blue(key)}' in ${styleText.gray(path)} is prefixed to ${styleText.blue(prefixed)}.`);
821
- content = content.replace(matched, `preference="${prefixed}"`);
822
- }
823
- }
824
- await outputFile(path, content, "utf-8");
825
- }));
826
- }
965
+ await buildPrefs(dist, this.ctx.build.prefs);
827
966
  }
828
967
  esbuild() {
829
968
  const { dist, build: { esbuildOptions } } = this.ctx;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zotero-plugin-scaffold",
3
3
  "type": "module",
4
- "version": "0.4.2",
4
+ "version": "0.6.0",
5
5
  "description": "A scaffold for Zotero plugin development.",
6
6
  "author": "northword",
7
7
  "license": "AGPL-3.0-or-later",
@@ -63,20 +63,21 @@
63
63
  }
64
64
  },
65
65
  "dependencies": {
66
- "@swc/core": "^1.11.16",
66
+ "@fluent/syntax": "^0.19.0",
67
+ "@swc/core": "^1.11.24",
67
68
  "adm-zip": "^0.5.16",
68
69
  "bumpp": "^10.1.0",
69
70
  "c12": "^3.0.3",
70
71
  "chokidar": "^4.0.3",
71
72
  "commander": "^13.1.0",
72
- "es-toolkit": "^1.34.1",
73
- "esbuild": "^0.25.2",
73
+ "es-toolkit": "^1.36.0",
74
+ "esbuild": "^0.25.3",
74
75
  "fs-extra": "^11.3.0",
75
76
  "hookable": "^5.5.3",
76
- "octokit": "^4.1.2",
77
+ "octokit": "^4.1.3",
77
78
  "std-env": "^3.9.0",
78
79
  "tiny-update-notifier": "^2.0.0",
79
- "tinyglobby": "^0.2.12",
80
+ "tinyglobby": "^0.2.13",
80
81
  "xvfb-ts": "^1.1.0"
81
82
  },
82
83
  "devDependencies": {