protostar 0.1.0.beta1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +647 -0
- data/THIRD_PARTY_NOTICES.md +61 -0
- data/exe/protoc-gen-protostar +7 -0
- data/exe/protostar +7 -0
- data/lib/protostar/builder/generator.rb +71 -0
- data/lib/protostar/builder/sink.rb +35 -0
- data/lib/protostar/builder.rb +965 -0
- data/lib/protostar/cli.rb +267 -0
- data/lib/protostar/codec/decode_generator.rb +199 -0
- data/lib/protostar/codec/decoder.rb +296 -0
- data/lib/protostar/codec/encode_generator.rb +224 -0
- data/lib/protostar/codec/encoder.rb +121 -0
- data/lib/protostar/codec/sizer.rb +91 -0
- data/lib/protostar/codec.rb +15 -0
- data/lib/protostar/compiler/ast.rb +193 -0
- data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
- data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
- data/lib/protostar/compiler/emitters/grpc.rb +175 -0
- data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
- data/lib/protostar/compiler/emitters/rbs.rb +394 -0
- data/lib/protostar/compiler/emitters/ruby.rb +503 -0
- data/lib/protostar/compiler/emitters.rb +268 -0
- data/lib/protostar/compiler/include/LICENSE +32 -0
- data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
- data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
- data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
- data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
- data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
- data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
- data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
- data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
- data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
- data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
- data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
- data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
- data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
- data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
- data/lib/protostar/compiler/lexer.rb +659 -0
- data/lib/protostar/compiler/linker.rb +894 -0
- data/lib/protostar/compiler/option_interpreter.rb +363 -0
- data/lib/protostar/compiler/parser.rb +1696 -0
- data/lib/protostar/compiler/retention.rb +104 -0
- data/lib/protostar/compiler/run.rb +184 -0
- data/lib/protostar/compiler/source_info.rb +161 -0
- data/lib/protostar/compiler/symbol_table.rb +223 -0
- data/lib/protostar/compiler/text_format.rb +340 -0
- data/lib/protostar/compiler/validator.rb +944 -0
- data/lib/protostar/compiler.rb +304 -0
- data/lib/protostar/diagnostics/codes.rb +1307 -0
- data/lib/protostar/diagnostics/formats.rb +64 -0
- data/lib/protostar/diagnostics/renderer.rb +240 -0
- data/lib/protostar/diagnostics/source.rb +153 -0
- data/lib/protostar/diagnostics.rb +117 -0
- data/lib/protostar/dsl.rb +367 -0
- data/lib/protostar/enum.rb +70 -0
- data/lib/protostar/errors.rb +23 -0
- data/lib/protostar/google/protobuf/any_pb.rb +90 -0
- data/lib/protostar/google/protobuf/api_pb.rb +199 -0
- data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
- data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
- data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
- data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
- data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
- data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
- data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
- data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
- data/lib/protostar/google/protobuf/type_pb.rb +202 -0
- data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
- data/lib/protostar/google_protobuf_shim.rb +24 -0
- data/lib/protostar/json/encoder.rb +340 -0
- data/lib/protostar/json/errors.rb +34 -0
- data/lib/protostar/json/parser.rb +437 -0
- data/lib/protostar/json/path.rb +39 -0
- data/lib/protostar/json.rb +95 -0
- data/lib/protostar/lint/command.rb +197 -0
- data/lib/protostar/lint/config.rb +98 -0
- data/lib/protostar/lint/context.rb +126 -0
- data/lib/protostar/lint/directives.rb +56 -0
- data/lib/protostar/lint/fixer.rb +165 -0
- data/lib/protostar/lint/naming.rb +54 -0
- data/lib/protostar/lint/rule.rb +120 -0
- data/lib/protostar/lint/rules/comment_enum.rb +31 -0
- data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
- data/lib/protostar/lint/rules/comment_field.rb +33 -0
- data/lib/protostar/lint/rules/comment_message.rb +31 -0
- data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
- data/lib/protostar/lint/rules/comment_service.rb +31 -0
- data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
- data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
- data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
- data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
- data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
- data/lib/protostar/lint/rules/field_not_required.rb +39 -0
- data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
- data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
- data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/import_no_public.rb +29 -0
- data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
- data/lib/protostar/lint/rules/import_used.rb +33 -0
- data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
- data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
- data/lib/protostar/lint/rules/no_groups.rb +34 -0
- data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/package_defined.rb +28 -0
- data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
- data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
- data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
- data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
- data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
- data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
- data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
- data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/service_suffix.rb +28 -0
- data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
- data/lib/protostar/lint/runner.rb +135 -0
- data/lib/protostar/lint.rb +122 -0
- data/lib/protostar/message/accessors.rb +86 -0
- data/lib/protostar/message/coercion.rb +171 -0
- data/lib/protostar/message/field_info.rb +145 -0
- data/lib/protostar/message/reflection.rb +149 -0
- data/lib/protostar/message.rb +572 -0
- data/lib/protostar/plugin.rb +94 -0
- data/lib/protostar/schema/default_value.rb +113 -0
- data/lib/protostar/schema/descriptor.rb +41 -0
- data/lib/protostar/schema/draft/copy.rb +88 -0
- data/lib/protostar/schema/draft/resolution.rb +177 -0
- data/lib/protostar/schema/draft.rb +779 -0
- data/lib/protostar/schema/enum.rb +106 -0
- data/lib/protostar/schema/extension_range.rb +37 -0
- data/lib/protostar/schema/features.rb +153 -0
- data/lib/protostar/schema/field.rb +201 -0
- data/lib/protostar/schema/file.rb +217 -0
- data/lib/protostar/schema/freezer.rb +61 -0
- data/lib/protostar/schema/message.rb +104 -0
- data/lib/protostar/schema/oneof.rb +38 -0
- data/lib/protostar/schema/options.rb +367 -0
- data/lib/protostar/schema/pool.rb +179 -0
- data/lib/protostar/schema/proto.rb +576 -0
- data/lib/protostar/schema/resolver.rb +118 -0
- data/lib/protostar/schema/service.rb +89 -0
- data/lib/protostar/schema/source_info.rb +53 -0
- data/lib/protostar/schema.rb +65 -0
- data/lib/protostar/short_names/any.rb +7 -0
- data/lib/protostar/short_names/duration.rb +7 -0
- data/lib/protostar/short_names/empty.rb +7 -0
- data/lib/protostar/short_names/field_mask.rb +7 -0
- data/lib/protostar/short_names/struct.rb +9 -0
- data/lib/protostar/short_names/timestamp.rb +7 -0
- data/lib/protostar/short_names/wrappers.rb +15 -0
- data/lib/protostar/text/extensions.rb +114 -0
- data/lib/protostar/text/parser.rb +439 -0
- data/lib/protostar/text/printer.rb +304 -0
- data/lib/protostar/text/tokenizer.rb +116 -0
- data/lib/protostar/text.rb +67 -0
- data/lib/protostar/types.rb +152 -0
- data/lib/protostar/unknown_field.rb +58 -0
- data/lib/protostar/version.rb +5 -0
- data/lib/protostar/view/generator.rb +298 -0
- data/lib/protostar/view/map.rb +194 -0
- data/lib/protostar/view/repeated.rb +143 -0
- data/lib/protostar/view/scan.rb +183 -0
- data/lib/protostar/view.rb +283 -0
- data/lib/protostar/well_known/any.rb +52 -0
- data/lib/protostar/well_known/duration.rb +53 -0
- data/lib/protostar/well_known/list_value.rb +63 -0
- data/lib/protostar/well_known/struct.rb +55 -0
- data/lib/protostar/well_known/timestamp.rb +64 -0
- data/lib/protostar/well_known/value.rb +60 -0
- data/lib/protostar/well_known.rb +38 -0
- data/lib/protostar/wire/io_source.rb +40 -0
- data/lib/protostar/wire/reader.rb +254 -0
- data/lib/protostar/wire/writer.rb +201 -0
- data/lib/protostar/wire.rb +96 -0
- data/lib/protostar.rb +95 -0
- data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
- data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
- data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
- data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
- data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
- data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
- data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
- data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
- data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
- data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
- data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
- data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
- data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
- data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
- data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
- data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
- data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
- data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
- data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
- data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
- data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
- data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
- data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
- data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
- data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
- data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
- data/sig/protostar/lint.rbs +216 -0
- data/sig/protostar.rbs +326 -0
- metadata +366 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# A built `.proto` file
|
|
6
|
+
class File < Descriptor
|
|
7
|
+
# @return [String] the package, "" when none
|
|
8
|
+
attr_reader :package
|
|
9
|
+
# @return [Symbol] :proto2, :proto3 or :editions
|
|
10
|
+
attr_reader :syntax
|
|
11
|
+
# @return [Symbol, Integer, nil] the Edition enum name for editions files
|
|
12
|
+
# (an Integer only for an edition this model has no name for)
|
|
13
|
+
attr_reader :edition
|
|
14
|
+
# @return [Array<String>] imported file names, in declaration order
|
|
15
|
+
attr_reader :dependencies
|
|
16
|
+
# @return [Array<Integer>] indexes into {#dependencies} of `import public`
|
|
17
|
+
attr_reader :public_dependencies
|
|
18
|
+
# @return [Array<Integer>] indexes into {#dependencies} of `import weak`
|
|
19
|
+
attr_reader :weak_dependencies
|
|
20
|
+
# @return [Array<String>] `import option` file names (edition 2024)
|
|
21
|
+
attr_reader :option_dependencies
|
|
22
|
+
# @return [Array<File>] linked {#dependencies}, same order
|
|
23
|
+
attr_reader :dependency_files
|
|
24
|
+
# @return [Array<Message>] top-level messages
|
|
25
|
+
attr_reader :messages
|
|
26
|
+
# @return [Array<Enum>] top-level enums
|
|
27
|
+
attr_reader :enums
|
|
28
|
+
# @return [Array<Service>]
|
|
29
|
+
attr_reader :services
|
|
30
|
+
# @return [Array<Field>] top-level extensions
|
|
31
|
+
attr_reader :extensions
|
|
32
|
+
# @return [SourceInfo, nil]
|
|
33
|
+
attr_reader :source_info
|
|
34
|
+
# @return [Array<Message>] every message, depth first in declaration order
|
|
35
|
+
attr_reader :all_messages
|
|
36
|
+
# @return [Array<Enum>] every enum, top level first, then by message in {#all_messages} order
|
|
37
|
+
attr_reader :all_enums
|
|
38
|
+
# @return [Array<Field>] every extension, top level first, then by message in {#all_messages} order
|
|
39
|
+
attr_reader :all_extensions
|
|
40
|
+
# @return [Hash{String => Descriptor}] every symbol this file defines, by full name
|
|
41
|
+
attr_reader :symbols
|
|
42
|
+
# @return [Array<File>] this file, its imports and whatever they re-export
|
|
43
|
+
# through `import public`: the files whose symbols are visible here
|
|
44
|
+
attr_reader :visible_files
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
def initialize(name:, package:, syntax:, edition:, proto_syntax:)
|
|
48
|
+
@name = name
|
|
49
|
+
@full_name = name
|
|
50
|
+
@index = 0
|
|
51
|
+
@package = package
|
|
52
|
+
@syntax = syntax
|
|
53
|
+
@edition = edition
|
|
54
|
+
@proto_syntax = proto_syntax
|
|
55
|
+
@dependencies = Freezer::EMPTY_ARRAY
|
|
56
|
+
@public_dependencies = Freezer::EMPTY_ARRAY
|
|
57
|
+
@weak_dependencies = Freezer::EMPTY_ARRAY
|
|
58
|
+
@option_dependencies = Freezer::EMPTY_ARRAY
|
|
59
|
+
@dependency_files = Freezer::EMPTY_ARRAY
|
|
60
|
+
@messages = @enums = @services = @extensions = Freezer::EMPTY_ARRAY
|
|
61
|
+
@all_messages = @all_enums = @all_extensions = Freezer::EMPTY_ARRAY
|
|
62
|
+
@symbols = {}
|
|
63
|
+
@visible_files = [self]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @api private
|
|
67
|
+
def __dependencies(dependencies:, public_dependencies:, weak_dependencies:, option_dependencies:, dependency_files:)
|
|
68
|
+
@dependencies = dependencies
|
|
69
|
+
@public_dependencies = public_dependencies
|
|
70
|
+
@weak_dependencies = weak_dependencies
|
|
71
|
+
@option_dependencies = option_dependencies
|
|
72
|
+
@dependency_files = dependency_files
|
|
73
|
+
@visible_files = compute_visible_files
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @api private
|
|
78
|
+
# @return [String, nil] the `syntax` string the FileDescriptorProto carries
|
|
79
|
+
attr_reader :proto_syntax
|
|
80
|
+
|
|
81
|
+
# @return [File] itself, so every descriptor answers `#file`
|
|
82
|
+
def file
|
|
83
|
+
self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @return [Integer] the edition number features resolve against
|
|
87
|
+
# (EDITION_PROTO2 or EDITION_PROTO3 for the legacy syntaxes)
|
|
88
|
+
def edition_number
|
|
89
|
+
case @syntax
|
|
90
|
+
when :proto2 then Features::EDITIONS[:EDITION_PROTO2]
|
|
91
|
+
when :proto3 then Features::EDITIONS[:EDITION_PROTO3]
|
|
92
|
+
else Features.edition_number(@edition)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @param full_name [String] without a leading dot
|
|
97
|
+
# @return [Message, nil] a message defined in this file
|
|
98
|
+
def find_message(full_name)
|
|
99
|
+
found = @symbols[full_name]
|
|
100
|
+
found if found.is_a?(Message)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [Enum, nil] an enum defined in this file
|
|
104
|
+
def find_enum(full_name)
|
|
105
|
+
found = @symbols[full_name]
|
|
106
|
+
found if found.is_a?(Enum)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @return [Service, nil] a service defined in this file
|
|
110
|
+
def find_service(full_name)
|
|
111
|
+
found = @symbols[full_name]
|
|
112
|
+
found if found.is_a?(Service)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @return [Field, nil] an extension defined in this file
|
|
116
|
+
def find_extension(full_name)
|
|
117
|
+
found = @symbols[full_name]
|
|
118
|
+
found if found.is_a?(Field) && found.extension?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @return [Descriptor, nil] any symbol defined in this file: message, field,
|
|
122
|
+
# oneof, enum, enum value, service or method
|
|
123
|
+
def find_symbol(full_name)
|
|
124
|
+
@symbols[full_name]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def inspect
|
|
128
|
+
"#<#{self.class.name} #{@name}>"
|
|
129
|
+
end
|
|
130
|
+
alias_method :to_s, :inspect
|
|
131
|
+
|
|
132
|
+
# This file as a `google.protobuf.FileDescriptorProto` of the bootstrap
|
|
133
|
+
# classes, as protoc's `FileDescriptor::CopyTo` writes it
|
|
134
|
+
# @param source_info [Boolean] include `source_code_info` when the file has it
|
|
135
|
+
# @param default_json_names [Boolean] false leaves out every `json_name` equal to the one
|
|
136
|
+
# derived from the field name, as protoc's Ruby generator embeds descriptors
|
|
137
|
+
# @return [Protostar::Google::Protobuf::FileDescriptorProto]
|
|
138
|
+
def to_proto(source_info: true, default_json_names: true)
|
|
139
|
+
Proto::Writer.file(self, source_info: source_info, json_names: default_json_names)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @param (see #to_proto)
|
|
143
|
+
# @return [String] the serialized FileDescriptorProto, byte for byte what protoc writes
|
|
144
|
+
def serialize(source_info: true, default_json_names: true)
|
|
145
|
+
bytes = to_proto(source_info: false, default_json_names: default_json_names).encode
|
|
146
|
+
return bytes unless source_info && @source_info
|
|
147
|
+
Proto::Writer.with_source_code_info(bytes, @source_info)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Builds a file from a `google.protobuf.FileDescriptorProto` message (or
|
|
151
|
+
# its bytes), as a plugin receives them. Extension bytes in options are
|
|
152
|
+
# decoded by the extensions the pool (or the file itself) defines;
|
|
153
|
+
# others stay {Options#unknown_fields}.
|
|
154
|
+
# @param proto [Protostar::Google::Protobuf::FileDescriptorProto, String]
|
|
155
|
+
# @param pool [Pool] where dependencies and extensions are looked up; the file is not added
|
|
156
|
+
# @return [File]
|
|
157
|
+
def self.from_proto(proto, pool:)
|
|
158
|
+
proto = Proto.types::FileDescriptorProto.decode(proto) if proto.is_a?(String)
|
|
159
|
+
Proto::Reader.new(proto, pool).call
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Starts describing a file. The draft creates the real descriptors as it
|
|
163
|
+
# goes; {Draft::File#resolve} links them and {Draft::File#freeze!} hands
|
|
164
|
+
# back the finished, shareable file.
|
|
165
|
+
#
|
|
166
|
+
# file = Schema::File.draft("shop.proto", package: "shop", syntax: :proto3)
|
|
167
|
+
# file.message("Item") do |m|
|
|
168
|
+
# m.field "name", 1, :string
|
|
169
|
+
# m.field "price_cents", 2, :int64, optional: true
|
|
170
|
+
# m.map "stock", 3, key: :string, value: :int32
|
|
171
|
+
# end
|
|
172
|
+
# file.resolve(pool)
|
|
173
|
+
# file.freeze! # => #<Protostar::Schema::File shop.proto>
|
|
174
|
+
#
|
|
175
|
+
# @param name [String] the file name as imported
|
|
176
|
+
# @param package [String, nil]
|
|
177
|
+
# @param syntax [Symbol, nil] :proto2, :proto3 or :editions; nil is proto2, and
|
|
178
|
+
# unlike an explicit :proto2 leaves `syntax` out of the FileDescriptorProto, as protoc does
|
|
179
|
+
# @param edition [Symbol, Integer, nil] e.g. :EDITION_2023; implies :editions
|
|
180
|
+
# @param dependencies [Array<String>] imported file names
|
|
181
|
+
# @param public_dependencies [Array<String, Integer>] names or indexes of `import public` files
|
|
182
|
+
# @param weak_dependencies [Array<String, Integer>]
|
|
183
|
+
# @param option_dependencies [Array<String>] `import option` file names
|
|
184
|
+
# @param options [Hash, nil] the file's options
|
|
185
|
+
# @return [Draft::File]
|
|
186
|
+
def self.draft(name, package: nil, syntax: nil, edition: nil, dependencies: [], public_dependencies: [],
|
|
187
|
+
weak_dependencies: [], option_dependencies: [], options: nil)
|
|
188
|
+
Draft::File.new(name, package: package, syntax: syntax, edition: edition, dependencies: dependencies,
|
|
189
|
+
public_dependencies: public_dependencies, weak_dependencies: weak_dependencies,
|
|
190
|
+
option_dependencies: option_dependencies, options: options)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
# protoc's rule: direct imports, plus the public imports of those, recursively
|
|
196
|
+
def compute_visible_files
|
|
197
|
+
seen = {self => true}
|
|
198
|
+
queue = []
|
|
199
|
+
@dependency_files.each do |dep|
|
|
200
|
+
next if seen[dep]
|
|
201
|
+
seen[dep] = true
|
|
202
|
+
queue << dep
|
|
203
|
+
end
|
|
204
|
+
until queue.empty?
|
|
205
|
+
dep = queue.shift
|
|
206
|
+
dep.public_dependencies.each do |i|
|
|
207
|
+
pub = dep.dependency_files[i]
|
|
208
|
+
next if pub.nil? || seen[pub]
|
|
209
|
+
seen[pub] = true
|
|
210
|
+
queue << pub
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
seen.keys
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# Deep-copies plain data (Hashes, Arrays, Strings, scalars) into frozen,
|
|
6
|
+
# deduplicated form so that building never freezes the caller's input.
|
|
7
|
+
# @api private
|
|
8
|
+
module Freezer
|
|
9
|
+
EMPTY_HASH = {}.freeze
|
|
10
|
+
EMPTY_ARRAY = [].freeze
|
|
11
|
+
|
|
12
|
+
# Freezes a descriptor graph before `Ractor.make_shareable` sees it.
|
|
13
|
+
# make_shareable on a graph full of back-references (every field points
|
|
14
|
+
# at its message, which points at all its fields) re-checks the graph
|
|
15
|
+
# from each back-reference and goes quadratic: about 1.4s for
|
|
16
|
+
# unittest.proto. Freezing everything first lets it confirm the graph in
|
|
17
|
+
# one pass. Arrays and Hashes are always descended into, since they may
|
|
18
|
+
# be frozen while their members are not; other frozen objects are
|
|
19
|
+
# finished descriptors of dependencies or immutable values.
|
|
20
|
+
def self.deep_freeze(root)
|
|
21
|
+
stack = [root]
|
|
22
|
+
containers = {}.compare_by_identity
|
|
23
|
+
until stack.empty?
|
|
24
|
+
obj = stack.pop
|
|
25
|
+
case obj
|
|
26
|
+
when Array
|
|
27
|
+
next if containers.key?(obj)
|
|
28
|
+
containers[obj] = true
|
|
29
|
+
stack.concat(obj)
|
|
30
|
+
when Hash
|
|
31
|
+
next if containers.key?(obj)
|
|
32
|
+
containers[obj] = true
|
|
33
|
+
obj.each { |k, v| stack << k << v }
|
|
34
|
+
else
|
|
35
|
+
next if obj.frozen?
|
|
36
|
+
obj.instance_variables.each { |ivar| stack << obj.instance_variable_get(ivar) }
|
|
37
|
+
end
|
|
38
|
+
obj.freeze
|
|
39
|
+
end
|
|
40
|
+
root
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.call(value)
|
|
44
|
+
case value
|
|
45
|
+
when Hash
|
|
46
|
+
return EMPTY_HASH if value.empty?
|
|
47
|
+
value.each_with_object({}) { |(k, v), out| out[call(k)] = call(v) }.freeze
|
|
48
|
+
when Array
|
|
49
|
+
return EMPTY_ARRAY if value.empty?
|
|
50
|
+
value.map { |v| call(v) }.freeze
|
|
51
|
+
when String
|
|
52
|
+
-value
|
|
53
|
+
when Symbol, Integer, Float, true, false, nil
|
|
54
|
+
value
|
|
55
|
+
else
|
|
56
|
+
raise Error, "cannot store a #{value.class} in a descriptor: #{value.inspect}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# A message type
|
|
6
|
+
class Message < Descriptor
|
|
7
|
+
# @return [File]
|
|
8
|
+
attr_reader :file
|
|
9
|
+
# @return [Message, nil] the enclosing message for a nested type
|
|
10
|
+
attr_reader :containing_message
|
|
11
|
+
# @return [Array<Field>] declaration order, oneof members included, extensions excluded
|
|
12
|
+
attr_reader :fields
|
|
13
|
+
# @return [Hash{Integer => Field}]
|
|
14
|
+
attr_reader :fields_by_number
|
|
15
|
+
# @return [Hash{String => Field}]
|
|
16
|
+
attr_reader :fields_by_name
|
|
17
|
+
# @return [Hash{String => Field}]
|
|
18
|
+
attr_reader :fields_by_json_name
|
|
19
|
+
# @return [Array<Oneof>] all oneofs, synthetic ones included
|
|
20
|
+
attr_reader :oneofs
|
|
21
|
+
# @return [Array<Oneof>] oneofs that are not synthetic (proto3 `optional`)
|
|
22
|
+
attr_reader :real_oneofs
|
|
23
|
+
# @return [Array<Message>]
|
|
24
|
+
attr_reader :nested_messages
|
|
25
|
+
# @return [Array<Enum>]
|
|
26
|
+
attr_reader :nested_enums
|
|
27
|
+
# @return [Array<Field>] extensions declared inside this message
|
|
28
|
+
attr_reader :extensions
|
|
29
|
+
# @return [Array<ExtensionRange>]
|
|
30
|
+
attr_reader :extension_range_descriptors
|
|
31
|
+
# @return [Array<Range>] inclusive extension number ranges
|
|
32
|
+
attr_reader :extension_ranges
|
|
33
|
+
# @return [Array<Range>] inclusive reserved number ranges
|
|
34
|
+
attr_reader :reserved_ranges
|
|
35
|
+
# @return [Array<String>]
|
|
36
|
+
attr_reader :reserved_names
|
|
37
|
+
# @return [Symbol, nil] declared `visibility`: :local or :export (edition 2024), nil when not declared
|
|
38
|
+
attr_reader :visibility
|
|
39
|
+
|
|
40
|
+
# @api private
|
|
41
|
+
def initialize(name:, full_name:, file:, containing_message:, index:)
|
|
42
|
+
@name = name
|
|
43
|
+
@full_name = full_name
|
|
44
|
+
@file = file
|
|
45
|
+
@containing_message = containing_message
|
|
46
|
+
@index = index
|
|
47
|
+
@reserved_ranges = Freezer::EMPTY_ARRAY
|
|
48
|
+
@reserved_names = Freezer::EMPTY_ARRAY
|
|
49
|
+
@visibility = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @api private
|
|
53
|
+
def __members(fields:, oneofs:, nested_messages:, nested_enums:, extensions:, extension_range_descriptors:)
|
|
54
|
+
@fields = fields
|
|
55
|
+
@oneofs = oneofs
|
|
56
|
+
@real_oneofs = oneofs.reject(&:synthetic?).freeze
|
|
57
|
+
@nested_messages = nested_messages
|
|
58
|
+
@nested_enums = nested_enums
|
|
59
|
+
@extensions = extensions
|
|
60
|
+
@extension_range_descriptors = extension_range_descriptors
|
|
61
|
+
@extension_ranges = extension_range_descriptors.map(&:range).freeze
|
|
62
|
+
@fields_by_number = {}
|
|
63
|
+
@fields_by_name = {}
|
|
64
|
+
@fields_by_json_name = {}
|
|
65
|
+
fields.each do |f|
|
|
66
|
+
@fields_by_number[f.number] ||= f
|
|
67
|
+
@fields_by_name[f.name] ||= f
|
|
68
|
+
@fields_by_json_name[f.json_name] ||= f
|
|
69
|
+
end
|
|
70
|
+
@fields_by_number.freeze
|
|
71
|
+
@fields_by_name.freeze
|
|
72
|
+
@fields_by_json_name.freeze
|
|
73
|
+
self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @param key [Integer, String, Symbol] a field number or name
|
|
77
|
+
# @return [Field, nil]
|
|
78
|
+
def field(key)
|
|
79
|
+
key.is_a?(Integer) ? @fields_by_number[key] : @fields_by_name[key.to_s]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Boolean] whether the number falls in an extension range
|
|
83
|
+
def extension_number?(number)
|
|
84
|
+
@extension_ranges.any? { |r| r.cover?(number) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [Boolean] a synthesized `map<K, V>` entry type
|
|
88
|
+
def map_entry?
|
|
89
|
+
options.map_entry?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# @return [Boolean]
|
|
93
|
+
def message_set_wire_format?
|
|
94
|
+
options.message_set_wire_format?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @param default_json_names [Boolean] see {File#to_proto}
|
|
98
|
+
# @return [Protostar::Google::Protobuf::DescriptorProto]
|
|
99
|
+
def to_proto(default_json_names: true)
|
|
100
|
+
Proto::Writer.message(self, default_json_names)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Protostar
|
|
4
|
+
module Schema
|
|
5
|
+
# A oneof, real or synthesized for a proto3 `optional` field
|
|
6
|
+
class Oneof < Descriptor
|
|
7
|
+
# @return [Message]
|
|
8
|
+
attr_reader :containing_message
|
|
9
|
+
# @return [Array<Field>] members in declaration order
|
|
10
|
+
attr_reader :fields
|
|
11
|
+
|
|
12
|
+
# @api private
|
|
13
|
+
def initialize(name:, full_name:, containing_message:, index:)
|
|
14
|
+
@name = name
|
|
15
|
+
@full_name = full_name
|
|
16
|
+
@containing_message = containing_message
|
|
17
|
+
@index = index
|
|
18
|
+
@fields = []
|
|
19
|
+
@synthetic = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [File]
|
|
23
|
+
def file
|
|
24
|
+
@containing_message.file
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Boolean] whether protoc synthesized it for a proto3 `optional` field
|
|
28
|
+
def synthetic?
|
|
29
|
+
@synthetic
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [Protostar::Google::Protobuf::OneofDescriptorProto]
|
|
33
|
+
def to_proto
|
|
34
|
+
Proto::Writer.oneof(self)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|