diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c472f815f..62f254313 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/setup-java@v1 with: - java-version: 12 + java-version: 8 - name: Mount caches uses: actions/cache@v2 diff --git a/compiler-plugin/src/main/scala/scalapb/compiler/FieldTransformations.scala b/compiler-plugin/src/main/scala/scalapb/compiler/FieldTransformations.scala new file mode 100644 index 000000000..c4b1cf55a --- /dev/null +++ b/compiler-plugin/src/main/scala/scalapb/compiler/FieldTransformations.scala @@ -0,0 +1,306 @@ +package scalapb.compiler + +import com.google.protobuf.Message +import scalapb.options.Scalapb.FieldTransformation.MatchType +import com.google.protobuf.Descriptors.FieldDescriptor +import com.google.protobuf.Descriptors.FileDescriptor +import scala.jdk.CollectionConverters._ +import com.google.protobuf.DescriptorProtos.FieldOptions +import scalapb.options.Scalapb.FieldTransformation +import com.google.protobuf.DynamicMessage +import com.google.protobuf.Descriptors.FieldDescriptor.Type +import scalapb.options.Scalapb.ScalaPbOptions.AuxFieldOptions +import com.google.protobuf.Descriptors.Descriptor +import com.google.protobuf.ByteString +import java.util.regex.Pattern +import java.util.regex.Matcher + +private[compiler] case class ResolvedFieldTransformation( + whenFields: Map[FieldDescriptor, Any], + set: scalapb.options.Scalapb.FieldOptions, + matchType: MatchType +) + +private[compiler] object ResolvedFieldTransformation { + def apply( + currentFile: String, + ft: FieldTransformation, + extensions: Seq[FieldDescriptor] + ): ResolvedFieldTransformation = { + ResolvedFieldTransformation( + FieldTransformations.fieldMap( + currentFile, + FieldOptions.parseFrom(ft.getWhen.toByteArray()), + extensions = extensions + ), + ft.getSet(), + ft.getMatchType() + ) + } +} + +private[compiler] object FieldTransformations { + def matches[T <: Message]( + currentFile: String, + input: Map[FieldDescriptor, Any], + transformation: ResolvedFieldTransformation + ): Boolean = { + transformation.matchType match { + case MatchType.CONTAINS => + matchContains(currentFile, input, transformation.whenFields) + case MatchType.EXACT => input == transformation.whenFields + case MatchType.PRESENCE => matchPresence(input, transformation.whenFields) + } + } + + def matchContains( + currentFile: String, + input: Map[FieldDescriptor, Any], + pattern: Map[FieldDescriptor, Any] + ): Boolean = { + pattern.forall { + case (fd, v) => + input.get(fd) match { + case None => false + case Some(u) => + if (fd.getType() != Type.MESSAGE) + u == v + else + matchContains( + currentFile, + fieldMap(currentFile, u.asInstanceOf[Message], Seq.empty), + fieldMap(currentFile, v.asInstanceOf[Message], Seq.empty) + ) + } + } + } + + def processFieldTransformations( + f: FileDescriptor, + transforms: Seq[ResolvedFieldTransformation] + ): Seq[AuxFieldOptions] = + if (transforms.isEmpty) Seq.empty + else { + val extensions: Seq[FieldDescriptor] = fieldExtensionsForFile(f) + def processFile: Seq[AuxFieldOptions] = + f.getMessageTypes().asScala.flatMap(processMessage(_)).toSeq + + def processMessage(m: Descriptor): Seq[AuxFieldOptions] = { + m.getFields().asScala.flatMap(processField(_)) ++ + m.getNestedTypes().asScala.flatMap(processMessage(_)).toSeq + }.toSeq + + def processField(fd: FieldDescriptor): Seq[AuxFieldOptions] = + if (transforms.nonEmpty) { + val noReg = FieldOptions.parseFrom(fd.getOptions().toByteArray()) + val input = fieldMap(f.getFullName(), noReg, extensions) + transforms.flatMap { transform => + if (matches(f.getFullName(), input, transform)) + Seq( + AuxFieldOptions.newBuilder + .setTarget(fd.getFullName()) + .setOptions(interpolateStrings(transform.set, fd.getOptions(), extensions)) + .build + ) + else Seq.empty + } + } else Seq.empty + processFile + } + + def matchPresence( + input: Map[FieldDescriptor, Any], + pattern: Map[FieldDescriptor, Any] + ): Boolean = { + pattern.forall { + case (fd, value) => + if (fd.isRepeated()) + throw new GeneratorException( + "Presence matching on repeated fields is not supported" + ) + else if (fd.getType() == Type.MESSAGE && input.contains(fd)) + matchPresence( + input(fd).asInstanceOf[Message].getAllFields().asScala.toMap, + value.asInstanceOf[Message].getAllFields().asScala.toMap + ) + else + input.contains(fd) + } + } + + def fieldExtensionsForFile(f: FileDescriptor): Seq[FieldDescriptor] = { + (f +: f.getDependencies().asScala.toSeq).flatMap { + _.getExtensions().asScala.filter( + // Comparing the descriptors references directly will not work. The google.protobuf.FieldOptions + // we will get from `getContainingType` is the one we get from parsing the code generation request + // inputs, which are disjoint from the compilerplugin's FieldOptions. + _.getContainingType.getFullName == FieldOptions.getDescriptor().getFullName() + ) + } + } + + // Like m.getAllFields(), but also resolves unknown fields from extensions available in the scope + // of the message. + def fieldMap( + currentFile: String, + m: Message, + extensions: Seq[FieldDescriptor] + ): Map[FieldDescriptor, Any] = { + val unknownFields = for { + number <- m.getUnknownFields().asMap().keySet().asScala + } yield { + val ext = extensions + .find(_.getNumber == number) + .getOrElse( + throw new GeneratorException( + s"$currentFile: Could not find extension number $number for message ${m.toString()}" + ) + ) + ext -> getExtensionField(m, ext) + } + + unknownFields.toMap ++ m.getAllFields().asScala + } + + def getExtensionField(m: Message, ext: FieldDescriptor): Message = { + if (ext.getType != Type.MESSAGE || !ext.isOptional) { + throw new GeneratorException( + s"Unknown extension fields must be optional message types: ${ext}" + ) + } + val fieldValue = m.getUnknownFields().getField(ext.getNumber()) + DynamicMessage.parseFrom( + ext.getMessageType(), + fieldValue.getLengthDelimitedList().asScala.foldLeft(ByteString.EMPTY)(_.concat(_)) + ) + } + + def splitPath(s: String): List[String] = splitPath0(s, s) + + private def splitPath0(s: String, allPath: String): List[String] = { + if (s.isEmpty()) throw new GeneratorException(s"Got empty path component in $allPath") + else { + val tokenEnd = if (s.startsWith("[")) { + val end = s.indexOf(']') + 1 + if (end == -1) throw new GeneratorException(s"Unmatched [ in path $allPath") + if (s.length < end + 1 || s(end) != '.') + throw new GeneratorException( + s"Extension can not be the last path component. Expected . after ] in $allPath" + ) + end + } else { + s.indexOf('.') + } + if (tokenEnd == -1) s :: Nil + else s.substring(0, tokenEnd) :: splitPath0(s.substring(tokenEnd + 1), allPath) + } + } + + def fieldByPath( + message: Message, + path: String, + extensions: Seq[FieldDescriptor] + ): String = + if (path.isEmpty()) throw new GeneratorException("Got an empty path") + else + fieldByPath(message, splitPath(path), path, extensions) match { + case Left(error) => throw new GeneratorException(error) + case Right(value) => value + } + + private[compiler] def fieldByPath( + message: Message, + path: List[String], + allPath: String, + extensions: Seq[FieldDescriptor] + ): Either[String, String] = { + for { + fieldName <- path.headOption.toRight("Got an empty path") + fd <- if (fieldName.startsWith("[")) + extensions + .find(_.getFullName == fieldName.substring(1, fieldName.length() - 1)) + .toRight( + s"Could not find extension $fieldName when resolving $allPath" + ) + else + Option(message.getDescriptorForType().findFieldByName(fieldName)) + .toRight( + s"Could not find field named $fieldName when resolving $allPath" + ) + _ <- if (fd.isRepeated()) Left("Repeated fields are not supported") + else Right(()) + v = if (fd.isExtension) getExtensionField(message, fd) else message.getField(fd) + res <- path match { + case _ :: Nil => Right(v.toString()) + case _ :: tail => + if (fd.getType() == Type.MESSAGE) + fieldByPath(v.asInstanceOf[Message], tail, allPath, extensions) + else + Left( + s"Type ${fd.getType.toString} does not have a field ${tail.head} in $allPath" + ) + case Nil => Left("Unexpected empty path") + } + } yield res + } + + // Substitutes $(path) references in string fields within msg with values coming from the data + // message + private[compiler] def interpolateStrings[T <: Message]( + msg: T, + data: Message, + extensions: Seq[FieldDescriptor] + ): T = { + val b = msg.toBuilder() + for { + (field, value) <- msg.getAllFields().asScala + } field.getType() match { + case Type.STRING if (!field.isRepeated()) => + b.setField(field, interpolate(value.asInstanceOf[String], data, extensions)) + case Type.MESSAGE => + if (field.isRepeated()) + b.setField( + field, + value + .asInstanceOf[java.util.List[Message]] + .asScala + .map(interpolateStrings(_, data, extensions)) + .asJava + ) + else + b.setField( + field, + interpolateStrings(value.asInstanceOf[Message], data, extensions) + ) + case _ => + } + b.build().asInstanceOf[T] + } + + val FieldPath: java.util.regex.Pattern = + raw"[$$]\(([a-zA-Z0-9_.\[\]]*)\)".r.pattern + + // Interpolates paths in the given string with values coming from the data message + private[compiler] def interpolate( + value: String, + data: Message, + extensions: Seq[FieldDescriptor] + ): String = + replaceAll(value, FieldPath, m => fieldByPath(data, m.group(1), extensions)) + + // Matcher.replaceAll appeared on Java 9, so we have this Java 8 compatible version instead. Adapted + // from https://stackoverflow.com/a/43372206/97524 + private[compiler] def replaceAll( + templateText: String, + pattern: Pattern, + replacer: Matcher => String + ): String = { + val matcher = pattern.matcher(templateText) + val result = new StringBuffer() + while (matcher.find()) { + matcher.appendReplacement(result, replacer.apply(matcher)); + } + matcher.appendTail(result); + result.toString() + } +} diff --git a/compiler-plugin/src/main/scala/scalapb/compiler/FileOptionsCache.scala b/compiler-plugin/src/main/scala/scalapb/compiler/FileOptionsCache.scala index fe8a0a732..d07a4a2ac 100644 --- a/compiler-plugin/src/main/scala/scalapb/compiler/FileOptionsCache.scala +++ b/compiler-plugin/src/main/scala/scalapb/compiler/FileOptionsCache.scala @@ -8,13 +8,7 @@ import scala.collection.mutable import scala.jdk.CollectionConverters._ import scala.util.Success import scala.util.Failure -import scalapb.options.Scalapb.PreprocesserOutput - -private[this] case class PackageScopedOptions( - fileName: String, - `package`: String, - options: ScalaPbOptions -) +import scalapb.options.Scalapb.PreprocessorOutput object FileOptionsCache { def parentPackages(packageName: String): List[String] = { @@ -33,13 +27,69 @@ object FileOptionsCache { .newBuilder(parent) .mergeFrom(child) .setScope(child.getScope) // retain child's scope + r.build() + } - val preprocessorsIn = r.getPreprocessorsList.asScala.toSeq - r.clearPreprocessors - .addAllPreprocessors(clearNegatedPreprocessors(preprocessorsIn).asJava) - .build() + def reducePackageOptions[T]( + files: Seq[(FileDescriptor, ScalaPbOptions)], + data: (FileDescriptor, ScalaPbOptions) => T + )(op: (T, T) => T): Map[FileDescriptor, T] = { + val byPackage = new mutable.HashMap[String, T] + val output = new mutable.HashMap[FileDescriptor, T] + + // Process files by package name, and process package scoped options for each package first. + files + .sortBy(f => (f._1.getPackage(), f._2.getScope != OptionsScope.PACKAGE)) + .foreach { + case (f, opts) => + val isPackageScoped = (opts.getScope == OptionsScope.PACKAGE) + if (isPackageScoped && f.getPackage().isEmpty()) + throw new GeneratorException( + s"${f.getFullName()}: a package statement is required when package-scoped options are used" + ) + if (isPackageScoped && byPackage.contains(f.getPackage())) { + val dups = files + .filter(other => + other._1.getPackage() == f.getPackage() && other._2 + .getScope() == OptionsScope.PACKAGE + ) + .map(_._1.getFullName()) + .mkString(", ") + throw new GeneratorException( + s"Multiple files contain package-scoped options for package '${f.getPackage}': ${dups}" + ) + } + + if (isPackageScoped && opts.hasObjectName()) + throw new GeneratorException( + s"${f.getFullName()}: object_name is not allowed in package-scoped options." + ) + + val packagesToInheritFrom = + if (isPackageScoped) parentPackages(f.getPackage()) + else f.getPackage() :: parentPackages(f.getPackage()) + + val inherited = packagesToInheritFrom.find(byPackage.contains(_)).map(byPackage(_)) + + val res = inherited match { + case Some(base) => op(base, data(f, opts)) + case None => data(f, opts) + } + output += f -> res + if (isPackageScoped) { + byPackage += f.getPackage -> res + } + } + output.toMap } + // For each file, which preprocessors are enabled + def preprocessorsForFile(files: Seq[FileDescriptor]): Map[FileDescriptor, Seq[String]] = + reducePackageOptions[Seq[String]]( + files.map(f => (f, f.getOptions.getExtension(Scalapb.options))), + (_, opts) => opts.getPreprocessorsList.asScala.toSeq + )((parent, child) => clearNegatedPreprocessors(parent ++ child)) + @deprecated( "Use buildCache that takes SecondaryOutputProvider. Preprocessors will not work", "0.10.10" @@ -56,93 +106,88 @@ object FileOptionsCache { } def buildCache( - files: Seq[FileDescriptor], + filesIn: Seq[FileDescriptor], secondaryOutputProvider: SecondaryOutputProvider ): Map[FileDescriptor, ScalaPbOptions] = { + val preprocessorsByFile: Map[FileDescriptor, Seq[String]] = preprocessorsForFile(filesIn) - val givenPackageOptions: Seq[PackageScopedOptions] = - files - .filter(_.getOptions.getExtension(Scalapb.options).getScope == OptionsScope.PACKAGE) - .map { file => - PackageScopedOptions( - file.getName, - file.getPackage, - file.getOptions.getExtension(Scalapb.options) - ) - } - .sortBy(_.`package`.length) // so parent packages come before subpackages - - givenPackageOptions.filter(_.`package`.isEmpty).foreach { pso => - throw new GeneratorException( - s"${pso.fileName}: a package statement is required when package-scoped options are used" - ) - } - - givenPackageOptions.groupBy(_.`package`).find(_._2.length > 1).foreach { - case (pn, s) => + for { + (file, names) <- preprocessorsByFile + name <- names + } { + if (!SecondaryOutputProvider.isNameValid(name)) throw new GeneratorException( - s"Multiple files contain package-scoped options for package '${pn}': ${s.map(_.fileName).sorted.mkString(", ")}" + s"${file.getFullName()}: Invalid preprocessor name: '$name'" ) } - givenPackageOptions.find(_.options.hasObjectName).foreach { pso => - throw new GeneratorException( - s"${pso.fileName}: object_name is not allowed in package-scoped options." - ) - } - - // Merge package-scoped options of parent packages with sub-packages, so for each package it - // is sufficient to look up the nearest parent package that has package-scoped options. - val optionsByPackage = new mutable.HashMap[String, ScalaPbOptions] - - givenPackageOptions.foreach { - case pso => - val parents: List[String] = parentPackages(pso.`package`) - val actualOptions = parents.find(optionsByPackage.contains) match { - case Some(p) => mergeOptions(optionsByPackage(p), pso.options) - case None => pso.options - } - optionsByPackage += pso.`package` -> actualOptions - } - - files.map { f => - val opts = if (f.getOptions.getExtension(Scalapb.options).getScope == OptionsScope.PACKAGE) { - optionsByPackage(f.getPackage) - } else { - (f.getPackage :: parentPackages(f.getPackage)).find(optionsByPackage.contains) match { - case Some(p) => - mergeOptions(optionsByPackage(p), f.getOptions.getExtension(Scalapb.options)) - case None => f.getOptions.getExtension(Scalapb.options) - } - } - - val preprocessors = opts.getPreprocessorsList().asScala.flatMap { name => - if (!SecondaryOutputProvider.isNameValid(name)) - throw new GeneratorException(s"${f.getFullName()}: Invalid preprocessor name: '$name'") - secondaryOutputProvider.get(name) match { - case Success(output) => - FileOptionsCache.validatePreprocessorOutput(name, output) - Some(output) - case Failure(exception) => - throw GeneratorException(s"${f.getFullName}: ${exception.getMessage()}") - } + val allPreprocessorNames: Set[String] = preprocessorsByFile.values.flatten.toSet + val preprocessorValues: Map[String, PreprocessorOutput] = allPreprocessorNames.map { name => + secondaryOutputProvider.get(name) match { + case Success(output) => + FileOptionsCache.validatePreprocessorOutput(name, output) + name -> output + case Failure(exception) => + val files = preprocessorsByFile + .collect { + case (fd, preprocessors) if preprocessors.contains(name) => fd.getFullName() + } + .mkString(", ") + throw GeneratorException(s"$files: ${exception.getMessage()}") } + }.toMap - val preprocessorsProvidedOptions = for { - proc <- preprocessors - fn <- Option(proc.getOptionsByFileMap.get(f.getFullName())) - } yield fn - - val effectiveOpts = preprocessorsProvidedOptions.foldRight(opts)(mergeOptions(_, _)) + val processedOptions: Map[FileDescriptor, ScalaPbOptions] = preprocessorsByFile.map { + case (file, preprocessorsForFile) => + file -> preprocessorsForFile + .flatMap(name => + Option(preprocessorValues(name).getOptionsByFileMap.get(file.getFullName())) + ) + .foldRight(file.getOptions().getExtension(Scalapb.options))(mergeOptions(_, _)) + }.toMap - f -> effectiveOpts + val fileOptions = reducePackageOptions[ScalaPbOptions]( + filesIn.map(f => (f, processedOptions(f))), + (_, opts) => opts + )( + mergeOptions(_, _) + ) + + val fieldTransformations = reducePackageOptions[Seq[ResolvedFieldTransformation]]( + filesIn.map(f => (f, processedOptions(f))), + (file, opts) => + opts + .getFieldTransformationsList() + .asScala + .map(t => + ResolvedFieldTransformation( + file.getFullName(), + t, + FieldTransformations.fieldExtensionsForFile(file) + ) + ) + .toSeq + )(_ ++ _) + + fileOptions.map { + case (f, opts) => + f -> + (if (opts.getIgnoreFieldTransformations) opts + else + opts.toBuilder + .addAllAuxFieldOptions( + FieldTransformations + .processFieldTransformations(f, fieldTransformations(f)) + .asJava + ) + .build()) }.toMap } private[scalapb] def validatePreprocessorOutput( name: String, - output: PreprocesserOutput - ): PreprocesserOutput = { + output: PreprocessorOutput + ): PreprocessorOutput = { output.getOptionsByFileMap().asScala.find(_._2.getScope() != OptionsScope.FILE).foreach { ev => throw new GeneratorException( s"Preprocessor options must be file-scoped. Preprocessor '${name}' provided scope '${ev._2 diff --git a/compiler-plugin/src/main/scala/scalapb/compiler/SecondaryOutputProvider.scala b/compiler-plugin/src/main/scala/scalapb/compiler/SecondaryOutputProvider.scala index 994729835..e8c6e61cd 100644 --- a/compiler-plugin/src/main/scala/scalapb/compiler/SecondaryOutputProvider.scala +++ b/compiler-plugin/src/main/scala/scalapb/compiler/SecondaryOutputProvider.scala @@ -1,6 +1,6 @@ package scalapb.compiler -import scalapb.options.Scalapb.PreprocesserOutput +import scalapb.options.Scalapb.PreprocessorOutput import java.io.File import java.nio.file.Files import com.google.protobuf.InvalidProtocolBufferException @@ -13,18 +13,18 @@ import scala.util.Success import scala.util.Failure trait SecondaryOutputProvider { - def get(name: String): Try[PreprocesserOutput] + def get(name: String): Try[PreprocessorOutput] } private final class FileBasedSecondaryOutputProvider(inputDir: File) extends SecondaryOutputProvider { - val cache = new HashMap[String, Try[PreprocesserOutput]] + val cache = new HashMap[String, Try[PreprocessorOutput]] - def get(name: String): Try[PreprocesserOutput] = { + def get(name: String): Try[PreprocessorOutput] = { cache.getOrElseUpdate(name, doGet(name)) } - private def doGet(name: String): Try[PreprocesserOutput] = { + private def doGet(name: String): Try[PreprocessorOutput] = { // names are checked in ProtoValidation. We check here again in case we somehow got here // through a different path. if (!SecondaryOutputProvider.isNameValid(name)) @@ -37,7 +37,7 @@ private final class FileBasedSecondaryOutputProvider(inputDir: File) } val bytes = Files.readAllBytes(in) Try { - com.google.protobuf.Any.parseFrom(bytes).unpack(classOf[PreprocesserOutput]) + com.google.protobuf.Any.parseFrom(bytes).unpack(classOf[PreprocessorOutput]) }.recoverWith { case e: InvalidProtocolBufferException => throw new GeneratorException( @@ -47,16 +47,16 @@ private final class FileBasedSecondaryOutputProvider(inputDir: File) } } -private final class InMemorySecondaryOutputProvider(map: Map[String, PreprocesserOutput]) +private final class InMemorySecondaryOutputProvider(map: Map[String, PreprocessorOutput]) extends SecondaryOutputProvider { - def get(name: String): Try[PreprocesserOutput] = map.get(name) match { + def get(name: String): Try[PreprocessorOutput] = map.get(name) match { case Some(v) => Success(v) case None => Failure(new GeneratorException(s"Preprocessor '$name' was not found.")) } } private object EmptySecondaryOutputProvider extends SecondaryOutputProvider { - def get(name: String): Try[PreprocesserOutput] = + def get(name: String): Try[PreprocessorOutput] = Try( throw new GeneratorException( "No secondary outputs available. The most likely causes are that " + @@ -89,6 +89,6 @@ object SecondaryOutputProvider { def isNameValid(name: String) = VALID_NAME_REGEX.pattern.matcher(name).matches() // For testing only - def fromMap(map: Map[String, PreprocesserOutput]): SecondaryOutputProvider = + def fromMap(map: Map[String, PreprocessorOutput]): SecondaryOutputProvider = new InMemorySecondaryOutputProvider(map) } diff --git a/compiler-plugin/src/test/scala/scalapb/compiler/FieldTransformationsSpec.scala b/compiler-plugin/src/test/scala/scalapb/compiler/FieldTransformationsSpec.scala new file mode 100644 index 000000000..36fbc33d8 --- /dev/null +++ b/compiler-plugin/src/test/scala/scalapb/compiler/FieldTransformationsSpec.scala @@ -0,0 +1,340 @@ +package scalapb.compiler + +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.must.Matchers + +import scala.jdk.CollectionConverters._ +import com.google.protobuf.DynamicMessage +import com.google.protobuf.TextFormat +import com.google.protobuf.DescriptorProtos.FieldOptions +import com.google.protobuf.UnknownFieldSet +import com.google.protobuf.UnknownFieldSet.Field +import scalapb.options.Scalapb.ScalaPbOptions + +class FieldTransformationsSpec extends AnyFlatSpec with Matchers with ProtocInvocationHelper { + val base = Seq( + "myvalidate.proto" -> + """|syntax = "proto2"; + |package opts; + |import "google/protobuf/descriptor.proto"; + |message FieldRules { + | optional Int32Rules int32 = 1; + |} + |message Int32Rules { + | optional int32 gt = 1; + | optional int32 gte = 2; + | optional int32 lt = 3; + |} + |extend google.protobuf.FieldOptions { + | optional FieldRules rules = 50001; + |}; + """.stripMargin, + "locals.proto" -> + """|syntax = "proto3"; + |package local; + |import "myvalidate.proto"; + |import "scalapb/scalapb.proto"; + |option (scalapb.options) = { + | field_transformations: [ + | { + | when { + | [opts.rules] { + | int32: {gt: 17} + | } + | } + | set { + | type: "MatchGt17" + | } + | } + | ] + |}; + |message X { + | int32 x = 1 [(opts.rules).int32 = {gt: 17}]; + |} + |""".stripMargin, + "package.proto" -> + """|syntax = "proto3"; + |package pkg; + |import "myvalidate.proto"; + |import "scalapb/scalapb.proto"; + |option (scalapb.options) = { + | scope: PACKAGE + | field_transformations: [ + | { + | when { + | [opts.rules] { + | int32: {gt: 12} + | } + | } + | set { + | type: "MatchGt12" + | } + | }, + | { + | when { + | [opts.rules] { + | int32: {lt: 1} + | } + | } + | match_type: PRESENCE + | set { + | type: "MatchLt[$([opts.rules].int32.lt)]" + | } + | } + | ] + |}; + |""".stripMargin, + "inherits.proto" -> + """|syntax = "proto3"; + |package pkg; + |import "myvalidate.proto"; + |message X { + | int32 x = 1 [(opts.rules).int32 = {gt: 12}]; + | int32 y = 2 [(opts.rules).int32 = {lt: 317}]; + |} + |""".stripMargin, + "ignores.proto" -> + """|syntax = "proto3"; + |package pkg; + |import "myvalidate.proto"; + |import "scalapb/scalapb.proto"; + |option (scalapb.options) = { + | ignore_field_transformations: true + |}; + |message I { + | int32 x = 1 [(opts.rules).int32 = {gt: 12}]; + |} + |""".stripMargin + ) + val files = generateFileSet(base) + val cache = FileOptionsCache.buildCache(files, SecondaryOutputProvider.empty) + val locals = files.find(_.getFullName() == "locals.proto").get + val inherits = files.find(_.getFullName() == "inherits.proto").get + val ignores = files.find(_.getFullName() == "ignores.proto").get + val extensions = FieldTransformations.fieldExtensionsForFile(inherits) + + val fieldRulesDesc = files + .flatMap { f => f.getMessageTypes().asScala } + .find(_.getFullName == "opts.FieldRules") + .get + + def fieldRules(s: String): FieldOptions = { + val dm = DynamicMessage.newBuilder(fieldRulesDesc) + TextFormat.merge(s, dm) + dm.build() + FieldOptions + .newBuilder() + .setUnknownFields( + UnknownFieldSet + .newBuilder() + .addField( + 50001, + Field + .newBuilder() + .addLengthDelimited( + dm.build().toByteString() + ) + .build() + ) + .build() + ) + .build() + } + + def matchPresence(msg: String, pattern: String): Boolean = { + FieldTransformations.matchPresence( + FieldTransformations.fieldMap("-", fieldRules(msg), extensions), + FieldTransformations.fieldMap("-", fieldRules(pattern), extensions) + ) + } + + "splitPath" should "split path correctly" in { + intercept[GeneratorException] { + FieldTransformations.splitPath("") + }.getMessage() must startWith("Got empty path component") + FieldTransformations.splitPath("foo.bar.baz") must be(List("foo", "bar", "baz")) + FieldTransformations.splitPath("foo") must be(List("foo")) + intercept[GeneratorException] { + FieldTransformations.splitPath("foo.") + }.getMessage() must startWith("Got empty path component") + FieldTransformations.splitPath("[foo].bar.baz") must be(List("[foo]", "bar", "baz")) + FieldTransformations.splitPath("[foo].x") must be(List("[foo]", "x")) + intercept[GeneratorException] { + FieldTransformations.splitPath("[foo]") + }.getMessage() must startWith("Extension can not be the last") + intercept[GeneratorException] { + FieldTransformations.splitPath("[foo].") + }.getMessage() must startWith("Got empty path component") + } + + "field transformations" should "work when local, inherited and ignored" in { + cache(locals) + .getAuxFieldOptionsList() + .asScala + .find(_.getTarget() == "local.X.x") + .get + .getOptions() + .getType() must be("MatchGt17") + cache(inherits) + .getAuxFieldOptionsList() + .asScala + .find(_.getTarget() == "pkg.X.x") + .get + .getOptions() + .getType() must be("MatchGt12") + cache(inherits) + .getAuxFieldOptionsList() + .asScala + .find(_.getTarget() == "pkg.X.y") + .get + .getOptions() + .getType() must be("MatchLt[317]") + cache(ignores) + .getAuxFieldOptionsList() + .asScala + .find(_.getTarget() == "pkg.I.x") must be(None) + } + + "matchPresence" must "match correctly" in { + matchPresence( + msg = "", + pattern = "" + ) must be(true) + + matchPresence( + msg = "", + pattern = "int32: {gt: 1}" + ) must be(false) + + matchPresence( + msg = "int32: {gt: 2}", + pattern = "int32: {gt: 1}" + ) must be(true) + + matchPresence( + msg = "int32: {gt: 0}", + pattern = "int32: {gt: 1}" + ) must be(true) + + matchPresence( + msg = "int32: {gt: 0}", + pattern = "int32: {gt: 0}" + ) must be(true) + + matchPresence( + msg = "int32: {}", + pattern = "int32: {}" + ) must be(true) + + matchPresence( + msg = "int32: {}", + pattern = "int32: {gt: 0}" + ) must be(false) + + matchPresence( + msg = "int32: {gt: 0}", + pattern = "int32: {}" + ) must be(true) + + matchPresence( + msg = "int32: {gt: 0, lt: 0}", + pattern = "int32: {gt: 0}" + ) must be(true) + } + + def fieldByPath(fo: FieldOptions, path: String) = + FieldTransformations.fieldByPath(fo, path, extensions) + + "fieldByPath" should "return correct result" in { + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "[opts.rules].int32.gt" + ) must be("1") + + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "[opts.rules].int32.lt" + ) must be("2") + + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "[opts.rules].int32.gte" + ) must be("0") + + intercept[GeneratorException] { + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "[opts.rules].int32.foo" + ) + }.getMessage must be("Could not find field named foo when resolving [opts.rules].int32.foo") + + intercept[GeneratorException] { + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "[opts.rules].int32.gt.lt" + ) + }.getMessage must be( + "Type INT32 does not have a field lt in [opts.rules].int32.gt.lt" + ) + + intercept[GeneratorException] { + fieldByPath( + fieldRules("int32: {gt: 1, lt: 2}"), + "" + ) + }.getMessage() must be("Got an empty path") + } + + import FieldTransformations.interpolateStrings + + def fieldOptions(s: String) = TextFormat.parse(s, classOf[scalapb.options.Scalapb.FieldOptions]) + + def scalapbOptions(s: String) = TextFormat.parse(s, classOf[ScalaPbOptions]) + + "interpolateStrings" should "interpolate strings" in { + interpolateStrings( + fieldOptions("type: \"Thingie($([opts.rules].int32.gt))\""), + fieldRules("int32: {gt: 1, lt: 2}"), + extensions + ) must be( + fieldOptions("type: \"Thingie(1)\"") + ) + + interpolateStrings( + fieldOptions("type: \"Thingie($([opts.rules].int32.gt), $([opts.rules].int32.lt))\""), + fieldRules("int32: {gt: 1, lt: 2}"), + extensions + ) must be( + fieldOptions("type: \"Thingie(1, 2)\"") + ) + + interpolateStrings( + fieldOptions("type: \"Thingie($([opts.rules].int32.gte))\""), + fieldRules("int32: {gt: 1, lt: 2}"), + extensions + ) must be( + fieldOptions("type: \"Thingie(0)\"") + ) + + // To test that it looks into nested fields: + interpolateStrings( + scalapbOptions( + "aux_field_options { options: { type: \"Thingie($([opts.rules].int32.gt))\" } }" + ), + fieldRules("int32: {gt: 1, lt: 2}"), + extensions + ) must be( + scalapbOptions("aux_field_options: { options: {type: \"Thingie(1)\"} }") + ) + + intercept[GeneratorException] { + interpolateStrings( + fieldOptions("type: \"Thingie($([opts.rules].int32.gtx))\""), + fieldRules("int32: {gt: 1, lt: 2}"), + extensions + ) + }.getMessage() must be( + "Could not find field named gtx when resolving [opts.rules].int32.gtx" + ) + } +} diff --git a/compiler-plugin/src/test/scala/scalapb/compiler/FileOptionsCacheSpec.scala b/compiler-plugin/src/test/scala/scalapb/compiler/FileOptionsCacheSpec.scala index 2eb2690b5..becf3ae60 100644 --- a/compiler-plugin/src/test/scala/scalapb/compiler/FileOptionsCacheSpec.scala +++ b/compiler-plugin/src/test/scala/scalapb/compiler/FileOptionsCacheSpec.scala @@ -7,7 +7,7 @@ import scalapb.options.Scalapb.ScalaPbOptions.OptionsScope import scala.jdk.CollectionConverters._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers -import scalapb.options.Scalapb.PreprocesserOutput +import scalapb.options.Scalapb.PreprocessorOutput class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { "parentPackages" should "return correct parent packages" in { @@ -214,7 +214,7 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { val provider = SecondaryOutputProvider.fromMap( Map( - "preproc" -> PreprocesserOutput + "preproc" -> PreprocessorOutput .newBuilder() .putOptionsByFile( "p1.proto", @@ -261,7 +261,7 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { val provider = SecondaryOutputProvider.fromMap( Map( - "preproc" -> PreprocesserOutput + "preproc" -> PreprocessorOutput .newBuilder() .putOptionsByFile( "p1.proto", @@ -340,7 +340,7 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { val provider = SecondaryOutputProvider.fromMap( Map( "preproc" -> - PreprocesserOutput + PreprocessorOutput .newBuilder() .putOptionsByFile( "p1.x.proto", @@ -394,8 +394,9 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { |""".stripMargin, "p1.x.proto" -> """|package_name: "scc.p1" - |import: "i4" + |import: "iz" |import: "i1" + |import: "i4" |import: "i2" |single_file: true |scope: FILE @@ -403,6 +404,7 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { |""".stripMargin, "p1.y.proto" -> """|package_name: "scc.p1" + |import: "iz" |import: "i1" |import: "i3" |single_file: true @@ -411,10 +413,13 @@ class FileOptionsCacheSpec extends AnyFlatSpec with Matchers { |""".stripMargin, "p1.z.proto" -> """|package_name: "scc.p1" + |import: "iz" |import: "i1" |import: "i4" |single_file: true |scope: FILE + |preprocessors: "preproc" + |preprocessors: "-preproc" |""".stripMargin ) ) diff --git a/compiler-plugin/src/test/scala/scalapb/compiler/ProtoValidationSpec.scala b/compiler-plugin/src/test/scala/scalapb/compiler/ProtoValidationSpec.scala index ededdec97..e564b31f0 100644 --- a/compiler-plugin/src/test/scala/scalapb/compiler/ProtoValidationSpec.scala +++ b/compiler-plugin/src/test/scala/scalapb/compiler/ProtoValidationSpec.scala @@ -1,66 +1,9 @@ package scalapb.compiler -import java.io.{File, FileInputStream, PrintWriter} -import java.nio.file.Files - -import scala.jdk.CollectionConverters._ -import com.google.protobuf.DescriptorProtos.FileDescriptorSet -import com.google.protobuf.Descriptors.FileDescriptor -import com.google.protobuf.ExtensionRegistry -import scalapb.options.Scalapb import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers -class ProtoValidationSpec extends AnyFlatSpec with Matchers { - def generateFileSet(files: Seq[(String, String)]) = { - val tmpDir = Files.createTempDirectory("validation").toFile - val fileNames = files.map { - case (name, content) => - val file = new File(tmpDir, name) - val pw = new PrintWriter(file) - pw.write(content) - pw.close() - file.getAbsoluteFile - } - val outFile = new File(tmpDir, "descriptor.out") - - require( - ProtocRunner - .forVersion(Version.protobufVersion) - .run( - Seq( - "-I", - tmpDir.toString + ":protobuf:third_party", - s"--descriptor_set_out=${outFile.toString}", - "--include_imports" - ) ++ fileNames.map(_.toString), - Seq.empty - ) == 0, - "protoc exited with an error" - ) - - val fileset: Seq[FileDescriptor] = { - val fin = new FileInputStream(outFile) - val registry = ExtensionRegistry.newInstance() - Scalapb.registerAllExtensions(registry) - val fileset = - try { - FileDescriptorSet.parseFrom(fin, registry) - } finally { - fin.close() - } - fileset.getFileList.asScala - .foldLeft[Map[String, FileDescriptor]](Map.empty) { - case (acc, fp) => - val deps = fp.getDependencyList.asScala.map(acc) - acc + (fp.getName -> FileDescriptor.buildFrom(fp, deps.toArray)) - } - .values - .toVector - } - fileset - } - +class ProtoValidationSpec extends AnyFlatSpec with Matchers with ProtocInvocationHelper { def runValidation( generatorParams: GeneratorParams, secondaryOutput: SecondaryOutputProvider, diff --git a/compiler-plugin/src/test/scala/scalapb/compiler/ProtocInvocationHelper.scala b/compiler-plugin/src/test/scala/scalapb/compiler/ProtocInvocationHelper.scala new file mode 100644 index 000000000..00e1b57fc --- /dev/null +++ b/compiler-plugin/src/test/scala/scalapb/compiler/ProtocInvocationHelper.scala @@ -0,0 +1,62 @@ +package scalapb.compiler + +import com.google.protobuf.Descriptors.FileDescriptor +import java.nio.file.Files +import java.io.File +import java.io.PrintWriter +import java.io.FileInputStream +import com.google.protobuf.ExtensionRegistry +import scalapb.options.Scalapb +import com.google.protobuf.DescriptorProtos.FileDescriptorSet +import scala.jdk.CollectionConverters._ + +trait ProtocInvocationHelper { + def generateFileSet(files: Seq[(String, String)]): Seq[FileDescriptor] = { + val tmpDir = Files.createTempDirectory("validation").toFile + val fileNames = files.map { + case (name, content) => + val file = new File(tmpDir, name) + val pw = new PrintWriter(file) + pw.write(content) + pw.close() + file.getAbsoluteFile + } + val outFile = new File(tmpDir, "descriptor.out") + + require( + ProtocRunner + .forVersion(Version.protobufVersion) + .run( + Seq( + "-I", + tmpDir.toString + ":protobuf:third_party", + s"--descriptor_set_out=${outFile.toString}", + "--include_imports" + ) ++ fileNames.map(_.toString), + Seq.empty + ) == 0, + "protoc exited with an error" + ) + + val fileset: Seq[FileDescriptor] = { + val fin = new FileInputStream(outFile) + val registry = ExtensionRegistry.newInstance() + Scalapb.registerAllExtensions(registry) + val fileset = + try { + FileDescriptorSet.parseFrom(fin, registry) + } finally { + fin.close() + } + fileset.getFileList.asScala + .foldLeft[Map[String, FileDescriptor]](Map.empty) { + case (acc, fp) => + val deps = fp.getDependencyList.asScala.map(acc) + acc + (fp.getName -> FileDescriptor.buildFrom(fp, deps.toArray)) + } + .values + .toVector + } + fileset + } +} diff --git a/e2e/src/main/protobuf/transformations/field_transformations.proto b/e2e/src/main/protobuf/transformations/field_transformations.proto new file mode 100644 index 000000000..9a34b8207 --- /dev/null +++ b/e2e/src/main/protobuf/transformations/field_transformations.proto @@ -0,0 +1,47 @@ +syntax = "proto2"; + +package com.thesamet.proto.e2e.transformations; + +import "transformations/option.proto"; +import "scalapb/scalapb.proto"; + +option (scalapb.options) = { + field_transformations : [ + { + when : { + [com.thesamet.proto.e2e.transformations.custom]{sensitive : true} + } + set : {type : 'com.thesamet.proto.e2e.SensitiveString'} + }, + { + when : { + [com.thesamet.proto.e2e.transformations.custom]{ + sensitive : true, + vnum : 1 + } + } + match_type : PRESENCE, + set : { + type : 'com.thesamet.proto.e2e.SensitiveString$([com.thesamet.proto.e2e.transformations.custom].vnum)' + }, + }, + { + when : { + [com.thesamet.proto.e2e.transformations.custom]{ + nested : {nn: {n: 4}} + } + } + match_type : CONTAINS, + set : { + scala_name: 'nested_four' + }, + } + ] +}; + +message Usage { + optional string foo = 1 [ (custom).sensitive = true ]; + optional string foover = 2 [ (custom).sensitive = true, (custom).vnum = 7 ]; + optional string sensitive_other = 3 [ (custom).sensitive = true, (custom).other = 8 ]; + optional string nested = 4 [ (custom).nested.nn.n = 4 ]; +} \ No newline at end of file diff --git a/e2e/src/main/protobuf/transformations/option.proto b/e2e/src/main/protobuf/transformations/option.proto new file mode 100644 index 000000000..545dde632 --- /dev/null +++ b/e2e/src/main/protobuf/transformations/option.proto @@ -0,0 +1,22 @@ + +syntax = "proto2"; + +package com.thesamet.proto.e2e.transformations; + +import "google/protobuf/descriptor.proto"; + +message Nested { + optional int32 n = 1; + optional Nested nn = 2; +} + +message MyCustomFieldOptions { + optional bool sensitive = 1; + optional int32 vnum = 2; + optional int32 other = 3; + optional Nested nested = 4; +} + +extend google.protobuf.FieldOptions { + optional MyCustomFieldOptions custom = 50001; +} \ No newline at end of file diff --git a/e2e/src/main/scala/com/thesamet/proto/e2e/SensitiveString.scala b/e2e/src/main/scala/com/thesamet/proto/e2e/SensitiveString.scala new file mode 100644 index 000000000..3c9423981 --- /dev/null +++ b/e2e/src/main/scala/com/thesamet/proto/e2e/SensitiveString.scala @@ -0,0 +1,17 @@ +package com.thesamet.proto.e2e + +import scalapb.TypeMapper + +final case class SensitiveString(s: String) + +final case class SensitiveString7(s: String) + +object SensitiveString { + implicit val tm: TypeMapper[String, SensitiveString] = + TypeMapper[String, SensitiveString](SensitiveString(_))(_.s) +} + +object SensitiveString7 { + implicit val tm7: TypeMapper[String, SensitiveString7] = + TypeMapper[String, SensitiveString7](SensitiveString7(_))(_.s) +} diff --git a/protobuf/scalapb/scalapb.proto b/protobuf/scalapb/scalapb.proto index b3aa58000..298fed959 100644 --- a/protobuf/scalapb/scalapb.proto +++ b/protobuf/scalapb/scalapb.proto @@ -149,6 +149,12 @@ message ScalaPbOptions { repeated string preprocessors = 24; + repeated FieldTransformation field_transformations = 25; + + // Ignores field transformations for this file. This is meant to allow specific files to + // opt out from field transformations inherited through package-scoped options. + optional bool ignore_field_transformations = 26; + // For use in tests only. Inhibit Java conversions even when when generator parameters // request for it. optional bool test_only_no_java_conversions = 999; @@ -306,6 +312,17 @@ extend google.protobuf.OneofOptions { optional OneofOptions oneof = 1020; } -message PreprocesserOutput { +message FieldTransformation { + optional google.protobuf.FieldOptions when = 1; + enum MatchType { + CONTAINS = 0; + EXACT = 1; + PRESENCE = 2; + } + optional MatchType match_type = 2 [default=CONTAINS]; + optional FieldOptions set = 3; +} + +message PreprocessorOutput { map options_by_file = 1; } diff --git a/scalapb-runtime/shared/src/main/scala/scalapb/options/FieldTransformation.scala b/scalapb-runtime/shared/src/main/scala/scalapb/options/FieldTransformation.scala new file mode 100644 index 000000000..b80147691 --- /dev/null +++ b/scalapb-runtime/shared/src/main/scala/scalapb/options/FieldTransformation.scala @@ -0,0 +1,245 @@ +// Generated by the Scala Plugin for the Protocol Buffer Compiler. +// Do not edit! +// +// Protofile syntax: PROTO2 + +package scalapb.options + +@SerialVersionUID(0L) +final case class FieldTransformation( + when: _root_.scala.Option[com.google.protobuf.descriptor.FieldOptions] = _root_.scala.None, + matchType: _root_.scala.Option[scalapb.options.FieldTransformation.MatchType] = _root_.scala.None, + set: _root_.scala.Option[scalapb.options.FieldOptions] = _root_.scala.None, + unknownFields: _root_.scalapb.UnknownFieldSet = _root_.scalapb.UnknownFieldSet.empty + ) extends scalapb.GeneratedMessage with scalapb.lenses.Updatable[FieldTransformation] { + @transient + private[this] var __serializedSizeCachedValue: _root_.scala.Int = 0 + private[this] def __computeSerializedValue(): _root_.scala.Int = { + var __size = 0 + if (when.isDefined) { + val __value = when.get + __size += 1 + _root_.com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(__value.serializedSize) + __value.serializedSize + }; + if (matchType.isDefined) { + val __value = matchType.get.value + __size += _root_.com.google.protobuf.CodedOutputStream.computeEnumSize(2, __value) + }; + if (set.isDefined) { + val __value = set.get + __size += 1 + _root_.com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(__value.serializedSize) + __value.serializedSize + }; + __size += unknownFields.serializedSize + __size + } + override def serializedSize: _root_.scala.Int = { + var read = __serializedSizeCachedValue + if (read == 0) { + read = __computeSerializedValue() + __serializedSizeCachedValue = read + } + read + } + def writeTo(`_output__`: _root_.com.google.protobuf.CodedOutputStream): _root_.scala.Unit = { + when.foreach { __v => + val __m = __v + _output__.writeTag(1, 2) + _output__.writeUInt32NoTag(__m.serializedSize) + __m.writeTo(_output__) + }; + matchType.foreach { __v => + val __m = __v.value + _output__.writeEnum(2, __m) + }; + set.foreach { __v => + val __m = __v + _output__.writeTag(3, 2) + _output__.writeUInt32NoTag(__m.serializedSize) + __m.writeTo(_output__) + }; + unknownFields.writeTo(_output__) + } + def getWhen: com.google.protobuf.descriptor.FieldOptions = when.getOrElse(com.google.protobuf.descriptor.FieldOptions.defaultInstance) + def clearWhen: FieldTransformation = copy(when = _root_.scala.None) + def withWhen(__v: com.google.protobuf.descriptor.FieldOptions): FieldTransformation = copy(when = Option(__v)) + def getMatchType: scalapb.options.FieldTransformation.MatchType = matchType.getOrElse(scalapb.options.FieldTransformation.MatchType.CONTAINS) + def clearMatchType: FieldTransformation = copy(matchType = _root_.scala.None) + def withMatchType(__v: scalapb.options.FieldTransformation.MatchType): FieldTransformation = copy(matchType = Option(__v)) + def getSet: scalapb.options.FieldOptions = set.getOrElse(scalapb.options.FieldOptions.defaultInstance) + def clearSet: FieldTransformation = copy(set = _root_.scala.None) + def withSet(__v: scalapb.options.FieldOptions): FieldTransformation = copy(set = Option(__v)) + def withUnknownFields(__v: _root_.scalapb.UnknownFieldSet) = copy(unknownFields = __v) + def discardUnknownFields = copy(unknownFields = _root_.scalapb.UnknownFieldSet.empty) + def getFieldByNumber(__fieldNumber: _root_.scala.Int): _root_.scala.Any = { + (__fieldNumber: @_root_.scala.unchecked) match { + case 1 => when.orNull + case 2 => matchType.map(_.javaValueDescriptor).orNull + case 3 => set.orNull + } + } + def getField(__field: _root_.scalapb.descriptors.FieldDescriptor): _root_.scalapb.descriptors.PValue = { + _root_.scala.Predef.require(__field.containingMessage eq companion.scalaDescriptor) + (__field.number: @_root_.scala.unchecked) match { + case 1 => when.map(_.toPMessage).getOrElse(_root_.scalapb.descriptors.PEmpty) + case 2 => matchType.map(__e => _root_.scalapb.descriptors.PEnum(__e.scalaValueDescriptor)).getOrElse(_root_.scalapb.descriptors.PEmpty) + case 3 => set.map(_.toPMessage).getOrElse(_root_.scalapb.descriptors.PEmpty) + } + } + def toProtoString: _root_.scala.Predef.String = _root_.scalapb.TextFormat.printToUnicodeString(this) + def companion = scalapb.options.FieldTransformation + // @@protoc_insertion_point(GeneratedMessage[scalapb.FieldTransformation]) +} + +object FieldTransformation extends scalapb.GeneratedMessageCompanion[scalapb.options.FieldTransformation] with scalapb.HasBuilder[scalapb.options.FieldTransformation] { + implicit def messageCompanion: scalapb.GeneratedMessageCompanion[scalapb.options.FieldTransformation] with scalapb.HasBuilder[scalapb.options.FieldTransformation] = this + def merge(`_message__`: scalapb.options.FieldTransformation, `_input__`: _root_.com.google.protobuf.CodedInputStream): scalapb.options.FieldTransformation = newBuilder(_message__).merge(_input__).result() + implicit def messageReads: _root_.scalapb.descriptors.Reads[scalapb.options.FieldTransformation] = _root_.scalapb.descriptors.Reads{ + case _root_.scalapb.descriptors.PMessage(__fieldsMap) => + _root_.scala.Predef.require(__fieldsMap.keys.forall(_.containingMessage == scalaDescriptor), "FieldDescriptor does not match message type.") + scalapb.options.FieldTransformation( + when = __fieldsMap.get(scalaDescriptor.findFieldByNumber(1).get).flatMap(_.as[_root_.scala.Option[com.google.protobuf.descriptor.FieldOptions]]), + matchType = __fieldsMap.get(scalaDescriptor.findFieldByNumber(2).get).flatMap(_.as[_root_.scala.Option[_root_.scalapb.descriptors.EnumValueDescriptor]]).map(__e => scalapb.options.FieldTransformation.MatchType.fromValue(__e.number)), + set = __fieldsMap.get(scalaDescriptor.findFieldByNumber(3).get).flatMap(_.as[_root_.scala.Option[scalapb.options.FieldOptions]]) + ) + case _ => throw new RuntimeException("Expected PMessage") + } + def javaDescriptor: _root_.com.google.protobuf.Descriptors.Descriptor = ScalapbProto.javaDescriptor.getMessageTypes().get(7) + def scalaDescriptor: _root_.scalapb.descriptors.Descriptor = ScalapbProto.scalaDescriptor.messages(7) + def messageCompanionForFieldNumber(__number: _root_.scala.Int): _root_.scalapb.GeneratedMessageCompanion[_] = { + var __out: _root_.scalapb.GeneratedMessageCompanion[_] = null + (__number: @_root_.scala.unchecked) match { + case 1 => __out = com.google.protobuf.descriptor.FieldOptions + case 3 => __out = scalapb.options.FieldOptions + } + __out + } + lazy val nestedMessagesCompanions: Seq[_root_.scalapb.GeneratedMessageCompanion[_ <: _root_.scalapb.GeneratedMessage]] = Seq.empty + def enumCompanionForFieldNumber(__fieldNumber: _root_.scala.Int): _root_.scalapb.GeneratedEnumCompanion[_] = { + (__fieldNumber: @_root_.scala.unchecked) match { + case 2 => scalapb.options.FieldTransformation.MatchType + } + } + lazy val defaultInstance = scalapb.options.FieldTransformation( + when = _root_.scala.None, + matchType = _root_.scala.None, + set = _root_.scala.None + ) + final class Builder private ( + private var __when: _root_.scala.Option[com.google.protobuf.descriptor.FieldOptions], + private var __matchType: _root_.scala.Option[scalapb.options.FieldTransformation.MatchType], + private var __set: _root_.scala.Option[scalapb.options.FieldOptions], + private var `_unknownFields__`: _root_.scalapb.UnknownFieldSet.Builder + ) extends _root_.scalapb.MessageBuilder[scalapb.options.FieldTransformation] { + def merge(`_input__`: _root_.com.google.protobuf.CodedInputStream): this.type = { + var _done__ = false + while (!_done__) { + val _tag__ = _input__.readTag() + _tag__ match { + case 0 => _done__ = true + case 10 => + __when = Option(__when.fold(_root_.scalapb.LiteParser.readMessage[com.google.protobuf.descriptor.FieldOptions](_input__))(_root_.scalapb.LiteParser.readMessage(_input__, _))) + case 16 => + __matchType = Option(scalapb.options.FieldTransformation.MatchType.fromValue(_input__.readEnum())) + case 26 => + __set = Option(__set.fold(_root_.scalapb.LiteParser.readMessage[scalapb.options.FieldOptions](_input__))(_root_.scalapb.LiteParser.readMessage(_input__, _))) + case tag => + if (_unknownFields__ == null) { + _unknownFields__ = new _root_.scalapb.UnknownFieldSet.Builder() + } + _unknownFields__.parseField(tag, _input__) + } + } + this + } + def result(): scalapb.options.FieldTransformation = { + scalapb.options.FieldTransformation( + when = __when, + matchType = __matchType, + set = __set, + unknownFields = if (_unknownFields__ == null) _root_.scalapb.UnknownFieldSet.empty else _unknownFields__.result() + ) + } + } + object Builder extends _root_.scalapb.MessageBuilderCompanion[scalapb.options.FieldTransformation, scalapb.options.FieldTransformation.Builder] { + def apply(): Builder = new Builder( + __when = _root_.scala.None, + __matchType = _root_.scala.None, + __set = _root_.scala.None, + `_unknownFields__` = null + ) + def apply(`_message__`: scalapb.options.FieldTransformation): Builder = new Builder( + __when = _message__.when, + __matchType = _message__.matchType, + __set = _message__.set, + `_unknownFields__` = new _root_.scalapb.UnknownFieldSet.Builder(_message__.unknownFields) + ) + } + def newBuilder: Builder = scalapb.options.FieldTransformation.Builder() + def newBuilder(`_message__`: scalapb.options.FieldTransformation): Builder = scalapb.options.FieldTransformation.Builder(_message__) + sealed abstract class MatchType(val value: _root_.scala.Int) extends _root_.scalapb.GeneratedEnum { + type EnumType = MatchType + def isContains: _root_.scala.Boolean = false + def isExact: _root_.scala.Boolean = false + def isPresence: _root_.scala.Boolean = false + def companion: _root_.scalapb.GeneratedEnumCompanion[MatchType] = scalapb.options.FieldTransformation.MatchType + final def asRecognized: _root_.scala.Option[scalapb.options.FieldTransformation.MatchType.Recognized] = if (isUnrecognized) _root_.scala.None else _root_.scala.Some(this.asInstanceOf[scalapb.options.FieldTransformation.MatchType.Recognized]) + } + + object MatchType extends _root_.scalapb.GeneratedEnumCompanion[MatchType] { + sealed trait Recognized extends MatchType + implicit def enumCompanion: _root_.scalapb.GeneratedEnumCompanion[MatchType] = this + @SerialVersionUID(0L) + case object CONTAINS extends MatchType(0) with MatchType.Recognized { + val index = 0 + val name = "CONTAINS" + override def isContains: _root_.scala.Boolean = true + } + + @SerialVersionUID(0L) + case object EXACT extends MatchType(1) with MatchType.Recognized { + val index = 1 + val name = "EXACT" + override def isExact: _root_.scala.Boolean = true + } + + @SerialVersionUID(0L) + case object PRESENCE extends MatchType(2) with MatchType.Recognized { + val index = 2 + val name = "PRESENCE" + override def isPresence: _root_.scala.Boolean = true + } + + @SerialVersionUID(0L) + final case class Unrecognized(unrecognizedValue: _root_.scala.Int) extends MatchType(unrecognizedValue) with _root_.scalapb.UnrecognizedEnum + + lazy val values = scala.collection.immutable.Seq(CONTAINS, EXACT, PRESENCE) + def fromValue(__value: _root_.scala.Int): MatchType = __value match { + case 0 => CONTAINS + case 1 => EXACT + case 2 => PRESENCE + case __other => Unrecognized(__other) + } + def javaDescriptor: _root_.com.google.protobuf.Descriptors.EnumDescriptor = scalapb.options.FieldTransformation.javaDescriptor.getEnumTypes().get(0) + def scalaDescriptor: _root_.scalapb.descriptors.EnumDescriptor = scalapb.options.FieldTransformation.scalaDescriptor.enums(0) + } + implicit class FieldTransformationLens[UpperPB](_l: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.FieldTransformation]) extends _root_.scalapb.lenses.ObjectLens[UpperPB, scalapb.options.FieldTransformation](_l) { + def when: _root_.scalapb.lenses.Lens[UpperPB, com.google.protobuf.descriptor.FieldOptions] = field(_.getWhen)((c_, f_) => c_.copy(when = Option(f_))) + def optionalWhen: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[com.google.protobuf.descriptor.FieldOptions]] = field(_.when)((c_, f_) => c_.copy(when = f_)) + def matchType: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.FieldTransformation.MatchType] = field(_.getMatchType)((c_, f_) => c_.copy(matchType = Option(f_))) + def optionalMatchType: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[scalapb.options.FieldTransformation.MatchType]] = field(_.matchType)((c_, f_) => c_.copy(matchType = f_)) + def set: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.FieldOptions] = field(_.getSet)((c_, f_) => c_.copy(set = Option(f_))) + def optionalSet: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[scalapb.options.FieldOptions]] = field(_.set)((c_, f_) => c_.copy(set = f_)) + } + final val WHEN_FIELD_NUMBER = 1 + final val MATCH_TYPE_FIELD_NUMBER = 2 + final val SET_FIELD_NUMBER = 3 + def of( + when: _root_.scala.Option[com.google.protobuf.descriptor.FieldOptions], + matchType: _root_.scala.Option[scalapb.options.FieldTransformation.MatchType], + set: _root_.scala.Option[scalapb.options.FieldOptions] + ): _root_.scalapb.options.FieldTransformation = _root_.scalapb.options.FieldTransformation( + when, + matchType, + set + ) + // @@protoc_insertion_point(GeneratedMessageCompanion[scalapb.FieldTransformation]) +} diff --git a/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocesserOutput.scala b/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocesserOutput.scala index 512cedf5c..cf7436fee 100644 --- a/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocesserOutput.scala +++ b/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocesserOutput.scala @@ -71,8 +71,8 @@ object PreprocesserOutput extends scalapb.GeneratedMessageCompanion[scalapb.opti ) case _ => throw new RuntimeException("Expected PMessage") } - def javaDescriptor: _root_.com.google.protobuf.Descriptors.Descriptor = ScalapbProto.javaDescriptor.getMessageTypes().get(7) - def scalaDescriptor: _root_.scalapb.descriptors.Descriptor = ScalapbProto.scalaDescriptor.messages(7) + def javaDescriptor: _root_.com.google.protobuf.Descriptors.Descriptor = ScalapbProto.javaDescriptor.getMessageTypes().get(8) + def scalaDescriptor: _root_.scalapb.descriptors.Descriptor = ScalapbProto.scalaDescriptor.messages(8) def messageCompanionForFieldNumber(__number: _root_.scala.Int): _root_.scalapb.GeneratedMessageCompanion[_] = { var __out: _root_.scalapb.GeneratedMessageCompanion[_] = null (__number: @_root_.scala.unchecked) match { diff --git a/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocessorOutput.scala b/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocessorOutput.scala new file mode 100644 index 000000000..2f1fce14a --- /dev/null +++ b/scalapb-runtime/shared/src/main/scala/scalapb/options/PreprocessorOutput.scala @@ -0,0 +1,305 @@ +// Generated by the Scala Plugin for the Protocol Buffer Compiler. +// Do not edit! +// +// Protofile syntax: PROTO2 + +package scalapb.options + +@SerialVersionUID(0L) +final case class PreprocessorOutput( + optionsByFile: _root_.scala.collection.immutable.Map[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions] = _root_.scala.collection.immutable.Map.empty, + unknownFields: _root_.scalapb.UnknownFieldSet = _root_.scalapb.UnknownFieldSet.empty + ) extends scalapb.GeneratedMessage with scalapb.lenses.Updatable[PreprocessorOutput] { + @transient + private[this] var __serializedSizeCachedValue: _root_.scala.Int = 0 + private[this] def __computeSerializedValue(): _root_.scala.Int = { + var __size = 0 + optionsByFile.foreach { __item => + val __value = scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toBase(__item) + __size += 1 + _root_.com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(__value.serializedSize) + __value.serializedSize + } + __size += unknownFields.serializedSize + __size + } + override def serializedSize: _root_.scala.Int = { + var read = __serializedSizeCachedValue + if (read == 0) { + read = __computeSerializedValue() + __serializedSizeCachedValue = read + } + read + } + def writeTo(`_output__`: _root_.com.google.protobuf.CodedOutputStream): _root_.scala.Unit = { + optionsByFile.foreach { __v => + val __m = scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toBase(__v) + _output__.writeTag(1, 2) + _output__.writeUInt32NoTag(__m.serializedSize) + __m.writeTo(_output__) + }; + unknownFields.writeTo(_output__) + } + def clearOptionsByFile = copy(optionsByFile = _root_.scala.collection.immutable.Map.empty) + def addOptionsByFile(__vs: (_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)*): PreprocessorOutput = addAllOptionsByFile(__vs) + def addAllOptionsByFile(__vs: Iterable[(_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)]): PreprocessorOutput = copy(optionsByFile = optionsByFile ++ __vs) + def withOptionsByFile(__v: _root_.scala.collection.immutable.Map[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions]): PreprocessorOutput = copy(optionsByFile = __v) + def withUnknownFields(__v: _root_.scalapb.UnknownFieldSet) = copy(unknownFields = __v) + def discardUnknownFields = copy(unknownFields = _root_.scalapb.UnknownFieldSet.empty) + def getFieldByNumber(__fieldNumber: _root_.scala.Int): _root_.scala.Any = { + (__fieldNumber: @_root_.scala.unchecked) match { + case 1 => optionsByFile.iterator.map(scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toBase(_)).toSeq + } + } + def getField(__field: _root_.scalapb.descriptors.FieldDescriptor): _root_.scalapb.descriptors.PValue = { + _root_.scala.Predef.require(__field.containingMessage eq companion.scalaDescriptor) + (__field.number: @_root_.scala.unchecked) match { + case 1 => _root_.scalapb.descriptors.PRepeated(optionsByFile.iterator.map(scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toBase(_).toPMessage).toVector) + } + } + def toProtoString: _root_.scala.Predef.String = _root_.scalapb.TextFormat.printToUnicodeString(this) + def companion = scalapb.options.PreprocessorOutput + // @@protoc_insertion_point(GeneratedMessage[scalapb.PreprocessorOutput]) +} + +object PreprocessorOutput extends scalapb.GeneratedMessageCompanion[scalapb.options.PreprocessorOutput] with scalapb.HasBuilder[scalapb.options.PreprocessorOutput] { + implicit def messageCompanion: scalapb.GeneratedMessageCompanion[scalapb.options.PreprocessorOutput] with scalapb.HasBuilder[scalapb.options.PreprocessorOutput] = this + def merge(`_message__`: scalapb.options.PreprocessorOutput, `_input__`: _root_.com.google.protobuf.CodedInputStream): scalapb.options.PreprocessorOutput = newBuilder(_message__).merge(_input__).result() + implicit def messageReads: _root_.scalapb.descriptors.Reads[scalapb.options.PreprocessorOutput] = _root_.scalapb.descriptors.Reads{ + case _root_.scalapb.descriptors.PMessage(__fieldsMap) => + _root_.scala.Predef.require(__fieldsMap.keys.forall(_.containingMessage == scalaDescriptor), "FieldDescriptor does not match message type.") + scalapb.options.PreprocessorOutput( + optionsByFile = __fieldsMap.get(scalaDescriptor.findFieldByNumber(1).get).map(_.as[_root_.scala.Seq[scalapb.options.PreprocessorOutput.OptionsByFileEntry]]).getOrElse(_root_.scala.Seq.empty).iterator.map(scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toCustom(_)).toMap + ) + case _ => throw new RuntimeException("Expected PMessage") + } + def javaDescriptor: _root_.com.google.protobuf.Descriptors.Descriptor = ScalapbProto.javaDescriptor.getMessageTypes().get(8) + def scalaDescriptor: _root_.scalapb.descriptors.Descriptor = ScalapbProto.scalaDescriptor.messages(8) + def messageCompanionForFieldNumber(__number: _root_.scala.Int): _root_.scalapb.GeneratedMessageCompanion[_] = { + var __out: _root_.scalapb.GeneratedMessageCompanion[_] = null + (__number: @_root_.scala.unchecked) match { + case 1 => __out = scalapb.options.PreprocessorOutput.OptionsByFileEntry + } + __out + } + lazy val nestedMessagesCompanions: Seq[_root_.scalapb.GeneratedMessageCompanion[_ <: _root_.scalapb.GeneratedMessage]] = + Seq[_root_.scalapb.GeneratedMessageCompanion[_ <: _root_.scalapb.GeneratedMessage]]( + _root_.scalapb.options.PreprocessorOutput.OptionsByFileEntry + ) + def enumCompanionForFieldNumber(__fieldNumber: _root_.scala.Int): _root_.scalapb.GeneratedEnumCompanion[_] = throw new MatchError(__fieldNumber) + lazy val defaultInstance = scalapb.options.PreprocessorOutput( + optionsByFile = _root_.scala.collection.immutable.Map.empty + ) + final class Builder private ( + private val __optionsByFile: _root_.scala.collection.mutable.Builder[(_root_.scala.Predef.String, scalapb.options.ScalaPbOptions), _root_.scala.collection.immutable.Map[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions]], + private var `_unknownFields__`: _root_.scalapb.UnknownFieldSet.Builder + ) extends _root_.scalapb.MessageBuilder[scalapb.options.PreprocessorOutput] { + def merge(`_input__`: _root_.com.google.protobuf.CodedInputStream): this.type = { + var _done__ = false + while (!_done__) { + val _tag__ = _input__.readTag() + _tag__ match { + case 0 => _done__ = true + case 10 => + __optionsByFile += scalapb.options.PreprocessorOutput._typemapper_optionsByFile.toCustom(_root_.scalapb.LiteParser.readMessage[scalapb.options.PreprocessorOutput.OptionsByFileEntry](_input__)) + case tag => + if (_unknownFields__ == null) { + _unknownFields__ = new _root_.scalapb.UnknownFieldSet.Builder() + } + _unknownFields__.parseField(tag, _input__) + } + } + this + } + def result(): scalapb.options.PreprocessorOutput = { + scalapb.options.PreprocessorOutput( + optionsByFile = __optionsByFile.result(), + unknownFields = if (_unknownFields__ == null) _root_.scalapb.UnknownFieldSet.empty else _unknownFields__.result() + ) + } + } + object Builder extends _root_.scalapb.MessageBuilderCompanion[scalapb.options.PreprocessorOutput, scalapb.options.PreprocessorOutput.Builder] { + def apply(): Builder = new Builder( + __optionsByFile = _root_.scala.collection.immutable.Map.newBuilder[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions], + `_unknownFields__` = null + ) + def apply(`_message__`: scalapb.options.PreprocessorOutput): Builder = new Builder( + __optionsByFile = _root_.scala.collection.immutable.Map.newBuilder[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions] ++= _message__.optionsByFile, + `_unknownFields__` = new _root_.scalapb.UnknownFieldSet.Builder(_message__.unknownFields) + ) + } + def newBuilder: Builder = scalapb.options.PreprocessorOutput.Builder() + def newBuilder(`_message__`: scalapb.options.PreprocessorOutput): Builder = scalapb.options.PreprocessorOutput.Builder(_message__) + @SerialVersionUID(0L) + final case class OptionsByFileEntry( + key: _root_.scala.Option[_root_.scala.Predef.String] = _root_.scala.None, + value: _root_.scala.Option[scalapb.options.ScalaPbOptions] = _root_.scala.None, + unknownFields: _root_.scalapb.UnknownFieldSet = _root_.scalapb.UnknownFieldSet.empty + ) extends scalapb.GeneratedMessage with scalapb.lenses.Updatable[OptionsByFileEntry] { + @transient + private[this] var __serializedSizeCachedValue: _root_.scala.Int = 0 + private[this] def __computeSerializedValue(): _root_.scala.Int = { + var __size = 0 + if (key.isDefined) { + val __value = key.get + __size += _root_.com.google.protobuf.CodedOutputStream.computeStringSize(1, __value) + }; + if (value.isDefined) { + val __value = value.get + __size += 1 + _root_.com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(__value.serializedSize) + __value.serializedSize + }; + __size += unknownFields.serializedSize + __size + } + override def serializedSize: _root_.scala.Int = { + var read = __serializedSizeCachedValue + if (read == 0) { + read = __computeSerializedValue() + __serializedSizeCachedValue = read + } + read + } + def writeTo(`_output__`: _root_.com.google.protobuf.CodedOutputStream): _root_.scala.Unit = { + key.foreach { __v => + val __m = __v + _output__.writeString(1, __m) + }; + value.foreach { __v => + val __m = __v + _output__.writeTag(2, 2) + _output__.writeUInt32NoTag(__m.serializedSize) + __m.writeTo(_output__) + }; + unknownFields.writeTo(_output__) + } + def getKey: _root_.scala.Predef.String = key.getOrElse("") + def clearKey: OptionsByFileEntry = copy(key = _root_.scala.None) + def withKey(__v: _root_.scala.Predef.String): OptionsByFileEntry = copy(key = Option(__v)) + def getValue: scalapb.options.ScalaPbOptions = value.getOrElse(scalapb.options.ScalaPbOptions.defaultInstance) + def clearValue: OptionsByFileEntry = copy(value = _root_.scala.None) + def withValue(__v: scalapb.options.ScalaPbOptions): OptionsByFileEntry = copy(value = Option(__v)) + def withUnknownFields(__v: _root_.scalapb.UnknownFieldSet) = copy(unknownFields = __v) + def discardUnknownFields = copy(unknownFields = _root_.scalapb.UnknownFieldSet.empty) + def getFieldByNumber(__fieldNumber: _root_.scala.Int): _root_.scala.Any = { + (__fieldNumber: @_root_.scala.unchecked) match { + case 1 => key.orNull + case 2 => value.orNull + } + } + def getField(__field: _root_.scalapb.descriptors.FieldDescriptor): _root_.scalapb.descriptors.PValue = { + _root_.scala.Predef.require(__field.containingMessage eq companion.scalaDescriptor) + (__field.number: @_root_.scala.unchecked) match { + case 1 => key.map(_root_.scalapb.descriptors.PString(_)).getOrElse(_root_.scalapb.descriptors.PEmpty) + case 2 => value.map(_.toPMessage).getOrElse(_root_.scalapb.descriptors.PEmpty) + } + } + def toProtoString: _root_.scala.Predef.String = _root_.scalapb.TextFormat.printToUnicodeString(this) + def companion = scalapb.options.PreprocessorOutput.OptionsByFileEntry + // @@protoc_insertion_point(GeneratedMessage[scalapb.PreprocessorOutput.OptionsByFileEntry]) + } + + object OptionsByFileEntry extends scalapb.GeneratedMessageCompanion[scalapb.options.PreprocessorOutput.OptionsByFileEntry] with scalapb.HasBuilder[scalapb.options.PreprocessorOutput.OptionsByFileEntry] { + implicit def messageCompanion: scalapb.GeneratedMessageCompanion[scalapb.options.PreprocessorOutput.OptionsByFileEntry] with scalapb.HasBuilder[scalapb.options.PreprocessorOutput.OptionsByFileEntry] = this + def merge(`_message__`: scalapb.options.PreprocessorOutput.OptionsByFileEntry, `_input__`: _root_.com.google.protobuf.CodedInputStream): scalapb.options.PreprocessorOutput.OptionsByFileEntry = newBuilder(_message__).merge(_input__).result() + implicit def messageReads: _root_.scalapb.descriptors.Reads[scalapb.options.PreprocessorOutput.OptionsByFileEntry] = _root_.scalapb.descriptors.Reads{ + case _root_.scalapb.descriptors.PMessage(__fieldsMap) => + _root_.scala.Predef.require(__fieldsMap.keys.forall(_.containingMessage == scalaDescriptor), "FieldDescriptor does not match message type.") + scalapb.options.PreprocessorOutput.OptionsByFileEntry( + key = __fieldsMap.get(scalaDescriptor.findFieldByNumber(1).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Predef.String]]), + value = __fieldsMap.get(scalaDescriptor.findFieldByNumber(2).get).flatMap(_.as[_root_.scala.Option[scalapb.options.ScalaPbOptions]]) + ) + case _ => throw new RuntimeException("Expected PMessage") + } + def javaDescriptor: _root_.com.google.protobuf.Descriptors.Descriptor = scalapb.options.PreprocessorOutput.javaDescriptor.getNestedTypes().get(0) + def scalaDescriptor: _root_.scalapb.descriptors.Descriptor = scalapb.options.PreprocessorOutput.scalaDescriptor.nestedMessages(0) + def messageCompanionForFieldNumber(__number: _root_.scala.Int): _root_.scalapb.GeneratedMessageCompanion[_] = { + var __out: _root_.scalapb.GeneratedMessageCompanion[_] = null + (__number: @_root_.scala.unchecked) match { + case 2 => __out = scalapb.options.ScalaPbOptions + } + __out + } + lazy val nestedMessagesCompanions: Seq[_root_.scalapb.GeneratedMessageCompanion[_ <: _root_.scalapb.GeneratedMessage]] = Seq.empty + def enumCompanionForFieldNumber(__fieldNumber: _root_.scala.Int): _root_.scalapb.GeneratedEnumCompanion[_] = throw new MatchError(__fieldNumber) + lazy val defaultInstance = scalapb.options.PreprocessorOutput.OptionsByFileEntry( + key = _root_.scala.None, + value = _root_.scala.None + ) + final class Builder private ( + private var __key: _root_.scala.Option[_root_.scala.Predef.String], + private var __value: _root_.scala.Option[scalapb.options.ScalaPbOptions], + private var `_unknownFields__`: _root_.scalapb.UnknownFieldSet.Builder + ) extends _root_.scalapb.MessageBuilder[scalapb.options.PreprocessorOutput.OptionsByFileEntry] { + def merge(`_input__`: _root_.com.google.protobuf.CodedInputStream): this.type = { + var _done__ = false + while (!_done__) { + val _tag__ = _input__.readTag() + _tag__ match { + case 0 => _done__ = true + case 10 => + __key = Option(_input__.readStringRequireUtf8()) + case 18 => + __value = Option(__value.fold(_root_.scalapb.LiteParser.readMessage[scalapb.options.ScalaPbOptions](_input__))(_root_.scalapb.LiteParser.readMessage(_input__, _))) + case tag => + if (_unknownFields__ == null) { + _unknownFields__ = new _root_.scalapb.UnknownFieldSet.Builder() + } + _unknownFields__.parseField(tag, _input__) + } + } + this + } + def result(): scalapb.options.PreprocessorOutput.OptionsByFileEntry = { + scalapb.options.PreprocessorOutput.OptionsByFileEntry( + key = __key, + value = __value, + unknownFields = if (_unknownFields__ == null) _root_.scalapb.UnknownFieldSet.empty else _unknownFields__.result() + ) + } + } + object Builder extends _root_.scalapb.MessageBuilderCompanion[scalapb.options.PreprocessorOutput.OptionsByFileEntry, scalapb.options.PreprocessorOutput.OptionsByFileEntry.Builder] { + def apply(): Builder = new Builder( + __key = _root_.scala.None, + __value = _root_.scala.None, + `_unknownFields__` = null + ) + def apply(`_message__`: scalapb.options.PreprocessorOutput.OptionsByFileEntry): Builder = new Builder( + __key = _message__.key, + __value = _message__.value, + `_unknownFields__` = new _root_.scalapb.UnknownFieldSet.Builder(_message__.unknownFields) + ) + } + def newBuilder: Builder = scalapb.options.PreprocessorOutput.OptionsByFileEntry.Builder() + def newBuilder(`_message__`: scalapb.options.PreprocessorOutput.OptionsByFileEntry): Builder = scalapb.options.PreprocessorOutput.OptionsByFileEntry.Builder(_message__) + implicit class OptionsByFileEntryLens[UpperPB](_l: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.PreprocessorOutput.OptionsByFileEntry]) extends _root_.scalapb.lenses.ObjectLens[UpperPB, scalapb.options.PreprocessorOutput.OptionsByFileEntry](_l) { + def key: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Predef.String] = field(_.getKey)((c_, f_) => c_.copy(key = Option(f_))) + def optionalKey: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Predef.String]] = field(_.key)((c_, f_) => c_.copy(key = f_)) + def value: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.ScalaPbOptions] = field(_.getValue)((c_, f_) => c_.copy(value = Option(f_))) + def optionalValue: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[scalapb.options.ScalaPbOptions]] = field(_.value)((c_, f_) => c_.copy(value = f_)) + } + final val KEY_FIELD_NUMBER = 1 + final val VALUE_FIELD_NUMBER = 2 + @transient + implicit val keyValueMapper: _root_.scalapb.TypeMapper[scalapb.options.PreprocessorOutput.OptionsByFileEntry, (_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)] = + _root_.scalapb.TypeMapper[scalapb.options.PreprocessorOutput.OptionsByFileEntry, (_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)](__m => (__m.getKey, __m.getValue))(__p => scalapb.options.PreprocessorOutput.OptionsByFileEntry(Some(__p._1), Some(__p._2))) + def of( + key: _root_.scala.Option[_root_.scala.Predef.String], + value: _root_.scala.Option[scalapb.options.ScalaPbOptions] + ): _root_.scalapb.options.PreprocessorOutput.OptionsByFileEntry = _root_.scalapb.options.PreprocessorOutput.OptionsByFileEntry( + key, + value + ) + // @@protoc_insertion_point(GeneratedMessageCompanion[scalapb.PreprocessorOutput.OptionsByFileEntry]) + } + + implicit class PreprocessorOutputLens[UpperPB](_l: _root_.scalapb.lenses.Lens[UpperPB, scalapb.options.PreprocessorOutput]) extends _root_.scalapb.lenses.ObjectLens[UpperPB, scalapb.options.PreprocessorOutput](_l) { + def optionsByFile: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.collection.immutable.Map[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions]] = field(_.optionsByFile)((c_, f_) => c_.copy(optionsByFile = f_)) + } + final val OPTIONS_BY_FILE_FIELD_NUMBER = 1 + @transient + private[options] val _typemapper_optionsByFile: _root_.scalapb.TypeMapper[scalapb.options.PreprocessorOutput.OptionsByFileEntry, (_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)] = implicitly[_root_.scalapb.TypeMapper[scalapb.options.PreprocessorOutput.OptionsByFileEntry, (_root_.scala.Predef.String, scalapb.options.ScalaPbOptions)]] + def of( + optionsByFile: _root_.scala.collection.immutable.Map[_root_.scala.Predef.String, scalapb.options.ScalaPbOptions] + ): _root_.scalapb.options.PreprocessorOutput = _root_.scalapb.options.PreprocessorOutput( + optionsByFile + ) + // @@protoc_insertion_point(GeneratedMessageCompanion[scalapb.PreprocessorOutput]) +} diff --git a/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalaPbOptions.scala b/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalaPbOptions.scala index 4d3cb3fa4..ba36702a0 100644 --- a/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalaPbOptions.scala +++ b/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalaPbOptions.scala @@ -66,6 +66,9 @@ package scalapb.options * List of message options to apply to some enums. * @param bytesType * Scala type to use for bytes fields. + * @param ignoreFieldTransformations + * Ignores field transformations for this file. This is meant to allow specific files to + * opt out from field transformations inherited through package-scoped options. * @param testOnlyNoJavaConversions * For use in tests only. Inhibit Java conversions even when when generator parameters * request for it. @@ -94,6 +97,8 @@ final case class ScalaPbOptions( auxEnumOptions: _root_.scala.Seq[scalapb.options.ScalaPbOptions.AuxEnumOptions] = _root_.scala.Seq.empty, bytesType: _root_.scala.Option[_root_.scala.Predef.String] = _root_.scala.None, preprocessors: _root_.scala.Seq[_root_.scala.Predef.String] = _root_.scala.Seq.empty, + fieldTransformations: _root_.scala.Seq[scalapb.options.FieldTransformation] = _root_.scala.Seq.empty, + ignoreFieldTransformations: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None, testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean] = _root_.scala.None, unknownFields: _root_.scalapb.UnknownFieldSet = _root_.scalapb.UnknownFieldSet.empty ) extends scalapb.GeneratedMessage with scalapb.lenses.Updatable[ScalaPbOptions] with _root_.scalapb.ExtendableMessage[ScalaPbOptions] { @@ -189,6 +194,14 @@ final case class ScalaPbOptions( val __value = __item __size += _root_.com.google.protobuf.CodedOutputStream.computeStringSize(24, __value) } + fieldTransformations.foreach { __item => + val __value = __item + __size += 2 + _root_.com.google.protobuf.CodedOutputStream.computeUInt32SizeNoTag(__value.serializedSize) + __value.serializedSize + } + if (ignoreFieldTransformations.isDefined) { + val __value = ignoreFieldTransformations.get + __size += _root_.com.google.protobuf.CodedOutputStream.computeBoolSize(26, __value) + }; if (testOnlyNoJavaConversions.isDefined) { val __value = testOnlyNoJavaConversions.get __size += _root_.com.google.protobuf.CodedOutputStream.computeBoolSize(999, __value) @@ -299,6 +312,16 @@ final case class ScalaPbOptions( val __m = __v _output__.writeString(24, __m) }; + fieldTransformations.foreach { __v => + val __m = __v + _output__.writeTag(25, 2) + _output__.writeUInt32NoTag(__m.serializedSize) + __m.writeTo(_output__) + }; + ignoreFieldTransformations.foreach { __v => + val __m = __v + _output__.writeBool(26, __m) + }; testOnlyNoJavaConversions.foreach { __v => val __m = __v _output__.writeBool(999, __m) @@ -377,6 +400,13 @@ final case class ScalaPbOptions( def addPreprocessors(__vs: _root_.scala.Predef.String*): ScalaPbOptions = addAllPreprocessors(__vs) def addAllPreprocessors(__vs: Iterable[_root_.scala.Predef.String]): ScalaPbOptions = copy(preprocessors = preprocessors ++ __vs) def withPreprocessors(__v: _root_.scala.Seq[_root_.scala.Predef.String]): ScalaPbOptions = copy(preprocessors = __v) + def clearFieldTransformations = copy(fieldTransformations = _root_.scala.Seq.empty) + def addFieldTransformations(__vs: scalapb.options.FieldTransformation*): ScalaPbOptions = addAllFieldTransformations(__vs) + def addAllFieldTransformations(__vs: Iterable[scalapb.options.FieldTransformation]): ScalaPbOptions = copy(fieldTransformations = fieldTransformations ++ __vs) + def withFieldTransformations(__v: _root_.scala.Seq[scalapb.options.FieldTransformation]): ScalaPbOptions = copy(fieldTransformations = __v) + def getIgnoreFieldTransformations: _root_.scala.Boolean = ignoreFieldTransformations.getOrElse(false) + def clearIgnoreFieldTransformations: ScalaPbOptions = copy(ignoreFieldTransformations = _root_.scala.None) + def withIgnoreFieldTransformations(__v: _root_.scala.Boolean): ScalaPbOptions = copy(ignoreFieldTransformations = Option(__v)) def getTestOnlyNoJavaConversions: _root_.scala.Boolean = testOnlyNoJavaConversions.getOrElse(false) def clearTestOnlyNoJavaConversions: ScalaPbOptions = copy(testOnlyNoJavaConversions = _root_.scala.None) def withTestOnlyNoJavaConversions(__v: _root_.scala.Boolean): ScalaPbOptions = copy(testOnlyNoJavaConversions = Option(__v)) @@ -406,6 +436,8 @@ final case class ScalaPbOptions( case 20 => auxEnumOptions case 21 => bytesType.orNull case 24 => preprocessors + case 25 => fieldTransformations + case 26 => ignoreFieldTransformations.orNull case 999 => testOnlyNoJavaConversions.orNull } } @@ -434,6 +466,8 @@ final case class ScalaPbOptions( case 20 => _root_.scalapb.descriptors.PRepeated(auxEnumOptions.iterator.map(_.toPMessage).toVector) case 21 => bytesType.map(_root_.scalapb.descriptors.PString(_)).getOrElse(_root_.scalapb.descriptors.PEmpty) case 24 => _root_.scalapb.descriptors.PRepeated(preprocessors.iterator.map(_root_.scalapb.descriptors.PString(_)).toVector) + case 25 => _root_.scalapb.descriptors.PRepeated(fieldTransformations.iterator.map(_.toPMessage).toVector) + case 26 => ignoreFieldTransformations.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty) case 999 => testOnlyNoJavaConversions.map(_root_.scalapb.descriptors.PBoolean(_)).getOrElse(_root_.scalapb.descriptors.PEmpty) } } @@ -471,6 +505,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. auxEnumOptions = __fieldsMap.get(scalaDescriptor.findFieldByNumber(20).get).map(_.as[_root_.scala.Seq[scalapb.options.ScalaPbOptions.AuxEnumOptions]]).getOrElse(_root_.scala.Seq.empty), bytesType = __fieldsMap.get(scalaDescriptor.findFieldByNumber(21).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Predef.String]]), preprocessors = __fieldsMap.get(scalaDescriptor.findFieldByNumber(24).get).map(_.as[_root_.scala.Seq[_root_.scala.Predef.String]]).getOrElse(_root_.scala.Seq.empty), + fieldTransformations = __fieldsMap.get(scalaDescriptor.findFieldByNumber(25).get).map(_.as[_root_.scala.Seq[scalapb.options.FieldTransformation]]).getOrElse(_root_.scala.Seq.empty), + ignoreFieldTransformations = __fieldsMap.get(scalaDescriptor.findFieldByNumber(26).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]), testOnlyNoJavaConversions = __fieldsMap.get(scalaDescriptor.findFieldByNumber(999).get).flatMap(_.as[_root_.scala.Option[_root_.scala.Boolean]]) ) case _ => throw new RuntimeException("Expected PMessage") @@ -483,6 +519,7 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. case 18 => __out = scalapb.options.ScalaPbOptions.AuxMessageOptions case 19 => __out = scalapb.options.ScalaPbOptions.AuxFieldOptions case 20 => __out = scalapb.options.ScalaPbOptions.AuxEnumOptions + case 25 => __out = scalapb.options.FieldTransformation } __out } @@ -521,6 +558,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. auxEnumOptions = _root_.scala.Seq.empty, bytesType = _root_.scala.None, preprocessors = _root_.scala.Seq.empty, + fieldTransformations = _root_.scala.Seq.empty, + ignoreFieldTransformations = _root_.scala.None, testOnlyNoJavaConversions = _root_.scala.None ) final class Builder private ( @@ -546,6 +585,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. private val __auxEnumOptions: _root_.scala.collection.immutable.VectorBuilder[scalapb.options.ScalaPbOptions.AuxEnumOptions], private var __bytesType: _root_.scala.Option[_root_.scala.Predef.String], private val __preprocessors: _root_.scala.collection.immutable.VectorBuilder[_root_.scala.Predef.String], + private val __fieldTransformations: _root_.scala.collection.immutable.VectorBuilder[scalapb.options.FieldTransformation], + private var __ignoreFieldTransformations: _root_.scala.Option[_root_.scala.Boolean], private var __testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean], private var `_unknownFields__`: _root_.scalapb.UnknownFieldSet.Builder ) extends _root_.scalapb.MessageBuilder[scalapb.options.ScalaPbOptions] { @@ -599,6 +640,10 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. __bytesType = Option(_input__.readStringRequireUtf8()) case 194 => __preprocessors += _input__.readStringRequireUtf8() + case 202 => + __fieldTransformations += _root_.scalapb.LiteParser.readMessage[scalapb.options.FieldTransformation](_input__) + case 208 => + __ignoreFieldTransformations = Option(_input__.readBool()) case 7992 => __testOnlyNoJavaConversions = Option(_input__.readBool()) case tag => @@ -634,6 +679,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. auxEnumOptions = __auxEnumOptions.result(), bytesType = __bytesType, preprocessors = __preprocessors.result(), + fieldTransformations = __fieldTransformations.result(), + ignoreFieldTransformations = __ignoreFieldTransformations, testOnlyNoJavaConversions = __testOnlyNoJavaConversions, unknownFields = if (_unknownFields__ == null) _root_.scalapb.UnknownFieldSet.empty else _unknownFields__.result() ) @@ -663,6 +710,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. __auxEnumOptions = new _root_.scala.collection.immutable.VectorBuilder[scalapb.options.ScalaPbOptions.AuxEnumOptions], __bytesType = _root_.scala.None, __preprocessors = new _root_.scala.collection.immutable.VectorBuilder[_root_.scala.Predef.String], + __fieldTransformations = new _root_.scala.collection.immutable.VectorBuilder[scalapb.options.FieldTransformation], + __ignoreFieldTransformations = _root_.scala.None, __testOnlyNoJavaConversions = _root_.scala.None, `_unknownFields__` = null ) @@ -689,6 +738,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. __auxEnumOptions = new _root_.scala.collection.immutable.VectorBuilder[scalapb.options.ScalaPbOptions.AuxEnumOptions] ++= _message__.auxEnumOptions, __bytesType = _message__.bytesType, __preprocessors = new _root_.scala.collection.immutable.VectorBuilder[_root_.scala.Predef.String] ++= _message__.preprocessors, + __fieldTransformations = new _root_.scala.collection.immutable.VectorBuilder[scalapb.options.FieldTransformation] ++= _message__.fieldTransformations, + __ignoreFieldTransformations = _message__.ignoreFieldTransformations, __testOnlyNoJavaConversions = _message__.testOnlyNoJavaConversions, `_unknownFields__` = new _root_.scalapb.UnknownFieldSet.Builder(_message__.unknownFields) ) @@ -1327,6 +1378,9 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. def bytesType: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Predef.String] = field(_.getBytesType)((c_, f_) => c_.copy(bytesType = Option(f_))) def optionalBytesType: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Predef.String]] = field(_.bytesType)((c_, f_) => c_.copy(bytesType = f_)) def preprocessors: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Seq[_root_.scala.Predef.String]] = field(_.preprocessors)((c_, f_) => c_.copy(preprocessors = f_)) + def fieldTransformations: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Seq[scalapb.options.FieldTransformation]] = field(_.fieldTransformations)((c_, f_) => c_.copy(fieldTransformations = f_)) + def ignoreFieldTransformations: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Boolean] = field(_.getIgnoreFieldTransformations)((c_, f_) => c_.copy(ignoreFieldTransformations = Option(f_))) + def optionalIgnoreFieldTransformations: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.ignoreFieldTransformations)((c_, f_) => c_.copy(ignoreFieldTransformations = f_)) def testOnlyNoJavaConversions: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Boolean] = field(_.getTestOnlyNoJavaConversions)((c_, f_) => c_.copy(testOnlyNoJavaConversions = Option(f_))) def optionalTestOnlyNoJavaConversions: _root_.scalapb.lenses.Lens[UpperPB, _root_.scala.Option[_root_.scala.Boolean]] = field(_.testOnlyNoJavaConversions)((c_, f_) => c_.copy(testOnlyNoJavaConversions = f_)) } @@ -1352,6 +1406,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. final val AUX_ENUM_OPTIONS_FIELD_NUMBER = 20 final val BYTES_TYPE_FIELD_NUMBER = 21 final val PREPROCESSORS_FIELD_NUMBER = 24 + final val FIELD_TRANSFORMATIONS_FIELD_NUMBER = 25 + final val IGNORE_FIELD_TRANSFORMATIONS_FIELD_NUMBER = 26 final val TEST_ONLY_NO_JAVA_CONVERSIONS_FIELD_NUMBER = 999 def of( packageName: _root_.scala.Option[_root_.scala.Predef.String], @@ -1376,6 +1432,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. auxEnumOptions: _root_.scala.Seq[scalapb.options.ScalaPbOptions.AuxEnumOptions], bytesType: _root_.scala.Option[_root_.scala.Predef.String], preprocessors: _root_.scala.Seq[_root_.scala.Predef.String], + fieldTransformations: _root_.scala.Seq[scalapb.options.FieldTransformation], + ignoreFieldTransformations: _root_.scala.Option[_root_.scala.Boolean], testOnlyNoJavaConversions: _root_.scala.Option[_root_.scala.Boolean] ): _root_.scalapb.options.ScalaPbOptions = _root_.scalapb.options.ScalaPbOptions( packageName, @@ -1400,6 +1458,8 @@ object ScalaPbOptions extends scalapb.GeneratedMessageCompanion[scalapb.options. auxEnumOptions, bytesType, preprocessors, + fieldTransformations, + ignoreFieldTransformations, testOnlyNoJavaConversions ) // @@protoc_insertion_point(GeneratedMessageCompanion[scalapb.ScalaPbOptions]) diff --git a/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalapbProto.scala b/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalapbProto.scala index f7817c9aa..666246517 100644 --- a/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalapbProto.scala +++ b/scalapb-runtime/shared/src/main/scala/scalapb/options/ScalapbProto.scala @@ -18,11 +18,12 @@ object ScalapbProto extends _root_.scalapb.GeneratedFileObject { scalapb.options.EnumOptions, scalapb.options.EnumValueOptions, scalapb.options.OneofOptions, - scalapb.options.PreprocesserOutput + scalapb.options.FieldTransformation, + scalapb.options.PreprocessorOutput ) private lazy val ProtoBytes: Array[Byte] = scalapb.Encoding.fromBase64(scala.collection.immutable.Seq( - """ChVzY2FsYXBiL3NjYWxhcGIucHJvdG8SB3NjYWxhcGIaIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlwdG9yLnByb3RvItIQCg5TY + """ChVzY2FsYXBiL3NjYWxhcGIucHJvdG8SB3NjYWxhcGIaIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlwdG9yLnByb3RvIqMSCg5TY 2FsYVBiT3B0aW9ucxIzCgxwYWNrYWdlX25hbWUYASABKAlCEOI/DRILcGFja2FnZU5hbWVSC3BhY2thZ2VOYW1lEjMKDGZsYXRfc GFja2FnZRgCIAEoCEIQ4j8NEgtmbGF0UGFja2FnZVILZmxhdFBhY2thZ2USIwoGaW1wb3J0GAMgAygJQgviPwgSBmltcG9ydFIGa W1wb3J0EikKCHByZWFtYmxlGAQgAygJQg3iPwoSCHByZWFtYmxlUghwcmVhbWJsZRIwCgtzaW5nbGVfZmlsZRgFIAEoCEIP4j8ME @@ -43,45 +44,52 @@ object ScalapbProto extends _root_.scalapb.GeneratedFileObject { GIuU2NhbGFQYk9wdGlvbnMuQXV4RmllbGRPcHRpb25zQhTiPxESD2F1eEZpZWxkT3B0aW9uc1IPYXV4RmllbGRPcHRpb25zEmUKE GF1eF9lbnVtX29wdGlvbnMYFCADKAsyJi5zY2FsYXBiLlNjYWxhUGJPcHRpb25zLkF1eEVudW1PcHRpb25zQhPiPxASDmF1eEVud W1PcHRpb25zUg5hdXhFbnVtT3B0aW9ucxItCgpieXRlc190eXBlGBUgASgJQg7iPwsSCWJ5dGVzVHlwZVIJYnl0ZXNUeXBlEjgKD - XByZXByb2Nlc3NvcnMYGCADKAlCEuI/DxINcHJlcHJvY2Vzc29yc1INcHJlcHJvY2Vzc29ycxJhCh10ZXN0X29ubHlfbm9famF2Y - V9jb252ZXJzaW9ucxjnByABKAhCHuI/GxIZdGVzdE9ubHlOb0phdmFDb252ZXJzaW9uc1IZdGVzdE9ubHlOb0phdmFDb252ZXJza - W9ucxp5ChFBdXhNZXNzYWdlT3B0aW9ucxIjCgZ0YXJnZXQYASABKAlCC+I/CBIGdGFyZ2V0UgZ0YXJnZXQSPwoHb3B0aW9ucxgCI - AEoCzIXLnNjYWxhcGIuTWVzc2FnZU9wdGlvbnNCDOI/CRIHb3B0aW9uc1IHb3B0aW9ucxp1Cg9BdXhGaWVsZE9wdGlvbnMSIwoGd - GFyZ2V0GAEgASgJQgviPwgSBnRhcmdldFIGdGFyZ2V0Ej0KB29wdGlvbnMYAiABKAsyFS5zY2FsYXBiLkZpZWxkT3B0aW9uc0IM4 - j8JEgdvcHRpb25zUgdvcHRpb25zGnMKDkF1eEVudW1PcHRpb25zEiMKBnRhcmdldBgBIAEoCUIL4j8IEgZ0YXJnZXRSBnRhcmdld - BI8CgdvcHRpb25zGAIgASgLMhQuc2NhbGFwYi5FbnVtT3B0aW9uc0IM4j8JEgdvcHRpb25zUgdvcHRpb25zIiUKDE9wdGlvbnNTY - 29wZRIICgRGSUxFEAASCwoHUEFDS0FHRRABIjIKD0VudW1WYWx1ZU5hbWluZxIPCgtBU19JTl9QUk9UTxAAEg4KCkNBTUVMX0NBU - 0UQASoJCOgHEICAgIACSgQIFhAXSgQIFxAYIvUDCg5NZXNzYWdlT3B0aW9ucxImCgdleHRlbmRzGAEgAygJQgziPwkSB2V4dGVuZ - HNSB2V4dGVuZHMSQgoRY29tcGFuaW9uX2V4dGVuZHMYAiADKAlCFeI/EhIQY29tcGFuaW9uRXh0ZW5kc1IQY29tcGFuaW9uRXh0Z - W5kcxIyCgthbm5vdGF0aW9ucxgDIAMoCUIQ4j8NEgthbm5vdGF0aW9uc1ILYW5ub3RhdGlvbnMSHQoEdHlwZRgEIAEoCUIJ4j8GE - gR0eXBlUgR0eXBlEk4KFWNvbXBhbmlvbl9hbm5vdGF0aW9ucxgFIAMoCUIZ4j8WEhRjb21wYW5pb25Bbm5vdGF0aW9uc1IUY29tc - GFuaW9uQW5ub3RhdGlvbnMSSQoUc2VhbGVkX29uZW9mX2V4dGVuZHMYBiADKAlCF+I/FBISc2VhbGVkT25lb2ZFeHRlbmRzUhJzZ - WFsZWRPbmVvZkV4dGVuZHMSIQoGbm9fYm94GAcgASgIQgriPwcSBW5vQm94UgVub0JveBJbChp1bmtub3duX2ZpZWxkc19hbm5vd - GF0aW9ucxgIIAMoCUId4j8aEhh1bmtub3duRmllbGRzQW5ub3RhdGlvbnNSGHVua25vd25GaWVsZHNBbm5vdGF0aW9ucyoJCOgHE - ICAgIACIn8KCkNvbGxlY3Rpb24SHQoEdHlwZRgBIAEoCUIJ4j8GEgR0eXBlUgR0eXBlEioKCW5vbl9lbXB0eRgCIAEoCEIN4j8KE - ghub25FbXB0eVIIbm9uRW1wdHkSJgoHYWRhcHRlchgDIAEoCUIM4j8JEgdhZGFwdGVyUgdhZGFwdGVyIu4DCgxGaWVsZE9wdGlvb - nMSHQoEdHlwZRgBIAEoCUIJ4j8GEgR0eXBlUgR0eXBlEi0KCnNjYWxhX25hbWUYAiABKAlCDuI/CxIJc2NhbGFOYW1lUglzY2FsY - U5hbWUSPAoPY29sbGVjdGlvbl90eXBlGAMgASgJQhPiPxASDmNvbGxlY3Rpb25UeXBlUg5jb2xsZWN0aW9uVHlwZRJECgpjb2xsZ - WN0aW9uGAggASgLMhMuc2NhbGFwYi5Db2xsZWN0aW9uQg/iPwwSCmNvbGxlY3Rpb25SCmNvbGxlY3Rpb24SJwoIa2V5X3R5cGUYB - CABKAlCDOI/CRIHa2V5VHlwZVIHa2V5VHlwZRItCgp2YWx1ZV90eXBlGAUgASgJQg7iPwsSCXZhbHVlVHlwZVIJdmFsdWVUeXBlE - jIKC2Fubm90YXRpb25zGAYgAygJQhDiPw0SC2Fubm90YXRpb25zUgthbm5vdGF0aW9ucxInCghtYXBfdHlwZRgHIAEoCUIM4j8JE - gdtYXBUeXBlUgdtYXBUeXBlEiEKBm5vX2JveBgeIAEoCEIK4j8HEgVub0JveFIFbm9Cb3gSKQoIcmVxdWlyZWQYHyABKAhCDeI/C - hIIcmVxdWlyZWRSCHJlcXVpcmVkKgkI6AcQgICAgAIiowEKC0VudW1PcHRpb25zEiYKB2V4dGVuZHMYASADKAlCDOI/CRIHZXh0Z - W5kc1IHZXh0ZW5kcxJCChFjb21wYW5pb25fZXh0ZW5kcxgCIAMoCUIV4j8SEhBjb21wYW5pb25FeHRlbmRzUhBjb21wYW5pb25Fe - HRlbmRzEh0KBHR5cGUYAyABKAlCCeI/BhIEdHlwZVIEdHlwZSoJCOgHEICAgIACInQKEEVudW1WYWx1ZU9wdGlvbnMSJgoHZXh0Z - W5kcxgBIAMoCUIM4j8JEgdleHRlbmRzUgdleHRlbmRzEi0KCnNjYWxhX25hbWUYAiABKAlCDuI/CxIJc2NhbGFOYW1lUglzY2FsY - U5hbWUqCQjoBxCAgICAAiJBCgxPbmVvZk9wdGlvbnMSJgoHZXh0ZW5kcxgBIAMoCUIM4j8JEgdleHRlbmRzUgdleHRlbmRzKgkI6 - AcQgICAgAIi8QEKElByZXByb2Nlc3Nlck91dHB1dBJqCg9vcHRpb25zX2J5X2ZpbGUYASADKAsyLi5zY2FsYXBiLlByZXByb2Nlc - 3Nlck91dHB1dC5PcHRpb25zQnlGaWxlRW50cnlCEuI/DxINb3B0aW9uc0J5RmlsZVINb3B0aW9uc0J5RmlsZRpvChJPcHRpb25zQ - nlGaWxlRW50cnkSGgoDa2V5GAEgASgJQgjiPwUSA2tleVIDa2V5EjkKBXZhbHVlGAIgASgLMhcuc2NhbGFwYi5TY2FsYVBiT3B0a - W9uc0IK4j8HEgV2YWx1ZVIFdmFsdWU6AjgBOlAKB29wdGlvbnMSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMY/AcgASgLM - hcuc2NhbGFwYi5TY2FsYVBiT3B0aW9uc1IHb3B0aW9uczpTCgdtZXNzYWdlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb - 25zGPwHIAEoCzIXLnNjYWxhcGIuTWVzc2FnZU9wdGlvbnNSB21lc3NhZ2U6SwoFZmllbGQSHS5nb29nbGUucHJvdG9idWYuRmllb - GRPcHRpb25zGPwHIAEoCzIVLnNjYWxhcGIuRmllbGRPcHRpb25zUgVmaWVsZDpWCgxlbnVtX29wdGlvbnMSHC5nb29nbGUucHJvd - G9idWYuRW51bU9wdGlvbnMY/AcgASgLMhQuc2NhbGFwYi5FbnVtT3B0aW9uc1ILZW51bU9wdGlvbnM6XAoKZW51bV92YWx1ZRIhL - mdvb2dsZS5wcm90b2J1Zi5FbnVtVmFsdWVPcHRpb25zGPwHIAEoCzIZLnNjYWxhcGIuRW51bVZhbHVlT3B0aW9uc1IJZW51bVZhb - HVlOksKBW9uZW9mEh0uZ29vZ2xlLnByb3RvYnVmLk9uZW9mT3B0aW9ucxj8ByABKAsyFS5zY2FsYXBiLk9uZW9mT3B0aW9uc1IFb - 25lb2ZCJwoPc2NhbGFwYi5vcHRpb25z4j8TCg9zY2FsYXBiLm9wdGlvbnMQAQ==""" + XByZXByb2Nlc3NvcnMYGCADKAlCEuI/DxINcHJlcHJvY2Vzc29yc1INcHJlcHJvY2Vzc29ycxJsChVmaWVsZF90cmFuc2Zvcm1hd + GlvbnMYGSADKAsyHC5zY2FsYXBiLkZpZWxkVHJhbnNmb3JtYXRpb25CGeI/FhIUZmllbGRUcmFuc2Zvcm1hdGlvbnNSFGZpZWxkV + HJhbnNmb3JtYXRpb25zEmEKHGlnbm9yZV9maWVsZF90cmFuc2Zvcm1hdGlvbnMYGiABKAhCH+I/HBIaaWdub3JlRmllbGRUcmFuc + 2Zvcm1hdGlvbnNSGmlnbm9yZUZpZWxkVHJhbnNmb3JtYXRpb25zEmEKHXRlc3Rfb25seV9ub19qYXZhX2NvbnZlcnNpb25zGOcHI + AEoCEIe4j8bEhl0ZXN0T25seU5vSmF2YUNvbnZlcnNpb25zUhl0ZXN0T25seU5vSmF2YUNvbnZlcnNpb25zGnkKEUF1eE1lc3NhZ + 2VPcHRpb25zEiMKBnRhcmdldBgBIAEoCUIL4j8IEgZ0YXJnZXRSBnRhcmdldBI/CgdvcHRpb25zGAIgASgLMhcuc2NhbGFwYi5NZ + XNzYWdlT3B0aW9uc0IM4j8JEgdvcHRpb25zUgdvcHRpb25zGnUKD0F1eEZpZWxkT3B0aW9ucxIjCgZ0YXJnZXQYASABKAlCC+I/C + BIGdGFyZ2V0UgZ0YXJnZXQSPQoHb3B0aW9ucxgCIAEoCzIVLnNjYWxhcGIuRmllbGRPcHRpb25zQgziPwkSB29wdGlvbnNSB29wd + GlvbnMacwoOQXV4RW51bU9wdGlvbnMSIwoGdGFyZ2V0GAEgASgJQgviPwgSBnRhcmdldFIGdGFyZ2V0EjwKB29wdGlvbnMYAiABK + AsyFC5zY2FsYXBiLkVudW1PcHRpb25zQgziPwkSB29wdGlvbnNSB29wdGlvbnMiJQoMT3B0aW9uc1Njb3BlEggKBEZJTEUQABILC + gdQQUNLQUdFEAEiMgoPRW51bVZhbHVlTmFtaW5nEg8KC0FTX0lOX1BST1RPEAASDgoKQ0FNRUxfQ0FTRRABKgkI6AcQgICAgAJKB + AgWEBdKBAgXEBgi9QMKDk1lc3NhZ2VPcHRpb25zEiYKB2V4dGVuZHMYASADKAlCDOI/CRIHZXh0ZW5kc1IHZXh0ZW5kcxJCChFjb + 21wYW5pb25fZXh0ZW5kcxgCIAMoCUIV4j8SEhBjb21wYW5pb25FeHRlbmRzUhBjb21wYW5pb25FeHRlbmRzEjIKC2Fubm90YXRpb + 25zGAMgAygJQhDiPw0SC2Fubm90YXRpb25zUgthbm5vdGF0aW9ucxIdCgR0eXBlGAQgASgJQgniPwYSBHR5cGVSBHR5cGUSTgoVY + 29tcGFuaW9uX2Fubm90YXRpb25zGAUgAygJQhniPxYSFGNvbXBhbmlvbkFubm90YXRpb25zUhRjb21wYW5pb25Bbm5vdGF0aW9uc + xJJChRzZWFsZWRfb25lb2ZfZXh0ZW5kcxgGIAMoCUIX4j8UEhJzZWFsZWRPbmVvZkV4dGVuZHNSEnNlYWxlZE9uZW9mRXh0ZW5kc + xIhCgZub19ib3gYByABKAhCCuI/BxIFbm9Cb3hSBW5vQm94ElsKGnVua25vd25fZmllbGRzX2Fubm90YXRpb25zGAggAygJQh3iP + xoSGHVua25vd25GaWVsZHNBbm5vdGF0aW9uc1IYdW5rbm93bkZpZWxkc0Fubm90YXRpb25zKgkI6AcQgICAgAIifwoKQ29sbGVjd + GlvbhIdCgR0eXBlGAEgASgJQgniPwYSBHR5cGVSBHR5cGUSKgoJbm9uX2VtcHR5GAIgASgIQg3iPwoSCG5vbkVtcHR5Ughub25Fb + XB0eRImCgdhZGFwdGVyGAMgASgJQgziPwkSB2FkYXB0ZXJSB2FkYXB0ZXIi7gMKDEZpZWxkT3B0aW9ucxIdCgR0eXBlGAEgASgJQ + gniPwYSBHR5cGVSBHR5cGUSLQoKc2NhbGFfbmFtZRgCIAEoCUIO4j8LEglzY2FsYU5hbWVSCXNjYWxhTmFtZRI8Cg9jb2xsZWN0a + W9uX3R5cGUYAyABKAlCE+I/EBIOY29sbGVjdGlvblR5cGVSDmNvbGxlY3Rpb25UeXBlEkQKCmNvbGxlY3Rpb24YCCABKAsyEy5zY + 2FsYXBiLkNvbGxlY3Rpb25CD+I/DBIKY29sbGVjdGlvblIKY29sbGVjdGlvbhInCghrZXlfdHlwZRgEIAEoCUIM4j8JEgdrZXlUe + XBlUgdrZXlUeXBlEi0KCnZhbHVlX3R5cGUYBSABKAlCDuI/CxIJdmFsdWVUeXBlUgl2YWx1ZVR5cGUSMgoLYW5ub3RhdGlvbnMYB + iADKAlCEOI/DRILYW5ub3RhdGlvbnNSC2Fubm90YXRpb25zEicKCG1hcF90eXBlGAcgASgJQgziPwkSB21hcFR5cGVSB21hcFR5c + GUSIQoGbm9fYm94GB4gASgIQgriPwcSBW5vQm94UgVub0JveBIpCghyZXF1aXJlZBgfIAEoCEIN4j8KEghyZXF1aXJlZFIIcmVxd + WlyZWQqCQjoBxCAgICAAiKjAQoLRW51bU9wdGlvbnMSJgoHZXh0ZW5kcxgBIAMoCUIM4j8JEgdleHRlbmRzUgdleHRlbmRzEkIKE + WNvbXBhbmlvbl9leHRlbmRzGAIgAygJQhXiPxISEGNvbXBhbmlvbkV4dGVuZHNSEGNvbXBhbmlvbkV4dGVuZHMSHQoEdHlwZRgDI + AEoCUIJ4j8GEgR0eXBlUgR0eXBlKgkI6AcQgICAgAIidAoQRW51bVZhbHVlT3B0aW9ucxImCgdleHRlbmRzGAEgAygJQgziPwkSB + 2V4dGVuZHNSB2V4dGVuZHMSLQoKc2NhbGFfbmFtZRgCIAEoCUIO4j8LEglzY2FsYU5hbWVSCXNjYWxhTmFtZSoJCOgHEICAgIACI + kEKDE9uZW9mT3B0aW9ucxImCgdleHRlbmRzGAEgAygJQgziPwkSB2V4dGVuZHNSB2V4dGVuZHMqCQjoBxCAgICAAiKbAgoTRmllb + GRUcmFuc2Zvcm1hdGlvbhI8CgR3aGVuGAEgASgLMh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9uc0IJ4j8GEgR3aGVuUgR3a + GVuEl8KCm1hdGNoX3R5cGUYAiABKA4yJi5zY2FsYXBiLkZpZWxkVHJhbnNmb3JtYXRpb24uTWF0Y2hUeXBlOghDT05UQUlOU0IO4 + j8LEgltYXRjaFR5cGVSCW1hdGNoVHlwZRIxCgNzZXQYAyABKAsyFS5zY2FsYXBiLkZpZWxkT3B0aW9uc0II4j8FEgNzZXRSA3Nld + CIyCglNYXRjaFR5cGUSDAoIQ09OVEFJTlMQABIJCgVFWEFDVBABEgwKCFBSRVNFTkNFEAIi8QEKElByZXByb2Nlc3Nvck91dHB1d + BJqCg9vcHRpb25zX2J5X2ZpbGUYASADKAsyLi5zY2FsYXBiLlByZXByb2Nlc3Nvck91dHB1dC5PcHRpb25zQnlGaWxlRW50cnlCE + uI/DxINb3B0aW9uc0J5RmlsZVINb3B0aW9uc0J5RmlsZRpvChJPcHRpb25zQnlGaWxlRW50cnkSGgoDa2V5GAEgASgJQgjiPwUSA + 2tleVIDa2V5EjkKBXZhbHVlGAIgASgLMhcuc2NhbGFwYi5TY2FsYVBiT3B0aW9uc0IK4j8HEgV2YWx1ZVIFdmFsdWU6AjgBOlAKB + 29wdGlvbnMSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMY/AcgASgLMhcuc2NhbGFwYi5TY2FsYVBiT3B0aW9uc1IHb3B0a + W9uczpTCgdtZXNzYWdlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGPwHIAEoCzIXLnNjYWxhcGIuTWVzc2FnZU9wd + GlvbnNSB21lc3NhZ2U6SwoFZmllbGQSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGPwHIAEoCzIVLnNjYWxhcGIuRmllb + GRPcHRpb25zUgVmaWVsZDpWCgxlbnVtX29wdGlvbnMSHC5nb29nbGUucHJvdG9idWYuRW51bU9wdGlvbnMY/AcgASgLMhQuc2Nhb + GFwYi5FbnVtT3B0aW9uc1ILZW51bU9wdGlvbnM6XAoKZW51bV92YWx1ZRIhLmdvb2dsZS5wcm90b2J1Zi5FbnVtVmFsdWVPcHRpb + 25zGPwHIAEoCzIZLnNjYWxhcGIuRW51bVZhbHVlT3B0aW9uc1IJZW51bVZhbHVlOksKBW9uZW9mEh0uZ29vZ2xlLnByb3RvYnVmL + k9uZW9mT3B0aW9ucxj8ByABKAsyFS5zY2FsYXBiLk9uZW9mT3B0aW9uc1IFb25lb2ZCJwoPc2NhbGFwYi5vcHRpb25z4j8TCg9zY + 2FsYXBiLm9wdGlvbnMQAQ==""" ).mkString) lazy val scalaDescriptor: _root_.scalapb.descriptors.FileDescriptor = { val scalaProto = com.google.protobuf.descriptor.FileDescriptorProto.parseFrom(ProtoBytes)