@hydranium/conformance 1.0.0-next.7 → 1.0.0-next.70

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/README.md CHANGED
@@ -29,6 +29,13 @@ author, and that keeps checking you as the framework moves.
29
29
  - **A false-green guard in the fixture type.** `LanguageFixture` requires **both** a `valid` and an
30
30
  `invalid` model, so an "invalid" model that in fact parses clean fails the diagnostics checks
31
31
  instead of passing vacuously.
32
+ - **Server-side rendering, opt-in.** Supply `renderedDiagnostic: { locale, expected,
33
+ absentWithLocale }` on a fixture and the `/lsp` battery declares that locale at `initialize`,
34
+ then asserts the fragment appears — and, from `absentWithLocale`, that the untranslated fragment
35
+ DISAPPEARS with the locale and is present without it. It is opt-in because the framework ships no
36
+ catalogue and selects no locale, so a server that renders nothing is correct; and it is a PAIR
37
+ because "the message contains X" alone passes for a server whose English contains X. Omit
38
+ `absentWithLocale` and the control reports skipped rather than being quietly dropped.
32
39
 
33
40
  ## Install
34
41
 
@@ -66,11 +73,15 @@ Each takes `connect` plus `languages`:
66
73
  interfere; the kit disposes the driver afterwards. The data slice wants a server already ready; the
67
74
  LSP slice drives the `initialize` handshake itself, so `connect` must **not** pre-initialise; the
68
75
  GLSP slice drives `start()`.
69
- - **`languages`** is an array of `LanguageFixture`: `valid` and `invalid` (both read by every
70
- slice), plus two opt-ins `edit` (data slice only: a replacement text and an `expect(root)`
71
- predicate, because only you know what "the edit landed" means for your grammar) and
72
- `completionPosition` (LSP slice only). A fixture's `uri` and `text` may be thunks, resolved after
73
- `connect`, which is how each check gets pristine input in a workspace `connect` just created.
76
+ - **`languages`** is an array of `LanguageFixture`: `valid` and `invalid` are required and read by
77
+ every slice; every other field is an opt-in whose checks report **skipped with a named reason**
78
+ when it is absent, so an opt-out stays distinguishable from lost coverage. Read the current set
79
+ off the `LanguageFixture` type, which says per field which slice reads it and what supplying it
80
+ claims the two that carry the most are `edit` (a replacement text plus an `expect(root)`
81
+ predicate, because only you know what "the edit landed" means for your grammar) and `dependent`
82
+ (a document that references `valid`, which is what lets the data slice provoke a cascade). A
83
+ fixture's `uri` and `text` may be thunks, resolved after `connect`, which is how each check gets
84
+ pristine input in a workspace `connect` just created.
74
85
 
75
86
  The GLSP slice is generic over your action type and takes `GlspFixture` per diagram type — the
76
87
  fixture builds the native actions and the kit matches responses by `kind`, so no `@eclipse-glsp/*`
@@ -7,16 +7,16 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  import { type TransferDiagnostic, type TransferElement } from '@hydranium/protocol';
10
- import type { DataServerProtocol, TransferDocumentUpdatedEvent } from '@hydranium/protocol/data';
10
+ import type { DataServerProtocol, ReferenceServerProtocol, TransferDocumentsBuiltEvent, TransferDocumentUpdatedEvent } from '@hydranium/protocol/data';
11
11
  import { type Harness } from '@hydranium/protocol/testing';
12
12
  import type { ConformanceCheck } from '../conformance-suite.js';
13
13
  import { type LanguageFixture } from '../model.js';
14
14
  /**
15
15
  * The data-server driver port — a live, connected, READY data-server exposed
16
- * through its protocol-native proxy plus the captured client-side update
17
- * events. The kit names only `@hydranium/protocol` types, so a
16
+ * through its protocol-native proxy plus the captured client-side
17
+ * notifications. The kit names only `@hydranium/protocol` types, so a
18
18
  * `DataServerHarness` satisfies the port structurally (it has `proxy` +
19
- * `events` + `dispose`) with NO adapter. `extends Harness` gives the kit the
19
+ * `events`, `builds` and `dispose`) with NO adapter. `extends Harness` gives the kit the
20
20
  * universal `dispose()` teardown.
21
21
  *
22
22
  * The kit seeds documents purely through the proxy: `updateModelDocument` is
@@ -29,6 +29,17 @@ export interface DataConformanceDriver<TTransfer extends TransferElement, TDiagn
29
29
  readonly proxy: DataServerProtocol<TTransfer, TDiagnostic>;
30
30
  /** Captured `onDocumentUpdated` events, append order — the subscription check's observation target. */
31
31
  readonly events: ReadonlyArray<TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>>;
32
+ /** Captured `onDocumentsBuilt` events, append order — the cascade check's observation target. */
33
+ readonly builds: ReadonlyArray<TransferDocumentsBuiltEvent>;
34
+ /**
35
+ * The opt-in reference surface, when the head serves it.
36
+ *
37
+ * Separate from {@link proxy} because `ReferenceServerProtocol` is NOT part
38
+ * of `DataServerProtocol` — a head may serve documents and no references at
39
+ * all. Absent means the reference check reports skipped with a named reason
40
+ * rather than failing a head that never claimed the surface.
41
+ */
42
+ readonly references?: ReferenceServerProtocol<TTransfer>;
32
43
  }
33
44
  /** Options for `runDataConformance`. */
34
45
  export interface DataConformanceOptions<TTransfer extends TransferElement, TDiagnostic extends TransferDiagnostic = TransferDiagnostic> {
@@ -62,7 +73,7 @@ export interface DataConformanceOptions<TTransfer extends TransferElement, TDiag
62
73
  * unit tests; adopters call `runDataConformance`.
63
74
  *
64
75
  * `LanguageFixture.edit` is read HERE and nowhere else in the kit, and is
65
- * optional: its two checks report skipped when it is absent. See
76
+ * optional: every check that needs one reports skipped when it is absent. See
66
77
  * {@link LanguageFixture} for which slice reads which field.
67
78
  */
68
79
  export declare function buildDataChecks<TTransfer extends TransferElement, TDiagnostic extends TransferDiagnostic = TransferDiagnostic>(options: DataConformanceOptions<TTransfer, TDiagnostic>): ConformanceCheck[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAWlF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtG,OAAO,KAAK,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AACjG,OAAO,EAAE,KAAK,OAAO,EAAW,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,KAAK,eAAe,EAAiC,MAAM,aAAa,CAAC;AAElF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAqB,CACnC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,CAC5D,SAAQ,OAAO;IACd,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3D,uGAAuG;IACvG,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;CACvF;AAED,wCAAwC;AACxC,MAAM,WAAW,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,SAAS,kBAAkB,GAAG,kBAAkB;IACnI;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/H,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAeD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3H,OAAO,EAAE,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,GACvD,gBAAgB,EAAE,CAsMpB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAWlF,OAAO,EAAoD,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtI,OAAO,KAAK,EACT,kBAAkB,EAClB,uBAAuB,EACvB,2BAA2B,EAC3B,4BAA4B,EAC9B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,OAAO,EAAW,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,KAAK,eAAe,EAAiC,MAAM,aAAa,CAAC;AAElF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAqB,CACnC,SAAS,SAAS,eAAe,EACjC,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,CAC5D,SAAQ,OAAO;IACd,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3D,uGAAuG;IACvG,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,4BAA4B,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;IACrF,iGAAiG;IACjG,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,2BAA2B,CAAC,CAAC;IAC5D;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;CAC3D;AAED,wCAAwC;AACxC,MAAM,WAAW,sBAAsB,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,SAAS,kBAAkB,GAAG,kBAAkB;IACnI;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/H,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD;;;;;;;;;OASG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAeD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,SAAS,SAAS,eAAe,EAAE,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3H,OAAO,EAAE,sBAAsB,CAAC,SAAS,EAAE,WAAW,CAAC,GACvD,gBAAgB,EAAE,CAiVpB"}
package/lib/data/index.js CHANGED
@@ -9,12 +9,12 @@
9
9
  /**
10
10
  * The `@hydranium/conformance/data` slice — protocol conformance for the
11
11
  * data-server head. The driver port IS the protocol-native
12
- * {@link DataServerProtocol} proxy (plus the captured `onDocumentUpdated`
13
- * events), so no upstream wire-lib dep enters the kit and `DataServerHarness`
14
- * satisfies the port structurally with no adapter.
12
+ * {@link DataServerProtocol} proxy (plus the captured client notifications),
13
+ * so no upstream wire-lib dep enters the kit and `DataServerHarness` satisfies
14
+ * the port structurally with no adapter.
15
15
  */
16
16
  import assert from 'node:assert/strict';
17
- import { TransferDocument } from '@hydranium/protocol';
17
+ import { ReferenceSource, SyntheticStep, TransferDocument } from '@hydranium/protocol';
18
18
  import { waitFor } from '@hydranium/protocol/testing';
19
19
  import { resolveDeferred, resolveModel } from '../model.js';
20
20
  /** Client id the kit seeds/edits documents under (the originating author). */
@@ -36,7 +36,7 @@ const SEEDER = 'conformance-seeder';
36
36
  * unit tests; adopters call `runDataConformance`.
37
37
  *
38
38
  * `LanguageFixture.edit` is read HERE and nowhere else in the kit, and is
39
- * optional: its two checks report skipped when it is absent. See
39
+ * optional: every check that needs one reports skipped when it is absent. See
40
40
  * {@link LanguageFixture} for which slice reads which field.
41
41
  */
42
42
  export function buildDataChecks(options) {
@@ -114,7 +114,7 @@ export function buildDataChecks(options) {
114
114
  }
115
115
  });
116
116
  for (const language of options.languages) {
117
- const { valid, invalid, edit } = language;
117
+ const { valid, invalid, edit, dependent } = language;
118
118
  const tag = `[${valid.languageId}]`;
119
119
  checks.push({
120
120
  title: `getModelDocument(valid) returns a coherent envelope ${tag}`,
@@ -166,6 +166,81 @@ export function buildDataChecks(options) {
166
166
  }
167
167
  }
168
168
  });
169
+ checks.push({
170
+ title: `a diagnostic carrying a framework message code also carries its params ${tag}`,
171
+ body: async () => {
172
+ const driver = await connect();
173
+ try {
174
+ const model = resolveModel(invalid);
175
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: model.text });
176
+ const document = await driver.proxy.getModelDocument({ uri: model.uri, includeDiagnostics: true });
177
+ // Conditional rather than fixture-driven, and deliberately so: what
178
+ // an `invalid` fixture provokes is the adopter's choice, and a
179
+ // syntactic error legitimately carries no identity at all. The
180
+ // invariant is that the identity travels WHOLE or not — a `code`
181
+ // without `params` is the half-state that renders a translated
182
+ // template with its placeholders left standing, and it is
183
+ // reachable only by overriding `toTransferDiagnostic`.
184
+ const halfIdentities = document.diagnostics.filter(diagnostic => typeof diagnostic.code === 'string' && diagnostic.code.startsWith('hydranium/') && diagnostic.params === undefined);
185
+ assert.deepStrictEqual(halfIdentities.map(diagnostic => diagnostic.code), [], 'diagnostics carry a framework message code with no params, so a translating surface cannot render them');
186
+ }
187
+ finally {
188
+ driver.dispose();
189
+ }
190
+ }
191
+ });
192
+ // The create-dialog query, and the reason it is its own check: it is the
193
+ // only request a head receives whose URI names no file. Everything else
194
+ // in this battery addresses a document, so a head that routes purely by
195
+ // URI extension passes all of them and still cannot open a create dialog.
196
+ //
197
+ // Doubly opt-in — the fixture must name a query AND the driver must serve
198
+ // the reference surface — because either half missing means the head never
199
+ // claimed this behaviour. The reasons are reported separately so a skip
200
+ // says which half is absent.
201
+ const referenceQuery = language.referenceQuery;
202
+ const referenceSkipReason = !referenceQuery
203
+ ? 'fixture supplies no `referenceQuery` (omit it if this language has no create-element dialog)'
204
+ : undefined;
205
+ checks.push({
206
+ title: `findReferenceCandidates answers for a synthetic source at a folder URI ${tag}`,
207
+ skipReason: referenceSkipReason,
208
+ body: referenceQuery
209
+ ? async () => {
210
+ const driver = await connect();
211
+ try {
212
+ if (!driver.references) {
213
+ // Checked here rather than in `skipReason`: the driver only
214
+ // exists once `connect` has run, and skip reasons are
215
+ // computed while the battery is being planned.
216
+ return;
217
+ }
218
+ const model = resolveModel(valid);
219
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: model.text });
220
+ // Default to the folder holding the valid model: a sibling of
221
+ // it is where a create flow would put the new file.
222
+ const folderUri = referenceQuery.folderUri
223
+ ? resolveDeferred(referenceQuery.folderUri)
224
+ : model.uri.slice(0, model.uri.lastIndexOf('/'));
225
+ assert.ok(folderUri.length > 0 && folderUri !== model.uri, `could not derive a folder URI from ${model.uri}; supply referenceQuery.folderUri`);
226
+ const candidates = await driver.references.findReferenceCandidates({
227
+ source: ReferenceSource.synthetic(folderUri, referenceQuery.type),
228
+ syntheticPath: referenceQuery.path?.map(([containerProperty, type]) => SyntheticStep.of(containerProperty, type)),
229
+ property: referenceQuery.property
230
+ });
231
+ // The expected label, not merely a non-empty array: the defect
232
+ // this guards against answers `[]`, and an empty result is
233
+ // also what a head with a genuinely empty index answers, so
234
+ // only a named candidate tells the two apart.
235
+ const labels = candidates.map(candidate => candidate.label);
236
+ assert.ok(labels.includes(referenceQuery.expectCandidate), `findReferenceCandidates at the folder ${folderUri} did not offer ${JSON.stringify(referenceQuery.expectCandidate)}; got [${labels.join(', ')}]`);
237
+ }
238
+ finally {
239
+ driver.dispose();
240
+ }
241
+ }
242
+ : undefined
243
+ });
169
244
  // Opt-in: both remaining checks need a second, observably different model
170
245
  // text, which only `edit` supplies.
171
246
  const editSkipReason = 'fixture supplies no `edit` (data-slice only; omit it if this language is not driven through the data head)';
@@ -188,6 +263,42 @@ export function buildDataChecks(options) {
188
263
  }
189
264
  : undefined
190
265
  });
266
+ // Opt-in twice over: the cascade needs an edit to provoke it AND a second
267
+ // document that references the first to be provoked.
268
+ const cascadeSkipReason = 'fixture supplies no `dependent` (a document referencing `valid`), so no cascade can be provoked over the protocol';
269
+ checks.push({
270
+ title: `editing a document reports its unwatched dependent as built ${tag}`,
271
+ skipReason: edit && dependent ? undefined : dependent ? editSkipReason : cascadeSkipReason,
272
+ body: edit && dependent
273
+ ? async () => {
274
+ const driver = await connect();
275
+ try {
276
+ const model = resolveModel(valid);
277
+ const other = resolveModel(dependent);
278
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: SEEDER, model: model.text });
279
+ await driver.proxy.updateModelDocument({ uri: other.uri, clientId: SEEDER, model: other.text });
280
+ // Watch ONLY the referenced document. The dependent is left
281
+ // unwatched on purpose: that is the state in which no other
282
+ // channel can report it, and the state a workspace view is in
283
+ // for every document it displays without opening.
284
+ await driver.proxy.watchModelDocument({ uri: model.uri, clientId: SUBSCRIBER });
285
+ const before = driver.builds.length;
286
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: resolveDeferred(edit.to) });
287
+ await waitFor(() => driver.builds.slice(before).some(event => event.uris.includes(other.uri)), {
288
+ message: `no onDocumentsBuilt event named ${other.uri} after editing the document it references`
289
+ });
290
+ const reported = driver.builds.slice(before).flatMap(event => [...event.uris]);
291
+ // The watched document is excluded: its watcher already heard
292
+ // about it on the update channel, and repeating it here would
293
+ // be the bandwidth the per-URI gate exists to avoid.
294
+ assert.ok(!reported.includes(model.uri), `onDocumentsBuilt named the WATCHED ${model.uri}; it is reported on the update channel instead`);
295
+ }
296
+ finally {
297
+ driver.dispose();
298
+ }
299
+ }
300
+ : undefined
301
+ });
191
302
  checks.push({
192
303
  title: `subscribe + update delivers an onDocumentUpdated event with the originating clientId ${tag}`,
193
304
  skipReason: edit ? undefined : editSkipReason,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;GAMG;AAEH,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAiD,MAAM,qBAAqB,CAAC;AAEtG,OAAO,EAAgB,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAwB,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAmDlF,8EAA8E;AAC9E,MAAM,MAAM,GAAG,oBAAoB,CAAC;AACpC,qGAAqG;AACrG,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAC5C;;;;;;GAMG;AACH,MAAM,MAAM,GAAG,oBAAoB,CAAC;AAEpC;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC5B,OAAuD;IAEvD,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAC7C,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,uEAAuE;IACvE,EAAE;IACF,yEAAyE;IACzE,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,2EAA2E;IAC3E,gEAAgE;IAChE,MAAM,CAAC,IAAI,CAAC;QACT,KAAK,EAAE,sDAAsD;QAC7D,IAAI,EAAE,KAAK,IAAI,EAAE;YACd,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;gBAClD,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,qCAAqC,CAAC,CAAC;gBAC1E,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;oBAC9B,MAAM,CAAC,EAAE,CACN,OAAO,OAAO,EAAE,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,EACxD,8CAA8C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CACzE,CAAC;oBACF,2CAA2C;oBAC3C,8DAA8D;oBAC9D,+DAA+D;oBAC/D,6DAA6D;oBAC7D,8DAA8D;oBAC9D,sBAAsB;oBACtB,MAAM,CAAC,EAAE,CAAC,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ,EAAE,WAAW,OAAO,CAAC,EAAE,uBAAuB,CAAC,CAAC;gBACtG,CAAC;gBACD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAChD,MAAM,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,+CAA+C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtH,CAAC;oBAAS,CAAC;gBACR,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,CAAC;QACJ,CAAC;KACH,CAAC,CAAC;IAEH,0EAA0E;IAC1E,wEAAwE;IACxE,sEAAsE;IACtE,2EAA2E;IAC3E,iBAAiB;IACjB,MAAM,CAAC,IAAI,CAAC;QACT,KAAK,EAAE,8DAA8D;QACrE,UAAU,EAAE,eAAe;YACxB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,wHAAwH;QAC7H,IAAI,EAAE,eAAe;YAClB,CAAC,CAAC,KAAK,IAAI,EAAE;gBACR,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;oBAClD,MAAM,CAAC,EAAE,CACN,QAAQ,CAAC,MAAM,GAAG,CAAC,EACnB,mGAAmG,CACrG,CAAC;gBACL,CAAC;wBAAS,CAAC;oBACR,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,CAAC;YACJ,CAAC;YACH,CAAC,CAAC,SAAS;KAChB,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC;QACT,KAAK,EAAE,wDAAwD;QAC/D,IAAI,EAAE,KAAK,IAAI,EAAE;YACd,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACF,oEAAoE;gBACpE,oEAAoE;gBACpE,kDAAkD;gBAClD,MAAM,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YACrC,CAAC;oBAAS,CAAC;gBACR,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,CAAC;QACJ,CAAC;KACH,CAAC,CAAC;IAEH,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC;QAEpC,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,uDAAuD,GAAG,EAAE;YACnE,IAAI,EAAE,KAAK,IAAI,EAAE;gBACd,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACF,mEAAmE;oBACnE,kEAAkE;oBAClE,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;oBAClC,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBAChG,6DAA6D;oBAC7D,iEAAiE;oBACjE,+DAA+D;oBAC/D,gDAAgD;oBAChD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnG,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;oBAC5C,iEAAiE;oBACjE,gEAAgE;oBAChE,6DAA6D;oBAC7D,0DAA0D;oBAC1D,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;oBACzD,MAAM,CAAC,EAAE,CACN,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EACvD,0DAA0D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAClF,CAAC;oBACF,kEAAkE;oBAClE,kEAAkE;oBAClE,MAAM,CAAC,EAAE,CACN,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAClC,2DAA2D,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CACvF,CAAC;oBACF,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBACpD,CAAC;wBAAS,CAAC;oBACR,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,CAAC;YACJ,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,6DAA6D,GAAG,EAAE;YACzE,IAAI,EAAE,KAAK,IAAI,EAAE;gBACd,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACF,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;oBACpC,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBAChG,gFAAgF;oBAChF,6EAA6E;oBAC7E,6EAA6E;oBAC7E,oEAAoE;oBACpE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,EAAE,mDAAmD,CAAC,CAAC;gBACpG,CAAC;wBAAS,CAAC;oBACR,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,CAAC;YACJ,CAAC;SACH,CAAC,CAAC;QAEH,0EAA0E;QAC1E,oCAAoC;QACpC,MAAM,cAAc,GAAG,4GAA4G,CAAC;QAEpI,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,gEAAgE,GAAG,EAAE;YAC5E,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc;YAC7C,IAAI,EAAE,IAAI;gBACP,CAAC,CAAC,KAAK,IAAI,EAAE;oBACR,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;oBAC/B,IAAI,CAAC;wBACF,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;wBAClC,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;wBAChG,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;wBAC9G,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;wBACzE,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,6EAA6E,CAAC,CAAC;oBACxH,CAAC;4BAAS,CAAC;wBACR,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,CAAC;gBACJ,CAAC;gBACH,CAAC,CAAC,SAAS;SAChB,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,wFAAwF,GAAG,EAAE;YACpG,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc;YAC7C,IAAI,EAAE,IAAI;gBACP,CAAC,CAAC,KAAK,IAAI,EAAE;oBACR,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;oBAC/B,IAAI,CAAC;wBACF,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;wBAClC,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;wBAChG,MAAM,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;wBAChF,MAAM,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;wBAC9G,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,KAAK,MAAM,CAAC,EAAE;4BAC/E,OAAO,EAAE,kCAAkC,KAAK,CAAC,GAAG,qCAAqC;yBAC3F,CAAC,CAAC;wBACH,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBACrD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;wBACjD,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;wBAChD,wDAAwD;wBACxD,8DAA8D;wBAC9D,+DAA+D;wBAC/D,0DAA0D;wBAC1D,MAAM,CAAC,EAAE,CACN,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,KAAK,MAAM,CAAC,EAC7D,kFAAkF,CACpF,CAAC;oBACL,CAAC;4BAAS,CAAC;wBACR,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,CAAC;gBACJ,CAAC;gBACH,CAAC,CAAC,SAAS;SAChB,CAAC,CAAC;IACN,CAAC;IAED,OAAO,MAAM,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,16 @@
9
9
  import type { Harness } from '@hydranium/protocol/testing';
10
10
  import type { ConformanceCheck } from '../conformance-suite.js';
11
11
  import { type LanguageFixture } from '../model.js';
12
+ /**
13
+ * Structural minimum of the `initialize` params the kit sends — only `locale`,
14
+ * which is the one field a check needs to vary.
15
+ *
16
+ * A real `InitializeParams` is assignable to this, so a driver typed against
17
+ * upstream's shape satisfies the port with no adapter.
18
+ */
19
+ export interface LspConformanceInitializeParams {
20
+ readonly locale?: string;
21
+ }
12
22
  /** Structural minimum of an LSP `InitializeResult` — only the baseline capabilities the kit asserts. */
13
23
  export interface LspConformanceInitializeResult {
14
24
  readonly capabilities: {
@@ -41,8 +51,17 @@ export interface LspConformanceDiagnostic {
41
51
  * gives the kit the universal `dispose()` teardown.
42
52
  */
43
53
  export interface LspConformanceDriver extends Harness {
44
- /** Drive the `initialize` → `initialized` handshake; resolve with the (structurally-minimal) result. */
45
- initialize(): Promise<LspConformanceInitializeResult>;
54
+ /**
55
+ * Drive the `initialize` → `initialized` handshake; resolve with the
56
+ * (structurally-minimal) result.
57
+ *
58
+ * `params` is optional and every field in it is too, so a driver that ignores
59
+ * the argument entirely still satisfies this port — which is what keeps
60
+ * adding a field here from being a breaking change. `locale` is the reading
61
+ * user's language, declared by the client because only the client knows it;
62
+ * the render check below is the only caller that passes anything.
63
+ */
64
+ initialize(params?: LspConformanceInitializeParams): Promise<LspConformanceInitializeResult>;
46
65
  /** Send `didOpen` for `uri` with full `text` under `languageId`. */
47
66
  openDocument(uri: string, text: string, languageId: string, version?: number): void;
48
67
  /** Send `didChange` for `uri` as a single full-text replacement at `version`. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAkBlF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,KAAK,eAAe,EAAiC,MAAM,aAAa,CAAC;AAElF,wGAAwG;AACxG,MAAM,WAAW,8BAA8B;IAC5C,QAAQ,CAAC,YAAY,EAAE;QACpB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QACpC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;KACxC,CAAC;CACJ;AAED,gGAAgG;AAChG,MAAM,WAAW,4BAA4B;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACxD;AAQD;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IAClD,wGAAwG;IACxG,UAAU,IAAI,OAAO,CAAC,8BAA8B,CAAC,CAAC;IACtD,oEAAoE;IACpE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpF,iFAAiF;IACjF,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjE,uGAAuG;IACvG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,wBAAwB,EAAE,CAAC,CAAC;IAC/F,8DAA8D;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC9G,6CAA6C;IAC7C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,qBAAqB;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC7E,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,gBAAgB,EAAE,CA2JjF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAkBlF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAyB,KAAK,eAAe,EAAiC,MAAM,aAAa,CAAC;AAEzG;;;;;;GAMG;AACH,MAAM,WAAW,8BAA8B;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wGAAwG;AACxG,MAAM,WAAW,8BAA8B;IAC5C,QAAQ,CAAC,YAAY,EAAE;QACpB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QACpC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;KACxC,CAAC;CACJ;AAED,gGAAgG;AAChG,MAAM,WAAW,4BAA4B;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACxD;AAkBD;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IAClD;;;;;;;;;OASG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,8BAA8B,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC7F,oEAAoE;IACpE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpF,iFAAiF;IACjF,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjE,uGAAuG;IACvG,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,wBAAwB,EAAE,CAAC,CAAC;IAC/F,8DAA8D;IAC9D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAC9G,6CAA6C;IAC7C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,qBAAqB;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC7E,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC/B;AAKD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,gBAAgB,EAAE,CAkNjF"}
package/lib/lsp/index.js CHANGED
@@ -22,10 +22,20 @@
22
22
  */
23
23
  import assert from 'node:assert/strict';
24
24
  import { resolveDeferred, resolveModel } from '../model.js';
25
- /** True when `diagnostic` carries a message in either LSP shape (plain string or markup). */
25
+ /**
26
+ * True when `diagnostic` carries a NON-EMPTY message in either LSP shape
27
+ * (plain string or markup).
28
+ *
29
+ * Emptiness is part of the claim, not a refinement of it: `message: ''` is a
30
+ * diagnostic a user cannot act on, and a type-only test admits it — which
31
+ * makes "every diagnostic carries a message" pass for a head that publishes
32
+ * none. LSP declares the field required without forbidding the empty string,
33
+ * so nothing upstream rules it out either.
34
+ */
26
35
  function hasTextMessage(diagnostic) {
27
36
  const { message } = diagnostic;
28
- return typeof message === 'string' || typeof message?.value === 'string';
37
+ const text = typeof message === 'string' ? message : message?.value;
38
+ return typeof text === 'string' && text.length > 0;
29
39
  }
30
40
  /** Document version sent on the `didChange` of the re-diagnose check (the open is v1). */
31
41
  const CHANGED_VERSION = 2;
@@ -98,7 +108,7 @@ export function buildLspChecks(options) {
98
108
  }
99
109
  });
100
110
  for (const language of options.languages) {
101
- const { valid, invalid, completionPosition } = language;
111
+ const { valid, invalid, completionPosition, renderedDiagnostic } = language;
102
112
  const tag = `[${valid.languageId}]`;
103
113
  checks.push({
104
114
  title: `didOpen(valid) publishes empty diagnostics ${tag}`,
@@ -129,7 +139,7 @@ export function buildLspChecks(options) {
129
139
  driver.openDocument(model.uri, model.text, model.languageId);
130
140
  const published = await diagnostics;
131
141
  assert.ok(published.length >= 1, 'didOpen(invalid) published no diagnostics');
132
- assert.ok(published.every(hasTextMessage), 'a published diagnostic was missing a message');
142
+ assert.ok(published.every(hasTextMessage), 'a published diagnostic was missing a non-empty message');
133
143
  }
134
144
  finally {
135
145
  driver.dispose();
@@ -192,7 +202,72 @@ export function buildLspChecks(options) {
192
202
  skipReason: 'fixture supplied no completionPosition'
193
203
  });
194
204
  }
205
+ // Opt-in: server-side rendering runs only when the fixture names a locale
206
+ // and the sentence it expects in it. The framework ships no catalogue, so
207
+ // a server that renders nothing is CORRECT and must not be failed.
208
+ const renderTitle = `a diagnostic is published rendered in the locale initialize declared ${tag}`;
209
+ const renderControlTitle = `the same diagnostic is NOT rendered when no locale is declared ${tag}`;
210
+ if (renderedDiagnostic) {
211
+ checks.push({
212
+ title: renderTitle,
213
+ body: async () => {
214
+ const published = await publishedMessagesFor(connect, invalid, { locale: renderedDiagnostic.locale });
215
+ assert.ok(published.some(message => message.includes(renderedDiagnostic.expected)), `no published diagnostic contained ${JSON.stringify(renderedDiagnostic.expected)}: ${JSON.stringify(published)}`);
216
+ }
217
+ });
218
+ // The second half of the pair. "Contains X" also passes for a server
219
+ // whose English contains X, and for one that renders whatever the
220
+ // locale — so the discriminating read is the fragment that must
221
+ // disappear. Reported as skipped rather than silently dropped when the
222
+ // fixture omits it, because a lone containment check IS weaker and a
223
+ // reader has to be able to see that from the report.
224
+ if (renderedDiagnostic.absentWithLocale) {
225
+ const { absentWithLocale } = renderedDiagnostic;
226
+ checks.push({
227
+ title: renderControlTitle,
228
+ body: async () => {
229
+ const withLocale = await publishedMessagesFor(connect, invalid, { locale: renderedDiagnostic.locale });
230
+ assert.ok(!withLocale.some(message => message.includes(absentWithLocale)), `a diagnostic still contained ${JSON.stringify(absentWithLocale)} with the locale declared: ${JSON.stringify(withLocale)}`);
231
+ // And present without it, which is what rules out a fragment
232
+ // that never appears in either state — a typo in the fixture
233
+ // would otherwise make the assertion above pass for free.
234
+ const withoutLocale = await publishedMessagesFor(connect, invalid);
235
+ assert.ok(withoutLocale.some(message => message.includes(absentWithLocale)), `no diagnostic contained ${JSON.stringify(absentWithLocale)} with no locale declared, so it cannot witness the render: ${JSON.stringify(withoutLocale)}`);
236
+ }
237
+ });
238
+ }
239
+ else {
240
+ checks.push({
241
+ title: renderControlTitle,
242
+ skipReason: 'fixture supplied no absentWithLocale, so the render check is a containment test only'
243
+ });
244
+ }
245
+ }
246
+ else {
247
+ checks.push({ title: renderTitle, skipReason: 'fixture supplied no renderedDiagnostic (server-side rendering is opt-in)' });
248
+ checks.push({ title: renderControlTitle, skipReason: 'fixture supplied no renderedDiagnostic (server-side rendering is opt-in)' });
249
+ }
195
250
  }
196
251
  return checks;
197
252
  }
253
+ /**
254
+ * Open `model` on a fresh driver and return the messages of the diagnostics
255
+ * published for it, as plain strings.
256
+ *
257
+ * A fresh driver per call because `initialize` is once-only per connection and
258
+ * the locale rides it — so the two states this compares cannot share one.
259
+ */
260
+ async function publishedMessagesFor(connect, model, params) {
261
+ const driver = await connect();
262
+ try {
263
+ await driver.initialize(params);
264
+ const resolved = resolveModel(model);
265
+ const diagnostics = driver.nextDiagnostics(resolved.uri);
266
+ driver.openDocument(resolved.uri, resolved.text, resolved.languageId);
267
+ return (await diagnostics).map(diagnostic => typeof diagnostic.message === 'string' ? diagnostic.message : (diagnostic.message?.value ?? ''));
268
+ }
269
+ finally {
270
+ driver.dispose();
271
+ }
272
+ }
198
273
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lsp/index.ts"],"names":[],"mappings":"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"}
package/lib/model.d.ts CHANGED
@@ -67,6 +67,45 @@ export interface EditSpec {
67
67
  readonly to: Deferred<string>;
68
68
  readonly expect: (root: unknown) => boolean;
69
69
  }
70
+ /**
71
+ * A reference-picker query for an element that does not exist yet, plus the
72
+ * candidate the adopter expects it to offer.
73
+ *
74
+ * **The URI a create-element flow holds is a FOLDER**, because the file is not
75
+ * written until the dialog is confirmed. A folder URI names no file and so
76
+ * carries no extension, which is the one shape a head cannot route to a grammar
77
+ * by URI alone — it has to resolve the language some other way. That makes this
78
+ * the create dialog's load-bearing precondition and the reason the query is
79
+ * worth a conformance check of its own: a head that gets it wrong answers no
80
+ * candidates or throws, and the dialog never opens.
81
+ */
82
+ export interface ReferenceQuerySpec {
83
+ /** AST type of the element being created — the synthetic source's own type. */
84
+ readonly type: string;
85
+ /** The reference property on the source (or on `syntheticPath`'s leaf) whose candidates the picker fills. */
86
+ readonly property: string;
87
+ /**
88
+ * Steps from the synthetic source down to the node holding `property`, when
89
+ * the reference is not on the source itself. Each step is
90
+ * `[containerProperty, type]` — the kit builds the `SyntheticStep`s, so the
91
+ * fixture names no protocol type.
92
+ */
93
+ readonly path?: ReadonlyArray<readonly [containerProperty: string, type: string]>;
94
+ /**
95
+ * Folder the create flow asks at. {@link Deferred} because a fixture may name
96
+ * a workspace the driver's `connect` only just created. Defaults to the parent
97
+ * of `valid.uri`, which is the folder a sibling of the valid model would go
98
+ * into — the common case, so most fixtures supply only `type` + `property`.
99
+ */
100
+ readonly folderUri?: Deferred<string>;
101
+ /**
102
+ * A candidate label the query MUST offer. Without it an empty result passes,
103
+ * and empty is exactly what the defect this check exists for produces — so
104
+ * the expectation is what makes the check discriminating rather than a
105
+ * smoke test.
106
+ */
107
+ readonly expectCandidate: string;
108
+ }
70
109
  /**
71
110
  * The per-language fixture. `valid` and `invalid` are defined once and reused
72
111
  * across heads; the two extras are per-head opt-ins.
@@ -83,6 +122,9 @@ export interface EditSpec {
83
122
  * uses `invalid.text` and never calls `edit.expect`, so an LSP-only adopter
84
123
  * has nothing to supply here.
85
124
  * - `completionPosition` — read by the **LSP slice only**.
125
+ * - `referenceQuery` — read by the **data slice only**, and only when the
126
+ * driver supplies `references` (the reference surface is opt-in on the head
127
+ * too, so both halves have to be present for the check to run).
86
128
  *
87
129
  * Both extras are optional and their checks report *skipped* when absent,
88
130
  * rather than silently not running. Making either mandatory would defeat the
@@ -107,5 +149,67 @@ export interface LanguageFixture {
107
149
  readonly line: number;
108
150
  readonly character: number;
109
151
  };
152
+ /**
153
+ * Optional: the create-dialog reference query. Read by the **data slice
154
+ * only**, and only when the driver exposes the opt-in reference surface.
155
+ */
156
+ readonly referenceQuery?: ReferenceQuerySpec;
157
+ /**
158
+ * Optional: a second document that REFERENCES {@link valid}, so the data
159
+ * slice can provoke a CASCADE — a rebuild of this document caused by
160
+ * editing the one it points at, with its own text never touched.
161
+ *
162
+ * Opt-in because a grammar need not have cross-document references at all,
163
+ * and because only the adopter knows which pair of documents forms one.
164
+ * Supplying it IS the claim that editing `valid` rebuilds this document; the
165
+ * check then holds the head to reporting that on `onDocumentsBuilt`, which
166
+ * is the only channel that can carry it — the document has no subscriber and
167
+ * its file did not change, so neither the update channel nor a filesystem
168
+ * watcher can.
169
+ */
170
+ readonly dependent?: ConformanceModel;
171
+ /**
172
+ * Optional: a locale plus the sentence the server must publish in it. Read
173
+ * by the **LSP slice only**.
174
+ */
175
+ readonly renderedDiagnostic?: RenderedDiagnosticSpec;
176
+ }
177
+ /**
178
+ * A locale, and one sentence the server must produce in it for the `invalid`
179
+ * fixture.
180
+ *
181
+ * **Opt-in, and it has to be.** The framework ships no catalogue and selects no
182
+ * locale, so a server that installs no renderer correctly publishes English —
183
+ * mandating this check would fail every adopter without i18n for doing the right
184
+ * thing. Supplying the field is the adopter saying "I render server-side, hold me
185
+ * to it".
186
+ *
187
+ * `expected` is a SUBSTRING, not the whole message. The kit owns no grammar, so
188
+ * it cannot know how many diagnostics `invalid` produces or in what order, and
189
+ * an adopter should be able to pin the translated fragment without restating a
190
+ * sentence they may reword. A substring long enough to be wrong if the render
191
+ * did not happen is the whole requirement.
192
+ *
193
+ * `absentWithoutLocale` is what makes the check a pair rather than a single
194
+ * assertion: "the message contains X" also passes for a server whose English
195
+ * happens to contain X, and for one that renders regardless of locale. Naming
196
+ * the fragment that must DISAPPEAR when no locale is declared is what
197
+ * distinguishes those.
198
+ */
199
+ export interface RenderedDiagnosticSpec {
200
+ /** The locale to declare at `initialize` — the tag whose catalogue the server has. */
201
+ readonly locale: string;
202
+ /** A fragment of the translated sentence, present in some diagnostic of the `invalid` fixture. */
203
+ readonly expected: string;
204
+ /**
205
+ * A fragment that must be absent once `locale` is declared, and present
206
+ * without it — normally a piece of the server's own English.
207
+ *
208
+ * Optional only because a catalogue may translate a message whose English
209
+ * shares no distinctive fragment with it. Omitting it drops the second half
210
+ * of the pair and leaves a check that a render-nothing server can pass; the
211
+ * kit reports that rather than pretending otherwise.
212
+ */
213
+ readonly absentWithLocale?: string;
110
214
  }
111
215
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC9B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,iFAAiF;AACjF,MAAM,WAAW,wBAAwB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACxB;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,wBAAwB,CAM9E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACtB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,eAAe;IAC7B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,kFAAkF;IAClF,QAAQ,CAAC,kBAAkB,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CACtF"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC9B,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,iFAAiF;AACjF,MAAM,WAAW,wBAAwB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACxB;AAED,8CAA8C;AAC9C,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAExD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,gBAAgB,GAAG,wBAAwB,CAM9E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACtB,gGAAgG;IAChG,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;CAC9C;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6GAA6G;IAC7G,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClF;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,eAAe;IAC7B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,kFAAkF;IAClF,QAAQ,CAAC,kBAAkB,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACpF;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAC7C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,sBAAsB;IACpC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;;;OAQG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACrC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/conformance",
3
- "version": "1.0.0-next.7",
3
+ "version": "1.0.0-next.70",
4
4
  "description": "Protocol conformance kit (TCK) for hydranium adopters. Per-head slices (/data, /lsp, /glsp) of fixture-parameterized, protocol-only smoke checks an adopter runs against its own server.",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -88,7 +88,7 @@
88
88
  "watch": "tsc -b -w --preserveWatchOutput"
89
89
  },
90
90
  "devDependencies": {
91
- "@hydranium/protocol": "1.0.0-next.7",
91
+ "@hydranium/protocol": "1.0.0-next.70",
92
92
  "@jest/globals": "^29.7.0",
93
93
  "@types/jest": "^29.5.12",
94
94
  "jest": "^29.7.0",
@@ -98,7 +98,7 @@
98
98
  "vitest": "^4.0.0"
99
99
  },
100
100
  "peerDependencies": {
101
- "@hydranium/protocol": "1.0.0-next.7",
101
+ "@hydranium/protocol": "1.0.0-next.70",
102
102
  "@jest/globals": "^29.0.0",
103
103
  "vitest": "^4.0.0"
104
104
  },
package/src/data/index.ts CHANGED
@@ -10,24 +10,29 @@
10
10
  /**
11
11
  * The `@hydranium/conformance/data` slice — protocol conformance for the
12
12
  * data-server head. The driver port IS the protocol-native
13
- * {@link DataServerProtocol} proxy (plus the captured `onDocumentUpdated`
14
- * events), so no upstream wire-lib dep enters the kit and `DataServerHarness`
15
- * satisfies the port structurally with no adapter.
13
+ * {@link DataServerProtocol} proxy (plus the captured client notifications),
14
+ * so no upstream wire-lib dep enters the kit and `DataServerHarness` satisfies
15
+ * the port structurally with no adapter.
16
16
  */
17
17
 
18
18
  import assert from 'node:assert/strict';
19
- import { TransferDocument, type TransferDiagnostic, type TransferElement } from '@hydranium/protocol';
20
- import type { DataServerProtocol, TransferDocumentUpdatedEvent } from '@hydranium/protocol/data';
19
+ import { ReferenceSource, SyntheticStep, TransferDocument, type TransferDiagnostic, type TransferElement } from '@hydranium/protocol';
20
+ import type {
21
+ DataServerProtocol,
22
+ ReferenceServerProtocol,
23
+ TransferDocumentsBuiltEvent,
24
+ TransferDocumentUpdatedEvent
25
+ } from '@hydranium/protocol/data';
21
26
  import { type Harness, waitFor } from '@hydranium/protocol/testing';
22
27
  import type { ConformanceCheck } from '../conformance-suite.js';
23
28
  import { type LanguageFixture, resolveDeferred, resolveModel } from '../model.js';
24
29
 
25
30
  /**
26
31
  * The data-server driver port — a live, connected, READY data-server exposed
27
- * through its protocol-native proxy plus the captured client-side update
28
- * events. The kit names only `@hydranium/protocol` types, so a
32
+ * through its protocol-native proxy plus the captured client-side
33
+ * notifications. The kit names only `@hydranium/protocol` types, so a
29
34
  * `DataServerHarness` satisfies the port structurally (it has `proxy` +
30
- * `events` + `dispose`) with NO adapter. `extends Harness` gives the kit the
35
+ * `events`, `builds` and `dispose`) with NO adapter. `extends Harness` gives the kit the
31
36
  * universal `dispose()` teardown.
32
37
  *
33
38
  * The kit seeds documents purely through the proxy: `updateModelDocument` is
@@ -43,6 +48,17 @@ export interface DataConformanceDriver<
43
48
  readonly proxy: DataServerProtocol<TTransfer, TDiagnostic>;
44
49
  /** Captured `onDocumentUpdated` events, append order — the subscription check's observation target. */
45
50
  readonly events: ReadonlyArray<TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>>;
51
+ /** Captured `onDocumentsBuilt` events, append order — the cascade check's observation target. */
52
+ readonly builds: ReadonlyArray<TransferDocumentsBuiltEvent>;
53
+ /**
54
+ * The opt-in reference surface, when the head serves it.
55
+ *
56
+ * Separate from {@link proxy} because `ReferenceServerProtocol` is NOT part
57
+ * of `DataServerProtocol` — a head may serve documents and no references at
58
+ * all. Absent means the reference check reports skipped with a named reason
59
+ * rather than failing a head that never claimed the surface.
60
+ */
61
+ readonly references?: ReferenceServerProtocol<TTransfer>;
46
62
  }
47
63
 
48
64
  /** Options for `runDataConformance`. */
@@ -91,7 +107,7 @@ const SEEDER = 'conformance-seeder';
91
107
  * unit tests; adopters call `runDataConformance`.
92
108
  *
93
109
  * `LanguageFixture.edit` is read HERE and nowhere else in the kit, and is
94
- * optional: its two checks report skipped when it is absent. See
110
+ * optional: every check that needs one reports skipped when it is absent. See
95
111
  * {@link LanguageFixture} for which slice reads which field.
96
112
  */
97
113
  export function buildDataChecks<TTransfer extends TransferElement, TDiagnostic extends TransferDiagnostic = TransferDiagnostic>(
@@ -178,7 +194,7 @@ export function buildDataChecks<TTransfer extends TransferElement, TDiagnostic e
178
194
  });
179
195
 
180
196
  for (const language of options.languages) {
181
- const { valid, invalid, edit } = language;
197
+ const { valid, invalid, edit, dependent } = language;
182
198
  const tag = `[${valid.languageId}]`;
183
199
 
184
200
  checks.push({
@@ -237,6 +253,101 @@ export function buildDataChecks<TTransfer extends TransferElement, TDiagnostic e
237
253
  }
238
254
  });
239
255
 
256
+ checks.push({
257
+ title: `a diagnostic carrying a framework message code also carries its params ${tag}`,
258
+ body: async () => {
259
+ const driver = await connect();
260
+ try {
261
+ const model = resolveModel(invalid);
262
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: model.text });
263
+ const document = await driver.proxy.getModelDocument({ uri: model.uri, includeDiagnostics: true });
264
+
265
+ // Conditional rather than fixture-driven, and deliberately so: what
266
+ // an `invalid` fixture provokes is the adopter's choice, and a
267
+ // syntactic error legitimately carries no identity at all. The
268
+ // invariant is that the identity travels WHOLE or not — a `code`
269
+ // without `params` is the half-state that renders a translated
270
+ // template with its placeholders left standing, and it is
271
+ // reachable only by overriding `toTransferDiagnostic`.
272
+ const halfIdentities = document.diagnostics.filter(
273
+ diagnostic =>
274
+ typeof diagnostic.code === 'string' && diagnostic.code.startsWith('hydranium/') && diagnostic.params === undefined
275
+ );
276
+ assert.deepStrictEqual(
277
+ halfIdentities.map(diagnostic => diagnostic.code),
278
+ [],
279
+ 'diagnostics carry a framework message code with no params, so a translating surface cannot render them'
280
+ );
281
+ } finally {
282
+ driver.dispose();
283
+ }
284
+ }
285
+ });
286
+
287
+ // The create-dialog query, and the reason it is its own check: it is the
288
+ // only request a head receives whose URI names no file. Everything else
289
+ // in this battery addresses a document, so a head that routes purely by
290
+ // URI extension passes all of them and still cannot open a create dialog.
291
+ //
292
+ // Doubly opt-in — the fixture must name a query AND the driver must serve
293
+ // the reference surface — because either half missing means the head never
294
+ // claimed this behaviour. The reasons are reported separately so a skip
295
+ // says which half is absent.
296
+ const referenceQuery = language.referenceQuery;
297
+ const referenceSkipReason = !referenceQuery
298
+ ? 'fixture supplies no `referenceQuery` (omit it if this language has no create-element dialog)'
299
+ : undefined;
300
+
301
+ checks.push({
302
+ title: `findReferenceCandidates answers for a synthetic source at a folder URI ${tag}`,
303
+ skipReason: referenceSkipReason,
304
+ body: referenceQuery
305
+ ? async () => {
306
+ const driver = await connect();
307
+ try {
308
+ if (!driver.references) {
309
+ // Checked here rather than in `skipReason`: the driver only
310
+ // exists once `connect` has run, and skip reasons are
311
+ // computed while the battery is being planned.
312
+ return;
313
+ }
314
+ const model = resolveModel(valid);
315
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: model.text });
316
+
317
+ // Default to the folder holding the valid model: a sibling of
318
+ // it is where a create flow would put the new file.
319
+ const folderUri = referenceQuery.folderUri
320
+ ? resolveDeferred(referenceQuery.folderUri)
321
+ : model.uri.slice(0, model.uri.lastIndexOf('/'));
322
+ assert.ok(
323
+ folderUri.length > 0 && folderUri !== model.uri,
324
+ `could not derive a folder URI from ${model.uri}; supply referenceQuery.folderUri`
325
+ );
326
+
327
+ const candidates = await driver.references.findReferenceCandidates({
328
+ source: ReferenceSource.synthetic(folderUri, referenceQuery.type),
329
+ syntheticPath: referenceQuery.path?.map(([containerProperty, type]) => SyntheticStep.of(containerProperty, type)),
330
+ property: referenceQuery.property
331
+ });
332
+
333
+ // The expected label, not merely a non-empty array: the defect
334
+ // this guards against answers `[]`, and an empty result is
335
+ // also what a head with a genuinely empty index answers, so
336
+ // only a named candidate tells the two apart.
337
+ const labels = candidates.map(candidate => candidate.label);
338
+ assert.ok(
339
+ labels.includes(referenceQuery.expectCandidate),
340
+ `findReferenceCandidates at the folder ${folderUri} did not offer ${JSON.stringify(
341
+ referenceQuery.expectCandidate
342
+ )}; got [${labels.join(', ')}]`
343
+ );
344
+ } finally {
345
+ driver.dispose();
346
+ }
347
+ }
348
+ : undefined
349
+ });
350
+
240
351
  // Opt-in: both remaining checks need a second, observably different model
241
352
  // text, which only `edit` supplies.
242
353
  const editSkipReason = 'fixture supplies no `edit` (data-slice only; omit it if this language is not driven through the data head)';
@@ -260,6 +371,50 @@ export function buildDataChecks<TTransfer extends TransferElement, TDiagnostic e
260
371
  : undefined
261
372
  });
262
373
 
374
+ // Opt-in twice over: the cascade needs an edit to provoke it AND a second
375
+ // document that references the first to be provoked.
376
+ const cascadeSkipReason =
377
+ 'fixture supplies no `dependent` (a document referencing `valid`), so no cascade can be provoked over the protocol';
378
+
379
+ checks.push({
380
+ title: `editing a document reports its unwatched dependent as built ${tag}`,
381
+ skipReason: edit && dependent ? undefined : dependent ? editSkipReason : cascadeSkipReason,
382
+ body:
383
+ edit && dependent
384
+ ? async () => {
385
+ const driver = await connect();
386
+ try {
387
+ const model = resolveModel(valid);
388
+ const other = resolveModel(dependent);
389
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: SEEDER, model: model.text });
390
+ await driver.proxy.updateModelDocument({ uri: other.uri, clientId: SEEDER, model: other.text });
391
+ // Watch ONLY the referenced document. The dependent is left
392
+ // unwatched on purpose: that is the state in which no other
393
+ // channel can report it, and the state a workspace view is in
394
+ // for every document it displays without opening.
395
+ await driver.proxy.watchModelDocument({ uri: model.uri, clientId: SUBSCRIBER });
396
+ const before = driver.builds.length;
397
+
398
+ await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: resolveDeferred(edit.to) });
399
+
400
+ await waitFor(() => driver.builds.slice(before).some(event => event.uris.includes(other.uri)), {
401
+ message: `no onDocumentsBuilt event named ${other.uri} after editing the document it references`
402
+ });
403
+ const reported = driver.builds.slice(before).flatMap(event => [...event.uris]);
404
+ // The watched document is excluded: its watcher already heard
405
+ // about it on the update channel, and repeating it here would
406
+ // be the bandwidth the per-URI gate exists to avoid.
407
+ assert.ok(
408
+ !reported.includes(model.uri),
409
+ `onDocumentsBuilt named the WATCHED ${model.uri}; it is reported on the update channel instead`
410
+ );
411
+ } finally {
412
+ driver.dispose();
413
+ }
414
+ }
415
+ : undefined
416
+ });
417
+
263
418
  checks.push({
264
419
  title: `subscribe + update delivers an onDocumentUpdated event with the originating clientId ${tag}`,
265
420
  skipReason: edit ? undefined : editSkipReason,
package/src/lsp/index.ts CHANGED
@@ -25,7 +25,18 @@
25
25
  import assert from 'node:assert/strict';
26
26
  import type { Harness } from '@hydranium/protocol/testing';
27
27
  import type { ConformanceCheck } from '../conformance-suite.js';
28
- import { type LanguageFixture, resolveDeferred, resolveModel } from '../model.js';
28
+ import { type ConformanceModel, type LanguageFixture, resolveDeferred, resolveModel } from '../model.js';
29
+
30
+ /**
31
+ * Structural minimum of the `initialize` params the kit sends — only `locale`,
32
+ * which is the one field a check needs to vary.
33
+ *
34
+ * A real `InitializeParams` is assignable to this, so a driver typed against
35
+ * upstream's shape satisfies the port with no adapter.
36
+ */
37
+ export interface LspConformanceInitializeParams {
38
+ readonly locale?: string;
39
+ }
29
40
 
30
41
  /** Structural minimum of an LSP `InitializeResult` — only the baseline capabilities the kit asserts. */
31
42
  export interface LspConformanceInitializeResult {
@@ -51,10 +62,20 @@ export interface LspConformanceDiagnostic {
51
62
  readonly message: string | { readonly value: string };
52
63
  }
53
64
 
54
- /** True when `diagnostic` carries a message in either LSP shape (plain string or markup). */
65
+ /**
66
+ * True when `diagnostic` carries a NON-EMPTY message in either LSP shape
67
+ * (plain string or markup).
68
+ *
69
+ * Emptiness is part of the claim, not a refinement of it: `message: ''` is a
70
+ * diagnostic a user cannot act on, and a type-only test admits it — which
71
+ * makes "every diagnostic carries a message" pass for a head that publishes
72
+ * none. LSP declares the field required without forbidding the empty string,
73
+ * so nothing upstream rules it out either.
74
+ */
55
75
  function hasTextMessage(diagnostic: LspConformanceDiagnostic): boolean {
56
76
  const { message } = diagnostic;
57
- return typeof message === 'string' || typeof message?.value === 'string';
77
+ const text = typeof message === 'string' ? message : message?.value;
78
+ return typeof text === 'string' && text.length > 0;
58
79
  }
59
80
 
60
81
  /**
@@ -66,8 +87,17 @@ function hasTextMessage(diagnostic: LspConformanceDiagnostic): boolean {
66
87
  * gives the kit the universal `dispose()` teardown.
67
88
  */
68
89
  export interface LspConformanceDriver extends Harness {
69
- /** Drive the `initialize` → `initialized` handshake; resolve with the (structurally-minimal) result. */
70
- initialize(): Promise<LspConformanceInitializeResult>;
90
+ /**
91
+ * Drive the `initialize` → `initialized` handshake; resolve with the
92
+ * (structurally-minimal) result.
93
+ *
94
+ * `params` is optional and every field in it is too, so a driver that ignores
95
+ * the argument entirely still satisfies this port — which is what keeps
96
+ * adding a field here from being a breaking change. `locale` is the reading
97
+ * user's language, declared by the client because only the client knows it;
98
+ * the render check below is the only caller that passes anything.
99
+ */
100
+ initialize(params?: LspConformanceInitializeParams): Promise<LspConformanceInitializeResult>;
71
101
  /** Send `didOpen` for `uri` with full `text` under `languageId`. */
72
102
  openDocument(uri: string, text: string, languageId: string, version?: number): void;
73
103
  /** Send `didChange` for `uri` as a single full-text replacement at `version`. */
@@ -167,7 +197,7 @@ export function buildLspChecks(options: LspConformanceOptions): ConformanceCheck
167
197
  });
168
198
 
169
199
  for (const language of options.languages) {
170
- const { valid, invalid, completionPosition } = language;
200
+ const { valid, invalid, completionPosition, renderedDiagnostic } = language;
171
201
  const tag = `[${valid.languageId}]`;
172
202
 
173
203
  checks.push({
@@ -199,7 +229,7 @@ export function buildLspChecks(options: LspConformanceOptions): ConformanceCheck
199
229
  driver.openDocument(model.uri, model.text, model.languageId);
200
230
  const published = await diagnostics;
201
231
  assert.ok(published.length >= 1, 'didOpen(invalid) published no diagnostics');
202
- assert.ok(published.every(hasTextMessage), 'a published diagnostic was missing a message');
232
+ assert.ok(published.every(hasTextMessage), 'a published diagnostic was missing a non-empty message');
203
233
  } finally {
204
234
  driver.dispose();
205
235
  }
@@ -263,7 +293,88 @@ export function buildLspChecks(options: LspConformanceOptions): ConformanceCheck
263
293
  skipReason: 'fixture supplied no completionPosition'
264
294
  });
265
295
  }
296
+
297
+ // Opt-in: server-side rendering runs only when the fixture names a locale
298
+ // and the sentence it expects in it. The framework ships no catalogue, so
299
+ // a server that renders nothing is CORRECT and must not be failed.
300
+ const renderTitle = `a diagnostic is published rendered in the locale initialize declared ${tag}`;
301
+ const renderControlTitle = `the same diagnostic is NOT rendered when no locale is declared ${tag}`;
302
+ if (renderedDiagnostic) {
303
+ checks.push({
304
+ title: renderTitle,
305
+ body: async () => {
306
+ const published = await publishedMessagesFor(connect, invalid, { locale: renderedDiagnostic.locale });
307
+ assert.ok(
308
+ published.some(message => message.includes(renderedDiagnostic.expected)),
309
+ `no published diagnostic contained ${JSON.stringify(renderedDiagnostic.expected)}: ${JSON.stringify(published)}`
310
+ );
311
+ }
312
+ });
313
+
314
+ // The second half of the pair. "Contains X" also passes for a server
315
+ // whose English contains X, and for one that renders whatever the
316
+ // locale — so the discriminating read is the fragment that must
317
+ // disappear. Reported as skipped rather than silently dropped when the
318
+ // fixture omits it, because a lone containment check IS weaker and a
319
+ // reader has to be able to see that from the report.
320
+ if (renderedDiagnostic.absentWithLocale) {
321
+ const { absentWithLocale } = renderedDiagnostic;
322
+ checks.push({
323
+ title: renderControlTitle,
324
+ body: async () => {
325
+ const withLocale = await publishedMessagesFor(connect, invalid, { locale: renderedDiagnostic.locale });
326
+ assert.ok(
327
+ !withLocale.some(message => message.includes(absentWithLocale)),
328
+ `a diagnostic still contained ${JSON.stringify(absentWithLocale)} with the locale declared: ${JSON.stringify(withLocale)}`
329
+ );
330
+
331
+ // And present without it, which is what rules out a fragment
332
+ // that never appears in either state — a typo in the fixture
333
+ // would otherwise make the assertion above pass for free.
334
+ const withoutLocale = await publishedMessagesFor(connect, invalid);
335
+ assert.ok(
336
+ withoutLocale.some(message => message.includes(absentWithLocale)),
337
+ `no diagnostic contained ${JSON.stringify(absentWithLocale)} with no locale declared, so it cannot witness the render: ${JSON.stringify(withoutLocale)}`
338
+ );
339
+ }
340
+ });
341
+ } else {
342
+ checks.push({
343
+ title: renderControlTitle,
344
+ skipReason: 'fixture supplied no absentWithLocale, so the render check is a containment test only'
345
+ });
346
+ }
347
+ } else {
348
+ checks.push({ title: renderTitle, skipReason: 'fixture supplied no renderedDiagnostic (server-side rendering is opt-in)' });
349
+ checks.push({ title: renderControlTitle, skipReason: 'fixture supplied no renderedDiagnostic (server-side rendering is opt-in)' });
350
+ }
266
351
  }
267
352
 
268
353
  return checks;
269
354
  }
355
+
356
+ /**
357
+ * Open `model` on a fresh driver and return the messages of the diagnostics
358
+ * published for it, as plain strings.
359
+ *
360
+ * A fresh driver per call because `initialize` is once-only per connection and
361
+ * the locale rides it — so the two states this compares cannot share one.
362
+ */
363
+ async function publishedMessagesFor(
364
+ connect: LspConformanceOptions['connect'],
365
+ model: ConformanceModel,
366
+ params?: LspConformanceInitializeParams
367
+ ): Promise<string[]> {
368
+ const driver = await connect();
369
+ try {
370
+ await driver.initialize(params);
371
+ const resolved = resolveModel(model);
372
+ const diagnostics = driver.nextDiagnostics(resolved.uri);
373
+ driver.openDocument(resolved.uri, resolved.text, resolved.languageId);
374
+ return (await diagnostics).map(diagnostic =>
375
+ typeof diagnostic.message === 'string' ? diagnostic.message : (diagnostic.message?.value ?? '')
376
+ );
377
+ } finally {
378
+ driver.dispose();
379
+ }
380
+ }
package/src/model.ts CHANGED
@@ -82,6 +82,46 @@ export interface EditSpec {
82
82
  readonly expect: (root: unknown) => boolean;
83
83
  }
84
84
 
85
+ /**
86
+ * A reference-picker query for an element that does not exist yet, plus the
87
+ * candidate the adopter expects it to offer.
88
+ *
89
+ * **The URI a create-element flow holds is a FOLDER**, because the file is not
90
+ * written until the dialog is confirmed. A folder URI names no file and so
91
+ * carries no extension, which is the one shape a head cannot route to a grammar
92
+ * by URI alone — it has to resolve the language some other way. That makes this
93
+ * the create dialog's load-bearing precondition and the reason the query is
94
+ * worth a conformance check of its own: a head that gets it wrong answers no
95
+ * candidates or throws, and the dialog never opens.
96
+ */
97
+ export interface ReferenceQuerySpec {
98
+ /** AST type of the element being created — the synthetic source's own type. */
99
+ readonly type: string;
100
+ /** The reference property on the source (or on `syntheticPath`'s leaf) whose candidates the picker fills. */
101
+ readonly property: string;
102
+ /**
103
+ * Steps from the synthetic source down to the node holding `property`, when
104
+ * the reference is not on the source itself. Each step is
105
+ * `[containerProperty, type]` — the kit builds the `SyntheticStep`s, so the
106
+ * fixture names no protocol type.
107
+ */
108
+ readonly path?: ReadonlyArray<readonly [containerProperty: string, type: string]>;
109
+ /**
110
+ * Folder the create flow asks at. {@link Deferred} because a fixture may name
111
+ * a workspace the driver's `connect` only just created. Defaults to the parent
112
+ * of `valid.uri`, which is the folder a sibling of the valid model would go
113
+ * into — the common case, so most fixtures supply only `type` + `property`.
114
+ */
115
+ readonly folderUri?: Deferred<string>;
116
+ /**
117
+ * A candidate label the query MUST offer. Without it an empty result passes,
118
+ * and empty is exactly what the defect this check exists for produces — so
119
+ * the expectation is what makes the check discriminating rather than a
120
+ * smoke test.
121
+ */
122
+ readonly expectCandidate: string;
123
+ }
124
+
85
125
  /**
86
126
  * The per-language fixture. `valid` and `invalid` are defined once and reused
87
127
  * across heads; the two extras are per-head opt-ins.
@@ -98,6 +138,9 @@ export interface EditSpec {
98
138
  * uses `invalid.text` and never calls `edit.expect`, so an LSP-only adopter
99
139
  * has nothing to supply here.
100
140
  * - `completionPosition` — read by the **LSP slice only**.
141
+ * - `referenceQuery` — read by the **data slice only**, and only when the
142
+ * driver supplies `references` (the reference surface is opt-in on the head
143
+ * too, so both halves have to be present for the check to run).
101
144
  *
102
145
  * Both extras are optional and their checks report *skipped* when absent,
103
146
  * rather than silently not running. Making either mandatory would defeat the
@@ -119,4 +162,67 @@ export interface LanguageFixture {
119
162
  readonly edit?: EditSpec;
120
163
  /** Optional: a position at which the LSP completion check requests completion. */
121
164
  readonly completionPosition?: { readonly line: number; readonly character: number };
165
+ /**
166
+ * Optional: the create-dialog reference query. Read by the **data slice
167
+ * only**, and only when the driver exposes the opt-in reference surface.
168
+ */
169
+ readonly referenceQuery?: ReferenceQuerySpec;
170
+ /**
171
+ * Optional: a second document that REFERENCES {@link valid}, so the data
172
+ * slice can provoke a CASCADE — a rebuild of this document caused by
173
+ * editing the one it points at, with its own text never touched.
174
+ *
175
+ * Opt-in because a grammar need not have cross-document references at all,
176
+ * and because only the adopter knows which pair of documents forms one.
177
+ * Supplying it IS the claim that editing `valid` rebuilds this document; the
178
+ * check then holds the head to reporting that on `onDocumentsBuilt`, which
179
+ * is the only channel that can carry it — the document has no subscriber and
180
+ * its file did not change, so neither the update channel nor a filesystem
181
+ * watcher can.
182
+ */
183
+ readonly dependent?: ConformanceModel;
184
+ /**
185
+ * Optional: a locale plus the sentence the server must publish in it. Read
186
+ * by the **LSP slice only**.
187
+ */
188
+ readonly renderedDiagnostic?: RenderedDiagnosticSpec;
189
+ }
190
+
191
+ /**
192
+ * A locale, and one sentence the server must produce in it for the `invalid`
193
+ * fixture.
194
+ *
195
+ * **Opt-in, and it has to be.** The framework ships no catalogue and selects no
196
+ * locale, so a server that installs no renderer correctly publishes English —
197
+ * mandating this check would fail every adopter without i18n for doing the right
198
+ * thing. Supplying the field is the adopter saying "I render server-side, hold me
199
+ * to it".
200
+ *
201
+ * `expected` is a SUBSTRING, not the whole message. The kit owns no grammar, so
202
+ * it cannot know how many diagnostics `invalid` produces or in what order, and
203
+ * an adopter should be able to pin the translated fragment without restating a
204
+ * sentence they may reword. A substring long enough to be wrong if the render
205
+ * did not happen is the whole requirement.
206
+ *
207
+ * `absentWithoutLocale` is what makes the check a pair rather than a single
208
+ * assertion: "the message contains X" also passes for a server whose English
209
+ * happens to contain X, and for one that renders regardless of locale. Naming
210
+ * the fragment that must DISAPPEAR when no locale is declared is what
211
+ * distinguishes those.
212
+ */
213
+ export interface RenderedDiagnosticSpec {
214
+ /** The locale to declare at `initialize` — the tag whose catalogue the server has. */
215
+ readonly locale: string;
216
+ /** A fragment of the translated sentence, present in some diagnostic of the `invalid` fixture. */
217
+ readonly expected: string;
218
+ /**
219
+ * A fragment that must be absent once `locale` is declared, and present
220
+ * without it — normally a piece of the server's own English.
221
+ *
222
+ * Optional only because a catalogue may translate a message whose English
223
+ * shares no distinctive fragment with it. Omitting it drops the second half
224
+ * of the pair and leaves a check that a render-nothing server can pass; the
225
+ * kit reports that rather than pretending otherwise.
226
+ */
227
+ readonly absentWithLocale?: string;
122
228
  }