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:
@@ -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,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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[]>;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user