@telorun/editor-protocol 0.1.1 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/editor-protocol",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "The Telo editor protocol: the contract between an editor host and a telo language-server engine — the telo/* requests, the telo/requirements notification and the protocol generation.",
5
5
  "keywords": [
6
6
  "telo",
package/src/index.ts CHANGED
@@ -15,6 +15,9 @@ export interface TeloExperimentalCapabilities {
15
15
  export interface TeloProtocolCapability {
16
16
  /** The generation the engine speaks. */
17
17
  protocol: number;
18
+ /** The engine serves `telo/viewModel` and `telo/celCompletion` and sends
19
+ * `telo/viewModelChanged`. */
20
+ viewModel?: boolean;
18
21
  }
19
22
 
20
23
  /** The file a module directory is read as: `telo/read` of a directory answers
@@ -27,8 +30,9 @@ export const TELO_MODULE_FILENAME = "telo.yaml";
27
30
  * pending. */
28
31
  export const TELO_SERVER_NAME = "telo";
29
32
 
30
- /** Method names of the requests an engine sends and a host serves, and of the
31
- * notification an engine sends. */
33
+ /** Method names of every `telo/*` message: the requests an engine sends and a
34
+ * host serves, the requests a host sends and an engine serves, and the
35
+ * notifications an engine sends. */
32
36
  export const TeloMethod = {
33
37
  read: "telo/read",
34
38
  exists: "telo/exists",
@@ -36,6 +40,9 @@ export const TeloMethod = {
36
40
  hubSearchRefs: "telo/hub/searchRefs",
37
41
  hubListVersions: "telo/hub/listVersions",
38
42
  requirements: "telo/requirements",
43
+ viewModel: "telo/viewModel",
44
+ celCompletion: "telo/celCompletion",
45
+ viewModelChanged: "telo/viewModelChanged",
39
46
  } as const;
40
47
  export type TeloMethod = (typeof TeloMethod)[keyof typeof TeloMethod];
41
48
 
@@ -145,6 +152,279 @@ export interface RequirementsParams {
145
152
  ranges: RequirementsRange[];
146
153
  }
147
154
 
155
+ /** `telo/viewModelChanged`: the owner's view model moved — sent after each
156
+ * analysis of the owner, and when the owner stops being analysed (a
157
+ * `telo/viewModel` for it then answers `null`). */
158
+ export interface ViewModelChangedParams {
159
+ /** Canonical `file:` URI of the owner module's document. */
160
+ owner: string;
161
+ /** Increases with every analysis of the owner, and when it is dropped. */
162
+ revision: number;
163
+ }
164
+
165
+ // --- Engine-served requests (host → engine) --------------------------------
166
+
167
+ /** `telo/viewModel`: the structured-view model of one owner module. */
168
+ export interface ViewModelParams {
169
+ owner: string;
170
+ }
171
+ /** `null` when the engine is not analysing `owner`. */
172
+ export type ViewModelResult = ViewModel | null;
173
+
174
+ /** `telo/celCompletion`: completion for a CEL value typed into a structured
175
+ * form field, which is not document text yet. */
176
+ export interface CelCompletionParams {
177
+ owner: string;
178
+ /** The resource the field belongs to. */
179
+ resource: { kind: string; name: string };
180
+ /** Concrete path of the field within the resource (`routes[0].handler.inputs.x`). */
181
+ path: string;
182
+ /** The tag the value is written under, without its `!` (`cel`, `interpolate`). */
183
+ tag: string;
184
+ /** The field's value without its tag. */
185
+ text: string;
186
+ /** Cursor offset into `text`. */
187
+ offset: number;
188
+ }
189
+ /** LSP `CompletionItem`s; a `textEdit` range is a line/character range in
190
+ * `text`. Empty when the engine is not analysing `owner`. */
191
+ export type CelCompletionResult = CompletionItem[];
192
+
193
+ /** The members of an LSP `CompletionItem` an engine sets. */
194
+ export interface CompletionItem {
195
+ label: string;
196
+ /** LSP `CompletionItemKind`. */
197
+ kind?: number;
198
+ detail?: string;
199
+ documentation?: string;
200
+ insertText?: string;
201
+ /** LSP `InsertTextFormat`; 2 is a snippet. */
202
+ insertTextFormat?: number;
203
+ textEdit?: { range: TextRange; newText: string };
204
+ preselect?: boolean;
205
+ sortText?: string;
206
+ filterText?: string;
207
+ command?: { title: string; command: string };
208
+ }
209
+
210
+ export interface TextRange {
211
+ start: { line: number; character: number };
212
+ end: { line: number; character: number };
213
+ }
214
+
215
+ /** Params and result of every engine-served request, by method. */
216
+ export interface TeloEngineRequests {
217
+ "telo/viewModel": [ViewModelParams, ViewModelResult];
218
+ "telo/celCompletion": [CelCompletionParams, CelCompletionResult];
219
+ }
220
+
221
+ // --- The view model ---------------------------------------------------------
222
+
223
+ /** A JSON Schema, as plain JSON. */
224
+ export type JsonSchema = Record<string, unknown>;
225
+
226
+ /**
227
+ * What a structured editor (a module canvas, a schema form, a reference picker)
228
+ * reads about one owner module, computed by the engine of the module's telo
229
+ * version over the same analysis its diagnostics come from.
230
+ */
231
+ export interface ViewModel {
232
+ owner: string;
233
+ revision: number;
234
+ /** The owner module drawn as a graph. */
235
+ moduleGraph: ModuleGraphData | null;
236
+ /** The schema of the owner's module document kind. */
237
+ moduleRootSchema: JsonSchema | null;
238
+ /** Each `kind:` spelling in the closure, and each constraint in
239
+ * `refConstraints`, mapped to the canonical kind it resolves to. A spelling
240
+ * that resolves to nothing is absent. */
241
+ kindSpellings: Record<string, string>;
242
+ /** Per reference-slot constraint: the canonical kinds that satisfy it and the
243
+ * spellings a new resource could be created with. A constraint that resolves
244
+ * to nothing is absent. */
245
+ refConstraints: Record<string, RefConstraint>;
246
+ /** Invocation contracts of every kind declaring one, by canonical kind. */
247
+ contracts: Record<string, KindContract>;
248
+ /** Why a resource of the owner module cannot fill a slot, by what it returns:
249
+ * one entry per reference slot declaring an `outputType` in the closure's
250
+ * kinds. */
251
+ outputRefusals: OutputRefusals[];
252
+ /** The body of every templated kind in the closure, by canonical kind. */
253
+ templates: Record<string, TemplateGraphData>;
254
+ /** Every reference written in the owner module's resources and its module
255
+ * document. */
256
+ referenceSites: ReferenceSite[];
257
+ /** Canonical URI → the LSP version of each open document the analysis read.
258
+ * A host holding a newer version of one of them holds text this model was
259
+ * not computed from. */
260
+ documents: Record<string, number>;
261
+ }
262
+
263
+ export interface RefConstraint {
264
+ accepted: string[];
265
+ userFacing: string[];
266
+ }
267
+
268
+ export interface KindContract {
269
+ inputType?: JsonSchema;
270
+ outputType?: JsonSchema;
271
+ }
272
+
273
+ export interface OutputRefusals {
274
+ /** The canonical kind declaring the slot. */
275
+ kind: string;
276
+ /** JSON Pointer of the slot's `x-telo-ref` node within that kind's `schema`. */
277
+ pointer: string;
278
+ /** Resource name, in the scope the entry is listed in (the owner module, or
279
+ * a template's body), → one line per definite mismatch. A resource absent
280
+ * here can fill the slot. */
281
+ refusals: Record<string, string[]>;
282
+ }
283
+
284
+ export interface TemplateGraphData {
285
+ /** Canonical `<module>.<Name>`. */
286
+ kindId: string;
287
+ name: string;
288
+ module?: string;
289
+ /** The kind's capability, inherited along `extends`. */
290
+ capability?: string;
291
+ /** The definition document as analysed; `metadata.source` is a document URI. */
292
+ definition: Record<string, unknown>;
293
+ graph: ModuleGraphData;
294
+ /** Why an entry of the body cannot fill a slot, by what it returns — the
295
+ * owner's `outputRefusals`, judged over the body's entries. */
296
+ outputRefusals: OutputRefusals[];
297
+ }
298
+
299
+ export interface ReferenceSite {
300
+ /** The resource writing the reference; the module document as itself. */
301
+ source: { kind: string; name: string };
302
+ /** Concrete path of the slot within that resource. */
303
+ path: string;
304
+ /** The name the reference holds, as written (`Alias.name` across an import). */
305
+ target: string;
306
+ }
307
+
308
+ /** A module drawn as boxes, ordered rows and classed edges — the analyzer's
309
+ * module graph as data. */
310
+ export interface ModuleGraphData {
311
+ root?: GraphNodeData;
312
+ nodes: GraphNodeData[];
313
+ edges: GraphEdgeData[];
314
+ regions: GraphRegionData[];
315
+ kinds: GraphKindData[];
316
+ }
317
+
318
+ /** `root` | `named` | `inline` | `scoped` | `imported` | `injected` |
319
+ * `enclosing` | `forwarded`. */
320
+ export type NodeOwnership = string;
321
+ /** `flow` | `holds` | `shape` | `data`. */
322
+ export type EdgeClass = string;
323
+ /** `step` | `entry` | `target` | `inline` | `reference` | `export`. */
324
+ export type RowKind = string;
325
+
326
+ export interface GraphNodeData {
327
+ id: string;
328
+ kind: string;
329
+ name: string;
330
+ capability?: string;
331
+ canonicalKind?: string;
332
+ unknownKind?: boolean;
333
+ ownership: NodeOwnership;
334
+ owner?: string;
335
+ ownerSite?: string;
336
+ module?: string;
337
+ external?: boolean;
338
+ alias?: string;
339
+ ports: GraphPortData[];
340
+ rows: GraphRowData[];
341
+ rowArrays: { field: string; kind: RowKind }[];
342
+ throws?: { codes: string[]; unbounded: boolean };
343
+ root?: boolean;
344
+ }
345
+
346
+ export interface GraphPortData {
347
+ slot: string;
348
+ refs: string[];
349
+ capabilities: string[];
350
+ array: boolean;
351
+ class: EdgeClass;
352
+ slots: { path: string; target?: string; targetNode?: string; inline?: boolean }[];
353
+ addPath?: string;
354
+ rowOwned?: boolean;
355
+ }
356
+
357
+ export interface GraphRowData {
358
+ id: string;
359
+ kind: RowKind;
360
+ name?: string;
361
+ path: string;
362
+ array: string;
363
+ index: number;
364
+ depth: number;
365
+ parent?: string;
366
+ target?: string;
367
+ targetNode?: string;
368
+ inputs?: string;
369
+ match?: Record<string, unknown>;
370
+ variant?: string;
371
+ variantLabel?: string;
372
+ predicate?: string;
373
+ catches?: boolean;
374
+ dispatch?: {
375
+ path: string;
376
+ refs: string[];
377
+ inline?: boolean;
378
+ alternatives?: { path: string; refs: string[] }[];
379
+ };
380
+ declares?: string;
381
+ unknownKind?: boolean;
382
+ }
383
+
384
+ export interface GraphEdgeData {
385
+ id: string;
386
+ from: string;
387
+ to?: string;
388
+ toName: string;
389
+ class: EdgeClass;
390
+ /** `schema` | `dependency` | `call` | `detached` | `trigger.inbound` |
391
+ * `trigger.consumer`. */
392
+ use: string[];
393
+ slot: string;
394
+ path: string;
395
+ row?: string;
396
+ inputs?: string;
397
+ boot?: boolean;
398
+ scoped?: boolean;
399
+ read?: string;
400
+ call?: string;
401
+ }
402
+
403
+ export interface GraphRegionData {
404
+ id: string;
405
+ /** `inline` | `scope` | `zone`. */
406
+ kind: string;
407
+ owner: string;
408
+ site: string;
409
+ members: string[];
410
+ attributes?: Record<string, string>;
411
+ boundaries?: { from: string; toName: string; escaping: string[] }[];
412
+ }
413
+
414
+ export interface GraphKindData {
415
+ id: string;
416
+ name: string;
417
+ module?: string;
418
+ abstract: boolean;
419
+ capability?: string;
420
+ extendsId?: string;
421
+ extendsName?: string;
422
+ instances: string[];
423
+ template: boolean;
424
+ own: boolean;
425
+ exported?: boolean;
426
+ }
427
+
148
428
  // --- Diagnostic.data -------------------------------------------------------
149
429
 
150
430
  /** The YAML tags a repair may write. A receiver that does not know a tag