OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of protoc; | 5 part of protoc; |
6 | 6 |
| 7 /// Generates the Dart output files for one .proto input file. |
| 8 /// |
| 9 /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart. |
7 class FileGenerator extends ProtobufContainer { | 10 class FileGenerator extends ProtobufContainer { |
8 /// Returns the the mixin to use by default in this file, | 11 /// Returns the the mixin to use by default in this file, |
9 /// or null for no mixin by default. | 12 /// or null for no mixin by default. |
10 static PbMixin _getDefaultMixin(FileDescriptorProto desc) { | 13 static PbMixin _getDefaultMixin(FileDescriptorProto desc) { |
11 if (!desc.hasOptions()) return null; | 14 if (!desc.hasOptions()) return null; |
12 if (!desc.options.hasExtension(Dart_options.defaultMixin)) { | 15 if (!desc.options.hasExtension(Dart_options.defaultMixin)) { |
13 return null; | 16 return null; |
14 } | 17 } |
15 var name = desc.options.getExtension(Dart_options.defaultMixin); | 18 var name = desc.options.getExtension(Dart_options.defaultMixin); |
16 PbMixin mixin = findMixin(name); | 19 PbMixin mixin = findMixin(name); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 if (_fileDescriptor.package != '') { | 107 if (_fileDescriptor.package != '') { |
105 // Two .protos can be in the same proto package. | 108 // Two .protos can be in the same proto package. |
106 // It isn't unique enough to use as a Dart library name. | 109 // It isn't unique enough to use as a Dart library name. |
107 // But we can prepend it. | 110 // But we can prepend it. |
108 return _fileDescriptor.package + "_" + libraryName; | 111 return _fileDescriptor.package + "_" + libraryName; |
109 } | 112 } |
110 | 113 |
111 return libraryName; | 114 return libraryName; |
112 } | 115 } |
113 | 116 |
114 CodeGeneratorResponse_File generateResponse(OutputConfiguration config) { | 117 /// Generates all the Dart files for this .proto file. |
| 118 List<CodeGeneratorResponse_File> generateFiles(OutputConfiguration config) { |
| 119 if (!_linked) throw new StateError("not linked"); |
| 120 |
| 121 makeFile(String extension, String content) { |
| 122 Uri protoUrl = new Uri.file(_fileDescriptor.name); |
| 123 Uri dartUrl = config.outputPathFor(protoUrl, extension); |
| 124 return new CodeGeneratorResponse_File() |
| 125 ..name = dartUrl.path |
| 126 ..content = content; |
| 127 } |
| 128 |
| 129 return [ |
| 130 makeFile(".pb.dart", generateMainFile(config)), |
| 131 makeFile(".pbenum.dart", generateEnumFile(config)), |
| 132 makeFile(".pbjson.dart", generateJsonFile(config)), |
| 133 ]; |
| 134 } |
| 135 |
| 136 /// Returns the contents of the .pb.dart file for this .proto file. |
| 137 String generateMainFile( |
| 138 [OutputConfiguration config = const DefaultOutputConfiguration()]) { |
| 139 if (!_linked) throw new StateError("not linked"); |
115 IndentingWriter out = new IndentingWriter(); | 140 IndentingWriter out = new IndentingWriter(); |
116 | 141 |
117 generate(out, config); | 142 writeMainHeader(out, config); |
118 | |
119 Uri filePath = new Uri.file(_fileDescriptor.name); | |
120 return new CodeGeneratorResponse_File() | |
121 ..name = config.outputPathFor(filePath, ".pb.dart").path | |
122 ..content = out.toString(); | |
123 } | |
124 | |
125 /// Generates the Dart code for this .proto file. | |
126 void generate(IndentingWriter out, | |
127 [OutputConfiguration config = const DefaultOutputConfiguration()]) { | |
128 if (!_linked) throw new StateError("not linked"); | |
129 | |
130 generateHeader(out, config); | |
131 | 143 |
132 // Generate code. | 144 // Generate code. |
133 for (MessageGenerator m in messageGenerators) { | 145 for (MessageGenerator m in messageGenerators) { |
134 m.generate(out); | 146 m.generate(out); |
135 } | 147 } |
136 | 148 |
137 // Generate code for extensions defined at top-level using a class | 149 // Generate code for extensions defined at top-level using a class |
138 // name derived from the file name. | 150 // name derived from the file name. |
139 if (!extensionGenerators.isEmpty) { | 151 if (!extensionGenerators.isEmpty) { |
140 // TODO(antonm): do not generate a class. | 152 // TODO(antonm): do not generate a class. |
(...skipping 10 matching lines...) Expand all Loading... |
151 out.println('}'); | 163 out.println('}'); |
152 }); | 164 }); |
153 } | 165 } |
154 | 166 |
155 for (ClientApiGenerator c in clientApiGenerators) { | 167 for (ClientApiGenerator c in clientApiGenerators) { |
156 c.generate(out); | 168 c.generate(out); |
157 } | 169 } |
158 for (ServiceGenerator s in serviceGenerators) { | 170 for (ServiceGenerator s in serviceGenerators) { |
159 s.generate(out); | 171 s.generate(out); |
160 } | 172 } |
| 173 |
| 174 return out.toString(); |
161 } | 175 } |
162 | 176 |
163 /// Prints header and imports. | 177 /// Writes the header and imports for the .pb.dart file. |
164 void generateHeader(IndentingWriter out, | 178 void writeMainHeader(IndentingWriter out, |
165 [OutputConfiguration config = const DefaultOutputConfiguration()]) { | 179 [OutputConfiguration config = const DefaultOutputConfiguration()]) { |
166 String libraryName = _generateLibraryName(protoFileUri); | 180 String libraryName = _generateLibraryName(protoFileUri); |
167 out.println('///\n' | 181 out.println('///\n' |
168 '// Generated code. Do not modify.\n' | 182 '// Generated code. Do not modify.\n' |
169 '///\n' | 183 '///\n' |
170 'library $libraryName;\n'); | 184 'library $libraryName;\n'); |
171 | 185 |
172 // We only add the dart:async import if there are services in the | 186 // We only add the dart:async import if there are services in the |
173 // FileDescriptorProto. | 187 // FileDescriptorProto. |
174 if (_fileDescriptor.service.isNotEmpty) { | 188 if (_fileDescriptor.service.isNotEmpty) { |
175 out.println("import 'dart:async';\n"); | 189 out.println("import 'dart:async';\n"); |
176 } | 190 } |
177 | 191 |
178 if (_needsFixnumImport) { | 192 if (_needsFixnumImport) { |
179 out.println("import 'package:fixnum/fixnum.dart';"); | 193 out.println("import 'package:fixnum/fixnum.dart';"); |
180 } | 194 } |
181 | 195 |
182 if (_needsProtobufImport) { | 196 if (_needsProtobufImport) { |
183 out.println("import 'package:protobuf/protobuf.dart';"); | 197 out.println("import 'package:protobuf/protobuf.dart';"); |
184 out.println(); | 198 out.println(); |
185 } | 199 } |
186 | 200 |
187 var mixinImports = findMixinsToImport(); | 201 var mixinImports = findMixinsToImport(); |
188 var importNames = mixinImports.keys.toList(); | 202 var importNames = mixinImports.keys.toList(); |
189 importNames.sort(); | 203 importNames.sort(); |
190 for (var imp in importNames) { | 204 for (var imp in importNames) { |
191 var symbols = mixinImports[imp]; | 205 var symbols = mixinImports[imp]; |
192 out.println("import '${imp}' show ${symbols.join(', ')};"); | 206 out.println("import '${imp}' show ${symbols.join(', ')};"); |
193 } | 207 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 symbols.add(m.name); | 299 symbols.add(m.name); |
286 } | 300 } |
287 | 301 |
288 for (var imp in imports.keys) { | 302 for (var imp in imports.keys) { |
289 imports[imp].sort(); | 303 imports[imp].sort(); |
290 } | 304 } |
291 | 305 |
292 return imports; | 306 return imports; |
293 } | 307 } |
294 | 308 |
295 CodeGeneratorResponse_File generateEnumResponse(OutputConfiguration config) { | 309 /// Returns the contents of the .pbenum.dart file for this .proto file. |
| 310 String generateEnumFile( |
| 311 [OutputConfiguration config = const DefaultOutputConfiguration()]) { |
296 if (!_linked) throw new StateError("not linked"); | 312 if (!_linked) throw new StateError("not linked"); |
297 | |
298 IndentingWriter out = new IndentingWriter(); | |
299 | |
300 generateEnumFile(out, config); | |
301 | |
302 Uri filePath = new Uri.file(_fileDescriptor.name); | |
303 return new CodeGeneratorResponse_File() | |
304 ..name = config.outputPathFor(filePath, ".pbenum.dart").path | |
305 ..content = out.toString(); | |
306 } | |
307 | |
308 void generateEnumFile(IndentingWriter out, | |
309 [OutputConfiguration config = const DefaultOutputConfiguration()]) { | |
310 Uri filePath = new Uri.file(_fileDescriptor.name); | 313 Uri filePath = new Uri.file(_fileDescriptor.name); |
311 if (filePath.isAbsolute) { | 314 if (filePath.isAbsolute) { |
312 // protoc should never generate a file descriptor with an absolute path. | 315 // protoc should never generate a file descriptor with an absolute path. |
313 throw "FAILURE: File with an absolute path is not supported"; | 316 throw "FAILURE: File with an absolute path is not supported"; |
314 } | 317 } |
315 | 318 |
316 var baseLibraryName = _generateLibraryName(filePath); | 319 var baseLibraryName = _generateLibraryName(filePath); |
317 var libraryName = baseLibraryName + "_pbenum"; | 320 var libraryName = baseLibraryName + "_pbenum"; |
| 321 var out = new IndentingWriter(); |
318 out.print(''' | 322 out.print(''' |
319 /// | 323 /// |
320 // Generated code. Do not modify. | 324 // Generated code. Do not modify. |
321 /// | 325 /// |
322 library $libraryName; | 326 library $libraryName; |
323 | 327 |
324 '''); | 328 '''); |
325 | 329 |
326 if (enumCount > 0) { | 330 if (enumCount > 0) { |
327 out.println("import 'package:protobuf/protobuf.dart';"); | 331 out.println("import 'package:protobuf/protobuf.dart';"); |
328 out.println(); | 332 out.println(); |
329 } | 333 } |
330 | 334 |
331 for (EnumGenerator e in enumGenerators) { | 335 for (EnumGenerator e in enumGenerators) { |
332 e.generate(out); | 336 e.generate(out); |
333 } | 337 } |
334 | 338 |
335 for (MessageGenerator m in messageGenerators) { | 339 for (MessageGenerator m in messageGenerators) { |
336 m.generateEnums(out); | 340 m.generateEnums(out); |
337 } | 341 } |
| 342 |
| 343 return out.toString(); |
338 } | 344 } |
339 | 345 |
340 /// Returns the number of enum types generated in the .pbenum.dart file. | 346 /// Returns the number of enum types generated in the .pbenum.dart file. |
341 int get enumCount { | 347 int get enumCount { |
342 var count = enumGenerators.length; | 348 var count = enumGenerators.length; |
343 for (MessageGenerator m in messageGenerators) { | 349 for (MessageGenerator m in messageGenerators) { |
344 count += m.enumCount; | 350 count += m.enumCount; |
345 } | 351 } |
346 return count; | 352 return count; |
347 } | 353 } |
348 | 354 |
349 CodeGeneratorResponse_File generateJsonDartResponse( | 355 /// Returns the contents of the .pbjson.dart file for this .proto file. |
350 OutputConfiguration config) { | 356 String generateJsonFile( |
| 357 [OutputConfiguration config = const DefaultOutputConfiguration()]) { |
351 if (!_linked) throw new StateError("not linked"); | 358 if (!_linked) throw new StateError("not linked"); |
352 | |
353 IndentingWriter out = new IndentingWriter(); | |
354 | |
355 generateJsonDart(out, config); | |
356 | |
357 Uri filePath = new Uri.file(_fileDescriptor.name); | |
358 return new CodeGeneratorResponse_File() | |
359 ..name = config.outputPathFor(filePath, ".pbjson.dart").path | |
360 ..content = out.toString(); | |
361 } | |
362 | |
363 void generateJsonDart(IndentingWriter out, | |
364 [OutputConfiguration config = const DefaultOutputConfiguration()]) { | |
365 Uri filePath = new Uri.file(_fileDescriptor.name); | 359 Uri filePath = new Uri.file(_fileDescriptor.name); |
366 if (filePath.isAbsolute) { | 360 if (filePath.isAbsolute) { |
367 // protoc should never generate a file descriptor with an absolute path. | 361 // protoc should never generate a file descriptor with an absolute path. |
368 throw "FAILURE: File with an absolute path is not supported"; | 362 throw "FAILURE: File with an absolute path is not supported"; |
369 } | 363 } |
370 | 364 |
371 var baseLibraryName = _generateLibraryName(filePath); | 365 var baseLibraryName = _generateLibraryName(filePath); |
372 var libraryName = baseLibraryName + "_pbjson"; | 366 var libraryName = baseLibraryName + "_pbjson"; |
| 367 var out = new IndentingWriter(); |
373 out.print(''' | 368 out.print(''' |
374 /// | 369 /// |
375 // Generated code. Do not modify. | 370 // Generated code. Do not modify. |
376 /// | 371 /// |
377 library $libraryName; | 372 library $libraryName; |
378 | 373 |
379 '''); | 374 '''); |
380 | 375 |
381 // Import the .pbjson.dart files we depend on. | 376 // Import the .pbjson.dart files we depend on. |
382 var importList = _findJsonProtosToImport(); | 377 var importList = _findJsonProtosToImport(); |
(...skipping 10 matching lines...) Expand all Loading... |
393 | 388 |
394 for (var e in enumGenerators) { | 389 for (var e in enumGenerators) { |
395 e.generateConstants(out); | 390 e.generateConstants(out); |
396 } | 391 } |
397 for (MessageGenerator m in messageGenerators) { | 392 for (MessageGenerator m in messageGenerators) { |
398 m.generateConstants(out); | 393 m.generateConstants(out); |
399 } | 394 } |
400 for (ServiceGenerator s in serviceGenerators) { | 395 for (ServiceGenerator s in serviceGenerators) { |
401 s.generateConstants(out); | 396 s.generateConstants(out); |
402 } | 397 } |
| 398 |
| 399 return out.toString(); |
403 } | 400 } |
404 | 401 |
405 /// Returns the generator for each .pbjson.dart file the generated | 402 /// Returns the generator for each .pbjson.dart file the generated |
406 /// .pbjson.dart needs to import. | 403 /// .pbjson.dart needs to import. |
407 Set<FileGenerator> _findJsonProtosToImport() { | 404 Set<FileGenerator> _findJsonProtosToImport() { |
408 var imports = new Set<FileGenerator>.identity(); | 405 var imports = new Set<FileGenerator>.identity(); |
409 for (var m in messageGenerators) { | 406 for (var m in messageGenerators) { |
410 m.addConstantImportsTo(imports); | 407 m.addConstantImportsTo(imports); |
411 } | 408 } |
412 for (var x in extensionGenerators) { | 409 for (var x in extensionGenerators) { |
413 x.addConstantImportsTo(imports); | 410 x.addConstantImportsTo(imports); |
414 } | 411 } |
415 for (var x in serviceGenerators) { | 412 for (var x in serviceGenerators) { |
416 x.addConstantImportsTo(imports); | 413 x.addConstantImportsTo(imports); |
417 } | 414 } |
418 imports.remove(this); // Don't need to import self. | 415 imports.remove(this); // Don't need to import self. |
419 return imports; | 416 return imports; |
420 } | 417 } |
421 } | 418 } |
OLD | NEW |