-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrpc.ts
153 lines (147 loc) · 4.82 KB
/
rpc.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import { ParseNode } from "./parsenode.ts";
import { Visitor } from "./visitor.ts";
import { nextTokenIs, Scanner, Token, TokenError } from "./deps.ts";
import { assignComments, expectSimpleIdent } from "./util.ts";
import { Type } from "./type.ts";
import { Option } from "./option.ts";
import { Comment } from "./comment.ts";
/**
* Represents an RPC method of a Service definition.
*
* https://developers.google.com/protocol-buffers/docs/reference/proto3-spec#service_definition
*/
export class RPC extends ParseNode {
constructor(
/**
* The name of the RPC method.
*/
public name: string,
/**
* The identifier of the Request object, and whether or not this is
* streaming.
*/
public request: { name: Type; streaming?: boolean },
/**
* The identifier of the Resonse object, and whether or not this is
* streaming.
*/
public response: { name: Type; streaming?: boolean },
/**
* A collection of direct child nodes in the RPC definition.
*/
public body: Option[] | null = [],
/**
* The starting [line, column]
*/
public start: [number, number] = [0, 0],
/**
* The ending [line, column]
*/
public end: [number, number] = [0, 0],
/**
* Any comment nodes directly above a RPC statement, or inside an RPC block
* that don't belong to one of the child nodes.
*/
public comments: Comment[] = [],
) {
super();
this.request.streaming = this.request.streaming || false;
this.response.streaming = this.response.streaming || false;
assignComments(this);
}
toProto() {
let comments = "";
if (this.comments.length) {
comments = this.comments.map((node) => node.toProto()).join("\n") + "\n";
}
let body = this.body ? " {}" : ";";
if (this.body && this.body.length) {
body = ` { \n ${
this.body.map((node) => node.toProto()).join("\n ")
}\n}`;
}
const request = this.request.streaming
? `stream ${this.request.name.toProto()}`
: this.request.name.toProto();
const response = this.response.streaming
? `stream ${this.response.name.toProto()}`
: this.response.name.toProto();
return `${comments}rpc ${this.name} (${request}) returns (${response})${body}`;
}
toJSON() {
return Object.assign(
{
type: "RPC",
start: this.start,
end: this.end,
name: this.name,
request: {
name: this.request.name.toJSON(),
streaming: this.request.streaming,
},
response: {
name: this.response.name.toJSON(),
streaming: this.response.streaming,
},
body: this.body?.map((node) => node.toJSON()) || null,
},
this.comments.length
? { comments: this.comments.map((node) => node.toJSON()) }
: {},
);
}
accept(visitor: Visitor) {
visitor.visit?.(this);
visitor.visitRPC?.(this);
this.request.name.accept(visitor);
this.response.name.accept(visitor);
for (const node of this.body || []) node.accept(visitor);
for (const node of this.comments) node.accept(visitor);
}
static async parse(scanner: Scanner): Promise<RPC> {
if (scanner.contents !== "rpc") {
await nextTokenIs(scanner, Token.keyword, "rpc");
}
const start = scanner.startPos;
const name = await expectSimpleIdent(scanner);
await nextTokenIs(scanner, Token.token, "(");
const request = {
name: await Type.parse(scanner),
streaming: false,
};
if (request.name.name === "stream") {
await nextTokenIs(scanner, Token.identifier);
request.streaming = true;
request.name = await Type.parse(scanner);
}
await nextTokenIs(scanner, Token.token, ")");
await nextTokenIs(scanner, Token.keyword, "returns");
await nextTokenIs(scanner, Token.token, "(");
const response = {
name: await Type.parse(scanner),
streaming: false,
};
if (response.name.name === "stream") {
await nextTokenIs(scanner, Token.identifier);
response.streaming = true;
response.name = await Type.parse(scanner);
}
await nextTokenIs(scanner, Token.token, ")");
const token = await nextTokenIs(scanner, Token.token);
if (token === ";") {
return new RPC(name, request, response, null, start, scanner.endPos);
} else if (token === "{") {
const body: Option[] = [];
for await (const token of scanner) {
const str = scanner.contents;
if (token === Token.token && str === "}") {
return new RPC(name, request, response, body, start, scanner.endPos);
} else if (token === Token.keyword && scanner.contents === "option") {
body.push(await Option.parse(scanner));
}
}
throw new TokenError(scanner, Token.eof);
}
throw new TokenError(scanner, Token.token, Token.token, "; or {");
}
}