internal/lsp/protocol/typescript: update LSP generating code
code.ts and util.ts for the latest version of the LSP protocol.
Change-Id: I911254ee7e66d91071e465ed83c456975e358ca4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/288732
Trust: Peter Weinberger <pjw@google.com>
Trust: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/protocol/typescript/README.md b/internal/lsp/protocol/typescript/README.md
index 4780045..af813d9 100644
--- a/internal/lsp/protocol/typescript/README.md
+++ b/internal/lsp/protocol/typescript/README.md
@@ -5,7 +5,8 @@
Make sure `node` and `tsc` are installed and in your PATH. There are detailed instructions below.
Get the typescript code for the jsonrpc protocol with
-`git clone git@github.com:microsoft vscode-languageserver-node.git`
+`git clone git@github.com:microsoft vscode-languageserver-node.git` or
+`git clone https://github.com/microsoft/vscode-languageserver-node.git`
`util.ts`` expects it to be in your HOME directory
diff --git a/internal/lsp/protocol/typescript/code.ts b/internal/lsp/protocol/typescript/code.ts
index 7509532..095c52a 100644
--- a/internal/lsp/protocol/typescript/code.ts
+++ b/internal/lsp/protocol/typescript/code.ts
@@ -116,19 +116,6 @@
reqnot.set(rpc, newNode)
}
-// handle missing typeArguments
-function lookUp(n: ts.NewExpression): ts.NodeArray<ts.TypeNode> {
- // parent should be VariableDeclaration. its children should be
- // Identifier('type') ???
- // TypeReference: [Identifier('RequestType1), ]
- // NewExpression (us)
- const p = n.parent;
- if (!ts.isVariableDeclaration(p)) throw new Error(`not variable decl`);
- const tr = p.type;
- if (!ts.isTypeReferenceNode(tr)) throw new Error(`not TypeReference`);
- return tr.typeArguments;
-}
-
function setReceives() {
// mark them all as server, then adjust the client ones.
// it would be nice to have some independent check on this
@@ -215,15 +202,14 @@
// probably safe to ignore these
// [key: string]: boolean | number | string | undefined;
// and InitializeResult: [custom: string]: any;]
- return
} else
- throw new Error(`217 unexpected ${strKind(t)}`)
+ throw new Error(`206 unexpected ${strKind(t)}`);
};
v.members.forEach(f);
if (mems.length == 0 && !v.heritageClauses &&
v.name.getText() != 'InitializedParams') {
- return // really? (Don't seem to need any of these)
- };
+ return // Don't seem to need any of these [Logger, PipTransport, ...]
+ }
// Found one we want
let x = newData(v, goName(v.name.getText()));
x.properties = ts.createNodeArray<ts.TypeElement>(mems);
@@ -270,7 +256,7 @@
};
if (ts.isTypeAliasDeclaration(x) || ts.isModuleDeclaration(x)) {
return
- };
+ }
if (!ts.isVariableStatement(x))
throw new Error(
`expected VariableStatment ${loc(x)} ${strKind(x)} ${x.getText()}`);
@@ -298,7 +284,6 @@
} else if (ts.isClassDeclaration(node)) {
const v: ts.ClassDeclaration = node;
var d: ts.PropertyDeclaration[] = [];
- // look harder at the PropertyDeclarations.
const wanted = function (c: ts.ClassElement): string {
if (ts.isConstructorDeclaration(c)) {
return ''
@@ -318,10 +303,10 @@
};
throw new Error(`Class decl ${strKind(c)} `)
};
- v.members.forEach((c, i) => wanted(c));
+ v.members.forEach((c) => wanted(c));
if (d.length == 0) {
return
- }; // don't need it, maybe
+ } // don't need it
let c = newData(v, v.name.getText());
c.members = ts.createNodeArray<ts.PropertyDeclaration>(d);
if (v.typeParameters) {
@@ -337,7 +322,7 @@
throw new Error(`Class dup ${loc(c.me)} and ${loc(data.get(c.name).me)}`);
data.set(c.name, c);
} else {
- throw new Error(`338 unexpected ${strKind(node)} ${loc(node)} `)
+ throw new Error(`325 unexpected ${strKind(node)} ${loc(node)} `)
}
}
@@ -348,15 +333,16 @@
if (at == bt) {
return a;
}
- const ax = `(${a.statements.length},${a.properties.length})`
- const bx = `(${b.statements.length},${b.properties.length})`
switch (a.name) {
case 'InitializeError':
case 'MessageType':
case 'CompletionItemTag':
case 'SymbolTag':
case 'CodeActionKind':
- // want the Module
+ case 'Integer':
+ case 'Uinteger':
+ case 'Decimal':
+ // want the Module, if anything
return a.statements.length > 0 ? a : b;
case 'CancellationToken':
case 'CancellationStrategy':
@@ -364,11 +350,12 @@
return a.properties.length > 0 ? a : b;
case 'TextDocumentContentChangeEvent': // almost the same
case 'TokenFormat':
+ case 'PrepareSupportDefaultBehavior':
return a;
}
console.log(
- `367 ${strKind(a.me)} ${strKind(b.me)} ${a.name} ${loc(a.me)} ${loc(b.me)}`)
- throw new Error(`Fix dataMerge for ${a.name}`)
+ `357 ${strKind(a.me)} ${strKind(b.me)} ${a.name} ${loc(a.me)} ${loc(b.me)}`)
+ throw new Error(`Fix dataMerge for ${a.name}`);
}
// is a node an ancestor of a NewExpression
@@ -427,12 +414,11 @@
ts.isLiteralTypeNode(n) || ts.isVariableStatement(n) ||
ts.isTupleTypeNode(n)) {
// we only see these in moreTypes, but they are handled elsewhere
- return;
} else if (ts.isEnumMember(n)) {
if (ts.isStringLiteral(n.initializer)) return;
- throw new Error(`EnumMember ${strKind(n.initializer)} ${n.name.getText()}`)
+ throw new Error(`419 EnumMember ${strKind(n.initializer)} ${n.name.getText()}`)
} else {
- throw new Error(`saw ${strKind(n)} in underlying. ${n.getText()} at ${loc(n)}`)
+ throw new Error(`421 saw ${strKind(n)} in underlying. ${n.getText()} at ${loc(n)}`)
}
}
@@ -503,12 +489,28 @@
goInterface(d, nm);
} else
throw new Error(
- `more cases in toGo ${nm} ${d.as.length} ${d.generics.length} `)
+ `492 more cases in toGo ${nm} ${d.as.length} ${d.generics.length} `)
}
-// these fields need a *
+// these fields need a *. (making every optional struct indirect led to very
+// complex literals in gopls.)
+// As of Jan 2021 (3.16.0) consider (sent by server)
+// LocationLink.originSelectionRange // unused by gopls
+// Diagnostics.codeDescription
+// CreateFile.createFileOptions and .annotationID // unused by gopls
+// same for RenameFile and DeleteFile
+// InitializeResult.serverInfo // gopls always sets
+// InnerServerCapabilites.completionProvider, .signatureHelpProvider, .documentLinkProvider,
+// .executeCommandProvider, .Workspace // always set
+// InnerserverCapabilities.codeLensProvier, .DocumentOnTypeFormattingProvider // unused(?)
+// FileOperationPattern.options // unused
+// CompletionItem.command
+// Hover.Range (?)
+// CodeAction.disabled, .command
+// CodeLens.command
var starred: [string, string][] = [
['TextDocumentContentChangeEvent', 'range'], ['CodeAction', 'command'],
+ ['CodeAction', 'disabled'],
['DidSaveTextDocumentParams', 'text'], ['CompletionItem', 'command'],
['Diagnostic', 'codeDescription']
];
@@ -524,13 +526,13 @@
ans = ans.concat(getComments(n));
const json = u.JSON(n);
// SelectionRange is a recursive type
- let gt = goType(n.type, n.name.getText(), nm);
- if (gt == d.name) gt = '*' + gt; // avoid recursive types
+ let gt = goType(n.type, n.name.getText());
+ if (gt == d.name) gt = '*' + gt; // avoid recursive types (SelectionRange)
// there are several cases where a * is needed
starred.forEach(([a, b]) => {
if (d.name == a && n.name.getText() == b) {
gt = '*' + gt;
- };
+ }
})
ans = ans.concat(`${goName(n.name.getText())} ${gt}`, json, '\n');
};
@@ -543,7 +545,7 @@
ans = ans.concat(goName(n.expression.getText()), '\n')
};
d.as.forEach((n: ts.HeritageClause) => n.types.forEach(f))
- ans = ans.concat(`}\n`);
+ ans = ans.concat('}\n')
typesOut.push(getComments(d.me))
typesOut.push(ans)
}
@@ -552,7 +554,7 @@
// Generates type definitions, and named constants
function goModule(d: Data, nm: string) {
if (d.generics.length > 0 || d.as.length > 0) {
- throw new Error(`goModule: unexpected for ${nm}
+ throw new Error(`557 goModule: unexpected for ${nm}
`)
}
// all the statements should be export const <id>: value
@@ -562,14 +564,14 @@
let isNumeric = false;
const f = function (n: ts.Statement, i: number) {
if (!ts.isVariableStatement(n)) {
- throw new Error(` ${nm} ${i} expected VariableStatement,
+ throw new Error(`567 ${nm} ${i} expected VariableStatement,
got ${strKind(n)}`);
}
const c = getComments(n)
const v = n.declarationList.declarations[0]; // only one
if (!v.initializer)
- throw new Error(`no initializer ${nm} ${i} ${v.name.getText()}`);
+ throw new Error(`574 no initializer ${nm} ${i} ${v.name.getText()}`)
isNumeric = strKind(v.initializer) == 'NumericLiteral';
if (c != '') constsOut.push(c); // no point if there are no comments
// There are duplicates.
@@ -581,7 +583,7 @@
d.statements.forEach(f)
typesOut.push(getComments(d.me))
// Or should they be type aliases?
- typesOut.push(`type ${nm} ${isNumeric ? 'float64' : 'string'}`)
+ typesOut.push(`type ${nm} ${isNumeric ? 'float64' : 'string'}`) // PJW: superfluous Integer and Uinteger
}
// generate Go code for an enum. Both types and named constants
@@ -609,19 +611,29 @@
if (nm != 'ServerCapabilities')
throw new Error(`${nm} has extra fields(${d.as.length},${d.generics.length}) ${d.me.getText()}`);
}
- typesOut.push(getComments(d.me))
+ typesOut.push(getComments(d.me));
// d.alias doesn't seem to have comments
- let aliasStr = goName(nm) == 'DocumentURI' ? ' ' : ' = '
+ let aliasStr = goName(nm) == 'DocumentURI' ? ' ' : ' = ';
+ if (nm == 'PrepareSupportDefaultBehavior') {
+ // code-insiders is sending a bool, not a number. PJW: check this after Jan/2021
+ // (and gopls never looks at it anyway)
+ typesOut.push(`type ${goName(nm)}${aliasStr}interface{}\n`);
+ return;
+ }
typesOut.push(`type ${goName(nm)}${aliasStr}${goType(d.alias, nm)}\n`)
}
// return a go type and maybe an assocated javascript tag
-function goType(n: ts.TypeNode, nm: string, parent?: string): string {
+function goType(n: ts.TypeNode, nm: string): string {
if (n.getText() == 'T') return 'interface{}'; // should check it's generic
if (ts.isTypeReferenceNode(n)) {
- return goName(n.typeName.getText()); // avoid <T>
+ switch (n.getText()) {
+ case 'integer': return 'int32';
+ case 'uinteger': return 'uint32';
+ default: return goName(n.typeName.getText()); // avoid <T>
+ }
} else if (ts.isUnionTypeNode(n)) {
- return goUnionType(n, nm, parent);
+ return goUnionType(n, nm);
} else if (ts.isIntersectionTypeNode(n)) {
return goIntersectionType(n, nm);
} else if (strKind(n) == 'StringKeyword') {
@@ -662,7 +674,7 @@
// The choice is uniform interface{}, or some heuristically assigned choice,
// or some better sytematic idea I haven't thought of. Using interface{}
// is, in practice, impossibly complex in the existing code.
-function goUnionType(n: ts.UnionTypeNode, nm: string, parent?: string): string {
+function goUnionType(n: ts.UnionTypeNode, nm: string): string {
let help = `/*${n.getText()}*/` // show the original as a comment
// There are some bad cases with newlines:
// range?: boolean | {\n };
@@ -674,7 +686,7 @@
}
// handle all the special cases
switch (n.types.length) {
- case 2:
+ case 2: {
const a = strKind(n.types[0])
const b = strKind(n.types[1])
if (a == 'NumberKeyword' && b == 'StringKeyword') { // ID
@@ -686,7 +698,6 @@
return `[]CodeAction ${help}`
}
let v = goType(n.types[0], 'a')
- if (v.startsWith(`[]interface`)) v = v.slice(2, v.length)
return `${v} ${help}`
}
if (a == 'BooleanKeyword') { // usually want bool
@@ -698,29 +709,30 @@
}
if (b == 'ArrayType') return `${goType(n.types[1], 'c')} ${help}`;
if (help.includes('InsertReplaceEdit') && n.types[0].getText() == 'TextEdit') {
- return `*TextEdit ${help}`
+ return `*TextEdit ${help}`;
}
- if (a == 'TypeReference' && a == b) return `interface{} ${help}`;
+ if (a == 'TypeReference') {
+ if (nm == 'edits') return `${goType(n.types[0], '715')} ${help}`;
+ if (a == b) return `interface{} ${help}`;
+ if (nm == 'code') return `interface{} ${help}`;
+ }
if (a == 'StringKeyword') return `string ${help}`;
if (a == 'TypeLiteral' && nm == 'TextDocumentContentChangeEvent') {
return `${goType(n.types[0], nm)}`
}
- throw new Error(`691 ${a} ${b} ${n.getText()} ${loc(n)}`);
- case 3:
+ throw new Error(`709 ${a} ${b} ${n.getText()} ${loc(n)}`);
+ }
+ case 3: {
const aa = strKind(n.types[0])
const bb = strKind(n.types[1])
const cc = strKind(n.types[2])
- if (nm == 'textDocument/prepareRename') {
- // want Range, not interface{}
- return `${goType(n.types[0], nm)} ${help}`
- }
if (nm == 'DocumentFilter') {
// not really a union. the first is enough, up to a missing
// omitempty but avoid repetitious comments
return `${goType(n.types[0], 'g')}`
}
if (nm == 'textDocument/documentSymbol') {
- return `[]interface{} ${help}`
+ return `[]interface{} ${help}`;
}
if (aa == 'TypeReference' && bb == 'ArrayType' && cc == 'NullKeyword') {
return `${goType(n.types[0], 'd')} ${help}`
@@ -735,11 +747,12 @@
}
if (aa == 'LiteralType' && bb == aa && cc == aa) return `string ${help}`;
break;
+ }
case 4:
if (nm == 'documentChanges') return `TextDocumentEdit ${help} `;
if (nm == 'textDocument/prepareRename') return `Range ${help} `;
default:
- throw new Error(`goUnionType len=${n.types.length} nm=${nm}`)
+ throw new Error(`goUnionType len=${n.types.length} nm=${nm}`);
}
// Result will be interface{} with a comment
@@ -762,6 +775,7 @@
if (!isLiteral) {
return res + '*/';
}
+ // I don't think we get here
// trace?: 'off' | 'messages' | 'verbose' should get string
return `${literal} /* ${n.getText()} */`
}
@@ -772,14 +786,14 @@
// but much simpler just to check explicitly.
function goIntersectionType(n: ts.IntersectionTypeNode, nm: string): string {
if (nm == 'ClientCapabilities') return expandIntersection(n);
- if (nm == 'ServerCapabilities') return expandIntersection(n);
+ //if (nm == 'ServerCapabilities') return expandIntersection(n); // save for later consideration
let inner = '';
n.types.forEach(
- (t: ts.TypeNode) => { inner = inner.concat(goType(t, nm), '\n') });
+ (t: ts.TypeNode) => { inner = inner.concat(goType(t, nm), '\n'); })
return `struct{ \n${inner}} `
}
-// for each of the itersected types, extract its components (each will
+// for each of the intersected types, extract its components (each will
// have a Data with properties) extract the properties, and keep track
// of them by name. The names that occur once can be output. The names
// that occur more than once need to be combined.
@@ -819,10 +833,6 @@
ans = ans.concat(getComments(b));
ans = ans.concat(
goName(b.name.getText()), ' ', goType(b.type, 'a'), u.JSON(b), '\n')
- } else if (a.type.kind == ts.SyntaxKind.ObjectKeyword) {
- ans = ans.concat(getComments(a))
- ans = ans.concat(
- goName(a.name.getText()), ' ', 'interface{}', u.JSON(a), '\n')
} else {
throw bad(a.type, `E ${a.getText()} in ${goName(k)} at ${loc(a)}`)
}
@@ -835,7 +845,7 @@
function goTypeLiteral(n: ts.TypeLiteralNode, nm: string): string {
let ans: string[] = []; // in case we generate a new extra type
- let res = 'struct{\n' // the actual answer usually
+ let res = 'struct{\n'; // the actual answer usually
const g = function (nx: ts.TypeElement) {
// add the json, as in goInterface(). Strange inside union types.
if (ts.isPropertySignature(nx)) {
@@ -853,13 +863,18 @@
if (nx.getText() == '[uri: string]: TextEdit[];') {
res = 'map[string][]TextEdit';
ans.push(`map[string][]TextEdit`); // this is never used
+ return;
+ }
+ if (nx.getText() == '[id: string /* ChangeAnnotationIdentifier */]: ChangeAnnotation;') {
+ res = 'map[string]ChangeAnnotationIdentifier';
+ ans.push(res);
return
}
- throw new Error(` handle ${nx.getText()}`)
+ throw new Error(`873 handle ${nx.getText()} ${loc(nx)}`);
} else
throw new Error(`TypeLiteral had ${strKind(nx)}`)
};
- n.members.forEach(g)
+ n.members.forEach(g);
// for some the generated type is wanted, for others it's not needed
if (!nm.startsWith('workspace')) {
if (res.startsWith('struct')) return res + '}'; // map[] is special
@@ -876,7 +891,7 @@
v.sort();
v.forEach((x) => toGo(seenTypes.get(x), x))
u.prgo(u.computeHeader(true))
- u.prgo(`import "encoding/json"\n\n`);
+ u.prgo('import "encoding/json"\n\n');
typesOut.forEach((s) => {
u.prgo(s);
// it's more convenient not to have to think about trailing newlines
@@ -1097,11 +1112,11 @@
`);
const a = side.name[0].toUpperCase() + side.name.substring(1)
f(`type ${a} interface {`);
- side.methods.forEach((v) => { f(v) });
+ side.methods.forEach((v) => { f(v) })
f('}\n');
f(`func ${side.name}Dispatch(ctx context.Context, ${side.name} ${a}, reply jsonrpc2.Replier, r jsonrpc2.Request) (bool, error) {
switch r.Method() {`);
- side.cases.forEach((v) => { f(v) });
+ side.cases.forEach((v) => { f(v) })
f(`
default:
return false, nil
diff --git a/internal/lsp/protocol/typescript/util.ts b/internal/lsp/protocol/typescript/util.ts
index 5fdd563..5e0756a 100644
--- a/internal/lsp/protocol/typescript/util.ts
+++ b/internal/lsp/protocol/typescript/util.ts
@@ -14,7 +14,7 @@
`${dir}/${srcDir}/protocol/src/browser/main.ts`, `${dir}${srcDir}/types/src/main.ts`,
`${dir}${srcDir}/jsonrpc/src/node/main.ts`
];
-export const gitHash = '901fd40345060d159f07d234bbc967966a929a34'
+export const gitHash = 'dae62de921d25964e8732411ca09e532dde992f5'
let outFname = 'tsprotocol.go';
let fda: number, fdb: number, fde: number; // file descriptors
@@ -65,6 +65,11 @@
lastDate = st.mtime
}
}
+ const cp = `// Copyright 2019 The Go Authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ `
const a =
`// Package protocol contains data types and code for LSP jsonrpcs\n` +
`// generated automatically from vscode-languageserver-node\n` +
@@ -73,10 +78,10 @@
const b = 'package protocol\n'
const c = `\n// Code generated (see typescript/README.md) DO NOT EDIT.\n\n`
if (pkgDoc) {
- return a + b + c
+ return cp + a + b + c
}
else {
- return b + a + c
+ return cp + b + a + c
}
};
@@ -105,11 +110,12 @@
export function constName(nm: string, type: string): string {
let pref = new Map<string, string>([
['DiagnosticSeverity', 'Severity'], ['WatchKind', 'Watch'],
- ['SignatureHelpTriggerKind', 'Sig'], ['CompletionItemTag', 'Compl']
+ ['SignatureHelpTriggerKind', 'Sig'], ['CompletionItemTag', 'Compl'],
+ ['Integer', 'INT_'], ['Uinteger', 'UINT_']
]) // typeName->prefix
let suff = new Map<string, string>([
['CompletionItemKind', 'Completion'], ['InsertTextFormat', 'TextFormat'],
- ['SymbolTag', 'Symbol']
+ ['SymbolTag', 'Symbol'], ['FileOperationPatternKind', 'Op'],
])
let ans = nm;
if (pref.get(type)) ans = pref.get(type) + ans;