Skip to content

Commit 21b1051

Browse files
authored
fix: multiple document-builder listeners (#1738)
Signed-off-by: Christian Dietrich <[email protected]>
1 parent 516fe4c commit 21b1051

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

packages/langium/src/workspace/document-builder.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
452452

453453
protected async notifyDocumentPhase(document: LangiumDocument, state: DocumentState, cancelToken: CancellationToken): Promise<void> {
454454
const listeners = this.documentPhaseListeners.get(state);
455-
for (const listener of listeners) {
455+
const listenersCopy = listeners.slice();
456+
for (const listener of listenersCopy) {
456457
try {
457458
await listener(document, cancelToken);
458459
} catch (err) {
@@ -471,7 +472,8 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
471472
return;
472473
}
473474
const listeners = this.buildPhaseListeners.get(state);
474-
for (const listener of listeners) {
475+
const listenersCopy = listeners.slice();
476+
for (const listener of listenersCopy) {
475477
await interruptAndCheck(cancelToken);
476478
await listener(documents, cancelToken);
477479
}

packages/langium/test/workspace/document-builder.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,60 @@ describe('DefaultDocumentBuilder', () => {
283283
]);
284284
});
285285

286+
test('can handle multiple listeners (buildPhase)', async () => {
287+
const services = await createServices();
288+
const workspace = services.shared.workspace;
289+
const documentFactory = workspace.LangiumDocumentFactory;
290+
const documents = workspace.LangiumDocuments;
291+
const uri = URI.parse('file:///test1.txt');
292+
const document1 = documentFactory.fromString(`
293+
foo 1 A
294+
foo 11 B
295+
bar A
296+
bar B
297+
`, uri);
298+
documents.addDocument(document1);
299+
300+
const builder = workspace.DocumentBuilder;
301+
const p1 = builder.waitUntil(DocumentState.IndexedReferences, uri).then(() => {
302+
});
303+
const p2 = builder.waitUntil(DocumentState.IndexedReferences, uri).then(() => {
304+
});
305+
await builder.build([document1], {});
306+
await Promise.all([p1, p2]);
307+
expect(document1.state).toBe(DocumentState.IndexedReferences);
308+
});
309+
310+
test('can handle multiple listeners (documentPhase)', async () => {
311+
const services = await createServices();
312+
const workspace = services.shared.workspace;
313+
const documentFactory = workspace.LangiumDocumentFactory;
314+
const documents = workspace.LangiumDocuments;
315+
const uri = URI.parse('file:///test1.txt');
316+
const document1 = documentFactory.fromString(`
317+
foo 1 A
318+
foo 11 B
319+
bar A
320+
bar B
321+
`, uri);
322+
documents.addDocument(document1);
323+
324+
const builder = workspace.DocumentBuilder;
325+
let p1called = false;
326+
const p1 = builder.onDocumentPhase(DocumentState.IndexedReferences, (_d) => {
327+
p1called = true;
328+
p1.dispose();
329+
});
330+
let p2called = false;
331+
const p2 = builder.onDocumentPhase(DocumentState.IndexedReferences, (_d) => {
332+
p2called = true;
333+
p2.dispose();
334+
});
335+
await builder.build([document1], {});
336+
expect(p1called).toBe(true);
337+
expect(p2called).toBe(true);
338+
});
339+
286340
test('waits until a specific workspace stage has been reached', async () => {
287341
const services = await createServices();
288342
const documentFactory = services.shared.workspace.LangiumDocumentFactory;

0 commit comments

Comments
 (0)