Skip to content

Commit

Permalink
refactor: change from class methods to arrow functions (#92)
Browse files Browse the repository at this point in the history
Big thanks to @koblas

Now we support `--ts_opt=unary_rpc_promise` and `--ts_opt=grpc_package=xxx`
  • Loading branch information
koblas authored Oct 4, 2021
1 parent 0fbff05 commit ce7dd99
Show file tree
Hide file tree
Showing 5 changed files with 1,227 additions and 1,011 deletions.
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
proseWrap: always
singleQuote: false
trailingComma: all
31 changes: 14 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
![npm](https://img.shields.io/npm/v/protoc-gen-ts)
![npm](https://img.shields.io/npm/dm/protoc-gen-ts)

Generates appropriate Protocol Buffer sources from Proto files directly through _TypeScript Compiler API_.

This plugin generates plain **Typescript** files that can be used AMD, UMD, CommonJS module systems.
Aim of this protoc plugin is to make usage of protocol buffers easy in Javascript/Typescript by taking modern approaches. This plugin generates plain **Typescript** files that can be used AMD, UMD, CommonJS module systems.

Aim of this protoc plugin is to make usage of protocol buffers easy in Javascript/Typescript by taking modern approaches.

## Example

Expand Down Expand Up @@ -72,7 +69,7 @@ To overcome this problem, every generated message class has a static method call
which can handle the mapping bidirectionally for you, even with the deeply structured messages. since it is
aware of the field graph, it does not rely on any runtime type information thus we get the chance to keep it fast.

given the change example above, one can write code as;
One can write code as;

```typescript
const change = Change.fromObject({
Expand All @@ -85,13 +82,15 @@ const change = Change.fromObject({
role: "maintainer"
}
});

console.log(change.author instanceof Author) // true
```


## Usage with `@grpc/grpc-js` or `grpc`

There is a seperate documentation for the usage of protoc-gen-ts along with either `@grpc/grpc-js` or `grpc`.
There is a seperate documentation for the usage of protoc-gen-ts along with either `@grpc/grpc-js` or `grpc`. By default
this generated gRPC interfaces will use `@grpc/grpc-js`.

Checkout [rpcs](docs/rpc.md).

Expand Down Expand Up @@ -140,20 +139,12 @@ ts_proto_library(
# Checkout the examples/bazel directory for an example.
```

## Environment variables

```sh
# This controls experimental features such as 'Promise' based rpcs.
export EXPERIMENTAL_FEATURES=true;
## Supported Options

* With `--ts_opt=unary_rpc_promise=true`, the service definition will contain a promise based rpc with a calling pattern of `const result = await client.METHOD(message)`. Note: all othe `metadata` and `options` parameters are still available to you.

# This controls the "import statement" for the outputs.
# this is here for legacy purposes.
export GRPC_PACKAGE_NAME="@grpc/grpc-js";
# or
export GRPC_PACKAGE_NAME="@grpc/grpc";
* With `--ts_opt=grpc_package=xxxx`, you can specify a different package to import rather than `@grpc/grpc-js`.

```
## Roadmap

- <s>Support for repeated non-integer fields</s>
Expand All @@ -178,10 +169,16 @@ export GRPC_PACKAGE_NAME="@grpc/grpc";

## Development

Generates appropriate Protocol Buffer sources from Proto files directly through _TypeScript Compiler API_.

```sh
# to run test invoke
yarn test
# additionally if you want to see error details
yarn test --test_output=errors

```

## Contributors

![GitHub Contributors Image](https://contrib.rocks/image?repo=thesayyn/protoc-gen-ts)
10 changes: 5 additions & 5 deletions index.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ def _ts_proto_library(ctx):

protoc_args.add("--descriptor_set_in=%s" % (":".join([desc.path for desc in transitive_descriptors])))

protoc_args.add_all(direct_sources)

env = dict()

env["GRPC_PACKAGE_NAME"] = ctx.attr.grpc_package_name
protoc_args.add("--ts_opt=grpc_package=%s" % ctx.attr.grpc_package_name)

if ctx.attr.experimental_features:
env['EXPERIMENTAL_FEATURES'] = "true"
protoc_args.add("--ts_opt=unary_rpc_promise")

protoc_args.add_all(direct_sources)

ctx.actions.run(
inputs = direct_sources + transitive_descriptors,
Expand Down Expand Up @@ -109,4 +109,4 @@ ts_proto_library = rule(
),

}
)
)
85 changes: 73 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,55 @@ function replaceExtension(filename, extension = ".ts") {
return filename.replace(/\.[^/.]+$/, extension)
}

/**
* @typedef {{ unary_rpc_promise: boolean, grpc_package: string }} ConfigParameters
*/

/**
* @param {string | undefined | null} parameters
* @return{ConfigParameters}
*/
function parseParameters(parameters) {
/** @type{ConfigParameters} */
const defaultValues = {
unary_rpc_promise: false,
grpc_package: "@grpc/grpc-js",
};

/** @type{{ [K keyof ConfigParameters]: (value: string) => ConfigParameters[K] }} */
const parsers = {
unary_rpc_promise: (value) => value === "true",
grpc_package: (value) => value,
};

/** @type{Partial<ConfigParameters>} */
const inputParams = {};

// comma separated
(parameters || "").split(',').forEach(param => {
const [key, value = "true"] = param.split('=', 2)

if (key in parsers) {
inputParams[key] = parsers[key](value);
}
})

// Legacy Environment variables
const legacy = {
...(process.env.EXPERIMENTAL_FEATURES ? { unary_rpc_promise: true } : {}),
...(process.env.GRPC_PACKAGE_NAME ? { grpc_package: process.env.GRPC_PACKAGE_NAME } : {}),
}

return { ...defaultValues, ...legacy, ...inputParams }
}

const request = plugin.CodeGeneratorRequest.deserialize(new Uint8Array(fs.readFileSync(0)));
const response = new plugin.CodeGeneratorResponse({
supported_features: plugin.CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL
});

const configParams = parseParameters(request.parameter)

for (const descriptor of request.proto_file) {
type.preprocess(descriptor, descriptor.name, `.${descriptor.package || ""}`);
}
Expand All @@ -36,7 +80,6 @@ for (const fileDescriptor of request.proto_file) {
// Will keep track of import statements
const importStatements = [];


// Create all named imports from dependencies
for (const dependency of fileDescriptor.dependency) {
const identifier = ts.factory.createUniqueName("dependency");
Expand Down Expand Up @@ -65,18 +108,37 @@ for (const fileDescriptor of request.proto_file) {
importStatements.push(createImport(pbIdentifier, "google-protobuf"));
}

// Create all services and clients
for (const serviceDescriptor of fileDescriptor.service) {
statements.push(rpc.createUnimplementedServer(fileDescriptor, serviceDescriptor, grpcIdentifier));
statements.push(rpc.createServiceClient(fileDescriptor, serviceDescriptor, grpcIdentifier));
}

// Import grpc only if there is service statements
if (fileDescriptor.service.length) {
importStatements.push(createImport(grpcIdentifier, process.env.GRPC_PACKAGE_NAME || "@grpc/grpc-js"));
// Import grpc only if there is service statements
importStatements.push(
createImport(
grpcIdentifier,
configParams.grpc_package,
)
);
statements.push(
...rpc.createGrpcInterfaceType(fileDescriptor, grpcIdentifier, configParams)
);
// Create all services and clients
for (const serviceDescriptor of fileDescriptor.service) {
statements.push(
rpc.createUnimplementedServer(
fileDescriptor,
serviceDescriptor,
grpcIdentifier
)
);
statements.push(
rpc.createServiceClient(
fileDescriptor,
serviceDescriptor,
grpcIdentifier,
configParams,
)
);
}
}


const {major, minor, patch} = request.compiler_version || {major: 0, minor: 0, patch: 0};

const doNotEditComment = ts.factory.createJSDocComment(
Expand All @@ -89,7 +151,6 @@ for (const fileDescriptor of request.proto_file) {

// Wrap statements within the namespace
if (fileDescriptor.package) {

statements = [
doNotEditComment,
...importStatements,
Expand Down Expand Up @@ -127,4 +188,4 @@ for (const fileDescriptor of request.proto_file) {
type.resetDependencyMap();
}

process.stdout.write(response.serialize());
process.stdout.write(response.serialize());
Loading

0 comments on commit ce7dd99

Please sign in to comment.