|
1 | 1 | import type { Context } from "../types/index.js"; |
2 | 2 | import type { Manifest } from "../types/manifest.js"; |
3 | 3 | import type { UpdateJSON } from "../types/update-json.js"; |
| 4 | +import { existsSync } from "node:fs"; |
4 | 5 | import { readFile, writeFile } from "node:fs/promises"; |
5 | | -import { basename, dirname } from "node:path"; |
| 6 | +import { basename, dirname, join } from "node:path"; |
6 | 7 | import process from "node:process"; |
7 | 8 | import AdmZip from "adm-zip"; |
8 | 9 | import chalk from "chalk"; |
9 | 10 | import { toMerged } from "es-toolkit"; |
10 | 11 | import { build as buildAsync } from "esbuild"; |
11 | | -import { copy, emptyDir, move, outputJSON, readJSON, writeJson } from "fs-extra/esm"; |
| 12 | +import { copy, emptyDir, move, outputFile, outputJSON, readJSON, writeJson } from "fs-extra/esm"; |
12 | 13 | import { glob } from "tinyglobby"; |
13 | 14 | import { generateHash } from "../utils/crypto.js"; |
| 15 | +import { PrefsManager, renderPluginPrefsDts } from "../utils/prefs-manager.js"; |
14 | 16 | import { dateFormat, replaceInFile, toArray } from "../utils/string.js"; |
15 | 17 | import { Base } from "./base.js"; |
16 | 18 |
|
@@ -52,6 +54,8 @@ export default class Build extends Base { |
52 | 54 | await this.prepareLocaleFiles(); |
53 | 55 | await this.ctx.hooks.callHook("build:fluent", this.ctx); |
54 | 56 |
|
| 57 | + await this.preparePrefs(); |
| 58 | + |
55 | 59 | this.logger.tip("Bundling scripts"); |
56 | 60 | await this.esbuild(); |
57 | 61 | await this.ctx.hooks.callHook("build:bundle", this.ctx); |
@@ -236,6 +240,61 @@ export default class Build extends Base { |
236 | 240 | }); |
237 | 241 | } |
238 | 242 |
|
| 243 | + async preparePrefs() { |
| 244 | + const { dts, prefixPrefKeys, prefix } = this.ctx.build.prefs; |
| 245 | + const { dist } = this.ctx; |
| 246 | + |
| 247 | + // Skip if not enable this builder |
| 248 | + if (!prefixPrefKeys && !dts) |
| 249 | + return; |
| 250 | + |
| 251 | + // Skip if no prefs.js |
| 252 | + const prefsFilePath = join(dist, "addon", "prefs.js"); |
| 253 | + if (!existsSync(prefsFilePath)) |
| 254 | + return; |
| 255 | + |
| 256 | + // Parse prefs.js |
| 257 | + const prefsManager = new PrefsManager("pref"); |
| 258 | + await prefsManager.read(prefsFilePath); |
| 259 | + const prefsWithPrefix = prefsManager.getPrefsWithPrefix(prefix); |
| 260 | + const prefsWithoutPrefix = prefsManager.getPrefsWithoutPrefix(prefix); |
| 261 | + |
| 262 | + // Generate prefs.d.ts |
| 263 | + if (dts) { |
| 264 | + const dtsContent = renderPluginPrefsDts(prefsWithoutPrefix, prefix); |
| 265 | + await outputFile(dts, dtsContent, "utf-8"); |
| 266 | + } |
| 267 | + |
| 268 | + // Generate prefixed prefs.js |
| 269 | + if (prefixPrefKeys) { |
| 270 | + prefsManager.clearPrefs(); |
| 271 | + prefsManager.setPrefs(prefsWithPrefix); |
| 272 | + await prefsManager.write(prefsFilePath); |
| 273 | + } |
| 274 | + |
| 275 | + // Prefix pref keys in xhtml |
| 276 | + if (prefixPrefKeys) { |
| 277 | + const HTML_PREFERENCE_PATTERN = new RegExp(`preference="((?!${prefix})\\S*)"`, "g"); |
| 278 | + const xhtmlPaths = await glob(`${dist}/addon/**/*.xhtml`); |
| 279 | + await Promise.all(xhtmlPaths.map(async (path) => { |
| 280 | + let content = await readFile(path, "utf-8"); |
| 281 | + const matchs = [...content.matchAll(HTML_PREFERENCE_PATTERN)]; |
| 282 | + for (const match of matchs) { |
| 283 | + const [matched, key] = match; |
| 284 | + if (!prefsWithoutPrefix[key] && !prefsWithoutPrefix[key]) { |
| 285 | + this.logger.warn(`preference key '${key}' in ${path} not init in prefs.js`); |
| 286 | + continue; |
| 287 | + } |
| 288 | + if (key.startsWith(prefix)) |
| 289 | + continue; |
| 290 | + else |
| 291 | + content = content.replace(matched, `preference="${prefix}.${key}"`); |
| 292 | + } |
| 293 | + await outputFile(path, content, "utf-8"); |
| 294 | + })); |
| 295 | + } |
| 296 | + } |
| 297 | + |
239 | 298 | esbuild() { |
240 | 299 | const { build: { esbuildOptions } } = this.ctx; |
241 | 300 |
|
|
0 commit comments