Skip to content

Commit

Permalink
startServer coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
acao committed May 19, 2024
1 parent 70707b9 commit 203a2c0
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export class MockProject {
},
},
logger: new MockLogger(),
loadConfigOptions: { rootDir: root },
loadConfigOptions: {
rootDir: root,
},
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { IPCMessageReader, IPCMessageWriter } from 'vscode-jsonrpc/node';
import { addHandlers, buildOptions, initializeHandlers } from '../startServer';

describe('buildOptions', () => {
it('should build options', () => {
const options = buildOptions({});
expect(options).toEqual({
loadConfigOptions: {
extensions: [],
rootDir: process.cwd(),
},
});
});
it('should build options with loadConfigOptions', () => {
const options = buildOptions({ loadConfigOptions: { rootDir: '/root' } });
expect(options).toEqual({
loadConfigOptions: {
rootDir: '/root',
},
});
});
it('should build options with loadConfigOptions without rootDir', () => {
const options = buildOptions({ loadConfigOptions: { extensions: [] } });
expect(options).toEqual({
loadConfigOptions: {
rootDir: process.cwd(),
extensions: [],
},
});
});
it('should build options with just extensions', () => {
const options = buildOptions({ extensions: [] });
expect(options).toEqual({
extensions: [],
loadConfigOptions: {
rootDir: process.cwd(),
extensions: [],
},
});
});
});

describe('initializeHandlers', () => {
beforeEach(() => {
jest.resetModules();
});
it('should initialize handlers', async () => {
const reader = new IPCMessageReader(process);
const writer = new IPCMessageWriter(process);
const handlers = await initializeHandlers({
reader,
writer,
options: {
loadConfigOptions: { rootDir: '/root' },
},
});
expect(handlers).toBeDefined();
});
});

describe('addHandlers', () => {
it('should add handlers', async () => {
const connection = {
onInitialize: jest.fn(),
onInitialized: jest.fn(),
onShutdown: jest.fn(),
onExit: jest.fn(),
onNotification: jest.fn(),
onRequest: jest.fn(),
sendNotification: jest.fn(),
sendRequest: jest.fn(),
console: {
error: jest.fn(),
warn: jest.fn(),
info: jest.fn(),
log: jest.fn(),
},
};

await addHandlers({
connection,
options: { loadConfigOptions: { rootDir: '/root' } },
});
expect(
connection.onNotification.mock.calls.map(c => c[0].method ?? c[0]),
).toEqual([
'textDocument/didOpen',
'textDocument/didSave',
'textDocument/didChange',
'textDocument/didClose',
'exit',
'$/cancelRequest',
'workspace/didChangeWatchedFiles',
'workspace/didChangeConfiguration',
]);
expect(
connection.onRequest.mock.calls.map(c => c[0].method ?? c[0]),
).toEqual([
'shutdown',
'initialize',
'textDocument/completion',
'completionItem/resolve',
'textDocument/definition',
'textDocument/hover',
'textDocument/documentSymbol',
'workspace/symbol',
]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,30 @@ import startServer from '../startServer';

describe('startServer', () => {
it('should start the server', async () => {
await startServer({});
await startServer();
// if the server starts, we're good
expect(true).toBe(true);
});
// this one fails to exit
it('should start the server with stream', async () => {
await startServer({
method: 'stream',
});
// if the server starts, we're good
expect(true).toBe(true);
});
it('should start the server with ipc', async () => {
await startServer({
method: 'node',
});
// if the server starts, we're good
expect(true).toBe(true);
});
it('should start the server with websockets', async () => {
await startServer({
method: 'socket',
port: 4000,
});
// if the server starts, we're good
expect(true).toBe(true);
});
Expand Down
87 changes: 41 additions & 46 deletions packages/graphql-language-service-server/src/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* LICENSE file in the root directory of this source tree.
*
*/
import * as net from 'node:net';
import { MessageProcessor } from './MessageProcessor';
import { GraphQLConfig, GraphQLExtensionDeclaration } from 'graphql-config';
import {
Expand Down Expand Up @@ -36,7 +35,7 @@ import {
DocumentSymbolRequest,
PublishDiagnosticsParams,
WorkspaceSymbolRequest,
createConnection,
createConnection as createLanguageServerConnection,
Connection,
} from 'vscode-languageserver/node';

Expand All @@ -48,43 +47,52 @@ import {
SupportedExtensionsEnum,
} from './constants';
import { LoadConfigOptions } from './types';
import { createConnection } from 'node:net';

export interface ServerOptions {
/**
* port for the LSP server to run on. required if using method socket
* socket, streams, or node (ipc).
* @default 'node'
*/
method?: 'socket' | 'stream' | 'node';
/**
* (socket only) port for the LSP server to run on. required if using method socket
*/
port?: number;
/**
* hostname if using socker
* (socket only) hostname for the LSP server to run on.
* @default '127.0.0.1'
*/
hostname?: string;
/**
* socket, streams, or node (ipc). `node` by default.
* (socket only) encoding for the LSP server to use.
* @default 'utf-8'
*/
method?: 'socket' | 'stream' | 'node';
encoding?: 'utf-8' | 'ascii';
/**
* `LoadConfigOptions` from `graphql-config@3` to use when we `loadConfig()`
* uses process.cwd() by default for `rootDir` option.
* you can also pass explicit `filepath`, add extensions, etc
*/
loadConfigOptions?: LoadConfigOptions;
/**
* (deprecated: use loadConfigOptions.rootDir now) the directory where graphql-config is found
* @deprecated use loadConfigOptions.rootDir now) the directory where graphql-config is found
*/
configDir?: string;
/**
* (deprecated: use loadConfigOptions.extensions now) array of functions to transform the graphql-config and add extensions dynamically
* @deprecated use loadConfigOptions.extensions
*/
extensions?: GraphQLExtensionDeclaration[];
/**
* default: ['.js', '.jsx', '.tsx', '.ts', '.mjs']
* allowed file extensions for embedded graphql, used by the parser.
* note that with vscode, this is also controlled by manifest and client configurations.
* do not put full-file graphql extensions here!
* @default ['.js', '.jsx', '.tsx', '.ts', '.mjs']
*/
fileExtensions?: ReadonlyArray<SupportedExtensionsEnum>;
/**
* default: ['graphql'] - allowed file extensions for graphql, used by the parser
* allowed file extensions for full-file graphql, used by the parser.
* @default ['graphql', 'graphqls', 'gql' ]
*/
graphqlFileExtensions?: string[];
/**
Expand Down Expand Up @@ -123,27 +131,25 @@ export type MappedServerOptions = Omit<ServerOptions, 'loadConfigOptions'> & {
* Legacy mappings for < 2.5.0
* @param options {ServerOptions}
*/
const buildOptions = (options: ServerOptions): MappedServerOptions => {
export const buildOptions = (options: ServerOptions): MappedServerOptions => {
const serverOptions = { ...options } as MappedServerOptions;

if (serverOptions.loadConfigOptions) {
const { extensions, rootDir } = serverOptions.loadConfigOptions;
if (extensions) {
serverOptions.loadConfigOptions.extensions = extensions;
}
if (!rootDir) {
if (serverOptions.configDir) {
serverOptions.loadConfigOptions.rootDir = serverOptions.configDir;
} else {
serverOptions.loadConfigOptions.rootDir = process.cwd();
}
}
if (serverOptions.extensions) {
serverOptions.loadConfigOptions.extensions = [
...serverOptions.extensions,
...(extensions || []),
];
}
} else {
serverOptions.loadConfigOptions = {
rootDir: options.configDir || process.cwd(),
extensions: [],
extensions: serverOptions.extensions || [],
};
}
return serverOptions;
Expand All @@ -156,7 +162,7 @@ const buildOptions = (options: ServerOptions): MappedServerOptions => {
* @returns {Promise<void>}
*/
export default async function startServer(
options: ServerOptions,
options?: ServerOptions,
): Promise<void> {
if (!options?.method) {
return;
Expand All @@ -176,41 +182,29 @@ export default async function startServer(
process.exit(1);
}

const { port, hostname } = options;
const socket = net
.createServer(async client => {
client.setEncoding('utf8');
reader = new SocketMessageReader(client);
writer = new SocketMessageWriter(client);
client.on('end', () => {
socket.close();
process.exit(0);
});
const s = await initializeHandlers({
reader,
writer,
options: finalOptions,
});
s.listen();
})
.listen(port, hostname);
return;
const { port, hostname, encoding } = options;
const socket = createConnection(port, hostname ?? '127.0.01');

reader = new SocketMessageReader(socket, encoding ?? 'utf-8');
writer = new SocketMessageWriter(socket, encoding ?? 'utf-8');

break;
case 'stream':
reader = new StreamMessageReader(process.stdin);
writer = new StreamMessageWriter(process.stdout);
break;
default:
reader = new IPCMessageReader(process);
writer = new IPCMessageWriter(process);

break;
}

const serverWithHandlers = await initializeHandlers({
const streamServer = await initializeHandlers({
reader,
writer,
options: finalOptions,
});
serverWithHandlers.listen();
streamServer.listen();
}

type InitializerParams = {
Expand All @@ -219,12 +213,12 @@ type InitializerParams = {
options: MappedServerOptions;
};

async function initializeHandlers({
export async function initializeHandlers({
reader,
writer,
options,
}: InitializerParams): Promise<Connection> {
const connection = createConnection(reader, writer);
const connection = createLanguageServerConnection(reader, writer);
const logger = new Logger(connection, options.debug);

try {
Expand Down Expand Up @@ -266,7 +260,7 @@ type HandlerOptions = {
*
* @param options {HandlerOptions}
*/
async function addHandlers({
export async function addHandlers({
connection,
logger,
config,
Expand Down Expand Up @@ -314,8 +308,9 @@ async function addHandlers({
},
);

connection.onNotification(DidCloseTextDocumentNotification.type, params =>
messageProcessor.handleDidCloseNotification(params),
connection.onNotification(
DidCloseTextDocumentNotification.type,
messageProcessor.handleDidCloseNotification,
);
connection.onRequest(ShutdownRequest.type, () =>
messageProcessor.handleShutdownRequest(),
Expand Down

0 comments on commit 203a2c0

Please sign in to comment.