Skip to content

feat: add generate options #150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .sage/einrideeslint.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const (
name = "eslint"
packageJSONContent = `{
"dependencies": {
"@einride/eslint-plugin": "4.2.0",
"eslint": "8.5.0"
"@einride/eslint-plugin": "7.4.0",
"eslint": "8.51.0"
}
}`
)
Expand Down
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,53 @@ Or download a prebuilt binary from [releases](./releases).
```bash
protoc
--typescript-http_out [OUTPUT DIR] \
--typescript-http_opt use_enum_numbers=true,use_multi_line_comment=true
[.proto files ...]
```

#### Support options

```ts
// UseProtoNames controls the casing of generated field names.
// If set to true, fields will use proto names (typically snake_case).
// If omitted or set to false, fields will use JSON names (typically camelCase).
use_proto_names: bool

// UseEnumNumbers emits enum values as numbers.
use_enum_numbers: bool

// The method names of service methods naming case.
// Only work when `UseEnumNumbers=true`
// opt:
// camelcase: convert name to lower camel case like `camelCase`
// pascalcase: convert name to pascalcase like `PascalCase`
// default is pascalcase
enum_field_naming: string

// Generate comments as multiline comments.
// multiline comments: /** ... */
// single line comments: // ...
use_multi_line_comment: bool
Comment on lines +49 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the comment formatting need to be configurable?
I'd rather pick one of the formats (single/multi) and always use that, not configurable.

Copy link
Author

@moecasts moecasts Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because multiline comments is readable in ide tips dialog.
image

image

and make comment formatting be configurable is to aviod breaking change(Maybe it's just me worrying too much).


// force add `undefined` to message field.
// default true
force_message_field_undefinable: bool

// If set to true, body will be JSON.stringify before send
// default true
use_body_stringify: bool
Comment on lines +58 to +60
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I'm all for having this option, I understand it as you are also using that as a way to pass options to the request handler?

I would rather see a new argument to the request handler - something like handlerOptions: T - than spreading it into the request body.

Copy link
Author

@moecasts moecasts Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noop, at this monent, JSON.stringify is a mandatory behavior.

f.P(t(3), "const body = JSON.stringify(request);")
default:
nullPath := nullPropagationPath(httprule.FieldPath{rule.Body}, input)
f.P(t(3), "const body = JSON.stringify(request?.", nullPath, " ?? {});")

add this option is remove it, and the default value is true to avoid breaking change.

if someone like to use JSON.stringify, this option can be enabled, or archive it in requestHandler.


// The method names of service methods naming case.
// opt:
// camelcase: convert name to lower camel case like `camelCase`
// pascalcase: convert name to pascalcase like `PascalCase`
// default is pascalcase
service_method_naming: 'camelcase' | 'pascalcase'

// If set to true, field int64 and uint64 will convert to string
force_long_as_string: bool
Comment on lines +69 to +70
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be called long_as_string instead? Not sure where the force comes from ;)

Copy link
Author

@moecasts moecasts Oct 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is borrowed from: https://github.com/stephenh/ts-proto
image

I would like to borrow from the existing naming rather than define a new one.

Of course, if you really don't like it, I can change it.

```

---

The generated clients can be used with any HTTP client that returns a Promise containing JSON data.
Expand All @@ -39,11 +83,17 @@ type Request = {
body: string | null
}

function fetchRequestHandler({path, method, body}: Request) {
// This is optional
type RequestOptions = {
useCache?: boolean;
}
Comment on lines +86 to +89
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this come from?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see it now, see comment on the use_body_string option.


function fetchRequestHandler({path, method, body}: Request & RequestOptions) {
return fetch(rootUrl + path, {method, body}).then(response => response.json())
}

export function siteClient() {
return createShipperServiceClient(fetchRequestHandler);
// This Generics is optional
return createShipperServiceClient<RequestOptions>(fetchRequestHandler);
}
```
1 change: 1 addition & 0 deletions examples/proto/buf.gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ version: v1
plugins:
- name: typescript-http
out: gen/typescript
opt: use_enum_numbers=true,force_message_field_undefined=false,use_body_stringify=false,service_method_naming=camelcase,force_long_as_string=true
26 changes: 20 additions & 6 deletions examples/proto/einride/example/freight/v1/freight_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ import "google/protobuf/field_mask.proto";
// - Each Shipper has a collection of [Site][einride.example.freight.v1.Site]
// resources, named `shippers/*/sites/*`
//
// - Each Shipper has a collection of [Shipment][einride.example.freight.v1.Shipment]
// - Each Shipper has a collection of
// [Shipment][einride.example.freight.v1.Shipment]
// resources, named `shippers/*/shipments/*`
service FreightService {
option (google.api.default_host) = "freight-example.einride.tech";

// Get a shipper.
// See: https://google.aip.dev/131 (Standard methods: Get).
rpc GetShipper(GetShipperRequest) returns (Shipper) {
option (google.api.http) = {get: "/v1/{name=shippers/*}"};
option (google.api.http) = {
get: "/v1/{name=shippers/*}",
additional_bindings {get: "/v1/{name=shippers-alias/*}"}
};
option (google.api.method_signature) = "name";
}

Expand Down Expand Up @@ -261,8 +265,8 @@ message ListSitesResponse {

// Request message for FreightService.CreateSite.
message CreateSiteRequest {
// The resource name of the parent shipper for which this site will be created.
// Format: shippers/{shipper}
// The resource name of the parent shipper for which this site will be
// created. Format: shippers/{shipper}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {child_type: "freight-example.einride.tech/Shipper"}
Expand Down Expand Up @@ -323,6 +327,16 @@ message ListShipmentsRequest {
// [ListShipmentsResponse.next_page_token][einride.example.freight.v1.ListShipmentsResponse.next_page_token]
// returned from the previous call to `ListShipments` method.
string page_token = 3;

// query condition
map<string, QueryMessage> query = 4 [(google.api.field_behavior) = OPTIONAL];
}

message QueryMessage {
string key = 1;
string value = 2;

optional QueryMessage nested_query = 3;
}

// Response message for FreightService.ListShipments.
Expand All @@ -339,8 +353,8 @@ message ListShipmentsResponse {

// Request message for FreightService.CreateShipment.
message CreateShipmentRequest {
// The resource name of the parent shipper for which this shipment will be created.
// Format: shippers/{shipper}
// The resource name of the parent shipper for which this shipment will be
// created. Format: shippers/{shipper}
string parent = 1 [
(google.api.field_behavior) = REQUIRED,
(google.api.resource_reference) = {child_type: "freight-example.einride.tech/Shipper"}
Expand Down
22 changes: 21 additions & 1 deletion examples/proto/einride/example/freight/v1/shipment.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ package einride.example.freight.v1;
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

enum ShipmentState {
// The shipment' state is unknown
UNKNOWN_UNSPECIFIED = 0;
// The shipment'state is active
ACTIVE = 1;
// The shipment'state is inactive
INACTIVE = 2;
}

// A shipment represents transportation of goods between an origin
// [site][einride.example.freight.v1.Site] and a destination
Expand Down Expand Up @@ -62,6 +72,16 @@ message Shipment {

// Annotations of the shipment.
map<string, string> annotations = 12;

// The state of the shipment
ShipmentState state = 14;

// wrapper string
optional google.protobuf.StringValue wrapper_string = 15;
// long number
int64 long_number = 16;
// wrapper long number
google.protobuf.Int64Value wrapper_long_number = 17;
}

// A shipment line item.
Expand All @@ -73,5 +93,5 @@ message LineItem {
// The weight of the line item in kilograms.
float weight_kg = 3;
// The volume of the line item in cubic meters.
float volume_m3 = 4;
optional float volume_m3 = 4;
}
Loading