Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: lib/file_generator.dart

Issue 2103743002: Rename mixin protos and add a check for undefined mixin name (Closed) Base URL: git@github.com:dart-lang/dart-protoc-plugin.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 final _dartIdentifier = new RegExp(r'^\w+$'); 7 final _dartIdentifier = new RegExp(r'^\w+$');
8 8
9 /// Generates the Dart output files for one .proto input file. 9 /// Generates the Dart output files for one .proto input file.
10 /// 10 ///
11 /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart. 11 /// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart.
12 class FileGenerator extends ProtobufContainer { 12 class FileGenerator extends ProtobufContainer {
13 /// Reads and the declared mixins in the file, keyed by name. 13 /// Reads and the declared mixins in the file, keyed by name.
14 /// 14 ///
15 /// Performs some basic validation on declared mixins, e.g. whether names 15 /// Performs some basic validation on declared mixins, e.g. whether names
16 /// are valid dart identifiers and whether there are cycles in the `parent` 16 /// are valid dart identifiers and whether there are cycles in the `parent`
17 /// hierarchy. 17 /// hierarchy.
18 /// Does not check for existence of import files or classes. 18 /// Does not check for existence of import files or classes.
19 static Map<String, PbMixin> _getDeclaredMixins(FileDescriptorProto desc) { 19 static Map<String, PbMixin> _getDeclaredMixins(FileDescriptorProto desc) {
20 String mixinError(String error) => 20 String mixinError(String error) =>
21 'Option "mixins" in file ${desc.name}: $error'; 21 'Option "mixins" in ${desc.name}: $error';
22 22
23 if (!desc.hasOptions() || 23 if (!desc.hasOptions() ||
24 !desc.options.hasExtension(Dart_options.importedMixins)) { 24 !desc.options.hasExtension(Dart_options.imports)) {
25 return <String, PbMixin>{}; 25 return <String, PbMixin>{};
26 } 26 }
27 var dartMixins = <String, DartMixin>{}; 27 var dartMixins = <String, DartMixin>{};
28 ImportedMixins importedMixins = 28 Imports importedMixins = desc.options.getExtension(Dart_options.imports);
frederikmutzel 2016/06/28 08:15:13 maybe rename the variable to imports as well?
skybrian 2016/06/28 08:40:34 Skipping for now.
29 desc.options.getExtension(Dart_options.importedMixins);
30 for (DartMixin mixin in importedMixins.mixins) { 29 for (DartMixin mixin in importedMixins.mixins) {
31 if (dartMixins.containsKey(mixin.name)) { 30 if (dartMixins.containsKey(mixin.name)) {
32 throw mixinError('Duplicate mixin name: "${mixin.name}"'); 31 throw mixinError('Duplicate mixin name: "${mixin.name}"');
33 } 32 }
34 if (!mixin.name.startsWith(_dartIdentifier)) { 33 if (!mixin.name.startsWith(_dartIdentifier)) {
35 throw mixinError( 34 throw mixinError(
36 '"${mixin.name}" is not a valid dart class identifier'); 35 '"${mixin.name}" is not a valid dart class identifier');
37 } 36 }
38 if (mixin.hasParent() && !mixin.parent.startsWith(_dartIdentifier)) { 37 if (mixin.hasParent() && !mixin.parent.startsWith(_dartIdentifier)) {
39 throw mixinError('Mixin parent "${mixin.parent}" of "${mixin.name}" is ' 38 throw mixinError('Mixin parent "${mixin.parent}" of "${mixin.name}" is '
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 return pbMixin; 81 return pbMixin;
83 } 82 }
84 return findMixin(name); 83 return findMixin(name);
85 } 84 }
86 for (var mixin in dartMixins.values) { 85 for (var mixin in dartMixins.values) {
87 resolveMixin(mixin.name); 86 resolveMixin(mixin.name);
88 } 87 }
89 return pbMixins; 88 return pbMixins;
90 } 89 }
91 90
92 final FileDescriptorProto _fileDescriptor; 91 final FileDescriptorProto descriptor;
93 92
94 // The relative path used to import the .proto file, as a URI. 93 // The relative path used to import the .proto file, as a URI.
95 final Uri protoFileUri; 94 final Uri protoFileUri;
96 95
97 final List<EnumGenerator> enumGenerators = <EnumGenerator>[]; 96 final List<EnumGenerator> enumGenerators = <EnumGenerator>[];
98 final List<MessageGenerator> messageGenerators = <MessageGenerator>[]; 97 final List<MessageGenerator> messageGenerators = <MessageGenerator>[];
99 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[]; 98 final List<ExtensionGenerator> extensionGenerators = <ExtensionGenerator>[];
100 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[]; 99 final List<ClientApiGenerator> clientApiGenerators = <ClientApiGenerator>[];
101 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[]; 100 final List<ServiceGenerator> serviceGenerators = <ServiceGenerator>[];
102 101
103 /// True if cross-references have been resolved. 102 /// True if cross-references have been resolved.
104 bool _linked = false; 103 bool _linked = false;
105 104
106 FileGenerator(FileDescriptorProto descriptor) 105 FileGenerator(FileDescriptorProto descriptor)
107 : _fileDescriptor = descriptor, 106 : descriptor = descriptor,
108 protoFileUri = new Uri.file(descriptor.name) { 107 protoFileUri = new Uri.file(descriptor.name) {
109 if (protoFileUri.isAbsolute) { 108 if (protoFileUri.isAbsolute) {
110 // protoc should never generate an import with an absolute path. 109 // protoc should never generate an import with an absolute path.
111 throw "FAILURE: Import with absolute path is not supported"; 110 throw "FAILURE: Import with absolute path is not supported";
112 } 111 }
113 112
114 var declaredMixins = _getDeclaredMixins(descriptor); 113 var declaredMixins = _getDeclaredMixins(descriptor);
115 var defaultMixinName = 114 var defaultMixinName =
116 descriptor.options?.getExtension(Dart_options.defaultMixin) ?? ''; 115 descriptor.options?.getExtension(Dart_options.defaultMixin) ?? '';
117 var defaultMixin = 116 var defaultMixin =
118 declaredMixins[defaultMixinName] ?? findMixin(defaultMixinName); 117 declaredMixins[defaultMixinName] ?? findMixin(defaultMixinName);
119 if (defaultMixin == null && defaultMixinName.isNotEmpty) { 118 if (defaultMixin == null && defaultMixinName.isNotEmpty) {
120 throw ('Option default_mixin on file ${descriptor.name}: Unknown mixin ' 119 throw ('Option default_mixin on file ${descriptor.name}: Unknown mixin '
121 '$defaultMixinName'); 120 '$defaultMixinName');
122 } 121 }
123 122
124 // Load and register all enum and message types. 123 // Load and register all enum and message types.
125 for (EnumDescriptorProto enumType in _fileDescriptor.enumType) { 124 for (EnumDescriptorProto enumType in descriptor.enumType) {
126 enumGenerators.add(new EnumGenerator(enumType, this)); 125 enumGenerators.add(new EnumGenerator(enumType, this));
127 } 126 }
128 for (DescriptorProto messageType in _fileDescriptor.messageType) { 127 for (DescriptorProto messageType in descriptor.messageType) {
129 messageGenerators.add(new MessageGenerator( 128 messageGenerators.add(new MessageGenerator(
130 messageType, this, declaredMixins, defaultMixin)); 129 messageType, this, declaredMixins, defaultMixin));
131 } 130 }
132 for (FieldDescriptorProto extension in _fileDescriptor.extension) { 131 for (FieldDescriptorProto extension in descriptor.extension) {
133 extensionGenerators.add(new ExtensionGenerator(extension, this)); 132 extensionGenerators.add(new ExtensionGenerator(extension, this));
134 } 133 }
135 for (ServiceDescriptorProto service in _fileDescriptor.service) { 134 for (ServiceDescriptorProto service in descriptor.service) {
136 var serviceGen = new ServiceGenerator(service, this); 135 var serviceGen = new ServiceGenerator(service, this);
137 serviceGenerators.add(serviceGen); 136 serviceGenerators.add(serviceGen);
138 clientApiGenerators.add(new ClientApiGenerator(serviceGen)); 137 clientApiGenerators.add(new ClientApiGenerator(serviceGen));
139 } 138 }
140 } 139 }
141 140
142 /// Creates the fields in each message. 141 /// Creates the fields in each message.
143 /// Resolves field types and extension targets using the supplied context. 142 /// Resolves field types and extension targets using the supplied context.
144 void resolve(GenerationContext ctx) { 143 void resolve(GenerationContext ctx) {
145 if (_linked) throw new StateError("cross references already resolved"); 144 if (_linked) throw new StateError("cross references already resolved");
146 145
147 for (var m in messageGenerators) { 146 for (var m in messageGenerators) {
148 m.resolve(ctx); 147 m.resolve(ctx);
149 } 148 }
150 for (var x in extensionGenerators) { 149 for (var x in extensionGenerators) {
151 x.resolve(ctx); 150 x.resolve(ctx);
152 } 151 }
153 152
154 _linked = true; 153 _linked = true;
155 } 154 }
156 155
157 String get package => _fileDescriptor.package; 156 String get package => descriptor.package;
158 String get classname => ''; 157 String get classname => '';
159 String get fqname => '.${_fileDescriptor.package}'; 158 String get fqname => '.${descriptor.package}';
160 FileGenerator get fileGen => this; 159 FileGenerator get fileGen => this;
161 160
162 // Extract the filename from a URI and remove the extension. 161 // Extract the filename from a URI and remove the extension.
163 String _fileNameWithoutExtension(Uri filePath) { 162 String _fileNameWithoutExtension(Uri filePath) {
164 String fileName = filePath.pathSegments.last; 163 String fileName = filePath.pathSegments.last;
165 int index = fileName.lastIndexOf("."); 164 int index = fileName.lastIndexOf(".");
166 return index == -1 ? fileName : fileName.substring(0, index); 165 return index == -1 ? fileName : fileName.substring(0, index);
167 } 166 }
168 167
169 String _generateClassName(Uri protoFilePath) { 168 String _generateClassName(Uri protoFilePath) {
170 String s = _fileNameWithoutExtension(protoFilePath).replaceAll('-', '_'); 169 String s = _fileNameWithoutExtension(protoFilePath).replaceAll('-', '_');
171 return '${s[0].toUpperCase()}${s.substring(1)}'; 170 return '${s[0].toUpperCase()}${s.substring(1)}';
172 } 171 }
173 172
174 /// Generates all the Dart files for this .proto file. 173 /// Generates all the Dart files for this .proto file.
175 List<CodeGeneratorResponse_File> generateFiles(OutputConfiguration config) { 174 List<CodeGeneratorResponse_File> generateFiles(OutputConfiguration config) {
176 if (!_linked) throw new StateError("not linked"); 175 if (!_linked) throw new StateError("not linked");
177 176
178 makeFile(String extension, String content) { 177 makeFile(String extension, String content) {
179 Uri protoUrl = new Uri.file(_fileDescriptor.name); 178 Uri protoUrl = new Uri.file(descriptor.name);
180 Uri dartUrl = config.outputPathFor(protoUrl, extension); 179 Uri dartUrl = config.outputPathFor(protoUrl, extension);
181 return new CodeGeneratorResponse_File() 180 return new CodeGeneratorResponse_File()
182 ..name = dartUrl.path 181 ..name = dartUrl.path
183 ..content = content; 182 ..content = content;
184 } 183 }
185 184
186 return [ 185 return [
187 makeFile(".pb.dart", generateMainFile(config)), 186 makeFile(".pb.dart", generateMainFile(config)),
188 makeFile(".pbenum.dart", generateEnumFile(config)), 187 makeFile(".pbenum.dart", generateEnumFile(config)),
189 makeFile(".pbserver.dart", generateServerFile(config)), 188 makeFile(".pbserver.dart", generateServerFile(config)),
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 return out.toString(); 227 return out.toString();
229 } 228 }
230 229
231 /// Writes the header and imports for the .pb.dart file. 230 /// Writes the header and imports for the .pb.dart file.
232 void writeMainHeader(IndentingWriter out, 231 void writeMainHeader(IndentingWriter out,
233 [OutputConfiguration config = const DefaultOutputConfiguration()]) { 232 [OutputConfiguration config = const DefaultOutputConfiguration()]) {
234 _writeLibraryHeading(out); 233 _writeLibraryHeading(out);
235 234
236 // We only add the dart:async import if there are services in the 235 // We only add the dart:async import if there are services in the
237 // FileDescriptorProto. 236 // FileDescriptorProto.
238 if (_fileDescriptor.service.isNotEmpty) { 237 if (descriptor.service.isNotEmpty) {
239 out.println("import 'dart:async';\n"); 238 out.println("import 'dart:async';\n");
240 } 239 }
241 240
242 if (_needsFixnumImport) { 241 if (_needsFixnumImport) {
243 out.println("import 'package:fixnum/fixnum.dart';"); 242 out.println("import 'package:fixnum/fixnum.dart';");
244 } 243 }
245 244
246 if (_needsProtobufImport) { 245 if (_needsProtobufImport) {
247 out.println("import 'package:protobuf/protobuf.dart';"); 246 out.println("import 'package:protobuf/protobuf.dart';");
248 out.println(); 247 out.println();
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 x.addConstantImportsTo(imports); 453 x.addConstantImportsTo(imports);
455 } 454 }
456 imports.remove(this); // Don't need to import self. 455 imports.remove(this); // Don't need to import self.
457 return imports; 456 return imports;
458 } 457 }
459 458
460 /// Writes the library name at the top of the dart file. 459 /// Writes the library name at the top of the dart file.
461 /// 460 ///
462 /// (This should be unique to avoid warnings about duplicate Dart libraries.) 461 /// (This should be unique to avoid warnings about duplicate Dart libraries.)
463 void _writeLibraryHeading(IndentingWriter out, [String extension]) { 462 void _writeLibraryHeading(IndentingWriter out, [String extension]) {
464 Uri filePath = new Uri.file(_fileDescriptor.name); 463 Uri filePath = new Uri.file(descriptor.name);
465 if (filePath.isAbsolute) { 464 if (filePath.isAbsolute) {
466 // protoc should never generate a file descriptor with an absolute path. 465 // protoc should never generate a file descriptor with an absolute path.
467 throw "FAILURE: File with an absolute path is not supported"; 466 throw "FAILURE: File with an absolute path is not supported";
468 } 467 }
469 468
470 var libraryName = _fileNameWithoutExtension(filePath).replaceAll('-', '_'); 469 var libraryName = _fileNameWithoutExtension(filePath).replaceAll('-', '_');
471 if (extension != null) libraryName += "_$extension"; 470 if (extension != null) libraryName += "_$extension";
472 if (_fileDescriptor.package != '') { 471 if (descriptor.package != '') {
473 // Two .protos can be in the same proto package. 472 // Two .protos can be in the same proto package.
474 // It isn't unique enough to use as a Dart library name. 473 // It isn't unique enough to use as a Dart library name.
475 // But we can prepend it. 474 // But we can prepend it.
476 libraryName = _fileDescriptor.package + "_" + libraryName; 475 libraryName = descriptor.package + "_" + libraryName;
477 } 476 }
478 out.println(''' 477 out.println('''
479 /// 478 ///
480 // Generated code. Do not modify. 479 // Generated code. Do not modify.
481 /// 480 ///
482 library $libraryName; 481 library $libraryName;
483 '''); 482 ''');
484 } 483 }
485 484
486 /// Writes an import of a .dart file corresponding to a .proto file. 485 /// Writes an import of a .dart file corresponding to a .proto file.
487 /// (Possibly the same .proto file.) 486 /// (Possibly the same .proto file.)
488 void _writeImport(IndentingWriter out, OutputConfiguration config, 487 void _writeImport(IndentingWriter out, OutputConfiguration config,
489 FileGenerator target, String extension) { 488 FileGenerator target, String extension) {
490 Uri resolvedImport = 489 Uri resolvedImport =
491 config.resolveImport(target.protoFileUri, protoFileUri, extension); 490 config.resolveImport(target.protoFileUri, protoFileUri, extension);
492 out.print("import '$resolvedImport'"); 491 out.print("import '$resolvedImport'");
493 if (package != target.package && target.package.isNotEmpty) { 492 if (package != target.package && target.package.isNotEmpty) {
494 out.print(' as ${target.packageImportPrefix}'); 493 out.print(' as ${target.packageImportPrefix}');
495 } 494 }
496 out.println(';'); 495 out.println(';');
497 } 496 }
498 } 497 }
OLDNEW
« no previous file with comments | « lib/code_generator.dart ('k') | lib/linker.dart » ('j') | lib/message_generator.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698