@hydranium/protocol 1.0.0-next.10

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.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/lib/abstract-logger.d.ts +66 -0
  4. package/lib/abstract-logger.d.ts.map +1 -0
  5. package/lib/abstract-logger.js +110 -0
  6. package/lib/abstract-logger.js.map +1 -0
  7. package/lib/browser-runtime.d.ts +124 -0
  8. package/lib/browser-runtime.d.ts.map +1 -0
  9. package/lib/browser-runtime.js +11 -0
  10. package/lib/browser-runtime.js.map +1 -0
  11. package/lib/client/data-events.d.ts +49 -0
  12. package/lib/client/data-events.d.ts.map +1 -0
  13. package/lib/client/data-events.js +60 -0
  14. package/lib/client/data-events.js.map +1 -0
  15. package/lib/client/data-port.d.ts +95 -0
  16. package/lib/client/data-port.d.ts.map +1 -0
  17. package/lib/client/data-port.js +11 -0
  18. package/lib/client/data-port.js.map +1 -0
  19. package/lib/client/data-session.d.ts +129 -0
  20. package/lib/client/data-session.d.ts.map +1 -0
  21. package/lib/client/data-session.js +179 -0
  22. package/lib/client/data-session.js.map +1 -0
  23. package/lib/client/index.d.ts +39 -0
  24. package/lib/client/index.d.ts.map +1 -0
  25. package/lib/client/index.js +55 -0
  26. package/lib/client/index.js.map +1 -0
  27. package/lib/client/message-relay.d.ts +111 -0
  28. package/lib/client/message-relay.d.ts.map +1 -0
  29. package/lib/client/message-relay.js +139 -0
  30. package/lib/client/message-relay.js.map +1 -0
  31. package/lib/client/post-message-transport.d.ts +77 -0
  32. package/lib/client/post-message-transport.d.ts.map +1 -0
  33. package/lib/client/post-message-transport.js +95 -0
  34. package/lib/client/post-message-transport.js.map +1 -0
  35. package/lib/clock.d.ts +111 -0
  36. package/lib/clock.d.ts.map +1 -0
  37. package/lib/clock.js +74 -0
  38. package/lib/clock.js.map +1 -0
  39. package/lib/data/data-protocol-methods.d.ts +39 -0
  40. package/lib/data/data-protocol-methods.d.ts.map +1 -0
  41. package/lib/data/data-protocol-methods.js +61 -0
  42. package/lib/data/data-protocol-methods.js.map +1 -0
  43. package/lib/data/data-server-protocol.d.ts +264 -0
  44. package/lib/data/data-server-protocol.d.ts.map +1 -0
  45. package/lib/data/data-server-protocol.js +11 -0
  46. package/lib/data/data-server-protocol.js.map +1 -0
  47. package/lib/data/diagnostics.d.ts +97 -0
  48. package/lib/data/diagnostics.d.ts.map +1 -0
  49. package/lib/data/diagnostics.js +25 -0
  50. package/lib/data/diagnostics.js.map +1 -0
  51. package/lib/data/events.d.ts +107 -0
  52. package/lib/data/events.d.ts.map +1 -0
  53. package/lib/data/events.js +11 -0
  54. package/lib/data/events.js.map +1 -0
  55. package/lib/data/index.d.ts +15 -0
  56. package/lib/data/index.d.ts.map +1 -0
  57. package/lib/data/index.js +38 -0
  58. package/lib/data/index.js.map +1 -0
  59. package/lib/data/methods.d.ts +57 -0
  60. package/lib/data/methods.d.ts.map +1 -0
  61. package/lib/data/methods.js +60 -0
  62. package/lib/data/methods.js.map +1 -0
  63. package/lib/data/requests.d.ts +65 -0
  64. package/lib/data/requests.d.ts.map +1 -0
  65. package/lib/data/requests.js +11 -0
  66. package/lib/data/requests.js.map +1 -0
  67. package/lib/debouncer.d.ts +75 -0
  68. package/lib/debouncer.d.ts.map +1 -0
  69. package/lib/debouncer.js +91 -0
  70. package/lib/debouncer.js.map +1 -0
  71. package/lib/errors.d.ts +84 -0
  72. package/lib/errors.d.ts.map +1 -0
  73. package/lib/errors.js +113 -0
  74. package/lib/errors.js.map +1 -0
  75. package/lib/host-diagnostics.d.ts +58 -0
  76. package/lib/host-diagnostics.d.ts.map +1 -0
  77. package/lib/host-diagnostics.js +18 -0
  78. package/lib/host-diagnostics.js.map +1 -0
  79. package/lib/index.d.ts +34 -0
  80. package/lib/index.d.ts.map +1 -0
  81. package/lib/index.js +56 -0
  82. package/lib/index.js.map +1 -0
  83. package/lib/latency-collector.d.ts +126 -0
  84. package/lib/latency-collector.d.ts.map +1 -0
  85. package/lib/latency-collector.js +137 -0
  86. package/lib/latency-collector.js.map +1 -0
  87. package/lib/logger.d.ts +119 -0
  88. package/lib/logger.d.ts.map +1 -0
  89. package/lib/logger.js +126 -0
  90. package/lib/logger.js.map +1 -0
  91. package/lib/model-server.d.ts +352 -0
  92. package/lib/model-server.d.ts.map +1 -0
  93. package/lib/model-server.js +160 -0
  94. package/lib/model-server.js.map +1 -0
  95. package/lib/model-service/args.d.ts +64 -0
  96. package/lib/model-service/args.d.ts.map +1 -0
  97. package/lib/model-service/args.js +11 -0
  98. package/lib/model-service/args.js.map +1 -0
  99. package/lib/model-service/index.d.ts +11 -0
  100. package/lib/model-service/index.d.ts.map +1 -0
  101. package/lib/model-service/index.js +31 -0
  102. package/lib/model-service/index.js.map +1 -0
  103. package/lib/model-service/reference-candidate.d.ts +56 -0
  104. package/lib/model-service/reference-candidate.d.ts.map +1 -0
  105. package/lib/model-service/reference-candidate.js +11 -0
  106. package/lib/model-service/reference-candidate.js.map +1 -0
  107. package/lib/noop-logger.d.ts +25 -0
  108. package/lib/noop-logger.d.ts.map +1 -0
  109. package/lib/noop-logger.js +36 -0
  110. package/lib/noop-logger.js.map +1 -0
  111. package/lib/observable-value.d.ts +72 -0
  112. package/lib/observable-value.d.ts.map +1 -0
  113. package/lib/observable-value.js +52 -0
  114. package/lib/observable-value.js.map +1 -0
  115. package/lib/patch-merge.d.ts +123 -0
  116. package/lib/patch-merge.d.ts.map +1 -0
  117. package/lib/patch-merge.js +104 -0
  118. package/lib/patch-merge.js.map +1 -0
  119. package/lib/profile-session.d.ts +87 -0
  120. package/lib/profile-session.d.ts.map +1 -0
  121. package/lib/profile-session.js +98 -0
  122. package/lib/profile-session.js.map +1 -0
  123. package/lib/profiling.d.ts +83 -0
  124. package/lib/profiling.d.ts.map +1 -0
  125. package/lib/profiling.js +20 -0
  126. package/lib/profiling.js.map +1 -0
  127. package/lib/project.d.ts +121 -0
  128. package/lib/project.d.ts.map +1 -0
  129. package/lib/project.js +34 -0
  130. package/lib/project.js.map +1 -0
  131. package/lib/rpc/bind-rpc-methods.d.ts +100 -0
  132. package/lib/rpc/bind-rpc-methods.d.ts.map +1 -0
  133. package/lib/rpc/bind-rpc-methods.js +110 -0
  134. package/lib/rpc/bind-rpc-methods.js.map +1 -0
  135. package/lib/rpc/create-rpc-proxy.d.ts +188 -0
  136. package/lib/rpc/create-rpc-proxy.d.ts.map +1 -0
  137. package/lib/rpc/create-rpc-proxy.js +158 -0
  138. package/lib/rpc/create-rpc-proxy.js.map +1 -0
  139. package/lib/rpc/index.d.ts +12 -0
  140. package/lib/rpc/index.d.ts.map +1 -0
  141. package/lib/rpc/index.js +31 -0
  142. package/lib/rpc/index.js.map +1 -0
  143. package/lib/rpc/wire-prefix.d.ts +37 -0
  144. package/lib/rpc/wire-prefix.d.ts.map +1 -0
  145. package/lib/rpc/wire-prefix.js +49 -0
  146. package/lib/rpc/wire-prefix.js.map +1 -0
  147. package/lib/testing/data-doubles.d.ts +121 -0
  148. package/lib/testing/data-doubles.d.ts.map +1 -0
  149. package/lib/testing/data-doubles.js +102 -0
  150. package/lib/testing/data-doubles.js.map +1 -0
  151. package/lib/testing/fake-clock.d.ts +35 -0
  152. package/lib/testing/fake-clock.d.ts.map +1 -0
  153. package/lib/testing/fake-clock.js +86 -0
  154. package/lib/testing/fake-clock.js.map +1 -0
  155. package/lib/testing/harness.d.ts +24 -0
  156. package/lib/testing/harness.d.ts.map +1 -0
  157. package/lib/testing/harness.js +11 -0
  158. package/lib/testing/harness.js.map +1 -0
  159. package/lib/testing/index.d.ts +13 -0
  160. package/lib/testing/index.d.ts.map +1 -0
  161. package/lib/testing/index.js +41 -0
  162. package/lib/testing/index.js.map +1 -0
  163. package/lib/testing/node/duplex-connection.d.ts +25 -0
  164. package/lib/testing/node/duplex-connection.d.ts.map +1 -0
  165. package/lib/testing/node/duplex-connection.js +34 -0
  166. package/lib/testing/node/duplex-connection.js.map +1 -0
  167. package/lib/testing/node/duplex-stream.d.ts +32 -0
  168. package/lib/testing/node/duplex-stream.d.ts.map +1 -0
  169. package/lib/testing/node/duplex-stream.js +35 -0
  170. package/lib/testing/node/duplex-stream.js.map +1 -0
  171. package/lib/testing/node/index.d.ts +11 -0
  172. package/lib/testing/node/index.d.ts.map +1 -0
  173. package/lib/testing/node/index.js +37 -0
  174. package/lib/testing/node/index.js.map +1 -0
  175. package/lib/testing/wait-for.d.ts +69 -0
  176. package/lib/testing/wait-for.d.ts.map +1 -0
  177. package/lib/testing/wait-for.js +67 -0
  178. package/lib/testing/wait-for.js.map +1 -0
  179. package/lib/tracer.d.ts +115 -0
  180. package/lib/tracer.d.ts.map +1 -0
  181. package/lib/tracer.js +205 -0
  182. package/lib/tracer.js.map +1 -0
  183. package/lib/transfer-diagnostic.d.ts +73 -0
  184. package/lib/transfer-diagnostic.d.ts.map +1 -0
  185. package/lib/transfer-diagnostic.js +45 -0
  186. package/lib/transfer-diagnostic.js.map +1 -0
  187. package/lib/transfer-document.d.ts +73 -0
  188. package/lib/transfer-document.d.ts.map +1 -0
  189. package/lib/transfer-document.js +46 -0
  190. package/lib/transfer-document.js.map +1 -0
  191. package/lib/transfer-element.d.ts +39 -0
  192. package/lib/transfer-element.d.ts.map +1 -0
  193. package/lib/transfer-element.js +11 -0
  194. package/lib/transfer-element.js.map +1 -0
  195. package/lib/uri.d.ts +62 -0
  196. package/lib/uri.d.ts.map +1 -0
  197. package/lib/uri.js +28 -0
  198. package/lib/uri.js.map +1 -0
  199. package/lib/util.d.ts +147 -0
  200. package/lib/util.d.ts.map +1 -0
  201. package/lib/util.js +211 -0
  202. package/lib/util.js.map +1 -0
  203. package/package.json +100 -0
  204. package/src/abstract-logger.ts +120 -0
  205. package/src/browser-runtime.ts +135 -0
  206. package/src/client/data-events.ts +71 -0
  207. package/src/client/data-port.ts +99 -0
  208. package/src/client/data-session.ts +209 -0
  209. package/src/client/index.ts +40 -0
  210. package/src/client/message-relay.ts +216 -0
  211. package/src/client/post-message-transport.ts +167 -0
  212. package/src/clock.ts +173 -0
  213. package/src/data/data-protocol-methods.ts +79 -0
  214. package/src/data/data-server-protocol.ts +296 -0
  215. package/src/data/diagnostics.ts +116 -0
  216. package/src/data/events.ts +127 -0
  217. package/src/data/index.ts +23 -0
  218. package/src/data/methods.ts +59 -0
  219. package/src/data/requests.ts +70 -0
  220. package/src/debouncer.ts +118 -0
  221. package/src/errors.ts +127 -0
  222. package/src/host-diagnostics.ts +63 -0
  223. package/src/index.ts +41 -0
  224. package/src/latency-collector.ts +231 -0
  225. package/src/logger.ts +172 -0
  226. package/src/model-server.ts +479 -0
  227. package/src/model-service/args.ts +67 -0
  228. package/src/model-service/index.ts +16 -0
  229. package/src/model-service/reference-candidate.ts +58 -0
  230. package/src/noop-logger.ts +36 -0
  231. package/src/observable-value.ts +92 -0
  232. package/src/patch-merge.ts +165 -0
  233. package/src/profile-session.ts +164 -0
  234. package/src/profiling.ts +113 -0
  235. package/src/project.ts +125 -0
  236. package/src/rpc/README.md +163 -0
  237. package/src/rpc/bind-rpc-methods.ts +180 -0
  238. package/src/rpc/create-rpc-proxy.ts +292 -0
  239. package/src/rpc/index.ts +16 -0
  240. package/src/rpc/wire-prefix.ts +48 -0
  241. package/src/testing/data-doubles.ts +178 -0
  242. package/src/testing/fake-clock.ts +106 -0
  243. package/src/testing/harness.ts +24 -0
  244. package/src/testing/index.ts +26 -0
  245. package/src/testing/node/duplex-connection.ts +50 -0
  246. package/src/testing/node/duplex-stream.ts +51 -0
  247. package/src/testing/node/index.ts +22 -0
  248. package/src/testing/wait-for.ts +94 -0
  249. package/src/tracer.ts +277 -0
  250. package/src/transfer-diagnostic.ts +92 -0
  251. package/src/transfer-document.ts +99 -0
  252. package/src/transfer-element.ts +43 -0
  253. package/src/uri.ts +61 -0
  254. package/src/util.ts +250 -0
@@ -0,0 +1,479 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2023 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ /**
11
+ * Generic model-server protocol types: lifecycle arguments, events, and
12
+ * cross-reference shapes. Free of any specific grammar, AST type, or
13
+ * language identifier — consumers parameterise the document/root types
14
+ * over `TRoot`.
15
+ */
16
+
17
+ import type { TransferClientArgs } from './model-service/args';
18
+ import type { ReferenceCandidate } from './model-service/reference-candidate';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Client / server arguments
22
+ // ---------------------------------------------------------------------------
23
+
24
+ // `TransferClientArgs` / `TransferUpdateArgs` / `TransferSaveArgs` live in
25
+ // `./model-service/args.ts` and are re-exported by the main barrel via
26
+ // `./model-service`. The legacy LSP-style protocol (Open / Close / events)
27
+ // defined here only consumes them as a supertype.
28
+
29
+ /** Open a document on behalf of a client. */
30
+ export interface OpenModelArgs extends TransferClientArgs {
31
+ /**
32
+ * Overrides the language the URI's extension would resolve to. Supply it
33
+ * only when the extension does not decide — an unregistered extension, or a
34
+ * document being opened under a language other than its own. A wrong value
35
+ * routes the document to the wrong grammar and it parses as garbage rather
36
+ * than failing.
37
+ */
38
+ languageId?: string;
39
+ /**
40
+ * Seeds the shared version sequence, defaulting to `0`. Only the FIRST open
41
+ * of a URI consumes it; after that the server owns the sequence and advances
42
+ * it itself, so callers never fabricate later numbers.
43
+ */
44
+ version?: number;
45
+ /**
46
+ * Content to open the document with instead of reading the file. Absent
47
+ * means read from the filesystem, which is the normal case.
48
+ *
49
+ * Honoured only on the first open of a URI: opening an already-open document
50
+ * is a no-op, so passing `text` for one silently changes nothing. Write
51
+ * through the update path instead.
52
+ */
53
+ text?: string;
54
+ }
55
+
56
+ /** Close a previously-opened document for the client. */
57
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
58
+ export interface CloseModelArgs extends TransferClientArgs {}
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Update / save events
62
+ // ---------------------------------------------------------------------------
63
+
64
+ export interface TransferUpdatedEvent<TDocument> {
65
+ document: TDocument;
66
+ sourceClientId: string;
67
+ /** See `ModelDocumentUpdateReason` in `./data/events` for the canonical reason set + semantics. */
68
+ reason: 'changed' | 'deleted' | 'rebuilt' | 'saved';
69
+ }
70
+
71
+ export interface TransferSavedEvent<TDocument> {
72
+ /** The document as persisted — the state that reached disk, not the state at request time. */
73
+ document: TDocument;
74
+ /**
75
+ * The client whose save produced this. Every co-editing client receives the
76
+ * event including the originator, so a recipient compares it against its own
77
+ * id to recognise its own echo; acting on that echo is how an update loop
78
+ * starts.
79
+ */
80
+ sourceClientId: string;
81
+ }
82
+
83
+ // ---------------------------------------------------------------------------
84
+ // Cross-reference shapes
85
+ // ---------------------------------------------------------------------------
86
+
87
+ /**
88
+ * The source-side address for a reference query: where the lookup is asked
89
+ * from. One of three shapes — a {@link DocumentSource} (the root of a
90
+ * document at the given URI), an {@link ElementSource} (an element resolved
91
+ * by its qualified name), or a {@link SyntheticSource} (a transient
92
+ * element that does not yet exist on disk, used during element-creation
93
+ * flows).
94
+ *
95
+ * Construct via the {@link ReferenceSource} namespace factories
96
+ * (`ReferenceSource.document(uri)` / `.element(name, type?)` /
97
+ * `.synthetic(uri, type)`) rather than tag-field literals — the factories
98
+ * surface the three variants via autocomplete and centralise any future
99
+ * shape changes.
100
+ */
101
+ export type ReferenceSource = DocumentSource | ElementSource | SyntheticSource;
102
+
103
+ /** A reference anchored at the root element of a document, identified by URI. */
104
+ export interface DocumentSource {
105
+ uri: string;
106
+ }
107
+
108
+ /**
109
+ * Narrow an unknown value to a {@link DocumentSource}. Not exclusive within
110
+ * {@link ReferenceSource}: a {@link SyntheticSource} also carries `uri`, so
111
+ * discriminating the union must try {@link isSyntheticSource} first.
112
+ */
113
+ export function isDocumentSource(object: unknown): object is DocumentSource {
114
+ return !!object && typeof object === 'object' && 'uri' in object && typeof object.uri === 'string';
115
+ }
116
+
117
+ /**
118
+ * A reference to an element identified by its **qualified name**, optionally
119
+ * narrowed by type.
120
+ *
121
+ * The name is the form a source-text writer would type — normally the
122
+ * project-qualified name (see `NameProvider.getProjectQualifiedName`). It is
123
+ * **not** rename-stable and is distinct from an element *key*: rename the
124
+ * element and this address changes. Clients that need a handle surviving
125
+ * renames address the element some other way; this shape addresses by name.
126
+ */
127
+ export interface ElementSource {
128
+ /**
129
+ * The qualified name as a source-text writer would spell it — normally the
130
+ * project-qualified form. Resolution is by exact match against the index, so
131
+ * a partially-qualified or differently-cased spelling simply finds nothing
132
+ * rather than falling back to a looser search.
133
+ */
134
+ name: string;
135
+ /**
136
+ * Disambiguates when one name is claimed by several AST types. Absent means
137
+ * "any type", which for an ambiguous name resolves arbitrarily rather than
138
+ * failing — pass it whenever the caller knows what it is addressing.
139
+ */
140
+ type?: string;
141
+ }
142
+
143
+ export function isElementSource(object: unknown): object is ElementSource {
144
+ return !!object && typeof object === 'object' && 'name' in object && typeof object.name === 'string';
145
+ }
146
+
147
+ /** An element of a document that does not yet exist on disk — used during element creation flows. */
148
+ export interface SyntheticSource {
149
+ /**
150
+ * The document the element would belong to. That document must already be
151
+ * LOADED — the default resolution takes its parse root as the synthetic
152
+ * node's container and answers `undefined` when it is not, so a URI for a
153
+ * file that exists on disk but was never opened resolves to nothing.
154
+ */
155
+ uri: string;
156
+ /**
157
+ * The AST type the element will have. Required here, unlike on an
158
+ * {@link ElementSource}, because no node exists yet from which to infer it —
159
+ * it is what scoping filters candidates against.
160
+ */
161
+ type: string;
162
+ }
163
+
164
+ export function isSyntheticSource(object: unknown): object is SyntheticSource {
165
+ return (
166
+ !!object &&
167
+ typeof object === 'object' &&
168
+ 'uri' in object &&
169
+ typeof object.uri === 'string' &&
170
+ 'type' in object &&
171
+ typeof object.type === 'string'
172
+ );
173
+ }
174
+
175
+ /**
176
+ * Factory helpers for the {@link ReferenceSource} variants. Use instead of
177
+ * tag-field literals so a future shape change lands in one place.
178
+ */
179
+ export namespace ReferenceSource {
180
+ export function document(uri: string): DocumentSource {
181
+ return { uri };
182
+ }
183
+ export function element(name: string, type?: string): ElementSource {
184
+ return { name, type };
185
+ }
186
+ export function synthetic(uri: string, type: string): SyntheticSource {
187
+ return { uri, type };
188
+ }
189
+ }
190
+
191
+ /**
192
+ * One step in a synthetic navigation path from a {@link ReferenceSource}
193
+ * toward the property whose references we want to query. Each step describes
194
+ * a transient AST node that does not yet exist in the document — e.g. an
195
+ * element being created via UI flow — and is spliced into the chain so the
196
+ * scope provider sees the world *as if* the synthetic child were already
197
+ * placed at that slot.
198
+ *
199
+ * The field names mirror Langium's `$type` / `$containerProperty` so adopter
200
+ * callsites read consistently with AST-side code.
201
+ *
202
+ * Construct via {@link SyntheticStep.of} rather than a tag-field literal.
203
+ */
204
+ export interface SyntheticStep {
205
+ /**
206
+ * The AST `$type` the spliced node claims. Scoping filters candidates
207
+ * against it, so a type the grammar does not declare yields an empty scope
208
+ * rather than an error.
209
+ */
210
+ type: string;
211
+ /**
212
+ * The containment slot on the parent step, or on the source for the first
213
+ * step. It must name a real containment property of that parent: the walk
214
+ * builds the node unconditionally, so a wrong slot produces a plausible node
215
+ * in a place the grammar has no rule for, and the emptiness surfaces later
216
+ * as "no candidates".
217
+ */
218
+ containerProperty: string;
219
+ /**
220
+ * Which element of an array-valued {@link containerProperty} the step
221
+ * addresses. **Mandatory for an array slot** on the resolving read
222
+ * (`ScopeProvider.resolveReferenceSource` given a whole context), which
223
+ * stops rather than descend into the array itself; a scope query reads it
224
+ * only as the stub's `$containerIndex`, since a fabricated node has no
225
+ * siblings to sit between.
226
+ *
227
+ * Absent means the slot holds a single node. Naming an out-of-range element
228
+ * resolves to nothing rather than failing.
229
+ */
230
+ index?: number;
231
+ }
232
+
233
+ /**
234
+ * Narrow an unknown value to a {@link SyntheticStep} — for a consumer
235
+ * validating a step that arrived over the wire. Framework code builds steps
236
+ * through {@link SyntheticStep.of} and never needs the check, so the absent
237
+ * in-repo caller is the seam working rather than unused surface.
238
+ */
239
+ export function isSyntheticStep(object: unknown): object is SyntheticStep {
240
+ return (
241
+ !!object &&
242
+ typeof object === 'object' &&
243
+ 'type' in object &&
244
+ typeof object.type === 'string' &&
245
+ 'containerProperty' in object &&
246
+ typeof object.containerProperty === 'string'
247
+ );
248
+ }
249
+
250
+ export namespace SyntheticStep {
251
+ /**
252
+ * Construct a single {@link SyntheticStep} — "which slot of the parent, of
253
+ * which AST type". Pass `index` to pin the step to an existing array
254
+ * element instead of a transient synthetic node.
255
+ */
256
+ export function of(containerProperty: string, type: string, index?: number): SyntheticStep {
257
+ return { containerProperty, type, index };
258
+ }
259
+
260
+ /**
261
+ * Construct a sequence of {@link SyntheticStep}s from `(containerProperty,
262
+ * type)` tuples. Convenience for 3+ step paths where repeating
263
+ * `SyntheticStep.of(...)` per entry is visually noisy. For 1-2 step paths
264
+ * the per-step factory typically reads more clearly.
265
+ */
266
+ export function chain(...steps: ReadonlyArray<Parameters<typeof of>>): SyntheticStep[] {
267
+ return steps.map(step => of(...step));
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Describes the question "what reachable elements are valid for this property
273
+ * of this (possibly synthetic) source-side element?". The server resolves it
274
+ * to a list of reference candidates ({@link ReferenceCandidate} in
275
+ * `@hydranium/protocol/model-service`).
276
+ *
277
+ * Build via {@link ReferenceContext.builder} — the staged builder enforces
278
+ * the `source -> path -> property` order at compile time.
279
+ */
280
+ export interface ReferenceContext {
281
+ /** Where the query originates — the source-side {@link ReferenceSource} the lookup is anchored at. */
282
+ source: ReferenceSource;
283
+ /**
284
+ * Synthetic navigation path from the source toward the leaf whose
285
+ * references we want. Each entry is a transient AST node spliced into
286
+ * the navigation chain — useful for elements that are being created or
287
+ * that cannot yet be identified canonically. Empty / absent for queries
288
+ * whose source IS the leaf.
289
+ */
290
+ syntheticPath?: SyntheticStep[];
291
+ /**
292
+ * The property of the leaf element (final step in {@link syntheticPath},
293
+ * or the source when the path is empty) whose reachable references we
294
+ * want to retrieve.
295
+ */
296
+ property: string;
297
+ }
298
+
299
+ /**
300
+ * Narrow a value to a {@link ReferenceContext}, discriminating it from a bare
301
+ * {@link ReferenceSource}. No source variant carries either `source` or
302
+ * `property`, so the pair is unambiguous — which is what lets one resolver
303
+ * accept both an anchor and a whole context.
304
+ */
305
+ export function isReferenceContext(object: unknown): object is ReferenceContext {
306
+ return (
307
+ !!object &&
308
+ typeof object === 'object' &&
309
+ 'source' in object &&
310
+ 'property' in object &&
311
+ typeof (object as ReferenceContext).property === 'string'
312
+ );
313
+ }
314
+
315
+ /**
316
+ * A concrete reference-resolution request: a {@link ReferenceContext} plus the
317
+ * written value to resolve. Extending the context makes resolution literally
318
+ * "the candidate query, narrowed to one value" — and a request carries a
319
+ * `syntheticPath` for free, so a reference anchored at a nested synthetic
320
+ * source resolves the same way it lists candidates.
321
+ *
322
+ * Build via {@link ReferenceRequest.builder} — same staged order as
323
+ * {@link ReferenceContext.builder}, ending with a mandatory `value`.
324
+ */
325
+ export interface ReferenceRequest extends ReferenceContext {
326
+ /** The textual value (the `$refText`) of the reference we are resolving. */
327
+ value: string;
328
+ }
329
+
330
+ // ---------------------------------------------------------------------------
331
+ // Staged builders for ReferenceContext / ReferenceRequest
332
+ // ---------------------------------------------------------------------------
333
+
334
+ /**
335
+ * First builder stage: pick the {@link ReferenceSource} variant. Generic over
336
+ * the stage that `property()` lands on, so the context and request builders
337
+ * share the source/path stages and differ only at the terminal.
338
+ */
339
+ export interface ReferenceSourceStage<TAfterProperty> {
340
+ /** Anchor at the semantic root of a loaded document — a {@link DocumentSource}. */
341
+ document(uri: string): ReferencePathStage<TAfterProperty>;
342
+ /** Anchor at an element addressed by qualified name — an {@link ElementSource}. */
343
+ element(name: string, type?: string): ReferencePathStage<TAfterProperty>;
344
+ /** Anchor at an element that does not exist yet — a {@link SyntheticSource}. */
345
+ synthetic(uri: string, type: string): ReferencePathStage<TAfterProperty>;
346
+ }
347
+
348
+ /**
349
+ * Second builder stage: append synthetic {@link SyntheticStep}s (repeatable,
350
+ * optional), then close on the leaf property. `step()` is unavailable after
351
+ * `property()`, which enforces the `source -> path -> property` order.
352
+ */
353
+ export interface ReferencePathStage<TAfterProperty> {
354
+ /**
355
+ * Append one {@link SyntheticStep}, outermost first, and return a new stage
356
+ * carrying the extended path. The builder is persistent, so a stage held in
357
+ * a variable is a reusable prefix: stepping off it twice builds two paths,
358
+ * and neither can be changed afterwards by the other.
359
+ */
360
+ step(containerProperty: string, type: string, index?: number): ReferencePathStage<TAfterProperty>;
361
+ /** Name the leaf property and close the builder. */
362
+ property(property: string): TAfterProperty;
363
+ }
364
+
365
+ /** Context terminal — `property()` closed the chain; build the context. */
366
+ export interface ReferenceContextBuildStage {
367
+ build(): ReferenceContext;
368
+ }
369
+
370
+ /** Request value stage — the value is mandatory before {@link ReferenceRequestBuildStage.build}. */
371
+ export interface ReferenceRequestValueStage {
372
+ value(value: string): ReferenceRequestBuildStage;
373
+ }
374
+
375
+ /** Request terminal — build the request. */
376
+ export interface ReferenceRequestBuildStage {
377
+ build(): ReferenceRequest;
378
+ }
379
+
380
+ /**
381
+ * Shared builder engine for both reference builders. Accumulates the source
382
+ * and the synthetic path, then hands the assembled {@link ReferenceContext} to
383
+ * `onProperty`, which produces the builder-specific terminal stage.
384
+ *
385
+ * **Persistent, not accumulating.** Each `step()` returns a NEW stage over a
386
+ * copied path, and `property()` copies again into the context it emits. A
387
+ * mutable builder would make a held stage a shared cursor — two branches off it
388
+ * would build one path between them, and two contexts built from it would alias
389
+ * a single array that a later `step()` could still change underneath both.
390
+ * Copying a path of two or three entries costs nothing next to a scope query.
391
+ */
392
+ function referenceBuilder<TAfterProperty>(onProperty: (context: ReferenceContext) => TAfterProperty): ReferenceSourceStage<TAfterProperty> {
393
+ const pathStageFor = (source: ReferenceSource, steps: readonly SyntheticStep[]): ReferencePathStage<TAfterProperty> => ({
394
+ step(containerProperty, type, index) {
395
+ return pathStageFor(source, [...steps, { containerProperty, type, index }]);
396
+ },
397
+ property(property) {
398
+ return onProperty(steps.length > 0 ? { source, property, syntheticPath: [...steps] } : { source, property });
399
+ }
400
+ });
401
+ return {
402
+ document: uri => pathStageFor({ uri }, []),
403
+ element: (name, type) => pathStageFor({ name, type }, []),
404
+ synthetic: (uri, type) => pathStageFor({ uri, type }, [])
405
+ };
406
+ }
407
+
408
+ export namespace ReferenceContext {
409
+ /** Staged builder entry — `source -> path -> property -> build`. */
410
+ export function builder(): ReferenceSourceStage<ReferenceContextBuildStage> {
411
+ return referenceBuilder(context => ({ build: () => context }));
412
+ }
413
+ }
414
+
415
+ export namespace ReferenceRequest {
416
+ /** Staged builder entry — `source -> path -> property -> value -> build`. */
417
+ export function builder(): ReferenceSourceStage<ReferenceRequestValueStage> {
418
+ return referenceBuilder(context => ({
419
+ value: (value: string) => ({ build: () => ({ ...context, value }) })
420
+ }));
421
+ }
422
+
423
+ /**
424
+ * Promote a {@link ReferenceContext} to a request using a selected
425
+ * candidate's value — the find -> select -> resolve flow. The candidate
426
+ * supplies only the value (it is target-side); the source / property /
427
+ * synthetic path come from the context the candidates were listed for.
428
+ * Accepts any {@link ReferenceCandidate} (a `ReferenceTarget` works too).
429
+ */
430
+ export function from(context: ReferenceContext, candidate: ReferenceCandidate): ReferenceRequest {
431
+ return { ...context, value: candidate.value };
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Naming tier for `findNextName`-style lookups — which uniqueness
437
+ * scope a proposed name must be unique within. This is NOT the
438
+ * name-qualification axis, which decides how a name is spelled; the two are
439
+ * independent even though each spells two of its members `local` and
440
+ * `project`, and conflating them reads as an argument to rename `tier`.
441
+ *
442
+ * - `'local'` — unique within the document (the document root is the
443
+ * uniqueness container).
444
+ * - `'project'` — unique within the owning project's document-qualified
445
+ * namespace.
446
+ * - `'public'` — unique within the project-qualified (cross-project)
447
+ * namespace.
448
+ */
449
+ export type NameTier = 'local' | 'project' | 'public';
450
+
451
+ /** Arguments for a next-free-name lookup. */
452
+ export interface FindNextNameArgs {
453
+ /**
454
+ * Locates the document, and via its project the qualification context. The
455
+ * create-element flow is the main caller, so this may name a document that
456
+ * does not exist yet; only the `'local'` tier needs it to resolve to one.
457
+ */
458
+ uri: string;
459
+ /**
460
+ * The AST `$type` of the element being named. Collisions are only looked for
461
+ * among elements of that same type, so the returned name may still be taken
462
+ * by an element of another type.
463
+ */
464
+ type: string;
465
+ /**
466
+ * The desired base name, returned unchanged when it is already free and
467
+ * otherwise used as the stem a suffix is appended to. Any occurrence of the
468
+ * name separator is replaced first, so a proposal cannot smuggle in a
469
+ * qualified name.
470
+ */
471
+ proposal: string;
472
+ /**
473
+ * Which uniqueness scope the returned name must be free in — how wide a net
474
+ * to check for collisions. The result is always a bare own-name whatever the
475
+ * tier; this never changes how the name is spelled. Defaults to `'project'`.
476
+ * See {@link NameTier} for what each tier covers.
477
+ */
478
+ tier?: NameTier;
479
+ }
@@ -0,0 +1,67 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ /**
11
+ * Argument shapes for the in-process `ModelService` facade — the
12
+ * canonical home for the lifecycle operation signatures. Implementation
13
+ * lives in `@hydranium/core/langium/model-service`; this protocol
14
+ * package owns the types so wire-side projections (the data-server
15
+ * protocol in `./data`) can structurally extend them rather than
16
+ * mirroring them by hand.
17
+ *
18
+ * `./model-server.ts` re-exports them, so an import from either path
19
+ * resolves.
20
+ */
21
+
22
+ /** Identifies a client-document binding. Every facade operation carries these fields. */
23
+ export interface TransferClientArgs {
24
+ /** Document URI. */
25
+ uri: string;
26
+ /** Stable identifier for the client invoking the operation. */
27
+ clientId: string;
28
+ }
29
+
30
+ /**
31
+ * Update a document's content via the in-process facade. `model` may be
32
+ * the structured (transfer-model or AST) root or its serialised textual
33
+ * form — implementations decide which is faster on their transport.
34
+ * Generic over `T` so adopters parameterise the structured shape against
35
+ * their grammar's transfer-model overlay; passing a string is always
36
+ * allowed.
37
+ */
38
+ export interface TransferUpdateArgs<T> extends TransferClientArgs {
39
+ /** Structured model root or its serialised textual form. */
40
+ model: T | string;
41
+ /**
42
+ * Optional based-on version: the text-document version this update
43
+ * was authored against. When set, the server compares against its
44
+ * current text-document version for `uri` and throws
45
+ * `ConflictError` on mismatch. Omit to opt out of the gate — mirrors
46
+ * LSP's `OptionalVersionedTextDocumentIdentifier` posture, intended
47
+ * for headless / CLI / batch tooling without a meaningful based-on
48
+ * version.
49
+ */
50
+ baseVersion?: number;
51
+ }
52
+
53
+ /**
54
+ * Persist a document to disk via the in-process facade. Same `model`
55
+ * shape as {@link TransferUpdateArgs}.
56
+ */
57
+ export interface TransferSaveArgs<T> extends TransferClientArgs {
58
+ /** Structured model root or its serialised textual form. */
59
+ model: T | string;
60
+ /**
61
+ * Optional based-on version — same semantics as
62
+ * {@link TransferUpdateArgs.baseVersion}. `save` delegates the gating
63
+ * check to its inner `update`, so this field threads through to the
64
+ * same `ConflictError` site.
65
+ */
66
+ baseVersion?: number;
67
+ }
@@ -0,0 +1,16 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ // Subpath barrel for the in-process `ModelService` facade contract. The
11
+ // implementation lives in `@hydranium/core`; this package owns the
12
+ // argument types so both the framework facade and the data-server wire
13
+ // protocol can structurally agree on the lifecycle shape.
14
+
15
+ export * from './args';
16
+ export * from './reference-candidate';
@@ -0,0 +1,58 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ import type { TransferElement } from '../transfer-element';
11
+
12
+ /**
13
+ * UI-facing descriptor of an AST element that may be assigned as the value
14
+ * of a reference. Carries the URI of the owning document, the AST type, the
15
+ * display label, and the persisted reference value.
16
+ *
17
+ * Produced by the reference-candidate pipeline in `@hydranium/core`
18
+ * (`ReferenceCandidateProvider.find`). Consumed by UI surfaces —
19
+ * command-palettes, drop-target action providers, completion popups — that
20
+ * present ranked, deduped reference candidates to the user.
21
+ *
22
+ * **Why two label fields**: `label` is what the user sees in the dropdown;
23
+ * `value` is what gets persisted as the reference's `$refText` when the
24
+ * user selects this element. Separating them lets the server present a
25
+ * human-readable display name (e.g. `node.name`) while storing the
26
+ * canonical reference identifier (e.g. `node.id`). Both fields are
27
+ * required — producers without a display/value distinction set the same
28
+ * string in both, so consumers never need to remember a fallback rule.
29
+ */
30
+ export interface ReferenceCandidate {
31
+ /** URI of the document declaring the referenced element. */
32
+ uri: string;
33
+ /** AST `$type` of the referenced element — useful for icon dispatch. */
34
+ type: string;
35
+ /** Display label shown to the user in dropdowns and chips. */
36
+ label: string;
37
+ /** String stored as `$refText` when the user selects this element. */
38
+ value: string;
39
+ }
40
+
41
+ /**
42
+ * Result of resolving a `ReferenceRequest` to its target — a
43
+ * {@link ReferenceCandidate} plus the resolved node's transfer subtree.
44
+ *
45
+ * A candidate and a target are the same kind of thing (an addressable
46
+ * reference target): `find` lists candidates, `resolveReference` returns the
47
+ * one a value matched. The target additionally carries `element` because it
48
+ * is a single result that can afford the payload, where candidates come as a
49
+ * list and stay lightweight. The encoded `element` is just the resolved
50
+ * node's subtree, NOT the whole document root — callers that want the full
51
+ * document fetch it via `getModelDocument(uri)`.
52
+ *
53
+ * Generic over the transfer root type so adopters get their typed overlay.
54
+ */
55
+ export interface ReferenceTarget<TTransfer extends TransferElement = TransferElement> extends ReferenceCandidate {
56
+ /** The resolved target node, encoded as a transfer subtree. */
57
+ element: TTransfer;
58
+ }
@@ -0,0 +1,36 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ import { AbstractLogger } from './abstract-logger';
11
+ import { type LogLevel, type Logger } from './logger';
12
+
13
+ /**
14
+ * {@link Logger} implementation that discards every message. Intended for
15
+ * programmatic / in-process consumers (test harnesses, non-LSP hosts) that
16
+ * use the framework services but don't have a vscode-jsonrpc connection to
17
+ * forward log output through.
18
+ *
19
+ * Chaining methods (`for`, `sub`, `with`) return a noop instance of the same
20
+ * class; `withUri` short-circuits to the same instance.
21
+ */
22
+ export class NoopLogger extends AbstractLogger implements Logger {
23
+ protected emit(_level: LogLevel, _label: string, _message: string, _args: readonly unknown[]): void {
24
+ // noop — every message is discarded.
25
+ }
26
+
27
+ override withUri(_uri: string): this {
28
+ // Composing a no-op label is wasted work — return the same instance.
29
+ return this;
30
+ }
31
+
32
+ protected derive(component: string): this {
33
+ const Subclass = this.constructor as new (component?: string) => this;
34
+ return new Subclass(component);
35
+ }
36
+ }