@hydranium/conformance 1.0.0-next.28 → 1.0.0-next.29
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/lib/data/index.d.ts +10 -1
- package/lib/data/index.d.ts.map +1 -1
- package/lib/data/index.js +53 -1
- package/lib/data/index.js.map +1 -1
- package/lib/model.d.ts +47 -0
- package/lib/model.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/data/index.ts +75 -2
- package/src/model.ts +48 -0
package/lib/data/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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, 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';
|
|
@@ -29,6 +29,15 @@ 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
|
+
/**
|
|
33
|
+
* The opt-in reference surface, when the head serves it.
|
|
34
|
+
*
|
|
35
|
+
* Separate from {@link proxy} because `ReferenceServerProtocol` is NOT part
|
|
36
|
+
* of `DataServerProtocol` — a head may serve documents and no references at
|
|
37
|
+
* all. Absent means the reference check reports skipped with a named reason
|
|
38
|
+
* rather than failing a head that never claimed the surface.
|
|
39
|
+
*/
|
|
40
|
+
readonly references?: ReferenceServerProtocol<TTransfer>;
|
|
32
41
|
}
|
|
33
42
|
/** Options for `runDataConformance`. */
|
|
34
43
|
export interface DataConformanceOptions<TTransfer extends TransferElement, TDiagnostic extends TransferDiagnostic = TransferDiagnostic> {
|
package/lib/data/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/data/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAWlF,OAAO,
|
|
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,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC1H,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;;;;;;;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,CAqSpB"}
|
package/lib/data/index.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* satisfies 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). */
|
|
@@ -189,6 +189,58 @@ export function buildDataChecks(options) {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
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
|
+
});
|
|
192
244
|
// Opt-in: both remaining checks need a second, observably different model
|
|
193
245
|
// text, which only `edit` supplies.
|
|
194
246
|
const editSkipReason = 'fixture supplies no `edit` (data-slice only; omit it if this language is not driven through the data head)';
|
package/lib/data/index.js.map
CHANGED
|
@@ -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;
|
|
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,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAiD,MAAM,qBAAqB,CAAC;AAEtI,OAAO,EAAgB,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAwB,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA4DlF,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,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,0EAA0E,GAAG,EAAE;YACtF,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,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;oBAEnG,oEAAoE;oBACpE,+DAA+D;oBAC/D,+DAA+D;oBAC/D,iEAAiE;oBACjE,+DAA+D;oBAC/D,0DAA0D;oBAC1D,uDAAuD;oBACvD,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAC/C,UAAU,CAAC,EAAE,CACV,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,CACvH,CAAC;oBACF,MAAM,CAAC,eAAe,CACnB,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EACjD,EAAE,EACF,wGAAwG,CAC1G,CAAC;gBACL,CAAC;wBAAS,CAAC;oBACR,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpB,CAAC;YACJ,CAAC;SACH,CAAC,CAAC;QAEH,yEAAyE;QACzE,wEAAwE;QACxE,wEAAwE;QACxE,0EAA0E;QAC1E,EAAE;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,wEAAwE;QACxE,6BAA6B;QAC7B,MAAM,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC;QAC/C,MAAM,mBAAmB,GAAG,CAAC,cAAc;YACxC,CAAC,CAAC,8FAA8F;YAChG,CAAC,CAAC,SAAS,CAAC;QAEf,MAAM,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,0EAA0E,GAAG,EAAE;YACtF,UAAU,EAAE,mBAAmB;YAC/B,IAAI,EAAE,cAAc;gBACjB,CAAC,CAAC,KAAK,IAAI,EAAE;oBACR,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;oBAC/B,IAAI,CAAC;wBACF,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;4BACtB,4DAA4D;4BAC5D,sDAAsD;4BACtD,+CAA+C;4BAC/C,OAAO;wBACV,CAAC;wBACD,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;wBAEhG,8DAA8D;wBAC9D,oDAAoD;wBACpD,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS;4BACvC,CAAC,CAAC,eAAe,CAAC,cAAc,CAAC,SAAS,CAAC;4BAC3C,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;wBACpD,MAAM,CAAC,EAAE,CACN,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,KAAK,KAAK,CAAC,GAAG,EAC/C,sCAAsC,KAAK,CAAC,GAAG,mCAAmC,CACpF,CAAC;wBAEF,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,uBAAuB,CAAC;4BAChE,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,SAAS,EAAE,cAAc,CAAC,IAAI,CAAC;4BACjE,aAAa,EAAE,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;4BACjH,QAAQ,EAAE,cAAc,CAAC,QAAQ;yBACnC,CAAC,CAAC;wBAEH,+DAA+D;wBAC/D,2DAA2D;wBAC3D,4DAA4D;wBAC5D,8CAA8C;wBAC9C,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;wBAC5D,MAAM,CAAC,EAAE,CACN,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC,EAC/C,yCAAyC,SAAS,kBAAkB,IAAI,CAAC,SAAS,CAC/E,cAAc,CAAC,eAAe,CAChC,UAAU,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACjC,CAAC;oBACL,CAAC;4BAAS,CAAC;wBACR,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,CAAC;gBACJ,CAAC;gBACH,CAAC,CAAC,SAAS;SAChB,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"}
|
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,10 @@ 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;
|
|
110
157
|
}
|
|
111
158
|
//# sourceMappingURL=model.d.ts.map
|
package/lib/model.d.ts.map
CHANGED
|
@@ -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
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/conformance",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.29",
|
|
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.
|
|
91
|
+
"@hydranium/protocol": "1.0.0-next.29",
|
|
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.
|
|
101
|
+
"@hydranium/protocol": "1.0.0-next.29",
|
|
102
102
|
"@jest/globals": "^29.0.0",
|
|
103
103
|
"vitest": "^4.0.0"
|
|
104
104
|
},
|
package/src/data/index.ts
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
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 { DataServerProtocol, ReferenceServerProtocol, TransferDocumentUpdatedEvent } from '@hydranium/protocol/data';
|
|
21
21
|
import { type Harness, waitFor } from '@hydranium/protocol/testing';
|
|
22
22
|
import type { ConformanceCheck } from '../conformance-suite.js';
|
|
23
23
|
import { type LanguageFixture, resolveDeferred, resolveModel } from '../model.js';
|
|
@@ -43,6 +43,15 @@ export interface DataConformanceDriver<
|
|
|
43
43
|
readonly proxy: DataServerProtocol<TTransfer, TDiagnostic>;
|
|
44
44
|
/** Captured `onDocumentUpdated` events, append order — the subscription check's observation target. */
|
|
45
45
|
readonly events: ReadonlyArray<TransferDocumentUpdatedEvent<TTransfer, TDiagnostic>>;
|
|
46
|
+
/**
|
|
47
|
+
* The opt-in reference surface, when the head serves it.
|
|
48
|
+
*
|
|
49
|
+
* Separate from {@link proxy} because `ReferenceServerProtocol` is NOT part
|
|
50
|
+
* of `DataServerProtocol` — a head may serve documents and no references at
|
|
51
|
+
* all. Absent means the reference check reports skipped with a named reason
|
|
52
|
+
* rather than failing a head that never claimed the surface.
|
|
53
|
+
*/
|
|
54
|
+
readonly references?: ReferenceServerProtocol<TTransfer>;
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
/** Options for `runDataConformance`. */
|
|
@@ -268,6 +277,70 @@ export function buildDataChecks<TTransfer extends TransferElement, TDiagnostic e
|
|
|
268
277
|
}
|
|
269
278
|
});
|
|
270
279
|
|
|
280
|
+
// The create-dialog query, and the reason it is its own check: it is the
|
|
281
|
+
// only request a head receives whose URI names no file. Everything else
|
|
282
|
+
// in this battery addresses a document, so a head that routes purely by
|
|
283
|
+
// URI extension passes all of them and still cannot open a create dialog.
|
|
284
|
+
//
|
|
285
|
+
// Doubly opt-in — the fixture must name a query AND the driver must serve
|
|
286
|
+
// the reference surface — because either half missing means the head never
|
|
287
|
+
// claimed this behaviour. The reasons are reported separately so a skip
|
|
288
|
+
// says which half is absent.
|
|
289
|
+
const referenceQuery = language.referenceQuery;
|
|
290
|
+
const referenceSkipReason = !referenceQuery
|
|
291
|
+
? 'fixture supplies no `referenceQuery` (omit it if this language has no create-element dialog)'
|
|
292
|
+
: undefined;
|
|
293
|
+
|
|
294
|
+
checks.push({
|
|
295
|
+
title: `findReferenceCandidates answers for a synthetic source at a folder URI ${tag}`,
|
|
296
|
+
skipReason: referenceSkipReason,
|
|
297
|
+
body: referenceQuery
|
|
298
|
+
? async () => {
|
|
299
|
+
const driver = await connect();
|
|
300
|
+
try {
|
|
301
|
+
if (!driver.references) {
|
|
302
|
+
// Checked here rather than in `skipReason`: the driver only
|
|
303
|
+
// exists once `connect` has run, and skip reasons are
|
|
304
|
+
// computed while the battery is being planned.
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const model = resolveModel(valid);
|
|
308
|
+
await driver.proxy.updateModelDocument({ uri: model.uri, clientId: AUTHOR, model: model.text });
|
|
309
|
+
|
|
310
|
+
// Default to the folder holding the valid model: a sibling of
|
|
311
|
+
// it is where a create flow would put the new file.
|
|
312
|
+
const folderUri = referenceQuery.folderUri
|
|
313
|
+
? resolveDeferred(referenceQuery.folderUri)
|
|
314
|
+
: model.uri.slice(0, model.uri.lastIndexOf('/'));
|
|
315
|
+
assert.ok(
|
|
316
|
+
folderUri.length > 0 && folderUri !== model.uri,
|
|
317
|
+
`could not derive a folder URI from ${model.uri}; supply referenceQuery.folderUri`
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const candidates = await driver.references.findReferenceCandidates({
|
|
321
|
+
source: ReferenceSource.synthetic(folderUri, referenceQuery.type),
|
|
322
|
+
syntheticPath: referenceQuery.path?.map(([containerProperty, type]) => SyntheticStep.of(containerProperty, type)),
|
|
323
|
+
property: referenceQuery.property
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// The expected label, not merely a non-empty array: the defect
|
|
327
|
+
// this guards against answers `[]`, and an empty result is
|
|
328
|
+
// also what a head with a genuinely empty index answers, so
|
|
329
|
+
// only a named candidate tells the two apart.
|
|
330
|
+
const labels = candidates.map(candidate => candidate.label);
|
|
331
|
+
assert.ok(
|
|
332
|
+
labels.includes(referenceQuery.expectCandidate),
|
|
333
|
+
`findReferenceCandidates at the folder ${folderUri} did not offer ${JSON.stringify(
|
|
334
|
+
referenceQuery.expectCandidate
|
|
335
|
+
)}; got [${labels.join(', ')}]`
|
|
336
|
+
);
|
|
337
|
+
} finally {
|
|
338
|
+
driver.dispose();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
: undefined
|
|
342
|
+
});
|
|
343
|
+
|
|
271
344
|
// Opt-in: both remaining checks need a second, observably different model
|
|
272
345
|
// text, which only `edit` supplies.
|
|
273
346
|
const editSkipReason = 'fixture supplies no `edit` (data-slice only; omit it if this language is not driven through the data head)';
|
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,9 @@ 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;
|
|
122
170
|
}
|