Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Unified Diff: third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc

Issue 2600753002: Reverts third_party/protobuf: Update to HEAD (f52e188fe4) (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc
diff --git a/third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc b/third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc
index e6571f6fdfd3e538dca3749f4e63f96ad8a58667..a66d28efe58465ef941d0aefe484643b869acc33 100755
--- a/third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc
+++ b/third_party/protobuf/src/google/protobuf/compiler/js/js_generator.cc
@@ -45,7 +45,6 @@
#include <google/protobuf/stubs/logging.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringprintf.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>
@@ -152,24 +151,16 @@ string StripProto(const string& filename) {
return StripSuffixString(filename, suffix);
}
-// Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
+// Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
// file foo/bar/baz.js.
-string GetJSFilename(const GeneratorOptions& options, const string& filename) {
- return StripProto(filename) + options.GetFileNameExtension();
+string GetJSFilename(const string& filename) {
+ return StripProto(filename) + "_pb.js";
}
// Given a filename like foo/bar/baz.proto, returns the root directory
// path ../../
-string GetRootPath(const string& from_filename, const string& to_filename) {
- if (to_filename.find("google/protobuf") == 0) {
- // Well-known types (.proto files in the google/protobuf directory) are
- // assumed to come from the 'google-protobuf' npm package. We may want to
- // generalize this exception later by letting others put generated code in
- // their own npm packages.
- return "google-protobuf/";
- }
-
- size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/');
+string GetRootPath(const string& filename) {
+ size_t slashes = std::count(filename.begin(), filename.end(), '/');
if (slashes == 0) {
return "./";
}
@@ -209,33 +200,28 @@ string GetPath(const GeneratorOptions& options,
}
}
-// Returns the name of the message with a leading dot and taking into account
-// nesting, for example ".OuterMessage.InnerMessage", or returns empty if
-// descriptor is null. This function does not handle namespacing, only message
-// nesting.
-string GetNestedMessageName(const Descriptor* descriptor) {
- if (descriptor == NULL) {
- return "";
- }
- 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;
- }
- return result;
-}
+// Forward declare, so that GetPrefix can call this method,
+// which in turn, calls GetPrefix.
+string GetPath(const GeneratorOptions& options,
+ const Descriptor* descriptor);
// Returns the path prefix for a message or enumeration that
// lives under the given file and containing type.
string GetPrefix(const GeneratorOptions& options,
const FileDescriptor* file_descriptor,
const Descriptor* containing_type) {
- string prefix =
- GetPath(options, file_descriptor) + GetNestedMessageName(containing_type);
+ string prefix = "";
+
+ if (containing_type == NULL) {
+ prefix = GetPath(options, file_descriptor);
+ } else {
+ prefix = GetPath(options, containing_type);
+ }
+
if (!prefix.empty()) {
prefix += ".";
}
+
return prefix;
}
@@ -279,13 +265,11 @@ string GetPath(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::IMPORT_COMMONJS &&
from_file != to_message->file()) {
// Cross-file ref in CommonJS needs to use the module alias instead of
// the global name.
- return ModuleAlias(to_message->file()->name()) +
- GetNestedMessageName(to_message->containing_type()) + "." +
- to_message->name();
+ return ModuleAlias(to_message->file()->name()) + "." + to_message->name();
} else {
// Within a single file we use a full name.
return GetPath(options, to_message);
@@ -315,8 +299,8 @@ char ToLowerASCII(char c) {
}
}
-std::vector<string> ParseLowerUnderscore(const string& input) {
- std::vector<string> words;
+vector<string> ParseLowerUnderscore(const string& input) {
+ vector<string> words;
string running = "";
for (int i = 0; i < input.size(); i++) {
if (input[i] == '_') {
@@ -334,8 +318,8 @@ std::vector<string> ParseLowerUnderscore(const string& input) {
return words;
}
-std::vector<string> ParseUpperCamel(const string& input) {
- std::vector<string> words;
+vector<string> ParseUpperCamel(const string& input) {
+ vector<string> words;
string running = "";
for (int i = 0; i < input.size(); i++) {
if (input[i] >= 'A' && input[i] <= 'Z' && !running.empty()) {
@@ -350,7 +334,7 @@ std::vector<string> ParseUpperCamel(const string& input) {
return words;
}
-string ToLowerCamel(const std::vector<string>& words) {
+string ToLowerCamel(const vector<string>& words) {
string result;
for (int i = 0; i < words.size(); i++) {
string word = words[i];
@@ -364,7 +348,7 @@ string ToLowerCamel(const std::vector<string>& words) {
return result;
}
-string ToUpperCamel(const std::vector<string>& words) {
+string ToUpperCamel(const vector<string>& words) {
string result;
for (int i = 0; i < words.size(); i++) {
string word = words[i];
@@ -413,24 +397,21 @@ string ToFileName(const string& input) {
// that top-level extensions should go in.
string GetExtensionFileName(const GeneratorOptions& options,
const FileDescriptor* file) {
- return options.output_dir + "/" + ToFileName(GetPath(options, file)) +
- options.GetFileNameExtension();
+ return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js";
}
// When we're generating one output file per type name, this is the filename
// that a top-level message should go in.
string GetMessageFileName(const GeneratorOptions& options,
const Descriptor* desc) {
- return options.output_dir + "/" + ToFileName(desc->name()) +
- options.GetFileNameExtension();
+ return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
}
// When we're generating one output file per type name, this is the filename
// that a top-level message should go in.
string GetEnumFileName(const GeneratorOptions& options,
const EnumDescriptor* desc) {
- return options.output_dir + "/" + ToFileName(desc->name()) +
- options.GetFileNameExtension();
+ return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
}
// Returns the message/response ID, if set.
@@ -455,21 +436,6 @@ 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());
-}
-
// Does JSPB ignore this entire oneof? True only if all fields are ignored.
bool IgnoreOneof(const OneofDescriptor* oneof) {
for (int i = 0; i < oneof->field_count(); i++) {
@@ -480,8 +446,9 @@ bool IgnoreOneof(const OneofDescriptor* oneof) {
return true;
}
-string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field,
- bool is_upper_camel, bool is_map, bool drop_list) {
+string JSIdent(const FieldDescriptor* field,
+ bool is_upper_camel,
+ bool is_map) {
string result;
if (field->type() == FieldDescriptor::TYPE_GROUP) {
result = is_upper_camel ?
@@ -492,22 +459,19 @@ string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field,
ToUpperCamel(ParseLowerUnderscore(field->name())) :
ToLowerCamel(ParseLowerUnderscore(field->name()));
}
- if (is_map || IsMap(options, field)) {
- // JSPB-style or proto3-style map.
+ if (is_map) {
result += "Map";
- } else if (!drop_list && field->is_repeated()) {
- // Repeated field.
+ } else if (field->is_repeated()) {
result += "List";
}
return result;
}
-string JSObjectFieldName(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- string name = JSIdent(options, field,
- /* is_upper_camel = */ false,
- /* is_map = */ false,
- /* drop_list = */ false);
+string JSObjectFieldName(const FieldDescriptor* field) {
+ string name = JSIdent(
+ field,
+ /* is_upper_camel = */ false,
+ /* is_map = */ false);
if (IsReserved(name)) {
name = "pb_" + name;
}
@@ -525,18 +489,15 @@ string JSByteGetterSuffix(BytesMode bytes_mode) {
default:
assert(false);
}
- return "";
}
// Returns the field name as a capitalized portion of a getter/setter method
// name, e.g. MyField for .getMyField().
-string JSGetterName(const GeneratorOptions& options,
- const FieldDescriptor* field,
- BytesMode bytes_mode = BYTES_DEFAULT,
- bool drop_list = false) {
- string name = JSIdent(options, field,
+string JSGetterName(const FieldDescriptor* field,
+ BytesMode bytes_mode = BYTES_DEFAULT) {
+ string name = JSIdent(field,
/* is_upper_camel = */ true,
- /* is_map = */ false, drop_list);
+ /* is_map = */ false);
if (field->type() == FieldDescriptor::TYPE_BYTES) {
string suffix = JSByteGetterSuffix(bytes_mode);
if (!suffix.empty()) {
@@ -550,12 +511,10 @@ string JSGetterName(const GeneratorOptions& options,
return name;
}
-string JSMapGetterName(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- return JSIdent(options, field,
+string JSMapGetterName(const FieldDescriptor* field) {
+ return JSIdent(field,
/* is_upper_camel = */ true,
- /* is_map = */ true,
- /* drop_list = */ false);
+ /* is_map = */ true);
}
@@ -788,10 +747,7 @@ string MaybeNumberString(const FieldDescriptor* field, const string& orig) {
}
string JSFieldDefault(const FieldDescriptor* field) {
- if (field->is_repeated()) {
- return "[]";
- }
-
+ assert(field->has_default_value());
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_INT32:
return MaybeNumberString(
@@ -933,85 +889,20 @@ string JSTypeName(const GeneratorOptions& options,
}
}
-// Used inside Google only -- do not remove.
-bool UseBrokenPresenceSemantics(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- return false;
-}
-
-// Returns true for fields that return "null" from accessors when they are
-// unset. This should normally only be true for non-repeated submessages, but
-// we have legacy users who relied on old behavior where accessors behaved this
-// way.
-bool ReturnsNullWhenUnset(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- field->is_optional()) {
- return true;
- }
-
- // TODO(haberman): remove this case and unconditionally return false.
- return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() &&
- !field->has_default_value();
-}
-
-// In a sane world, this would be the same as ReturnsNullWhenUnset(). But in
-// the status quo, some fields declare that they never return null/undefined
-// even though they actually do:
-// * required fields
-// * optional enum fields
-// * proto3 primitive fields.
-bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) {
- return false;
- }
-
- if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
- field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
- return false;
- }
-
- return ReturnsNullWhenUnset(options, field);
-}
-
-bool SetterAcceptsUndefined(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- if (ReturnsNullWhenUnset(options, field)) {
- return true;
- }
-
- // Broken presence semantics always accepts undefined for setters.
- return UseBrokenPresenceSemantics(options, field);
-}
-
-bool SetterAcceptsNull(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- if (ReturnsNullWhenUnset(options, field)) {
- return true;
- }
-
- // With broken presence semantics, fields with defaults accept "null" for
- // setters, but other fields do not. This is a strange quirk of the old
- // codegen.
- return UseBrokenPresenceSemantics(options, field) &&
- field->has_default_value();
-}
-
-// Returns types which are known to by non-nullable by default.
-// The style guide requires that we omit "!" in this case.
-bool IsPrimitive(const string& type) {
- return type == "undefined" || type == "string" || type == "number" ||
- type == "boolean";
-}
+bool HasFieldPresence(const FieldDescriptor* field);
string JSFieldTypeAnnotation(const GeneratorOptions& options,
const FieldDescriptor* field,
- bool is_setter_argument,
+ bool force_optional,
bool force_present,
bool singular_if_not_packed,
BytesMode bytes_mode = BYTES_DEFAULT) {
- GOOGLE_CHECK(!(is_setter_argument && force_present));
+ bool is_primitive =
+ (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
+ field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
+ (field->type() != FieldDescriptor::TYPE_BYTES ||
+ bytes_mode == BYTES_B64));
+
string jstype = JSTypeName(options, field, bytes_mode);
if (field->is_repeated() &&
@@ -1020,35 +911,27 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options,
bytes_mode == BYTES_DEFAULT) {
jstype = "(Array<!Uint8Array>|Array<string>)";
} else {
- if (!IsPrimitive(jstype)) {
+ if (!is_primitive) {
jstype = "!" + jstype;
}
jstype = "Array.<" + jstype + ">";
}
- }
-
- bool is_null_or_undefined = false;
-
- if (is_setter_argument) {
- if (SetterAcceptsNull(options, field)) {
- jstype = "?" + jstype;
- is_null_or_undefined = true;
+ if (!force_optional) {
+ jstype = "!" + jstype;
}
+ }
- if (SetterAcceptsUndefined(options, field)) {
- jstype += "|undefined";
- is_null_or_undefined = true;
- }
- } else if (force_present) {
- // Don't add null or undefined.
- } else {
- if (DeclaredReturnTypeIsNullable(options, field)) {
- jstype = "?" + jstype;
- is_null_or_undefined = true;
- }
+ if (field->is_optional() && is_primitive &&
+ (!field->has_default_value() || force_optional) && !force_present) {
+ jstype += "?";
+ } else if (field->is_required() && !is_primitive && !force_optional) {
+ jstype = "!" + jstype;
}
- if (!is_null_or_undefined && !IsPrimitive(jstype)) {
+ if (force_optional && HasFieldPresence(field)) {
+ jstype += "|undefined";
+ }
+ if (force_present && jstype[0] != '!' && !is_primitive) {
jstype = "!" + jstype;
}
@@ -1075,16 +958,12 @@ string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
return name;
}
-string JSBinaryReaderMethodName(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- return "jspb.BinaryReader.prototype.read" +
- JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+string JSBinaryReaderMethodName(const FieldDescriptor* field) {
+ return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
}
-string JSBinaryWriterMethodName(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- return "jspb.BinaryWriter.prototype.write" +
- JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+string JSBinaryWriterMethodName(const FieldDescriptor* field) {
+ return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
}
string JSReturnClause(const FieldDescriptor* desc) {
@@ -1096,10 +975,9 @@ string JSReturnDoc(const GeneratorOptions& options,
return "";
}
-bool HasRepeatedFields(const GeneratorOptions& options,
- const Descriptor* desc) {
+bool HasRepeatedFields(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()) {
return true;
}
}
@@ -1110,9 +988,8 @@ static const char* kRepeatedFieldArrayName = ".repeatedFields_";
string RepeatedFieldsArrayName(const GeneratorOptions& options,
const Descriptor* desc) {
- return HasRepeatedFields(options, desc)
- ? (GetPath(options, desc) + kRepeatedFieldArrayName)
- : "null";
+ return HasRepeatedFields(desc) ?
+ (GetPath(options, desc) + kRepeatedFieldArrayName) : "null";
}
bool HasOneofFields(const Descriptor* desc) {
@@ -1132,11 +1009,10 @@ string OneofFieldsArrayName(const GeneratorOptions& options,
(GetPath(options, desc) + kOneofGroupArrayName) : "null";
}
-string RepeatedFieldNumberList(const GeneratorOptions& options,
- const Descriptor* desc) {
+string RepeatedFieldNumberList(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()) {
numbers.push_back(JSFieldIndex(desc->field(i)));
}
}
@@ -1200,65 +1076,34 @@ string JSExtensionsObjectName(const GeneratorOptions& options,
const FileDescriptor* from_file,
const Descriptor* desc) {
if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
- // TODO(haberman): fix this for the kImportCommonJs case.
+ // TODO(haberman): fix this for the IMPORT_COMMONJS case.
return "jspb.Message.messageSetExtensions";
} else {
return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
}
}
-static const int kMapKeyField = 1;
-static const int kMapValueField = 2;
-
-const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
- assert(field->is_map());
- return field->message_type()->FindFieldByNumber(kMapKeyField);
-}
-
-const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
- assert(field->is_map());
- return field->message_type()->FindFieldByNumber(kMapValueField);
-}
-
string FieldDefinition(const GeneratorOptions& options,
const FieldDescriptor* field) {
- if (IsMap(options, field)) {
- const FieldDescriptor* key_field = MapFieldKey(field);
- const FieldDescriptor* value_field = MapFieldValue(field);
- string key_type = ProtoTypeName(options, key_field);
- string value_type;
- if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
- value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
- value_type = RelativeTypeName(value_field);
- } else {
- value_type = ProtoTypeName(options, value_field);
- }
- return StringPrintf("map<%s, %s> %s = %d;",
- key_type.c_str(),
- value_type.c_str(),
- field->name().c_str(),
- field->number());
+ string qualifier = field->is_repeated() ? "repeated" :
+ (field->is_optional() ? "optional" : "required");
+ string type, name;
+ if (field->type() == FieldDescriptor::TYPE_ENUM ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE) {
+ type = RelativeTypeName(field);
+ name = field->name();
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ type = "group";
+ name = field->message_type()->name();
} else {
- string qualifier = field->is_repeated() ? "repeated" :
- (field->is_optional() ? "optional" : "required");
- string type, name;
- if (field->type() == FieldDescriptor::TYPE_ENUM ||
- field->type() == FieldDescriptor::TYPE_MESSAGE) {
- type = RelativeTypeName(field);
- name = field->name();
- } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
- type = "group";
- name = field->message_type()->name();
- } else {
- type = ProtoTypeName(options, field);
- name = field->name();
- }
- return StringPrintf("%s %s %s = %d;",
- qualifier.c_str(),
- type.c_str(),
- name.c_str(),
- field->number());
+ type = ProtoTypeName(options, field);
+ name = field->name();
}
+ return StringPrintf("%s %s %s = %d;",
+ qualifier.c_str(),
+ type.c_str(),
+ name.c_str(),
+ field->number());
}
string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
@@ -1319,29 +1164,6 @@ bool HasExtensions(const FileDescriptor* file) {
return false;
}
-bool HasMap(const GeneratorOptions& options, const Descriptor* desc) {
- for (int i = 0; i < desc->field_count(); i++) {
- if (IsMap(options, desc->field(i))) {
- return true;
- }
- }
- for (int i = 0; i < desc->nested_type_count(); i++) {
- if (HasMap(options, desc->nested_type(i))) {
- return true;
- }
- }
- return false;
-}
-
-bool FileHasMap(const GeneratorOptions& options, const FileDescriptor* desc) {
- for (int i = 0; i < desc->message_type_count(); i++) {
- if (HasMap(options, desc->message_type(i))) {
- return true;
- }
- }
- return false;
-}
-
bool IsExtendable(const Descriptor* desc) {
return desc->extension_range_count() > 0;
}
@@ -1369,24 +1191,43 @@ string GetPivot(const Descriptor* desc) {
return SimpleItoa(pivot);
}
-// Whether this field represents presence. For fields with presence, we
-// generate extra methods (clearFoo() and hasFoo()) for this field.
-bool HasFieldPresence(const GeneratorOptions& options,
- const FieldDescriptor* field) {
- if (field->is_repeated() || field->is_map()) {
- // We say repeated fields and maps don't have presence, but we still do
- // generate clearFoo() methods for them through a special case elsewhere.
- return false;
- }
+// Returns true for fields that represent "null" as distinct from the default
+// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
+bool HasFieldPresence(const FieldDescriptor* field) {
+ return
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
+ (field->containing_oneof() != NULL) ||
+ (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3);
+}
- if (UseBrokenPresenceSemantics(options, field)) {
- // Proto3 files with broken presence semantics have field presence.
- return true;
- }
+// For proto3 fields without presence, returns a string representing the default
+// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more
+// information.
+string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT32:
+ case FieldDescriptor::CPPTYPE_UINT64: {
+ return "0";
+ }
+
+ case FieldDescriptor::CPPTYPE_ENUM:
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return "0";
+
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return "false";
+
+ case FieldDescriptor::CPPTYPE_STRING: // includes BYTES
+ return "\"\"";
- return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
- field->containing_oneof() != NULL ||
- field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
+ default:
+ // MESSAGE is handled separately.
+ assert(false);
+ return "";
+ }
}
// We use this to implement the semantics that same file can be generated
@@ -1413,19 +1254,19 @@ class FileDeduplicator {
return true;
}
- void GetAllowedSet(std::set<const void*>* allowed_set) {
+ void GetAllowedSet(set<const void*>* allowed_set) {
*allowed_set = allowed_descs_;
}
private:
bool error_on_conflict_;
- std::map<string, const void*> descs_by_filename_;
- std::set<const void*> allowed_descs_;
+ map<string, const void*> descs_by_filename_;
+ set<const void*> allowed_descs_;
};
void DepthFirstSearch(const FileDescriptor* file,
- std::vector<const FileDescriptor*>* list,
- std::set<const FileDescriptor*>* seen) {
+ vector<const FileDescriptor*>* list,
+ set<const FileDescriptor*>* seen) {
if (!seen->insert(file).second) {
return;
}
@@ -1443,7 +1284,7 @@ void DepthFirstSearch(const FileDescriptor* file,
// FileDescriptor is not in the given set.
class NotInSet {
public:
- explicit NotInSet(const std::set<const FileDescriptor*>& file_set)
+ explicit NotInSet(const set<const FileDescriptor*>& file_set)
: file_set_(file_set) {}
bool operator()(const FileDescriptor* file) {
@@ -1451,21 +1292,21 @@ class NotInSet {
}
private:
- const std::set<const FileDescriptor*>& file_set_;
+ const set<const FileDescriptor*>& file_set_;
};
// This function generates an ordering of the input FileDescriptors that matches
// the logic of the old code generator. The order is significant because two
// different input files can generate the same output file, and the last one
// needs to win.
-void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input,
- std::vector<const FileDescriptor*>* ordered) {
+void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input,
+ vector<const FileDescriptor*>* ordered) {
// First generate an ordering of all reachable files (including dependencies)
// with depth-first search. This mimics the behavior of --include_imports,
// which is what the old codegen used.
ordered->clear();
- std::set<const FileDescriptor*> seen;
- std::set<const FileDescriptor*> input_set;
+ set<const FileDescriptor*> seen;
+ set<const FileDescriptor*> input_set;
for (int i = 0; i < input.size(); i++) {
DepthFirstSearch(input[i], ordered, &seen);
input_set.insert(input[i]);
@@ -1482,10 +1323,10 @@ void GenerateJspbFileOrder(const std::vector<const FileDescriptor*>& input,
// only those to generate code.
bool GenerateJspbAllowedSet(const GeneratorOptions& options,
- const std::vector<const FileDescriptor*>& files,
- std::set<const void*>* allowed_set,
+ const vector<const FileDescriptor*>& files,
+ set<const void*>* allowed_set,
string* error) {
- std::vector<const FileDescriptor*> files_ordered;
+ vector<const FileDescriptor*> files_ordered;
GenerateJspbFileOrder(files, &files_ordered);
// Choose the last descriptor for each filename.
@@ -1553,7 +1394,7 @@ void Generator::FindProvidesForFile(const GeneratorOptions& options,
void Generator::FindProvides(const GeneratorOptions& options,
io::Printer* printer,
- const std::vector<const FileDescriptor*>& files,
+ const vector<const FileDescriptor*>& files,
std::set<string>* provided) const {
for (int i = 0; i < files.size(); i++) {
FindProvidesForFile(options, printer, files[i], provided);
@@ -1567,10 +1408,6 @@ void Generator::FindProvidesForMessage(
io::Printer* printer,
const Descriptor* desc,
std::set<string>* provided) const {
- if (IgnoreMessage(options, desc)) {
- return;
- }
-
string name = GetPath(options, desc);
provided->insert(name);
@@ -1595,7 +1432,7 @@ void Generator::FindProvidesForEnum(const GeneratorOptions& options,
void Generator::FindProvidesForFields(
const GeneratorOptions& options,
io::Printer* printer,
- const std::vector<const FieldDescriptor*>& fields,
+ const vector<const FieldDescriptor*>& fields,
std::set<string>* provided) const {
for (int i = 0; i < fields.size(); i++) {
const FieldDescriptor* field = fields[i];
@@ -1605,8 +1442,7 @@ void Generator::FindProvidesForFields(
}
string name =
- GetPath(options, field->file()) + "." +
- JSObjectFieldName(options, field);
+ GetPath(options, field->file()) + "." + JSObjectFieldName(field);
provided->insert(name);
}
}
@@ -1616,19 +1452,8 @@ void Generator::GenerateProvides(const GeneratorOptions& options,
std::set<string>* provided) const {
for (std::set<string>::iterator it = provided->begin();
it != provided->end(); ++it) {
- if (options.import_style == GeneratorOptions::kImportClosure) {
- printer->Print("goog.provide('$name$');\n", "name", *it);
- } else {
- // We aren't using Closure's import system, but we use goog.exportSymbol()
- // to construct the expected tree of objects, eg.
- //
- // goog.exportSymbol('foo.bar.Baz', null, this);
- //
- // // Later generated code expects foo.bar = {} to exist:
- // foo.bar.Baz = function() { /* ... */ }
- printer->Print("goog.exportSymbol('$name$', null, global);\n", "name",
- *it);
- }
+ printer->Print("goog.provide('$name$');\n",
+ "name", *it);
}
}
@@ -1644,39 +1469,30 @@ void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
GenerateRequiresImpl(options, printer, &required, &forwards, provided,
/* require_jspb = */ have_message,
- /* require_extension = */ HasExtensions(desc),
- /* require_map = */ HasMap(options, desc));
+ /* require_extension = */ HasExtensions(desc));
}
void Generator::GenerateRequiresForLibrary(
const GeneratorOptions& options, io::Printer* printer,
- const std::vector<const FileDescriptor*>& files,
+ const vector<const FileDescriptor*>& files,
std::set<string>* provided) const {
- GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure);
+ GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE);
// For Closure imports we need to import every message type individually.
std::set<string> required;
std::set<string> forwards;
bool have_extensions = false;
- bool have_map = false;
bool have_message = false;
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)) {
- FindRequiresForMessage(options, desc, &required, &forwards,
- &have_message);
- }
+ FindRequiresForMessage(options,
+ files[i]->message_type(j),
+ &required, &forwards, &have_message);
}
-
if (!have_extensions && HasExtensions(files[i])) {
have_extensions = true;
}
- if (!have_map && FileHasMap(options, files[i])) {
- have_map = true;
- }
-
for (int j = 0; j < files[i]->extension_count(); j++) {
const FieldDescriptor* extension = files[i]->extension(j);
if (IgnoreField(extension)) {
@@ -1693,13 +1509,12 @@ void Generator::GenerateRequiresForLibrary(
GenerateRequiresImpl(options, printer, &required, &forwards, provided,
/* require_jspb = */ have_message,
- /* require_extension = */ have_extensions,
- /* require_map = */ have_map);
+ /* require_extension = */ have_extensions);
}
void Generator::GenerateRequiresForExtensions(
const GeneratorOptions& options, io::Printer* printer,
- const std::vector<const FieldDescriptor*>& fields,
+ const vector<const FieldDescriptor*>& fields,
std::set<string>* provided) const {
std::set<string> required;
std::set<string> forwards;
@@ -1713,8 +1528,7 @@ void Generator::GenerateRequiresForExtensions(
GenerateRequiresImpl(options, printer, &required, &forwards, provided,
/* require_jspb = */ false,
- /* require_extension = */ fields.size() > 0,
- /* require_map = */ false);
+ /* require_extension = */ fields.size() > 0);
}
void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
@@ -1722,22 +1536,21 @@ void Generator::GenerateRequiresImpl(const GeneratorOptions& options,
std::set<string>* required,
std::set<string>* forwards,
std::set<string>* provided,
- bool require_jspb, bool require_extension,
- bool require_map) const {
+ bool require_jspb,
+ bool require_extension) const {
if (require_jspb) {
printer->Print(
- "goog.require('jspb.Message');\n"
- "goog.require('jspb.BinaryReader');\n"
- "goog.require('jspb.BinaryWriter');\n");
+ "goog.require('jspb.Message');\n");
+ if (options.binary) {
+ printer->Print(
+ "goog.require('jspb.BinaryReader');\n"
+ "goog.require('jspb.BinaryWriter');\n");
+ }
}
if (require_extension) {
- printer->Print("goog.require('jspb.ExtensionFieldBinaryInfo');\n");
printer->Print(
"goog.require('jspb.ExtensionFieldInfo');\n");
}
- if (require_map) {
- printer->Print("goog.require('jspb.Map');\n");
- }
std::set<string>::iterator it;
for (it = required->begin(); it != required->end(); ++it) {
@@ -1810,9 +1623,7 @@ void Generator::FindRequiresForField(const GeneratorOptions& options,
forwards->insert(GetPath(options, field->enum_type()));
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- if (!IgnoreMessage(options, field->message_type())) {
- required->insert(GetPath(options, field->message_type()));
- }
+ required->insert(GetPath(options, field->message_type()));
}
}
@@ -1848,10 +1659,6 @@ void Generator::GenerateClassesAndEnums(const GeneratorOptions& options,
void Generator::GenerateClass(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
- if (IgnoreMessage(options, desc)) {
- return;
- }
-
if (!NamespaceOnly(desc)) {
printer->Print("\n");
GenerateClassConstructor(options, printer, desc);
@@ -1859,20 +1666,22 @@ void Generator::GenerateClass(const GeneratorOptions& options,
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);
-
+ if (options.binary) {
+ // 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);
+ }
+ GenerateClassClone(options, printer, desc);
GenerateClassRegistration(options, printer, desc);
GenerateClassFields(options, printer, desc);
if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.MessageSet") {
GenerateClassExtensionFieldInfo(options, printer, desc);
}
- if (options.import_style != GeneratorOptions::kImportClosure) {
+ if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) {
for (int i = 0; i < desc->extension_count(); i++) {
GenerateExtension(options, printer, desc->extension(i));
}
@@ -1930,7 +1739,7 @@ void Generator::GenerateClassConstructor(const GeneratorOptions& options,
void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
- if (HasRepeatedFields(options, desc)) {
+ if (HasRepeatedFields(desc)) {
printer->Print(
"/**\n"
" * List of repeated fields within this message type.\n"
@@ -1941,7 +1750,7 @@ void Generator::GenerateClassFieldInfo(const GeneratorOptions& options,
"\n",
"classname", GetPath(options, desc),
"rptfieldarray", kRepeatedFieldArrayName,
- "rptfields", RepeatedFieldNumberList(options, desc));
+ "rptfields", RepeatedFieldNumberList(desc));
}
if (HasOneofFields(desc)) {
@@ -2110,110 +1919,62 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options,
"classname", GetPath(options, desc));
}
-void Generator::GenerateFieldValueExpression(io::Printer* printer,
- const char *obj_reference,
- const FieldDescriptor* field,
- bool use_default) const {
- bool is_float_or_double =
- field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
- field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE;
- if (use_default) {
- if (is_float_or_double) {
- // Coerce "Nan" and "Infinity" to actual float values.
- //
- // This will change null to 0, but that doesn't matter since we're getting
- // with a default.
- printer->Print("+");
- }
-
- printer->Print(
- "jspb.Message.getFieldWithDefault($obj$, $index$, $default$)",
- "obj", obj_reference,
- "index", JSFieldIndex(field),
- "default", JSFieldDefault(field));
- } else {
- if (is_float_or_double) {
- if (field->is_required()) {
- // Use "+" to convert all fields to numeric (including null).
- printer->Print(
- "+jspb.Message.getField($obj$, $index$)",
- "index", JSFieldIndex(field),
- "obj", obj_reference);
- } else {
- // Converts "NaN" and "Infinity" while preserving null.
- printer->Print(
- "jspb.Message.get$cardinality$FloatingPointField($obj$, $index$)",
- "cardinality", field->is_repeated() ? "Repeated" : "Optional",
- "index", JSFieldIndex(field),
- "obj", obj_reference);
- }
- } else {
- printer->Print("jspb.Message.getField($obj$, $index$)",
- "index", JSFieldIndex(field),
- "obj", obj_reference);
- }
- }
-}
-
void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
printer->Print("$fieldname$: ",
- "fieldname", JSObjectFieldName(options, field));
-
- if (IsMap(options, field)) {
- 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.
- string value_to_object;
- if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- value_to_object =
- GetPath(options, value_field->message_type()) + ".toObject";
- } else {
- value_to_object = "undefined";
- }
- printer->Print(
- "(f = msg.get$name$()) ? f.toObject(includeInstance, $valuetoobject$) "
- ": []",
- "name", JSGetterName(options, field), "valuetoobject", value_to_object);
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ "fieldname", JSObjectFieldName(field));
+
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field.
if (field->is_repeated()) {
{
printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
" $type$.toObject, includeInstance)",
- "getter", JSGetterName(options, field),
+ "getter", JSGetterName(field),
"type", SubmessageTypeRef(options, field));
}
} else {
printer->Print("(f = msg.get$getter$()) && "
"$type$.toObject(includeInstance, f)",
- "getter", JSGetterName(options, field),
+ "getter", JSGetterName(field),
"type", SubmessageTypeRef(options, field));
}
- } else if (field->type() == FieldDescriptor::TYPE_BYTES) {
- // For bytes fields we want to always return the B64 data.
- printer->Print("msg.get$getter$()",
- "getter", JSGetterName(options, field, BYTES_B64));
} else {
- bool use_default = field->has_default_value();
-
- if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 &&
- // Repeated fields get initialized to their default in the constructor
- // (why?), so we emit a plain getField() call for them.
- !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) {
- // Proto3 puts all defaults (including implicit defaults) in toObject().
- // But for proto2 we leave the existing semantics unchanged: unset fields
- // without default are unset.
- use_default = true;
+ // Simple field (singular or repeated).
+ if ((!HasFieldPresence(field) && !field->is_repeated()) ||
+ field->type() == FieldDescriptor::TYPE_BYTES) {
+ // Delegate to the generated get<field>() method in order not to duplicate
+ // the proto3-field-default-value or byte-coercion logic here.
+ printer->Print("msg.get$getter$()",
+ "getter", JSGetterName(field, BYTES_B64));
+ } else {
+ if (field->has_default_value()) {
+ printer->Print("jspb.Message.getField(msg, $index$) == null ? "
+ "$defaultValue$ : ",
+ "index", JSFieldIndex(field),
+ "defaultValue", JSFieldDefault(field));
+ }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+ if (field->is_repeated()) {
+ printer->Print("jspb.Message.getRepeatedFloatingPointField("
+ "msg, $index$)",
+ "index", JSFieldIndex(field));
+ } else if (field->is_optional() && !field->has_default_value()) {
+ printer->Print("jspb.Message.getOptionalFloatingPointField("
+ "msg, $index$)",
+ "index", JSFieldIndex(field));
+ } else {
+ // Convert "NaN" to NaN.
+ printer->Print("+jspb.Message.getField(msg, $index$)",
+ "index", JSFieldIndex(field));
+ }
+ } else {
+ printer->Print("jspb.Message.getField(msg, $index$)",
+ "index", JSFieldIndex(field));
+ }
}
-
- // We don't implement this by calling the accessors, because the semantics
- // of the accessors are changing independently of the toObject() semantics.
- // We are migrating the accessors to return defaults instead of null, but
- // it may take longer to migrate toObject (or we might not want to do it at
- // all). So we want to generate independent code.
- GenerateFieldValueExpression(printer, "msg", field, use_default);
}
}
@@ -2247,29 +2008,7 @@ void Generator::GenerateClassFieldFromObject(
const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (IsMap(options, field)) {
- 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
- // to recursively call fromObject() on them before setting the map field.
- printer->Print(
- " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
- " msg, $index$, jspb.Map.fromObject(obj.$name$, $fieldclass$, "
- "$fieldclass$.fromObject));\n",
- "name", JSObjectFieldName(options, field),
- "index", JSFieldIndex(field),
- "fieldclass", GetPath(options, value_field->message_type()));
- } else {
- // `msg` is a newly-constructed message object that has not yet built any
- // map containers wrapping underlying arrays, so we can simply directly
- // set the array here without fear of a stale wrapper.
- printer->Print(
- " goog.isDef(obj.$name$) && "
- "jspb.Message.setField(msg, $index$, obj.$name$);\n",
- "name", JSObjectFieldName(options, field),
- "index", JSFieldIndex(field));
- }
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// Message field (singular or repeated)
if (field->is_repeated()) {
{
@@ -2279,7 +2018,7 @@ void Generator::GenerateClassFieldFromObject(
" msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
" return $fieldclass$.fromObject(i);\n"
" }));\n",
- "name", JSObjectFieldName(options, field),
+ "name", JSObjectFieldName(field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2287,7 +2026,7 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
" msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
- "name", JSObjectFieldName(options, field),
+ "name", JSObjectFieldName(field),
"index", JSFieldIndex(field),
"fieldclass", SubmessageTypeRef(options, field));
}
@@ -2296,11 +2035,26 @@ void Generator::GenerateClassFieldFromObject(
printer->Print(
" goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
"obj.$name$);\n",
- "name", JSObjectFieldName(options, field),
+ "name", JSObjectFieldName(field),
"index", JSFieldIndex(field));
}
}
+void Generator::GenerateClassClone(const GeneratorOptions& options,
+ io::Printer* printer,
+ const Descriptor* desc) const {
+ printer->Print(
+ "/**\n"
+ " * Creates a deep clone of this proto. No data is shared with the "
+ "original.\n"
+ " * @return {!$name$} The clone.\n"
+ " */\n"
+ "$name$.prototype.cloneMessage = function() {\n"
+ " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n"
+ "};\n\n\n",
+ "name", GetPath(options, desc));
+}
+
void Generator::GenerateClassRegistration(const GeneratorOptions& options,
io::Printer* printer,
const Descriptor* desc) const {
@@ -2328,11 +2082,12 @@ void GenerateBytesWrapper(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field,
BytesMode bytes_mode) {
- string type = JSFieldTypeAnnotation(
- options, field,
- /* is_setter_argument = */ false,
- /* force_present = */ false,
- /* singular_if_not_packed = */ false, bytes_mode);
+ string type =
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false,
+ bytes_mode);
printer->Print(
"/**\n"
" * $fielddef$\n"
@@ -2350,74 +2105,17 @@ void GenerateBytesWrapper(const GeneratorOptions& options,
"comment", FieldComments(field, bytes_mode),
"type", type,
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field, bytes_mode),
+ "name", JSGetterName(field, bytes_mode),
"list", field->is_repeated() ? "List" : "",
"suffix", JSByteGetterSuffix(bytes_mode),
- "defname", JSGetterName(options, field, BYTES_DEFAULT));
+ "defname", JSGetterName(field, BYTES_DEFAULT));
}
void Generator::GenerateClassField(const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (IsMap(options, field)) {
- const FieldDescriptor* key_field = MapFieldKey(field);
- const FieldDescriptor* value_field = MapFieldValue(field);
- // Map field: special handling to instantiate the map object on demand.
- string key_type =
- JSFieldTypeAnnotation(
- options, key_field,
- /* is_setter_argument = */ false,
- /* force_present = */ true,
- /* singular_if_not_packed = */ false);
- string value_type =
- JSFieldTypeAnnotation(
- options, value_field,
- /* is_setter_argument = */ false,
- /* force_present = */ true,
- /* singular_if_not_packed = */ false);
-
- printer->Print(
- "/**\n"
- " * $fielddef$\n"
- " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
- " * empty, instead returning `undefined`\n"
- " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
- " */\n",
- "fielddef", FieldDefinition(options, field),
- "keytype", key_type,
- "valuetype", value_type);
- printer->Print(
- "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n"
- " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
- "class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
- "keytype", key_type,
- "valuetype", value_type);
- printer->Print(
- " jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
- "index", JSFieldIndex(field));
-
- if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
- printer->Print(",\n"
- " $messageType$",
- "messageType", GetPath(options, value_field->message_type()));
- } else {
- printer->Print(",\n"
- " null");
- }
-
- printer->Print(
- "));\n");
-
- printer->Print(
- "};\n"
- "\n"
- "\n");
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- // Message field: special handling in order to wrap the underlying data
- // array with a message object.
-
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
"/**\n"
" * $fielddef$\n"
@@ -2427,7 +2125,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"fielddef", FieldDefinition(options, field),
"comment", FieldComments(field, BYTES_DEFAULT),
"type", JSFieldTypeAnnotation(options, field,
- /* is_setter_argument = */ false,
+ /* force_optional = */ false,
/* force_present = */ false,
/* singular_if_not_packed = */ false));
printer->Print(
@@ -2439,9 +2137,9 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"\n"
"\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
+ "name", JSGetterName(field),
"type", JSFieldTypeAnnotation(options, field,
- /* is_setter_argument = */ false,
+ /* force_optional = */ false,
/* force_present = */ false,
/* singular_if_not_packed = */ false),
"rpt", (field->is_repeated() ? "Repeated" : ""),
@@ -2450,17 +2148,17 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
", 1" : ""));
printer->Print(
- "/** @param {$optionaltype$} value$returndoc$ */\n"
+ "/** @param {$optionaltype$} value $returndoc$ */\n"
"$class$.prototype.set$name$ = function(value) {\n"
" jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
"optionaltype",
JSFieldTypeAnnotation(options, field,
- /* is_setter_argument = */ true,
+ /* force_optional = */ true,
/* force_present = */ false,
/* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field),
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
+ "name", JSGetterName(field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"repeatedtag", (field->is_repeated() ? "Repeated" : ""));
@@ -2474,9 +2172,16 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
(", " + JSOneofArray(options, field)) : ""),
"returnvalue", JSReturnClause(field));
- if (field->is_repeated()) {
- GenerateRepeatedMessageHelperMethods(options, printer, field);
- }
+ printer->Print(
+ "$class$.prototype.clear$name$ = function() {\n"
+ " this.set$name$($clearedvalue$);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+ "returnvalue", JSReturnClause(field));
} else {
bool untyped =
@@ -2490,12 +2195,12 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
BytesMode bytes_mode =
field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ?
BYTES_B64 : BYTES_DEFAULT;
- string typed_annotation = JSFieldTypeAnnotation(
- options, field,
- /* is_setter_argument = */ false,
- /* force_present = */ false,
- /* singular_if_not_packed = */ false,
- /* bytes_mode = */ bytes_mode);
+ string typed_annotation =
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ false,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false,
+ /* bytes_mode = */ bytes_mode);
if (untyped) {
printer->Print(
"/**\n"
@@ -2516,7 +2221,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
printer->Print(
"$class$.prototype.get$name$ = function() {\n",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field));
+ "name", JSGetterName(field));
if (untyped) {
printer->Print(
@@ -2527,21 +2232,41 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
"type", typed_annotation);
}
- bool use_default = !ReturnsNullWhenUnset(options, field);
-
- // Raw fields with no default set should just return undefined.
- if (untyped && !field->has_default_value()) {
- use_default = false;
- }
-
- // Repeated fields get initialized to their default in the constructor
- // (why?), so we emit a plain getField() call for them.
- if (field->is_repeated()) {
- use_default = false;
+ // For proto3 fields without presence, use special getters that will return
+ // defaults when the field is unset, possibly constructing a value if
+ // required.
+ if (!HasFieldPresence(field) && !field->is_repeated()) {
+ printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)",
+ "index", JSFieldIndex(field),
+ "default", Proto3PrimitiveFieldDefault(field));
+ } else {
+ if (field->has_default_value()) {
+ printer->Print("jspb.Message.getField(this, $index$) == null ? "
+ "$defaultValue$ : ",
+ "index", JSFieldIndex(field),
+ "defaultValue", JSFieldDefault(field));
+ }
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT ||
+ field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) {
+ if (field->is_repeated()) {
+ printer->Print("jspb.Message.getRepeatedFloatingPointField("
+ "this, $index$)",
+ "index", JSFieldIndex(field));
+ } else if (field->is_optional() && !field->has_default_value()) {
+ printer->Print("jspb.Message.getOptionalFloatingPointField("
+ "this, $index$)",
+ "index", JSFieldIndex(field));
+ } else {
+ // Convert "NaN" to NaN.
+ printer->Print("+jspb.Message.getField(this, $index$)",
+ "index", JSFieldIndex(field));
+ }
+ } else {
+ printer->Print("jspb.Message.getField(this, $index$)",
+ "index", JSFieldIndex(field));
+ }
}
- GenerateFieldValueExpression(printer, "this", field, use_default);
-
if (untyped) {
printer->Print(
";\n"
@@ -2564,24 +2289,24 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
if (untyped) {
printer->Print(
"/**\n"
- " * @param {*} value$returndoc$\n"
+ " * @param {*} value $returndoc$\n"
" */\n",
"returndoc", JSReturnDoc(options, field));
} else {
printer->Print(
- "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype",
- JSFieldTypeAnnotation(
- options, field,
- /* is_setter_argument = */ true,
- /* force_present = */ false,
- /* singular_if_not_packed = */ false),
+ "/** @param {$optionaltype$} value $returndoc$ */\n",
+ "optionaltype",
+ JSFieldTypeAnnotation(options, field,
+ /* force_optional = */ true,
+ /* force_present = */ !HasFieldPresence(field),
+ /* singular_if_not_packed = */ false),
"returndoc", JSReturnDoc(options, field));
}
printer->Print(
"$class$.prototype.set$name$ = function(value) {\n"
" jspb.Message.set$oneoftag$Field(this, $index$",
"class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
+ "name", JSGetterName(field),
"oneoftag", (field->containing_oneof() ? "Oneof" : ""),
"index", JSFieldIndex(field));
printer->Print(
@@ -2601,133 +2326,30 @@ void Generator::GenerateClassField(const GeneratorOptions& options,
if (untyped) {
printer->Print(
"/**\n"
- " * Clears the value.$returndoc$\n"
+ " * Clears the value. $returndoc$\n"
" */\n",
"returndoc", JSReturnDoc(options, field));
}
-
- if (field->is_repeated()) {
- GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped);
+ if (HasFieldPresence(field)) {
+ printer->Print(
+ "$class$.prototype.clear$name$ = function() {\n"
+ " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
+ "class", GetPath(options, field->containing_type()),
+ "name", JSGetterName(field),
+ "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
+ "oneofgroup", (field->containing_oneof() ?
+ (", " + JSOneofArray(options, field)) : ""),
+ "index", JSFieldIndex(field));
+ printer->Print(
+ "$clearedvalue$);$returnvalue$\n"
+ "};\n"
+ "\n"
+ "\n",
+ "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
+ "returnvalue", JSReturnClause(field));
}
}
-
- // Generate clearFoo() method for map fields, repeated fields, and other
- // fields with presence.
- if (IsMap(options, field)) {
- printer->Print(
- "$class$.prototype.clear$name$ = function() {\n"
- " this.get$name$().clear();$returnvalue$\n"
- "};\n"
- "\n"
- "\n",
- "class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
- "returnvalue", JSReturnClause(field));
- } else if (field->is_repeated() ||
- (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- !field->is_required())) {
- // Fields where we can delegate to the regular setter.
- printer->Print(
- "$class$.prototype.clear$name$ = function() {\n"
- " this.set$name$($clearedvalue$);$returnvalue$\n"
- "};\n"
- "\n"
- "\n",
- "class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
- "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
- "returnvalue", JSReturnClause(field));
- } else if (HasFieldPresence(options, field)) {
- // Fields where we can't delegate to the regular setter because it doesn't
- // accept "undefined" as an argument.
- printer->Print(
- "$class$.prototype.clear$name$ = function() {\n"
- " jspb.Message.set$maybeoneof$Field(this, "
- "$index$$maybeoneofgroup$, ",
- "class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
- "maybeoneof", (field->containing_oneof() ? "Oneof" : ""),
- "maybeoneofgroup", (field->containing_oneof() ?
- (", " + JSOneofArray(options, field)) : ""),
- "index", JSFieldIndex(field));
- printer->Print(
- "$clearedvalue$);$returnvalue$\n"
- "};\n"
- "\n"
- "\n",
- "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
- "returnvalue", JSReturnClause(field));
- }
-
- if (HasFieldPresence(options, field)) {
- printer->Print(
- "/**\n"
- " * Returns whether this field is set.\n"
- " * @return {!boolean}\n"
- " */\n"
- "$class$.prototype.has$name$ = function() {\n"
- " return jspb.Message.getField(this, $index$) != null;\n"
- "};\n"
- "\n"
- "\n",
- "class", GetPath(options, field->containing_type()),
- "name", JSGetterName(options, field),
- "index", JSFieldIndex(field));
- }
-}
-
-void Generator::GenerateRepeatedPrimitiveHelperMethods(
- const GeneratorOptions& options, io::Printer* printer,
- const FieldDescriptor* field, bool untyped) const {
- printer->Print(
- "/**\n"
- " * @param {!$optionaltype$} value\n"
- " * @param {number=} opt_index\n"
- " */\n"
- "$class$.prototype.add$name$ = function(value, opt_index) {\n"
- " jspb.Message.addToRepeatedField(this, $index$",
- "class", GetPath(options, field->containing_type()), "name",
- JSGetterName(options, field, BYTES_DEFAULT,
- /* drop_list = */ true),
- "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "index",
- JSFieldIndex(field));
- printer->Print(
- "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, opt_index);\n"
- "};\n"
- "\n"
- "\n",
- "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "",
- "typeclose", untyped ? ")" : "", "oneofgroup",
- (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""),
- "rptvalueinit", "");
-}
-
-void Generator::GenerateRepeatedMessageHelperMethods(
- const GeneratorOptions& options, io::Printer* printer,
- const FieldDescriptor* field) const {
- printer->Print(
- "/**\n"
- " * @param {!$optionaltype$=} opt_value\n"
- " * @param {number=} opt_index\n"
- " * @return {!$optionaltype$}\n"
- " */\n"
- "$class$.prototype.add$name$ = function(opt_value, opt_index) {\n"
- " return jspb.Message.addTo$repeatedtag$WrapperField(",
- "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class",
- GetPath(options, field->containing_type()), "name",
- JSGetterName(options, field, BYTES_DEFAULT,
- /* drop_list = */ true),
- "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
-
- printer->Print(
- "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n"
- "};\n"
- "\n"
- "\n",
- "index", JSFieldIndex(field), "oneofgroup",
- (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""),
- "ctor", GetPath(options, field->message_type()));
}
void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
@@ -2754,27 +2376,6 @@ void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options,
"$class$.extensions = {};\n"
"\n",
"class", GetPath(options, desc));
-
- printer->Print(
- "\n"
- "/**\n"
- " * The extensions registered with this message class. This is a "
- "map of\n"
- " * extension field number to fieldInfo object.\n"
- " *\n"
- " * For example:\n"
- " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, "
- "ctor: proto.example.MyMessage} }\n"
- " *\n"
- " * fieldName contains the JsCompiler renamed field name property "
- "so that it\n"
- " * works in OPTIMIZED mode.\n"
- " *\n"
- " * @type {!Object.<number, jspb.ExtensionFieldBinaryInfo>}\n"
- " */\n"
- "$class$.extensionsBinary = {};\n"
- "\n",
- "class", GetPath(options, desc));
}
}
@@ -2815,16 +2416,14 @@ void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options,
"class", GetPath(options, desc));
for (int i = 0; i < desc->field_count(); i++) {
- if (!IgnoreField(desc->field(i))) {
- GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
- }
+ GenerateClassDeserializeBinaryField(options, printer, desc->field(i));
}
printer->Print(
" default:\n");
if (IsExtendable(desc)) {
printer->Print(
- " jspb.Message.readBinaryExtension(msg, reader, $extobj$Binary,\n"
+ " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
" $class$.prototype.getExtension,\n"
" $class$.prototype.setExtension);\n"
" break;\n",
@@ -2853,60 +2452,40 @@ void Generator::GenerateClassDeserializeBinaryField(
printer->Print(" case $num$:\n",
"num", SimpleItoa(field->number()));
- if (IsMap(options, field)) {
- const FieldDescriptor* key_field = MapFieldKey(field);
- const FieldDescriptor* value_field = MapFieldValue(field);
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
- " var value = msg.get$name$();\n"
- " reader.readMessage(value, function(message, reader) {\n",
- "name", JSGetterName(options, field));
-
- printer->Print(" jspb.Map.deserializeBinary(message, reader, "
- "$keyReaderFn$, $valueReaderFn$",
- "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
- "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
-
- if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
- printer->Print(", $messageType$.deserializeBinaryFromReader",
- "messageType", GetPath(options, value_field->message_type()));
- }
-
- printer->Print(");\n");
- printer->Print(" });\n");
- } else {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- printer->Print(
- " var value = new $fieldclass$;\n"
- " reader.read$msgOrGroup$($grpfield$value,"
- "$fieldclass$.deserializeBinaryFromReader);\n",
+ " 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()) + ", ") : "");
- } else {
- printer->Print(
- " var value = /** @type {$fieldtype$} */ "
- "(reader.read$reader$());\n",
- "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
- /* singular_if_not_packed */ true,
- BYTES_U8),
- "reader",
- JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
- }
-
- if (field->is_repeated() && !field->is_packed()) {
- printer->Print(
- " msg.add$name$(value);\n", "name",
- JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true));
- } else {
- // Singular fields, and packed repeated fields, receive a |value| either
- // as the field's value or as the array of all the field's values; set
- // this as the field's value directly.
- printer->Print(
- " msg.set$name$(value);\n",
- "name", JSGetterName(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$} */ (reader.$reader$());\n",
+ "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+ /* singular_if_not_packed = */ true,
+ BYTES_U8),
+ "reader", JSBinaryReaderMethodName(field));
+ }
+
+ if (field->is_repeated() && !field->is_packed()) {
+ // Repeated fields receive a |value| one at at a time; append to array
+ // returned by get$name$(). Annoyingly, we have to call 'set' after
+ // changing the array.
+ printer->Print(" msg.get$name$().push(value);\n", "name",
+ JSGetterName(field));
+ printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
+ JSGetterName(field));
+ } else {
+ // Singular fields, and packed repeated fields, receive a |value| either as
+ // the field's value or as the array of all the field's values; set this as
+ // the field's value directly.
+ printer->Print(
+ " msg.set$name$(value);\n",
+ "name", JSGetterName(field));
}
printer->Print(" break;\n");
@@ -2917,37 +2496,45 @@ void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options,
const Descriptor* desc) const {
printer->Print(
"/**\n"
+ " * Class method variant: serializes the given message to binary data\n"
+ " * (in protobuf wire format), writing to the given BinaryWriter.\n"
+ " * @param {!$class$} message\n"
+ " * @param {!jspb.BinaryWriter} writer\n"
+ " */\n"
+ "$class$.serializeBinaryToWriter = function(message, "
+ "writer) {\n"
+ " message.serializeBinaryToWriter(writer);\n"
+ "};\n"
+ "\n"
+ "\n"
+ "/**\n"
" * Serializes the message to binary data (in protobuf wire format).\n"
" * @return {!Uint8Array}\n"
" */\n"
"$class$.prototype.serializeBinary = function() {\n"
" var writer = new jspb.BinaryWriter();\n"
- " $class$.serializeBinaryToWriter(this, writer);\n"
+ " this.serializeBinaryToWriter(writer);\n"
" return writer.getResultBuffer();\n"
"};\n"
"\n"
"\n"
"/**\n"
- " * Serializes the given message to binary data (in protobuf wire\n"
- " * format), writing to the given BinaryWriter.\n"
- " * @param {!$class$} message\n"
+ " * Serializes the message to binary data (in protobuf wire format),\n"
+ " * writing to the given BinaryWriter.\n"
" * @param {!jspb.BinaryWriter} writer\n"
" */\n"
- "$class$.serializeBinaryToWriter = function(message, "
- "writer) {\n"
+ "$class$.prototype.serializeBinaryToWriter = function (writer) {\n"
" var f = undefined;\n",
"class", GetPath(options, desc));
for (int i = 0; i < desc->field_count(); i++) {
- if (!IgnoreField(desc->field(i))) {
- GenerateClassSerializeBinaryField(options, printer, desc->field(i));
- }
+ GenerateClassSerializeBinaryField(options, printer, desc->field(i));
}
if (IsExtendable(desc)) {
printer->Print(
- " jspb.Message.serializeBinaryExtensions(message, writer,\n"
- " $extobj$Binary, $class$.prototype.getExtension);\n",
+ " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
+ " $class$.prototype.getExtension);\n",
"extobj", JSExtensionsObjectName(options, desc->file(), desc),
"class", GetPath(options, desc));
}
@@ -2962,37 +2549,15 @@ void Generator::GenerateClassSerializeBinaryField(
const GeneratorOptions& options,
io::Printer* printer,
const FieldDescriptor* field) const {
- if (HasFieldPresence(options, field) &&
- field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
- string typed_annotation = JSFieldTypeAnnotation(
- options, field,
- /* is_setter_argument = */ false,
- /* force_present = */ false,
- /* singular_if_not_packed = */ false,
- /* bytes_mode = */ BYTES_DEFAULT);
- printer->Print(
- " f = /** @type {$type$} */ "
- "(jspb.Message.getField(message, $index$));\n",
- "index", JSFieldIndex(field),
- "type", typed_annotation);
- } else {
- printer->Print(
- " 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" : "");
- }
+ printer->Print(
+ " f = this.get$name$();\n",
+ "name", JSGetterName(field, BYTES_U8));
- // Print an `if (condition)` statement that evaluates to true if the field
- // goes on the wire.
- if (IsMap(options, field)) {
- printer->Print(
- " if (f && f.getLength() > 0) {\n");
- } else if (field->is_repeated()) {
+ if (field->is_repeated()) {
printer->Print(
" if (f.length > 0) {\n");
} else {
- if (HasFieldPresence(options, field)) {
+ if (HasFieldPresence(field)) {
printer->Print(
" if (f != null) {\n");
} else {
@@ -3031,47 +2596,23 @@ void Generator::GenerateClassSerializeBinaryField(
}
}
- // Write the field on the wire.
- if (IsMap(options, field)) {
- 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));
-
- if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
- printer->Print(", $messageType$.serializeBinaryToWriter",
- "messageType", GetPath(options, value_field->message_type()));
- }
+ printer->Print(
+ " writer.$writer$(\n"
+ " $index$,\n"
+ " f",
+ "writer", JSBinaryWriterMethodName(field),
+ "index", SimpleItoa(field->number()));
- printer->Print(");\n");
- } else {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
- " writer.write$method$(\n"
- " $index$,\n"
- " f",
- "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
- "index", SimpleItoa(field->number()));
-
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- !IsMap(options, field)) {
- printer->Print(
- ",\n"
- " $submsg$.serializeBinaryToWriter\n",
+ ",\n"
+ " $submsg$.serializeBinaryToWriter\n",
"submsg", SubmessageTypeRef(options, field));
- } else {
- printer->Print("\n");
- }
-
- printer->Print(
- " );\n");
+ } else {
+ printer->Print("\n");
}
-
- // Close the `if`.
printer->Print(
+ " );\n"
" }\n");
}
@@ -3115,11 +2656,11 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
" */\n"
"$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
- "name", JSObjectFieldName(options, field),
+ "name", JSObjectFieldName(field),
"class", extension_scope,
"extensionType", JSFieldTypeAnnotation(
options, field,
- /* is_setter_argument = */ false,
+ /* force_optional = */ false,
/* force_present = */ true,
/* singular_if_not_packed = */ false));
printer->Print(
@@ -3129,9 +2670,9 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
" /** @type {?function((boolean|undefined),!jspb.Message=): "
"!Object} */ (\n"
" $toObject$),\n"
- " $repeated$);\n",
+ " $repeated$",
"index", SimpleItoa(field->number()),
- "name", JSObjectFieldName(options, field),
+ "name", JSObjectFieldName(field),
"ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
SubmessageTypeRef(options, field) : string("null")),
"toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
@@ -3139,30 +2680,28 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
string("null")),
"repeated", (field->is_repeated() ? "1" : "0"));
- printer->Print(
- "\n"
- "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n"
- " $class$.$name$,\n"
- " $binaryReaderFn$,\n"
- " $binaryWriterFn$,\n"
- " $binaryMessageSerializeFn$,\n"
- " $binaryMessageDeserializeFn$,\n",
- "extendName",
- JSExtensionsObjectName(options, field->file(), field->containing_type()),
- "index", SimpleItoa(field->number()), "class", extension_scope, "name",
- JSObjectFieldName(options, field), "binaryReaderFn",
- JSBinaryReaderMethodName(options, field), "binaryWriterFn",
- JSBinaryWriterMethodName(options, field), "binaryMessageSerializeFn",
- (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
- ? (SubmessageTypeRef(options, field) + ".serializeBinaryToWriter")
- : "undefined",
- "binaryMessageDeserializeFn",
- (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
- ? (SubmessageTypeRef(options, field) + ".deserializeBinaryFromReader")
- : "undefined");
-
- printer->Print(" $isPacked$);\n", "isPacked",
- (field->is_packed() ? "true" : "false"));
+ if (options.binary) {
+ printer->Print(
+ ",\n"
+ " jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
+ " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+ " $binaryMessageSerializeFn$,\n"
+ " $binaryMessageDeserializeFn$,\n"
+ " $isPacked$);\n",
+ "binaryReaderFn", JSBinaryReaderMethodName(field),
+ "binaryWriterFn", JSBinaryWriterMethodName(field),
+ "binaryMessageSerializeFn",
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+ (SubmessageTypeRef(options, field) +
+ ".serializeBinaryToWriter") : "null",
+ "binaryMessageDeserializeFn",
+ (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
+ (SubmessageTypeRef(options, field) +
+ ".deserializeBinaryFromReader") : "null",
+ "isPacked", (field->is_packed() ? "true" : "false"));
+ } else {
+ printer->Print(");\n");
+ }
printer->Print(
"// This registers the extension field with the extended class, so that\n"
@@ -3173,11 +2712,11 @@ void Generator::GenerateExtension(const GeneratorOptions& options,
field->containing_type()),
"index", SimpleItoa(field->number()),
"class", extension_scope,
- "name", JSObjectFieldName(options, field));
+ "name", JSObjectFieldName(field));
}
bool GeneratorOptions::ParseFromOptions(
- const std::vector< std::pair< string, string > >& options,
+ const vector< pair< string, string > >& options,
string* error) {
for (int i = 0; i < options.size(); i++) {
if (options[i].first == "add_require_for_enums") {
@@ -3212,25 +2751,17 @@ bool GeneratorOptions::ParseFromOptions(
library = options[i].second;
} else if (options[i].first == "import_style") {
if (options[i].second == "closure") {
- import_style = kImportClosure;
+ import_style = IMPORT_CLOSURE;
} else if (options[i].second == "commonjs") {
- import_style = kImportCommonJs;
+ import_style = IMPORT_COMMONJS;
} else if (options[i].second == "browser") {
- import_style = kImportBrowser;
+ import_style = IMPORT_BROWSER;
} else if (options[i].second == "es6") {
- import_style = kImportEs6;
+ import_style = IMPORT_ES6;
} else {
*error = "Unknown import style " + options[i].second + ", expected " +
"one of: closure, commonjs, browser, es6.";
}
- } else if (options[i].first == "extension") {
- extension = options[i].second;
- } else if (options[i].first == "one_output_file_per_input_file") {
- if (!options[i].second.empty()) {
- *error = "Unexpected option value for one_output_file_per_input_file";
- return false;
- }
- one_output_file_per_input_file = true;
} else {
// Assume any other option is an output directory, as long as it is a bare
// `key` rather than a `key=value` option.
@@ -3242,40 +2773,18 @@ bool GeneratorOptions::ParseFromOptions(
}
}
- if (import_style != kImportClosure &&
- (add_require_for_enums || testonly || !library.empty() ||
- error_on_name_conflict || extension != ".js" ||
- one_output_file_per_input_file)) {
- *error =
- "The add_require_for_enums, testonly, library, error_on_name_conflict, "
- "extension, and one_output_file_per_input_file options should only be "
- "used for import_style=closure";
- return false;
+ if (!library.empty() && import_style != IMPORT_CLOSURE) {
+ *error = "The library option should only be used for "
+ "import_style=closure";
}
return true;
}
-GeneratorOptions::OutputMode GeneratorOptions::output_mode() const {
- // We use one output file per input file if we are not using Closure or if
- // this is explicitly requested.
- if (import_style != kImportClosure || one_output_file_per_input_file) {
- return kOneOutputFilePerInputFile;
- }
-
- // If a library name is provided, we put everything in that one file.
- if (!library.empty()) {
- return kEverythingInOneFile;
- }
-
- // Otherwise, we create one output file per type.
- return kOneOutputFilePerType;
-}
-
void Generator::GenerateFilesInDepOrder(
const GeneratorOptions& options,
io::Printer* printer,
- const std::vector<const FileDescriptor*>& files) const {
+ const vector<const FileDescriptor*>& files) const {
// Build a std::set over all files so that the DFS can detect when it recurses
// into a dep not specified in the user's command line.
std::set<const FileDescriptor*> all_files(files.begin(), files.end());
@@ -3318,7 +2827,7 @@ void Generator::GenerateFile(const GeneratorOptions& options,
GenerateHeader(options, printer);
// Generate "require" statements.
- if (options.import_style == GeneratorOptions::kImportCommonJs) {
+ if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
printer->Print("var jspb = require('google-protobuf');\n");
printer->Print("var goog = jspb;\n");
printer->Print("var global = Function('return this')();\n\n");
@@ -3328,61 +2837,52 @@ void Generator::GenerateFile(const GeneratorOptions& options,
printer->Print(
"var $alias$ = require('$file$');\n",
"alias", ModuleAlias(name),
- "file", GetRootPath(file->name(), name) + GetJSFilename(options, name));
+ "file", GetRootPath(file->name()) + GetJSFilename(name));
}
}
- std::set<string> provided;
- std::set<const FieldDescriptor*> extensions;
+ // We aren't using Closure's import system, but we use goog.exportSymbol()
+ // to construct the expected tree of objects, eg.
+ //
+ // goog.exportSymbol('foo.bar.Baz', null, this);
+ //
+ // // Later generated code expects foo.bar = {} to exist:
+ // foo.bar.Baz = function() { /* ... */ }
+ set<string> provided;
+
+ // Cover the case where this file declares extensions but no messages.
+ // This will ensure that the file-level object will be declared to hold
+ // the extensions.
for (int i = 0; i < file->extension_count(); i++) {
- // We honor the jspb::ignore option here only when working with
- // Closure-style imports. Use of this option is discouraged and so we want
- // to avoid adding new support for it.
- if (options.import_style == GeneratorOptions::kImportClosure &&
- IgnoreField(file->extension(i))) {
- continue;
- }
- provided.insert(GetPath(options, file) + "." +
- JSObjectFieldName(options, file->extension(i)));
- extensions.insert(file->extension(i));
+ provided.insert(file->extension(i)->full_name());
}
FindProvidesForFile(options, printer, file, &provided);
- GenerateProvides(options, printer, &provided);
- std::vector<const FileDescriptor*> files;
- files.push_back(file);
- if (options.import_style == GeneratorOptions::kImportClosure) {
- GenerateRequiresForLibrary(options, printer, files, &provided);
+ for (std::set<string>::iterator it = provided.begin();
+ it != provided.end(); ++it) {
+ printer->Print("goog.exportSymbol('$name$', null, global);\n",
+ "name", *it);
}
GenerateClassesAndEnums(options, printer, file);
- // Generate code for top-level extensions. Extensions nested inside messages
- // are emitted inside GenerateClassesAndEnums().
- for (std::set<const FieldDescriptor*>::const_iterator it = extensions.begin();
- it != extensions.end(); ++it) {
- GenerateExtension(options, printer, *it);
+ // Extensions nested inside messages are emitted inside
+ // GenerateClassesAndEnums().
+ for (int i = 0; i < file->extension_count(); i++) {
+ GenerateExtension(options, printer, file->extension(i));
}
- if (options.import_style == GeneratorOptions::kImportCommonJs) {
+ if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
printer->Print("goog.object.extend(exports, $package$);\n",
"package", GetPath(options, file));
}
-
- // Emit well-known type methods.
- for (FileToc* toc = well_known_types_js; toc->name != NULL; toc++) {
- string name = string("google/protobuf/") + toc->name;
- if (name == StripProto(file->name()) + ".js") {
- printer->Print(toc->data);
- }
- }
}
-bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
+bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
const string& parameter,
GeneratorContext* context,
string* error) const {
- std::vector< std::pair< string, string > > option_pairs;
+ vector< pair< string, string > > option_pairs;
ParseGeneratorParameter(parameter, &option_pairs);
GeneratorOptions options;
if (!options.ParseFromOptions(option_pairs, error)) {
@@ -3390,17 +2890,22 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
}
- if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) {
+ // There are three schemes for where output files go:
+ //
+ // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file
+ // - import_style = IMPORT_CLOSURE, library empty: one output file per type
+ // - import_style != IMPORT_CLOSURE: one output file per .proto file
+ if (options.import_style == GeneratorOptions::IMPORT_CLOSURE &&
+ options.library != "") {
// All output should go in a single file.
- string filename = options.output_dir + "/" + options.library +
- options.GetFileNameExtension();
+ string filename = options.output_dir + "/" + options.library + ".js";
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
GOOGLE_CHECK(output.get());
io::Printer printer(output.get(), '$');
// Pull out all extensions -- we need these to generate all
// provides/requires.
- std::vector<const FieldDescriptor*> extensions;
+ vector<const FieldDescriptor*> extensions;
for (int i = 0; i < files.size(); i++) {
for (int j = 0; j < files[i]->extension_count(); j++) {
const FieldDescriptor* extension = files[i]->extension(j);
@@ -3428,8 +2933,8 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
if (printer.failed()) {
return false;
}
- } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) {
- std::set<const void*> allowed_set;
+ } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
+ set<const void*> allowed_set;
if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
return false;
}
@@ -3500,7 +3005,7 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
GenerateHeader(options, &printer);
std::set<string> provided;
- std::vector<const FieldDescriptor*> fields;
+ vector<const FieldDescriptor*> fields;
for (int j = 0; j < files[i]->extension_count(); j++) {
if (ShouldGenerateExtension(files[i]->extension(j))) {
@@ -3520,14 +3025,13 @@ bool Generator::GenerateAll(const std::vector<const FileDescriptor*>& files,
}
}
}
- } else /* options.output_mode() == kOneOutputFilePerInputFile */ {
+ } else {
// Generate one output file per input (.proto) file.
for (int i = 0; i < files.size(); i++) {
const google::protobuf::FileDescriptor* file = files[i];
- string filename =
- options.output_dir + "/" + GetJSFilename(options, file->name());
+ string filename = options.output_dir + "/" + GetJSFilename(file->name());
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
GOOGLE_CHECK(output.get());
io::Printer printer(output.get(), '$');

Powered by Google App Engine
This is Rietveld 408576698