diff --git a/README.md b/README.md index 63c37ac..b7664cd 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Every object in the store has a globally unique UUID stored in the id property, The store is divided into a root store and separate stores defined for each type of object, with actual data stored in these individual object stores. -Each object-specific store implements [EventEmitter](https://nodejs.org/docs/latest/api/events.html#class-eventemitter), allowing the renderer to monitor changes to the store through events. +Each object-specific store extends [`CCBaseStore`](/src/store/base.ts), which implements [EventEmitter](https://nodejs.org/docs/latest/api/events.html#class-eventemitter), allowing the renderer to monitor changes to the store through events. Each object-specific store must implement the following four events, with the event object passing the object that triggered the event: - `didRegister`: Triggered when an object is registered in the store. diff --git a/src/store/base.ts b/src/store/base.ts new file mode 100644 index 0000000..7a98445 --- /dev/null +++ b/src/store/base.ts @@ -0,0 +1,45 @@ +import EventEmitter from "eventemitter3"; +import type CCStore from "."; + +/** Events emitted by every object-specific store */ +export type CCBaseStoreEvents = { + didRegister(object: T): void; + willUnregister(object: T): void; + didUnregister(object: T): void; +}; + +/** Base class of the object-specific stores (components, nodes, pins, and connections) */ +export abstract class CCBaseStore< + Id extends string, + T extends { readonly id: Id }, + Events extends CCBaseStoreEvents, +> extends EventEmitter { + protected readonly store: CCStore; + + protected readonly objects: Map = new Map(); + + constructor(store: CCStore) { + super(); + this.store = store; + } + + /** Subscribe to the events of other stores. Called after all stores are constructed. */ + abstract mount(): void; + + /** + * Get an object by id + * @param id id of object + * @returns object of `id` + */ + get(id: Id): T | undefined { + return this.objects.get(id); + } + + /** + * Get array of objects + * @returns array of objects + */ + getMany(): T[] { + return [...this.objects.values()]; + } +} diff --git a/src/store/component.ts b/src/store/component.ts index 77408ec..8f72a09 100644 --- a/src/store/component.ts +++ b/src/store/component.ts @@ -1,8 +1,8 @@ -import EventEmitter from "eventemitter3"; import nullthrows from "nullthrows"; import invariant from "tiny-invariant"; import type { Tagged } from "type-fest"; import type CCStore from "."; +import { CCBaseStore, type CCBaseStoreEvents } from "./base"; import type { CCIntrinsicComponentType } from "./intrinsics/types"; export type CCComponentId = Tagged; @@ -14,10 +14,7 @@ export type CCComponent = { name: string; }; -export type CCComponentStoreEvents = { - didRegister(component: CCComponent): void; - willUnregister(component: CCComponent): void; - didUnregister(component: CCComponent): void; +export type CCComponentStoreEvents = CCBaseStoreEvents & { didUpdate(component: CCComponent): void; }; export const ccComponentStoreChangeEventTypes: (keyof CCComponentStoreEvents)[] = @@ -26,23 +23,11 @@ export const ccComponentStoreChangeEventTypes: (keyof CCComponentStoreEvents)[] /** * Store of components */ -export class CCComponentStore extends EventEmitter { - #store: CCStore; - - #components: Map = new Map(); - - /** - * Constructor of CCComponentStore - * @param store store - * @param rootComponent root component - * @param rootComponentId id of root component - * @param components initial components - */ - constructor(store: CCStore) { - super(); - this.#store = store; - } - +export class CCComponentStore extends CCBaseStore< + CCComponentId, + CCComponent, + CCComponentStoreEvents +> { import(components: CCComponent[]) { for (const component of components) { this.register(component); @@ -56,8 +41,8 @@ export class CCComponentStore extends EventEmitter { * @param component component to be registered */ register(component: CCComponent): void { - invariant(!this.#components.has(component.id)); - this.#components.set(component.id, component); + invariant(!this.objects.has(component.id)); + this.objects.set(component.id, component); this.emit("didRegister", component); } @@ -66,33 +51,24 @@ export class CCComponentStore extends EventEmitter { * @param id id of a component to be unregistered */ async unregister(id: CCComponentId): Promise { - const component = this.#components.get(id); + const component = this.objects.get(id); if (!component) throw new Error(`Component ${id} not found`); - await this.#store.transactionManager.runInTransaction(() => { + await this.store.transactionManager.runInTransaction(() => { this.emit("willUnregister", component); - this.#components.delete(id); + this.objects.delete(id); }); this.emit("didUnregister", component); } - /** - * Get a component by CCComponentId - * @param id id of component - * @returns component of `id` - */ - get(id: CCComponentId): CCComponent | undefined { - return this.#components.get(id); - } - /** * Update the name of component * @param id id of component * @param value new name */ update(id: CCComponentId, value: Pick): void { - const component = this.#components.get(id); + const component = this.objects.get(id); invariant(component); - this.#components.set(id, { ...component, ...value }); + this.objects.set(id, { ...component, ...value }); this.emit("didUpdate", component); } @@ -110,14 +86,6 @@ export class CCComponentStore extends EventEmitter { ...partialComponent, }; } - - /** - * Get array of components - * @returns array of components - */ - getMany(): CCComponent[] { - return [...this.#components.values()]; - } } /** diff --git a/src/store/componentPin.ts b/src/store/componentPin.ts index bc6f0f9..d17c690 100644 --- a/src/store/componentPin.ts +++ b/src/store/componentPin.ts @@ -1,8 +1,7 @@ -import EventEmitter from "eventemitter3"; import nullthrows from "nullthrows"; import invariant from "tiny-invariant"; import type { Tagged } from "type-fest"; -import type CCStore from "."; +import { CCBaseStore, type CCBaseStoreEvents } from "./base"; import type { CCComponentId } from "./component"; import { IntrinsicComponentDefinition } from "./intrinsics/base"; import { input, output } from "./intrinsics/definitions"; @@ -45,10 +44,7 @@ export type CCComponentPinBitWidthStatus = | { isFixed: false; fixMode: "automatic" | "nodeDependent" } | { isFixed: true; bitWidth: number }; -export type CCComponentPinStoreEvents = { - didRegister(pin: CCComponentPin): void; - willUnregister(pin: CCComponentPin): void; - didUnregister(pin: CCComponentPin): void; +export type CCComponentPinStoreEvents = CCBaseStoreEvents & { didUpdate(pin: CCComponentPin): void; }; export const ccComponentPinStoreChangeEventTypes: (keyof CCComponentPinStoreEvents)[] = @@ -57,32 +53,20 @@ export const ccComponentPinStoreChangeEventTypes: (keyof CCComponentPinStoreEven /** * Store of pins */ -export class CCComponentPinStore extends EventEmitter { - #store: CCStore; - - #pins: Map = new Map(); - - /** - * Constructor of CCComponentPinStore - * @param store store - * @param pins initial pins - */ - constructor(store: CCStore) { - super(); - this.#store = store; - } - +export class CCComponentPinStore extends CCBaseStore< + CCComponentPinId, + CCComponentPin, + CCComponentPinStoreEvents +> { import(componentPins: CCComponentPin[]): void { for (const pin of componentPins) { - this.#pins.set(pin.id, pin); + this.objects.set(pin.id, pin); } } mount() { - this.#store.nodePins.on("didRegister", (nodePin) => { - const componentPin = this.#store.componentPins.get( - nodePin.componentPinId, - ); + this.store.nodePins.on("didRegister", (nodePin) => { + const componentPin = this.store.componentPins.get(nodePin.componentPinId); if ( componentPin?.id === input.outputPin.Out.id || componentPin?.id === output.inputPin.In.id @@ -90,7 +74,7 @@ export class CCComponentPinStore extends EventEmitter this.register(this.createForNodePin(nodePin.id)); } }); - this.#store.nodePins.on("willUnregister", (nodePin) => { + this.store.nodePins.on("willUnregister", (nodePin) => { const pin = this.getByImplementation(nodePin.id); if (pin) this.unregister(pin.id); }); @@ -101,17 +85,17 @@ export class CCComponentPinStore extends EventEmitter * @param pin pin to be registered */ register(pin: CCComponentPin): void { - invariant(this.#store.components.get(pin.componentId)); - this.#pins.set(pin.id, pin); + invariant(this.store.components.get(pin.componentId)); + this.objects.set(pin.id, pin); this.emit("didRegister", pin); } createForNodePin(nodePinId: CCNodePinId): CCComponentPin { - const targetNodePin = nullthrows(this.#store.nodePins.get(nodePinId)); + const targetNodePin = nullthrows(this.store.nodePins.get(nodePinId)); const targetComponentPin = nullthrows( - this.#store.componentPins.get(targetNodePin.componentPinId), + this.store.componentPins.get(targetNodePin.componentPinId), ); - const targetNode = nullthrows(this.#store.nodes.get(targetNodePin.nodeId)); + const targetNode = nullthrows(this.store.nodes.get(targetNodePin.nodeId)); const existingComponentPins = this.getManyByComponentId( targetNode.parentComponentId, ); @@ -133,29 +117,20 @@ export class CCComponentPinStore extends EventEmitter * @param id id of a pin to be unregistered */ async unregister(id: CCComponentPinId): Promise { - const pin = nullthrows(this.#pins.get(id)); - await this.#store.transactionManager.runInTransaction(() => { + const pin = nullthrows(this.objects.get(id)); + await this.store.transactionManager.runInTransaction(() => { this.emit("willUnregister", pin); - this.#pins.delete(id); + this.objects.delete(id); }); this.emit("didUnregister", pin); } - /** - * Get a pin by id - * @param id id of pin - * @returns pin of `id` - */ - get(id: CCComponentPinId): CCComponentPin | undefined { - return this.#pins.get(id); - } - /** * Get all of pins * @returns all pins */ getByNodePinId(nodePinId: CCNodePinId): CCComponentPin { - const pin = [...this.#pins.values()].find( + const pin = [...this.objects.values()].find( ({ implementation }) => implementation && implementation === nodePinId, ); invariant(pin); @@ -168,14 +143,14 @@ export class CCComponentPinStore extends EventEmitter * @returns pins of component */ getManyByComponentId(componentId: CCComponentId): CCComponentPin[] { - return [...this.#pins.values()].filter( + return [...this.objects.values()].filter( (pin) => pin.componentId === componentId, ); } getByImplementation(implementation: CCNodePinId): CCComponentPin | null { return ( - [...this.#pins.values()].find( + [...this.objects.values()].find( (pin) => pin.implementation === implementation, ) ?? null ); @@ -190,9 +165,9 @@ export class CCComponentPinStore extends EventEmitter id: CCComponentPinId, value: Partial>, ): void { - const pin = this.#pins.get(id); + const pin = this.objects.get(id); invariant(pin); - this.#pins.set(id, { ...pin, ...value }); + this.objects.set(id, { ...pin, ...value }); this.emit("didUpdate", pin); } @@ -206,7 +181,7 @@ export class CCComponentPinStore extends EventEmitter getComponentPinBitWidthStatus( pinId: CCComponentPinId, ): CCComponentPinBitWidthStatus { - const pin = this.#pins.get(pinId); + const pin = this.objects.get(pinId); invariant(pin); // Intrinsic components @@ -233,7 +208,7 @@ export class CCComponentPinStore extends EventEmitter pin.implementation, "Pin implementation must be defined for user-defined components", ); - const bitWidthStatus = this.#store.nodePins.getNodePinBitWidthStatus( + const bitWidthStatus = this.store.nodePins.getNodePinBitWidthStatus( pin.implementation, ); if (bitWidthStatus.isFixed) { @@ -254,12 +229,4 @@ export class CCComponentPinStore extends EventEmitter ...partialPin, }; } - - /** - * Get array of pins - * @returns array of pins - */ - getMany(): CCComponentPin[] { - return [...this.#pins.values()]; - } } diff --git a/src/store/connection.ts b/src/store/connection.ts index 99f4545..8ba1a8b 100644 --- a/src/store/connection.ts +++ b/src/store/connection.ts @@ -1,7 +1,6 @@ -import EventEmitter from "eventemitter3"; import nullthrows from "nullthrows"; import type { Tagged } from "type-fest"; -import type CCStore from "."; +import { CCBaseStore, type CCBaseStoreEvents } from "./base"; import type { CCComponentId } from "./component"; import type { CCComponentPinId } from "./componentPin"; import type { CCNodeId } from "./node"; @@ -22,40 +21,26 @@ export type CCConnection = { bentPortion: number; }; -export type CCConnectionStoreEvents = { - didRegister(Connection: CCConnection): void; - willUnregister(Connection: CCConnection): void; - didUnregister(Connection: CCConnection): void; -}; +export type CCConnectionStoreEvents = CCBaseStoreEvents; export const ccConnectionStoreChangeEventTypes: (keyof CCConnectionStoreEvents)[] = ["didRegister", "didUnregister"]; /** * Store of connections */ -export class CCConnectionStore extends EventEmitter { - #store: CCStore; - - #connections: Map = new Map(); - - /** - * Constructor of CCConnectionStore - * @param store store - * @param connections initial connections - */ - constructor(store: CCStore) { - super(); - this.#store = store; - } - +export class CCConnectionStore extends CCBaseStore< + CCConnectionId, + CCConnection, + CCConnectionStoreEvents +> { import(connections: CCConnection[]): void { for (const connection of connections) { - this.#connections.set(connection.id, connection); + this.objects.set(connection.id, connection); } } mount() { - this.#store.nodePins.on("willUnregister", (nodePin) => { + this.store.nodePins.on("willUnregister", (nodePin) => { const connections = this.getConnectionsByNodePinId(nodePin.id); if (connections.length > 0) { this.unregister(connections.map((connection) => connection.id)); @@ -64,13 +49,13 @@ export class CCConnectionStore extends EventEmitter { // A config change can change the bit width of a pin (e.g. the resolution of a // display), which invalidates the connections that were valid when they were made. // CCStore mounts CCNodePinStore first, so its bit width cache is already dropped. - this.#store.nodes.on("didUpdateConfig", (node) => { + this.store.nodes.on("didUpdateConfig", (node) => { // TODO: Dropping a connection can in turn invalidate another one. Resolving that // needs a repeated sweep, which the re-validation on `didRegister` below lacks too. const invalidatedConnections = this.getMany().filter( (connection) => connection.parentComponentId === node.parentComponentId && - !this.#store.nodePins.hasCompatibleBitWidths( + !this.store.nodePins.hasCompatibleBitWidths( connection.from, connection.to, ), @@ -81,13 +66,13 @@ export class CCConnectionStore extends EventEmitter { ); } }); - this.#store.connections.on("didRegister", (connection) => { + this.store.connections.on("didRegister", (connection) => { const component = nullthrows( - this.#store.components.get(connection.parentComponentId), + this.store.components.get(connection.parentComponentId), ); - const nodes = this.#store.nodes.getManyByComponentId(component.id); + const nodes = this.store.nodes.getManyByComponentId(component.id); for (const node of nodes) { - const nodePins = this.#store.nodePins.getManyByNodeId(node.id); + const nodePins = this.store.nodePins.getManyByNodeId(node.id); for (const nodePin of nodePins) { const connections = this.getConnectionsByNodePinId(nodePin.id); for (const connection of connections) { @@ -95,7 +80,7 @@ export class CCConnectionStore extends EventEmitter { const from = connection.from; const to = connection.to; this.unregister([connection.id]).then(() => { - if (this.#store.nodePins.isConnectable(from, to)) { + if (this.store.nodePins.isConnectable(from, to)) { this.register( CCConnectionStore.create({ from, @@ -119,10 +104,10 @@ export class CCConnectionStore extends EventEmitter { register(connection: CCConnection): void { const fromNodePinId = connection.from; const toNodePinId = connection.to; - if (!this.#store.nodePins.isConnectable(fromNodePinId, toNodePinId)) { + if (!this.store.nodePins.isConnectable(fromNodePinId, toNodePinId)) { return; } - this.#connections.set(connection.id, connection); + this.objects.set(connection.id, connection); this.emit("didRegister", connection); } @@ -131,11 +116,11 @@ export class CCConnectionStore extends EventEmitter { * @param ids ids of connections to be unregistered */ async unregister(ids: CCConnectionId[]): Promise { - const connections = ids.map((id) => nullthrows(this.#connections.get(id))); - await this.#store.transactionManager.runInTransaction(() => { + const connections = ids.map((id) => nullthrows(this.objects.get(id))); + await this.store.transactionManager.runInTransaction(() => { for (const connection of connections) { this.emit("willUnregister", connection); - this.#connections.delete(connection.id); + this.objects.delete(connection.id); } // Announced as soon as the connections are gone, not when the transaction ends. // Otherwise a listener of a change announced in between, such as a renderer @@ -148,15 +133,6 @@ export class CCConnectionStore extends EventEmitter { }); } - /** - * Get a connection by CCConnectionId - * @param id id of connection - * @returns connection of `id` - */ - get(id: CCConnectionId): CCConnection | undefined { - return this.#connections.get(id); - } - /** * Get all of connections * @returns map of id and connection (read only) @@ -164,7 +140,7 @@ export class CCConnectionStore extends EventEmitter { getConnectionIdsByParentComponentId( parentComponentId: CCComponentId, ): CCConnectionId[] { - return [...this.#connections.values()] + return [...this.objects.values()] .filter( (connection) => connection.parentComponentId === parentComponentId, ) @@ -172,7 +148,7 @@ export class CCConnectionStore extends EventEmitter { } getManyByParentComponentId(parentComponentId: CCComponentId): CCConnection[] { - return [...this.#connections.values()].filter( + return [...this.objects.values()].filter( (connection) => connection.parentComponentId === parentComponentId, ); } @@ -184,7 +160,7 @@ export class CCConnectionStore extends EventEmitter { * @returns connections connected to the pin of the node */ getConnectionsByNodePinId(nodePinId: CCNodePinId): CCConnection[] { - return [...this.#connections.values()].filter( + return [...this.objects.values()].filter( (connection) => connection.from === nodePinId || connection.to === nodePinId, ); @@ -201,12 +177,4 @@ export class CCConnectionStore extends EventEmitter { ...partialConnection, }; } - - /** - * Get array of connections - * @returns array of connections - */ - getMany(): CCConnection[] { - return [...this.#connections.values()]; - } } diff --git a/src/store/node.ts b/src/store/node.ts index edb6566..905724a 100644 --- a/src/store/node.ts +++ b/src/store/node.ts @@ -1,9 +1,8 @@ -import EventEmitter from "eventemitter3"; import nullthrows from "nullthrows"; import invariant from "tiny-invariant"; import type { Tagged } from "type-fest"; import type { Vector2 } from "../common/vector2"; -import type CCStore from "."; +import { CCBaseStore, type CCBaseStoreEvents } from "./base"; import type { CCComponentId } from "./component"; import { definitionByComponentId } from "./intrinsics/definitions"; import type { CCIntrinsicComponentSpec } from "./intrinsics/types"; @@ -20,10 +19,7 @@ export type CCNode< config: Spec["config"]; }; -export type CCNodeStoreEvents = { - didRegister(node: CCNode): void; - willUnregister(node: CCNode): void; - didUnregister(node: CCNode): void; +export type CCNodeStoreEvents = CCBaseStoreEvents & { didUpdate(node: CCNode): void; /** * Emitted in addition to `didUpdate` when the config of a node changed, so that @@ -40,21 +36,11 @@ export const ccNodeStoreChangeEventTypes: (keyof CCNodeStoreEvents)[] = [ /** * Store of nodes */ -export class CCNodeStore extends EventEmitter { - #store: CCStore; - - #nodes: Map = new Map(); - - /** - * Constructor of CCNodeStore - * @param store store - * @param nodes initial nodes - */ - constructor(store: CCStore) { - super(); - this.#store = store; - } - +export class CCNodeStore extends CCBaseStore< + CCNodeId, + CCNode, + CCNodeStoreEvents +> { import(nodes: CCNode[]): void { for (const node of nodes) { node.position = { x: node.position.x, y: node.position.y }; @@ -63,8 +49,8 @@ export class CCNodeStore extends EventEmitter { } mount() { - this.#store.components.on("willUnregister", (component) => { - const ids = [...this.#nodes.values()] + this.store.components.on("willUnregister", (component) => { + const ids = [...this.objects.values()] .filter( (node) => node.parentComponentId === component.id || @@ -82,9 +68,9 @@ export class CCNodeStore extends EventEmitter { * @param node node to be registered */ register(node: CCNode): void { - invariant(this.#store.components.get(node.componentId)); - invariant(this.#store.components.get(node.parentComponentId)); - this.#nodes.set(node.id, node); + invariant(this.store.components.get(node.componentId)); + invariant(this.store.components.get(node.parentComponentId)); + this.objects.set(node.id, node); this.emit("didRegister", node); } @@ -93,11 +79,11 @@ export class CCNodeStore extends EventEmitter { * @param ids ids of nodes to be unregistered */ async unregister(ids: CCNodeId[]): Promise { - const nodes = ids.map((id) => nullthrows(this.#nodes.get(id))); - await this.#store.transactionManager.runInTransaction(() => { + const nodes = ids.map((id) => nullthrows(this.objects.get(id))); + await this.store.transactionManager.runInTransaction(() => { for (const node of nodes) { this.emit("willUnregister", node); - this.#nodes.delete(node.id); + this.objects.delete(node.id); } }); for (const node of nodes) { @@ -105,23 +91,14 @@ export class CCNodeStore extends EventEmitter { } } - /** - * Get a node by id - * @param id id of node - * @returns node of `id` - */ - get(id: CCNodeId): CCNode | undefined { - return this.#nodes.get(id); - } - getManyByParentComponentId(parentComponentId: CCComponentId): CCNode[] { - return [...this.#nodes.values()].filter( + return [...this.objects.values()].filter( (node) => node.parentComponentId === parentComponentId, ); } getManyByComponentId(componentId: CCComponentId): CCNode[] { - return [...this.#nodes.values()].filter( + return [...this.objects.values()].filter( (node) => node.componentId === componentId, ); } @@ -135,9 +112,9 @@ export class CCNodeStore extends EventEmitter { id: CCNodeId, value: Partial>, ): void { - const existingNode = nullthrows(this.#nodes.get(id)); + const existingNode = nullthrows(this.objects.get(id)); const newNode = { ...existingNode, ...value }; - this.#nodes.set(id, newNode); + this.objects.set(id, newNode); if ("config" in value && value.config !== existingNode.config) { this.emit("didUpdateConfig", newNode); } @@ -157,12 +134,4 @@ export class CCNodeStore extends EventEmitter { ...partialNode, }; } - - /** - * Get array of nodes - * @returns array of nodes - */ - getMany(): CCNode[] { - return [...this.#nodes.values()]; - } } diff --git a/src/store/nodePin.ts b/src/store/nodePin.ts index 90ee596..6862b3b 100644 --- a/src/store/nodePin.ts +++ b/src/store/nodePin.ts @@ -1,8 +1,7 @@ -import EventEmitter from "eventemitter3"; import nullthrows from "nullthrows"; import invariant from "tiny-invariant"; import type { Tagged } from "type-fest"; -import type CCStore from "."; +import { CCBaseStore, type CCBaseStoreEvents } from "./base"; import type { CCComponentPinId, CCNodePinBitWidthStatus } from "./componentPin"; import { IntrinsicComponentDefinition } from "./intrinsics/base"; import type { CCNodeId } from "./node"; @@ -17,10 +16,7 @@ export type CCNodePin = { manualBitWidth: number | null; }; -export type CCNodePinStoreEvents = { - didRegister(pin: CCNodePin): void; - willUnregister(pin: CCNodePin): void; - didUnregister(pin: CCNodePin): void; +export type CCNodePinStoreEvents = CCBaseStoreEvents & { didUpdate(pin: CCNodePin): void; }; export const ccNodePinStoreChangeEventTypes: (keyof CCNodePinStoreEvents)[] = [ @@ -29,11 +25,11 @@ export const ccNodePinStoreChangeEventTypes: (keyof CCNodePinStoreEvents)[] = [ "didUpdate", ]; -export class CCNodePinStore extends EventEmitter { - #store: CCStore; - - #nodePins: Map = new Map(); - +export class CCNodePinStore extends CCBaseStore< + CCNodePinId, + CCNodePin, + CCNodePinStoreEvents +> { #markedAsDeleted: Set = new Set(); #bitWidthCache: Map = new Map(); @@ -42,16 +38,6 @@ export class CCNodePinStore extends EventEmitter { this.#bitWidthCache.clear(); } - /** - * Constructor of CCNodePinStore - * @param store store - * @param nodePins initial pins - */ - constructor(store: CCStore) { - super(); - this.#store = store; - } - import(nodePins: CCNodePin[]) { for (const nodePin of nodePins) { this.register(nodePin); @@ -59,14 +45,14 @@ export class CCNodePinStore extends EventEmitter { } mount() { - this.#store.connections.on("didRegister", () => this.#clearBitWidthCache()); - this.#store.connections.on("didUnregister", () => + this.store.connections.on("didRegister", () => this.#clearBitWidthCache()); + this.store.connections.on("didUnregister", () => this.#clearBitWidthCache(), ); // A calculated bit width may be derived from the config of its node - this.#store.nodes.on("didUpdateConfig", () => this.#clearBitWidthCache()); - this.#store.nodes.on("didRegister", (node) => { - const componentPins = this.#store.componentPins.getManyByComponentId( + this.store.nodes.on("didUpdateConfig", () => this.#clearBitWidthCache()); + this.store.nodes.on("didRegister", (node) => { + const componentPins = this.store.componentPins.getManyByComponentId( node.componentId, ); for (const componentPin of componentPins) { @@ -79,15 +65,15 @@ export class CCNodePinStore extends EventEmitter { ); } }); - this.#store.nodes.on("willUnregister", (node) => { - for (const pin of this.#nodePins.values()) { + this.store.nodes.on("willUnregister", (node) => { + for (const pin of this.objects.values()) { if (pin.nodeId === node.id) { this.unregister(pin.id); } } }); - this.#store.componentPins.on("didRegister", (componentPin) => { - for (const node of this.#store.nodes.getManyByComponentId( + this.store.componentPins.on("didRegister", (componentPin) => { + for (const node of this.store.nodes.getManyByComponentId( componentPin.componentId, )) { this.register( @@ -99,8 +85,8 @@ export class CCNodePinStore extends EventEmitter { ); } }); - this.#store.componentPins.on("willUnregister", (componentPin) => { - for (const pin of this.#nodePins.values()) { + this.store.componentPins.on("willUnregister", (componentPin) => { + for (const pin of this.objects.values()) { if (pin.componentPinId === componentPin.id) { this.unregister(pin.id); } @@ -113,9 +99,9 @@ export class CCNodePinStore extends EventEmitter { * @param nodePin pin to be registered */ register(nodePin: CCNodePin): void { - invariant(this.#store.componentPins.get(nodePin.componentPinId)); - invariant(this.#store.nodes.get(nodePin.nodeId)); - this.#nodePins.set(nodePin.id, nodePin); + invariant(this.store.componentPins.get(nodePin.componentPinId)); + invariant(this.store.nodes.get(nodePin.nodeId)); + this.objects.set(nodePin.id, nodePin); this.#clearBitWidthCache(); this.emit("didRegister", nodePin); } @@ -125,11 +111,11 @@ export class CCNodePinStore extends EventEmitter { * @param id id of a pin to be unregistered */ async unregister(id: CCNodePinId): Promise { - const nodePin = nullthrows(this.#nodePins.get(id)); + const nodePin = nullthrows(this.objects.get(id)); this.#markedAsDeleted.add(id); - await this.#store.transactionManager.runInTransaction(() => { + await this.store.transactionManager.runInTransaction(() => { this.emit("willUnregister", nodePin); - this.#nodePins.delete(nodePin.id); + this.objects.delete(nodePin.id); // Its removal is announced only when the transaction ends, but the bit widths // derived from it are stale from now on this.#clearBitWidthCache(); @@ -139,22 +125,13 @@ export class CCNodePinStore extends EventEmitter { } update(id: CCNodePinId, value: Pick) { - const existingNodePin = nullthrows(this.#nodePins.get(id)); + const existingNodePin = nullthrows(this.objects.get(id)); const newNodePin = { ...existingNodePin, ...value }; - this.#nodePins.set(id, newNodePin); + this.objects.set(id, newNodePin); this.#clearBitWidthCache(); this.emit("didUpdate", newNodePin); } - /** - * Get a pin by id - * @param id id of pin - * @returns pin of `id` - */ - get(id: CCNodePinId): CCNodePin | undefined { - return this.#nodePins.get(id); - } - /** * Get all of pins * @returns all pins @@ -163,7 +140,7 @@ export class CCNodePinStore extends EventEmitter { nodeId: CCNodeId, componentPinId: CCComponentPinId, ): CCNodePin { - const pin = [...this.#nodePins.values()].find( + const pin = [...this.objects.values()].find( (candidate) => candidate.nodeId === nodeId && candidate.componentPinId === componentPinId, @@ -178,14 +155,14 @@ export class CCNodePinStore extends EventEmitter { * @returns pins of component */ getManyByNodeId(nodeId: CCNodeId): CCNodePin[] { - return [...this.#nodePins.values()].filter((pin) => pin.nodeId === nodeId); + return [...this.objects.values()].filter((pin) => pin.nodeId === nodeId); } getManyByNodeIdAndComponentPinId( nodeId: CCNodeId, componentPinId: CCComponentPinId, ): CCNodePin[] { - return [...this.#nodePins.values()].filter( + return [...this.objects.values()].filter( (pin) => pin.nodeId === nodeId && pin.componentPinId === componentPinId, ); } @@ -240,7 +217,7 @@ export class CCNodePinStore extends EventEmitter { targetNodePin; seen.add(targetNodeId); - const targetNode = nullthrows(this.#store.nodes.get(targetNodeId)); + const targetNode = nullthrows(this.store.nodes.get(targetNodeId)); const targetNodePins = this.getManyByNodeId(targetNode.id); const attributes = IntrinsicComponentDefinition.getPinAttributesByPinId( @@ -272,7 +249,7 @@ export class CCNodePinStore extends EventEmitter { } else { // A user defined component pin is fixed by the implementation of its component const componentPinBitWidthStatus = - this.#store.componentPins.getComponentPinBitWidthStatus( + this.store.componentPins.getComponentPinBitWidthStatus( targetComponentPinId, ); if (componentPinBitWidthStatus.isFixed) { @@ -283,7 +260,7 @@ export class CCNodePinStore extends EventEmitter { // node, so any of them may be the one that is connected to a pin of a known width. for (const siblingNodePin of targetNodePins) { const siblingComponentPinBitWidthStatus = - this.#store.componentPins.getComponentPinBitWidthStatus( + this.store.componentPins.getComponentPinBitWidthStatus( siblingNodePin.componentPinId, ); if (siblingComponentPinBitWidthStatus.isFixed) { @@ -297,11 +274,11 @@ export class CCNodePinStore extends EventEmitter { ); } const connections = nullthrows( - this.#store.connections.getConnectionsByNodePinId(siblingNodePin.id), + this.store.connections.getConnectionsByNodePinId(siblingNodePin.id), ); for (const connection of connections) { const componentPin = nullthrows( - this.#store.componentPins.get(siblingNodePin.componentPinId), + this.store.componentPins.get(siblingNodePin.componentPinId), ); const connectedNodePinId = componentPin.type === "input" ? connection.from : connection.to; @@ -335,10 +312,10 @@ export class CCNodePinStore extends EventEmitter { if (!aNodePin || !bNodePin) { throw new Error(`Node pin ${a} or ${b} does not exist in the store`); } - const aComponentPin = this.#store.componentPins.get( + const aComponentPin = this.store.componentPins.get( aNodePin?.componentPinId ?? null, ); - const bComponentPin = this.#store.componentPins.get( + const bComponentPin = this.store.componentPins.get( bNodePin?.componentPinId ?? null, ); if (!aComponentPin || !bComponentPin) { @@ -352,8 +329,8 @@ export class CCNodePinStore extends EventEmitter { ); return false; } - const aNode = this.#store.nodes.get(aNodePin.nodeId); - const bNode = this.#store.nodes.get(bNodePin.nodeId); + const aNode = this.store.nodes.get(aNodePin.nodeId); + const bNode = this.store.nodes.get(bNodePin.nodeId); if (!aNode || !bNode) { throw new Error( `Node ${aNodePin.nodeId} or ${bNodePin.nodeId} does not exist in the store`, @@ -371,10 +348,10 @@ export class CCNodePinStore extends EventEmitter { ); return false; } - const aConnections = this.#store.connections.getConnectionsByNodePinId( + const aConnections = this.store.connections.getConnectionsByNodePinId( aNodePin.id, ); - const bConnections = this.#store.connections.getConnectionsByNodePinId( + const bConnections = this.store.connections.getConnectionsByNodePinId( bNodePin.id, ); if (aComponentPin.type === "input" && aConnections.length > 0) { @@ -428,12 +405,4 @@ export class CCNodePinStore extends EventEmitter { (attributes?.bitWidthPolicy.type === "configurable" ? 1 : null), }; } - - /** - * Get array of pins - * @returns array of pins - */ - getMany(): CCNodePin[] { - return [...this.#nodePins.values()]; - } }