Skip to content

Commit

Permalink
Add wildcard option for auxiliary options.
Browse files Browse the repository at this point in the history
For #1584
  • Loading branch information
thesamet committed Oct 11, 2023
1 parent 01d5369 commit 3fac97a
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 15 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
CollectionAdapter for (#1509)
- Introduced new generator parameter `scala3_sources` (also available via
scalapb.proto) to generate sources that are compatible with Scala 3 (#1576)
- aux_*_options now accept "*" in the target field to match all entities in
scope.

## [0.11.13]
- Added input and output message type for method descriptor (#1503)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class DescriptorImplicits private[compiler] (

(fd.getFile.scalaOptions.getAuxFieldOptionsList.asScala
.collect {
case opt if opt.getTarget == fd.getFullName() => opt.getOptions
case opt if Helper.targetMatches(opt.getTarget(), fd.getFullName()) => opt.getOptions
} :+ localOptions).reduce[FieldOptions]((left, right) =>
left.toBuilder.mergeFrom(right).build()
)
Expand Down Expand Up @@ -532,9 +532,9 @@ class DescriptorImplicits private[compiler] (
val localOptions = message.getOptions.getExtension[MessageOptions](Scalapb.message)

message.getFile.scalaOptions.getAuxMessageOptionsList.asScala
.find(_.getTarget == message.getFullName())
.fold(localOptions)(aux =>
MessageOptions.newBuilder(aux.getOptions).mergeFrom(localOptions).build
.filter(o => Helper.targetMatches(o.getTarget, message.getFullName()))
.foldLeft(localOptions)((local, aux) =>
MessageOptions.newBuilder(aux.getOptions).mergeFrom(local).build
)
}

Expand Down Expand Up @@ -772,9 +772,9 @@ class DescriptorImplicits private[compiler] (
val localOptions = enumDescriptor.getOptions.getExtension[EnumOptions](Scalapb.enumOptions)

enumDescriptor.getFile.scalaOptions.getAuxEnumOptionsList.asScala
.find(_.getTarget == enumDescriptor.getFullName())
.fold(localOptions)(aux =>
EnumOptions.newBuilder(aux.getOptions).mergeFrom(localOptions).build
.filter(o => Helper.targetMatches(o.getTarget, enumDescriptor.getFullName()))
.foldLeft(localOptions)((local, aux) =>
EnumOptions.newBuilder(aux.getOptions).mergeFrom(local).build
)
}

Expand Down Expand Up @@ -862,9 +862,9 @@ class DescriptorImplicits private[compiler] (
val localOptions = enumValue.getOptions.getExtension[EnumValueOptions](Scalapb.enumValue)

enumValue.getFile.scalaOptions.getAuxEnumValueOptionsList.asScala
.find(_.getTarget == enumValue.getFullName())
.fold(localOptions)(aux =>
EnumValueOptions.newBuilder(aux.getOptions).mergeFrom(localOptions).build
.filter(o => Helper.targetMatches(o.getTarget, enumValue.getFullName()))
.foldLeft(localOptions)((local, aux) =>
EnumValueOptions.newBuilder(aux.getOptions).mergeFrom(local).build
)
}

Expand Down Expand Up @@ -1239,4 +1239,11 @@ object Helper {
.replace(">", ">")
.replace("\\", "&92;")
}

// Does the pattern matches the name. If the pattern is "*" the name always matches, otherwise
// must be an exact match. This may evolve in the future.
def targetMatches(pattern: String, name: String): Boolean = pattern match {
case "*" => true
case o => name == o
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,25 @@ class DescriptorImplicitsSpec extends AnyFlatSpec with Matchers with ProtocInvoc
.find(_.getFullName() == "inside_disable_flat.proto")
.get
.disableOutput must be(false)
}

"Helpers.targetMatches" should "do exact match when not *" in {
Helper.targetMatches("foo", "foo") must be(true)
Helper.targetMatches("foo", "") must be(false)
Helper.targetMatches("foo", "bar") must be(false)
Helper.targetMatches("", "") must be(true)
Helper.targetMatches("", "foo") must be(false)
}

"Helpers.targetMatches" should "return true when *" in {
Helper.targetMatches("*", "foo") must be(true)
Helper.targetMatches("*", "bar") must be(true)
Helper.targetMatches("*", "") must be(true)
Helper.targetMatches("*", "*") must be(true)
}

"Helpers.targetMatches" should "not support * as a generic wildcard" in {
Helper.targetMatches("foo.*", "foo.bar") must be(false)
Helper.targetMatches("foo.*.bar", "bar.giz.bar") must be(false)
}
}
3 changes: 2 additions & 1 deletion docs/src/main/markdown/customizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@ option (scalapb.options) = {
};
```

The list `aux_message_options` contains options targeted at different messages define under the same proto package of the package-scoped options. The `target` name needs to be fully-qualified message name in the protobuf namespace. Similar to `aux_message_options`, we also have `aux_enum_options`, `aux_enum_value_options` and `aux_field_options`. See [example usage here](https://github.com/scalapb/ScalaPB/tree/master/e2e/src/main/protobuf/scoped).
The list `aux_message_options` contains options targeted at different messages define under the same proto package of the package-scoped options. The `target` name needs to be fully-qualified message name in the protobuf namespace. Similar to `aux_message_options`, we also have `aux_enum_options`, `aux_enum_value_options` and `aux_field_options`. See [example usage here](https://github.com/scalapb/ScalaPB/tree/master/e2e/src/main/protobuf/scoped). If the target is set `*` then the options will be
applied to all the entities in the file or package (depending on the `scope` option).

## Primitive wrappers

Expand Down
26 changes: 26 additions & 0 deletions e2e/src/main/protobuf/scoped/wildcard.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
syntax = "proto3";

package scalapb.e2e.scoped;

import "scalapb/scalapb.proto";

option (scalapb.options) = {
aux_message_options: [
{
target: "scalapb.e2e.scoped.Wild2",
options: {
extends: "scalapb.e2e.scoped.SomeTrait"
}
},
{
target: "*"
options: {
extends: "scalapb.e2e.scoped.WildcardTrait"
}
}
]
};

message Wild1 {}

message Wild2 {}
3 changes: 3 additions & 0 deletions e2e/src/main/scala/scalapb/e2e/scoped/WildcardTrait.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scalapb.e2e.scoped

trait WildcardTrait
11 changes: 11 additions & 0 deletions e2e/src/test/scala/scoped/WildcardSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package scalapb.e2e.scoped

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
import scalapb.changed.scoped._

class WildcardSpec extends AnyFlatSpec with Matchers {
assert(Wild1().isInstanceOf[WildcardTrait])
assert(Wild2().isInstanceOf[WildcardTrait])
assert(Wild2().isInstanceOf[SomeTrait])
}
12 changes: 8 additions & 4 deletions protobuf/scalapb/scalapb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ message ScalaPbOptions {
// This is useful when you can't add a dependency on scalapb.proto from the proto file that
// defines the message.
message AuxMessageOptions {
// The fully-qualified name of the message in the proto name space.
// The fully-qualified name of the message in the proto name space. Set to `*` to apply to all
// messages in scope.
optional string target = 1;

// Options to apply to the message. If there are any options defined on the target message
Expand All @@ -121,7 +122,8 @@ message ScalaPbOptions {
// This is useful when you can't add a dependency on scalapb.proto from the proto file that
// defines the field.
message AuxFieldOptions {
// The fully-qualified name of the field in the proto name space.
// The fully-qualified name of the field in the proto name space. Set to `*` to apply to all
// fields in scope.
optional string target = 1;

// Options to apply to the field. If there are any options defined on the target message
Expand All @@ -133,7 +135,8 @@ message ScalaPbOptions {
// This is useful when you can't add a dependency on scalapb.proto from the proto file that
// defines the enum.
message AuxEnumOptions {
// The fully-qualified name of the enum in the proto name space.
// The fully-qualified name of the enum in the proto name space. Set to `*` to apply to
// all enums in scope.
optional string target = 1;

// Options to apply to the enum. If there are any options defined on the target enum
Expand All @@ -145,7 +148,8 @@ message ScalaPbOptions {
// options. This is useful when you can't add a dependency on scalapb.proto from the proto
// file that defines the enum.
message AuxEnumValueOptions {
// The fully-qualified name of the enum value in the proto name space.
// The fully-qualified name of the enum value in the proto name space. Set to `*` to apply
// to all enum values in scope.
optional string target = 1;

// Options to apply to the enum value. If there are any options defined on
Expand Down

0 comments on commit 3fac97a

Please sign in to comment.