Skip to content

Commit 6c602d5

Browse files
kaisalmenmsujew
andauthored
notifyBuildPhase was never called for Parsed state (#1572)
* fix: notifyBuildPhase was never called for Parsed state * Added new unit test "Check all onBuidPhase callbacks" * Improve code documentation and shorten required code Co-authored-by: Mark Sujew <[email protected]>
1 parent 721b882 commit 6c602d5

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build:clean": "npm run clean && npm run build",
1414
"lint": "npm run lint --workspaces",
1515
"test": "vitest",
16+
"test:run": "vitest --run",
1617
"test-ui": "vitest --ui",
1718
"coverage": "vitest run --coverage",
1819
"validate-exports": "npm run validate-exports --workspace=langium",

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,19 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
352352

353353
protected async runCancelable(documents: LangiumDocument[], targetState: DocumentState, cancelToken: CancellationToken,
354354
callback: (document: LangiumDocument) => MaybePromise<unknown>): Promise<void> {
355-
const filtered = documents.filter(e => e.state < targetState);
355+
const filtered = documents.filter(doc => doc.state < targetState);
356356
for (const document of filtered) {
357357
await interruptAndCheck(cancelToken);
358358
await callback(document);
359359
document.state = targetState;
360360
await this.notifyDocumentPhase(document, targetState, cancelToken);
361361
}
362-
await this.notifyBuildPhase(filtered, targetState, cancelToken);
362+
363+
// Do not use `filtered` here, as that will miss documents that have previously reached the current target state
364+
// For example, this happens in case the cancellation triggers between the processing of two documents
365+
// Or files that were picked up during the workspace initialization
366+
const targetStateDocs = documents.filter(doc => doc.state === targetState);
367+
await this.notifyBuildPhase(targetStateDocs, targetState, cancelToken);
363368
this.currentState = targetState;
364369
}
365370

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,45 @@ describe('DefaultDocumentBuilder', () => {
8282
expect(called).toBe(true);
8383
});
8484

85+
test('Check all onBuidPhase callbacks', async () => {
86+
const services = await createServices();
87+
const documentFactory = services.shared.workspace.LangiumDocumentFactory;
88+
const documents = services.shared.workspace.LangiumDocuments;
89+
const document = documentFactory.fromString(`
90+
foo 1 A
91+
foo 11 B
92+
bar A
93+
bar B
94+
`, URI.parse('file:///test1.txt'));
95+
documents.addDocument(document);
96+
97+
const builder = services.shared.workspace.DocumentBuilder;
98+
const awaiting: Array<Promise<void>> = [];
99+
builder.onBuildPhase(DocumentState.Parsed, () => {
100+
awaiting.push(Promise.resolve());
101+
});
102+
builder.onBuildPhase(DocumentState.IndexedContent, () => {
103+
awaiting.push(Promise.resolve());
104+
});
105+
builder.onBuildPhase(DocumentState.ComputedScopes, () => {
106+
awaiting.push(Promise.resolve());
107+
});
108+
builder.onBuildPhase(DocumentState.Linked, () => {
109+
awaiting.push(Promise.resolve());
110+
});
111+
builder.onBuildPhase(DocumentState.IndexedReferences, () => {
112+
awaiting.push(Promise.resolve());
113+
});
114+
builder.onBuildPhase(DocumentState.Validated, () => {
115+
awaiting.push(Promise.resolve());
116+
});
117+
118+
await builder.build([document], { validation: true });
119+
expect(async () => await Promise.all(awaiting)).not.toThrowError();
120+
expect(document.state).toBe(DocumentState.Validated);
121+
expect(awaiting.length).toBe(6);
122+
});
123+
85124
test('resumes document build after cancellation', async () => {
86125
const services = await createServices();
87126
const documentFactory = services.shared.workspace.LangiumDocumentFactory;

0 commit comments

Comments
 (0)