@@ -22,93 +22,6 @@ const String _typedDataImportUrl = 'dart:typed_data';
2222///
2323/// Outputs include .pb.dart, pbenum.dart, and .pbjson.dart.
2424class FileGenerator extends ProtobufContainer {
25- /// Reads and the declared mixins in the file, keyed by name.
26- ///
27- /// Performs some basic validation on declared mixins, e.g. whether names
28- /// are valid dart identifiers and whether there are cycles in the `parent`
29- /// hierarchy.
30- /// Does not check for existence of import files or classes.
31- static Map <String , PbMixin > _getDeclaredMixins (FileDescriptorProto desc) {
32- String mixinError (String error) =>
33- 'Option "mixins" in ${desc .name }: $error ' ;
34-
35- if (! desc.hasOptions () ||
36- ! desc.options.hasExtension (Dart_options .imports)) {
37- return < String , PbMixin > {};
38- }
39- final dartMixins = < String , DartMixin > {};
40- final importedMixins =
41- desc.options.getExtension (Dart_options .imports) as Imports ;
42- for (final mixin in importedMixins.mixins) {
43- if (dartMixins.containsKey (mixin .name)) {
44- throw mixinError ('Duplicate mixin name: "${mixin .name }"' );
45- }
46- if (! mixin .name.startsWith (_dartIdentifier)) {
47- throw mixinError (
48- '"${mixin .name }" is not a valid dart class identifier' ,
49- );
50- }
51- if (mixin .hasParent () && ! mixin .parent.startsWith (_dartIdentifier)) {
52- throw mixinError (
53- 'Mixin parent "${mixin .parent }" of "${mixin .name }" is '
54- 'not a valid dart class identifier' ,
55- );
56- }
57- dartMixins[mixin .name] = mixin ;
58- }
59-
60- // Detect cycles and unknown parents.
61- for (final mixin in dartMixins.values) {
62- if (! mixin .hasParent ()) continue ;
63- var currentMixin = mixin ;
64- final parentChain = < String > [];
65- while (currentMixin.hasParent ()) {
66- final parentName = currentMixin.parent;
67-
68- final declaredMixin = dartMixins.containsKey (parentName);
69- final internalMixin = ! declaredMixin && findMixin (parentName) != null ;
70-
71- if (internalMixin) break ; // No further validation of parent chain.
72-
73- if (! declaredMixin) {
74- throw mixinError (
75- 'Unknown mixin parent "${mixin .parent }" of '
76- '"${currentMixin .name }"' ,
77- );
78- }
79-
80- if (parentChain.contains (parentName)) {
81- final cycle = '${parentChain .join ('->' )}->$parentName ' ;
82- throw mixinError ('Cycle in parent chain: $cycle ' );
83- }
84- parentChain.add (parentName);
85- currentMixin = dartMixins[parentName]! ;
86- }
87- }
88-
89- // Turn DartMixins into PbMixins.
90- final pbMixins = < String , PbMixin > {};
91- PbMixin ? resolveMixin (String name) {
92- if (pbMixins.containsKey (name)) return pbMixins[name];
93- if (dartMixins.containsKey (name)) {
94- final dartMixin = dartMixins[name]! ;
95- final pbMixin = PbMixin (
96- dartMixin.name,
97- importFrom: dartMixin.importFrom,
98- parent: resolveMixin (dartMixin.parent),
99- );
100- pbMixins[name] = pbMixin;
101- return pbMixin;
102- }
103- return findMixin (name);
104- }
105-
106- for (final mixin in dartMixins.values) {
107- resolveMixin (mixin .name);
108- }
109- return pbMixins;
110- }
111-
11225 final FileDescriptorProto descriptor;
11326 final GenerationOptions options;
11427
@@ -124,16 +37,15 @@ class FileGenerator extends ProtobufContainer {
12437
12538 /// Used to avoid collisions after names have been mangled to match the Dart
12639 /// style.
127- final Set <String > usedTopLevelNames =
128- < String > {}..addAll (forbiddenTopLevelNames);
40+ final Set <String > usedTopLevelNames = < String > {...forbiddenTopLevelNames};
12941
13042 /// Used to avoid collisions in the service file after names have been mangled
13143 /// to match the dart style.
132- final Set <String > usedTopLevelServiceNames =
133- < String > {}..addAll (forbiddenTopLevelNames);
44+ final Set <String > usedTopLevelServiceNames = < String > {
45+ ...forbiddenTopLevelNames,
46+ };
13447
135- final Set <String > usedExtensionNames =
136- < String > {}..addAll (forbiddenExtensionNames);
48+ final Set <String > usedExtensionNames = < String > {...forbiddenExtensionNames};
13749
13850 /// Whether cross-references have been resolved.
13951 bool _linked = false ;
@@ -143,6 +55,23 @@ class FileGenerator extends ProtobufContainer {
14355 @override
14456 final FeatureSet features;
14557
58+ /// Maps imports in the current file to their import prefixes.
59+ /// E.g. in `import 'x/y/z.pb.dart' as $1` this maps `x/y/z.pb.dart` to `$1` .
60+ final Map <String , String > _importPrefixes = {};
61+
62+ /// Get the import prefix of `container` in the current file generator.
63+ ///
64+ /// Note that just calling this does not import the `container` in the current
65+ /// file. This just assigns an prefix to the container in the current file
66+ /// generator.
67+ String importPrefix (ProtobufContainer container) {
68+ final protoFilePath = container.fileGen! .protoFileUri.toString ();
69+ return _importPrefixes.putIfAbsent (
70+ protoFilePath,
71+ () => '\$ ${_importPrefixes .length }' ,
72+ );
73+ }
74+
14675 FileGenerator (
14776 FeatureSetDefaults editionDefaults,
14877 this .descriptor,
@@ -781,10 +710,7 @@ class FileGenerator extends ProtobufContainer {
781710 // evaluate to true not just for the main .pb.dart file based off the proto
782711 // file, but also for the .pbserver.dart, .pbgrpc.dart files.
783712 if (ext == '.pb.dart' || protoFileUri != target.protoFileUri) {
784- importWriter.addImport (
785- import,
786- prefix: target.importPrefix (context: fileGen),
787- );
713+ importWriter.addImport (import, prefix: fileGen.importPrefix (target));
788714 } else {
789715 importWriter.addImport (import);
790716 }
@@ -875,6 +801,89 @@ FeatureSet _getEditionDefaults(
875801 return defaults;
876802}
877803
804+ /// Reads and the declared mixins in the file, keyed by name.
805+ ///
806+ /// Performs some basic validation on declared mixins, e.g. whether names
807+ /// are valid dart identifiers and whether there are cycles in the `parent`
808+ /// hierarchy.
809+ /// Does not check for existence of import files or classes.
810+ Map <String , PbMixin > _getDeclaredMixins (FileDescriptorProto desc) {
811+ String mixinError (String error) => 'Option "mixins" in ${desc .name }: $error ' ;
812+
813+ if (! desc.hasOptions () || ! desc.options.hasExtension (Dart_options .imports)) {
814+ return < String , PbMixin > {};
815+ }
816+ final dartMixins = < String , DartMixin > {};
817+ final importedMixins =
818+ desc.options.getExtension (Dart_options .imports) as Imports ;
819+ for (final mixin in importedMixins.mixins) {
820+ if (dartMixins.containsKey (mixin .name)) {
821+ throw mixinError ('Duplicate mixin name: "${mixin .name }"' );
822+ }
823+ if (! mixin .name.startsWith (_dartIdentifier)) {
824+ throw mixinError ('"${mixin .name }" is not a valid dart class identifier' );
825+ }
826+ if (mixin .hasParent () && ! mixin .parent.startsWith (_dartIdentifier)) {
827+ throw mixinError (
828+ 'Mixin parent "${mixin .parent }" of "${mixin .name }" is '
829+ 'not a valid dart class identifier' ,
830+ );
831+ }
832+ dartMixins[mixin .name] = mixin ;
833+ }
834+
835+ // Detect cycles and unknown parents.
836+ for (final mixin in dartMixins.values) {
837+ if (! mixin .hasParent ()) continue ;
838+ var currentMixin = mixin ;
839+ final parentChain = < String > [];
840+ while (currentMixin.hasParent ()) {
841+ final parentName = currentMixin.parent;
842+
843+ final declaredMixin = dartMixins.containsKey (parentName);
844+ final internalMixin = ! declaredMixin && findMixin (parentName) != null ;
845+
846+ if (internalMixin) break ; // No further validation of parent chain.
847+
848+ if (! declaredMixin) {
849+ throw mixinError (
850+ 'Unknown mixin parent "${mixin .parent }" of '
851+ '"${currentMixin .name }"' ,
852+ );
853+ }
854+
855+ if (parentChain.contains (parentName)) {
856+ final cycle = '${parentChain .join ('->' )}->$parentName ' ;
857+ throw mixinError ('Cycle in parent chain: $cycle ' );
858+ }
859+ parentChain.add (parentName);
860+ currentMixin = dartMixins[parentName]! ;
861+ }
862+ }
863+
864+ // Turn DartMixins into PbMixins.
865+ final pbMixins = < String , PbMixin > {};
866+ PbMixin ? resolveMixin (String name) {
867+ if (pbMixins.containsKey (name)) return pbMixins[name];
868+ if (dartMixins.containsKey (name)) {
869+ final dartMixin = dartMixins[name]! ;
870+ final pbMixin = PbMixin (
871+ dartMixin.name,
872+ importFrom: dartMixin.importFrom,
873+ parent: resolveMixin (dartMixin.parent),
874+ );
875+ pbMixins[name] = pbMixin;
876+ return pbMixin;
877+ }
878+ return findMixin (name);
879+ }
880+
881+ for (final mixin in dartMixins.values) {
882+ resolveMixin (mixin .name);
883+ }
884+ return pbMixins;
885+ }
886+
878887const _fileIgnores = {
879888 'annotate_overrides' ,
880889 'camel_case_types' ,
0 commit comments