From 8b071d35f48fcf901d83a019d3620ad672ce2048 Mon Sep 17 00:00:00 2001 From: etiennep-chromium Date: Sat, 9 Aug 2025 15:52:57 -0400 Subject: [PATCH 1/2] fix: Honour packed repeated fields encoding for proto2 (#1210) Follow up to https://github.com/stephenh/ts-proto/pull/1208/files I got the proto2 logic wrong. https://github.com/stephenh/ts-proto/issues/1207 --- .../from-partial-no-initialize/test.ts | 4 +--- integration/groups/test.ts | 16 ++++----------- .../google/protobuf/descriptor.ts | 20 ++++++++++--------- .../options/google/protobuf/descriptor.ts | 20 ++++++++++--------- integration/proto2-long/simple.ts | 20 +++++-------------- integration/proto2-no-default-vals/simple.ts | 20 +++++-------------- integration/proto2-no-optionals/simple.ts | 20 +++++-------------- integration/proto2/simple.ts | 20 +++++-------------- .../google/protobuf/descriptor.ts | 20 ++++++++++--------- integration/vector-tile/vector_tile.ts | 8 ++++++-- src/types.ts | 8 ++------ 11 files changed, 66 insertions(+), 110 deletions(-) diff --git a/integration/from-partial-no-initialize/test.ts b/integration/from-partial-no-initialize/test.ts index 0b59eafed..7f764c961 100644 --- a/integration/from-partial-no-initialize/test.ts +++ b/integration/from-partial-no-initialize/test.ts @@ -112,11 +112,9 @@ export const TPartial: MessageFns = { } } if (message.repeatedNumber !== undefined && message.repeatedNumber.length !== 0) { - writer.uint32(58).fork(); for (const v of message.repeatedNumber) { - writer.int32(v); + writer.uint32(56).int32(v!); } - writer.join(); } return writer; }, diff --git a/integration/groups/test.ts b/integration/groups/test.ts index 3f8dccede..a2c737269 100644 --- a/integration/groups/test.ts +++ b/integration/groups/test.ts @@ -271,11 +271,9 @@ function createBaseGroupsRepeatedTest(): GroupsRepeatedTest { export const GroupsRepeatedTest: MessageFns = { encode(message: GroupsRepeatedTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { if (message.int1 !== undefined && message.int1.length !== 0) { - writer.uint32(10).fork(); for (const v of message.int1) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); } if (message.group !== undefined && message.group.length !== 0) { for (const v of message.group) { @@ -283,11 +281,9 @@ export const GroupsRepeatedTest: MessageFns = { } } if (message.int3 !== undefined && message.int3.length !== 0) { - writer.uint32(26).fork(); for (const v of message.int3) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); } if (message._unknownFields !== undefined) { for (const [key, values] of Object.entries(message._unknownFields)) { @@ -545,11 +541,9 @@ function createBaseGroupsNestedTest(): GroupsNestedTest { export const GroupsNestedTest: MessageFns = { encode(message: GroupsNestedTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { if (message.int1 !== undefined && message.int1.length !== 0) { - writer.uint32(10).fork(); for (const v of message.int1) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); } if (message.group !== undefined && message.group.length !== 0) { for (const v of message.group) { @@ -557,11 +551,9 @@ export const GroupsNestedTest: MessageFns = { } } if (message.int3 !== undefined && message.int3.length !== 0) { - writer.uint32(26).fork(); for (const v of message.int3) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); } if (message._unknownFields !== undefined) { for (const [key, values] of Object.entries(message._unknownFields)) { diff --git a/integration/meta-typings-as-const/google/protobuf/descriptor.ts b/integration/meta-typings-as-const/google/protobuf/descriptor.ts index 1d649fadc..2c055c8e1 100644 --- a/integration/meta-typings-as-const/google/protobuf/descriptor.ts +++ b/integration/meta-typings-as-const/google/protobuf/descriptor.ts @@ -1020,16 +1020,12 @@ export const FileDescriptorProto: MessageFns = { for (const v of message.dependency) { writer.uint32(26).string(v!); } - writer.uint32(82).fork(); for (const v of message.publicDependency) { - writer.int32(v); + writer.uint32(80).int32(v!); } - writer.join(); - writer.uint32(90).fork(); for (const v of message.weakDependency) { - writer.int32(v); + writer.uint32(88).int32(v!); } - writer.join(); for (const v of message.messageType) { DescriptorProto.encode(v!, writer.uint32(34).fork()).join(); } @@ -2953,12 +2949,16 @@ function createBaseSourceCodeInfo_Location(): SourceCodeInfo_Location { export const SourceCodeInfo_Location: MessageFns = { encode(message: SourceCodeInfo_Location, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); + writer.uint32(18).fork(); for (const v of message.span) { - writer.uint32(16).int32(v!); + writer.int32(v); } + writer.join(); if (message.leadingComments !== undefined && message.leadingComments !== "") { writer.uint32(26).string(message.leadingComments); } @@ -3091,9 +3091,11 @@ function createBaseGeneratedCodeInfo_Annotation(): GeneratedCodeInfo_Annotation export const GeneratedCodeInfo_Annotation: MessageFns = { encode(message: GeneratedCodeInfo_Annotation, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); if (message.sourceFile !== undefined && message.sourceFile !== "") { writer.uint32(18).string(message.sourceFile); } diff --git a/integration/options/google/protobuf/descriptor.ts b/integration/options/google/protobuf/descriptor.ts index beb1cc657..da5df1da4 100644 --- a/integration/options/google/protobuf/descriptor.ts +++ b/integration/options/google/protobuf/descriptor.ts @@ -1020,16 +1020,12 @@ export const FileDescriptorProto: MessageFns = { for (const v of message.dependency) { writer.uint32(26).string(v!); } - writer.uint32(82).fork(); for (const v of message.publicDependency) { - writer.int32(v); + writer.uint32(80).int32(v!); } - writer.join(); - writer.uint32(90).fork(); for (const v of message.weakDependency) { - writer.int32(v); + writer.uint32(88).int32(v!); } - writer.join(); for (const v of message.messageType) { DescriptorProto.encode(v!, writer.uint32(34).fork()).join(); } @@ -2953,12 +2949,16 @@ function createBaseSourceCodeInfo_Location(): SourceCodeInfo_Location { export const SourceCodeInfo_Location: MessageFns = { encode(message: SourceCodeInfo_Location, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); + writer.uint32(18).fork(); for (const v of message.span) { - writer.uint32(16).int32(v!); + writer.int32(v); } + writer.join(); if (message.leadingComments !== undefined && message.leadingComments !== "") { writer.uint32(26).string(message.leadingComments); } @@ -3091,9 +3091,11 @@ function createBaseGeneratedCodeInfo_Annotation(): GeneratedCodeInfo_Annotation export const GeneratedCodeInfo_Annotation: MessageFns = { encode(message: GeneratedCodeInfo_Annotation, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); if (message.sourceFile !== undefined && message.sourceFile !== "") { writer.uint32(18).string(message.sourceFile); } diff --git a/integration/proto2-long/simple.ts b/integration/proto2-long/simple.ts index bfce90156..b6138afad 100644 --- a/integration/proto2-long/simple.ts +++ b/integration/proto2-long/simple.ts @@ -142,40 +142,30 @@ function createBaseOptionalsTest(): OptionalsTest { export const OptionalsTest: MessageFns = { encode(message: OptionalsTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - writer.uint32(10).fork(); for (const v of message.repId) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); for (const v of message.repChild) { Child.encode(v!, writer.uint32(18).fork()).join(); } - writer.uint32(26).fork(); for (const v of message.repState) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); - writer.uint32(34).fork(); for (const v of message.repLong) { - writer.int64(v.toString()); + writer.uint32(32).int64(v!.toString()); } - writer.join(); - writer.uint32(42).fork(); for (const v of message.repTruth) { - writer.bool(v); + writer.uint32(40).bool(v!); } - writer.join(); for (const v of message.repDescription) { writer.uint32(50).string(v!); } for (const v of message.repData) { writer.uint32(58).bytes(v!); } - writer.uint32(66).fork(); for (const v of message.repFloat) { - writer.float(v); + writer.uint32(69).float(v!); } - writer.join(); if (message.optId !== undefined && message.optId !== 0) { writer.uint32(88).int32(message.optId); } diff --git a/integration/proto2-no-default-vals/simple.ts b/integration/proto2-no-default-vals/simple.ts index 533eea06a..b575c638f 100644 --- a/integration/proto2-no-default-vals/simple.ts +++ b/integration/proto2-no-default-vals/simple.ts @@ -141,40 +141,30 @@ function createBaseOptionalsTest(): OptionalsTest { export const OptionalsTest: MessageFns = { encode(message: OptionalsTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - writer.uint32(10).fork(); for (const v of message.repId) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); for (const v of message.repChild) { Child.encode(v!, writer.uint32(18).fork()).join(); } - writer.uint32(26).fork(); for (const v of message.repState) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); - writer.uint32(34).fork(); for (const v of message.repLong) { - writer.int64(v); + writer.uint32(32).int64(v!); } - writer.join(); - writer.uint32(42).fork(); for (const v of message.repTruth) { - writer.bool(v); + writer.uint32(40).bool(v!); } - writer.join(); for (const v of message.repDescription) { writer.uint32(50).string(v!); } for (const v of message.repData) { writer.uint32(58).bytes(v!); } - writer.uint32(66).fork(); for (const v of message.repFloat) { - writer.float(v); + writer.uint32(69).float(v!); } - writer.join(); if (message.optId !== undefined && message.optId !== 0) { writer.uint32(88).int32(message.optId); } diff --git a/integration/proto2-no-optionals/simple.ts b/integration/proto2-no-optionals/simple.ts index 0a52d7d47..543623575 100644 --- a/integration/proto2-no-optionals/simple.ts +++ b/integration/proto2-no-optionals/simple.ts @@ -141,40 +141,30 @@ function createBaseOptionalsTest(): OptionalsTest { export const OptionalsTest: MessageFns = { encode(message: OptionalsTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - writer.uint32(10).fork(); for (const v of message.repId) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); for (const v of message.repChild) { Child.encode(v!, writer.uint32(18).fork()).join(); } - writer.uint32(26).fork(); for (const v of message.repState) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); - writer.uint32(34).fork(); for (const v of message.repLong) { - writer.int64(v); + writer.uint32(32).int64(v!); } - writer.join(); - writer.uint32(42).fork(); for (const v of message.repTruth) { - writer.bool(v); + writer.uint32(40).bool(v!); } - writer.join(); for (const v of message.repDescription) { writer.uint32(50).string(v!); } for (const v of message.repData) { writer.uint32(58).bytes(v!); } - writer.uint32(66).fork(); for (const v of message.repFloat) { - writer.float(v); + writer.uint32(69).float(v!); } - writer.join(); if (message.optId !== 0) { writer.uint32(88).int32(message.optId); } diff --git a/integration/proto2/simple.ts b/integration/proto2/simple.ts index f60448901..3161f18ec 100644 --- a/integration/proto2/simple.ts +++ b/integration/proto2/simple.ts @@ -141,40 +141,30 @@ function createBaseOptionalsTest(): OptionalsTest { export const OptionalsTest: MessageFns = { encode(message: OptionalsTest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - writer.uint32(10).fork(); for (const v of message.repId) { - writer.int32(v); + writer.uint32(8).int32(v!); } - writer.join(); for (const v of message.repChild) { Child.encode(v!, writer.uint32(18).fork()).join(); } - writer.uint32(26).fork(); for (const v of message.repState) { - writer.int32(v); + writer.uint32(24).int32(v!); } - writer.join(); - writer.uint32(34).fork(); for (const v of message.repLong) { - writer.int64(v); + writer.uint32(32).int64(v!); } - writer.join(); - writer.uint32(42).fork(); for (const v of message.repTruth) { - writer.bool(v); + writer.uint32(40).bool(v!); } - writer.join(); for (const v of message.repDescription) { writer.uint32(50).string(v!); } for (const v of message.repData) { writer.uint32(58).bytes(v!); } - writer.uint32(66).fork(); for (const v of message.repFloat) { - writer.float(v); + writer.uint32(69).float(v!); } - writer.join(); if (message.optId !== undefined && message.optId !== 0) { writer.uint32(88).int32(message.optId); } diff --git a/integration/unknown-fields/google/protobuf/descriptor.ts b/integration/unknown-fields/google/protobuf/descriptor.ts index 45f21b995..f08159025 100644 --- a/integration/unknown-fields/google/protobuf/descriptor.ts +++ b/integration/unknown-fields/google/protobuf/descriptor.ts @@ -1063,16 +1063,12 @@ export const FileDescriptorProto: MessageFns = { for (const v of message.dependency) { writer.uint32(26).string(v!); } - writer.uint32(82).fork(); for (const v of message.publicDependency) { - writer.int32(v); + writer.uint32(80).int32(v!); } - writer.join(); - writer.uint32(90).fork(); for (const v of message.weakDependency) { - writer.int32(v); + writer.uint32(88).int32(v!); } - writer.join(); for (const v of message.messageType) { DescriptorProto.encode(v!, writer.uint32(34).fork()).join(); } @@ -3386,12 +3382,16 @@ function createBaseSourceCodeInfo_Location(): SourceCodeInfo_Location { export const SourceCodeInfo_Location: MessageFns = { encode(message: SourceCodeInfo_Location, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); + writer.uint32(18).fork(); for (const v of message.span) { - writer.uint32(16).int32(v!); + writer.int32(v); } + writer.join(); if (message.leadingComments !== undefined && message.leadingComments !== "") { writer.uint32(26).string(message.leadingComments); } @@ -3556,9 +3556,11 @@ function createBaseGeneratedCodeInfo_Annotation(): GeneratedCodeInfo_Annotation export const GeneratedCodeInfo_Annotation: MessageFns = { encode(message: GeneratedCodeInfo_Annotation, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + writer.uint32(10).fork(); for (const v of message.path) { - writer.uint32(8).int32(v!); + writer.int32(v); } + writer.join(); if (message.sourceFile !== undefined && message.sourceFile !== "") { writer.uint32(18).string(message.sourceFile); } diff --git a/integration/vector-tile/vector_tile.ts b/integration/vector-tile/vector_tile.ts index 1f041257b..d32531657 100644 --- a/integration/vector-tile/vector_tile.ts +++ b/integration/vector-tile/vector_tile.ts @@ -306,15 +306,19 @@ export const Tile_Feature: MessageFns = { if (message.id !== undefined && message.id !== 0) { writer.uint32(8).uint64(message.id); } + writer.uint32(18).fork(); for (const v of message.tags) { - writer.uint32(16).uint32(v!); + writer.uint32(v); } + writer.join(); if (message.type !== undefined && message.type !== 0) { writer.uint32(24).int32(message.type); } + writer.uint32(34).fork(); for (const v of message.geometry) { - writer.uint32(32).uint32(v!); + writer.uint32(v); } + writer.join(); return writer; }, diff --git a/src/types.ts b/src/types.ts index ee86739f0..b0f261251 100644 --- a/src/types.ts +++ b/src/types.ts @@ -163,12 +163,8 @@ export function toReaderCall(field: FieldDescriptorProto): string { } export function packedField(field: FieldDescriptorProto, isProto3Syntax: boolean): number | undefined { - if (isProto3Syntax && field.options?.packed === false) { - return undefined; - } else if (!isProto3Syntax && !!field.options?.packed) { - return undefined; - } - return packedType(field.type); + const shouldPack = field.options?.packed ?? isProto3Syntax; + return shouldPack ? packedType(field.type) : undefined; } export function packedType(type: FieldDescriptorProto_Type): number | undefined { From 65dc52fdc390c4a6a373fa3212bac58aaa480713 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 9 Aug 2025 19:56:40 +0000 Subject: [PATCH 2/2] chore(release): 2.7.7 [skip ci] ## [2.7.7](https://github.com/stephenh/ts-proto/compare/v2.7.6...v2.7.7) (2025-08-09) ### Bug Fixes * Honour packed repeated fields encoding for proto2 ([#1210](https://github.com/stephenh/ts-proto/issues/1210)) ([8b071d3](https://github.com/stephenh/ts-proto/commit/8b071d35f48fcf901d83a019d3620ad672ce2048)) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edaaf354f..a9a7cb08a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [2.7.7](https://github.com/stephenh/ts-proto/compare/v2.7.6...v2.7.7) (2025-08-09) + + +### Bug Fixes + +* Honour packed repeated fields encoding for proto2 ([#1210](https://github.com/stephenh/ts-proto/issues/1210)) ([8b071d3](https://github.com/stephenh/ts-proto/commit/8b071d35f48fcf901d83a019d3620ad672ce2048)) + ## [2.7.6](https://github.com/stephenh/ts-proto/compare/v2.7.5...v2.7.6) (2025-08-08) diff --git a/package.json b/package.json index 1019ad6a6..34e42a8f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ts-proto", - "version": "2.7.6", + "version": "2.7.7", "description": "", "main": "build/src/plugin.js", "repository": "github:stephenh/ts-proto",