From 81dc93ef7ac6de8ab01806a3c7cffdd0b94af54b Mon Sep 17 00:00:00 2001 From: Zbigniew Mandziejewicz Date: Sun, 3 Feb 2019 18:54:31 +0100 Subject: [PATCH 1/4] fix: exclude map entry message from typings, fix optional values --- javascript/net/grpc/web/grpc_generator.cc | 54 ++++++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/javascript/net/grpc/web/grpc_generator.cc b/javascript/net/grpc/web/grpc_generator.cc index 024e47a4..5e3d2053 100644 --- a/javascript/net/grpc/web/grpc_generator.cc +++ b/javascript/net/grpc/web/grpc_generator.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -274,11 +275,30 @@ string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) } if (desc->is_repeated()) { - js_field_type += "[]"; + js_field_type = "Array<" + js_field_type + ">"; } return js_field_type; } +string AsObjectFieldType(const FieldDescriptor *desc, const FileDescriptor *file) { + if (desc->type() != FieldDescriptor::TYPE_MESSAGE) { + return JSFieldType(desc, file); + }; + + if (desc->is_map()) { + const Descriptor* message = desc->message_type(); + string key_type = AsObjectFieldType(message->field(0), file); + string value_type = AsObjectFieldType(message->field(1), file); + return "Array<[" + key_type + ", " + value_type + "]>"; + }; + + string field_type = JSMessageType(desc->message_type(), file) + ".AsObject"; + if (desc->is_repeated()) { + field_type = "Array<" + field_type + ">"; + } + return field_type; +} + string JSFieldName(const FieldDescriptor *desc) { string js_field_name = ToUpperCamel(ParseLowerUnderscore(desc->name())); @@ -698,24 +718,37 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, const FieldDescriptor* field = desc->field(i); vars["js_field_name"] = JSFieldName(field); vars["js_field_type"] = JSFieldType(field, file); - if (field->type() != FieldDescriptor::TYPE_MESSAGE) { + if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { printer->Print(vars, "get$js_field_name$(): $js_field_type$;\n"); } else { printer->Print(vars, "get$js_field_name$(): $js_field_type$ | undefined;\n"); } - if (field->type() != FieldDescriptor::TYPE_MESSAGE) { + if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { printer->Print(vars, "set$js_field_name$(value: $js_field_type$): void;\n"); } else if (!field->is_map()) { printer->Print(vars, "set$js_field_name$(value?: $js_field_type$): void;\n"); } + if (field->is_repeated() && !field->is_map()) { + printer->Print(vars, "clear$js_field_name$(): void;\n"); + vars["js_field_name"] = JSElementName(field); + vars["js_field_type"] = JSElementType(field, file); + if (field->type() != FieldDescriptor::TYPE_MESSAGE) { + printer->Print(vars, + "add$js_field_name$(value: $js_field_type$, index?: number);\n"); + } else { + printer->Print(vars, + "add$js_field_name$(value?: $js_field_type$, index?: number): $js_field_type$;\n"); + } + } if (field->type() == FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { printer->Print(vars, "clear$js_field_name$(): void;\n"); } + printer->Print("\n"); } printer->Print( vars, @@ -739,16 +772,10 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, for (int i = 0; i < desc->field_count(); i++) { const FieldDescriptor* field = desc->field(i); vars["js_field_name"] = CamelCaseJSFieldName(field); - if (field->type() != FieldDescriptor::TYPE_MESSAGE) { - vars["js_field_type"] = JSFieldType(field, file); - printer->Print(vars, "$js_field_name$: $js_field_type$;\n"); + vars["js_field_type"] = AsObjectFieldType(field, file); + if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { + printer->Print(vars, "$js_field_name$: $js_field_type$,\n"); } else { - string js_field_type = JSMessageType(field->message_type(), file) + - ".AsObject"; - if (field->is_repeated()) { - js_field_type += "[]"; - } - vars["js_field_type"] = js_field_type; printer->Print(vars, "$js_field_name$?: $js_field_type$;\n"); } } @@ -756,6 +783,9 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, printer->Print("}\n"); for (int i = 0; i < desc->nested_type_count(); i++) { + if (desc->options().map_entry()) { + continue; + } printer->Print("\n"); PrintProtoDtsMessage(printer, desc->nested_type(i), file); } From 4a8c5bd712be7cf6091bd4953ae50a2b32ebd2db Mon Sep 17 00:00:00 2001 From: Zbigniew Mandziejewicz Date: Sun, 3 Feb 2019 19:33:04 +0100 Subject: [PATCH 2/4] fix: support jstype option, fix skipping map entry --- javascript/net/grpc/web/grpc_generator.cc | 25 ++++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/javascript/net/grpc/web/grpc_generator.cc b/javascript/net/grpc/web/grpc_generator.cc index 5e3d2053..76f0a6fb 100644 --- a/javascript/net/grpc/web/grpc_generator.cc +++ b/javascript/net/grpc/web/grpc_generator.cc @@ -31,6 +31,7 @@ using google::protobuf::FieldDescriptor; using google::protobuf::FileDescriptor; using google::protobuf::MethodDescriptor; using google::protobuf::ServiceDescriptor; +using google::protobuf::FieldOptions; using google::protobuf::compiler::CodeGenerator; using google::protobuf::compiler::GeneratorContext; using google::protobuf::compiler::ParseGeneratorParameter; @@ -238,15 +239,21 @@ string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) case FieldDescriptor::TYPE_FLOAT: case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + js_field_type = "number"; + break; case FieldDescriptor::TYPE_INT64: case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SINT32: case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FIXED64: case FieldDescriptor::TYPE_SFIXED64: - js_field_type = "number"; + if (desc->options().jstype() == FieldOptions::JS_STRING) { + js_field_type = "string"; + } else { + js_field_type = "number"; + }; break; case FieldDescriptor::TYPE_BOOL: js_field_type = "boolean"; @@ -284,18 +291,16 @@ string AsObjectFieldType(const FieldDescriptor *desc, const FileDescriptor *file if (desc->type() != FieldDescriptor::TYPE_MESSAGE) { return JSFieldType(desc, file); }; - if (desc->is_map()) { const Descriptor* message = desc->message_type(); string key_type = AsObjectFieldType(message->field(0), file); string value_type = AsObjectFieldType(message->field(1), file); return "Array<[" + key_type + ", " + value_type + "]>"; }; - string field_type = JSMessageType(desc->message_type(), file) + ".AsObject"; if (desc->is_repeated()) { - field_type = "Array<" + field_type + ">"; - } + return "Array<" + field_type + ">"; + }; return field_type; } @@ -783,7 +788,7 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, printer->Print("}\n"); for (int i = 0; i < desc->nested_type_count(); i++) { - if (desc->options().map_entry()) { + if (desc->nested_type(i)->options().map_entry()) { continue; } printer->Print("\n"); From 54e09aac6454166a7cdbc58cf4ed19ae4ed6acd3 Mon Sep 17 00:00:00 2001 From: Zbigniew Mandziejewicz Date: Sun, 3 Feb 2019 20:57:00 +0100 Subject: [PATCH 3/4] refactor: add methods for element type/name --- javascript/net/grpc/web/grpc_generator.cc | 64 +++++++++++++---------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/javascript/net/grpc/web/grpc_generator.cc b/javascript/net/grpc/web/grpc_generator.cc index 76f0a6fb..b858c5ba 100644 --- a/javascript/net/grpc/web/grpc_generator.cc +++ b/javascript/net/grpc/web/grpc_generator.cc @@ -218,19 +218,18 @@ string ModuleAlias(const string& filename) { } string JSMessageType(const Descriptor *desc, const FileDescriptor *file) { - string result; - if (desc->file() != file) { - result = ModuleAlias(desc->file()->name()); - } - result += StripPrefixString(desc->full_name(), desc->file()->package()); - if (!result.empty() && result[0] == '.') { - result = result.substr(1); - } - - return result; + string result; + if (desc->file() != file) { + result = ModuleAlias(desc->file()->name()); + } + result += StripPrefixString(desc->full_name(), desc->file()->package()); + if (!result.empty() && result[0] == '.') { + result = result.substr(1); + } + return result; } -string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) +string JSElementType(const FieldDescriptor *desc, const FileDescriptor *file) { string js_field_type; switch (desc->type()) @@ -269,20 +268,25 @@ string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) } break; case FieldDescriptor::TYPE_MESSAGE: - if (desc->is_map()) { - string key_type = JSFieldType(desc->message_type()->field(0), file); - string value_type = JSFieldType(desc->message_type()->field(1), file); - return "jspb.Map<" + key_type + ", " + value_type + ">"; - } js_field_type = JSMessageType(desc->message_type(), file); break; default: js_field_type = "{}"; break; } + return js_field_type; +} + +string JSFieldType(const FieldDescriptor *desc, const FileDescriptor *file) { + string js_field_type = JSElementType(desc, file); + if (desc->is_map()) { + string key_type = JSFieldType(desc->message_type()->field(0), file); + string value_type = JSFieldType(desc->message_type()->field(1), file); + return "jspb.Map<" + key_type + ", " + value_type + ">"; + } if (desc->is_repeated()) { - js_field_type = "Array<" + js_field_type + ">"; + return "Array<" + js_field_type + ">"; } return js_field_type; } @@ -304,9 +308,12 @@ string AsObjectFieldType(const FieldDescriptor *desc, const FileDescriptor *file return field_type; } -string JSFieldName(const FieldDescriptor *desc) -{ - string js_field_name = ToUpperCamel(ParseLowerUnderscore(desc->name())); +string JSElementName(const FieldDescriptor *desc) { + return ToUpperCamel(ParseLowerUnderscore(desc->name())); +} + +string JSFieldName(const FieldDescriptor *desc) { + string js_field_name = JSElementName(desc); if (desc->is_map()) { js_field_name += "Map"; } else if (desc->is_repeated()) { @@ -718,7 +725,6 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, printer->Print(vars, "export class $class_name$ extends jspb.Message {\n"); printer->Indent(); - printer->Print("constructor ();\n"); for (int i = 0; i < desc->field_count(); i++) { const FieldDescriptor* field = desc->field(i); vars["js_field_name"] = JSFieldName(field); @@ -730,15 +736,20 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, printer->Print(vars, "get$js_field_name$(): $js_field_type$ | undefined;\n"); } - if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { + if (!field->is_map() && (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated())) { printer->Print(vars, "set$js_field_name$(value: $js_field_type$): void;\n"); } else if (!field->is_map()) { printer->Print(vars, "set$js_field_name$(value?: $js_field_type$): void;\n"); } - if (field->is_repeated() && !field->is_map()) { + if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_repeated() && !field->is_map()) { + printer->Print(vars, "has$js_field_name$(): boolean;\n"); + } + if (field->type() == FieldDescriptor::TYPE_MESSAGE || field->is_repeated() || field->is_map()) { printer->Print(vars, "clear$js_field_name$(): void;\n"); + } + if (field->is_repeated() && !field->is_map()) { vars["js_field_name"] = JSElementName(field); vars["js_field_type"] = JSElementType(field, file); if (field->type() != FieldDescriptor::TYPE_MESSAGE) { @@ -749,10 +760,7 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, "add$js_field_name$(value?: $js_field_type$, index?: number): $js_field_type$;\n"); } } - if (field->type() == FieldDescriptor::TYPE_MESSAGE || - field->is_repeated()) { - printer->Print(vars, "clear$js_field_name$(): void;\n"); - } + printer->Print("\n"); } printer->Print( @@ -781,7 +789,7 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { printer->Print(vars, "$js_field_name$: $js_field_type$,\n"); } else { - printer->Print(vars, "$js_field_name$?: $js_field_type$;\n"); + printer->Print(vars, "$js_field_name$?: $js_field_type$,\n"); } } printer->Outdent(); From ae53a4e2c2ef185ebcae76a57dd1cdf235e9c5b7 Mon Sep 17 00:00:00 2001 From: Zbigniew Mandziejewicz Date: Sun, 3 Feb 2019 21:22:52 +0100 Subject: [PATCH 4/4] fix: Prefix reserved fields in AsObject --- javascript/net/grpc/web/grpc_generator.cc | 76 ++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/javascript/net/grpc/web/grpc_generator.cc b/javascript/net/grpc/web/grpc_generator.cc index b858c5ba..d4c992c0 100644 --- a/javascript/net/grpc/web/grpc_generator.cc +++ b/javascript/net/grpc/web/grpc_generator.cc @@ -59,6 +59,76 @@ enum ImportStyle { TYPESCRIPT = 2, // import * as grpcWeb from 'grpc-web' }; +const char* kKeyword[] = { + "abstract", + "boolean", + "break", + "byte", + "case", + "catch", + "char", + "class", + "const", + "continue", + "debugger", + "default", + "delete", + "do", + "double", + "else", + "enum", + "export", + "extends", + "false", + "final", + "finally", + "float", + "for", + "function", + "goto", + "if", + "implements", + "import", + "in", + "instanceof", + "int", + "interface", + "long", + "native", + "new", + "null", + "package", + "private", + "protected", + "public", + "return", + "short", + "static", + "super", + "switch", + "synchronized", + "this", + "throw", + "throws", + "transient", + "try", + "typeof", + "var", + "void", + "volatile", + "while", + "with", +}; + +bool IsReserved(const string& ident) { + for (int i = 0; i < sizeof(kKeyword) / sizeof(kKeyword[0]); i++) { + if (ident == kKeyword[i]) { + return true; + } + } + return false; +} + string GetModeVar(const Mode mode) { switch (mode) { case OP: @@ -784,7 +854,11 @@ void PrintProtoDtsMessage(Printer *printer, const Descriptor *desc, printer->Indent(); for (int i = 0; i < desc->field_count(); i++) { const FieldDescriptor* field = desc->field(i); - vars["js_field_name"] = CamelCaseJSFieldName(field); + string js_field_name = CamelCaseJSFieldName(field); + if (IsReserved(js_field_name)) { + js_field_name = "pb_" + js_field_name; + } + vars["js_field_name"] = js_field_name; vars["js_field_type"] = AsObjectFieldType(field, file); if (field->type() != FieldDescriptor::TYPE_MESSAGE || field->is_repeated()) { printer->Print(vars, "$js_field_name$: $js_field_type$,\n");