@typespec/protobuf 0.49.0-dev.2 → 0.49.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.rush/temp/package-deps_build.json +29 -27
  2. package/.rush/temp/shrinkwrap-deps.json +41 -38
  3. package/dist/src/ast.d.ts +29 -8
  4. package/dist/src/ast.d.ts.map +1 -1
  5. package/dist/src/ast.js.map +1 -1
  6. package/dist/src/transform/index.d.ts.map +1 -1
  7. package/dist/src/transform/index.js +13 -2
  8. package/dist/src/transform/index.js.map +1 -1
  9. package/dist/src/write.d.ts +0 -6
  10. package/dist/src/write.d.ts.map +1 -1
  11. package/dist/src/write.js +63 -30
  12. package/dist/src/write.js.map +1 -1
  13. package/lib/proto.tsp +5 -0
  14. package/package.json +4 -4
  15. package/src/ast.ts +33 -8
  16. package/src/transform/index.ts +17 -1
  17. package/src/write.ts +81 -30
  18. package/temp/tsconfig.tsbuildinfo +1 -1
  19. package/test/scenarios/addressbook/output/@typespec/protobuf/addressbook.proto +1 -1
  20. package/test/scenarios/addressbook/output/@typespec/protobuf/main.proto +1 -1
  21. package/test/scenarios/anonymous-package/output/@typespec/protobuf/main.proto +1 -1
  22. package/test/scenarios/array/output/@typespec/protobuf/com/azure/test.proto +1 -1
  23. package/test/scenarios/cross package references/output/@typespec/protobuf/A.proto +1 -1
  24. package/test/scenarios/cross package references/output/@typespec/protobuf/B.proto +1 -1
  25. package/test/scenarios/derived-scalar/output/@typespec/protobuf/com/azure/Test.proto +1 -1
  26. package/test/scenarios/doc/input/main.tsp +67 -0
  27. package/test/scenarios/doc/output/@typespec/protobuf/com/azure/Test.proto +35 -0
  28. package/test/scenarios/empty/output/@typespec/protobuf/main.proto +1 -1
  29. package/test/scenarios/enum/output/@typespec/protobuf/main.proto +1 -1
  30. package/test/scenarios/extern/output/@typespec/protobuf/main.proto +1 -1
  31. package/test/scenarios/inferred-message-names/output/@typespec/protobuf/com/azure/test.proto +1 -1
  32. package/test/scenarios/intrinsics/output/@typespec/protobuf/com/azure/Test.proto +1 -1
  33. package/test/scenarios/map/output/@typespec/protobuf/main.proto +1 -1
  34. package/test/scenarios/name-collision/output/@typespec/protobuf/main.proto +1 -1
  35. package/test/scenarios/omit/output/@typespec/protobuf/main.proto +1 -1
  36. package/test/scenarios/omit-off/output/@typespec/protobuf/main.proto +1 -1
  37. package/test/scenarios/options/output/@typespec/protobuf/com/azure/Test.proto +1 -1
  38. package/test/scenarios/reserved fields/output/@typespec/protobuf/main.proto +1 -1
  39. package/test/scenarios/simple/output/@typespec/protobuf/com/azure/Test.proto +1 -1
  40. package/test/scenarios/simple-no-service/output/@typespec/protobuf/com/azure/Test.proto +1 -1
  41. package/test/scenarios/streams/output/@typespec/protobuf/main.proto +1 -1
  42. package/.rush/temp/operation/build/all.log +0 -1
  43. package/.rush/temp/operation/build/state.json +0 -3
package/src/write.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  matchType,
6
6
  ProtoDeclaration,
7
7
  ProtoEnumDeclaration,
8
+ ProtoEnumVariantDeclaration,
8
9
  ProtoFieldDeclaration,
9
10
  ProtoFile,
10
11
  ProtoMessageDeclaration,
@@ -17,21 +18,19 @@ import {
17
18
 
18
19
  // This module defines how to emit the text representation of a ProtoFile AST.
19
20
 
20
- /**
21
- * Header for the top of all emitted proto files.
22
- *
23
- * We only support Protobuf 3 syntax.
24
- */
25
- export const PROTO_HEADER = `/* Generated by Microsoft TypeSpec */
26
-
27
- syntax = "proto3";
28
- `;
21
+ const PROTO_MAX_ONE_LINE_DOC_LENGTH = 80;
29
22
 
30
23
  /**
31
24
  * Write the given `file` to a string.
32
25
  */
33
26
  export function writeProtoFile(file: ProtoFile): string {
34
- let result = PROTO_HEADER;
27
+ let result = "// Generated by Microsoft TypeSpec\n";
28
+
29
+ let docComment = collect(writeBlockDocumentationComment(file)).join("\n");
30
+ if (docComment.length > 0) docComment = "\n" + docComment;
31
+ result += docComment;
32
+
33
+ result += '\nsyntax = "proto3";\n';
35
34
 
36
35
  if (file.package) result += `\npackage ${file.package};\n`;
37
36
 
@@ -51,7 +50,7 @@ export function writeProtoFile(file: ProtoFile): string {
51
50
  if (opts.length > 0) result += "\n";
52
51
 
53
52
  for (const decl of file.declarations) {
54
- result += "\n" + collect(writeDeclaration(decl)).join("\n") + "\n";
53
+ result += "\n" + collect(writeDeclaration(decl, 0)).join("\n") + "\n";
55
54
  }
56
55
 
57
56
  return result;
@@ -60,25 +59,28 @@ export function writeProtoFile(file: ProtoFile): string {
60
59
  /**
61
60
  * Write the given `decl` to a line iterable.
62
61
  */
63
- function* writeDeclaration(decl: ProtoDeclaration): Iterable<string> {
62
+ function* writeDeclaration(decl: ProtoDeclaration, indentLevel: number): Iterable<string> {
64
63
  switch (decl.kind) {
65
64
  case "message":
66
- yield* writeMessage(decl);
65
+ yield* writeMessage(decl, indentLevel);
67
66
  return;
68
67
  case "service":
69
- yield* writeService(decl);
68
+ yield* writeService(decl, indentLevel);
70
69
  return;
71
70
  case "field":
72
- yield writeField(decl);
71
+ yield* writeField(decl, indentLevel);
73
72
  return;
74
73
  case "oneof":
75
- yield* writeOneOf(decl);
74
+ yield* writeOneOf(decl, indentLevel);
76
75
  return;
77
76
  case "enum":
78
- yield* writeEnum(decl);
77
+ yield* writeEnum(decl, indentLevel);
78
+ return;
79
+ case "variant":
80
+ yield* writeVariant(decl, indentLevel);
79
81
  return;
80
82
  case "method":
81
- yield writeMethod(decl);
83
+ yield* writeMethod(decl);
82
84
  return;
83
85
  /* c8 ignore next 5 */
84
86
  default:
@@ -90,14 +92,16 @@ function* writeDeclaration(decl: ProtoDeclaration): Iterable<string> {
90
92
  /**
91
93
  * Write the given message `decl` to a line iterable.
92
94
  */
93
- function* writeMessage(decl: ProtoMessageDeclaration): Iterable<string> {
95
+ function* writeMessage(decl: ProtoMessageDeclaration, indentLevel: number): Iterable<string> {
96
+ yield* writeBlockDocumentationComment(decl);
97
+
94
98
  const head = `message ${decl.name} {`;
95
99
  const tail = "}";
96
100
 
97
101
  if (decl.declarations.length > 0 || decl.reservations?.length) {
98
102
  yield head;
99
103
  yield* indent(writeReservations(decl));
100
- yield* indent(flatMap(decl.declarations, writeDeclaration));
104
+ yield* indent(flatMap(decl.declarations, (decl) => writeDeclaration(decl, indentLevel + 1)));
101
105
  yield tail;
102
106
  } else yield head + tail;
103
107
  }
@@ -119,49 +123,65 @@ function* writeReservations(decl: ProtoMessageDeclaration): Iterable<string> {
119
123
  }
120
124
  }
121
125
 
122
- function* writeService(decl: ProtoServiceDeclaration): Iterable<string> {
126
+ function* writeService(decl: ProtoServiceDeclaration, indentLevel: number): Iterable<string> {
127
+ yield* writeBlockDocumentationComment(decl);
128
+
123
129
  const head = `service ${decl.name} {`;
124
130
  const tail = "}";
125
131
 
126
132
  if (decl.operations.length > 0) {
127
133
  yield head;
128
- yield* indent(flatMap(decl.operations, writeDeclaration));
134
+ yield* indent(flatMap(decl.operations, (decl) => writeDeclaration(decl, indentLevel + 1)));
129
135
  yield tail;
130
136
  } else yield head + tail;
131
137
  }
132
138
 
133
- function writeMethod(decl: ProtoMethodDeclaration): string {
139
+ function* writeMethod(decl: ProtoMethodDeclaration): Iterable<string> {
140
+ yield* writeBlockDocumentationComment(decl);
141
+
134
142
  const [inStream, outStream] = [
135
143
  decl.stream & StreamingMode.In,
136
144
  decl.stream & StreamingMode.Out,
137
145
  ].map((v) => (v ? "stream " : ""));
138
146
 
139
- return `rpc ${decl.name}(${inStream}${writeType(decl.input)}) returns (${outStream}${writeType(
147
+ yield `rpc ${decl.name}(${inStream}${writeType(decl.input)}) returns (${outStream}${writeType(
140
148
  decl.returns
141
149
  )});`;
142
150
  }
143
151
 
144
- function* writeOneOf(decl: ProtoOneOfDeclaration): Iterable<string> {
152
+ function* writeOneOf(decl: ProtoOneOfDeclaration, indentLevel: number): Iterable<string> {
153
+ yield* writeBlockDocumentationComment(decl);
154
+
145
155
  // OneOf declarations must have at least one element, so no need to check for declarations
146
156
  yield `oneof ${decl.name} {`;
147
- yield* indent(flatMap(decl.declarations, writeDeclaration));
157
+ yield* indent(flatMap(decl.declarations, (decl) => writeDeclaration(decl, indentLevel + 1)));
148
158
  yield "}";
149
159
  }
150
160
 
151
- function* writeEnum(decl: ProtoEnumDeclaration): Iterable<string> {
161
+ function* writeEnum(decl: ProtoEnumDeclaration, indentLevel: number): Iterable<string> {
162
+ yield* writeBlockDocumentationComment(decl);
163
+
152
164
  yield `enum ${decl.name} {`;
153
165
  if (decl.allowAlias) {
154
166
  yield " option allow_alias = true;";
155
167
 
156
168
  if (decl.variants.length > 0) yield "";
157
169
  }
158
- yield* indent(flatMap(decl.variants, ([name, idx]) => `${name} = ${idx};`));
170
+ yield* indent(flatMap(decl.variants, (decl) => writeDeclaration(decl, indentLevel + 1)));
159
171
  yield "}";
160
172
  }
161
173
 
162
- function writeField(decl: ProtoFieldDeclaration): string {
174
+ function writeVariant(decl: ProtoEnumVariantDeclaration, indentLevel: number): Iterable<string> {
175
+ const output = `${decl.name} = ${decl.value};`;
176
+
177
+ return writeDocumentationCommentFlexible(decl, output, indentLevel);
178
+ }
179
+
180
+ function writeField(decl: ProtoFieldDeclaration, indentLevel: number): Iterable<string> {
163
181
  const prefix = decl.repeated ? "repeated " : "";
164
- return prefix + `${writeType(decl.type)} ${decl.name} = ${decl.index};`;
182
+ const output = prefix + `${writeType(decl.type)} ${decl.name} = ${decl.index};`;
183
+
184
+ return writeDocumentationCommentFlexible(decl, output, indentLevel);
165
185
  }
166
186
 
167
187
  function writeType(type: ProtoType): string {
@@ -189,6 +209,37 @@ function* indent(it: Iterable<string>, depth: number = 2): Iterable<string> {
189
209
  }
190
210
  }
191
211
 
212
+ /**
213
+ * Writes a block comment from the given declaration.
214
+ */
215
+ function* writeBlockDocumentationComment(decl: ProtoDeclaration | ProtoFile): Iterable<string> {
216
+ yield* decl.doc
217
+ ?.trim()
218
+ .split("\n")
219
+ .map((line) => `// ${line}`) ?? [];
220
+ }
221
+
222
+ /**
223
+ * Writes a block comment or inline postfix comment depending on the length of the content.
224
+ */
225
+ function* writeDocumentationCommentFlexible(
226
+ decl: ProtoDeclaration,
227
+ output: string,
228
+ indentLevel: number
229
+ ): Iterable<string> {
230
+ const docComment = decl.doc?.trim();
231
+ const docCommentIsOneLine = docComment && !docComment?.includes("\n");
232
+
233
+ const fullLength = indentLevel * 2 + output.length + 1 + (docComment?.length ?? 0);
234
+
235
+ if (docCommentIsOneLine && fullLength <= PROTO_MAX_ONE_LINE_DOC_LENGTH) {
236
+ yield output + " // " + decl.doc;
237
+ } else {
238
+ yield* writeBlockDocumentationComment(decl);
239
+ yield output;
240
+ }
241
+ }
242
+
192
243
  /**
193
244
  * A version of flatMap that works with generic iterables.
194
245
  *