DEV Community

Cover image for Implementing a Serverless Framework Language Server
Tim Walter
Tim Walter

Posted on

Implementing a Serverless Framework Language Server

Beginning of a Dev Diary

For a long time now I was thinking about starting to write posts for dev.to.
My motivation behind that is to share my knowledge and give something back to the developer community.
As I recently started a new side project, the idea of this blog series came in my mind.
The vision of my side project is the implementation of a developer tool, namely a language server for the serverless framework.
If you do not know what a language server is, the following post may interest you.
This kind of post represents a dev diary, in which I share my thoughts (and references) while implementing the project.
Hopefully you'll like it and leave me some feedback.

Inspiration and First Progression

Recently (more like the whole last year) I did work a lot with the serverless framework.
While my experience with it mostly is positive, I couldn't come around the point, that I had one big issue with it.
See when writing Infrastructure as Code (IaC) I try to stay in my zone* as I would program in any other language.
But personally I can only achieve this when I stay inside my IDE most of the time, working with auto completion, descriptive hover events, shortcuts and so on.

* The zone is usually described as a state-of-mind where one feels productive and hyper-focused (source)

Here's the point.
While the serverless framework is still kinda "new" there aren't any extensive developer tooling available for it right now. Only tools I've found were some simple "code snippet" extensions in VS Code.
Not really my style.
So to speak, I tried to implement the change I needed.

In my time working with (and crafting) developer tools I did also come around so called language server. To not reinvent the wheel, let me extract a quote from the Microsoft Github Repository for the Language Server Protocol (LSP).

Adding features like auto complete, go to definition, or documentation on hover for a programming language takes significant effort.
Traditionally this work had to be repeated for each development tool, as each tool provides different APIs for implementing the same feature.
A Language Server is meant to provide the language-specific smarts and communicate with development tools over a protocol that enables inter-process communication.

My goal was well defined:
I wanted to implement a language server for the serverless framework, since this would bring all the features I need.

By the way, of course there are other ways to solve this, e.g. you could use the YAML language extension for VS Code and use a JSON schema for the serverless yml file.

In the beginning

To make one thing clear. I never developed a language server. That implies I had to do lots of researching before I could even think of any line of code. But even before trying to understand the language server protocol, I needed to define some capabilities I try to develop. You can't work on a project without a scope am I right? So lets see what my mind came up with.

First User Stories
First iteration of some user stories I had in mind


Let's do it

After some researching, I had a small overview, what I need to do.
As you may have already read between the lines, I am a VS Code sheep.
Therefore to keep the first iteration simple, I try to stay inside that environment.
And by that I mean, I fired up the yeoman generator for vs code extensions.

I tried to start easy. What I needed was the vscode-languageclient and the vscode-languageserver npm package.
When my extension is activated (latest activation point is when ever a serverless.yml file is opened) it will boot up a language client and server.
Those two processes will be communicating on different occasions, e.g. when a watched file does change or a user hovers over a symbol.
To see some action I was starting with a language server, that would always recommend to autocomplete the word service if a user starts to type the character 's'.

First Autocompletion

// This handler is triggered when a `textDocument/completion` request is received
connection.onCompletion(params => {
  // params equals the CompletionParams type.
  // Is ignored for this simple use case

  return [
    // List of CompletionItem
    {
      label: 'Service Definition',
      kind: CompletionItemKind.Text,
      detail: 'Some details to describe',
      // documentation is used for more information about an item
      documentation: {
        value: `[serverless framework](https://serverless.com)`,
        kind: MarkupKind.Markdown, // You can even use Markdown
      },
      insertText: 'service:',
    },
  ];
});
Enter fullscreen mode Exit fullscreen mode

For more information about the types, look into the specification

What seems to be unimpressive at the first sight, actually was quite some work. Including understanding the communication part between client and server. Helpful resources are the example implementation of a language server and the language server extension guide.
Now as the language client (in this case VS Code) and the language server (a process spawned by the extension) were successfully communicating, I was ready to workout out my first prototype.

In my future post I'll go more into details, how I implemented my first feature. The auto completion of a user-defined variable.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay