Skip to content
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
13 changes: 11 additions & 2 deletions bin/cucumber-language-server.cjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
#!/usr/bin/env node
/* eslint-disable @typescript-eslint/no-var-requires */
require('source-map-support').install()
const { startWasmServer } = require('../dist/cjs/src/wasm/startWasmServer')
const { startStandaloneServer } = require('../dist/cjs/src/wasm/startStandaloneServer')
const { NodeFiles } = require('../dist/cjs/src/node/NodeFiles')
const url = require('url')
const { version } = require('../src/version')

const wasmBaseUrl = url.pathToFileURL(
`${__dirname}/../node_modules/@cucumber/language-service/dist`
)
startWasmServer(wasmBaseUrl.href, (rootUri) => new NodeFiles(rootUri))
const { connection } = startStandaloneServer(wasmBaseUrl.href, (rootUri) => new NodeFiles(rootUri))

// Don't die on unhandled Promise rejections
process.on('unhandledRejection', (reason, p) => {
connection.console.error(
`Cucumber Language Server ${version}: Unhandled Rejection at promise: ${p}, reason: ${reason}`
)
})
380 changes: 236 additions & 144 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,30 +64,30 @@
},
"homepage": "https://github.com/cucumber/language-server#readme",
"devDependencies": {
"@cucumber/cucumber": "8.8.0",
"@cucumber/cucumber": "8.9.0",
"@types/mocha": "10.0.0",
"@types/node": "18.11.9",
"@typescript-eslint/eslint-plugin": "5.43.0",
"@typescript-eslint/parser": "5.43.0",
"eslint": "8.27.0",
"@typescript-eslint/eslint-plugin": "5.44.0",
"@typescript-eslint/parser": "5.44.0",
"eslint": "8.28.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-simple-import-sort": "8.0.0",
"husky": "8.0.2",
"mocha": "10.1.0",
"npm-check-updates": "16.4.1",
"prettier": "2.7.1",
"npm-check-updates": "16.4.3",
"prettier": "2.8.0",
"pretty-quick": "3.1.3",
"ts-node": "10.9.1",
"typescript": "4.9.3",
"vscode-jsonrpc": "8.0.2",
"vscode-languageserver-protocol": "3.17.2"
},
"dependencies": {
"@cucumber/gherkin-utils": "^8.0.1",
"@cucumber/language-service": "^1.2.0",
"@cucumber/gherkin-utils": "^8.0.2",
"@cucumber/language-service": "^1.3.0",
"fast-glob": "3.2.12",
"source-map-support": "0.5.21",
"vscode-languageserver": "8.0.2",
Expand Down
44 changes: 26 additions & 18 deletions src/CucumberLanguageServer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
buildSuggestions,
CucumberExpressions,
ExpressionBuilder,
ExpressionBuilderResult,
getGenerateSnippetCodeAction,
Expand Down Expand Up @@ -85,18 +86,21 @@ export class CucumberLanguageServer {
private expressionBuilderResult: ExpressionBuilderResult | undefined = undefined
private reindexingTimeout: NodeJS.Timeout
private rootUri: string
#suggestions: readonly Suggestion[]
#files: Files

get suggestions() {
return this.#suggestions
}
private files: Files
public registry: CucumberExpressions.ParameterTypeRegistry
public expressions: readonly CucumberExpressions.Expression[] = []
public suggestions: readonly Suggestion[] = []

constructor(
private readonly connection: Connection,
private readonly documents: TextDocuments<TextDocument>,
parserAdapter: ParserAdapter,
private readonly makeFiles: (rootUri: string) => Files
private readonly makeFiles: (rootUri: string) => Files,
private readonly onReindexed: (
registry: CucumberExpressions.ParameterTypeRegistry,
expressions: readonly CucumberExpressions.Expression[],
suggestions: readonly Suggestion[]
) => void
) {
this.expressionBuilder = new ExpressionBuilder(parserAdapter)

Expand All @@ -120,7 +124,7 @@ export class CucumberLanguageServer {
} else {
connection.console.error(`Could not determine rootPath`)
}
this.#files = makeFiles(this.rootUri)
this.files = makeFiles(this.rootUri)
// Some users have reported that the globs don't find any files. This is to debug that issue
connection.console.info(`Root uri : ${this.rootUri}`)
connection.console.info(`Current dir : ${process.cwd()}`)
Expand Down Expand Up @@ -224,8 +228,8 @@ export class CucumberLanguageServer {
return []
}
const mustacheTemplate = settings.snippetTemplates[languageName]
const createFile = !(await this.#files.exists(link.targetUri))
const relativePath = this.#files.relativePath(link.targetUri)
const createFile = !(await this.files.exists(link.targetUri))
const relativePath = this.files.relativePath(link.targetUri)
const codeAction = getGenerateSnippetCodeAction(
diagnostics,
link,
Expand Down Expand Up @@ -401,7 +405,7 @@ export class CucumberLanguageServer {
// https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#workDoneProgress

this.connection.console.info(`Reindexing ${this.rootUri}`)
const gherkinSources = await loadGherkinSources(this.#files, settings.features)
const gherkinSources = await loadGherkinSources(this.files, settings.features)
this.connection.console.info(
`* Found ${gherkinSources.length} feature file(s) in ${JSON.stringify(settings.features)}`
)
Expand All @@ -410,7 +414,7 @@ export class CucumberLanguageServer {
[]
)
this.connection.console.info(`* Found ${stepTexts.length} steps in those feature files`)
const glueSources = await loadGlueSources(this.#files, settings.glue)
const glueSources = await loadGlueSources(this.files, settings.glue)
this.connection.console.info(
`* Found ${glueSources.length} glue file(s) in ${JSON.stringify(settings.glue)}`
)
Expand Down Expand Up @@ -446,15 +450,19 @@ export class CucumberLanguageServer {
this.connection.languages.semanticTokens.refresh()

try {
this.#suggestions = buildSuggestions(
const expressions = this.expressionBuilderResult.expressionLinks.map((l) => l.expression)
const suggestions = buildSuggestions(
this.expressionBuilderResult.registry,
stepTexts,
this.expressionBuilderResult.expressionLinks.map((l) => l.expression)
)
this.connection.console.info(
`* Built ${this.#suggestions.length} suggestions for auto complete`
expressions
)
this.searchIndex = jsSearchIndex(this.#suggestions)
this.connection.console.info(`* Built ${suggestions.length} suggestions for auto complete`)
this.searchIndex = jsSearchIndex(suggestions)
const registry = this.expressionBuilderResult.registry
this.registry = registry
this.expressions = expressions
this.suggestions = suggestions
this.onReindexed(registry, expressions, suggestions)
} catch (err) {
this.connection.console.error(err.stack)
this.connection.console.error(
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './CucumberLanguageServer.js'
export * from './Files.js'
export * from './newWasmServer.js'
export * from './startServer.js'
export { CucumberExpressions, Suggestion } from '@cucumber/language-service'
30 changes: 0 additions & 30 deletions src/newWasmServer.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './NodeFiles.js'
export * from './startNodeServer.js'
8 changes: 0 additions & 8 deletions src/node/startNodeServer.ts

This file was deleted.

22 changes: 0 additions & 22 deletions src/startServer.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const version = '1.1.1'
export const version = '1.2.0'
3 changes: 2 additions & 1 deletion src/wasm/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './startWasmServer.js'
export * from './startEmbeddedServer.js'
export * from './startStandaloneServer.js'
42 changes: 42 additions & 0 deletions src/wasm/startEmbeddedServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { CucumberExpressions, ParserAdapter, Suggestion } from '@cucumber/language-service'
import { WasmParserAdapter } from '@cucumber/language-service/wasm'
import { PassThrough } from 'stream'
import { Connection, TextDocuments } from 'vscode-languageserver'
import { createConnection } from 'vscode-languageserver/node'
import { TextDocument } from 'vscode-languageserver-textdocument'

import { CucumberLanguageServer } from '../CucumberLanguageServer.js'
import { Files } from '../Files'

export type ServerInfo = {
writer: NodeJS.WritableStream
reader: NodeJS.ReadableStream
server: CucumberLanguageServer
connection: Connection
}

export function startEmbeddedServer(
wasmBaseUrl: string,
makeFiles: (rootUri: string) => Files,
onReindexed: (
registry: CucumberExpressions.ParameterTypeRegistry,
expressions: readonly CucumberExpressions.Expression[],
suggestions: readonly Suggestion[]
) => void
): ServerInfo {
const adapter: ParserAdapter = new WasmParserAdapter(wasmBaseUrl)
const inputStream = new PassThrough()
const outputStream = new PassThrough()

const connection = createConnection(inputStream, outputStream)
const documents = new TextDocuments(TextDocument)
const server = new CucumberLanguageServer(connection, documents, adapter, makeFiles, onReindexed)
connection.listen()

return {
writer: inputStream,
reader: outputStream,
server,
connection,
}
}
15 changes: 15 additions & 0 deletions src/wasm/startStandaloneServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { WasmParserAdapter } from '@cucumber/language-service/wasm'
import { TextDocuments } from 'vscode-languageserver'
import { createConnection, ProposedFeatures } from 'vscode-languageserver/node'
import { TextDocument } from 'vscode-languageserver-textdocument'

import { CucumberLanguageServer } from '../CucumberLanguageServer'
import { Files } from '../Files'

export function startStandaloneServer(wasmBaseUrl: string, makeFiles: (rootUri: string) => Files) {
const adapter = new WasmParserAdapter(wasmBaseUrl)
const connection = createConnection(ProposedFeatures.all)
const documents = new TextDocuments(TextDocument)
new CucumberLanguageServer(connection, documents, adapter, makeFiles, () => undefined)
connection.listen()
}
8 changes: 0 additions & 8 deletions src/wasm/startWasmServer.ts

This file was deleted.

7 changes: 4 additions & 3 deletions test/CucumberLanguageServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import { TextDocument } from 'vscode-languageserver-textdocument'
import { CompletionItem, CompletionItemKind } from 'vscode-languageserver-types'

import { CucumberLanguageServer } from '../src/CucumberLanguageServer.js'
import { NodeFiles } from '../src/node/NodeFiles'
import { Settings } from '../src/types'
import { NodeFiles } from '../src/node/NodeFiles.js'
import { Settings } from '../src/types.js'

describe('CucumberLanguageServer', () => {
let inputStream: Duplex
Expand All @@ -43,7 +43,8 @@ describe('CucumberLanguageServer', () => {
serverConnection,
documents,
new WasmParserAdapter('node_modules/@cucumber/language-service/dist'),
(rootUri) => new NodeFiles(rootUri)
(rootUri) => new NodeFiles(rootUri),
() => undefined
)
serverConnection.listen()

Expand Down