Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit onUpdate event on DocumentBuilder#build #1190

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions packages/langium/src/workspace/document-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export interface DocumentBuilder {
onBuildPhase(targetState: DocumentState, callback: DocumentBuildListener): Disposable;
}

export type DocumentUpdateListener = (changed: URI[], deleted: URI[]) => void
export type DocumentUpdateListener = (changed: URI[], deleted: URI[]) => void | Promise<void>
export type DocumentBuildListener = (built: LangiumDocument[], cancelToken: CancellationToken) => void | Promise<void>
export class DefaultDocumentBuilder implements DocumentBuilder {

Expand Down Expand Up @@ -144,6 +144,7 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
this.buildState.delete(key);
}
}
await this.emitUpdate(documents.map(e => e.uri), []);
await this.buildDocuments(documents, options, cancelToken);
}

Expand Down Expand Up @@ -173,9 +174,7 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
doc.diagnostics = undefined;
});
// Notify listeners of the update
for (const listener of this.updateListeners) {
listener(changed, deleted);
}
await this.emitUpdate(changed, deleted);
// Only allow interrupting the execution after all state changes are done
await interruptAndCheck(cancelToken);

Expand All @@ -191,6 +190,10 @@ export class DefaultDocumentBuilder implements DocumentBuilder {
await this.buildDocuments(rebuildDocuments, this.updateBuildOptions, cancelToken);
}

protected async emitUpdate(changed: URI[], deleted: URI[]): Promise<void> {
await Promise.all(this.updateListeners.map(listener => listener(changed, deleted)));
}

/**
* Check whether the given document should be relinked after changes were found in the given URIs.
*/
Expand Down
10 changes: 5 additions & 5 deletions packages/langium/test/grammar/type-system/inferred-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe('Inferred types', () => {
});

test('Should infer data type rules as unions', async () => {
expectTypes(`
await expectTypes(`
Strings returns string: 'a' | 'b' | 'c';
MoreStrings returns string: Strings | 'd' | 'e';
Complex returns string: ID ('.' ID)*;
Expand Down Expand Up @@ -323,7 +323,7 @@ describe('Inferred types', () => {
});

test('Infers X as a super interface of Y and Z with property `id`', async () => {
expectTypes(`
await expectTypes(`
entry X: id=ID ({infer Y} 'a' | {infer Z} 'b');
terminal ID: /[a-zA-Z_][a-zA-Z0-9_]*/;
`, expandToString`
Expand All @@ -343,7 +343,7 @@ describe('Inferred types', () => {

describe('inferred types that are used by the grammar', () => {
test('B is defined and A is not', async () => {
expectTypes(`
await expectTypes(`
A infers B: 'a' name=ID (otherA=[B])?;
hidden terminal WS: /\\s+/;
terminal ID: /[a-zA-Z_][a-zA-Z0-9_]*/;
Expand All @@ -359,7 +359,7 @@ describe('inferred types that are used by the grammar', () => {

describe('inferred and declared types', () => {
test('Declared interfaces should be preserved as interfaces', async () => {
expectTypes(`
await expectTypes(`
X returns X: Y | Z;
Y: y='y';
Z: z='z';
Expand Down Expand Up @@ -881,10 +881,10 @@ describe('generated types from declared types include all of them', () => {
// });

const services = createLangiumGrammarServices(EmptyFileSystem).grammar;
const helper = parseHelper<Grammar>(services);

async function getTypes(grammar: string): Promise<AstTypes> {
await clearDocuments(services);
const helper = parseHelper<Grammar>(services);
const result = await helper(grammar);
const gram = result.parseResult.value;
return collectAst(gram);
Expand Down
36 changes: 36 additions & 0 deletions packages/langium/test/workspace/document-builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,42 @@ describe('DefaultDocumentBuilder', () => {
return services;
}

test('emits `onUpdate` on `update` call', async () => {
const services = await createServices();
const documentFactory = services.shared.workspace.LangiumDocumentFactory;
const documents = services.shared.workspace.LangiumDocuments;
const document = documentFactory.fromString('', URI.parse('file:///test1.txt'));
documents.addDocument(document);

const builder = services.shared.workspace.DocumentBuilder;
await builder.build([document], {});
addTextDocument(document, services);
let called = false;
builder.onUpdate(() => {
called = true;
});
await builder.update([document.uri], []);
expect(called).toBe(true);
});

test('emits `onUpdate` on `build` call', async () => {
const services = await createServices();
const documentFactory = services.shared.workspace.LangiumDocumentFactory;
const documents = services.shared.workspace.LangiumDocuments;
const document = documentFactory.fromString('', URI.parse('file:///test1.txt'));
documents.addDocument(document);

const builder = services.shared.workspace.DocumentBuilder;
await builder.build([document], {});
addTextDocument(document, services);
let called = false;
builder.onUpdate(() => {
called = true;
});
await builder.build([document]);
expect(called).toBe(true);
});

test('resumes document build after cancellation', async () => {
const services = await createServices();
const documentFactory = services.shared.workspace.LangiumDocumentFactory;
Expand Down