diff options
Diffstat (limited to 'src/google/protobuf/compiler/js/js_generator.cc')
-rw-r--r--[-rwxr-xr-x] | src/google/protobuf/compiler/js/js_generator.cc | 203 |
1 files changed, 114 insertions, 89 deletions
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index b5771f26..5779d5e2 100755..100644 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -42,12 +42,12 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> +#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/compiler/js/well_known_types_embed.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/stubs/strutil.h> namespace google { @@ -220,8 +220,8 @@ string GetNestedMessageName(const Descriptor* descriptor) { if (descriptor == NULL) { return ""; } - string result = - StripPrefixString(descriptor->full_name(), descriptor->file()->package()); + string result = StripPrefixString(descriptor->full_name(), + descriptor->file()->package()); // Add a leading dot if one is not already present. if (!result.empty() && result[0] != '.') { result = "." + result; @@ -276,7 +276,8 @@ string GetEnumPath(const GeneratorOptions& options, string MaybeCrossFileRef(const GeneratorOptions& options, const FileDescriptor* from_file, const Descriptor* to_message) { - if (options.import_style == GeneratorOptions::kImportCommonJs && + if ((options.import_style == GeneratorOptions::kImportCommonJs || + options.import_style == GeneratorOptions::kImportCommonJsStrict) && from_file != to_message->file()) { // Cross-file ref in CommonJS needs to use the module alias instead of // the global name. @@ -438,9 +439,10 @@ string GetMessageId(const Descriptor* desc) { bool IgnoreExtensionField(const FieldDescriptor* field) { // Exclude descriptor extensions from output "to avoid clutter" (from original // codegen). - return field->is_extension() && - field->containing_type()->file()->name() == - "google/protobuf/descriptor.proto"; + if (!field->is_extension()) return false; + const FileDescriptor* file = field->containing_type()->file(); + return file->name() == "net/proto2/proto/descriptor.proto" || + file->name() == "google/protobuf/descriptor.proto"; } @@ -452,19 +454,9 @@ bool IgnoreField(const FieldDescriptor* field) { } -// Used inside Google only -- do not remove. -bool ShouldTreatMapsAsRepeatedFields(const FileDescriptor& descriptor) { - return false; -} - // Do we ignore this message type? -bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) { - return d->options().map_entry() && - !ShouldTreatMapsAsRepeatedFields(*d->file()); -} - -bool IsMap(const GeneratorOptions& options, const FieldDescriptor* field) { - return field->is_map() && !ShouldTreatMapsAsRepeatedFields(*field->file()); +bool IgnoreMessage(const Descriptor* d) { + return d->options().map_entry(); } // Does JSPB ignore this entire oneof? True only if all fields are ignored. @@ -489,7 +481,7 @@ string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field, ToUpperCamel(ParseLowerUnderscore(field->name())) : ToLowerCamel(ParseLowerUnderscore(field->name())); } - if (is_map || IsMap(options, field)) { + if (is_map || field->is_map()) { // JSPB-style or proto3-style map. result += "Map"; } else if (!drop_list && field->is_repeated()) { @@ -568,7 +560,8 @@ string JSFieldIndex(const FieldDescriptor* field) { for (int i = 0; i < parent_type->field_count(); i++) { if (parent_type->field(i)->type() == FieldDescriptor::TYPE_GROUP && parent_type->field(i)->message_type() == containing_type) { - return SimpleItoa(field->number() - parent_type->field(i)->number()); + return SimpleItoa(field->number() - + parent_type->field(i)->number()); } } } @@ -780,7 +773,7 @@ bool IsIntegralFieldWithStringJSType(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_UINT64: // The default value of JSType is JS_NORMAL, which behaves the same as // JS_NUMBER. - return field->options().jstype() == google::protobuf::FieldOptions::JS_STRING; + return field->options().jstype() == FieldOptions::JS_STRING; default: return false; } @@ -803,15 +796,15 @@ string JSFieldDefault(const FieldDescriptor* field) { // The original codegen is in Java, and Java protobufs store unsigned // integer values as signed integer values. In order to exactly match the // output, we need to reinterpret as base-2 signed. Ugh. - return MaybeNumberString( - field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); + return MaybeNumberString(field, SimpleItoa(static_cast<int32>( + field->default_value_uint32()))); case FieldDescriptor::CPPTYPE_INT64: return MaybeNumberString( field, SimpleItoa(field->default_value_int64())); case FieldDescriptor::CPPTYPE_UINT64: // See above note for uint32 -- reinterpreting as signed. - return MaybeNumberString( - field, SimpleItoa(static_cast<int64>(field->default_value_uint64()))); + return MaybeNumberString(field, SimpleItoa(static_cast<int64>( + field->default_value_uint64()))); case FieldDescriptor::CPPTYPE_ENUM: return SimpleItoa(field->default_value_enum()->number()); case FieldDescriptor::CPPTYPE_BOOL: @@ -1013,11 +1006,11 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options, bool is_setter_argument, bool force_present, bool singular_if_not_packed, - BytesMode bytes_mode = BYTES_DEFAULT) { - GOOGLE_CHECK(!(is_setter_argument && force_present)); + BytesMode bytes_mode = BYTES_DEFAULT, + bool force_singular = false) { string jstype = JSTypeName(options, field, bytes_mode); - if (field->is_repeated() && + if (!force_singular && field->is_repeated() && (field->is_packed() || !singular_if_not_packed)) { if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_DEFAULT) { @@ -1135,7 +1128,7 @@ string JSReturnDoc(const GeneratorOptions& options, bool HasRepeatedFields(const GeneratorOptions& options, const Descriptor* desc) { for (int i = 0; i < desc->field_count(); i++) { - if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { + if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { return true; } } @@ -1173,7 +1166,7 @@ string RepeatedFieldNumberList(const GeneratorOptions& options, const Descriptor* desc) { std::vector<string> numbers; for (int i = 0; i < desc->field_count(); i++) { - if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { + if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) { numbers.push_back(JSFieldIndex(desc->field(i))); } } @@ -1259,7 +1252,7 @@ const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) { string FieldDefinition(const GeneratorOptions& options, const FieldDescriptor* field) { - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); string key_type = ProtoTypeName(options, key_field); @@ -1351,7 +1344,7 @@ bool HasExtensions(const FileDescriptor* file) { bool HasMap(const GeneratorOptions& options, const Descriptor* desc) { for (int i = 0; i < desc->field_count(); i++) { - if (IsMap(options, desc->field(i))) { + if (desc->field(i)->is_map()) { return true; } } @@ -1617,7 +1610,7 @@ void Generator::FindProvidesForMessage( io::Printer* printer, const Descriptor* desc, std::set<string>* provided) const { - if (IgnoreMessage(options, desc)) { + if (IgnoreMessage(desc)) { return; } @@ -1675,8 +1668,19 @@ void Generator::GenerateProvides(const GeneratorOptions& options, // // // Later generated code expects foo.bar = {} to exist: // foo.bar.Baz = function() { /* ... */ } - printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", - *it); + + // Do not use global scope in strict mode + if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + string namespaceObject = *it; + // Remove "proto." from the namespace object + GOOGLE_CHECK_EQ(0, namespaceObject.compare(0, 6, "proto.")); + namespaceObject.erase(0, 6); + printer->Print("goog.exportSymbol('$name$', null, proto);\n", "name", + namespaceObject); + } else { + printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", + *it); + } } } } @@ -1712,7 +1716,7 @@ void Generator::GenerateRequiresForLibrary( for (int i = 0; i < files.size(); i++) { for (int j = 0; j < files[i]->message_type_count(); j++) { const Descriptor* desc = files[i]->message_type(j); - if (!IgnoreMessage(options, desc)) { + if (!IgnoreMessage(desc)) { FindRequiresForMessage(options, desc, &required, &forwards, &have_message); } @@ -1857,7 +1861,7 @@ void Generator::FindRequiresForField(const GeneratorOptions& options, forwards->insert(GetEnumPath(options, field->enum_type())); } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (!IgnoreMessage(options, field->message_type())) { + if (!IgnoreMessage(field->message_type())) { required->insert(GetMessagePath(options, field->message_type())); } } @@ -1895,7 +1899,7 @@ void Generator::GenerateClassesAndEnums(const GeneratorOptions& options, void Generator::GenerateClass(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc) const { - if (IgnoreMessage(options, desc)) { + if (IgnoreMessage(desc)) { return; } @@ -2217,7 +2221,7 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, printer->Print("$fieldname$: ", "fieldname", JSObjectFieldName(options, field)); - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* value_field = MapFieldValue(field); // If the map values are of a message type, we must provide their static // toObject() method; otherwise we pass undefined for that argument. @@ -2285,7 +2289,7 @@ void Generator::GenerateClassFromObject(const GeneratorOptions& options, " * @return {!$classname$}\n" " */\n" "$classname$.fromObject = function(obj) {\n" - " var f, msg = new $classname$();\n", + " var msg = new $classname$();\n", "classname", GetMessagePath(options, desc)); for (int i = 0; i < desc->field_count(); i++) { @@ -2303,7 +2307,7 @@ void Generator::GenerateClassFieldFromObject( const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* value_field = MapFieldValue(field); if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { // Since the map values are of message type, we have to do some extra work @@ -2415,7 +2419,7 @@ void GenerateBytesWrapper(const GeneratorOptions& options, void Generator::GenerateClassField(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); // Map field: special handling to instantiate the map object on demand. @@ -2695,7 +2699,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, // Generate clearFoo() method for map fields, repeated fields, and other // fields with presence. - if (IsMap(options, field)) { + if (field->is_map()) { printer->Print( "$class$.prototype.$clearername$ = function() {\n" " this.$gettername$().clear();$returnvalue$\n" @@ -2750,7 +2754,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, printer->Print( "/**\n" " * Returns whether this field is set.\n" - " * @return {!boolean}\n" + " * @return {boolean}\n" " */\n" "$class$.prototype.$hasername$ = function() {\n" " return jspb.Message.getField(this, $index$) != null;\n" @@ -2770,7 +2774,7 @@ void Generator::GenerateRepeatedPrimitiveHelperMethods( // clang-format off printer->Print( "/**\n" - " * @param {!$optionaltype$} value\n" + " * @param {$optionaltype$} value\n" " * @param {number=} opt_index$returndoc$\n" " */\n" "$class$.prototype.$addername$ = function(value, opt_index) {\n" @@ -2778,7 +2782,14 @@ void Generator::GenerateRepeatedPrimitiveHelperMethods( "class", GetMessagePath(options, field->containing_type()), "addername", "add" + JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true), - "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), + "optionaltype", + JSFieldTypeAnnotation( + options, field, + /* is_setter_argument = */ false, + /* force_present = */ true, + /* singular_if_not_packed = */ false, + BYTES_DEFAULT, + /* force_singular = */ true), "index", JSFieldIndex(field), "returndoc", JSReturnDoc(options, field)); printer->Annotate("addername", field); @@ -2942,11 +2953,10 @@ void Generator::GenerateClassDeserializeBinaryField( const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { + printer->Print(" case $num$:\n", "num", + SimpleItoa(field->number())); - printer->Print(" case $num$:\n", - "num", SimpleItoa(field->number())); - - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); printer->Print( @@ -2976,11 +2986,12 @@ void Generator::GenerateClassDeserializeBinaryField( " var value = new $fieldclass$;\n" " reader.read$msgOrGroup$($grpfield$value," "$fieldclass$.deserializeBinaryFromReader);\n", - "fieldclass", SubmessageTypeRef(options, field), - "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? - "Group" : "Message", - "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? - (SimpleItoa(field->number()) + ", ") : ""); + "fieldclass", SubmessageTypeRef(options, field), "msgOrGroup", + (field->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message", + "grpfield", + (field->type() == FieldDescriptor::TYPE_GROUP) + ? (SimpleItoa(field->number()) + ", ") + : ""); } else { printer->Print( " var value = /** @type {$fieldtype$} */ " @@ -3078,12 +3089,12 @@ void Generator::GenerateClassSerializeBinaryField( " f = message.get$name$($nolazy$);\n", "name", JSGetterName(options, field, BYTES_U8), // No lazy creation for maps containers -- fastpath the empty case. - "nolazy", IsMap(options, field) ? "true" : ""); + "nolazy", field->is_map() ? "true" : ""); } // Print an `if (condition)` statement that evaluates to true if the field // goes on the wire. - if (IsMap(options, field)) { + if (field->is_map()) { printer->Print( " if (f && f.getLength() > 0) {\n"); } else if (field->is_repeated()) { @@ -3136,15 +3147,15 @@ void Generator::GenerateClassSerializeBinaryField( } // Write the field on the wire. - if (IsMap(options, field)) { + if (field->is_map()) { const FieldDescriptor* key_field = MapFieldKey(field); const FieldDescriptor* value_field = MapFieldValue(field); printer->Print( " f.serializeBinary($index$, writer, " - "$keyWriterFn$, $valueWriterFn$", - "index", SimpleItoa(field->number()), - "keyWriterFn", JSBinaryWriterMethodName(options, key_field), - "valueWriterFn", JSBinaryWriterMethodName(options, value_field)); + "$keyWriterFn$, $valueWriterFn$", + "index", SimpleItoa(field->number()), "keyWriterFn", + JSBinaryWriterMethodName(options, key_field), "valueWriterFn", + JSBinaryWriterMethodName(options, value_field)); if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { printer->Print(", $messageType$.serializeBinaryToWriter", @@ -3161,7 +3172,7 @@ void Generator::GenerateClassSerializeBinaryField( "index", SimpleItoa(field->number())); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !IsMap(options, field)) { + !field->is_map()) { printer->Print( ",\n" " $submsg$.serializeBinaryToWriter\n", @@ -3193,11 +3204,10 @@ void Generator::GenerateEnum(const GeneratorOptions& options, for (int i = 0; i < enumdesc->value_count(); i++) { const EnumValueDescriptor* value = enumdesc->value(i); - printer->Print( - " $name$: $value$$comma$\n", - "name", ToEnumCase(value->name()), - "value", SimpleItoa(value->number()), - "comma", (i == enumdesc->value_count() - 1) ? "" : ","); + printer->Print(" $name$: $value$$comma$\n", "name", + ToEnumCase(value->name()), "value", + SimpleItoa(value->number()), "comma", + (i == enumdesc->value_count() - 1) ? "" : ","); printer->Annotate("name", value); } @@ -3240,13 +3250,15 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "!Object} */ (\n" " $toObject$),\n" " $repeated$);\n", - "index", SimpleItoa(field->number()), - "name", extension_object_name, - "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? - SubmessageTypeRef(options, field) : string("null")), - "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? - (SubmessageTypeRef(options, field) + ".toObject") : - string("null")), + "index", SimpleItoa(field->number()), "name", + extension_object_name, "ctor", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? SubmessageTypeRef(options, field) + : string("null")), + "toObject", + (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? (SubmessageTypeRef(options, field) + ".toObject") + : string("null")), "repeated", (field->is_repeated() ? "1" : "0")); printer->Print( @@ -3259,8 +3271,8 @@ void Generator::GenerateExtension(const GeneratorOptions& options, " $binaryMessageDeserializeFn$,\n", "extendName", JSExtensionsObjectName(options, field->file(), field->containing_type()), - "index", SimpleItoa(field->number()), "class", extension_scope, "name", - extension_object_name, "binaryReaderFn", + "index", SimpleItoa(field->number()), "class", extension_scope, + "name", extension_object_name, "binaryReaderFn", JSBinaryReaderMethodName(options, field), "binaryWriterFn", JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) @@ -3279,10 +3291,9 @@ void Generator::GenerateExtension(const GeneratorOptions& options, "// toObject() will function correctly.\n" "$extendName$[$index$] = $class$.$name$;\n" "\n", - "extendName", JSExtensionsObjectName(options, field->file(), - field->containing_type()), - "index", SimpleItoa(field->number()), - "class", extension_scope, + "extendName", + JSExtensionsObjectName(options, field->file(), field->containing_type()), + "index", SimpleItoa(field->number()), "class", extension_scope, "name", extension_object_name); } @@ -3325,6 +3336,8 @@ bool GeneratorOptions::ParseFromOptions( import_style = kImportClosure; } else if (options[i].second == "commonjs") { import_style = kImportCommonJs; + } else if (options[i].second == "commonjs_strict") { + import_style = kImportCommonJsStrict; } else if (options[i].second == "browser") { import_style = kImportBrowser; } else if (options[i].second == "es6") { @@ -3434,17 +3447,24 @@ void Generator::GenerateFile(const GeneratorOptions& options, GenerateHeader(options, printer); // Generate "require" statements. - if (options.import_style == GeneratorOptions::kImportCommonJs) { + if ((options.import_style == GeneratorOptions::kImportCommonJs || + options.import_style == GeneratorOptions::kImportCommonJsStrict)) { printer->Print("var jspb = require('google-protobuf');\n"); printer->Print("var goog = jspb;\n"); - printer->Print("var global = Function('return this')();\n\n"); + + // Do not use global scope in strict mode + if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + printer->Print("var proto = {};\n\n"); + } else { + printer->Print("var global = Function('return this')();\n\n"); + } for (int i = 0; i < file->dependency_count(); i++) { const string& name = file->dependency(i)->name(); printer->Print( - "var $alias$ = require('$file$');\n", - "alias", ModuleAlias(name), - "file", + "var $alias$ = require('$file$');\n" + "goog.object.extend(proto, $alias$);\n", + "alias", ModuleAlias(name), "file", GetRootPath(file->name(), name) + GetJSFilename(options, name)); } } @@ -3481,9 +3501,14 @@ void Generator::GenerateFile(const GeneratorOptions& options, GenerateExtension(options, printer, *it); } - if (options.import_style == GeneratorOptions::kImportCommonJs) { + // if provided is empty, do not export anything + if (options.import_style == GeneratorOptions::kImportCommonJs && + !provided.empty()) { printer->Print("goog.object.extend(exports, $package$);\n", "package", GetFilePath(options, file)); + } else if (options.import_style == GeneratorOptions::kImportCommonJsStrict) { + printer->Print("goog.object.extend(exports, proto);\n", "package", + GetFilePath(options, file)); } // Emit well-known type methods. @@ -3641,7 +3666,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files, // Generate one output file per input (.proto) file. for (int i = 0; i < files.size(); i++) { - const google::protobuf::FileDescriptor* file = files[i]; + const FileDescriptor* file = files[i]; string filename = options.output_dir + "/" + GetJSFilename(options, file->name()); |