@swmmrs/swmmrs 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,153 +1,153 @@
1
- import { ObjectNotFoundError } from "../exceptions.js";
2
- import type { Call } from "../protocol.js";
3
- import type { NodeSnapshot, LinkSnapshot, SubcatchmentSnapshot } from "../snapshots.js";
4
- import { Node, type NodeQualitySnapshot, type NodeStatisticsSnapshot } from "./nodes.js";
5
- import { Link, type LinkQualitySnapshot, type LinkStatisticsSnapshot } from "./links.js";
6
- import { Subcatchment, RainGage, type SubcatchmentQualitySnapshot, type SubcatchmentStatisticsSnapshot } from "./subcatchments.js";
7
-
8
- /**
9
- * Configured-order handles with synchronous, case-insensitive ID lookup and stable identity.
10
- * Obtain simulation collections from the owner rather than constructing a replacement view.
11
- * All access checks the owner lifecycle; no access is valid after close.
12
- * @typeParam T - Handle type returned by lookup and iteration.
13
- */
14
- export class ObjectCollection<T> implements Iterable<T> {
15
- readonly #ids: readonly string[];
16
- readonly #byId: Map<string, string>;
17
- readonly #views = new Map<string, T>();
18
- readonly #create: (id: string) => T;
19
- readonly #assertOpen: () => void;
20
-
21
- /** Construct the shared collection implementation.
22
- * @param ids - Canonical IDs in configured order; copied on construction.
23
- * @param create - Factory called once per looked-up canonical ID.
24
- * @param assertOpen - Lifecycle guard called before collection access.
25
- */
26
- constructor(ids: readonly string[], create: (id: string) => T, assertOpen: () => void) {
27
- this.#ids = Object.freeze([...ids]);
28
- this.#byId = new Map(ids.map((id) => [id.toLowerCase(), id]));
29
- this.#create = create;
30
- this.#assertOpen = assertOpen;
31
- }
32
- /** Canonical IDs in configured order; a frozen array. */
33
- get ids(): readonly string[] { this.#assertOpen(); return this.#ids; }
34
- /** Number of configured objects. */
35
- get size(): number { this.#assertOpen(); return this.#ids.length; }
36
- /** Test membership synchronously.
37
- * @param id - Case-insensitive object ID.
38
- * @returns Whether the ID is configured.
39
- */
40
- has(id: string): boolean { this.#assertOpen(); return this.#byId.has(id.toLowerCase()); }
41
- /** Look up a stable handle synchronously.
42
- * @param id - Case-insensitive object ID.
43
- * @returns The same handle instance for repeated lookups of one canonical ID.
44
- * @throws ObjectNotFoundError for an unknown ID; lifecycle errors after close.
45
- */
46
- get(id: string): T {
47
- this.#assertOpen();
48
- const canonical = this.#byId.get(id.toLowerCase());
49
- if (canonical === undefined) throw new ObjectNotFoundError({ message: `Unknown object: ${id}`, code: 505, operation: "lookup" });
50
- let view = this.#views.get(canonical);
51
- if (view === undefined) { view = this.#create(canonical); this.#views.set(canonical, view); }
52
- return view;
53
- }
54
- /** Look up a configured-order handle synchronously.
55
- * @param index - Zero-based integer index; negative and fractional values are invalid.
56
- * @returns The stable handle at the index.
57
- * @throws RangeError for an out-of-range or noninteger index.
58
- */
59
- at(index: number): T {
60
- this.#assertOpen();
61
- const id = this.#ids[index];
62
- if (!Number.isInteger(index) || id === undefined) throw new RangeError(`Object index out of range: ${index}`);
63
- return this.get(id);
64
- }
65
- /** Iterate handles in configured order.
66
- * @returns Synchronous iterator, checking the owner on each lookup.
67
- */
68
- *[Symbol.iterator](): IterableIterator<T> {
69
- this.#assertOpen();
70
- for (const id of this.#ids) yield this.get(id);
71
- }
72
- }
73
-
74
- /** Owner-bound node handles. Snapshot selections preserve requested order; omit IDs for all nodes. */
75
- export class NodeCollection extends ObjectCollection<Node> {
76
- readonly #call: Call;
77
- private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
78
- super(ids, (id) => Node.create(id, call), assertOpen); this.#call = call;
79
- }
80
- /** @internal */
81
- static create(ids: readonly string[], call: Call, assertOpen: () => void): NodeCollection { return new NodeCollection(ids, call, assertOpen); }
82
- /** Read node hydraulics in `running`, `complete`, or `ended`.
83
- * @param ids - Ordered selection; omit for all, use [] for empty columns. Unknown or case-insensitive duplicate IDs reject.
84
- * @returns Detached columns aligned with canonical `objectIds`, without a timestamp.
85
- */
86
- snapshot(ids?: readonly string[]): Promise<NodeSnapshot> { return this.#call("nodes", ids); }
87
- /** Read node quality in `running`, `complete`, or `ended`.
88
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
89
- * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
90
- */
91
- qualitySnapshot(ids?: readonly string[]): Promise<NodeQualitySnapshot> { return this.#call("nodeQualitySnapshot", ids); }
92
- /** Read cumulative node statistics in `running` or `complete`, before ending the run.
93
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
94
- * @returns Detached statistics columns aligned with canonical `objectIds`.
95
- */
96
- statisticsSnapshot(ids?: readonly string[]): Promise<NodeStatisticsSnapshot> { return this.#call("nodeStatisticsSnapshot", ids); }
97
- }
98
- /** Owner-bound link handles. Snapshot selections preserve requested order; omit IDs for all links. */
99
- export class LinkCollection extends ObjectCollection<Link> {
100
- readonly #call: Call;
101
- private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
102
- super(ids, (id) => Link.create(id, call), assertOpen); this.#call = call;
103
- }
104
- /** @internal */
105
- static create(ids: readonly string[], call: Call, assertOpen: () => void): LinkCollection { return new LinkCollection(ids, call, assertOpen); }
106
- /** Read link hydraulics in `running`, `complete`, or `ended`.
107
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject, including case-only duplicates.
108
- * @returns Detached hydraulic columns aligned with canonical `objectIds`, without a timestamp.
109
- */
110
- snapshot(ids?: readonly string[]): Promise<LinkSnapshot> { return this.#call("links", ids); }
111
- /** Read link quality in `running`, `complete`, or `ended`.
112
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
113
- * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
114
- */
115
- qualitySnapshot(ids?: readonly string[]): Promise<LinkQualitySnapshot> { return this.#call("linkQualitySnapshot", ids); }
116
- /** Read cumulative link statistics in `running` or `complete`.
117
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
118
- * @returns Detached scalar columns; flow-class durations have one seven-value row per link.
119
- */
120
- statisticsSnapshot(ids?: readonly string[]): Promise<LinkStatisticsSnapshot> { return this.#call("linkStatisticsSnapshot", ids); }
121
- }
122
- /** Owner-bound subcatchment handles and aligned hydraulic, quality, and statistics reads. */
123
- export class SubcatchmentCollection extends ObjectCollection<Subcatchment> {
124
- readonly #call: Call;
125
- private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
126
- super(ids, (id) => Subcatchment.create(id, call), assertOpen); this.#call = call;
127
- }
128
- /** @internal */
129
- static create(ids: readonly string[], call: Call, assertOpen: () => void): SubcatchmentCollection { return new SubcatchmentCollection(ids, call, assertOpen); }
130
- /** Read runoff results in `running`, `complete`, or `ended`.
131
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject, including case-only duplicates.
132
- * @returns Detached runoff columns aligned with canonical `objectIds`, without a timestamp.
133
- */
134
- snapshot(ids?: readonly string[]): Promise<SubcatchmentSnapshot> { return this.#call("subcatchments", ids); }
135
- /** Read subcatchment quality in `running`, `complete`, or `ended`.
136
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
137
- * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
138
- */
139
- qualitySnapshot(ids?: readonly string[]): Promise<SubcatchmentQualitySnapshot> { return this.#call("subcatchmentQualitySnapshot", ids); }
140
- /** Read cumulative runoff statistics in `running` or `complete`.
141
- * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
142
- * @returns Detached statistics columns aligned with canonical `objectIds`.
143
- */
144
- statisticsSnapshot(ids?: readonly string[]): Promise<SubcatchmentStatisticsSnapshot> { return this.#call("subcatchmentStatisticsSnapshot", ids); }
145
- }
146
- /** Owner-bound rain-gage handles. Rain gages provide per-object results, not collection snapshots. */
147
- export class RainGageCollection extends ObjectCollection<RainGage> {
148
- private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
149
- super(ids, (id) => RainGage.create(id, call), assertOpen);
150
- }
151
- /** @internal */
152
- static create(ids: readonly string[], call: Call, assertOpen: () => void): RainGageCollection { return new RainGageCollection(ids, call, assertOpen); }
153
- }
1
+ import { ObjectNotFoundError } from "../exceptions.js";
2
+ import type { Call } from "../protocol.js";
3
+ import type { NodeSnapshot, LinkSnapshot, SubcatchmentSnapshot } from "../snapshots.js";
4
+ import { Node, type NodeQualitySnapshot, type NodeStatisticsSnapshot } from "./nodes.js";
5
+ import { Link, type LinkQualitySnapshot, type LinkStatisticsSnapshot } from "./links.js";
6
+ import { Subcatchment, RainGage, type SubcatchmentQualitySnapshot, type SubcatchmentStatisticsSnapshot } from "./subcatchments.js";
7
+
8
+ /**
9
+ * Configured-order handles with synchronous, case-insensitive ID lookup and stable identity.
10
+ * Obtain simulation collections from the owner rather than constructing a replacement view.
11
+ * All access checks the owner lifecycle; no access is valid after close.
12
+ * @typeParam T - Handle type returned by lookup and iteration.
13
+ */
14
+ export class ObjectCollection<T> implements Iterable<T> {
15
+ readonly #ids: readonly string[];
16
+ readonly #byId: Map<string, string>;
17
+ readonly #views = new Map<string, T>();
18
+ readonly #create: (id: string) => T;
19
+ readonly #assertOpen: () => void;
20
+
21
+ /** Construct the shared collection implementation.
22
+ * @param ids - Canonical IDs in configured order; copied on construction.
23
+ * @param create - Factory called once per looked-up canonical ID.
24
+ * @param assertOpen - Lifecycle guard called before collection access.
25
+ */
26
+ constructor(ids: readonly string[], create: (id: string) => T, assertOpen: () => void) {
27
+ this.#ids = Object.freeze([...ids]);
28
+ this.#byId = new Map(ids.map((id) => [id.toLowerCase(), id]));
29
+ this.#create = create;
30
+ this.#assertOpen = assertOpen;
31
+ }
32
+ /** Canonical IDs in configured order; a frozen array. */
33
+ get ids(): readonly string[] { this.#assertOpen(); return this.#ids; }
34
+ /** Number of configured objects. */
35
+ get size(): number { this.#assertOpen(); return this.#ids.length; }
36
+ /** Test membership synchronously.
37
+ * @param id - Case-insensitive object ID.
38
+ * @returns Whether the ID is configured.
39
+ */
40
+ has(id: string): boolean { this.#assertOpen(); return this.#byId.has(id.toLowerCase()); }
41
+ /** Look up a stable handle synchronously.
42
+ * @param id - Case-insensitive object ID.
43
+ * @returns The same handle instance for repeated lookups of one canonical ID.
44
+ * @throws ObjectNotFoundError for an unknown ID; lifecycle errors after close.
45
+ */
46
+ get(id: string): T {
47
+ this.#assertOpen();
48
+ const canonical = this.#byId.get(id.toLowerCase());
49
+ if (canonical === undefined) throw new ObjectNotFoundError({ message: `Unknown object: ${id}`, code: 505, operation: "lookup" });
50
+ let view = this.#views.get(canonical);
51
+ if (view === undefined) { view = this.#create(canonical); this.#views.set(canonical, view); }
52
+ return view;
53
+ }
54
+ /** Look up a configured-order handle synchronously.
55
+ * @param index - Zero-based integer index; negative and fractional values are invalid.
56
+ * @returns The stable handle at the index.
57
+ * @throws RangeError for an out-of-range or noninteger index.
58
+ */
59
+ at(index: number): T {
60
+ this.#assertOpen();
61
+ const id = this.#ids[index];
62
+ if (!Number.isInteger(index) || id === undefined) throw new RangeError(`Object index out of range: ${index}`);
63
+ return this.get(id);
64
+ }
65
+ /** Iterate handles in configured order.
66
+ * @returns Synchronous iterator, checking the owner on each lookup.
67
+ */
68
+ *[Symbol.iterator](): IterableIterator<T> {
69
+ this.#assertOpen();
70
+ for (const id of this.#ids) yield this.get(id);
71
+ }
72
+ }
73
+
74
+ /** Owner-bound node handles. Snapshot selections preserve requested order; omit IDs for all nodes. */
75
+ export class NodeCollection extends ObjectCollection<Node> {
76
+ readonly #call: Call;
77
+ private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
78
+ super(ids, (id) => Node.create(id, call), assertOpen); this.#call = call;
79
+ }
80
+ /** @internal */
81
+ static create(ids: readonly string[], call: Call, assertOpen: () => void): NodeCollection { return new NodeCollection(ids, call, assertOpen); }
82
+ /** Read node hydraulics in `running`, `complete`, or `ended`.
83
+ * @param ids - Ordered selection; omit for all, use [] for empty columns. Unknown or case-insensitive duplicate IDs reject.
84
+ * @returns Detached columns aligned with canonical `objectIds`, without a timestamp.
85
+ */
86
+ snapshot(ids?: readonly string[]): Promise<NodeSnapshot> { return this.#call("nodes", ids); }
87
+ /** Read node quality in `running`, `complete`, or `ended`.
88
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
89
+ * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
90
+ */
91
+ qualitySnapshot(ids?: readonly string[]): Promise<NodeQualitySnapshot> { return this.#call("nodeQualitySnapshot", ids); }
92
+ /** Read cumulative node statistics in `running` or `complete`, before ending the run.
93
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
94
+ * @returns Detached statistics columns aligned with canonical `objectIds`.
95
+ */
96
+ statisticsSnapshot(ids?: readonly string[]): Promise<NodeStatisticsSnapshot> { return this.#call("nodeStatisticsSnapshot", ids); }
97
+ }
98
+ /** Owner-bound link handles. Snapshot selections preserve requested order; omit IDs for all links. */
99
+ export class LinkCollection extends ObjectCollection<Link> {
100
+ readonly #call: Call;
101
+ private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
102
+ super(ids, (id) => Link.create(id, call), assertOpen); this.#call = call;
103
+ }
104
+ /** @internal */
105
+ static create(ids: readonly string[], call: Call, assertOpen: () => void): LinkCollection { return new LinkCollection(ids, call, assertOpen); }
106
+ /** Read link hydraulics in `running`, `complete`, or `ended`.
107
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject, including case-only duplicates.
108
+ * @returns Detached hydraulic columns aligned with canonical `objectIds`, without a timestamp.
109
+ */
110
+ snapshot(ids?: readonly string[]): Promise<LinkSnapshot> { return this.#call("links", ids); }
111
+ /** Read link quality in `running`, `complete`, or `ended`.
112
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
113
+ * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
114
+ */
115
+ qualitySnapshot(ids?: readonly string[]): Promise<LinkQualitySnapshot> { return this.#call("linkQualitySnapshot", ids); }
116
+ /** Read cumulative link statistics in `running` or `complete`.
117
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
118
+ * @returns Detached scalar columns; flow-class durations have one seven-value row per link.
119
+ */
120
+ statisticsSnapshot(ids?: readonly string[]): Promise<LinkStatisticsSnapshot> { return this.#call("linkStatisticsSnapshot", ids); }
121
+ }
122
+ /** Owner-bound subcatchment handles and aligned hydraulic, quality, and statistics reads. */
123
+ export class SubcatchmentCollection extends ObjectCollection<Subcatchment> {
124
+ readonly #call: Call;
125
+ private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
126
+ super(ids, (id) => Subcatchment.create(id, call), assertOpen); this.#call = call;
127
+ }
128
+ /** @internal */
129
+ static create(ids: readonly string[], call: Call, assertOpen: () => void): SubcatchmentCollection { return new SubcatchmentCollection(ids, call, assertOpen); }
130
+ /** Read runoff results in `running`, `complete`, or `ended`.
131
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject, including case-only duplicates.
132
+ * @returns Detached runoff columns aligned with canonical `objectIds`, without a timestamp.
133
+ */
134
+ snapshot(ids?: readonly string[]): Promise<SubcatchmentSnapshot> { return this.#call("subcatchments", ids); }
135
+ /** Read subcatchment quality in `running`, `complete`, or `ended`.
136
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
137
+ * @returns Detached pollutant-major matrices; inner rows follow `objectIds`.
138
+ */
139
+ qualitySnapshot(ids?: readonly string[]): Promise<SubcatchmentQualitySnapshot> { return this.#call("subcatchmentQualitySnapshot", ids); }
140
+ /** Read cumulative runoff statistics in `running` or `complete`.
141
+ * @param ids - Ordered IDs; omit for all or use [] for none. Unknown/duplicate IDs reject.
142
+ * @returns Detached statistics columns aligned with canonical `objectIds`.
143
+ */
144
+ statisticsSnapshot(ids?: readonly string[]): Promise<SubcatchmentStatisticsSnapshot> { return this.#call("subcatchmentStatisticsSnapshot", ids); }
145
+ }
146
+ /** Owner-bound rain-gage handles. Rain gages provide per-object results, not collection snapshots. */
147
+ export class RainGageCollection extends ObjectCollection<RainGage> {
148
+ private constructor(ids: readonly string[], call: Call, assertOpen: () => void) {
149
+ super(ids, (id) => RainGage.create(id, call), assertOpen);
150
+ }
151
+ /** @internal */
152
+ static create(ids: readonly string[], call: Call, assertOpen: () => void): RainGageCollection { return new RainGageCollection(ids, call, assertOpen); }
153
+ }