1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

Use union type to limit initialize options

This commit is contained in:
Matt Gibson
2022-11-17 15:15:41 -05:00
parent cde5c3df97
commit 9b3b389a6f
4 changed files with 28 additions and 21 deletions

View File

@@ -1,12 +1,12 @@
import { Jsonify } from "type-fest"; import { Jsonify } from "type-fest";
import { SessionStorable } from "./session-storable"; import { SessionStorable } from "./session-storable";
import { InitializeOptions } from "./sync-item-metadata";
class BuildOptions<T, TJson = Jsonify<T>> { class BuildOptions<T, TJson = Jsonify<T>> {
ctor?: new () => T; ctor?: new () => T;
initializer?: (keyValuePair: TJson) => T; initializer?: (keyValuePair: TJson) => T;
initializeAsArray? = false; initializeAs?: InitializeOptions;
initializeAsRecord? = false;
} }
/** /**
@@ -47,8 +47,7 @@ export function sessionSync<T>(buildOptions: BuildOptions<T>) {
sessionKey: `${prototype.constructor.name}_${propertyKey}`, sessionKey: `${prototype.constructor.name}_${propertyKey}`,
ctor: buildOptions.ctor, ctor: buildOptions.ctor,
initializer: buildOptions.initializer, initializer: buildOptions.initializer,
initializeAsArray: buildOptions.initializeAsArray, initializeAs: buildOptions.initializeAs ?? "object",
initializeAsRecord: buildOptions.initializeAsRecord,
}); });
}; };
} }

View File

@@ -1,23 +1,20 @@
export type InitializeOptions = "array" | "record" | "object";
export class SyncedItemMetadata { export class SyncedItemMetadata {
propertyKey: string; propertyKey: string;
sessionKey: string; sessionKey: string;
ctor?: new () => any; ctor?: new () => any;
initializer?: (keyValuePair: any) => any; initializer?: (keyValuePair: any) => any;
initializeAsArray?: boolean; initializeAs: InitializeOptions;
initializeAsRecord?: boolean;
static builder(metadata: SyncedItemMetadata): (o: any) => any { static builder(metadata: SyncedItemMetadata): (o: any) => any {
if (metadata.initializeAsArray && metadata.initializeAsRecord) {
throw new Error("initializeAsArray and initializeAsRecord cannot both be true");
}
const itemBuilder = const itemBuilder =
metadata.initializer != null metadata.initializer != null
? metadata.initializer ? metadata.initializer
: (o: any) => Object.assign(new metadata.ctor(), o); : (o: any) => Object.assign(new metadata.ctor(), o);
if (metadata.initializeAsArray) { if (metadata.initializeAs === "array") {
return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o)); return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o));
} else if (metadata.initializeAsRecord) { } else if (metadata.initializeAs === "record") {
return (keyValuePair: any) => { return (keyValuePair: any) => {
const record: Record<any, any> = {}; const record: Record<any, any> = {};
for (const key in keyValuePair) { for (const key in keyValuePair) {

View File

@@ -8,29 +8,40 @@ describe("builder", () => {
const ctor = TestClass; const ctor = TestClass;
it("should use initializer if provided", () => { it("should use initializer if provided", () => {
const metadata = { propertyKey, sessionKey: key, initializer }; const metadata: SyncedItemMetadata = {
propertyKey,
sessionKey: key,
initializer,
initializeAs: "object",
};
const builder = SyncedItemMetadata.builder(metadata); const builder = SyncedItemMetadata.builder(metadata);
expect(builder({})).toBe("used initializer"); expect(builder({})).toBe("used initializer");
}); });
it("should use ctor if initializer is not provided", () => { it("should use ctor if initializer is not provided", () => {
const metadata = { propertyKey, sessionKey: key, ctor }; const metadata: SyncedItemMetadata = { propertyKey, sessionKey: key, ctor };
const builder = SyncedItemMetadata.builder(metadata); const builder = SyncedItemMetadata.builder(metadata);
expect(builder({})).toBeInstanceOf(TestClass); expect(builder({})).toBeInstanceOf(TestClass);
}); });
it("should prefer initializer over ctor", () => { it("should prefer initializer over ctor", () => {
const metadata = { propertyKey, sessionKey: key, ctor, initializer }; const metadata: SyncedItemMetadata = {
propertyKey,
sessionKey: key,
ctor,
initializer,
initializeAs: "object",
};
const builder = SyncedItemMetadata.builder(metadata); const builder = SyncedItemMetadata.builder(metadata);
expect(builder({})).toBe("used initializer"); expect(builder({})).toBe("used initializer");
}); });
it("should honor initialize as array", () => { it("should honor initialize as array", () => {
const metadata = { const metadata: SyncedItemMetadata = {
propertyKey, propertyKey,
sessionKey: key, sessionKey: key,
initializer: initializer, initializer: initializer,
initializeAsArray: true, initializeAs: "array",
}; };
const builder = SyncedItemMetadata.builder(metadata); const builder = SyncedItemMetadata.builder(metadata);
expect(builder([{}])).toBeInstanceOf(Array); expect(builder([{}])).toBeInstanceOf(Array);
@@ -38,11 +49,11 @@ describe("builder", () => {
}); });
it("should honor initialize as record", () => { it("should honor initialize as record", () => {
const metadata = { const metadata: SyncedItemMetadata = {
propertyKey, propertyKey,
sessionKey: key, sessionKey: key,
initializer: initializer, initializer: initializer,
initializeAsRecord: true, initializeAs: "record",
}; };
const builder = SyncedItemMetadata.builder(metadata); const builder = SyncedItemMetadata.builder(metadata);
expect(builder({ key: "" })).toBeInstanceOf(Object); expect(builder({ key: "" })).toBeInstanceOf(Object);

View File

@@ -8,8 +8,8 @@ import { browserSession, sessionSync } from "../decorators/session-sync-observab
@browserSession @browserSession
export class BrowserFolderService extends BaseFolderService { export class BrowserFolderService extends BaseFolderService {
@sessionSync({ initializer: Folder.fromJSON, initializeAsArray: true }) @sessionSync({ initializer: Folder.fromJSON, initializeAs: "array" })
protected _folders: BehaviorSubject<Folder[]>; protected _folders: BehaviorSubject<Folder[]>;
@sessionSync({ initializer: FolderView.fromJSON, initializeAsArray: true }) @sessionSync({ initializer: FolderView.fromJSON, initializeAs: "array" })
protected _folderViews: BehaviorSubject<FolderView[]>; protected _folderViews: BehaviorSubject<FolderView[]>;
} }