diff --git a/packages/protobuf/src/create-descriptor-set.ts b/packages/protobuf/src/create-descriptor-set.ts index 764b07584..8f071e073 100644 --- a/packages/protobuf/src/create-descriptor-set.ts +++ b/packages/protobuf/src/create-descriptor-set.ts @@ -52,11 +52,9 @@ import { parseTextFormatEnumValue, parseTextFormatScalarValue, } from "./private/text-format.js"; +import type { BinaryReadOptions, BinaryWriteOptions } from "./binary-format.js"; import type { FeatureResolverFn } from "./private/feature-set.js"; -import { - createFeatureResolver, - featureSetDefaults, -} from "./private/feature-set.js"; +import { createFeatureResolver } from "./private/feature-set.js"; /** * Create a DescriptorSet, a convenient interface for working with a set of @@ -90,8 +88,9 @@ export function createDescriptorSet( let resolveFeatures = resolverByEdition.get(edition); if (resolveFeatures === undefined) { resolveFeatures = createFeatureResolver( - options?.featureSetDefaults ?? featureSetDefaults, edition, + options?.featureSetDefaults, + options?.serializationOptions, ); resolverByEdition.set(edition, resolveFeatures); } @@ -117,6 +116,12 @@ interface CreateDescriptorSetOptions { * `--experimental_edition_defaults_out`. */ featureSetDefaults?: FeatureSetDefaults; + + /** + * Internally, data is serialized when features are resolved. The + * serialization options given here will be used for feature resolution. + */ + serializationOptions?: Partial; } /** diff --git a/packages/protobuf/src/private/feature-set.ts b/packages/protobuf/src/private/feature-set.ts index f4d8c75ff..5e8ecef8c 100644 --- a/packages/protobuf/src/private/feature-set.ts +++ b/packages/protobuf/src/private/feature-set.ts @@ -18,15 +18,24 @@ import { FeatureSetDefaults, } from "../google/protobuf/descriptor_pb.js"; import { protoBase64 } from "../proto-base64.js"; +import type { + BinaryReadOptions, + BinaryWriteOptions, +} from "../binary-format.js"; /** - * Static edition feature defaults supported by @bufbuild/protobuf. + * Return the edition feature defaults supported by @bufbuild/protobuf. */ -export const featureSetDefaults = FeatureSetDefaults.fromBinary( - protoBase64.dec( - /*upstream-inject-feature-defaults-start*/ "ChESDAgBEAIYAiABKAEwAhjmBwoREgwIAhABGAEgAigBMAEY5wcKERIMCAEQARgBIAIoATABGOgHIOYHKOgH" /*upstream-inject-feature-defaults-end*/, - ), -); +function getFeatureSetDefaults( + options?: Partial, +): FeatureSetDefaults { + return FeatureSetDefaults.fromBinary( + protoBase64.dec( + /*upstream-inject-feature-defaults-start*/ "ChESDAgBEAIYAiABKAEwAhjmBwoREgwIAhABGAEgAigBMAEY5wcKERIMCAEQARgBIAIoATABGOgHIOYHKOgH" /*upstream-inject-feature-defaults-end*/, + ), + options, + ); +} /** * A merged google.protobuf.FeaturesSet, with all fields guaranteed to be set. @@ -46,18 +55,22 @@ export type FeatureResolverFn = ( ) => MergedFeatureSet; /** - * Create an edition feature resolver with the given feature set defaults. + * Create an edition feature resolver with the given feature set defaults, or + * the feature set defaults supported by @bufbuild/protobuf. */ export function createFeatureResolver( - compiledFeatureSetDefaults: FeatureSetDefaults, edition: Edition, + compiledFeatureSetDefaults?: FeatureSetDefaults, + serializationOptions?: Partial, ): FeatureResolverFn { - const min = compiledFeatureSetDefaults.minimumEdition; - const max = compiledFeatureSetDefaults.maximumEdition; + const fds = + compiledFeatureSetDefaults ?? getFeatureSetDefaults(serializationOptions); + const min = fds.minimumEdition; + const max = fds.maximumEdition; if ( min === undefined || max === undefined || - compiledFeatureSetDefaults.defaults.some((d) => d.edition === undefined) + fds.defaults.some((d) => d.edition === undefined) ) { throw new Error("Invalid FeatureSetDefaults"); } @@ -72,7 +85,7 @@ export function createFeatureResolver( ); } let highestMatch: { e: Edition; f: FeatureSet } | undefined = undefined; - for (const c of compiledFeatureSetDefaults.defaults) { + for (const c of fds.defaults) { const e = c.edition ?? 0; if (e > edition) { continue; @@ -88,12 +101,12 @@ export function createFeatureResolver( if (highestMatch === undefined) { throw new Error(`No valid default found for edition ${Edition[edition]}`); } - const defaultsBin = highestMatch.f.toBinary(); + const featureSetBin = highestMatch.f.toBinary(serializationOptions); return (...rest): MergedFeatureSet => { - const f = FeatureSet.fromBinary(defaultsBin); + const f = FeatureSet.fromBinary(featureSetBin, serializationOptions); for (const c of rest) { if (c !== undefined) { - f.fromBinary(c.toBinary()); + f.fromBinary(c.toBinary(serializationOptions), serializationOptions); } } if (!validateMergedFeatures(f)) {