Skip to content

Commit 5c85ce0

Browse files
authored
Merge pull request #47 from lstreckeisen/CMI-95-Improve-Language-Server-Command-error-handling
make generator throw error when something goes wrong
2 parents cb4e91e + f3e386b commit 5c85ce0

File tree

4 files changed

+30
-24
lines changed

4 files changed

+30
-24
lines changed

src/language/commands/GeneratorCommandExecutor.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,34 @@ export class GeneratorCommandExecutor {
1414
this.serviceRegistry = serviceRegistry
1515
}
1616

17-
async execute (generator: ContextMapperGenerator, args: unknown[], cancelToken: CancellationToken): Promise<string[] | undefined> {
17+
async execute (generator: ContextMapperGenerator, args: unknown[], cancelToken: CancellationToken): Promise<string[]> {
1818
const filePath = args[0] as string
1919

2020
const model = await this.extractModel(filePath)
2121
if (cancelToken.isCancellationRequested) {
22-
return undefined
22+
return []
2323
}
2424

25-
if (model == null) {
26-
return undefined
27-
}
28-
args.shift()
25+
args.shift() // remove source file from args array
2926
return await generator.generate(model, filePath, args, cancelToken)
3027
}
3128

32-
private async extractModel (filePath: string): Promise<ContextMappingModel | undefined> {
29+
private async extractModel (filePath: string): Promise<ContextMappingModel> {
3330
const extensions = ContextMapperDslLanguageMetaData.fileExtensions as readonly string[]
3431
if (!extensions.includes(path.extname(filePath))) {
35-
console.error('Unsupported file extension on file', filePath)
36-
return undefined
32+
throw new Error(`Unsupported file extension on file ${filePath}`)
3733
}
3834

3935
if (!fs.existsSync(filePath)) {
40-
console.error(`File ${filePath} does not exist.`)
41-
return undefined
36+
throw new Error(`File ${filePath} does not exist.`)
4237
}
4338

4439
const document = await this.getServices().shared.workspace.LangiumDocuments.getOrCreateDocument(URI.file(path.resolve(filePath)))
4540
await this.getServices().shared.workspace.DocumentBuilder.build([document], { validation: true })
4641

4742
const validationErrors = (document.diagnostics ?? []).filter(e => e.severity === 1)
4843
if (validationErrors.length > 0) {
49-
console.error(`File ${filePath} is invalid`)
50-
return undefined
44+
throw new Error(`File ${filePath} is invalid`)
5145
}
5246

5347
return document.parseResult.value as ContextMappingModel

src/language/commands/generators/ContextMapperGenerator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import { ContextMappingModel } from '../../generated/ast.js'
22
import { CancellationToken } from 'vscode-languageserver'
33

44
export interface ContextMapperGenerator {
5-
generate(model: ContextMappingModel, filePath: string, args: unknown[], cancelToken: CancellationToken): Promise<string[] | undefined>
5+
generate(model: ContextMappingModel, filePath: string, args: unknown[], cancelToken: CancellationToken): Promise<string[]>
66
}

src/language/commands/generators/PlantUMLGenerator.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import { ComponentDiagramGenerator } from './plantuml/ComponentDiagramGenerator.
66
import { CancellationToken } from 'vscode-languageserver'
77

88
export class PlantUMLGenerator implements ContextMapperGenerator {
9-
async generate (model: ContextMappingModel, filePath: string, args: unknown[], cancelToken: CancellationToken): Promise<string[] | undefined> {
9+
async generate (model: ContextMappingModel, filePath: string, args: unknown[], cancelToken: CancellationToken): Promise<string[]> {
1010
// there must not be any extra spaces especially at the start, since the path will be treated as relative otherwise
1111
const destination = (args[0] as string)?.trim()
1212
if (destination == null || destination === '') {
1313
console.log('Destination must be specified')
14-
return undefined
14+
throw Error('Destination must be specified')
1515
}
1616

1717
if (cancelToken.isCancellationRequested) {
18-
return undefined
18+
return []
1919
}
2020
const fileName = filePath.split('/').pop()!.split('.')[0]
2121

@@ -30,7 +30,6 @@ export class PlantUMLGenerator implements ContextMapperGenerator {
3030
diagrams.push(componentDiagram)
3131
}
3232

33-
console.log('Successfully generated PlantUML diagrams')
3433
return diagrams
3534
}
3635

test/commands/CommandExecution.test.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { afterEach, beforeAll, describe, expect, test } from 'vitest'
55
import { NodeFileSystem } from 'langium/node'
66
import fs from 'node:fs'
77
import path from 'node:path'
8+
import { fail } from 'node:assert'
89

910
const outDir = path.join(__dirname, 'out')
1011

@@ -38,8 +39,12 @@ describe('Command execution tests', () => {
3839
test('test plantUML command with invalid file extension', async () => {
3940
const file = path.join(__dirname, '..', 'invalid-files', 'test.txt')
4041

41-
const result = await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
42-
expect(result).toBeUndefined()
42+
try {
43+
await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
44+
fail('Expected generator to fail')
45+
} catch (e) {
46+
expect(e).not.toBeUndefined()
47+
}
4348

4449
const outContentExists = fs.existsSync(outDir)
4550
expect(outContentExists).toEqual(false)
@@ -48,8 +53,12 @@ describe('Command execution tests', () => {
4853
test('test plantUML command with invalid file', async () => {
4954
const file = path.join(__dirname, '..', 'invalid-files', 'invalid.cml')
5055

51-
const result = await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
52-
expect(result).toBeUndefined()
56+
try {
57+
await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
58+
fail('Expected generator to fail')
59+
} catch (e) {
60+
expect(e).not.toBeUndefined()
61+
}
5362

5463
const outContentExists = fs.existsSync(outDir)
5564
expect(outContentExists).toEqual(false)
@@ -58,8 +67,12 @@ describe('Command execution tests', () => {
5867
test('test plantUML command with non-existing file', async () => {
5968
const file = path.join(__dirname, '..', 'invalid-files', 'non-existing.cml')
6069

61-
const result = await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
62-
expect(result).toBeUndefined()
70+
try {
71+
await commandHandler.executeCommand('org.contextmapper.GeneratePlantUML', [file, outDir])
72+
fail('Expected generator to fail')
73+
} catch (e) {
74+
expect(e).not.toBeUndefined()
75+
}
6376

6477
const outContentExists = fs.existsSync(outDir)
6578
expect(outContentExists).toEqual(false)

0 commit comments

Comments
 (0)