@hydranium/conformance 1.0.0-next.31 → 1.0.0-next.32

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
 
@@ -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;AAkBD;;;;;;;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
@@ -108,7 +108,7 @@ export function buildLspChecks(options) {
108
108
  }
109
109
  });
110
110
  for (const language of options.languages) {
111
- const { valid, invalid, completionPosition } = language;
111
+ const { valid, invalid, completionPosition, renderedDiagnostic } = language;
112
112
  const tag = `[${valid.languageId}]`;
113
113
  checks.push({
114
114
  title: `didOpen(valid) publishes empty diagnostics ${tag}`,
@@ -202,7 +202,72 @@ export function buildLspChecks(options) {
202
202
  skipReason: 'fixture supplied no completionPosition'
203
203
  });
204
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
+ }
205
250
  }
206
251
  return checks;
207
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
+ }
208
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
@@ -154,5 +154,48 @@ export interface LanguageFixture {
154
154
  * only**, and only when the driver exposes the opt-in reference surface.
155
155
  */
156
156
  readonly referenceQuery?: ReferenceQuerySpec;
157
+ /**
158
+ * Optional: a locale plus the sentence the server must publish in it. Read
159
+ * by the **LSP slice only**.
160
+ */
161
+ readonly renderedDiagnostic?: RenderedDiagnosticSpec;
162
+ }
163
+ /**
164
+ * A locale, and one sentence the server must produce in it for the `invalid`
165
+ * fixture.
166
+ *
167
+ * **Opt-in, and it has to be.** The framework ships no catalogue and selects no
168
+ * locale, so a server that installs no renderer correctly publishes English —
169
+ * mandating this check would fail every adopter without i18n for doing the right
170
+ * thing. Supplying the field is the adopter saying "I render server-side, hold me
171
+ * to it".
172
+ *
173
+ * `expected` is a SUBSTRING, not the whole message. The kit owns no grammar, so
174
+ * it cannot know how many diagnostics `invalid` produces or in what order, and
175
+ * an adopter should be able to pin the translated fragment without restating a
176
+ * sentence they may reword. A substring long enough to be wrong if the render
177
+ * did not happen is the whole requirement.
178
+ *
179
+ * `absentWithoutLocale` is what makes the check a pair rather than a single
180
+ * assertion: "the message contains X" also passes for a server whose English
181
+ * happens to contain X, and for one that renders regardless of locale. Naming
182
+ * the fragment that must DISAPPEAR when no locale is declared is what
183
+ * distinguishes those.
184
+ */
185
+ export interface RenderedDiagnosticSpec {
186
+ /** The locale to declare at `initialize` — the tag whose catalogue the server has. */
187
+ readonly locale: string;
188
+ /** A fragment of the translated sentence, present in some diagnostic of the `invalid` fixture. */
189
+ readonly expected: string;
190
+ /**
191
+ * A fragment that must be absent once `locale` is declared, and present
192
+ * without it — normally a piece of the server's own English.
193
+ *
194
+ * Optional only because a catalogue may translate a message whose English
195
+ * shares no distinctive fragment with it. Omitting it drops the second half
196
+ * of the pair and leaves a check that a render-nothing server can pass; the
197
+ * kit reports that rather than pretending otherwise.
198
+ */
199
+ readonly absentWithLocale?: string;
157
200
  }
158
201
  //# 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;;;;;;;;;;;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;CAC/C"}
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;;;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.31",
3
+ "version": "1.0.0-next.32",
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.31",
91
+ "@hydranium/protocol": "1.0.0-next.32",
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.31",
101
+ "@hydranium/protocol": "1.0.0-next.32",
102
102
  "@jest/globals": "^29.0.0",
103
103
  "vitest": "^4.0.0"
104
104
  },
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 {
@@ -76,8 +87,17 @@ function hasTextMessage(diagnostic: LspConformanceDiagnostic): boolean {
76
87
  * gives the kit the universal `dispose()` teardown.
77
88
  */
78
89
  export interface LspConformanceDriver extends Harness {
79
- /** Drive the `initialize` → `initialized` handshake; resolve with the (structurally-minimal) result. */
80
- 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>;
81
101
  /** Send `didOpen` for `uri` with full `text` under `languageId`. */
82
102
  openDocument(uri: string, text: string, languageId: string, version?: number): void;
83
103
  /** Send `didChange` for `uri` as a single full-text replacement at `version`. */
@@ -177,7 +197,7 @@ export function buildLspChecks(options: LspConformanceOptions): ConformanceCheck
177
197
  });
178
198
 
179
199
  for (const language of options.languages) {
180
- const { valid, invalid, completionPosition } = language;
200
+ const { valid, invalid, completionPosition, renderedDiagnostic } = language;
181
201
  const tag = `[${valid.languageId}]`;
182
202
 
183
203
  checks.push({
@@ -273,7 +293,88 @@ export function buildLspChecks(options: LspConformanceOptions): ConformanceCheck
273
293
  skipReason: 'fixture supplied no completionPosition'
274
294
  });
275
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
+ }
276
351
  }
277
352
 
278
353
  return checks;
279
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
@@ -167,4 +167,48 @@ export interface LanguageFixture {
167
167
  * only**, and only when the driver exposes the opt-in reference surface.
168
168
  */
169
169
  readonly referenceQuery?: ReferenceQuerySpec;
170
+ /**
171
+ * Optional: a locale plus the sentence the server must publish in it. Read
172
+ * by the **LSP slice only**.
173
+ */
174
+ readonly renderedDiagnostic?: RenderedDiagnosticSpec;
175
+ }
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;
170
214
  }