internal/lsp: new requests.ts to generate new versions of tsclient.go and tsserver.go

Adjust the output of requests.ts to use the new facilities of jsonrpc2.go.

Change-Id: I316f7846db9f683345b836915d992e751f126196
Reviewed-on: https://go-review.googlesource.com/c/tools/+/184081
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
pjw 2019-06-27 16:49:48 -07:00 committed by Peter Weinberger
parent 212fb13d59
commit 6cdbf07be9
1 changed files with 33 additions and 29 deletions

View File

@ -62,11 +62,15 @@ function generate(files: string[], options: ts.CompilerOptions): void {
// 2. serverHandler(...) { return func(...) { switch r.method}} // 2. serverHandler(...) { return func(...) { switch r.method}}
// 3. func (x *xDispatcher) Method(ctx, parm) // 3. func (x *xDispatcher) Method(ctx, parm)
not.forEach( not.forEach(
(v, k) => {receives.get(k) == 'client' ? goNot(client, k) : (v, k) => {
goNot(server, k)}); receives.get(k) == 'client' ? goNot(client, k) :
goNot(server, k)
});
req.forEach( req.forEach(
(v, k) => {receives.get(k) == 'client' ? goReq(client, k) : (v, k) => {
goReq(server, k)}); receives.get(k) == 'client' ? goReq(client, k) :
goReq(server, k)
});
// and print the Go code // and print the Go code
output(client); output(client);
output(server); output(server);
@ -94,7 +98,7 @@ function sig(nm: string, a: string, b: string, names?: boolean): string {
} }
const notNil = `if r.Params != nil { const notNil = `if r.Params != nil {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
return return
}`; }`;
// Go code for notifications. Side is client or server, m is the request method // Go code for notifications. Side is client or server, m is the request method
@ -109,7 +113,7 @@ function goNot(side: side, m: string) {
if (a != '') { if (a != '') {
case1 = `var params ${a} case1 = `var params ${a}
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
if err := ${side.name}.${nm}(ctx, &params); err != nil { if err := ${side.name}.${nm}(ctx, &params); err != nil {
@ -148,7 +152,7 @@ function goReq(side: side, m: string) {
if (a != '') { if (a != '') {
case1 = `var params ${a} case1 = `var params ${a}
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
}`; }`;
} }
@ -158,12 +162,12 @@ function goReq(side: side, m: string) {
}`; }`;
if (b != '') { if (b != '') {
case2 = `resp, err := ${side.name}.${nm}(ctx${arg2}) case2 = `resp, err := ${side.name}.${nm}(ctx${arg2})
if err := conn.Reply(ctx, r, resp, err); err != nil { if err := r.Reply(ctx, resp, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
}`; }`;
} else { // response is nil } else { // response is nil
case2 = `err := ${side.name}.${nm}(ctx${arg2}) case2 = `err := ${side.name}.${nm}(ctx${arg2})
if err := conn.Reply(ctx, r, nil, err); err != nil { if err := r.Reply(ctx, nil, err); err != nil {
log.Errorf(ctx, "%v", err) log.Errorf(ctx, "%v", err)
}` }`
} }
@ -206,7 +210,7 @@ function methodName(m: string): string {
function output(side: side) { function output(side: side) {
if (side.outputFile === undefined) side.outputFile = `ts${side.name}.go`; if (side.outputFile === undefined) side.outputFile = `ts${side.name}.go`;
side.fd = fs.openSync(side.outputFile, 'w'); side.fd = fs.openSync(side.outputFile, 'w');
const f = function(s: string) { const f = function (s: string) {
fs.writeSync(side.fd, s); fs.writeSync(side.fd, s);
fs.writeSync(side.fd, '\n'); fs.writeSync(side.fd, '\n');
}; };
@ -223,24 +227,24 @@ function output(side: side) {
`); `);
const a = side.name[0].toUpperCase() + side.name.substring(1) const a = side.name[0].toUpperCase() + side.name.substring(1)
f(`type ${a} interface {`); f(`type ${a} interface {`);
side.methods.forEach((v) => {f(v)}); side.methods.forEach((v) => { f(v) });
f('}\n'); f('}\n');
f(`func ${side.name}Handler(log xlog.Logger, ${side.name} ${ f(`func ${side.name}Handler(log xlog.Logger, ${side.name} ${
side.goName}) jsonrpc2.Handler { side.goName}) jsonrpc2.Handler {
return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) { return func(ctx context.Context, r *jsonrpc2.Request) {
switch r.Method { switch r.Method {
case "$/cancelRequest": case "$/cancelRequest":
var params CancelParams var params CancelParams
if err := json.Unmarshal(*r.Params, &params); err != nil { if err := json.Unmarshal(*r.Params, &params); err != nil {
sendParseError(ctx, log, conn, r, err) sendParseError(ctx, log, r, err)
return return
} }
conn.Cancel(params.ID)`); r.Conn().Cancel(params.ID)`);
side.cases.forEach((v) => {f(v)}); side.cases.forEach((v) => { f(v) });
f(` f(`
default: default:
if r.IsNotify() { if r.IsNotify() {
conn.Reply(ctx, r, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method)) r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method))
} }
} }
} }
@ -250,7 +254,7 @@ function output(side: side) {
*jsonrpc2.Conn *jsonrpc2.Conn
} }
`); `);
side.calls.forEach((v) => {f(v)}); side.calls.forEach((v) => { f(v) });
if (side.name == 'server') if (side.name == 'server')
f(` f(`
type CancelParams struct { type CancelParams struct {
@ -271,19 +275,19 @@ interface side {
fd?: number fd?: number
} }
let client: side = let client: side =
{methods: [], cases: [], calls: [], name: 'client', goName: 'Client'}; { methods: [], cases: [], calls: [], name: 'client', goName: 'Client' };
let server: side = let server: side =
{methods: [], cases: [], calls: [], name: 'server', goName: 'Server'}; { methods: [], cases: [], calls: [], name: 'server', goName: 'Server' };
let req = new Map<string, ts.NewExpression>(); // requests let req = new Map<string, ts.NewExpression>(); // requests
let not = new Map<string, ts.NewExpression>(); // notifications let not = new Map<string, ts.NewExpression>(); // notifications
let receives = new Map<string, 'server'|'client'>(); // who receives it let receives = new Map<string, 'server' | 'client'>(); // who receives it
function setReceives() { function setReceives() {
// mark them all as server, then adjust the client ones. // mark them all as server, then adjust the client ones.
// it would be nice to have some independent check // it would be nice to have some independent check
req.forEach((_, k) => {receives.set(k, 'server')}); req.forEach((_, k) => { receives.set(k, 'server') });
not.forEach((_, k) => {receives.set(k, 'server')}); not.forEach((_, k) => { receives.set(k, 'server') });
receives.set('window/logMessage', 'client'); receives.set('window/logMessage', 'client');
receives.set('telemetry/event', 'client'); receives.set('telemetry/event', 'client');
receives.set('client/registerCapability', 'client'); receives.set('client/registerCapability', 'client');
@ -321,7 +325,7 @@ function goType(m: string, n: ts.Node): string {
if (ts.isUnionTypeNode(n)) { if (ts.isUnionTypeNode(n)) {
let x: string[] = []; let x: string[] = [];
n.types.forEach( n.types.forEach(
(v) => {v.kind != ts.SyntaxKind.NullKeyword && x.push(goType(m, v))}); (v) => { v.kind != ts.SyntaxKind.NullKeyword && x.push(goType(m, v)) });
if (x.length == 1) return x[0]; if (x.length == 1) return x[0];
prb(`===========${m} ${x}`) prb(`===========${m} ${x}`)
@ -466,7 +470,7 @@ function main() {
} }
createOutputFiles() createOutputFiles()
generate( generate(
files, {target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS}); files, { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS });
} }
main() main()