# Generate Go types and signatures for the LSP protocol

## Setup

1. Make sure `node` is installed.
  As explained at the [node site](<https://nodejs.org>)
  you may need `npm install @types/node` for the node runtime types
2. Install the typescript compiler, with `npm install typescript`
3. Make sure `tsc` and `node` are in your execution path.
4. Get the typescript code for the jsonrpc protocol with `git clone git@github.com:microsoft/vscode-languageserver-node.git`

## Usage

To generate the protocol types (x/tools/internal/lsp/protocol/tsprotocol.go)
```tsc go.ts && node go.js [-d dir] [-o out.go]```

and for simple checking

```gofmt -w out.go && golint out.go && go build out.go```

`-d dir` names the directory into which the `vscode-languageserver-node` repository was cloned.
It defaults to `$(HOME)`.

`-o out.go` says where the generated go code goes.
It defaults to `tsprotocol.go`.

To generate the client and server boilerplate (tsclient.go and tsserver.go)
```tsc requests.ts && node requests.js [-d dir] && gofmt -w tsclient.go tsserver.go```

-d dir is the same as above. The output files are written into the current directory.

## Notes

1. `go.ts` and `requests.ts` use the Typescript compiler's API, which is [introduced](https://github.com/Microsoft/TypeScript/wiki/Architectural-Overview) in their wiki.
2. Because the Typescript and Go type systems are incompatible, `go.ts ` and `request.ts` are filled with heuristics and special cases. Therefore they are tied to a specific commit of `vscode-languageserver-node`. The hash code of the commit is included in the header of `tsprotocol.go` and stored in the variable `gitHash` in `go.ts`. It is checked (see `git()` in `go.ts`) on every execution of `go.ts`.
3. Generating the `ts*.go` files is only semi-automated. Please file an issue if the released version is too far behind.
4. For the impatient, first change `gitHash` by hand (`git()` shows how to find the hash).
    1. Then try to run `go.ts` and  `requests.ts`. This will likely fail because the heuristics don't cover some new case. For instance, some simple type like `string` might have changed to a union type `string | [number,number]`. (Look at the `UnionTypeNode` code near line 588 of `go.ts`.) Another example is that some formal parameter generated by `requests.ts` will have anonymous structure type, which is essentially unusable. (See the code related to `ourTypes`.)
    1. Next step is to try to move the generated code to `internal/lsp/protocol` and try to build `gopls` and its tests. This will likely fail because types have changed. Generally the fixes are fairly easy. (The code for `ourTypes` was a case where changes had to be made to `requests.ts`.)
    1. Since there are not adequate integration tests, the next step is to run `gopls`. A common failure will be a nil dereference, because some previously simple default is now in an optional structure.