import { Observable } from 'lib0/observable'; import type { WorkspaceInfo, WorkspaceMeta } from './types'; export interface WorkspaceMetaCollectionScope { get: (workspaceId: string) => WorkspaceInfo | undefined; list: () => WorkspaceInfo[]; add: (workspace: WorkspaceInfo) => void; remove: (workspaceId: string) => boolean; clear: () => void; update: (workspaceId: string, workspaceMeta: Partial) => void; } export interface WorkspaceMetaCollectionChangeEvent { added?: WorkspaceInfo; deleted?: WorkspaceInfo; updated?: WorkspaceInfo; } export class WorkspaceMetaCollection extends Observable<'change'> { private _workspacesMap = new Map(); get workspaces(): WorkspaceInfo[] { return Array.from(this._workspacesMap.values()); } find(workspaceId: string) { return this._workspacesMap.get(workspaceId); } createScope(): WorkspaceMetaCollectionScope { const scopedWorkspaceIds = new Set(); const get = (workspaceId: string) => { if (!scopedWorkspaceIds.has(workspaceId)) { return; } return this._workspacesMap.get(workspaceId); }; const add = (workspace: WorkspaceInfo) => { if (this._workspacesMap.has(workspace.id)) { throw new Error(`Duplicate workspace id.`); } this._workspacesMap.set(workspace.id.toString(), workspace); scopedWorkspaceIds.add(workspace.id); this.emit('change', [ { added: workspace, } as WorkspaceMetaCollectionChangeEvent, ]); }; const remove = (workspaceId: string) => { if (!scopedWorkspaceIds.has(workspaceId)) { return true; } const workspace = this._workspacesMap.get(workspaceId); if (workspace) { const ret = this._workspacesMap.delete(workspaceId); // If deletion failed, return. if (!ret) { return ret; } scopedWorkspaceIds.delete(workspaceId); this.emit('change', [ { deleted: workspace, } as WorkspaceMetaCollectionChangeEvent, ]); } return true; }; const clear = () => { scopedWorkspaceIds.forEach(id => { remove(id); }); }; const update = ( workspaceId: string, workspaceMeta: Partial ) => { if (!scopedWorkspaceIds.has(workspaceId)) { return true; } const workspace = this._workspacesMap.get(workspaceId); if (!workspace) { return true; } this._workspacesMap.set(workspaceId, { ...workspace, ...workspaceMeta }); this.emit('change', [ { updated: this._workspacesMap.get(workspaceId), } as WorkspaceMetaCollectionChangeEvent, ]); }; // TODO: need to optimize const list = () => { const workspaces: WorkspaceInfo[] = []; scopedWorkspaceIds.forEach(id => { const workspace = this._workspacesMap.get(id); if (workspace) { workspaces.push(workspace); } }); return workspaces; }; return { get, list, add, remove, clear, update, }; } }