@telorun/editor-protocol 0.1.1 → 0.3.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.3.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
@@ -5,7 +5,7 @@
5
5
 
6
6
  /** The protocol generation this package describes. Additions within a
7
7
  * generation are negotiated by capability; an incompatible change bumps it. */
8
- export const TELO_EDITOR_PROTOCOL = 1;
8
+ export const TELO_EDITOR_PROTOCOL = 2;
9
9
 
10
10
  /** What an engine advertises under `ServerCapabilities.experimental`. */
11
11
  export interface TeloExperimentalCapabilities {
@@ -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,331 @@ 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
+ /** The assignment to draw the module graph in, keyed by dimension; a
171
+ * dimension left out takes its default. */
172
+ configuration?: Record<string, unknown>;
173
+ }
174
+ /** `null` when the engine is not analysing `owner`. */
175
+ export type ViewModelResult = ViewModel | null;
176
+
177
+ /** `telo/celCompletion`: completion for a CEL value typed into a structured
178
+ * form field, which is not document text yet. */
179
+ export interface CelCompletionParams {
180
+ owner: string;
181
+ /** The resource the field belongs to. */
182
+ resource: { kind: string; name: string };
183
+ /** Concrete path of the field within the resource (`routes[0].handler.inputs.x`). */
184
+ path: string;
185
+ /** The tag the value is written under, without its `!` (`cel`, `interpolate`). */
186
+ tag: string;
187
+ /** The field's value without its tag. */
188
+ text: string;
189
+ /** Cursor offset into `text`. */
190
+ offset: number;
191
+ }
192
+ /** LSP `CompletionItem`s; a `textEdit` range is a line/character range in
193
+ * `text`. Empty when the engine is not analysing `owner`. */
194
+ export type CelCompletionResult = CompletionItem[];
195
+
196
+ /** The members of an LSP `CompletionItem` an engine sets. */
197
+ export interface CompletionItem {
198
+ label: string;
199
+ /** LSP `CompletionItemKind`. */
200
+ kind?: number;
201
+ detail?: string;
202
+ documentation?: string;
203
+ insertText?: string;
204
+ /** LSP `InsertTextFormat`; 2 is a snippet. */
205
+ insertTextFormat?: number;
206
+ textEdit?: { range: TextRange; newText: string };
207
+ preselect?: boolean;
208
+ sortText?: string;
209
+ filterText?: string;
210
+ command?: { title: string; command: string };
211
+ }
212
+
213
+ export interface TextRange {
214
+ start: { line: number; character: number };
215
+ end: { line: number; character: number };
216
+ }
217
+
218
+ /** Params and result of every engine-served request, by method. */
219
+ export interface TeloEngineRequests {
220
+ "telo/viewModel": [ViewModelParams, ViewModelResult];
221
+ "telo/celCompletion": [CelCompletionParams, CelCompletionResult];
222
+ }
223
+
224
+ // --- The view model ---------------------------------------------------------
225
+
226
+ /** A JSON Schema, as plain JSON. */
227
+ export type JsonSchema = Record<string, unknown>;
228
+
229
+ /**
230
+ * What a structured editor (a module canvas, a schema form, a reference picker)
231
+ * reads about one owner module, computed by the engine of the module's telo
232
+ * version over the same analysis its diagnostics come from.
233
+ */
234
+ export interface ViewModel {
235
+ owner: string;
236
+ revision: number;
237
+ /** The owner module drawn as a graph. */
238
+ moduleGraph: ModuleGraphData | null;
239
+ /** The configurations `moduleGraph` can be drawn in. Absent when the module
240
+ * writes no `!if` / `!switch` choice. */
241
+ configurations?: ViewModelConfigurations;
242
+ /** The schema of the owner's module document kind. */
243
+ moduleRootSchema: JsonSchema | null;
244
+ /** Each `kind:` spelling in the closure, and each constraint in
245
+ * `refConstraints`, mapped to the canonical kind it resolves to. A spelling
246
+ * that resolves to nothing is absent. */
247
+ kindSpellings: Record<string, string>;
248
+ /** Per reference-slot constraint: the canonical kinds that satisfy it and the
249
+ * spellings a new resource could be created with. A constraint that resolves
250
+ * to nothing is absent. */
251
+ refConstraints: Record<string, RefConstraint>;
252
+ /** Invocation contracts of every kind declaring one, by canonical kind. */
253
+ contracts: Record<string, KindContract>;
254
+ /** Why a resource of the owner module cannot fill a slot, by what it returns:
255
+ * one entry per reference slot declaring an `outputType` in the closure's
256
+ * kinds. */
257
+ outputRefusals: OutputRefusals[];
258
+ /** The body of every templated kind in the closure, by canonical kind. */
259
+ templates: Record<string, TemplateGraphData>;
260
+ /** Every reference written in the owner module's resources and its module
261
+ * document. */
262
+ referenceSites: ReferenceSite[];
263
+ /** Canonical URI → the LSP version of each open document the analysis read.
264
+ * A host holding a newer version of one of them holds text this model was
265
+ * not computed from. */
266
+ documents: Record<string, number>;
267
+ }
268
+
269
+ /** One axis of the configuration picker: the path it is read at, its domain
270
+ * and the value a picker starts at (a presence dimension: `absent`). */
271
+ export interface GraphDimension {
272
+ key: string;
273
+ values: unknown[];
274
+ default: unknown;
275
+ }
276
+
277
+ export interface ViewModelConfigurations {
278
+ dimensions: GraphDimension[];
279
+ /** The assignment `moduleGraph` is drawn in, every dimension present. */
280
+ selected: Record<string, unknown>;
281
+ }
282
+
283
+ /** One alternative of a choice: `then`, `else`, `default`, a case key, or
284
+ * `absent` (an `!if` with no `else:` whose condition is false). At a
285
+ * declaration position it carries the kind the branch declares. */
286
+ export interface GraphAlternative {
287
+ key: string;
288
+ kind?: string;
289
+ }
290
+
291
+ /** A `!if` / `!switch` drawn at a box. At a declaration position (`path` is
292
+ * `""`) the box is the choice, identified by its name — only its kind follows
293
+ * the selected configuration. */
294
+ export interface GraphChoice {
295
+ path: string;
296
+ tag: "if" | "switch";
297
+ alternatives: GraphAlternative[];
298
+ selected: string | null;
299
+ }
300
+
301
+ /** A `!for-each` drawn as one box (a family) or one row (a repeat in a list),
302
+ * never one per element. */
303
+ export interface GraphRepeat {
304
+ source: string;
305
+ as: string;
306
+ }
307
+
308
+ export interface RefConstraint {
309
+ accepted: string[];
310
+ userFacing: string[];
311
+ }
312
+
313
+ export interface KindContract {
314
+ inputType?: JsonSchema;
315
+ outputType?: JsonSchema;
316
+ }
317
+
318
+ export interface OutputRefusals {
319
+ /** The canonical kind declaring the slot. */
320
+ kind: string;
321
+ /** JSON Pointer of the slot's `x-telo-ref` node within that kind's `schema`. */
322
+ pointer: string;
323
+ /** Resource name, in the scope the entry is listed in (the owner module, or
324
+ * a template's body), → one line per definite mismatch. A resource absent
325
+ * here can fill the slot. */
326
+ refusals: Record<string, string[]>;
327
+ }
328
+
329
+ export interface TemplateGraphData {
330
+ /** Canonical `<module>.<Name>`. */
331
+ kindId: string;
332
+ name: string;
333
+ module?: string;
334
+ /** The kind's capability, inherited along `extends`. */
335
+ capability?: string;
336
+ /** The definition document as analysed; `metadata.source` is a document URI. */
337
+ definition: Record<string, unknown>;
338
+ graph: ModuleGraphData;
339
+ /** Why an entry of the body cannot fill a slot, by what it returns — the
340
+ * owner's `outputRefusals`, judged over the body's entries. */
341
+ outputRefusals: OutputRefusals[];
342
+ }
343
+
344
+ export interface ReferenceSite {
345
+ /** The resource writing the reference; the module document as itself. */
346
+ source: { kind: string; name: string };
347
+ /** Concrete path of the slot within that resource. */
348
+ path: string;
349
+ /** The name the reference holds, as written (`Alias.name` across an import). */
350
+ target: string;
351
+ }
352
+
353
+ /** A module drawn as boxes, ordered rows and classed edges — the analyzer's
354
+ * module graph as data. */
355
+ export interface ModuleGraphData {
356
+ root?: GraphNodeData;
357
+ nodes: GraphNodeData[];
358
+ edges: GraphEdgeData[];
359
+ regions: GraphRegionData[];
360
+ kinds: GraphKindData[];
361
+ }
362
+
363
+ /** `root` | `named` | `inline` | `scoped` | `imported` | `injected` |
364
+ * `enclosing` | `forwarded`. */
365
+ export type NodeOwnership = string;
366
+ /** `flow` | `holds` | `shape` | `data`. */
367
+ export type EdgeClass = string;
368
+ /** `step` | `entry` | `target` | `repeat` | `inline` | `reference` | `export`. */
369
+ export type RowKind = string;
370
+
371
+ export interface GraphNodeData {
372
+ id: string;
373
+ kind: string;
374
+ name: string;
375
+ capability?: string;
376
+ canonicalKind?: string;
377
+ unknownKind?: boolean;
378
+ ownership: NodeOwnership;
379
+ owner?: string;
380
+ ownerSite?: string;
381
+ module?: string;
382
+ external?: boolean;
383
+ alias?: string;
384
+ ports: GraphPortData[];
385
+ rows: GraphRowData[];
386
+ rowArrays: { field: string; kind: RowKind }[];
387
+ throws?: { codes: string[]; unbounded: boolean };
388
+ root?: boolean;
389
+ choice?: GraphChoice;
390
+ choices?: GraphChoice[];
391
+ family?: GraphRepeat;
392
+ }
393
+
394
+ export interface GraphPortData {
395
+ slot: string;
396
+ refs: string[];
397
+ capabilities: string[];
398
+ array: boolean;
399
+ class: EdgeClass;
400
+ slots: { path: string; target?: string; targetNode?: string; inline?: boolean }[];
401
+ addPath?: string;
402
+ rowOwned?: boolean;
403
+ }
404
+
405
+ export interface GraphRowData {
406
+ id: string;
407
+ kind: RowKind;
408
+ name?: string;
409
+ path: string;
410
+ array: string;
411
+ index: number;
412
+ depth: number;
413
+ parent?: string;
414
+ target?: string;
415
+ targetNode?: string;
416
+ inputs?: string;
417
+ match?: Record<string, unknown>;
418
+ variant?: string;
419
+ variantLabel?: string;
420
+ predicate?: string;
421
+ catches?: boolean;
422
+ dispatch?: {
423
+ path: string;
424
+ refs: string[];
425
+ inline?: boolean;
426
+ alternatives?: { path: string; refs: string[] }[];
427
+ };
428
+ declares?: string;
429
+ unknownKind?: boolean;
430
+ /** `repeat` rows: the loop the list item is. */
431
+ repeat?: GraphRepeat;
432
+ /** A step a template repeat emitted: its identity text, in place of `name`. */
433
+ emitted?: string;
434
+ }
435
+
436
+ export interface GraphEdgeData {
437
+ id: string;
438
+ from: string;
439
+ to?: string;
440
+ toName: string;
441
+ class: EdgeClass;
442
+ /** `schema` | `dependency` | `call` | `detached` | `trigger.inbound` |
443
+ * `trigger.consumer`. */
444
+ use: string[];
445
+ slot: string;
446
+ path: string;
447
+ row?: string;
448
+ inputs?: string;
449
+ boot?: boolean;
450
+ scoped?: boolean;
451
+ read?: string;
452
+ call?: string;
453
+ }
454
+
455
+ export interface GraphRegionData {
456
+ id: string;
457
+ /** `inline` | `scope` | `zone`. */
458
+ kind: string;
459
+ owner: string;
460
+ site: string;
461
+ members: string[];
462
+ attributes?: Record<string, string>;
463
+ boundaries?: { from: string; toName: string; escaping: string[] }[];
464
+ }
465
+
466
+ export interface GraphKindData {
467
+ id: string;
468
+ name: string;
469
+ module?: string;
470
+ abstract: boolean;
471
+ capability?: string;
472
+ extendsId?: string;
473
+ extendsName?: string;
474
+ instances: string[];
475
+ template: boolean;
476
+ own: boolean;
477
+ exported?: boolean;
478
+ }
479
+
148
480
  // --- Diagnostic.data -------------------------------------------------------
149
481
 
150
482
  /** The YAML tags a repair may write. A receiver that does not know a tag
@@ -166,6 +498,13 @@ export interface TeloDiagnosticData {
166
498
  resource?: { kind: string; name: string };
167
499
  /** Dotted path of the offending value within that resource. */
168
500
  path?: string;
501
+ /** Present only on a diagnostic that holds in some configurations of the
502
+ * application but not all: partial assignments covering where it holds, each
503
+ * `{ "<dimension path>": <JSON value> }` naming only the dimensions it
504
+ * narrows (one it leaves out holds every value; the diagnostic holds where
505
+ * some entry agrees on every key it names). Empty when it holds in none. The
506
+ * label is in `message` only. */
507
+ configurations?: Array<Record<string, unknown>>;
169
508
  }
170
509
 
171
510
  // --- Commands --------------------------------------------------------------