Skip to content

Commit

Permalink
feat: Add static-only variant to to outputTypeAnnotations option (#858)
Browse files Browse the repository at this point in the history
* Add const-only variant to to outputTypeAnnotations option

* Rename option to static-only

* Add integration test
* Add helper for adding type to message
  • Loading branch information
bouk committed Jul 4, 2023
1 parent 1f73bad commit d7c4af7
Show file tree
Hide file tree
Showing 13 changed files with 1,167 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ Generated code will be placed in the Gradle build directory.

- With `--ts_proto_opt=outputSchema=true`, meta typings will be generated that can later be used in other code generators.

- With `--ts_proto_opt=outputTypeAnnotations=true`, each message will be given a `$type` field containing its fully-qualified name.
- With `--ts_proto_opt=outputTypeAnnotations=true`, each message will be given a `$type` field containing its fully-qualified name. You can use `--ts_proto_opt=outputTypeAnnotations=static-only` to omit it from the `interface` declaration.

- With `--ts_proto_opt=outputTypeRegistry=true`, the type registry will be generated that can be used to resolve message types by fully-qualified name. Also, each message will be given a `$type` field containing its fully-qualified name.

Expand Down
Binary file added integration/static-only/bar/bar.bin
Binary file not shown.
9 changes: 9 additions & 0 deletions integration/static-only/bar/bar.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
syntax = "proto3";

package foo.bar;

import "foo.proto";

message Bar {
Foo foo = 1;
}
82 changes: 82 additions & 0 deletions integration/static-only/bar/bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { Foo } from "../foo";

export const protobufPackage = "foo.bar";

export interface Bar {
foo: Foo | undefined;
}

function createBaseBar(): Bar {
return { foo: undefined };
}

export const Bar = {
$type: "foo.bar.Bar" as const,

encode(message: Bar, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.foo !== undefined) {
Foo.encode(message.foo, writer.uint32(10).fork()).ldelim();
}
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): Bar {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseBar();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}

message.foo = Foo.decode(reader, reader.uint32());
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},

fromJSON(object: any): Bar {
return { foo: isSet(object.foo) ? Foo.fromJSON(object.foo) : undefined };
},

toJSON(message: Bar): unknown {
const obj: any = {};
message.foo !== undefined && (obj.foo = message.foo ? Foo.toJSON(message.foo) : undefined);
return obj;
},

create<I extends Exact<DeepPartial<Bar>, I>>(base?: I): Bar {
return Bar.fromPartial(base ?? {});
},

fromPartial<I extends Exact<DeepPartial<Bar>, I>>(object: I): Bar {
const message = createBaseBar();
message.foo = (object.foo !== undefined && object.foo !== null) ? Foo.fromPartial(object.foo) : undefined;
return message;
},
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
Binary file added integration/static-only/foo.bin
Binary file not shown.
18 changes: 18 additions & 0 deletions integration/static-only/foo.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";

package foo;

import "google/protobuf/timestamp.proto";
import "google/protobuf/struct.proto";

message Foo {
google.protobuf.Timestamp timestamp = 1;
}

message Foo2 {
google.protobuf.Timestamp timestamp = 1;
}

message WithStruct {
google.protobuf.Struct struct = 1;
}
233 changes: 233 additions & 0 deletions integration/static-only/foo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { Struct } from "./google/protobuf/struct";
import { Timestamp } from "./google/protobuf/timestamp";

export const protobufPackage = "foo";

export interface Foo {
timestamp: Date | undefined;
}

export interface Foo2 {
timestamp: Date | undefined;
}

export interface WithStruct {
struct: { [key: string]: any } | undefined;
}

function createBaseFoo(): Foo {
return { timestamp: undefined };
}

export const Foo = {
$type: "foo.Foo" as const,

encode(message: Foo, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.timestamp !== undefined) {
Timestamp.encode(toTimestamp(message.timestamp), writer.uint32(10).fork()).ldelim();
}
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): Foo {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseFoo();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}

message.timestamp = fromTimestamp(Timestamp.decode(reader, reader.uint32()));
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},

fromJSON(object: any): Foo {
return { timestamp: isSet(object.timestamp) ? fromJsonTimestamp(object.timestamp) : undefined };
},

toJSON(message: Foo): unknown {
const obj: any = {};
message.timestamp !== undefined && (obj.timestamp = message.timestamp.toISOString());
return obj;
},

create<I extends Exact<DeepPartial<Foo>, I>>(base?: I): Foo {
return Foo.fromPartial(base ?? {});
},

fromPartial<I extends Exact<DeepPartial<Foo>, I>>(object: I): Foo {
const message = createBaseFoo();
message.timestamp = object.timestamp ?? undefined;
return message;
},
};

function createBaseFoo2(): Foo2 {
return { timestamp: undefined };
}

export const Foo2 = {
$type: "foo.Foo2" as const,

encode(message: Foo2, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.timestamp !== undefined) {
Timestamp.encode(toTimestamp(message.timestamp), writer.uint32(10).fork()).ldelim();
}
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): Foo2 {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseFoo2();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}

message.timestamp = fromTimestamp(Timestamp.decode(reader, reader.uint32()));
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},

fromJSON(object: any): Foo2 {
return { timestamp: isSet(object.timestamp) ? fromJsonTimestamp(object.timestamp) : undefined };
},

toJSON(message: Foo2): unknown {
const obj: any = {};
message.timestamp !== undefined && (obj.timestamp = message.timestamp.toISOString());
return obj;
},

create<I extends Exact<DeepPartial<Foo2>, I>>(base?: I): Foo2 {
return Foo2.fromPartial(base ?? {});
},

fromPartial<I extends Exact<DeepPartial<Foo2>, I>>(object: I): Foo2 {
const message = createBaseFoo2();
message.timestamp = object.timestamp ?? undefined;
return message;
},
};

function createBaseWithStruct(): WithStruct {
return { struct: undefined };
}

export const WithStruct = {
$type: "foo.WithStruct" as const,

encode(message: WithStruct, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.struct !== undefined) {
Struct.encode(Struct.wrap(message.struct), writer.uint32(10).fork()).ldelim();
}
return writer;
},

decode(input: _m0.Reader | Uint8Array, length?: number): WithStruct {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseWithStruct();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}

message.struct = Struct.unwrap(Struct.decode(reader, reader.uint32()));
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},

fromJSON(object: any): WithStruct {
return { struct: isObject(object.struct) ? object.struct : undefined };
},

toJSON(message: WithStruct): unknown {
const obj: any = {};
message.struct !== undefined && (obj.struct = message.struct);
return obj;
},

create<I extends Exact<DeepPartial<WithStruct>, I>>(base?: I): WithStruct {
return WithStruct.fromPartial(base ?? {});
},

fromPartial<I extends Exact<DeepPartial<WithStruct>, I>>(object: I): WithStruct {
const message = createBaseWithStruct();
message.struct = object.struct ?? undefined;
return message;
},
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function toTimestamp(date: Date): Timestamp {
const seconds = date.getTime() / 1_000;
const nanos = (date.getTime() % 1_000) * 1_000_000;
return { seconds, nanos };
}

function fromTimestamp(t: Timestamp): Date {
let millis = (t.seconds || 0) * 1_000;
millis += (t.nanos || 0) / 1_000_000;
return new Date(millis);
}

function fromJsonTimestamp(o: any): Date {
if (o instanceof Date) {
return o;
} else if (typeof o === "string") {
return new Date(o);
} else {
return fromTimestamp(Timestamp.fromJSON(o));
}
}

function isObject(value: any): boolean {
return typeof value === "object" && value !== null;
}

function isSet(value: any): boolean {
return value !== null && value !== undefined;
}

0 comments on commit d7c4af7

Please sign in to comment.