protobuf_parse/pure/convert/
mod.rs

1//! Convert parser model to rust-protobuf model
2
3mod option_resolver;
4mod type_resolver;
5
6use protobuf::descriptor::descriptor_proto::ReservedRange;
7use protobuf::descriptor::enum_descriptor_proto::EnumReservedRange;
8use protobuf::descriptor::field_descriptor_proto;
9use protobuf::descriptor::field_descriptor_proto::Type;
10use protobuf::descriptor::FieldDescriptorProto;
11use protobuf::descriptor::OneofDescriptorProto;
12use protobuf::reflect::FileDescriptor;
13use protobuf_support::json_name::json_name;
14use protobuf_support::text_format::escape_bytes_to;
15
16use crate::case_convert::camel_case;
17use crate::path::fs_path_to_proto_path;
18use crate::proto_path::ProtoPath;
19use crate::protobuf_abs_path::ProtobufAbsPath;
20use crate::protobuf_ident::ProtobufIdent;
21use crate::pure::convert::option_resolver::OptionResoler;
22use crate::pure::convert::option_resolver::ProtobufOptions;
23use crate::pure::convert::type_resolver::MessageOrEnum;
24use crate::pure::convert::type_resolver::TypeResolver;
25use crate::pure::model;
26use crate::FileDescriptorPair;
27use crate::ProtobufAbsPathRef;
28use crate::ProtobufIdentRef;
29
30#[derive(Debug, thiserror::Error)]
31enum ConvertError {
32    #[error("default value is not a string literal")]
33    DefaultValueIsNotStringLiteral,
34    #[error("expecting a message for name {0}")]
35    ExpectingMessage(ProtobufAbsPath),
36    #[error("expecting an enum for name {0}")]
37    ExpectingEnum(ProtobufAbsPath),
38}
39
40pub struct WithFullName<T> {
41    full_name: ProtobufAbsPath,
42    t: T,
43}
44
45#[derive(Debug, PartialEq)]
46enum TypeResolved {
47    Int32,
48    Int64,
49    Uint32,
50    Uint64,
51    Sint32,
52    Sint64,
53    Bool,
54    Fixed64,
55    Sfixed64,
56    Double,
57    String,
58    Bytes,
59    Fixed32,
60    Sfixed32,
61    Float,
62    Message(ProtobufAbsPath),
63    Enum(ProtobufAbsPath),
64    Group(ProtobufAbsPath),
65}
66
67impl TypeResolved {
68    fn from_field(field: &FieldDescriptorProto) -> TypeResolved {
69        match field.type_() {
70            Type::TYPE_DOUBLE => TypeResolved::Double,
71            Type::TYPE_FLOAT => TypeResolved::Float,
72            Type::TYPE_INT64 => TypeResolved::Int64,
73            Type::TYPE_UINT64 => TypeResolved::Uint64,
74            Type::TYPE_INT32 => TypeResolved::Int32,
75            Type::TYPE_FIXED64 => TypeResolved::Fixed64,
76            Type::TYPE_FIXED32 => TypeResolved::Fixed32,
77            Type::TYPE_UINT32 => TypeResolved::Uint32,
78            Type::TYPE_SFIXED32 => TypeResolved::Sfixed32,
79            Type::TYPE_SFIXED64 => TypeResolved::Sfixed64,
80            Type::TYPE_SINT32 => TypeResolved::Sint32,
81            Type::TYPE_SINT64 => TypeResolved::Sint64,
82            Type::TYPE_BOOL => TypeResolved::Bool,
83            Type::TYPE_STRING => TypeResolved::String,
84            Type::TYPE_BYTES => TypeResolved::Bytes,
85            Type::TYPE_GROUP => {
86                assert!(!field.type_name().is_empty());
87                TypeResolved::Group(ProtobufAbsPath::new(field.type_name()))
88            }
89            Type::TYPE_ENUM => {
90                assert!(!field.type_name().is_empty());
91                TypeResolved::Enum(ProtobufAbsPath::new(field.type_name()))
92            }
93            Type::TYPE_MESSAGE => {
94                assert!(!field.type_name().is_empty());
95                TypeResolved::Message(ProtobufAbsPath::new(field.type_name()))
96            }
97        }
98    }
99
100    fn type_enum(&self) -> Type {
101        match self {
102            TypeResolved::Bool => Type::TYPE_BOOL,
103            TypeResolved::Int32 => Type::TYPE_INT32,
104            TypeResolved::Int64 => Type::TYPE_INT64,
105            TypeResolved::Uint32 => Type::TYPE_UINT32,
106            TypeResolved::Uint64 => Type::TYPE_UINT64,
107            TypeResolved::Sint32 => Type::TYPE_SINT32,
108            TypeResolved::Sint64 => Type::TYPE_SINT64,
109            TypeResolved::Fixed32 => Type::TYPE_FIXED32,
110            TypeResolved::Fixed64 => Type::TYPE_FIXED64,
111            TypeResolved::Sfixed32 => Type::TYPE_SFIXED32,
112            TypeResolved::Sfixed64 => Type::TYPE_SFIXED64,
113            TypeResolved::Float => Type::TYPE_FLOAT,
114            TypeResolved::Double => Type::TYPE_DOUBLE,
115            TypeResolved::String => Type::TYPE_STRING,
116            TypeResolved::Bytes => Type::TYPE_BYTES,
117            TypeResolved::Message(_) => Type::TYPE_MESSAGE,
118            TypeResolved::Enum(_) => Type::TYPE_ENUM,
119            TypeResolved::Group(_) => Type::TYPE_GROUP,
120        }
121    }
122
123    fn type_name(&self) -> Option<&ProtobufAbsPath> {
124        match self {
125            TypeResolved::Message(t) | TypeResolved::Enum(t) | TypeResolved::Group(t) => Some(t),
126            _ => None,
127        }
128    }
129}
130
131pub(crate) struct Resolver<'a> {
132    type_resolver: TypeResolver<'a>,
133    current_file: &'a model::FileDescriptor,
134}
135
136impl<'a> Resolver<'a> {
137    fn map_entry_name_for_field_name(field_name: &str) -> ProtobufIdent {
138        // Field name and message name must match, otherwise
139        // Google's validation fails.
140        // https://git.io/JeOvF
141        ProtobufIdent::from(format!("{}Entry", camel_case(field_name)))
142    }
143
144    fn map_entry_field(
145        &self,
146        scope: &ProtobufAbsPath,
147        name: &str,
148        number: i32,
149        field_type: &model::FieldType,
150    ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto> {
151        // should be consisent with DescriptorBuilder::ValidateMapEntry
152
153        let mut output = protobuf::descriptor::FieldDescriptorProto::new();
154
155        output.set_name(name.to_owned());
156        output.set_number(number);
157
158        let t = self.field_type(&scope, name, field_type)?;
159        output.set_type(t.type_enum());
160        if let Some(t_name) = t.type_name() {
161            output.set_type_name(t_name.path.clone());
162        }
163
164        output.set_label(field_descriptor_proto::Label::LABEL_OPTIONAL);
165
166        output.set_json_name(json_name(&name));
167
168        Ok(output)
169    }
170
171    fn map_entry_message(
172        &self,
173        scope: &ProtobufAbsPath,
174        field_name: &str,
175        key: &model::FieldType,
176        value: &model::FieldType,
177    ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
178        let mut output = protobuf::descriptor::DescriptorProto::new();
179
180        output.options.mut_or_insert_default().set_map_entry(true);
181        output.set_name(Resolver::map_entry_name_for_field_name(field_name).into_string());
182        output
183            .field
184            .push(self.map_entry_field(&scope, "key", 1, key)?);
185        output
186            .field
187            .push(self.map_entry_field(&scope, "value", 2, value)?);
188
189        Ok(output)
190    }
191
192    fn group_message(
193        &self,
194        scope: &ProtobufAbsPath,
195        name: &str,
196        fields: &[model::WithLoc<model::Field>],
197    ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
198        let mut output = protobuf::descriptor::DescriptorProto::new();
199
200        output.set_name(name.to_owned());
201
202        for f in fields {
203            output.field.push(self.field(scope, f, None)?);
204        }
205
206        Ok(output)
207    }
208
209    fn message(
210        &self,
211        scope: &ProtobufAbsPathRef,
212        input: &model::Message,
213    ) -> anyhow::Result<protobuf::descriptor::DescriptorProto> {
214        let mut nested_scope = scope.to_owned();
215        nested_scope.push_simple(ProtobufIdentRef::new(&input.name));
216
217        let mut output = protobuf::descriptor::DescriptorProto::new();
218        output.set_name(input.name.clone());
219
220        let mut nested_messages = Vec::new();
221
222        for m in &input.messages {
223            let message = self.message(&nested_scope, &m.t)?;
224            nested_messages.push(model::WithLoc {
225                t: message,
226                loc: m.loc,
227            });
228        }
229
230        for f in input.regular_fields_including_in_oneofs() {
231            match &f.t.typ {
232                model::FieldType::Map(t) => {
233                    let message = self.map_entry_message(&nested_scope, &f.t.name, &t.0, &t.1)?;
234                    nested_messages.push(model::WithLoc {
235                        t: message,
236                        loc: f.loc,
237                    });
238                }
239                model::FieldType::Group(model::Group {
240                    name: group_name,
241                    fields,
242                    ..
243                }) => {
244                    let message = self.group_message(&nested_scope, group_name, fields)?;
245                    nested_messages.push(model::WithLoc {
246                        t: message,
247                        loc: f.loc,
248                    });
249                }
250                _ => (),
251            }
252        }
253
254        // Preserve declaration order
255        nested_messages.sort_by_key(|m| m.loc);
256        output.nested_type = nested_messages
257            .into_iter()
258            .map(|model::WithLoc { t, .. }| t)
259            .collect();
260
261        output.enum_type = input
262            .enums
263            .iter()
264            .map(|e| self.enumeration(scope, e))
265            .collect::<Result<_, _>>()?;
266
267        {
268            let mut fields = Vec::new();
269
270            for fo in &input.fields {
271                match &fo.t {
272                    model::FieldOrOneOf::Field(f) => {
273                        let oneof_index = if self.is_proto3_optional(f) {
274                            let oneof_index = output.oneof_decl.len() as i32;
275                            let mut oneof = OneofDescriptorProto::new();
276                            oneof.set_name(format!("_{}", f.name));
277                            output.oneof_decl.push(oneof);
278                            Some(oneof_index)
279                        } else {
280                            None
281                        };
282                        fields.push(self.field(&nested_scope, f, oneof_index)?);
283                    }
284                    model::FieldOrOneOf::OneOf(o) => {
285                        let oneof_index = output.oneof_decl.len();
286                        for f in &o.fields {
287                            fields.push(self.field(&nested_scope, f, Some(oneof_index as i32))?);
288                        }
289                        output.oneof_decl.push(self.oneof(scope, o)?);
290                    }
291                }
292            }
293
294            output.field = fields;
295        }
296
297        for ext in &input.extension_ranges {
298            let mut extension_range = protobuf::descriptor::descriptor_proto::ExtensionRange::new();
299            extension_range.set_start(*ext.start());
300            extension_range.set_end(*ext.end() + 1);
301            output.extension_range.push(extension_range);
302        }
303        for ext in &input.extensions {
304            let mut extension = self.field(scope, &ext.t.field, None)?;
305            extension.set_extendee(
306                self.type_resolver
307                    .resolve_message_or_enum(scope, &ext.t.extendee)?
308                    .full_name
309                    .path,
310            );
311            output.extension.push(extension);
312        }
313
314        for reserved in &input.reserved_nums {
315            let mut reserved_range = ReservedRange::new();
316            reserved_range.set_start(*reserved.start());
317            reserved_range.set_end(*reserved.end() + 1);
318            output.reserved_range.push(reserved_range);
319        }
320        output.reserved_name = input.reserved_names.clone().into();
321
322        Ok(output)
323    }
324
325    fn service_method(
326        &self,
327        input: &model::Method,
328    ) -> anyhow::Result<protobuf::descriptor::MethodDescriptorProto> {
329        let scope = &self.current_file.package;
330        let mut output = protobuf::descriptor::MethodDescriptorProto::new();
331        output.set_name(input.name.clone());
332        output.set_input_type(
333            self.type_resolver
334                .resolve_message_or_enum(scope, &input.input_type)?
335                .full_name
336                .to_string(),
337        );
338        output.set_output_type(
339            self.type_resolver
340                .resolve_message_or_enum(scope, &input.output_type)?
341                .full_name
342                .to_string(),
343        );
344
345        if input.client_streaming {
346            output.set_client_streaming(input.client_streaming);
347        }
348
349        if input.server_streaming {
350            output.set_server_streaming(input.server_streaming);
351        }
352        Ok(output)
353    }
354
355    fn service(
356        &self,
357        input: &model::Service,
358    ) -> anyhow::Result<protobuf::descriptor::ServiceDescriptorProto> {
359        let mut output = protobuf::descriptor::ServiceDescriptorProto::new();
360        output.set_name(input.name.clone());
361
362        output.method = input
363            .methods
364            .iter()
365            .map(|m| self.service_method(m))
366            .collect::<Result<_, _>>()?;
367
368        Ok(output)
369    }
370
371    fn is_proto3_optional(&self, input: &model::WithLoc<model::Field>) -> bool {
372        (self.current_file.syntax, input.t.rule)
373            == (model::Syntax::Proto3, Some(model::Rule::Optional))
374    }
375
376    fn field(
377        &self,
378        scope: &ProtobufAbsPathRef,
379        input: &model::WithLoc<model::Field>,
380        oneof_index: Option<i32>,
381    ) -> anyhow::Result<protobuf::descriptor::FieldDescriptorProto> {
382        let mut output = protobuf::descriptor::FieldDescriptorProto::new();
383        output.set_name(input.t.name.clone());
384
385        if let model::FieldType::Map(..) = input.t.typ {
386            output.set_label(protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED);
387        } else {
388            output.set_label(label(input.t.rule));
389
390            if self.is_proto3_optional(input) {
391                output.set_proto3_optional(true);
392            }
393        }
394
395        let t = self.field_type(scope, &input.t.name, &input.t.typ)?;
396        output.set_type(t.type_enum());
397        if let Some(t_name) = t.type_name() {
398            output.set_type_name(t_name.path.clone());
399        }
400
401        output.set_number(input.t.number);
402        // TODO: move default to option parser
403        if let Some(ref default) = input.t.options.as_slice().by_name("default") {
404            let default = match output.type_() {
405                protobuf::descriptor::field_descriptor_proto::Type::TYPE_STRING => {
406                    if let &model::ProtobufConstant::String(ref s) = default {
407                        s.decode_utf8()?
408                    } else {
409                        return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
410                    }
411                }
412                protobuf::descriptor::field_descriptor_proto::Type::TYPE_BYTES => {
413                    if let &model::ProtobufConstant::String(ref s) = default {
414                        let mut buf = String::new();
415                        escape_bytes_to(&s.decode_bytes()?, &mut buf);
416                        buf
417                    } else {
418                        return Err(ConvertError::DefaultValueIsNotStringLiteral.into());
419                    }
420                }
421                _ => default.format(),
422            };
423            output.set_default_value(default);
424        }
425
426        if let Some(oneof_index) = oneof_index {
427            output.set_oneof_index(oneof_index);
428        }
429
430        if let Some(json_name) = input.t.options.as_slice().by_name_string("json_name")? {
431            output.set_json_name(json_name);
432        } else {
433            output.set_json_name(json_name(&input.t.name));
434        }
435
436        Ok(output)
437    }
438
439    fn find_message_by_abs_name(
440        &self,
441        abs_path: &ProtobufAbsPath,
442    ) -> anyhow::Result<WithFullName<&'a model::Message>> {
443        let with_full_name = self
444            .type_resolver
445            .find_message_or_enum_by_abs_name(abs_path)?;
446        match with_full_name.t {
447            MessageOrEnum::Message(m) => Ok(WithFullName {
448                t: m,
449                full_name: with_full_name.full_name,
450            }),
451            MessageOrEnum::Enum(..) => Err(ConvertError::ExpectingMessage(abs_path.clone()).into()),
452        }
453    }
454
455    fn find_enum_by_abs_name(
456        &self,
457        abs_path: &ProtobufAbsPath,
458    ) -> anyhow::Result<&'a model::Enumeration> {
459        match self
460            .type_resolver
461            .find_message_or_enum_by_abs_name(abs_path)?
462            .t
463        {
464            MessageOrEnum::Enum(e) => Ok(e),
465            MessageOrEnum::Message(..) => Err(ConvertError::ExpectingEnum(abs_path.clone()).into()),
466        }
467    }
468
469    fn field_type(
470        &self,
471        scope: &ProtobufAbsPathRef,
472        name: &str,
473        input: &model::FieldType,
474    ) -> anyhow::Result<TypeResolved> {
475        Ok(match *input {
476            model::FieldType::Bool => TypeResolved::Bool,
477            model::FieldType::Int32 => TypeResolved::Int32,
478            model::FieldType::Int64 => TypeResolved::Int64,
479            model::FieldType::Uint32 => TypeResolved::Uint32,
480            model::FieldType::Uint64 => TypeResolved::Uint64,
481            model::FieldType::Sint32 => TypeResolved::Sint32,
482            model::FieldType::Sint64 => TypeResolved::Sint64,
483            model::FieldType::Fixed32 => TypeResolved::Fixed32,
484            model::FieldType::Fixed64 => TypeResolved::Fixed64,
485            model::FieldType::Sfixed32 => TypeResolved::Sfixed32,
486            model::FieldType::Sfixed64 => TypeResolved::Sfixed64,
487            model::FieldType::Float => TypeResolved::Float,
488            model::FieldType::Double => TypeResolved::Double,
489            model::FieldType::String => TypeResolved::String,
490            model::FieldType::Bytes => TypeResolved::Bytes,
491            model::FieldType::MessageOrEnum(ref name) => {
492                let t = self.type_resolver.resolve_message_or_enum(scope, &name)?;
493                match t.t {
494                    MessageOrEnum::Message(..) => TypeResolved::Message(t.full_name),
495                    MessageOrEnum::Enum(..) => TypeResolved::Enum(t.full_name),
496                }
497            }
498            model::FieldType::Map(..) => {
499                let mut type_name = scope.to_owned();
500                type_name.push_simple(&Resolver::map_entry_name_for_field_name(name));
501                TypeResolved::Message(type_name)
502            }
503            model::FieldType::Group(model::Group {
504                name: ref group_name,
505                ..
506            }) => {
507                let mut type_name = scope.to_owned();
508                type_name.push_simple(ProtobufIdentRef::new(group_name));
509                TypeResolved::Group(type_name)
510            }
511        })
512    }
513
514    fn enum_value(
515        &self,
516        _scope: &ProtobufAbsPathRef,
517        input: &model::EnumValue,
518    ) -> anyhow::Result<protobuf::descriptor::EnumValueDescriptorProto> {
519        let mut output = protobuf::descriptor::EnumValueDescriptorProto::new();
520        output.set_name(input.name.clone());
521        output.set_number(input.number);
522        Ok(output)
523    }
524
525    fn enumeration(
526        &self,
527        scope: &ProtobufAbsPathRef,
528        input: &model::Enumeration,
529    ) -> anyhow::Result<protobuf::descriptor::EnumDescriptorProto> {
530        let mut output = protobuf::descriptor::EnumDescriptorProto::new();
531        output.set_name(input.name.clone());
532        output.value = input
533            .values
534            .iter()
535            .map(|v| self.enum_value(scope, &v))
536            .collect::<Result<_, _>>()?;
537
538        for reserved in &input.reserved_nums {
539            let mut reserved_range = EnumReservedRange::new();
540            reserved_range.set_start(*reserved.start());
541            // EnumReservedRange is inclusive, not like ExtensionRange and
542            // ReservedRange, which are exclusive.
543            reserved_range.set_end(*reserved.end());
544            output.reserved_range.push(reserved_range);
545        }
546
547        output.reserved_name = input.reserved_names.clone().into();
548
549        Ok(output)
550    }
551
552    fn oneof(
553        &self,
554        _scope: &ProtobufAbsPathRef,
555        input: &model::OneOf,
556    ) -> anyhow::Result<protobuf::descriptor::OneofDescriptorProto> {
557        let mut output = protobuf::descriptor::OneofDescriptorProto::new();
558        output.set_name(input.name.clone());
559        Ok(output)
560    }
561
562    fn extension(
563        &self,
564        scope: &ProtobufAbsPath,
565        input: &model::Extension,
566    ) -> anyhow::Result<(
567        protobuf::descriptor::FieldDescriptorProto,
568        Option<protobuf::descriptor::DescriptorProto>,
569    )> {
570        let mut field = self.field(scope, &input.field, None)?;
571        field.set_extendee(
572            self.type_resolver
573                .resolve_message_or_enum(scope, &input.extendee)?
574                .full_name
575                .to_string(),
576        );
577        let group_messages = if let model::FieldType::Group(g) = &input.field.t.typ {
578            Some(self.group_message(scope, &g.name, &g.fields)?)
579        } else {
580            None
581        };
582        Ok((field, group_messages))
583    }
584}
585
586fn syntax(input: model::Syntax) -> String {
587    match input {
588        model::Syntax::Proto2 => "proto2".to_owned(),
589        model::Syntax::Proto3 => "proto3".to_owned(),
590    }
591}
592
593fn label(input: Option<model::Rule>) -> protobuf::descriptor::field_descriptor_proto::Label {
594    match input {
595        Some(model::Rule::Optional) => {
596            protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL
597        }
598        Some(model::Rule::Required) => {
599            protobuf::descriptor::field_descriptor_proto::Label::LABEL_REQUIRED
600        }
601        Some(model::Rule::Repeated) => {
602            protobuf::descriptor::field_descriptor_proto::Label::LABEL_REPEATED
603        }
604        None => protobuf::descriptor::field_descriptor_proto::Label::LABEL_OPTIONAL,
605    }
606}
607
608pub(crate) fn populate_dependencies(
609    input: &model::FileDescriptor,
610    output: &mut protobuf::descriptor::FileDescriptorProto,
611) {
612    for import in &input.imports {
613        if import.vis == model::ImportVis::Public {
614            output
615                .public_dependency
616                .push(output.dependency.len() as i32);
617        } else if import.vis == model::ImportVis::Weak {
618            output.weak_dependency.push(output.dependency.len() as i32);
619        }
620        output.dependency.push(import.path.to_string());
621    }
622}
623
624pub(crate) fn file_descriptor(
625    name: &ProtoPath,
626    input: &model::FileDescriptor,
627    deps: &[FileDescriptorPair],
628) -> anyhow::Result<protobuf::descriptor::FileDescriptorProto> {
629    let resolver = Resolver {
630        current_file: &input,
631        type_resolver: TypeResolver {
632            current_file: &input,
633            deps,
634        },
635    };
636
637    let mut output = protobuf::descriptor::FileDescriptorProto::new();
638    output.set_name(fs_path_to_proto_path(name));
639    output.set_syntax(syntax(input.syntax));
640
641    if input.package != ProtobufAbsPath::root() {
642        output.set_package(input.package.to_root_rel().to_string());
643    }
644
645    populate_dependencies(&input, &mut output);
646
647    let mut messages = Vec::new();
648    let mut services = Vec::new();
649
650    let mut extensions = Vec::new();
651    for e in &input.extensions {
652        let (ext, group_messages) = resolver.extension(&resolver.current_file.package, &e.t)?;
653        extensions.push(ext);
654        messages.extend(group_messages.map(model::WithLoc::with_loc(e.loc)));
655    }
656    output.extension = extensions;
657
658    for m in &input.messages {
659        let message = resolver.message(&resolver.current_file.package, &m.t)?;
660        messages.push(model::WithLoc {
661            t: message,
662            loc: m.loc,
663        });
664    }
665
666    for s in &input.services {
667        let service = resolver.service(&s.t)?;
668        services.push(model::WithLoc {
669            t: service,
670            loc: s.loc,
671        })
672    }
673
674    // Preserve declaration order
675    messages.sort_by_key(|m| m.loc);
676    output.message_type = messages
677        .into_iter()
678        .map(|model::WithLoc { t, .. }| t)
679        .collect();
680
681    output.enum_type = input
682        .enums
683        .iter()
684        .map(|e| resolver.enumeration(&resolver.current_file.package, e))
685        .collect::<Result<_, _>>()?;
686
687    output.service = services
688        .into_iter()
689        .map(|model::WithLoc { t, .. }| t)
690        .collect();
691
692    let descriptor_without_options = FileDescriptor::new_dynamic(
693        output.clone(),
694        &deps
695            .iter()
696            .map(|d| d.descriptor.clone())
697            .collect::<Vec<_>>(),
698    )?;
699
700    let option_resolver = OptionResoler {
701        resolver: &resolver,
702        descriptor_without_options,
703    };
704
705    option_resolver.file(&mut output)?;
706
707    Ok(output)
708}