Skip to content

Commit

Permalink
feat: support create profile (#85)
Browse files Browse the repository at this point in the history
* feat: support create profile

* fix: regexp group index error

* fix: cancel support discard profile changes
  • Loading branch information
northword authored Jan 4, 2025
1 parent bc2e4f8 commit 01deb31
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 105 deletions.
3 changes: 3 additions & 0 deletions packages/scaffold/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ const defaultConfig = {
devtools: true,
startArgs: [],
asProxy: false,
prebuild: true,
// keepProfileChanges: true,
createProfileIfMissing: true,
hooks: {},
},
addonLint: {},
Expand Down
46 changes: 24 additions & 22 deletions packages/scaffold/src/core/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default class Serve extends Base {
private runner?: ZoteroRunner;

private _zoteroBinPath?: string;
private _profilePath?: string;

constructor(ctx: Context) {
super(ctx);
Expand All @@ -27,23 +26,33 @@ export default class Serve extends Base {
process.on("SIGINT", this.exit);

this.runner = new ZoteroRunner({
binaryPath: this.zoteroBinPath,
profilePath: this.profilePath,
dataDir: this.dataDir,
plugins: [{
id: this.ctx.id,
sourceDir: join(this.ctx.dist, "addon"),
}],
asProxy: this.ctx.server.asProxy,
devtools: this.ctx.server.devtools,
binaryArgs: this.ctx.server.startArgs,
binary: {
path: this.zoteroBinPath,
devtools: this.ctx.server.devtools,
args: this.ctx.server.startArgs,
},
profile: {
path: this.profilePath,
dataDir: this.dataDir,
// keepChanges: this.ctx.server.keepProfileChanges,
createIfMissing: this.ctx.server.createProfileIfMissing,
},
plugins: {
list: [{
id: this.ctx.id,
sourceDir: join(this.ctx.dist, "addon"),
}],
asProxy: this.ctx.server.asProxy,
},
});

await this.ctx.hooks.callHook("serve:init", this.ctx);

// prebuild
await this.builder.run();
await this.ctx.hooks.callHook("serve:prebuild", this.ctx);
if (this.ctx.server.prebuild) {
await this.builder.run();
await this.ctx.hooks.callHook("serve:prebuild", this.ctx);
}

// start Zotero
await this.runner.run();
Expand Down Expand Up @@ -133,17 +142,10 @@ export default class Serve extends Base {
}

get profilePath() {
if (this._profilePath)
return this._profilePath;

this._profilePath = process.env.ZOTERO_PLUGIN_PROFILE_PATH;
if (!this._profilePath || !existsSync(this._profilePath))
throw new Error("The Zotero profile not found.");

return this._profilePath;
return process.env.ZOTERO_PLUGIN_PROFILE_PATH;
}

get dataDir() {
return process.env.ZOTERO_PLUGIN_DATA_DIR ?? "";
return process.env.ZOTERO_PLUGIN_DATA_DIR;
}
}
32 changes: 19 additions & 13 deletions packages/scaffold/src/core/tester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,19 +561,25 @@ export default class Test extends Base {

async startZotero() {
this.runner = new ZoteroRunner({
binaryPath: this.zoteroBinPath,
profilePath: this.profilePath,
dataDir: this.dataDir,
plugins: [{
id: this.ctx.id,
sourceDir: join(this.ctx.dist, "addon"),
}, {
id: this.testPluginID,
sourceDir: this.testPluginDir,
}],
devtools: this.ctx.server.devtools,
binaryArgs: this.ctx.server.startArgs,
customPrefs: this.prefs,
binary: {
path: this.zoteroBinPath,
devtools: this.ctx.server.devtools,
args: this.ctx.server.startArgs,
},
profile: {
path: this.profilePath,
dataDir: this.dataDir,
customPrefs: this.prefs,
},
plugins: {
list: [{
id: this.ctx.id,
sourceDir: join(this.ctx.dist, "addon"),
}, {
id: this.testPluginID,
sourceDir: this.testPluginDir,
}],
},
});

await this.runner.run();
Expand Down
5 changes: 5 additions & 0 deletions packages/scaffold/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@ export interface ServerConfig {
* @default false
*/
asProxy: boolean;

prebuild: boolean;
// keepProfileChanges: boolean;
createProfileIfMissing: boolean;

/**
* The lifecycle hook.
*/
Expand Down
13 changes: 5 additions & 8 deletions packages/scaffold/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import type { Hookable } from "hookable";
import type { Log } from "../utils/log.js";
import type { Hooks } from "./config.js";
import type { RecursivePartial } from "./utils.js";
import { Config } from "./config.js";

type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
};
export { Config, Hooks };

/**
* User config
*/
interface UserConfig extends RecursivePartial<Config> {}
export interface UserConfig extends RecursivePartial<Config> {}

interface OverrideConfig extends RecursivePartial<Config> {}
export interface OverrideConfig extends RecursivePartial<Config> {}

interface Context extends Config {
export interface Context extends Config {
pkgUser: any;
version: string;
hooks: Hookable<Hooks>;
Expand All @@ -34,5 +33,3 @@ export interface TemplateData {
xpiName: string;
buildTime: string;
}

export { Config, Context, Hooks, OverrideConfig, UserConfig };
25 changes: 25 additions & 0 deletions packages/scaffold/src/types/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
};

export type RecursiveRequired<T> = {
// eslint-disable-next-line ts/no-unsafe-function-type
[K in keyof T]-?: T[K] extends object ? T[K] extends Function ? T[K]
: RecursiveRequired<T[K]>
: T[K];
};

export type RecursiveNonNullable<T> = {
// eslint-disable-next-line ts/no-unsafe-function-type
[K in keyof T]-?: T[K] extends object ? T[K] extends Function ? T[K]
: RecursiveNonNullable<NonNullable<T[K]>>
: NonNullable<T[K]>;
};

type RecursiveOptionalKeys<T> = {
[K in keyof T]-?: undefined extends T[K] ? K : T[K] extends object ? K | RecursiveOptionalKeys<T[K]> : never;
}[keyof T];

export type RecursivePickOptional<T> = {
[K in keyof T as K extends RecursiveOptionalKeys<T> ? K : never]?: T[K] extends object ? RecursivePickOptional<T[K]> : T[K];
};
78 changes: 78 additions & 0 deletions packages/scaffold/src/utils/prefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { readFile } from "node:fs/promises";
import { isNotNil } from "es-toolkit";
import { outputFile } from "fs-extra/esm";
import { logger } from "./log.js";
import { prefs as defaultPrefs } from "./zotero/preference.js";

export type Prefs = Record<string, string | number | boolean | undefined | null>;

export class PrefsManager {
private namespace: "pref" | "user_pref";
private prefs: Prefs;

constructor(namespace: "pref" | "user_pref") {
this.namespace = namespace;
this.prefs = { ...defaultPrefs };
}

private parsePrefjs(content: string) {
// eslint-disable-next-line regexp/no-super-linear-backtracking
const prefPattern = /^(pref|user_pref)\s*\(\s*["']([^"']+)["']\s*,\s*(.+)\s*\)\s*;$/gm;
const matches = content.matchAll(prefPattern);
for (const match of matches) {
const key = match[2].trim();
const value = match[3].trim();
this.prefs[key] = value;
};
}

public async read(path: string) {
const content = await readFile(path, "utf-8");
this.parsePrefjs(content);
}

private renderPrefjs() {
return Object.entries(this.prefs).map(([key, value]) => {
if (!isNotNil(value))
return "";

let cleanValue = "";
if (typeof value === "boolean") {
cleanValue = `${value}`;
}
else if (typeof value === "string") {
cleanValue = `${value.replace("\n", "\\n")}`;
}
else if (typeof value === "number") {
cleanValue = value.toString();
}

return `${this.namespace}("${key}", ${cleanValue});`;
}).filter(c => !!c).join("\n");
}

public async write(path: string) {
const content = this.renderPrefjs();
// console.log(content);
await outputFile(path, content, "utf-8");
logger.debug("The <profile>/prefs.js has been modified.");
}

setPref(key: string, value: any) {
this.prefs[key] = value;
};

setPrefs(prefs: Prefs) {
Object.entries(prefs).forEach(([key, value]) => {
this.setPref(key, value);
});
}

getPref(key: string) {
return this.prefs[key] ?? undefined;
}

getPrefs() {
return this.prefs;
}
}
Loading

0 comments on commit 01deb31

Please sign in to comment.