protocolbuffers / protobuf-javascript

BSD 3-Clause "New" or "Revised" License
360 stars 67 forks source link

The generated code(js) is different from what I defined in .proto file #37

Closed microlv closed 2 years ago

microlv commented 4 years ago

What version of protobuf and what language are you using? Version: v3.11.0 Language: Javascript

What operating system (Linux, Windows, ...) and version? Windows/Linux

What runtime / compiler are you using (e.g., python version or gcc version) protoc

What did you do? Steps to reproduce the behavior:

  1. download the protoc cmder 2.define the .proto file liek the below code:
    
    syntax = "proto3";

message Response { string result = 1; repeated string data = 2; repeated string dataEChart = 3; string con_lv = 4; string Msg = 5; }

3. protoc  --js_out=import_style=commonjs,binary:. *.proto
4. look into the _pb.js file
```js
proto.Response.toObject = function(includeInstance, msg) {
  var f, obj = {
    result: jspb.Message.getFieldWithDefault(msg, 1, ""),
    dataList: (f = jspb.Message.getRepeatedField(msg, 2)) == null ? undefined : f,
    dataechartList: (f = jspb.Message.getRepeatedField(msg, 3)) == null ? undefined : f,
    conLv: jspb.Message.getFieldWithDefault(msg, 4, ""),
    msg: jspb.Message.getFieldWithDefault(msg, 5, "")
  };

  if (includeInstance) {
    obj.$jspbMessageInstance = msg;
  }
  return obj;
};
}

What did you expect to see I want to keep my field as the same as I defined in .proto file. but I found some fields are changed. In toObject function there are some fields are changed, like:

repeated string data = 2; ===>> dataList //why has List???
repeated string dataEChart = 3; ===>>dataechartList  //why to LowerCase, why has List???
string con_lv = 4; ===>> conLv //why changed to Lv??
string Msg = 5; ===>> msg //why lowercase

What did you see instead? My field has been changed! and I want to keep it as the same as I defined it in .proto file

Anything else we should know about your project / environment web project/ commonjs coding style/ use webpack/

thesayyn commented 4 years ago

@microlv You might wanna use my generator to generate with exact names. It generates typescript but you can compile it to js and use it.

https://github.com/thesayyn/protoc-gen-ts

microlv commented 4 years ago

@thesayyn I don't found your example code in your project. do u miss add it to github? And I don't use TS. only es. is any doc can tell me how to do with es6?

thesayyn commented 4 years ago

@microlv Unfortunately it doesn’t compile to ESM directly although you can use typescript to get ESM compatible js outputs from ts files.

Maybe later I can add an option to get ESM-JS outputs from generated Typescript files thus you can get ESM outputs directly from the plugin. But for now, you need to compile them to js which is so easy. It will take only few minutes.

guyisra commented 4 years ago

any updates on this? this is a critical issue!

untra commented 4 years ago

Just speculation here: I get the sense that appending list to repeated fields variable names was a design decision made before typescript was a thing, so as to give developers the contextual clues that the expected type would be an array of something.

but yes, if there was a compile-time flag to allow proto generation to not mangle the variable names of repeated fields, that would be quite nice.

jamierumbelow commented 3 years ago

Would like to add my +1 to this issue. We're using the --js_out and protoc-gen-ts plugin compilation to generate typedefs, which we use to verify the data shape at compile time. We then send the data over the wire in JSON to a Golang API.

What I don't understand is why the JS changes the keys this way, but the JSON keys in Golang don't get similarly changed:

In JS:

locationsList: Array<Location.AsObject>,

and the same prop in go:

Locations []*Location `protobuf:"bytes,11,rep,name=locations,proto3" json:"locations,omitempty"`

This means we need to manually extend the type in order to get the thing compiling correctly with keys that can be decoded when they get to the server:

export interface Thing extends Omit<ThingProto.AsObject, "locationsList"> {
  locations: ThingProto.AsObject["locationsList"]
}
thesayyn commented 3 years ago

@microlv You might wanna use my generator to generate with exact names. It generates typescript but you can compile it to js and use it.

https://github.com/thesayyn/protoc-gen-ts

@jamierumbelow i don't see a reason why you shouldn't use protoc-gen-ts directly. it uses google-protobuf under the hood as a peer dependency which means you still get the security fixes as you go

jamierumbelow commented 3 years ago

I thought I was – but just looked a little closer and realised I was using ts-protoc-gen, rather than protoc-gen-ts. Will give it a go. Thanks!

thesayyn commented 3 years ago

Don't forget to upstream the changes you make to the compiler according to your needs. I would appreciate help from all of you.

dibenede commented 2 years ago

We transform names to lower camelcase intentionally to match commonjs style as opposed to the lower_style that is more common in protobuf. Additionally, we add suffixes to match the types. We can't easily change this because it would be a compatibility break.