diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index d2dac2f606f6..425761d122d4 100644 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -1950,19 +1950,189 @@ void Generator::GenerateTestOnly(const GeneratorOptions& options, printer->Print("\n"); } -void Generator::GenerateClassesAndEnums(const GeneratorOptions& options, - io::Printer* printer, - const FileDescriptor* file) const { - for (int i = 0; i < file->message_type_count(); i++) { - GenerateClassConstructorAndDeclareExtensionFieldInfo(options, printer, - file->message_type(i)); - } - for (int i = 0; i < file->message_type_count(); i++) { - GenerateClass(options, printer, file->message_type(i)); - } - for (int i = 0; i < file->enum_type_count(); i++) { - GenerateEnum(options, printer, file->enum_type(i)); - } +void Generator::GenerateClassesAndEnums(const GeneratorOptions& options, io::Printer* printer, const FileDescriptor* file) const +{ + if (options.import_style == = GeneratorOptions::ImportStyle::kImportTypescript) + { + for (int i = 0; i < file->message_type_count(); i++) + { + GenerateTypescriptClass(options, printer, file->message_type(i)); + } + } + else + { + for (int i = 0; i < file->message_type_count(); i++) { + GenerateClassConstructorAndDeclareExtensionFieldInfo(options, printer, file->message_type(i)); + } + + for (int i = 0; i < file->message_type_count(); i++) + { + GenerateClass(options, printer, file->message_type(i)); + } + + for (int i = 0; i < file->enum_type_count(); i++) + { + GenerateEnum(options, printer, file->enum_type(i)); + } + } + +} + +void Generator::GenerateTypescriptClass(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const +{ + if (IgnoreMessage(desc)) + { + return; + } + + // Only proto3 is supported for now + if (desc->file()->syntax() != FileDescriptor::SYNTAX_PROTO3) + { + return; + } + + + printer->Print( + "/**\n" + " * Generated by JsPbCodeGenerator.\n" + " */\n" + "export class $classname$ extends jspb.Message {\n", + + "classprefix", GetMessagePathPrefix(options, desc), + "classname", desc->name(), + ); + printer->Indent(); + + // TODO - Print fields and accessors + printer->Print( + "public static readonly displayname: string = '$displayName$';\n", + + "displayName", GetMessagePath(options, desc), + ); + + for (int i = 0; i < desc->field_count(); i++) { + if (IgnoreField(desc->field(i))) { + continue; + } + + FieldDescriptor* field = desc->field(i); + std::string identifier = JSIdent(options, field, false, false, false); + std::string index = JSFieldIndex(field); + std::string type = JSFieldTypeAnnotation(options, field, + /* is_setter_argument = */ false, + /* force_present = */ false, + /* singular_if_not_packed = */ false); + + GenerateClassField(options, printer, desc->field(i)); + + // Getter + { + printer->Print( + "get $name$(): $type$ {\n" + " return ", + + "name", identifier, + "type", type, + ); + printer->Annotate("gettername", field); + + GenerateFieldValueExpression(printer, "this", field, /* use_default = */ false); + + printer->Print("};\n\n"); + } + + // Setter + { + printer->Print( + "set $name$(value: $type$) {\n" + " jspb.Message.setField(this, $index$, value);" + "};\n\n", + + "name", identifier, + "index", index, + "type", type, + ); + printer->Annotate("settername", field); + + GenerateFieldValueExpression(printer, "this", field, /* use_default = */ false); + + printer->Print("};\n\n"); + + + printer->Print( + "$class$.prototype.$settername$ = function(value) {\n" + " return jspb.Message.setProto3$typetag$Field(this, $index$, " + "value);" + "\n" + "};\n" + "\n" + "\n", + "class", GetMessagePath(options, field->containing_type()), + "settername", "set" + JSGetterName(options, field), "typetag", + JSTypeTag(field), "index", JSFieldIndex(field)); + } + } + + // Print constructor + printer->Print("constructor(optionalData: Array) {\n"); + printer->Indent(); + printer->Outdent(); + printer->Print("}\n"); + + // Print Methods + // TODO - Print methods + + //Close class + printer->Outdent(); + printer->Print("}\n"); + + + + + + + + + + + + + + + if (!NamespaceOnly(desc)) + { + printer->Print("\n"); + GenerateClassFieldInfo(options, printer, desc); + + GenerateClassToObject(options, printer, desc); + // These must come *before* the extension-field info generation in + // GenerateClassRegistration so that references to the binary + // serialization/deserialization functions may be placed in the extension + // objects. + GenerateClassDeserializeBinary(options, printer, desc); + GenerateClassSerializeBinary(options, printer, desc); + } + + // Recurse on nested types. These must come *before* the extension-field + // info generation in GenerateClassRegistration so that extensions that + // reference nested types proceed the definitions of the nested types. + for (int i = 0; i < desc->enum_type_count(); i++) { + GenerateEnum(options, printer, desc->enum_type(i)); + } + for (int i = 0; i < desc->nested_type_count(); i++) { + GenerateClass(options, printer, desc->nested_type(i)); + } + + if (!NamespaceOnly(desc)) { + GenerateClassRegistration(options, printer, desc); + GenerateClassFields(options, printer, desc); + + if (options.import_style != GeneratorOptions::kImportClosure) { + for (int i = 0; i < desc->extension_count(); i++) { + GenerateExtension(options, printer, desc->extension(i)); + } + } + } } void Generator::GenerateClass(const GeneratorOptions& options, @@ -2038,7 +2208,8 @@ void Generator::GenerateClassConstructor(const GeneratorOptions& options, : (IsResponse(desc) ? "''" : "0"), "pivot", GetPivot(desc), "rptfields", RepeatedFieldsArrayName(options, desc), "oneoffields", - OneofFieldsArrayName(options, desc)); + OneofFieldsArrayName(options, desc) + ); printer->Print( "};\n" "goog.inherits($classname$, jspb.Message);\n" @@ -2051,7 +2222,8 @@ void Generator::GenerateClassConstructor(const GeneratorOptions& options, " */\n" " $classname$.displayName = '$classname$';\n" "}\n", - "classname", GetMessagePath(options, desc)); + "classname", GetMessagePath(options, desc) + ); } void Generator::GenerateClassConstructorAndDeclareExtensionFieldInfo( @@ -2600,6 +2772,8 @@ void Generator::GenerateClassField(const GeneratorOptions& options, // Message field: special handling in order to wrap the underlying data // array with a message object. + + // Print getter printer->Print( "/**\n" " * $fielddef$\n" @@ -2621,16 +2795,19 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "\n" "\n", "class", GetMessagePath(options, field->containing_type()), - "gettername", "get" + JSGetterName(options, field), "type", - JSFieldTypeAnnotation(options, field, + "gettername", "get" + JSGetterName(options, field), + "type", JSFieldTypeAnnotation(options, field, /* is_setter_argument = */ false, /* force_present = */ false, /* singular_if_not_packed = */ false), - "rpt", (field->is_repeated() ? "Repeated" : ""), "index", - JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field), - "required", - (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : "")); + "rpt", (field->is_repeated() ? "Repeated" : ""), + "index", JSFieldIndex(field), + "wrapperclass", SubmessageTypeRef(options, field), + "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? ", 1" : "") + ); printer->Annotate("gettername", field); + + // Print setter printer->Print( "/**\n" " * @param {$optionaltype$} value\n" @@ -2691,13 +2868,18 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "$comment$" " * @return {$type$}\n" " */\n", - "fielddef", FieldDefinition(options, field), "comment", - FieldComments(field, bytes_mode), "type", typed_annotation); + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field, bytes_mode), + "type", typed_annotation + ); } - printer->Print("$class$.prototype.$gettername$ = function() {\n", "class", - GetMessagePath(options, field->containing_type()), - "gettername", "get" + JSGetterName(options, field)); + printer->Print( + "$class$.prototype.$gettername$ = function() {\n", + + "class", GetMessagePath(options, field->containing_type()), + "gettername", "get" + JSGetterName(options, field) + ); printer->Annotate("gettername", field); if (untyped) { diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h index cd9631afb772..964fe351ee47 100644 --- a/src/google/protobuf/compiler/js/js_generator.h +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -73,6 +73,7 @@ struct GeneratorOptions { kImportCommonJsStrict, // require() with no global export kImportBrowser, // no import statements kImportEs6, // import { member } from '' + kImportTypescript, // import { member } from '' } import_style; GeneratorOptions() @@ -93,7 +94,11 @@ struct GeneratorOptions { // Returns the file name extension to use for generated code. std::string GetFileNameExtension() const { - return import_style == kImportClosure ? extension : "_pb.js"; + return import_style == kImportClosure + ? extension + : import_style == kImportTypescript + ? "_pb.ts" + : "_pb.js"; } enum OutputMode { @@ -247,6 +252,8 @@ class PROTOC_EXPORT Generator : public CodeGenerator { bool use_default) const; // Generate definition for one class. + void GenerateTypescriptClass(const GeneratorOptions& options, io::Printer* printer, + const Descriptor* desc) const; void GenerateClass(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const; void GenerateClassConstructor(const GeneratorOptions& options,