| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | 30 |
| 31 #include <google/protobuf/compiler/js/js_generator.h> | 31 #include "google/protobuf/compiler/js/js_generator.h" |
| 32 | 32 |
| 33 #include <assert.h> | 33 #include <assert.h> |
| 34 #include <algorithm> | 34 #include <algorithm> |
| 35 #include <limits> | 35 #include <limits> |
| 36 #include <map> | 36 #include <map> |
| 37 #include <memory> | 37 #include <memory> |
| 38 #ifndef _SHARED_PTR_H | 38 #ifndef _SHARED_PTR_H |
| 39 #include <google/protobuf/stubs/shared_ptr.h> | 39 #include <google/protobuf/stubs/shared_ptr.h> |
| 40 #endif | 40 #endif |
| 41 #include <string> | 41 #include <string> |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 | 144 |
| 145 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto | 145 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto |
| 146 // suffix stripped. | 146 // suffix stripped. |
| 147 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. | 147 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. |
| 148 string StripProto(const string& filename) { | 148 string StripProto(const string& filename) { |
| 149 const char* suffix = HasSuffixString(filename, ".protodevel") | 149 const char* suffix = HasSuffixString(filename, ".protodevel") |
| 150 ? ".protodevel" : ".proto"; | 150 ? ".protodevel" : ".proto"; |
| 151 return StripSuffixString(filename, suffix); | 151 return StripSuffixString(filename, suffix); |
| 152 } | 152 } |
| 153 | 153 |
| 154 // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript | 154 // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript |
| 155 // file foo/bar/baz.js. | 155 // file foo/bar/baz.js. |
| 156 string GetJSFilename(const string& filename) { | 156 string GetJSFilename(const GeneratorOptions& options, const string& filename) { |
| 157 return StripProto(filename) + "_pb.js"; | 157 return StripProto(filename) + options.GetFileNameExtension(); |
| 158 } | 158 } |
| 159 | 159 |
| 160 // Given a filename like foo/bar/baz.proto, returns the root directory | 160 // Given a filename like foo/bar/baz.proto, returns the root directory |
| 161 // path ../../ | 161 // path ../../ |
| 162 string GetRootPath(const string& filename) { | 162 string GetRootPath(const string& from_filename, const string& to_filename) { |
| 163 size_t slashes = std::count(filename.begin(), filename.end(), '/'); | 163 if (to_filename.find("google/protobuf") == 0) { |
| 164 // Well-known types (.proto files in the google/protobuf directory) are |
| 165 // assumed to come from the 'google-protobuf' npm package. We may want to |
| 166 // generalize this exception later by letting others put generated code in |
| 167 // their own npm packages. |
| 168 return "google-protobuf/"; |
| 169 } |
| 170 |
| 171 size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/'); |
| 164 if (slashes == 0) { | 172 if (slashes == 0) { |
| 165 return "./"; | 173 return "./"; |
| 166 } | 174 } |
| 167 string result = ""; | 175 string result = ""; |
| 168 for (size_t i = 0; i < slashes; i++) { | 176 for (size_t i = 0; i < slashes; i++) { |
| 169 result += "../"; | 177 result += "../"; |
| 170 } | 178 } |
| 171 return result; | 179 return result; |
| 172 } | 180 } |
| 173 | 181 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 193 const FileDescriptor* file) { | 201 const FileDescriptor* file) { |
| 194 if (!options.namespace_prefix.empty()) { | 202 if (!options.namespace_prefix.empty()) { |
| 195 return options.namespace_prefix; | 203 return options.namespace_prefix; |
| 196 } else if (!file->package().empty()) { | 204 } else if (!file->package().empty()) { |
| 197 return "proto." + file->package(); | 205 return "proto." + file->package(); |
| 198 } else { | 206 } else { |
| 199 return "proto"; | 207 return "proto"; |
| 200 } | 208 } |
| 201 } | 209 } |
| 202 | 210 |
| 203 // Forward declare, so that GetPrefix can call this method, | 211 // Returns the name of the message with a leading dot and taking into account |
| 204 // which in turn, calls GetPrefix. | 212 // nesting, for example ".OuterMessage.InnerMessage", or returns empty if |
| 205 string GetPath(const GeneratorOptions& options, | 213 // descriptor is null. This function does not handle namespacing, only message |
| 206 const Descriptor* descriptor); | 214 // nesting. |
| 215 string GetNestedMessageName(const Descriptor* descriptor) { |
| 216 if (descriptor == NULL) { |
| 217 return ""; |
| 218 } |
| 219 return StripPrefixString(descriptor->full_name(), |
| 220 descriptor->file()->package()); |
| 221 } |
| 207 | 222 |
| 208 // Returns the path prefix for a message or enumeration that | 223 // Returns the path prefix for a message or enumeration that |
| 209 // lives under the given file and containing type. | 224 // lives under the given file and containing type. |
| 210 string GetPrefix(const GeneratorOptions& options, | 225 string GetPrefix(const GeneratorOptions& options, |
| 211 const FileDescriptor* file_descriptor, | 226 const FileDescriptor* file_descriptor, |
| 212 const Descriptor* containing_type) { | 227 const Descriptor* containing_type) { |
| 213 string prefix = ""; | 228 string prefix = GetPath(options, file_descriptor) + |
| 214 | 229 GetNestedMessageName(containing_type); |
| 215 if (containing_type == NULL) { | |
| 216 prefix = GetPath(options, file_descriptor); | |
| 217 } else { | |
| 218 prefix = GetPath(options, containing_type); | |
| 219 } | |
| 220 | |
| 221 if (!prefix.empty()) { | 230 if (!prefix.empty()) { |
| 222 prefix += "."; | 231 prefix += "."; |
| 223 } | 232 } |
| 224 | |
| 225 return prefix; | 233 return prefix; |
| 226 } | 234 } |
| 227 | 235 |
| 228 | 236 |
| 229 // Returns the fully normalized JavaScript path for the given | 237 // Returns the fully normalized JavaScript path for the given |
| 230 // message descriptor. | 238 // message descriptor. |
| 231 string GetPath(const GeneratorOptions& options, | 239 string GetPath(const GeneratorOptions& options, |
| 232 const Descriptor* descriptor) { | 240 const Descriptor* descriptor) { |
| 233 return GetPrefix( | 241 return GetPrefix( |
| 234 options, descriptor->file(), | 242 options, descriptor->file(), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 258 string GetPath(const GeneratorOptions& options, | 266 string GetPath(const GeneratorOptions& options, |
| 259 const EnumValueDescriptor* value_descriptor) { | 267 const EnumValueDescriptor* value_descriptor) { |
| 260 return GetPath( | 268 return GetPath( |
| 261 options, | 269 options, |
| 262 value_descriptor->type()) + "." + value_descriptor->name(); | 270 value_descriptor->type()) + "." + value_descriptor->name(); |
| 263 } | 271 } |
| 264 | 272 |
| 265 string MaybeCrossFileRef(const GeneratorOptions& options, | 273 string MaybeCrossFileRef(const GeneratorOptions& options, |
| 266 const FileDescriptor* from_file, | 274 const FileDescriptor* from_file, |
| 267 const Descriptor* to_message) { | 275 const Descriptor* to_message) { |
| 268 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS && | 276 if (options.import_style == GeneratorOptions::kImportCommonJs && |
| 269 from_file != to_message->file()) { | 277 from_file != to_message->file()) { |
| 270 // Cross-file ref in CommonJS needs to use the module alias instead of | 278 // Cross-file ref in CommonJS needs to use the module alias instead of |
| 271 // the global name. | 279 // the global name. |
| 272 return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); | 280 return ModuleAlias(to_message->file()->name()) + |
| 281 GetNestedMessageName(to_message->containing_type()) + |
| 282 "." + to_message->name(); |
| 273 } else { | 283 } else { |
| 274 // Within a single file we use a full name. | 284 // Within a single file we use a full name. |
| 275 return GetPath(options, to_message); | 285 return GetPath(options, to_message); |
| 276 } | 286 } |
| 277 } | 287 } |
| 278 | 288 |
| 279 string SubmessageTypeRef(const GeneratorOptions& options, | 289 string SubmessageTypeRef(const GeneratorOptions& options, |
| 280 const FieldDescriptor* field) { | 290 const FieldDescriptor* field) { |
| 281 GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); | 291 GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); |
| 282 return MaybeCrossFileRef(options, field->file(), field->message_type()); | 292 return MaybeCrossFileRef(options, field->file(), field->message_type()); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 } | 400 } |
| 391 } | 401 } |
| 392 | 402 |
| 393 return result; | 403 return result; |
| 394 } | 404 } |
| 395 | 405 |
| 396 // When we're generating one output file per type name, this is the filename | 406 // When we're generating one output file per type name, this is the filename |
| 397 // that top-level extensions should go in. | 407 // that top-level extensions should go in. |
| 398 string GetExtensionFileName(const GeneratorOptions& options, | 408 string GetExtensionFileName(const GeneratorOptions& options, |
| 399 const FileDescriptor* file) { | 409 const FileDescriptor* file) { |
| 400 return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js"; | 410 return options.output_dir + "/" + ToFileName(GetPath(options, file)) + |
| 411 options.GetFileNameExtension(); |
| 401 } | 412 } |
| 402 | 413 |
| 403 // When we're generating one output file per type name, this is the filename | 414 // When we're generating one output file per type name, this is the filename |
| 404 // that a top-level message should go in. | 415 // that a top-level message should go in. |
| 405 string GetMessageFileName(const GeneratorOptions& options, | 416 string GetMessageFileName(const GeneratorOptions& options, |
| 406 const Descriptor* desc) { | 417 const Descriptor* desc) { |
| 407 return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; | 418 return options.output_dir + "/" + ToFileName(desc->name()) + |
| 419 options.GetFileNameExtension(); |
| 408 } | 420 } |
| 409 | 421 |
| 410 // When we're generating one output file per type name, this is the filename | 422 // When we're generating one output file per type name, this is the filename |
| 411 // that a top-level message should go in. | 423 // that a top-level message should go in. |
| 412 string GetEnumFileName(const GeneratorOptions& options, | 424 string GetEnumFileName(const GeneratorOptions& options, |
| 413 const EnumDescriptor* desc) { | 425 const EnumDescriptor* desc) { |
| 414 return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; | 426 return options.output_dir + "/" + ToFileName(desc->name()) + |
| 427 options.GetFileNameExtension(); |
| 415 } | 428 } |
| 416 | 429 |
| 417 // Returns the message/response ID, if set. | 430 // Returns the message/response ID, if set. |
| 418 string GetMessageId(const Descriptor* desc) { | 431 string GetMessageId(const Descriptor* desc) { |
| 419 return string(); | 432 return string(); |
| 420 } | 433 } |
| 421 | 434 |
| 422 bool IgnoreExtensionField(const FieldDescriptor* field) { | 435 bool IgnoreExtensionField(const FieldDescriptor* field) { |
| 423 // Exclude descriptor extensions from output "to avoid clutter" (from original | 436 // Exclude descriptor extensions from output "to avoid clutter" (from original |
| 424 // codegen). | 437 // codegen). |
| 425 return field->is_extension() && | 438 return field->is_extension() && |
| 426 field->containing_type()->file()->name() == | 439 field->containing_type()->file()->name() == |
| 427 "google/protobuf/descriptor.proto"; | 440 "google/protobuf/descriptor.proto"; |
| 428 } | 441 } |
| 429 | 442 |
| 430 | 443 |
| 431 // Used inside Google only -- do not remove. | 444 // Used inside Google only -- do not remove. |
| 432 bool IsResponse(const Descriptor* desc) { return false; } | 445 bool IsResponse(const Descriptor* desc) { return false; } |
| 433 | 446 |
| 434 bool IgnoreField(const FieldDescriptor* field) { | 447 bool IgnoreField(const FieldDescriptor* field) { |
| 435 return IgnoreExtensionField(field); | 448 return IgnoreExtensionField(field); |
| 436 } | 449 } |
| 437 | 450 |
| 438 | 451 |
| 452 // Used inside Google only -- do not remove. |
| 453 bool ShouldTreatMapsAsRepeatedFields(const FileDescriptor& descriptor) { |
| 454 return false; |
| 455 } |
| 456 |
| 457 // Do we ignore this message type? |
| 458 bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) { |
| 459 return d->options().map_entry() && |
| 460 !ShouldTreatMapsAsRepeatedFields(*d->file()); |
| 461 } |
| 462 |
| 463 bool IsMap(const GeneratorOptions& options, const FieldDescriptor* field) { |
| 464 return field->is_map() && !ShouldTreatMapsAsRepeatedFields(*field->file()); |
| 465 } |
| 466 |
| 439 // Does JSPB ignore this entire oneof? True only if all fields are ignored. | 467 // Does JSPB ignore this entire oneof? True only if all fields are ignored. |
| 440 bool IgnoreOneof(const OneofDescriptor* oneof) { | 468 bool IgnoreOneof(const OneofDescriptor* oneof) { |
| 441 for (int i = 0; i < oneof->field_count(); i++) { | 469 for (int i = 0; i < oneof->field_count(); i++) { |
| 442 if (!IgnoreField(oneof->field(i))) { | 470 if (!IgnoreField(oneof->field(i))) { |
| 443 return false; | 471 return false; |
| 444 } | 472 } |
| 445 } | 473 } |
| 446 return true; | 474 return true; |
| 447 } | 475 } |
| 448 | 476 |
| 449 string JSIdent(const FieldDescriptor* field, | 477 string JSIdent(const GeneratorOptions& options, const FieldDescriptor* field, |
| 450 bool is_upper_camel, | 478 bool is_upper_camel, bool is_map, bool drop_list) { |
| 451 bool is_map) { | |
| 452 string result; | 479 string result; |
| 453 if (field->type() == FieldDescriptor::TYPE_GROUP) { | 480 if (field->type() == FieldDescriptor::TYPE_GROUP) { |
| 454 result = is_upper_camel ? | 481 result = is_upper_camel ? |
| 455 ToUpperCamel(ParseUpperCamel(field->message_type()->name())) : | 482 ToUpperCamel(ParseUpperCamel(field->message_type()->name())) : |
| 456 ToLowerCamel(ParseUpperCamel(field->message_type()->name())); | 483 ToLowerCamel(ParseUpperCamel(field->message_type()->name())); |
| 457 } else { | 484 } else { |
| 458 result = is_upper_camel ? | 485 result = is_upper_camel ? |
| 459 ToUpperCamel(ParseLowerUnderscore(field->name())) : | 486 ToUpperCamel(ParseLowerUnderscore(field->name())) : |
| 460 ToLowerCamel(ParseLowerUnderscore(field->name())); | 487 ToLowerCamel(ParseLowerUnderscore(field->name())); |
| 461 } | 488 } |
| 462 if (is_map) { | 489 if (is_map || IsMap(options, field)) { |
| 490 // JSPB-style or proto3-style map. |
| 463 result += "Map"; | 491 result += "Map"; |
| 464 } else if (field->is_repeated()) { | 492 } else if (!drop_list && field->is_repeated()) { |
| 493 // Repeated field. |
| 465 result += "List"; | 494 result += "List"; |
| 466 } | 495 } |
| 467 return result; | 496 return result; |
| 468 } | 497 } |
| 469 | 498 |
| 470 string JSObjectFieldName(const FieldDescriptor* field) { | 499 string JSObjectFieldName(const GeneratorOptions& options, |
| 471 string name = JSIdent( | 500 const FieldDescriptor* field) { |
| 472 field, | 501 string name = JSIdent(options, field, |
| 473 /* is_upper_camel = */ false, | 502 /* is_upper_camel = */ false, |
| 474 /* is_map = */ false); | 503 /* is_map = */ false, |
| 504 /* drop_list = */ false); |
| 475 if (IsReserved(name)) { | 505 if (IsReserved(name)) { |
| 476 name = "pb_" + name; | 506 name = "pb_" + name; |
| 477 } | 507 } |
| 478 return name; | 508 return name; |
| 479 } | 509 } |
| 480 | 510 |
| 481 string JSByteGetterSuffix(BytesMode bytes_mode) { | 511 string JSByteGetterSuffix(BytesMode bytes_mode) { |
| 482 switch (bytes_mode) { | 512 switch (bytes_mode) { |
| 483 case BYTES_DEFAULT: | 513 case BYTES_DEFAULT: |
| 484 return ""; | 514 return ""; |
| 485 case BYTES_B64: | 515 case BYTES_B64: |
| 486 return "B64"; | 516 return "B64"; |
| 487 case BYTES_U8: | 517 case BYTES_U8: |
| 488 return "U8"; | 518 return "U8"; |
| 489 default: | 519 default: |
| 490 assert(false); | 520 assert(false); |
| 491 } | 521 } |
| 522 return ""; |
| 492 } | 523 } |
| 493 | 524 |
| 494 // Returns the field name as a capitalized portion of a getter/setter method | 525 // Returns the field name as a capitalized portion of a getter/setter method |
| 495 // name, e.g. MyField for .getMyField(). | 526 // name, e.g. MyField for .getMyField(). |
| 496 string JSGetterName(const FieldDescriptor* field, | 527 string JSGetterName(const GeneratorOptions& options, |
| 497 BytesMode bytes_mode = BYTES_DEFAULT) { | 528 const FieldDescriptor* field, |
| 498 string name = JSIdent(field, | 529 BytesMode bytes_mode = BYTES_DEFAULT, |
| 530 bool drop_list = false) { |
| 531 string name = JSIdent(options, field, |
| 499 /* is_upper_camel = */ true, | 532 /* is_upper_camel = */ true, |
| 500 /* is_map = */ false); | 533 /* is_map = */ false, drop_list); |
| 501 if (field->type() == FieldDescriptor::TYPE_BYTES) { | 534 if (field->type() == FieldDescriptor::TYPE_BYTES) { |
| 502 string suffix = JSByteGetterSuffix(bytes_mode); | 535 string suffix = JSByteGetterSuffix(bytes_mode); |
| 503 if (!suffix.empty()) { | 536 if (!suffix.empty()) { |
| 504 name += "_as" + suffix; | 537 name += "_as" + suffix; |
| 505 } | 538 } |
| 506 } | 539 } |
| 507 if (name == "Extension" || name == "JsPbMessageId") { | 540 if (name == "Extension" || name == "JsPbMessageId") { |
| 508 // Avoid conflicts with base-class names. | 541 // Avoid conflicts with base-class names. |
| 509 name += "$"; | 542 name += "$"; |
| 510 } | 543 } |
| 511 return name; | 544 return name; |
| 512 } | 545 } |
| 513 | 546 |
| 514 string JSMapGetterName(const FieldDescriptor* field) { | 547 string JSMapGetterName(const GeneratorOptions& options, |
| 515 return JSIdent(field, | 548 const FieldDescriptor* field) { |
| 549 return JSIdent(options, field, |
| 516 /* is_upper_camel = */ true, | 550 /* is_upper_camel = */ true, |
| 517 /* is_map = */ true); | 551 /* is_map = */ true, |
| 552 /* drop_list = */ false); |
| 518 } | 553 } |
| 519 | 554 |
| 520 | 555 |
| 521 | 556 |
| 522 string JSOneofName(const OneofDescriptor* oneof) { | 557 string JSOneofName(const OneofDescriptor* oneof) { |
| 523 return ToUpperCamel(ParseLowerUnderscore(oneof->name())); | 558 return ToUpperCamel(ParseLowerUnderscore(oneof->name())); |
| 524 } | 559 } |
| 525 | 560 |
| 526 // Returns the index corresponding to this field in the JSPB array (underlying | 561 // Returns the index corresponding to this field in the JSPB array (underlying |
| 527 // data storage array). | 562 // data storage array). |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 string DoubleToString(double value) { | 775 string DoubleToString(double value) { |
| 741 string result = SimpleDtoa(value); | 776 string result = SimpleDtoa(value); |
| 742 return PostProcessFloat(result); | 777 return PostProcessFloat(result); |
| 743 } | 778 } |
| 744 | 779 |
| 745 string MaybeNumberString(const FieldDescriptor* field, const string& orig) { | 780 string MaybeNumberString(const FieldDescriptor* field, const string& orig) { |
| 746 return orig; | 781 return orig; |
| 747 } | 782 } |
| 748 | 783 |
| 749 string JSFieldDefault(const FieldDescriptor* field) { | 784 string JSFieldDefault(const FieldDescriptor* field) { |
| 750 assert(field->has_default_value()); | 785 if (field->is_repeated()) { |
| 786 return "[]"; |
| 787 } |
| 788 |
| 751 switch (field->cpp_type()) { | 789 switch (field->cpp_type()) { |
| 752 case FieldDescriptor::CPPTYPE_INT32: | 790 case FieldDescriptor::CPPTYPE_INT32: |
| 753 return MaybeNumberString( | 791 return MaybeNumberString( |
| 754 field, SimpleItoa(field->default_value_int32())); | 792 field, SimpleItoa(field->default_value_int32())); |
| 755 case FieldDescriptor::CPPTYPE_UINT32: | 793 case FieldDescriptor::CPPTYPE_UINT32: |
| 756 // The original codegen is in Java, and Java protobufs store unsigned | 794 // The original codegen is in Java, and Java protobufs store unsigned |
| 757 // integer values as signed integer values. In order to exactly match the | 795 // integer values as signed integer values. In order to exactly match the |
| 758 // output, we need to reinterpret as base-2 signed. Ugh. | 796 // output, we need to reinterpret as base-2 signed. Ugh. |
| 759 return MaybeNumberString( | 797 return MaybeNumberString( |
| 760 field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); | 798 field, SimpleItoa(static_cast<int32>(field->default_value_uint32()))); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 return JSStringTypeName(options, field, bytes_mode); | 920 return JSStringTypeName(options, field, bytes_mode); |
| 883 case FieldDescriptor::CPPTYPE_ENUM: | 921 case FieldDescriptor::CPPTYPE_ENUM: |
| 884 return GetPath(options, field->enum_type()); | 922 return GetPath(options, field->enum_type()); |
| 885 case FieldDescriptor::CPPTYPE_MESSAGE: | 923 case FieldDescriptor::CPPTYPE_MESSAGE: |
| 886 return GetPath(options, field->message_type()); | 924 return GetPath(options, field->message_type()); |
| 887 default: | 925 default: |
| 888 return ""; | 926 return ""; |
| 889 } | 927 } |
| 890 } | 928 } |
| 891 | 929 |
| 892 bool HasFieldPresence(const FieldDescriptor* field); | 930 bool UseBrokenPresenceSemantics(const GeneratorOptions& options, |
| 931 const FieldDescriptor* field) { |
| 932 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { |
| 933 return options.broken_proto3_semantics; |
| 934 } else if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2) { |
| 935 return false; |
| 936 } else { |
| 937 GOOGLE_LOG(FATAL) << "We can only handle syntax=proto2 and syntax=proto3."; |
| 938 return false; |
| 939 } |
| 940 } |
| 941 |
| 942 // Returns true for fields that return "null" from accessors when they are |
| 943 // unset. This should normally only be true for non-repeated submessages, but |
| 944 // we have legacy users who relied on old behavior where accessors behaved this |
| 945 // way. |
| 946 bool ReturnsNullWhenUnset(const GeneratorOptions& options, |
| 947 const FieldDescriptor* field) { |
| 948 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
| 949 field->is_optional()) { |
| 950 return true; |
| 951 } |
| 952 |
| 953 // TODO(haberman): remove this case and unconditionally return false. |
| 954 return UseBrokenPresenceSemantics(options, field) && !field->is_repeated() && |
| 955 !field->has_default_value(); |
| 956 } |
| 957 |
| 958 // In a sane world, this would be the same as ReturnsNullWhenUnset(). But in |
| 959 // the status quo, some fields declare that they never return null/undefined |
| 960 // even though they actually do: |
| 961 // * required fields |
| 962 // * optional enum fields |
| 963 // * proto3 primitive fields. |
| 964 bool DeclaredReturnTypeIsNullable(const GeneratorOptions& options, |
| 965 const FieldDescriptor* field) { |
| 966 if (field->is_required() || field->type() == FieldDescriptor::TYPE_ENUM) { |
| 967 return false; |
| 968 } |
| 969 |
| 970 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && |
| 971 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { |
| 972 return false; |
| 973 } |
| 974 |
| 975 return ReturnsNullWhenUnset(options, field); |
| 976 } |
| 977 |
| 978 bool SetterAcceptsUndefined(const GeneratorOptions& options, |
| 979 const FieldDescriptor* field) { |
| 980 if (ReturnsNullWhenUnset(options, field)) { |
| 981 return true; |
| 982 } |
| 983 |
| 984 // Broken presence semantics always accepts undefined for setters. |
| 985 return UseBrokenPresenceSemantics(options, field); |
| 986 } |
| 987 |
| 988 bool SetterAcceptsNull(const GeneratorOptions& options, |
| 989 const FieldDescriptor* field) { |
| 990 if (ReturnsNullWhenUnset(options, field)) { |
| 991 return true; |
| 992 } |
| 993 |
| 994 // With broken presence semantics, fields with defaults accept "null" for |
| 995 // setters, but other fields do not. This is a strange quirk of the old |
| 996 // codegen. |
| 997 return UseBrokenPresenceSemantics(options, field) && |
| 998 field->has_default_value(); |
| 999 } |
| 1000 |
| 1001 // Returns types which are known to by non-nullable by default. |
| 1002 // The style guide requires that we omit "!" in this case. |
| 1003 bool IsPrimitive(const string& type) { |
| 1004 return type == "undefined" || type == "string" || type == "number" || |
| 1005 type == "boolean"; |
| 1006 } |
| 893 | 1007 |
| 894 string JSFieldTypeAnnotation(const GeneratorOptions& options, | 1008 string JSFieldTypeAnnotation(const GeneratorOptions& options, |
| 895 const FieldDescriptor* field, | 1009 const FieldDescriptor* field, |
| 896 bool force_optional, | 1010 bool is_setter_argument, |
| 897 bool force_present, | 1011 bool force_present, |
| 898 bool singular_if_not_packed, | 1012 bool singular_if_not_packed, |
| 899 BytesMode bytes_mode = BYTES_DEFAULT) { | 1013 BytesMode bytes_mode = BYTES_DEFAULT) { |
| 900 bool is_primitive = | 1014 GOOGLE_CHECK(!(is_setter_argument && force_present)); |
| 901 (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && | |
| 902 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && | |
| 903 (field->type() != FieldDescriptor::TYPE_BYTES || | |
| 904 bytes_mode == BYTES_B64)); | |
| 905 | |
| 906 string jstype = JSTypeName(options, field, bytes_mode); | 1015 string jstype = JSTypeName(options, field, bytes_mode); |
| 907 | 1016 |
| 908 if (field->is_repeated() && | 1017 if (field->is_repeated() && |
| 909 (field->is_packed() || !singular_if_not_packed)) { | 1018 (field->is_packed() || !singular_if_not_packed)) { |
| 910 if (field->type() == FieldDescriptor::TYPE_BYTES && | 1019 if (field->type() == FieldDescriptor::TYPE_BYTES && |
| 911 bytes_mode == BYTES_DEFAULT) { | 1020 bytes_mode == BYTES_DEFAULT) { |
| 912 jstype = "(Array<!Uint8Array>|Array<string>)"; | 1021 jstype = "(Array<!Uint8Array>|Array<string>)"; |
| 913 } else { | 1022 } else { |
| 914 if (!is_primitive) { | 1023 if (!IsPrimitive(jstype)) { |
| 915 jstype = "!" + jstype; | 1024 jstype = "!" + jstype; |
| 916 } | 1025 } |
| 917 jstype = "Array.<" + jstype + ">"; | 1026 jstype = "Array.<" + jstype + ">"; |
| 918 } | 1027 } |
| 919 if (!force_optional) { | 1028 } |
| 920 jstype = "!" + jstype; | 1029 |
| 1030 bool is_null_or_undefined = false; |
| 1031 |
| 1032 if (is_setter_argument) { |
| 1033 if (SetterAcceptsNull(options, field)) { |
| 1034 jstype = "?" + jstype; |
| 1035 is_null_or_undefined = true; |
| 1036 } |
| 1037 |
| 1038 if (SetterAcceptsUndefined(options, field)) { |
| 1039 jstype += "|undefined"; |
| 1040 is_null_or_undefined = true; |
| 1041 } |
| 1042 } else if (force_present) { |
| 1043 // Don't add null or undefined. |
| 1044 } else { |
| 1045 if (DeclaredReturnTypeIsNullable(options, field)) { |
| 1046 jstype = "?" + jstype; |
| 1047 is_null_or_undefined = true; |
| 921 } | 1048 } |
| 922 } | 1049 } |
| 923 | 1050 |
| 924 if (field->is_optional() && is_primitive && | 1051 if (!is_null_or_undefined && !IsPrimitive(jstype)) { |
| 925 (!field->has_default_value() || force_optional) && !force_present) { | |
| 926 jstype += "?"; | |
| 927 } else if (field->is_required() && !is_primitive && !force_optional) { | |
| 928 jstype = "!" + jstype; | 1052 jstype = "!" + jstype; |
| 929 } | 1053 } |
| 930 | 1054 |
| 931 if (force_optional && HasFieldPresence(field)) { | |
| 932 jstype += "|undefined"; | |
| 933 } | |
| 934 if (force_present && jstype[0] != '!' && !is_primitive) { | |
| 935 jstype = "!" + jstype; | |
| 936 } | |
| 937 | |
| 938 return jstype; | 1055 return jstype; |
| 939 } | 1056 } |
| 940 | 1057 |
| 941 string JSBinaryReaderMethodType(const FieldDescriptor* field) { | 1058 string JSBinaryReaderMethodType(const FieldDescriptor* field) { |
| 942 string name = field->type_name(); | 1059 string name = field->type_name(); |
| 943 if (name[0] >= 'a' && name[0] <= 'z') { | 1060 if (name[0] >= 'a' && name[0] <= 'z') { |
| 944 name[0] = (name[0] - 'a') + 'A'; | 1061 name[0] = (name[0] - 'a') + 'A'; |
| 945 } | 1062 } |
| 946 | 1063 |
| 947 return name; | 1064 return name; |
| 948 } | 1065 } |
| 949 | 1066 |
| 950 string JSBinaryReadWriteMethodName(const FieldDescriptor* field, | 1067 string JSBinaryReadWriteMethodName(const FieldDescriptor* field, |
| 951 bool is_writer) { | 1068 bool is_writer) { |
| 952 string name = JSBinaryReaderMethodType(field); | 1069 string name = JSBinaryReaderMethodType(field); |
| 953 if (field->is_packed()) { | 1070 if (field->is_packed()) { |
| 954 name = "Packed" + name; | 1071 name = "Packed" + name; |
| 955 } else if (is_writer && field->is_repeated()) { | 1072 } else if (is_writer && field->is_repeated()) { |
| 956 name = "Repeated" + name; | 1073 name = "Repeated" + name; |
| 957 } | 1074 } |
| 958 return name; | 1075 return name; |
| 959 } | 1076 } |
| 960 | 1077 |
| 961 string JSBinaryReaderMethodName(const FieldDescriptor* field) { | 1078 string JSBinaryReaderMethodName(const GeneratorOptions& options, |
| 962 return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false); | 1079 const FieldDescriptor* field) { |
| 1080 if (options.binary) { |
| 1081 return "jspb.BinaryReader.prototype.read" + |
| 1082 JSBinaryReadWriteMethodName(field, /* is_writer = */ false); |
| 1083 } else { |
| 1084 return "null"; |
| 1085 } |
| 963 } | 1086 } |
| 964 | 1087 |
| 965 string JSBinaryWriterMethodName(const FieldDescriptor* field) { | 1088 string JSBinaryWriterMethodName(const GeneratorOptions& options, |
| 966 return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true); | 1089 const FieldDescriptor* field) { |
| 1090 if (options.binary) { |
| 1091 return "jspb.BinaryWriter.prototype.write" + |
| 1092 JSBinaryReadWriteMethodName(field, /* is_writer = */ true); |
| 1093 } else { |
| 1094 return "null"; |
| 1095 } |
| 967 } | 1096 } |
| 968 | 1097 |
| 969 string JSReturnClause(const FieldDescriptor* desc) { | 1098 string JSReturnClause(const FieldDescriptor* desc) { |
| 970 return ""; | 1099 return ""; |
| 971 } | 1100 } |
| 972 | 1101 |
| 973 string JSReturnDoc(const GeneratorOptions& options, | 1102 string JSReturnDoc(const GeneratorOptions& options, |
| 974 const FieldDescriptor* desc) { | 1103 const FieldDescriptor* desc) { |
| 975 return ""; | 1104 return ""; |
| 976 } | 1105 } |
| 977 | 1106 |
| 978 bool HasRepeatedFields(const Descriptor* desc) { | 1107 bool HasRepeatedFields(const GeneratorOptions& options, |
| 1108 const Descriptor* desc) { |
| 979 for (int i = 0; i < desc->field_count(); i++) { | 1109 for (int i = 0; i < desc->field_count(); i++) { |
| 980 if (desc->field(i)->is_repeated()) { | 1110 if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { |
| 981 return true; | 1111 return true; |
| 982 } | 1112 } |
| 983 } | 1113 } |
| 984 return false; | 1114 return false; |
| 985 } | 1115 } |
| 986 | 1116 |
| 987 static const char* kRepeatedFieldArrayName = ".repeatedFields_"; | 1117 static const char* kRepeatedFieldArrayName = ".repeatedFields_"; |
| 988 | 1118 |
| 989 string RepeatedFieldsArrayName(const GeneratorOptions& options, | 1119 string RepeatedFieldsArrayName(const GeneratorOptions& options, |
| 990 const Descriptor* desc) { | 1120 const Descriptor* desc) { |
| 991 return HasRepeatedFields(desc) ? | 1121 return HasRepeatedFields(options, desc) |
| 992 (GetPath(options, desc) + kRepeatedFieldArrayName) : "null"; | 1122 ? (GetPath(options, desc) + kRepeatedFieldArrayName) |
| 1123 : "null"; |
| 993 } | 1124 } |
| 994 | 1125 |
| 995 bool HasOneofFields(const Descriptor* desc) { | 1126 bool HasOneofFields(const Descriptor* desc) { |
| 996 for (int i = 0; i < desc->field_count(); i++) { | 1127 for (int i = 0; i < desc->field_count(); i++) { |
| 997 if (desc->field(i)->containing_oneof()) { | 1128 if (desc->field(i)->containing_oneof()) { |
| 998 return true; | 1129 return true; |
| 999 } | 1130 } |
| 1000 } | 1131 } |
| 1001 return false; | 1132 return false; |
| 1002 } | 1133 } |
| 1003 | 1134 |
| 1004 static const char* kOneofGroupArrayName = ".oneofGroups_"; | 1135 static const char* kOneofGroupArrayName = ".oneofGroups_"; |
| 1005 | 1136 |
| 1006 string OneofFieldsArrayName(const GeneratorOptions& options, | 1137 string OneofFieldsArrayName(const GeneratorOptions& options, |
| 1007 const Descriptor* desc) { | 1138 const Descriptor* desc) { |
| 1008 return HasOneofFields(desc) ? | 1139 return HasOneofFields(desc) ? |
| 1009 (GetPath(options, desc) + kOneofGroupArrayName) : "null"; | 1140 (GetPath(options, desc) + kOneofGroupArrayName) : "null"; |
| 1010 } | 1141 } |
| 1011 | 1142 |
| 1012 string RepeatedFieldNumberList(const Descriptor* desc) { | 1143 string RepeatedFieldNumberList(const GeneratorOptions& options, |
| 1144 const Descriptor* desc) { |
| 1013 std::vector<string> numbers; | 1145 std::vector<string> numbers; |
| 1014 for (int i = 0; i < desc->field_count(); i++) { | 1146 for (int i = 0; i < desc->field_count(); i++) { |
| 1015 if (desc->field(i)->is_repeated()) { | 1147 if (desc->field(i)->is_repeated() && !IsMap(options, desc->field(i))) { |
| 1016 numbers.push_back(JSFieldIndex(desc->field(i))); | 1148 numbers.push_back(JSFieldIndex(desc->field(i))); |
| 1017 } | 1149 } |
| 1018 } | 1150 } |
| 1019 return "[" + Join(numbers, ",") + "]"; | 1151 return "[" + Join(numbers, ",") + "]"; |
| 1020 } | 1152 } |
| 1021 | 1153 |
| 1022 string OneofGroupList(const Descriptor* desc) { | 1154 string OneofGroupList(const Descriptor* desc) { |
| 1023 // List of arrays (one per oneof), each of which is a list of field indices | 1155 // List of arrays (one per oneof), each of which is a list of field indices |
| 1024 std::vector<string> oneof_entries; | 1156 std::vector<string> oneof_entries; |
| 1025 for (int i = 0; i < desc->oneof_decl_count(); i++) { | 1157 for (int i = 0; i < desc->oneof_decl_count(); i++) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1069 } | 1201 } |
| 1070 } | 1202 } |
| 1071 | 1203 |
| 1072 return type.substr(prefix); | 1204 return type.substr(prefix); |
| 1073 } | 1205 } |
| 1074 | 1206 |
| 1075 string JSExtensionsObjectName(const GeneratorOptions& options, | 1207 string JSExtensionsObjectName(const GeneratorOptions& options, |
| 1076 const FileDescriptor* from_file, | 1208 const FileDescriptor* from_file, |
| 1077 const Descriptor* desc) { | 1209 const Descriptor* desc) { |
| 1078 if (desc->full_name() == "google.protobuf.bridge.MessageSet") { | 1210 if (desc->full_name() == "google.protobuf.bridge.MessageSet") { |
| 1079 // TODO(haberman): fix this for the IMPORT_COMMONJS case. | 1211 // TODO(haberman): fix this for the kImportCommonJs case. |
| 1080 return "jspb.Message.messageSetExtensions"; | 1212 return "jspb.Message.messageSetExtensions"; |
| 1081 } else { | 1213 } else { |
| 1082 return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; | 1214 return MaybeCrossFileRef(options, from_file, desc) + ".extensions"; |
| 1083 } | 1215 } |
| 1084 } | 1216 } |
| 1085 | 1217 |
| 1218 static const int kMapKeyField = 1; |
| 1219 static const int kMapValueField = 2; |
| 1220 |
| 1221 const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) { |
| 1222 assert(field->is_map()); |
| 1223 return field->message_type()->FindFieldByNumber(kMapKeyField); |
| 1224 } |
| 1225 |
| 1226 const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) { |
| 1227 assert(field->is_map()); |
| 1228 return field->message_type()->FindFieldByNumber(kMapValueField); |
| 1229 } |
| 1230 |
| 1086 string FieldDefinition(const GeneratorOptions& options, | 1231 string FieldDefinition(const GeneratorOptions& options, |
| 1087 const FieldDescriptor* field) { | 1232 const FieldDescriptor* field) { |
| 1088 string qualifier = field->is_repeated() ? "repeated" : | 1233 if (IsMap(options, field)) { |
| 1089 (field->is_optional() ? "optional" : "required"); | 1234 const FieldDescriptor* key_field = MapFieldKey(field); |
| 1090 string type, name; | 1235 const FieldDescriptor* value_field = MapFieldValue(field); |
| 1091 if (field->type() == FieldDescriptor::TYPE_ENUM || | 1236 string key_type = ProtoTypeName(options, key_field); |
| 1092 field->type() == FieldDescriptor::TYPE_MESSAGE) { | 1237 string value_type; |
| 1093 type = RelativeTypeName(field); | 1238 if (value_field->type() == FieldDescriptor::TYPE_ENUM || |
| 1094 name = field->name(); | 1239 value_field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 1095 } else if (field->type() == FieldDescriptor::TYPE_GROUP) { | 1240 value_type = RelativeTypeName(value_field); |
| 1096 type = "group"; | 1241 } else { |
| 1097 name = field->message_type()->name(); | 1242 value_type = ProtoTypeName(options, value_field); |
| 1243 } |
| 1244 return StringPrintf("map<%s, %s> %s = %d;", |
| 1245 key_type.c_str(), |
| 1246 value_type.c_str(), |
| 1247 field->name().c_str(), |
| 1248 field->number()); |
| 1098 } else { | 1249 } else { |
| 1099 type = ProtoTypeName(options, field); | 1250 string qualifier = field->is_repeated() ? "repeated" : |
| 1100 name = field->name(); | 1251 (field->is_optional() ? "optional" : "required"); |
| 1252 string type, name; |
| 1253 if (field->type() == FieldDescriptor::TYPE_ENUM || |
| 1254 field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 1255 type = RelativeTypeName(field); |
| 1256 name = field->name(); |
| 1257 } else if (field->type() == FieldDescriptor::TYPE_GROUP) { |
| 1258 type = "group"; |
| 1259 name = field->message_type()->name(); |
| 1260 } else { |
| 1261 type = ProtoTypeName(options, field); |
| 1262 name = field->name(); |
| 1263 } |
| 1264 return StringPrintf("%s %s %s = %d;", |
| 1265 qualifier.c_str(), |
| 1266 type.c_str(), |
| 1267 name.c_str(), |
| 1268 field->number()); |
| 1101 } | 1269 } |
| 1102 return StringPrintf("%s %s %s = %d;", | |
| 1103 qualifier.c_str(), | |
| 1104 type.c_str(), | |
| 1105 name.c_str(), | |
| 1106 field->number()); | |
| 1107 } | 1270 } |
| 1108 | 1271 |
| 1109 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { | 1272 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { |
| 1110 string comments; | 1273 string comments; |
| 1111 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { | 1274 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { |
| 1112 comments += | 1275 comments += |
| 1113 " * Note that Boolean fields may be set to 0/1 when serialized from " | 1276 " * Note that Boolean fields may be set to 0/1 when serialized from " |
| 1114 "a Java server.\n" | 1277 "a Java server.\n" |
| 1115 " * You should avoid comparisons like {@code val === true/false} in " | 1278 " * You should avoid comparisons like {@code val === true/false} in " |
| 1116 "those cases.\n"; | 1279 "those cases.\n"; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1184 | 1347 |
| 1185 int pivot = -1; | 1348 int pivot = -1; |
| 1186 if (IsExtendable(desc)) { | 1349 if (IsExtendable(desc)) { |
| 1187 pivot = ((max_field_number + 1) < kDefaultPivot) ? | 1350 pivot = ((max_field_number + 1) < kDefaultPivot) ? |
| 1188 (max_field_number + 1) : kDefaultPivot; | 1351 (max_field_number + 1) : kDefaultPivot; |
| 1189 } | 1352 } |
| 1190 | 1353 |
| 1191 return SimpleItoa(pivot); | 1354 return SimpleItoa(pivot); |
| 1192 } | 1355 } |
| 1193 | 1356 |
| 1194 // Returns true for fields that represent "null" as distinct from the default | 1357 // Whether this field represents presence. For fields with presence, we |
| 1195 // value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. | 1358 // generate extra methods (clearFoo() and hasFoo()) for this field. |
| 1196 bool HasFieldPresence(const FieldDescriptor* field) { | 1359 bool HasFieldPresence(const GeneratorOptions& options, |
| 1197 return | 1360 const FieldDescriptor* field) { |
| 1198 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || | 1361 if (field->is_repeated() || field->is_map()) { |
| 1199 (field->containing_oneof() != NULL) || | 1362 // We say repeated fields and maps don't have presence, but we still do |
| 1200 (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3); | 1363 // generate clearFoo() methods for them through a special case elsewhere. |
| 1201 } | 1364 return false; |
| 1365 } |
| 1202 | 1366 |
| 1203 // For proto3 fields without presence, returns a string representing the default | 1367 if (UseBrokenPresenceSemantics(options, field)) { |
| 1204 // value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more | 1368 // Proto3 files with broken presence semantics have field presence. |
| 1205 // information. | 1369 return true; |
| 1206 string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { | 1370 } |
| 1207 switch (field->cpp_type()) { | |
| 1208 case FieldDescriptor::CPPTYPE_INT32: | |
| 1209 case FieldDescriptor::CPPTYPE_INT64: | |
| 1210 case FieldDescriptor::CPPTYPE_UINT32: | |
| 1211 case FieldDescriptor::CPPTYPE_UINT64: { | |
| 1212 return "0"; | |
| 1213 } | |
| 1214 | 1371 |
| 1215 case FieldDescriptor::CPPTYPE_ENUM: | 1372 return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || |
| 1216 case FieldDescriptor::CPPTYPE_FLOAT: | 1373 field->containing_oneof() != NULL || |
| 1217 case FieldDescriptor::CPPTYPE_DOUBLE: | 1374 field->file()->syntax() == FileDescriptor::SYNTAX_PROTO2; |
| 1218 return "0"; | |
| 1219 | |
| 1220 case FieldDescriptor::CPPTYPE_BOOL: | |
| 1221 return "false"; | |
| 1222 | |
| 1223 case FieldDescriptor::CPPTYPE_STRING: // includes BYTES | |
| 1224 return "\"\""; | |
| 1225 | |
| 1226 default: | |
| 1227 // MESSAGE is handled separately. | |
| 1228 assert(false); | |
| 1229 return ""; | |
| 1230 } | |
| 1231 } | 1375 } |
| 1232 | 1376 |
| 1233 // We use this to implement the semantics that same file can be generated | 1377 // We use this to implement the semantics that same file can be generated |
| 1234 // multiple times, but the last one wins. We never actually write the files, | 1378 // multiple times, but the last one wins. We never actually write the files, |
| 1235 // but we keep a set of which descriptors were the final one for a given | 1379 // but we keep a set of which descriptors were the final one for a given |
| 1236 // filename. | 1380 // filename. |
| 1237 class FileDeduplicator { | 1381 class FileDeduplicator { |
| 1238 public: | 1382 public: |
| 1239 explicit FileDeduplicator(const GeneratorOptions& options) | 1383 explicit FileDeduplicator(const GeneratorOptions& options) |
| 1240 : error_on_conflict_(options.error_on_name_conflict) {} | 1384 : error_on_conflict_(options.error_on_name_conflict) {} |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1401 } | 1545 } |
| 1402 | 1546 |
| 1403 printer->Print("\n"); | 1547 printer->Print("\n"); |
| 1404 } | 1548 } |
| 1405 | 1549 |
| 1406 void Generator::FindProvidesForMessage( | 1550 void Generator::FindProvidesForMessage( |
| 1407 const GeneratorOptions& options, | 1551 const GeneratorOptions& options, |
| 1408 io::Printer* printer, | 1552 io::Printer* printer, |
| 1409 const Descriptor* desc, | 1553 const Descriptor* desc, |
| 1410 std::set<string>* provided) const { | 1554 std::set<string>* provided) const { |
| 1555 if (IgnoreMessage(options, desc)) { |
| 1556 return; |
| 1557 } |
| 1558 |
| 1411 string name = GetPath(options, desc); | 1559 string name = GetPath(options, desc); |
| 1412 provided->insert(name); | 1560 provided->insert(name); |
| 1413 | 1561 |
| 1414 for (int i = 0; i < desc->enum_type_count(); i++) { | 1562 for (int i = 0; i < desc->enum_type_count(); i++) { |
| 1415 FindProvidesForEnum(options, printer, desc->enum_type(i), | 1563 FindProvidesForEnum(options, printer, desc->enum_type(i), |
| 1416 provided); | 1564 provided); |
| 1417 } | 1565 } |
| 1418 for (int i = 0; i < desc->nested_type_count(); i++) { | 1566 for (int i = 0; i < desc->nested_type_count(); i++) { |
| 1419 FindProvidesForMessage(options, printer, desc->nested_type(i), | 1567 FindProvidesForMessage(options, printer, desc->nested_type(i), |
| 1420 provided); | 1568 provided); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1435 const vector<const FieldDescriptor*>& fields, | 1583 const vector<const FieldDescriptor*>& fields, |
| 1436 std::set<string>* provided) const { | 1584 std::set<string>* provided) const { |
| 1437 for (int i = 0; i < fields.size(); i++) { | 1585 for (int i = 0; i < fields.size(); i++) { |
| 1438 const FieldDescriptor* field = fields[i]; | 1586 const FieldDescriptor* field = fields[i]; |
| 1439 | 1587 |
| 1440 if (IgnoreField(field)) { | 1588 if (IgnoreField(field)) { |
| 1441 continue; | 1589 continue; |
| 1442 } | 1590 } |
| 1443 | 1591 |
| 1444 string name = | 1592 string name = |
| 1445 GetPath(options, field->file()) + "." + JSObjectFieldName(field); | 1593 GetPath(options, field->file()) + "." + |
| 1594 JSObjectFieldName(options, field); |
| 1446 provided->insert(name); | 1595 provided->insert(name); |
| 1447 } | 1596 } |
| 1448 } | 1597 } |
| 1449 | 1598 |
| 1450 void Generator::GenerateProvides(const GeneratorOptions& options, | 1599 void Generator::GenerateProvides(const GeneratorOptions& options, |
| 1451 io::Printer* printer, | 1600 io::Printer* printer, |
| 1452 std::set<string>* provided) const { | 1601 std::set<string>* provided) const { |
| 1453 for (std::set<string>::iterator it = provided->begin(); | 1602 for (std::set<string>::iterator it = provided->begin(); |
| 1454 it != provided->end(); ++it) { | 1603 it != provided->end(); ++it) { |
| 1455 printer->Print("goog.provide('$name$');\n", | 1604 if (options.import_style == GeneratorOptions::kImportClosure) { |
| 1456 "name", *it); | 1605 printer->Print("goog.provide('$name$');\n", "name", *it); |
| 1606 } else { |
| 1607 // We aren't using Closure's import system, but we use goog.exportSymbol() |
| 1608 // to construct the expected tree of objects, eg. |
| 1609 // |
| 1610 // goog.exportSymbol('foo.bar.Baz', null, this); |
| 1611 // |
| 1612 // // Later generated code expects foo.bar = {} to exist: |
| 1613 // foo.bar.Baz = function() { /* ... */ } |
| 1614 printer->Print("goog.exportSymbol('$name$', null, global);\n", "name", |
| 1615 *it); |
| 1616 } |
| 1457 } | 1617 } |
| 1458 } | 1618 } |
| 1459 | 1619 |
| 1460 void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, | 1620 void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, |
| 1461 io::Printer* printer, | 1621 io::Printer* printer, |
| 1462 const Descriptor* desc, | 1622 const Descriptor* desc, |
| 1463 std::set<string>* provided) const { | 1623 std::set<string>* provided) const { |
| 1464 std::set<string> required; | 1624 std::set<string> required; |
| 1465 std::set<string> forwards; | 1625 std::set<string> forwards; |
| 1466 bool have_message = false; | 1626 bool have_message = false; |
| 1467 FindRequiresForMessage(options, desc, | 1627 FindRequiresForMessage(options, desc, |
| 1468 &required, &forwards, &have_message); | 1628 &required, &forwards, &have_message); |
| 1469 | 1629 |
| 1470 GenerateRequiresImpl(options, printer, &required, &forwards, provided, | 1630 GenerateRequiresImpl(options, printer, &required, &forwards, provided, |
| 1471 /* require_jspb = */ have_message, | 1631 /* require_jspb = */ have_message, |
| 1472 /* require_extension = */ HasExtensions(desc)); | 1632 /* require_extension = */ HasExtensions(desc)); |
| 1473 } | 1633 } |
| 1474 | 1634 |
| 1475 void Generator::GenerateRequiresForLibrary( | 1635 void Generator::GenerateRequiresForLibrary( |
| 1476 const GeneratorOptions& options, io::Printer* printer, | 1636 const GeneratorOptions& options, io::Printer* printer, |
| 1477 const vector<const FileDescriptor*>& files, | 1637 const vector<const FileDescriptor*>& files, |
| 1478 std::set<string>* provided) const { | 1638 std::set<string>* provided) const { |
| 1479 GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE); | 1639 GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::kImportClosure); |
| 1480 // For Closure imports we need to import every message type individually. | 1640 // For Closure imports we need to import every message type individually. |
| 1481 std::set<string> required; | 1641 std::set<string> required; |
| 1482 std::set<string> forwards; | 1642 std::set<string> forwards; |
| 1483 bool have_extensions = false; | 1643 bool have_extensions = false; |
| 1484 bool have_message = false; | 1644 bool have_message = false; |
| 1485 | 1645 |
| 1486 for (int i = 0; i < files.size(); i++) { | 1646 for (int i = 0; i < files.size(); i++) { |
| 1487 for (int j = 0; j < files[i]->message_type_count(); j++) { | 1647 for (int j = 0; j < files[i]->message_type_count(); j++) { |
| 1488 FindRequiresForMessage(options, | 1648 const Descriptor* desc = files[i]->message_type(j); |
| 1489 files[i]->message_type(j), | 1649 if (!IgnoreMessage(options, desc)) { |
| 1490 &required, &forwards, &have_message); | 1650 FindRequiresForMessage(options, desc, &required, &forwards, |
| 1651 &have_message); |
| 1652 } |
| 1491 } | 1653 } |
| 1654 |
| 1492 if (!have_extensions && HasExtensions(files[i])) { | 1655 if (!have_extensions && HasExtensions(files[i])) { |
| 1493 have_extensions = true; | 1656 have_extensions = true; |
| 1494 } | 1657 } |
| 1495 | 1658 |
| 1496 for (int j = 0; j < files[i]->extension_count(); j++) { | 1659 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 1497 const FieldDescriptor* extension = files[i]->extension(j); | 1660 const FieldDescriptor* extension = files[i]->extension(j); |
| 1498 if (IgnoreField(extension)) { | 1661 if (IgnoreField(extension)) { |
| 1499 continue; | 1662 continue; |
| 1500 } | 1663 } |
| 1501 if (extension->containing_type()->full_name() != | 1664 if (extension->containing_type()->full_name() != |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1541 if (require_jspb) { | 1704 if (require_jspb) { |
| 1542 printer->Print( | 1705 printer->Print( |
| 1543 "goog.require('jspb.Message');\n"); | 1706 "goog.require('jspb.Message');\n"); |
| 1544 if (options.binary) { | 1707 if (options.binary) { |
| 1545 printer->Print( | 1708 printer->Print( |
| 1546 "goog.require('jspb.BinaryReader');\n" | 1709 "goog.require('jspb.BinaryReader');\n" |
| 1547 "goog.require('jspb.BinaryWriter');\n"); | 1710 "goog.require('jspb.BinaryWriter');\n"); |
| 1548 } | 1711 } |
| 1549 } | 1712 } |
| 1550 if (require_extension) { | 1713 if (require_extension) { |
| 1714 if (options.binary) { |
| 1715 printer->Print( |
| 1716 "goog.require('jspb.ExtensionFieldBinaryInfo');\n"); |
| 1717 } |
| 1551 printer->Print( | 1718 printer->Print( |
| 1552 "goog.require('jspb.ExtensionFieldInfo');\n"); | 1719 "goog.require('jspb.ExtensionFieldInfo');\n"); |
| 1553 } | 1720 } |
| 1554 | 1721 |
| 1555 std::set<string>::iterator it; | 1722 std::set<string>::iterator it; |
| 1556 for (it = required->begin(); it != required->end(); ++it) { | 1723 for (it = required->begin(); it != required->end(); ++it) { |
| 1557 if (provided->find(*it) != provided->end()) { | 1724 if (provided->find(*it) != provided->end()) { |
| 1558 continue; | 1725 continue; |
| 1559 } | 1726 } |
| 1560 printer->Print("goog.require('$name$');\n", | 1727 printer->Print("goog.require('$name$');\n", |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1616 if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && | 1783 if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM && |
| 1617 // N.B.: file-level extensions with enum type do *not* create | 1784 // N.B.: file-level extensions with enum type do *not* create |
| 1618 // dependencies, as per original codegen. | 1785 // dependencies, as per original codegen. |
| 1619 !(field->is_extension() && field->extension_scope() == NULL)) { | 1786 !(field->is_extension() && field->extension_scope() == NULL)) { |
| 1620 if (options.add_require_for_enums) { | 1787 if (options.add_require_for_enums) { |
| 1621 required->insert(GetPath(options, field->enum_type())); | 1788 required->insert(GetPath(options, field->enum_type())); |
| 1622 } else { | 1789 } else { |
| 1623 forwards->insert(GetPath(options, field->enum_type())); | 1790 forwards->insert(GetPath(options, field->enum_type())); |
| 1624 } | 1791 } |
| 1625 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 1792 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 1626 required->insert(GetPath(options, field->message_type())); | 1793 if (!IgnoreMessage(options, field->message_type())) { |
| 1794 required->insert(GetPath(options, field->message_type())); |
| 1795 } |
| 1627 } | 1796 } |
| 1628 } | 1797 } |
| 1629 | 1798 |
| 1630 void Generator::FindRequiresForExtension(const GeneratorOptions& options, | 1799 void Generator::FindRequiresForExtension(const GeneratorOptions& options, |
| 1631 const FieldDescriptor* field, | 1800 const FieldDescriptor* field, |
| 1632 std::set<string>* required, | 1801 std::set<string>* required, |
| 1633 std::set<string>* forwards) const { | 1802 std::set<string>* forwards) const { |
| 1634 if (field->containing_type()->full_name() != "google.protobuf.bridge.Message
Set") { | 1803 if (field->containing_type()->full_name() != "google.protobuf.bridge.Message
Set") { |
| 1635 required->insert(GetPath(options, field->containing_type())); | 1804 required->insert(GetPath(options, field->containing_type())); |
| 1636 } | 1805 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1652 GenerateClass(options, printer, file->message_type(i)); | 1821 GenerateClass(options, printer, file->message_type(i)); |
| 1653 } | 1822 } |
| 1654 for (int i = 0; i < file->enum_type_count(); i++) { | 1823 for (int i = 0; i < file->enum_type_count(); i++) { |
| 1655 GenerateEnum(options, printer, file->enum_type(i)); | 1824 GenerateEnum(options, printer, file->enum_type(i)); |
| 1656 } | 1825 } |
| 1657 } | 1826 } |
| 1658 | 1827 |
| 1659 void Generator::GenerateClass(const GeneratorOptions& options, | 1828 void Generator::GenerateClass(const GeneratorOptions& options, |
| 1660 io::Printer* printer, | 1829 io::Printer* printer, |
| 1661 const Descriptor* desc) const { | 1830 const Descriptor* desc) const { |
| 1831 if (IgnoreMessage(options, desc)) { |
| 1832 return; |
| 1833 } |
| 1834 |
| 1662 if (!NamespaceOnly(desc)) { | 1835 if (!NamespaceOnly(desc)) { |
| 1663 printer->Print("\n"); | 1836 printer->Print("\n"); |
| 1664 GenerateClassConstructor(options, printer, desc); | 1837 GenerateClassConstructor(options, printer, desc); |
| 1665 GenerateClassFieldInfo(options, printer, desc); | 1838 GenerateClassFieldInfo(options, printer, desc); |
| 1666 | 1839 |
| 1667 | 1840 |
| 1668 GenerateClassToObject(options, printer, desc); | 1841 GenerateClassToObject(options, printer, desc); |
| 1669 if (options.binary) { | 1842 if (options.binary) { |
| 1670 // These must come *before* the extension-field info generation in | 1843 // These must come *before* the extension-field info generation in |
| 1671 // GenerateClassRegistration so that references to the binary | 1844 // GenerateClassRegistration so that references to the binary |
| 1672 // serialization/deserialization functions may be placed in the extension | 1845 // serialization/deserialization functions may be placed in the extension |
| 1673 // objects. | 1846 // objects. |
| 1674 GenerateClassDeserializeBinary(options, printer, desc); | 1847 GenerateClassDeserializeBinary(options, printer, desc); |
| 1675 GenerateClassSerializeBinary(options, printer, desc); | 1848 GenerateClassSerializeBinary(options, printer, desc); |
| 1676 } | 1849 } |
| 1677 GenerateClassClone(options, printer, desc); | |
| 1678 GenerateClassRegistration(options, printer, desc); | 1850 GenerateClassRegistration(options, printer, desc); |
| 1679 GenerateClassFields(options, printer, desc); | 1851 GenerateClassFields(options, printer, desc); |
| 1680 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa
geSet") { | 1852 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa
geSet") { |
| 1681 GenerateClassExtensionFieldInfo(options, printer, desc); | 1853 GenerateClassExtensionFieldInfo(options, printer, desc); |
| 1682 } | 1854 } |
| 1683 | 1855 |
| 1684 if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) { | 1856 if (options.import_style != GeneratorOptions::kImportClosure) { |
| 1685 for (int i = 0; i < desc->extension_count(); i++) { | 1857 for (int i = 0; i < desc->extension_count(); i++) { |
| 1686 GenerateExtension(options, printer, desc->extension(i)); | 1858 GenerateExtension(options, printer, desc->extension(i)); |
| 1687 } | 1859 } |
| 1688 } | 1860 } |
| 1689 } | 1861 } |
| 1690 | 1862 |
| 1691 // Recurse on nested types. | 1863 // Recurse on nested types. |
| 1692 for (int i = 0; i < desc->enum_type_count(); i++) { | 1864 for (int i = 0; i < desc->enum_type_count(); i++) { |
| 1693 GenerateEnum(options, printer, desc->enum_type(i)); | 1865 GenerateEnum(options, printer, desc->enum_type(i)); |
| 1694 } | 1866 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1732 "goog.inherits($classname$, jspb.Message);\n" | 1904 "goog.inherits($classname$, jspb.Message);\n" |
| 1733 "if (goog.DEBUG && !COMPILED) {\n" | 1905 "if (goog.DEBUG && !COMPILED) {\n" |
| 1734 " $classname$.displayName = '$classname$';\n" | 1906 " $classname$.displayName = '$classname$';\n" |
| 1735 "}\n", | 1907 "}\n", |
| 1736 "classname", GetPath(options, desc)); | 1908 "classname", GetPath(options, desc)); |
| 1737 } | 1909 } |
| 1738 | 1910 |
| 1739 void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, | 1911 void Generator::GenerateClassFieldInfo(const GeneratorOptions& options, |
| 1740 io::Printer* printer, | 1912 io::Printer* printer, |
| 1741 const Descriptor* desc) const { | 1913 const Descriptor* desc) const { |
| 1742 if (HasRepeatedFields(desc)) { | 1914 if (HasRepeatedFields(options, desc)) { |
| 1743 printer->Print( | 1915 printer->Print( |
| 1744 "/**\n" | 1916 "/**\n" |
| 1745 " * List of repeated fields within this message type.\n" | 1917 " * List of repeated fields within this message type.\n" |
| 1746 " * @private {!Array<number>}\n" | 1918 " * @private {!Array<number>}\n" |
| 1747 " * @const\n" | 1919 " * @const\n" |
| 1748 " */\n" | 1920 " */\n" |
| 1749 "$classname$$rptfieldarray$ = $rptfields$;\n" | 1921 "$classname$$rptfieldarray$ = $rptfields$;\n" |
| 1750 "\n", | 1922 "\n", |
| 1751 "classname", GetPath(options, desc), | 1923 "classname", GetPath(options, desc), |
| 1752 "rptfieldarray", kRepeatedFieldArrayName, | 1924 "rptfieldarray", kRepeatedFieldArrayName, |
| 1753 "rptfields", RepeatedFieldNumberList(desc)); | 1925 "rptfields", RepeatedFieldNumberList(options, desc)); |
| 1754 } | 1926 } |
| 1755 | 1927 |
| 1756 if (HasOneofFields(desc)) { | 1928 if (HasOneofFields(desc)) { |
| 1757 printer->Print( | 1929 printer->Print( |
| 1758 "/**\n" | 1930 "/**\n" |
| 1759 " * Oneof group definitions for this message. Each group defines the " | 1931 " * Oneof group definitions for this message. Each group defines the " |
| 1760 "field\n" | 1932 "field\n" |
| 1761 " * numbers belonging to that group. When of these fields' value is " | 1933 " * numbers belonging to that group. When of these fields' value is " |
| 1762 "set, all\n" | 1934 "set, all\n" |
| 1763 " * other fields in the group are cleared. During deserialization, if " | 1935 " * other fields in the group are cleared. During deserialization, if " |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1912 " obj.$$jspbMessageInstance = msg;\n" | 2084 " obj.$$jspbMessageInstance = msg;\n" |
| 1913 " }\n" | 2085 " }\n" |
| 1914 " return obj;\n" | 2086 " return obj;\n" |
| 1915 "};\n" | 2087 "};\n" |
| 1916 "}\n" | 2088 "}\n" |
| 1917 "\n" | 2089 "\n" |
| 1918 "\n", | 2090 "\n", |
| 1919 "classname", GetPath(options, desc)); | 2091 "classname", GetPath(options, desc)); |
| 1920 } | 2092 } |
| 1921 | 2093 |
| 2094 void Generator::GenerateFieldValueExpression(io::Printer* printer, |
| 2095 const char *obj_reference, |
| 2096 const FieldDescriptor* field, |
| 2097 bool use_default) const { |
| 2098 bool is_float_or_double = |
| 2099 field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || |
| 2100 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE; |
| 2101 if (use_default) { |
| 2102 if (is_float_or_double) { |
| 2103 // Coerce "Nan" and "Infinity" to actual float values. |
| 2104 // |
| 2105 // This will change null to 0, but that doesn't matter since we're getting |
| 2106 // with a default. |
| 2107 printer->Print("+"); |
| 2108 } |
| 2109 |
| 2110 printer->Print( |
| 2111 "jspb.Message.getFieldWithDefault($obj$, $index$, $default$)", |
| 2112 "obj", obj_reference, |
| 2113 "index", JSFieldIndex(field), |
| 2114 "default", JSFieldDefault(field)); |
| 2115 } else { |
| 2116 if (is_float_or_double) { |
| 2117 if (field->is_required()) { |
| 2118 // Use "+" to convert all fields to numeric (including null). |
| 2119 printer->Print( |
| 2120 "+jspb.Message.getField($obj$, $index$)", |
| 2121 "index", JSFieldIndex(field), |
| 2122 "obj", obj_reference); |
| 2123 } else { |
| 2124 // Converts "NaN" and "Infinity" while preserving null. |
| 2125 printer->Print( |
| 2126 "jspb.Message.get$cardinality$FloatingPointField($obj$, $index$)", |
| 2127 "cardinality", field->is_repeated() ? "Repeated" : "Optional", |
| 2128 "index", JSFieldIndex(field), |
| 2129 "obj", obj_reference); |
| 2130 } |
| 2131 } else { |
| 2132 printer->Print("jspb.Message.getField($obj$, $index$)", |
| 2133 "index", JSFieldIndex(field), |
| 2134 "obj", obj_reference); |
| 2135 } |
| 2136 } |
| 2137 } |
| 2138 |
| 1922 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, | 2139 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, |
| 1923 io::Printer* printer, | 2140 io::Printer* printer, |
| 1924 const FieldDescriptor* field) const { | 2141 const FieldDescriptor* field) const { |
| 1925 printer->Print("$fieldname$: ", | 2142 printer->Print("$fieldname$: ", |
| 1926 "fieldname", JSObjectFieldName(field)); | 2143 "fieldname", JSObjectFieldName(options, field)); |
| 1927 | 2144 |
| 1928 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 2145 if (IsMap(options, field)) { |
| 2146 printer->Print("(f = msg.get$name$()) ? f.toArray() : []", |
| 2147 "name", JSGetterName(options, field)); |
| 2148 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 1929 // Message field. | 2149 // Message field. |
| 1930 if (field->is_repeated()) { | 2150 if (field->is_repeated()) { |
| 1931 { | 2151 { |
| 1932 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" | 2152 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" |
| 1933 " $type$.toObject, includeInstance)", | 2153 " $type$.toObject, includeInstance)", |
| 1934 "getter", JSGetterName(field), | 2154 "getter", JSGetterName(options, field), |
| 1935 "type", SubmessageTypeRef(options, field)); | 2155 "type", SubmessageTypeRef(options, field)); |
| 1936 } | 2156 } |
| 1937 } else { | 2157 } else { |
| 1938 printer->Print("(f = msg.get$getter$()) && " | 2158 printer->Print("(f = msg.get$getter$()) && " |
| 1939 "$type$.toObject(includeInstance, f)", | 2159 "$type$.toObject(includeInstance, f)", |
| 1940 "getter", JSGetterName(field), | 2160 "getter", JSGetterName(options, field), |
| 1941 "type", SubmessageTypeRef(options, field)); | 2161 "type", SubmessageTypeRef(options, field)); |
| 1942 } | 2162 } |
| 2163 } else if (field->type() == FieldDescriptor::TYPE_BYTES) { |
| 2164 // For bytes fields we want to always return the B64 data. |
| 2165 printer->Print("msg.get$getter$()", |
| 2166 "getter", JSGetterName(options, field, BYTES_B64)); |
| 1943 } else { | 2167 } else { |
| 1944 // Simple field (singular or repeated). | 2168 bool use_default = field->has_default_value(); |
| 1945 if ((!HasFieldPresence(field) && !field->is_repeated()) || | 2169 |
| 1946 field->type() == FieldDescriptor::TYPE_BYTES) { | 2170 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && |
| 1947 // Delegate to the generated get<field>() method in order not to duplicate | 2171 // Repeated fields get initialized to their default in the constructor |
| 1948 // the proto3-field-default-value or byte-coercion logic here. | 2172 // (why?), so we emit a plain getField() call for them. |
| 1949 printer->Print("msg.get$getter$()", | 2173 !field->is_repeated() && !UseBrokenPresenceSemantics(options, field)) { |
| 1950 "getter", JSGetterName(field, BYTES_B64)); | 2174 // Proto3 puts all defaults (including implicit defaults) in toObject(). |
| 1951 } else { | 2175 // But for proto2 we leave the existing semantics unchanged: unset fields |
| 1952 if (field->has_default_value()) { | 2176 // without default are unset. |
| 1953 printer->Print("jspb.Message.getField(msg, $index$) == null ? " | 2177 use_default = true; |
| 1954 "$defaultValue$ : ", | |
| 1955 "index", JSFieldIndex(field), | |
| 1956 "defaultValue", JSFieldDefault(field)); | |
| 1957 } | |
| 1958 if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || | |
| 1959 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { | |
| 1960 if (field->is_repeated()) { | |
| 1961 printer->Print("jspb.Message.getRepeatedFloatingPointField(" | |
| 1962 "msg, $index$)", | |
| 1963 "index", JSFieldIndex(field)); | |
| 1964 } else if (field->is_optional() && !field->has_default_value()) { | |
| 1965 printer->Print("jspb.Message.getOptionalFloatingPointField(" | |
| 1966 "msg, $index$)", | |
| 1967 "index", JSFieldIndex(field)); | |
| 1968 } else { | |
| 1969 // Convert "NaN" to NaN. | |
| 1970 printer->Print("+jspb.Message.getField(msg, $index$)", | |
| 1971 "index", JSFieldIndex(field)); | |
| 1972 } | |
| 1973 } else { | |
| 1974 printer->Print("jspb.Message.getField(msg, $index$)", | |
| 1975 "index", JSFieldIndex(field)); | |
| 1976 } | |
| 1977 } | 2178 } |
| 2179 |
| 2180 // We don't implement this by calling the accessors, because the semantics |
| 2181 // of the accessors are changing independently of the toObject() semantics. |
| 2182 // We are migrating the accessors to return defaults instead of null, but |
| 2183 // it may take longer to migrate toObject (or we might not want to do it at |
| 2184 // all). So we want to generate independent code. |
| 2185 GenerateFieldValueExpression(printer, "msg", field, use_default); |
| 1978 } | 2186 } |
| 1979 } | 2187 } |
| 1980 | 2188 |
| 1981 void Generator::GenerateClassFromObject(const GeneratorOptions& options, | 2189 void Generator::GenerateClassFromObject(const GeneratorOptions& options, |
| 1982 io::Printer* printer, | 2190 io::Printer* printer, |
| 1983 const Descriptor* desc) const { | 2191 const Descriptor* desc) const { |
| 1984 printer->Print( | 2192 printer->Print( |
| 1985 "if (jspb.Message.GENERATE_FROM_OBJECT) {\n" | 2193 "if (jspb.Message.GENERATE_FROM_OBJECT) {\n" |
| 1986 "/**\n" | 2194 "/**\n" |
| 1987 " * Loads data from an object into a new instance of this proto.\n" | 2195 " * Loads data from an object into a new instance of this proto.\n" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2001 printer->Print( | 2209 printer->Print( |
| 2002 " return msg;\n" | 2210 " return msg;\n" |
| 2003 "};\n" | 2211 "};\n" |
| 2004 "}\n"); | 2212 "}\n"); |
| 2005 } | 2213 } |
| 2006 | 2214 |
| 2007 void Generator::GenerateClassFieldFromObject( | 2215 void Generator::GenerateClassFieldFromObject( |
| 2008 const GeneratorOptions& options, | 2216 const GeneratorOptions& options, |
| 2009 io::Printer* printer, | 2217 io::Printer* printer, |
| 2010 const FieldDescriptor* field) const { | 2218 const FieldDescriptor* field) const { |
| 2011 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 2219 if (IsMap(options, field)) { |
| 2220 // `msg` is a newly-constructed message object that has not yet built any |
| 2221 // map containers wrapping underlying arrays, so we can simply directly set |
| 2222 // the array here without fear of a stale wrapper. |
| 2223 printer->Print( |
| 2224 " goog.isDef(obj.$name$) && " |
| 2225 "jspb.Message.setField(msg, $index$, obj.$name$);\n", |
| 2226 "name", JSObjectFieldName(options, field), |
| 2227 "index", JSFieldIndex(field)); |
| 2228 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2012 // Message field (singular or repeated) | 2229 // Message field (singular or repeated) |
| 2013 if (field->is_repeated()) { | 2230 if (field->is_repeated()) { |
| 2014 { | 2231 { |
| 2015 printer->Print( | 2232 printer->Print( |
| 2016 " goog.isDef(obj.$name$) && " | 2233 " goog.isDef(obj.$name$) && " |
| 2017 "jspb.Message.setRepeatedWrapperField(\n" | 2234 "jspb.Message.setRepeatedWrapperField(\n" |
| 2018 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" | 2235 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" |
| 2019 " return $fieldclass$.fromObject(i);\n" | 2236 " return $fieldclass$.fromObject(i);\n" |
| 2020 " }));\n", | 2237 " }));\n", |
| 2021 "name", JSObjectFieldName(field), | 2238 "name", JSObjectFieldName(options, field), |
| 2022 "index", JSFieldIndex(field), | 2239 "index", JSFieldIndex(field), |
| 2023 "fieldclass", SubmessageTypeRef(options, field)); | 2240 "fieldclass", SubmessageTypeRef(options, field)); |
| 2024 } | 2241 } |
| 2025 } else { | 2242 } else { |
| 2026 printer->Print( | 2243 printer->Print( |
| 2027 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" | 2244 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" |
| 2028 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", | 2245 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", |
| 2029 "name", JSObjectFieldName(field), | 2246 "name", JSObjectFieldName(options, field), |
| 2030 "index", JSFieldIndex(field), | 2247 "index", JSFieldIndex(field), |
| 2031 "fieldclass", SubmessageTypeRef(options, field)); | 2248 "fieldclass", SubmessageTypeRef(options, field)); |
| 2032 } | 2249 } |
| 2033 } else { | 2250 } else { |
| 2034 // Simple (primitive) field. | 2251 // Simple (primitive) field. |
| 2035 printer->Print( | 2252 printer->Print( |
| 2036 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " | 2253 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " |
| 2037 "obj.$name$);\n", | 2254 "obj.$name$);\n", |
| 2038 "name", JSObjectFieldName(field), | 2255 "name", JSObjectFieldName(options, field), |
| 2039 "index", JSFieldIndex(field)); | 2256 "index", JSFieldIndex(field)); |
| 2040 } | 2257 } |
| 2041 } | 2258 } |
| 2042 | 2259 |
| 2043 void Generator::GenerateClassClone(const GeneratorOptions& options, | |
| 2044 io::Printer* printer, | |
| 2045 const Descriptor* desc) const { | |
| 2046 printer->Print( | |
| 2047 "/**\n" | |
| 2048 " * Creates a deep clone of this proto. No data is shared with the " | |
| 2049 "original.\n" | |
| 2050 " * @return {!$name$} The clone.\n" | |
| 2051 " */\n" | |
| 2052 "$name$.prototype.cloneMessage = function() {\n" | |
| 2053 " return /** @type {!$name$} */ (jspb.Message.cloneMessage(this));\n" | |
| 2054 "};\n\n\n", | |
| 2055 "name", GetPath(options, desc)); | |
| 2056 } | |
| 2057 | |
| 2058 void Generator::GenerateClassRegistration(const GeneratorOptions& options, | 2260 void Generator::GenerateClassRegistration(const GeneratorOptions& options, |
| 2059 io::Printer* printer, | 2261 io::Printer* printer, |
| 2060 const Descriptor* desc) const { | 2262 const Descriptor* desc) const { |
| 2061 // Register any extensions defined inside this message type. | 2263 // Register any extensions defined inside this message type. |
| 2062 for (int i = 0; i < desc->extension_count(); i++) { | 2264 for (int i = 0; i < desc->extension_count(); i++) { |
| 2063 const FieldDescriptor* extension = desc->extension(i); | 2265 const FieldDescriptor* extension = desc->extension(i); |
| 2064 if (ShouldGenerateExtension(extension)) { | 2266 if (ShouldGenerateExtension(extension)) { |
| 2065 GenerateExtension(options, printer, extension); | 2267 GenerateExtension(options, printer, extension); |
| 2066 } | 2268 } |
| 2067 } | 2269 } |
| 2068 | 2270 |
| 2069 } | 2271 } |
| 2070 | 2272 |
| 2071 void Generator::GenerateClassFields(const GeneratorOptions& options, | 2273 void Generator::GenerateClassFields(const GeneratorOptions& options, |
| 2072 io::Printer* printer, | 2274 io::Printer* printer, |
| 2073 const Descriptor* desc) const { | 2275 const Descriptor* desc) const { |
| 2074 for (int i = 0; i < desc->field_count(); i++) { | 2276 for (int i = 0; i < desc->field_count(); i++) { |
| 2075 if (!IgnoreField(desc->field(i))) { | 2277 if (!IgnoreField(desc->field(i))) { |
| 2076 GenerateClassField(options, printer, desc->field(i)); | 2278 GenerateClassField(options, printer, desc->field(i)); |
| 2077 } | 2279 } |
| 2078 } | 2280 } |
| 2079 } | 2281 } |
| 2080 | 2282 |
| 2081 void GenerateBytesWrapper(const GeneratorOptions& options, | 2283 void GenerateBytesWrapper(const GeneratorOptions& options, |
| 2082 io::Printer* printer, | 2284 io::Printer* printer, |
| 2083 const FieldDescriptor* field, | 2285 const FieldDescriptor* field, |
| 2084 BytesMode bytes_mode) { | 2286 BytesMode bytes_mode) { |
| 2085 string type = | 2287 string type = JSFieldTypeAnnotation( |
| 2086 JSFieldTypeAnnotation(options, field, | 2288 options, field, |
| 2087 /* force_optional = */ false, | 2289 /* is_setter_argument = */ false, |
| 2088 /* force_present = */ !HasFieldPresence(field), | 2290 /* force_present = */ false, |
| 2089 /* singular_if_not_packed = */ false, | 2291 /* singular_if_not_packed = */ false, bytes_mode); |
| 2090 bytes_mode); | |
| 2091 printer->Print( | 2292 printer->Print( |
| 2092 "/**\n" | 2293 "/**\n" |
| 2093 " * $fielddef$\n" | 2294 " * $fielddef$\n" |
| 2094 "$comment$" | 2295 "$comment$" |
| 2095 " * This is a type-conversion wrapper around `get$defname$()`\n" | 2296 " * This is a type-conversion wrapper around `get$defname$()`\n" |
| 2096 " * @return {$type$}\n" | 2297 " * @return {$type$}\n" |
| 2097 " */\n" | 2298 " */\n" |
| 2098 "$class$.prototype.get$name$ = function() {\n" | 2299 "$class$.prototype.get$name$ = function() {\n" |
| 2099 " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" | 2300 " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" |
| 2100 " this.get$defname$()));\n" | 2301 " this.get$defname$()));\n" |
| 2101 "};\n" | 2302 "};\n" |
| 2102 "\n" | 2303 "\n" |
| 2103 "\n", | 2304 "\n", |
| 2104 "fielddef", FieldDefinition(options, field), | 2305 "fielddef", FieldDefinition(options, field), |
| 2105 "comment", FieldComments(field, bytes_mode), | 2306 "comment", FieldComments(field, bytes_mode), |
| 2106 "type", type, | 2307 "type", type, |
| 2107 "class", GetPath(options, field->containing_type()), | 2308 "class", GetPath(options, field->containing_type()), |
| 2108 "name", JSGetterName(field, bytes_mode), | 2309 "name", JSGetterName(options, field, bytes_mode), |
| 2109 "list", field->is_repeated() ? "List" : "", | 2310 "list", field->is_repeated() ? "List" : "", |
| 2110 "suffix", JSByteGetterSuffix(bytes_mode), | 2311 "suffix", JSByteGetterSuffix(bytes_mode), |
| 2111 "defname", JSGetterName(field, BYTES_DEFAULT)); | 2312 "defname", JSGetterName(options, field, BYTES_DEFAULT)); |
| 2112 } | 2313 } |
| 2113 | 2314 |
| 2114 | 2315 |
| 2115 void Generator::GenerateClassField(const GeneratorOptions& options, | 2316 void Generator::GenerateClassField(const GeneratorOptions& options, |
| 2116 io::Printer* printer, | 2317 io::Printer* printer, |
| 2117 const FieldDescriptor* field) const { | 2318 const FieldDescriptor* field) const { |
| 2118 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 2319 if (IsMap(options, field)) { |
| 2320 const FieldDescriptor* key_field = MapFieldKey(field); |
| 2321 const FieldDescriptor* value_field = MapFieldValue(field); |
| 2322 // Map field: special handling to instantiate the map object on demand. |
| 2323 string key_type = |
| 2324 JSFieldTypeAnnotation( |
| 2325 options, key_field, |
| 2326 /* is_setter_argument = */ false, |
| 2327 /* force_present = */ true, |
| 2328 /* singular_if_not_packed = */ false); |
| 2329 string value_type = |
| 2330 JSFieldTypeAnnotation( |
| 2331 options, value_field, |
| 2332 /* is_setter_argument = */ false, |
| 2333 /* force_present = */ true, |
| 2334 /* singular_if_not_packed = */ false); |
| 2335 |
| 2119 printer->Print( | 2336 printer->Print( |
| 2120 "/**\n" | 2337 "/**\n" |
| 2121 " * $fielddef$\n" | 2338 " * $fielddef$\n" |
| 2339 " * @param {boolean=} opt_noLazyCreate Do not create the map if\n" |
| 2340 " * empty, instead returning `undefined`\n" |
| 2341 " * @return {!jspb.Map<$keytype$,$valuetype$>}\n" |
| 2342 " */\n", |
| 2343 "fielddef", FieldDefinition(options, field), |
| 2344 "keytype", key_type, |
| 2345 "valuetype", value_type); |
| 2346 printer->Print( |
| 2347 "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n" |
| 2348 " return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n", |
| 2349 "class", GetPath(options, field->containing_type()), |
| 2350 "name", JSGetterName(options, field), |
| 2351 "keytype", key_type, |
| 2352 "valuetype", value_type); |
| 2353 printer->Print( |
| 2354 " jspb.Message.getMapField(this, $index$, opt_noLazyCreate", |
| 2355 "index", JSFieldIndex(field)); |
| 2356 |
| 2357 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 2358 printer->Print(",\n" |
| 2359 " $messageType$", |
| 2360 "messageType", GetPath(options, value_field->message_type())); |
| 2361 } else if (options.binary) { |
| 2362 printer->Print(",\n" |
| 2363 " null"); |
| 2364 } |
| 2365 |
| 2366 printer->Print( |
| 2367 "));\n"); |
| 2368 |
| 2369 printer->Print( |
| 2370 "};\n" |
| 2371 "\n" |
| 2372 "\n"); |
| 2373 } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2374 // Message field: special handling in order to wrap the underlying data |
| 2375 // array with a message object. |
| 2376 |
| 2377 printer->Print( |
| 2378 "/**\n" |
| 2379 " * $fielddef$\n" |
| 2122 "$comment$" | 2380 "$comment$" |
| 2123 " * @return {$type$}\n" | 2381 " * @return {$type$}\n" |
| 2124 " */\n", | 2382 " */\n", |
| 2125 "fielddef", FieldDefinition(options, field), | 2383 "fielddef", FieldDefinition(options, field), |
| 2126 "comment", FieldComments(field, BYTES_DEFAULT), | 2384 "comment", FieldComments(field, BYTES_DEFAULT), |
| 2127 "type", JSFieldTypeAnnotation(options, field, | 2385 "type", JSFieldTypeAnnotation(options, field, |
| 2128 /* force_optional = */ false, | 2386 /* is_setter_argument = */ false, |
| 2129 /* force_present = */ false, | 2387 /* force_present = */ false, |
| 2130 /* singular_if_not_packed = */ false)); | 2388 /* singular_if_not_packed = */ false)); |
| 2131 printer->Print( | 2389 printer->Print( |
| 2132 "$class$.prototype.get$name$ = function() {\n" | 2390 "$class$.prototype.get$name$ = function() {\n" |
| 2133 " return /** @type{$type$} */ (\n" | 2391 " return /** @type{$type$} */ (\n" |
| 2134 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " | 2392 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " |
| 2135 "$index$$required$));\n" | 2393 "$index$$required$));\n" |
| 2136 "};\n" | 2394 "};\n" |
| 2137 "\n" | 2395 "\n" |
| 2138 "\n", | 2396 "\n", |
| 2139 "class", GetPath(options, field->containing_type()), | 2397 "class", GetPath(options, field->containing_type()), |
| 2140 "name", JSGetterName(field), | 2398 "name", JSGetterName(options, field), |
| 2141 "type", JSFieldTypeAnnotation(options, field, | 2399 "type", JSFieldTypeAnnotation(options, field, |
| 2142 /* force_optional = */ false, | 2400 /* is_setter_argument = */ false, |
| 2143 /* force_present = */ false, | 2401 /* force_present = */ false, |
| 2144 /* singular_if_not_packed = */ false), | 2402 /* singular_if_not_packed = */ false), |
| 2145 "rpt", (field->is_repeated() ? "Repeated" : ""), | 2403 "rpt", (field->is_repeated() ? "Repeated" : ""), |
| 2146 "index", JSFieldIndex(field), | 2404 "index", JSFieldIndex(field), |
| 2147 "wrapperclass", SubmessageTypeRef(options, field), | 2405 "wrapperclass", SubmessageTypeRef(options, field), |
| 2148 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? | 2406 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? |
| 2149 ", 1" : "")); | 2407 ", 1" : "")); |
| 2150 printer->Print( | 2408 printer->Print( |
| 2151 "/** @param {$optionaltype$} value $returndoc$ */\n" | 2409 "/** @param {$optionaltype$} value$returndoc$ */\n" |
| 2152 "$class$.prototype.set$name$ = function(value) {\n" | 2410 "$class$.prototype.set$name$ = function(value) {\n" |
| 2153 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", | 2411 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", |
| 2154 "optionaltype", | 2412 "optionaltype", |
| 2155 JSFieldTypeAnnotation(options, field, | 2413 JSFieldTypeAnnotation(options, field, |
| 2156 /* force_optional = */ true, | 2414 /* is_setter_argument = */ true, |
| 2157 /* force_present = */ false, | 2415 /* force_present = */ false, |
| 2158 /* singular_if_not_packed = */ false), | 2416 /* singular_if_not_packed = */ false), |
| 2159 "returndoc", JSReturnDoc(options, field), | 2417 "returndoc", JSReturnDoc(options, field), |
| 2160 "class", GetPath(options, field->containing_type()), | 2418 "class", GetPath(options, field->containing_type()), |
| 2161 "name", JSGetterName(field), | 2419 "name", JSGetterName(options, field), |
| 2162 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), | 2420 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), |
| 2163 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); | 2421 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); |
| 2164 | 2422 |
| 2165 printer->Print( | 2423 printer->Print( |
| 2166 "this, $index$$oneofgroup$, value);$returnvalue$\n" | 2424 "this, $index$$oneofgroup$, value);$returnvalue$\n" |
| 2167 "};\n" | 2425 "};\n" |
| 2168 "\n" | 2426 "\n" |
| 2169 "\n", | 2427 "\n", |
| 2170 "index", JSFieldIndex(field), | 2428 "index", JSFieldIndex(field), |
| 2171 "oneofgroup", (field->containing_oneof() ? | 2429 "oneofgroup", (field->containing_oneof() ? |
| 2172 (", " + JSOneofArray(options, field)) : ""), | 2430 (", " + JSOneofArray(options, field)) : ""), |
| 2173 "returnvalue", JSReturnClause(field)); | 2431 "returnvalue", JSReturnClause(field)); |
| 2174 | 2432 |
| 2175 printer->Print( | 2433 if (field->is_repeated()) { |
| 2176 "$class$.prototype.clear$name$ = function() {\n" | 2434 GenerateRepeatedMessageHelperMethods(options, printer, field); |
| 2177 " this.set$name$($clearedvalue$);$returnvalue$\n" | 2435 } |
| 2178 "};\n" | |
| 2179 "\n" | |
| 2180 "\n", | |
| 2181 "class", GetPath(options, field->containing_type()), | |
| 2182 "name", JSGetterName(field), | |
| 2183 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), | |
| 2184 "returnvalue", JSReturnClause(field)); | |
| 2185 | 2436 |
| 2186 } else { | 2437 } else { |
| 2187 bool untyped = | 2438 bool untyped = |
| 2188 false; | 2439 false; |
| 2189 | 2440 |
| 2190 // Simple (primitive) field, either singular or repeated. | 2441 // Simple (primitive) field, either singular or repeated. |
| 2191 | 2442 |
| 2192 // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; | 2443 // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; |
| 2193 // at this point we "lie" to non-binary users and tell the the return | 2444 // at this point we "lie" to non-binary users and tell the the return |
| 2194 // type is always base64 string, pending a LSC to migrate to typed getters. | 2445 // type is always base64 string, pending a LSC to migrate to typed getters. |
| 2195 BytesMode bytes_mode = | 2446 BytesMode bytes_mode = |
| 2196 field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? | 2447 field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? |
| 2197 BYTES_B64 : BYTES_DEFAULT; | 2448 BYTES_B64 : BYTES_DEFAULT; |
| 2198 string typed_annotation = | 2449 string typed_annotation = JSFieldTypeAnnotation( |
| 2199 JSFieldTypeAnnotation(options, field, | 2450 options, field, |
| 2200 /* force_optional = */ false, | 2451 /* is_setter_argument = */ false, |
| 2201 /* force_present = */ !HasFieldPresence(field), | 2452 /* force_present = */ false, |
| 2202 /* singular_if_not_packed = */ false, | 2453 /* singular_if_not_packed = */ false, |
| 2203 /* bytes_mode = */ bytes_mode); | 2454 /* bytes_mode = */ bytes_mode); |
| 2204 if (untyped) { | 2455 if (untyped) { |
| 2205 printer->Print( | 2456 printer->Print( |
| 2206 "/**\n" | 2457 "/**\n" |
| 2207 " * @return {?} Raw field, untyped.\n" | 2458 " * @return {?} Raw field, untyped.\n" |
| 2208 " */\n"); | 2459 " */\n"); |
| 2209 } else { | 2460 } else { |
| 2210 printer->Print( | 2461 printer->Print( |
| 2211 "/**\n" | 2462 "/**\n" |
| 2212 " * $fielddef$\n" | 2463 " * $fielddef$\n" |
| 2213 "$comment$" | 2464 "$comment$" |
| 2214 " * @return {$type$}\n" | 2465 " * @return {$type$}\n" |
| 2215 " */\n", | 2466 " */\n", |
| 2216 "fielddef", FieldDefinition(options, field), | 2467 "fielddef", FieldDefinition(options, field), |
| 2217 "comment", FieldComments(field, bytes_mode), | 2468 "comment", FieldComments(field, bytes_mode), |
| 2218 "type", typed_annotation); | 2469 "type", typed_annotation); |
| 2219 } | 2470 } |
| 2220 | 2471 |
| 2221 printer->Print( | 2472 printer->Print( |
| 2222 "$class$.prototype.get$name$ = function() {\n", | 2473 "$class$.prototype.get$name$ = function() {\n", |
| 2223 "class", GetPath(options, field->containing_type()), | 2474 "class", GetPath(options, field->containing_type()), |
| 2224 "name", JSGetterName(field)); | 2475 "name", JSGetterName(options, field)); |
| 2225 | 2476 |
| 2226 if (untyped) { | 2477 if (untyped) { |
| 2227 printer->Print( | 2478 printer->Print( |
| 2228 " return "); | 2479 " return "); |
| 2229 } else { | 2480 } else { |
| 2230 printer->Print( | 2481 printer->Print( |
| 2231 " return /** @type {$type$} */ (", | 2482 " return /** @type {$type$} */ (", |
| 2232 "type", typed_annotation); | 2483 "type", typed_annotation); |
| 2233 } | 2484 } |
| 2234 | 2485 |
| 2235 // For proto3 fields without presence, use special getters that will return | 2486 bool use_default = !ReturnsNullWhenUnset(options, field); |
| 2236 // defaults when the field is unset, possibly constructing a value if | 2487 |
| 2237 // required. | 2488 // Raw fields with no default set should just return undefined. |
| 2238 if (!HasFieldPresence(field) && !field->is_repeated()) { | 2489 if (untyped && !field->has_default_value()) { |
| 2239 printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)", | 2490 use_default = false; |
| 2240 "index", JSFieldIndex(field), | |
| 2241 "default", Proto3PrimitiveFieldDefault(field)); | |
| 2242 } else { | |
| 2243 if (field->has_default_value()) { | |
| 2244 printer->Print("jspb.Message.getField(this, $index$) == null ? " | |
| 2245 "$defaultValue$ : ", | |
| 2246 "index", JSFieldIndex(field), | |
| 2247 "defaultValue", JSFieldDefault(field)); | |
| 2248 } | |
| 2249 if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || | |
| 2250 field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { | |
| 2251 if (field->is_repeated()) { | |
| 2252 printer->Print("jspb.Message.getRepeatedFloatingPointField(" | |
| 2253 "this, $index$)", | |
| 2254 "index", JSFieldIndex(field)); | |
| 2255 } else if (field->is_optional() && !field->has_default_value()) { | |
| 2256 printer->Print("jspb.Message.getOptionalFloatingPointField(" | |
| 2257 "this, $index$)", | |
| 2258 "index", JSFieldIndex(field)); | |
| 2259 } else { | |
| 2260 // Convert "NaN" to NaN. | |
| 2261 printer->Print("+jspb.Message.getField(this, $index$)", | |
| 2262 "index", JSFieldIndex(field)); | |
| 2263 } | |
| 2264 } else { | |
| 2265 printer->Print("jspb.Message.getField(this, $index$)", | |
| 2266 "index", JSFieldIndex(field)); | |
| 2267 } | |
| 2268 } | 2491 } |
| 2269 | 2492 |
| 2493 // Repeated fields get initialized to their default in the constructor |
| 2494 // (why?), so we emit a plain getField() call for them. |
| 2495 if (field->is_repeated()) { |
| 2496 use_default = false; |
| 2497 } |
| 2498 |
| 2499 GenerateFieldValueExpression(printer, "this", field, use_default); |
| 2500 |
| 2270 if (untyped) { | 2501 if (untyped) { |
| 2271 printer->Print( | 2502 printer->Print( |
| 2272 ";\n" | 2503 ";\n" |
| 2273 "};\n" | 2504 "};\n" |
| 2274 "\n" | 2505 "\n" |
| 2275 "\n"); | 2506 "\n"); |
| 2276 } else { | 2507 } else { |
| 2277 printer->Print( | 2508 printer->Print( |
| 2278 ");\n" | 2509 ");\n" |
| 2279 "};\n" | 2510 "};\n" |
| 2280 "\n" | 2511 "\n" |
| 2281 "\n"); | 2512 "\n"); |
| 2282 } | 2513 } |
| 2283 | 2514 |
| 2284 if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { | 2515 if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { |
| 2285 GenerateBytesWrapper(options, printer, field, BYTES_B64); | 2516 GenerateBytesWrapper(options, printer, field, BYTES_B64); |
| 2286 GenerateBytesWrapper(options, printer, field, BYTES_U8); | 2517 GenerateBytesWrapper(options, printer, field, BYTES_U8); |
| 2287 } | 2518 } |
| 2288 | 2519 |
| 2289 if (untyped) { | 2520 if (untyped) { |
| 2290 printer->Print( | 2521 printer->Print( |
| 2291 "/**\n" | 2522 "/**\n" |
| 2292 " * @param {*} value $returndoc$\n" | 2523 " * @param {*} value$returndoc$\n" |
| 2293 " */\n", | 2524 " */\n", |
| 2294 "returndoc", JSReturnDoc(options, field)); | 2525 "returndoc", JSReturnDoc(options, field)); |
| 2295 } else { | 2526 } else { |
| 2296 printer->Print( | 2527 printer->Print( |
| 2297 "/** @param {$optionaltype$} value $returndoc$ */\n", | 2528 "/** @param {$optionaltype$} value$returndoc$ */\n", "optionaltype", |
| 2298 "optionaltype", | 2529 JSFieldTypeAnnotation( |
| 2299 JSFieldTypeAnnotation(options, field, | 2530 options, field, |
| 2300 /* force_optional = */ true, | 2531 /* is_setter_argument = */ true, |
| 2301 /* force_present = */ !HasFieldPresence(field), | 2532 /* force_present = */ false, |
| 2302 /* singular_if_not_packed = */ false), | 2533 /* singular_if_not_packed = */ false), |
| 2303 "returndoc", JSReturnDoc(options, field)); | 2534 "returndoc", JSReturnDoc(options, field)); |
| 2304 } | 2535 } |
| 2305 printer->Print( | 2536 printer->Print( |
| 2306 "$class$.prototype.set$name$ = function(value) {\n" | 2537 "$class$.prototype.set$name$ = function(value) {\n" |
| 2307 " jspb.Message.set$oneoftag$Field(this, $index$", | 2538 " jspb.Message.set$oneoftag$Field(this, $index$", |
| 2308 "class", GetPath(options, field->containing_type()), | 2539 "class", GetPath(options, field->containing_type()), |
| 2309 "name", JSGetterName(field), | 2540 "name", JSGetterName(options, field), |
| 2310 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), | 2541 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), |
| 2311 "index", JSFieldIndex(field)); | 2542 "index", JSFieldIndex(field)); |
| 2312 printer->Print( | 2543 printer->Print( |
| 2313 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" | 2544 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" |
| 2314 "};\n" | 2545 "};\n" |
| 2315 "\n" | 2546 "\n" |
| 2316 "\n", | 2547 "\n", |
| 2317 "type", | 2548 "type", |
| 2318 untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", | 2549 untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", |
| 2319 "typeclose", untyped ? ")" : "", | 2550 "typeclose", untyped ? ")" : "", |
| 2320 "oneofgroup", | 2551 "oneofgroup", |
| 2321 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) | 2552 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) |
| 2322 : ""), | 2553 : ""), |
| 2323 "returnvalue", JSReturnClause(field), "rptvalueinit", | 2554 "returnvalue", JSReturnClause(field), "rptvalueinit", |
| 2324 (field->is_repeated() ? " || []" : "")); | 2555 (field->is_repeated() ? " || []" : "")); |
| 2325 | 2556 |
| 2326 if (untyped) { | 2557 if (untyped) { |
| 2327 printer->Print( | 2558 printer->Print( |
| 2328 "/**\n" | 2559 "/**\n" |
| 2329 " * Clears the value. $returndoc$\n" | 2560 " * Clears the value.$returndoc$\n" |
| 2330 " */\n", | 2561 " */\n", |
| 2331 "returndoc", JSReturnDoc(options, field)); | 2562 "returndoc", JSReturnDoc(options, field)); |
| 2332 } | 2563 } |
| 2333 | 2564 |
| 2334 if (HasFieldPresence(field)) { | 2565 |
| 2335 printer->Print( | 2566 if (field->is_repeated()) { |
| 2336 "$class$.prototype.clear$name$ = function() {\n" | 2567 GenerateRepeatedPrimitiveHelperMethods(options, printer, field, untyped); |
| 2337 " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ", | |
| 2338 "class", GetPath(options, field->containing_type()), | |
| 2339 "name", JSGetterName(field), | |
| 2340 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), | |
| 2341 "oneofgroup", (field->containing_oneof() ? | |
| 2342 (", " + JSOneofArray(options, field)) : ""), | |
| 2343 "index", JSFieldIndex(field)); | |
| 2344 printer->Print( | |
| 2345 "$clearedvalue$);$returnvalue$\n" | |
| 2346 "};\n" | |
| 2347 "\n" | |
| 2348 "\n", | |
| 2349 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), | |
| 2350 "returnvalue", JSReturnClause(field)); | |
| 2351 } | 2568 } |
| 2352 } | 2569 } |
| 2570 |
| 2571 // Generate clearFoo() method for map fields, repeated fields, and other |
| 2572 // fields with presence. |
| 2573 if (IsMap(options, field)) { |
| 2574 printer->Print( |
| 2575 "$class$.prototype.clear$name$ = function() {\n" |
| 2576 " this.get$name$().clear();$returnvalue$\n" |
| 2577 "};\n" |
| 2578 "\n" |
| 2579 "\n", |
| 2580 "class", GetPath(options, field->containing_type()), |
| 2581 "name", JSGetterName(options, field), |
| 2582 "returnvalue", JSReturnClause(field)); |
| 2583 } else if (field->is_repeated() || |
| 2584 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
| 2585 !field->is_required())) { |
| 2586 // Fields where we can delegate to the regular setter. |
| 2587 printer->Print( |
| 2588 "$class$.prototype.clear$name$ = function() {\n" |
| 2589 " this.set$name$($clearedvalue$);$returnvalue$\n" |
| 2590 "};\n" |
| 2591 "\n" |
| 2592 "\n", |
| 2593 "class", GetPath(options, field->containing_type()), |
| 2594 "name", JSGetterName(options, field), |
| 2595 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), |
| 2596 "returnvalue", JSReturnClause(field)); |
| 2597 } else if (HasFieldPresence(options, field)) { |
| 2598 // Fields where we can't delegate to the regular setter because it doesn't |
| 2599 // accept "undefined" as an argument. |
| 2600 printer->Print( |
| 2601 "$class$.prototype.clear$name$ = function() {\n" |
| 2602 " jspb.Message.set$maybeoneof$Field(this, " |
| 2603 "$index$$maybeoneofgroup$, ", |
| 2604 "class", GetPath(options, field->containing_type()), |
| 2605 "name", JSGetterName(options, field), |
| 2606 "maybeoneof", (field->containing_oneof() ? "Oneof" : ""), |
| 2607 "maybeoneofgroup", (field->containing_oneof() ? |
| 2608 (", " + JSOneofArray(options, field)) : ""), |
| 2609 "index", JSFieldIndex(field)); |
| 2610 printer->Print( |
| 2611 "$clearedvalue$);$returnvalue$\n" |
| 2612 "};\n" |
| 2613 "\n" |
| 2614 "\n", |
| 2615 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), |
| 2616 "returnvalue", JSReturnClause(field)); |
| 2617 } |
| 2618 |
| 2619 if (HasFieldPresence(options, field)) { |
| 2620 printer->Print( |
| 2621 "/**\n" |
| 2622 " * Returns whether this field is set.\n" |
| 2623 " * @return {!boolean}\n" |
| 2624 " */\n" |
| 2625 "$class$.prototype.has$name$ = function() {\n" |
| 2626 " return jspb.Message.getField(this, $index$) != null;\n" |
| 2627 "};\n" |
| 2628 "\n" |
| 2629 "\n", |
| 2630 "class", GetPath(options, field->containing_type()), |
| 2631 "name", JSGetterName(options, field), |
| 2632 "index", JSFieldIndex(field)); |
| 2633 } |
| 2353 } | 2634 } |
| 2354 | 2635 |
| 2636 void Generator::GenerateRepeatedPrimitiveHelperMethods( |
| 2637 const GeneratorOptions& options, io::Printer* printer, |
| 2638 const FieldDescriptor* field, bool untyped) const { |
| 2639 printer->Print( |
| 2640 "/**\n" |
| 2641 " * @param {!$optionaltype$} value\n" |
| 2642 " * @param {number=} opt_index\n" |
| 2643 " */\n" |
| 2644 "$class$.prototype.add$name$ = function(value, opt_index) {\n" |
| 2645 " jspb.Message.addToRepeatedField(this, $index$", |
| 2646 "class", GetPath(options, field->containing_type()), "name", |
| 2647 JSGetterName(options, field, BYTES_DEFAULT, |
| 2648 /* drop_list = */ true), |
| 2649 "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "index", |
| 2650 JSFieldIndex(field)); |
| 2651 printer->Print( |
| 2652 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$, opt_index);\n" |
| 2653 "};\n" |
| 2654 "\n" |
| 2655 "\n", |
| 2656 "type", untyped ? "/** @type{string|number|boolean|!Uint8Array} */(" : "", |
| 2657 "typeclose", untyped ? ")" : "", "oneofgroup", |
| 2658 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), |
| 2659 "rptvalueinit", ""); |
| 2660 } |
| 2661 |
| 2662 void Generator::GenerateRepeatedMessageHelperMethods( |
| 2663 const GeneratorOptions& options, io::Printer* printer, |
| 2664 const FieldDescriptor* field) const { |
| 2665 printer->Print( |
| 2666 "/**\n" |
| 2667 " * @param {!$optionaltype$=} opt_value\n" |
| 2668 " * @param {number=} opt_index\n" |
| 2669 " * @return {!$optionaltype$}\n" |
| 2670 " */\n" |
| 2671 "$class$.prototype.add$name$ = function(opt_value, opt_index) {\n" |
| 2672 " return jspb.Message.addTo$repeatedtag$WrapperField(", |
| 2673 "optionaltype", JSTypeName(options, field, BYTES_DEFAULT), "class", |
| 2674 GetPath(options, field->containing_type()), "name", |
| 2675 JSGetterName(options, field, BYTES_DEFAULT, |
| 2676 /* drop_list = */ true), |
| 2677 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); |
| 2678 |
| 2679 printer->Print( |
| 2680 "this, $index$$oneofgroup$, opt_value, $ctor$, opt_index);\n" |
| 2681 "};\n" |
| 2682 "\n" |
| 2683 "\n", |
| 2684 "index", JSFieldIndex(field), "oneofgroup", |
| 2685 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), |
| 2686 "ctor", GetPath(options, field->message_type())); |
| 2687 } |
| 2688 |
| 2355 void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, | 2689 void Generator::GenerateClassExtensionFieldInfo(const GeneratorOptions& options, |
| 2356 io::Printer* printer, | 2690 io::Printer* printer, |
| 2357 const Descriptor* desc) const { | 2691 const Descriptor* desc) const { |
| 2358 if (IsExtendable(desc)) { | 2692 if (IsExtendable(desc)) { |
| 2359 printer->Print( | 2693 printer->Print( |
| 2360 "\n" | 2694 "\n" |
| 2361 "/**\n" | 2695 "/**\n" |
| 2362 " * The extensions registered with this message class. This is a " | 2696 " * The extensions registered with this message class. This is a " |
| 2363 "map of\n" | 2697 "map of\n" |
| 2364 " * extension field number to fieldInfo object.\n" | 2698 " * extension field number to fieldInfo object.\n" |
| 2365 " *\n" | 2699 " *\n" |
| 2366 " * For example:\n" | 2700 " * For example:\n" |
| 2367 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " | 2701 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " |
| 2368 "ctor: proto.example.MyMessage} }\n" | 2702 "ctor: proto.example.MyMessage} }\n" |
| 2369 " *\n" | 2703 " *\n" |
| 2370 " * fieldName contains the JsCompiler renamed field name property " | 2704 " * fieldName contains the JsCompiler renamed field name property " |
| 2371 "so that it\n" | 2705 "so that it\n" |
| 2372 " * works in OPTIMIZED mode.\n" | 2706 " * works in OPTIMIZED mode.\n" |
| 2373 " *\n" | 2707 " *\n" |
| 2374 " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" | 2708 " * @type {!Object.<number, jspb.ExtensionFieldInfo>}\n" |
| 2375 " */\n" | 2709 " */\n" |
| 2376 "$class$.extensions = {};\n" | 2710 "$class$.extensions = {};\n" |
| 2377 "\n", | 2711 "\n", |
| 2378 "class", GetPath(options, desc)); | 2712 "class", GetPath(options, desc)); |
| 2713 |
| 2714 if (options.binary) { |
| 2715 printer->Print( |
| 2716 "\n" |
| 2717 "/**\n" |
| 2718 " * The extensions registered with this message class. This is a " |
| 2719 "map of\n" |
| 2720 " * extension field number to fieldInfo object.\n" |
| 2721 " *\n" |
| 2722 " * For example:\n" |
| 2723 " * { 123: {fieldIndex: 123, fieldName: {my_field_name: 0}, " |
| 2724 "ctor: proto.example.MyMessage} }\n" |
| 2725 " *\n" |
| 2726 " * fieldName contains the JsCompiler renamed field name property " |
| 2727 "so that it\n" |
| 2728 " * works in OPTIMIZED mode.\n" |
| 2729 " *\n" |
| 2730 " * @type {!Object.<number, jspb.ExtensionFieldBinaryInfo>}\n" |
| 2731 " */\n" |
| 2732 "$class$.extensionsBinary = {};\n" |
| 2733 "\n", |
| 2734 "class", GetPath(options, desc)); |
| 2735 } |
| 2379 } | 2736 } |
| 2380 } | 2737 } |
| 2381 | 2738 |
| 2382 | 2739 |
| 2383 void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, | 2740 void Generator::GenerateClassDeserializeBinary(const GeneratorOptions& options, |
| 2384 io::Printer* printer, | 2741 io::Printer* printer, |
| 2385 const Descriptor* desc) const { | 2742 const Descriptor* desc) const { |
| 2386 // TODO(cfallin): Handle lazy decoding when requested by field option and/or | 2743 // TODO(cfallin): Handle lazy decoding when requested by field option and/or |
| 2387 // by default for 'bytes' fields and packed repeated fields. | 2744 // by default for 'bytes' fields and packed repeated fields. |
| 2388 | 2745 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2416 "class", GetPath(options, desc)); | 2773 "class", GetPath(options, desc)); |
| 2417 | 2774 |
| 2418 for (int i = 0; i < desc->field_count(); i++) { | 2775 for (int i = 0; i < desc->field_count(); i++) { |
| 2419 GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); | 2776 GenerateClassDeserializeBinaryField(options, printer, desc->field(i)); |
| 2420 } | 2777 } |
| 2421 | 2778 |
| 2422 printer->Print( | 2779 printer->Print( |
| 2423 " default:\n"); | 2780 " default:\n"); |
| 2424 if (IsExtendable(desc)) { | 2781 if (IsExtendable(desc)) { |
| 2425 printer->Print( | 2782 printer->Print( |
| 2426 " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n" | 2783 " jspb.Message.readBinaryExtension(msg, reader, $extobj$Binary,\n" |
| 2427 " $class$.prototype.getExtension,\n" | 2784 " $class$.prototype.getExtension,\n" |
| 2428 " $class$.prototype.setExtension);\n" | 2785 " $class$.prototype.setExtension);\n" |
| 2429 " break;\n", | 2786 " break;\n", |
| 2430 "extobj", JSExtensionsObjectName(options, desc->file(), desc), | 2787 "extobj", JSExtensionsObjectName(options, desc->file(), desc), |
| 2431 "class", GetPath(options, desc)); | 2788 "class", GetPath(options, desc)); |
| 2432 } else { | 2789 } else { |
| 2433 printer->Print( | 2790 printer->Print( |
| 2434 " reader.skipField();\n" | 2791 " reader.skipField();\n" |
| 2435 " break;\n"); | 2792 " break;\n"); |
| 2436 } | 2793 } |
| 2437 | 2794 |
| 2438 printer->Print( | 2795 printer->Print( |
| 2439 " }\n" | 2796 " }\n" |
| 2440 " }\n" | 2797 " }\n" |
| 2441 " return msg;\n" | 2798 " return msg;\n" |
| 2442 "};\n" | 2799 "};\n" |
| 2443 "\n" | 2800 "\n" |
| 2444 "\n"); | 2801 "\n"); |
| 2445 } | 2802 } |
| 2446 | 2803 |
| 2447 void Generator::GenerateClassDeserializeBinaryField( | 2804 void Generator::GenerateClassDeserializeBinaryField( |
| 2448 const GeneratorOptions& options, | 2805 const GeneratorOptions& options, |
| 2449 io::Printer* printer, | 2806 io::Printer* printer, |
| 2450 const FieldDescriptor* field) const { | 2807 const FieldDescriptor* field) const { |
| 2451 | 2808 |
| 2452 printer->Print(" case $num$:\n", | 2809 printer->Print(" case $num$:\n", |
| 2453 "num", SimpleItoa(field->number())); | 2810 "num", SimpleItoa(field->number())); |
| 2454 | 2811 |
| 2455 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 2812 if (IsMap(options, field)) { |
| 2813 const FieldDescriptor* key_field = MapFieldKey(field); |
| 2814 const FieldDescriptor* value_field = MapFieldValue(field); |
| 2456 printer->Print( | 2815 printer->Print( |
| 2457 " var value = new $fieldclass$;\n" | 2816 " var value = msg.get$name$();\n" |
| 2458 " reader.read$msgOrGroup$($grpfield$value," | 2817 " reader.readMessage(value, function(message, reader) {\n", |
| 2459 "$fieldclass$.deserializeBinaryFromReader);\n", | 2818 "name", JSGetterName(options, field)); |
| 2819 |
| 2820 printer->Print(" jspb.Map.deserializeBinary(message, reader, " |
| 2821 "$keyReaderFn$, $valueReaderFn$", |
| 2822 "keyReaderFn", JSBinaryReaderMethodName(options, key_field), |
| 2823 "valueReaderFn", JSBinaryReaderMethodName(options, value_field)); |
| 2824 |
| 2825 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 2826 printer->Print(", $messageType$.deserializeBinaryFromReader", |
| 2827 "messageType", GetPath(options, value_field->message_type())); |
| 2828 } |
| 2829 |
| 2830 printer->Print(");\n"); |
| 2831 printer->Print(" });\n"); |
| 2832 } else { |
| 2833 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2834 printer->Print( |
| 2835 " var value = new $fieldclass$;\n" |
| 2836 " reader.read$msgOrGroup$($grpfield$value," |
| 2837 "$fieldclass$.deserializeBinaryFromReader);\n", |
| 2460 "fieldclass", SubmessageTypeRef(options, field), | 2838 "fieldclass", SubmessageTypeRef(options, field), |
| 2461 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? | 2839 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? |
| 2462 "Group" : "Message", | 2840 "Group" : "Message", |
| 2463 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? | 2841 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? |
| 2464 (SimpleItoa(field->number()) + ", ") : ""); | 2842 (SimpleItoa(field->number()) + ", ") : ""); |
| 2465 } else { | 2843 } else { |
| 2466 printer->Print( | 2844 printer->Print( |
| 2467 " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", | 2845 " var value = /** @type {$fieldtype$} */ " |
| 2468 "fieldtype", JSFieldTypeAnnotation(options, field, false, true, | 2846 "(reader.read$reader$());\n", |
| 2469 /* singular_if_not_packed = */ true, | 2847 "fieldtype", JSFieldTypeAnnotation(options, field, false, true, |
| 2470 BYTES_U8), | 2848 /* singular_if_not_packed */ true, |
| 2471 "reader", JSBinaryReaderMethodName(field)); | 2849 BYTES_U8), |
| 2472 } | 2850 "reader", |
| 2851 JSBinaryReadWriteMethodName(field, /* is_writer = */ false)); |
| 2852 } |
| 2473 | 2853 |
| 2474 if (field->is_repeated() && !field->is_packed()) { | 2854 if (field->is_repeated() && !field->is_packed()) { |
| 2475 // Repeated fields receive a |value| one at at a time; append to array | 2855 printer->Print( |
| 2476 // returned by get$name$(). Annoyingly, we have to call 'set' after | 2856 " msg.add$name$(value);\n", "name", |
| 2477 // changing the array. | 2857 JSGetterName(options, field, BYTES_DEFAULT, /* drop_list = */ true)); |
| 2478 printer->Print(" msg.get$name$().push(value);\n", "name", | 2858 } else { |
| 2479 JSGetterName(field)); | 2859 // Singular fields, and packed repeated fields, receive a |value| either |
| 2480 printer->Print(" msg.set$name$(msg.get$name$());\n", "name", | 2860 // as the field's value or as the array of all the field's values; set |
| 2481 JSGetterName(field)); | 2861 // this as the field's value directly. |
| 2482 } else { | 2862 printer->Print( |
| 2483 // Singular fields, and packed repeated fields, receive a |value| either as | 2863 " msg.set$name$(value);\n", |
| 2484 // the field's value or as the array of all the field's values; set this as | 2864 "name", JSGetterName(options, field)); |
| 2485 // the field's value directly. | 2865 } |
| 2486 printer->Print( | |
| 2487 " msg.set$name$(value);\n", | |
| 2488 "name", JSGetterName(field)); | |
| 2489 } | 2866 } |
| 2490 | 2867 |
| 2491 printer->Print(" break;\n"); | 2868 printer->Print(" break;\n"); |
| 2492 } | 2869 } |
| 2493 | 2870 |
| 2494 void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, | 2871 void Generator::GenerateClassSerializeBinary(const GeneratorOptions& options, |
| 2495 io::Printer* printer, | 2872 io::Printer* printer, |
| 2496 const Descriptor* desc) const { | 2873 const Descriptor* desc) const { |
| 2497 printer->Print( | 2874 printer->Print( |
| 2498 "/**\n" | 2875 "/**\n" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2526 "$class$.prototype.serializeBinaryToWriter = function (writer) {\n" | 2903 "$class$.prototype.serializeBinaryToWriter = function (writer) {\n" |
| 2527 " var f = undefined;\n", | 2904 " var f = undefined;\n", |
| 2528 "class", GetPath(options, desc)); | 2905 "class", GetPath(options, desc)); |
| 2529 | 2906 |
| 2530 for (int i = 0; i < desc->field_count(); i++) { | 2907 for (int i = 0; i < desc->field_count(); i++) { |
| 2531 GenerateClassSerializeBinaryField(options, printer, desc->field(i)); | 2908 GenerateClassSerializeBinaryField(options, printer, desc->field(i)); |
| 2532 } | 2909 } |
| 2533 | 2910 |
| 2534 if (IsExtendable(desc)) { | 2911 if (IsExtendable(desc)) { |
| 2535 printer->Print( | 2912 printer->Print( |
| 2536 " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n" | 2913 " jspb.Message.serializeBinaryExtensions(this, writer,\n" |
| 2537 " $class$.prototype.getExtension);\n", | 2914 " $extobj$Binary, $class$.prototype.getExtension);\n", |
| 2538 "extobj", JSExtensionsObjectName(options, desc->file(), desc), | 2915 "extobj", JSExtensionsObjectName(options, desc->file(), desc), |
| 2539 "class", GetPath(options, desc)); | 2916 "class", GetPath(options, desc)); |
| 2540 } | 2917 } |
| 2541 | 2918 |
| 2542 printer->Print( | 2919 printer->Print( |
| 2543 "};\n" | 2920 "};\n" |
| 2544 "\n" | 2921 "\n" |
| 2545 "\n"); | 2922 "\n"); |
| 2546 } | 2923 } |
| 2547 | 2924 |
| 2548 void Generator::GenerateClassSerializeBinaryField( | 2925 void Generator::GenerateClassSerializeBinaryField( |
| 2549 const GeneratorOptions& options, | 2926 const GeneratorOptions& options, |
| 2550 io::Printer* printer, | 2927 io::Printer* printer, |
| 2551 const FieldDescriptor* field) const { | 2928 const FieldDescriptor* field) const { |
| 2552 printer->Print( | 2929 if (HasFieldPresence(options, field) && |
| 2553 " f = this.get$name$();\n", | 2930 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { |
| 2554 "name", JSGetterName(field, BYTES_U8)); | 2931 string typed_annotation = JSFieldTypeAnnotation( |
| 2932 options, field, |
| 2933 /* is_setter_argument = */ false, |
| 2934 /* force_present = */ false, |
| 2935 /* singular_if_not_packed = */ false, |
| 2936 /* bytes_mode = */ BYTES_DEFAULT); |
| 2937 printer->Print( |
| 2938 " f = /** @type {$type$} */ (jspb.Message.getField(this, $index$));\n", |
| 2939 "index", JSFieldIndex(field), |
| 2940 "type", typed_annotation); |
| 2941 } else { |
| 2942 printer->Print( |
| 2943 " f = this.get$name$($nolazy$);\n", |
| 2944 "name", JSGetterName(options, field, BYTES_U8), |
| 2945 // No lazy creation for maps containers -- fastpath the empty case. |
| 2946 "nolazy", (field->is_map()) ? "true" : ""); |
| 2947 } |
| 2555 | 2948 |
| 2556 if (field->is_repeated()) { | 2949 // Print an `if (condition)` statement that evaluates to true if the field |
| 2950 // goes on the wire. |
| 2951 if (IsMap(options, field)) { |
| 2952 printer->Print( |
| 2953 " if (f && f.getLength() > 0) {\n"); |
| 2954 } else if (field->is_repeated()) { |
| 2557 printer->Print( | 2955 printer->Print( |
| 2558 " if (f.length > 0) {\n"); | 2956 " if (f.length > 0) {\n"); |
| 2559 } else { | 2957 } else { |
| 2560 if (HasFieldPresence(field)) { | 2958 if (HasFieldPresence(options, field)) { |
| 2561 printer->Print( | 2959 printer->Print( |
| 2562 " if (f != null) {\n"); | 2960 " if (f != null) {\n"); |
| 2563 } else { | 2961 } else { |
| 2564 // No field presence: serialize onto the wire only if value is | 2962 // No field presence: serialize onto the wire only if value is |
| 2565 // non-default. Defaults are documented here: | 2963 // non-default. Defaults are documented here: |
| 2566 // https://goto.google.com/lhdfm | 2964 // https://goto.google.com/lhdfm |
| 2567 switch (field->cpp_type()) { | 2965 switch (field->cpp_type()) { |
| 2568 case FieldDescriptor::CPPTYPE_INT32: | 2966 case FieldDescriptor::CPPTYPE_INT32: |
| 2569 case FieldDescriptor::CPPTYPE_INT64: | 2967 case FieldDescriptor::CPPTYPE_INT64: |
| 2570 case FieldDescriptor::CPPTYPE_UINT32: | 2968 case FieldDescriptor::CPPTYPE_UINT32: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2589 printer->Print( | 2987 printer->Print( |
| 2590 " if (f.length > 0) {\n"); | 2988 " if (f.length > 0) {\n"); |
| 2591 break; | 2989 break; |
| 2592 default: | 2990 default: |
| 2593 assert(false); | 2991 assert(false); |
| 2594 break; | 2992 break; |
| 2595 } | 2993 } |
| 2596 } | 2994 } |
| 2597 } | 2995 } |
| 2598 | 2996 |
| 2997 // Write the field on the wire. |
| 2998 if (IsMap(options, field)) { |
| 2999 const FieldDescriptor* key_field = MapFieldKey(field); |
| 3000 const FieldDescriptor* value_field = MapFieldValue(field); |
| 3001 printer->Print( |
| 3002 " f.serializeBinary($index$, writer, " |
| 3003 "$keyWriterFn$, $valueWriterFn$", |
| 3004 "index", SimpleItoa(field->number()), |
| 3005 "keyWriterFn", JSBinaryWriterMethodName(options, key_field), |
| 3006 "valueWriterFn", JSBinaryWriterMethodName(options, value_field)); |
| 3007 |
| 3008 if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) { |
| 3009 printer->Print(", $messageType$.serializeBinaryToWriter", |
| 3010 "messageType", GetPath(options, value_field->message_type())); |
| 3011 } |
| 3012 |
| 3013 printer->Print(");\n"); |
| 3014 } else { |
| 3015 printer->Print( |
| 3016 " writer.write$method$(\n" |
| 3017 " $index$,\n" |
| 3018 " f", |
| 3019 "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true), |
| 3020 "index", SimpleItoa(field->number())); |
| 3021 |
| 3022 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
| 3023 !IsMap(options, field)) { |
| 3024 printer->Print( |
| 3025 ",\n" |
| 3026 " $submsg$.serializeBinaryToWriter\n", |
| 3027 "submsg", SubmessageTypeRef(options, field)); |
| 3028 } else { |
| 3029 printer->Print("\n"); |
| 3030 } |
| 3031 |
| 3032 printer->Print( |
| 3033 " );\n"); |
| 3034 } |
| 3035 |
| 3036 // Close the `if`. |
| 2599 printer->Print( | 3037 printer->Print( |
| 2600 " writer.$writer$(\n" | |
| 2601 " $index$,\n" | |
| 2602 " f", | |
| 2603 "writer", JSBinaryWriterMethodName(field), | |
| 2604 "index", SimpleItoa(field->number())); | |
| 2605 | |
| 2606 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | |
| 2607 printer->Print( | |
| 2608 ",\n" | |
| 2609 " $submsg$.serializeBinaryToWriter\n", | |
| 2610 "submsg", SubmessageTypeRef(options, field)); | |
| 2611 } else { | |
| 2612 printer->Print("\n"); | |
| 2613 } | |
| 2614 printer->Print( | |
| 2615 " );\n" | |
| 2616 " }\n"); | 3038 " }\n"); |
| 2617 } | 3039 } |
| 2618 | 3040 |
| 2619 void Generator::GenerateEnum(const GeneratorOptions& options, | 3041 void Generator::GenerateEnum(const GeneratorOptions& options, |
| 2620 io::Printer* printer, | 3042 io::Printer* printer, |
| 2621 const EnumDescriptor* enumdesc) const { | 3043 const EnumDescriptor* enumdesc) const { |
| 2622 printer->Print( | 3044 printer->Print( |
| 2623 "/**\n" | 3045 "/**\n" |
| 2624 " * @enum {number}\n" | 3046 " * @enum {number}\n" |
| 2625 " */\n" | 3047 " */\n" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2649 GetPath(options, field->file())); | 3071 GetPath(options, field->file())); |
| 2650 | 3072 |
| 2651 printer->Print( | 3073 printer->Print( |
| 2652 "\n" | 3074 "\n" |
| 2653 "/**\n" | 3075 "/**\n" |
| 2654 " * A tuple of {field number, class constructor} for the extension\n" | 3076 " * A tuple of {field number, class constructor} for the extension\n" |
| 2655 " * field named `$name$`.\n" | 3077 " * field named `$name$`.\n" |
| 2656 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" | 3078 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" |
| 2657 " */\n" | 3079 " */\n" |
| 2658 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", | 3080 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", |
| 2659 "name", JSObjectFieldName(field), | 3081 "name", JSObjectFieldName(options, field), |
| 2660 "class", extension_scope, | 3082 "class", extension_scope, |
| 2661 "extensionType", JSFieldTypeAnnotation( | 3083 "extensionType", JSFieldTypeAnnotation( |
| 2662 options, field, | 3084 options, field, |
| 2663 /* force_optional = */ false, | 3085 /* is_setter_argument = */ false, |
| 2664 /* force_present = */ true, | 3086 /* force_present = */ true, |
| 2665 /* singular_if_not_packed = */ false)); | 3087 /* singular_if_not_packed = */ false)); |
| 2666 printer->Print( | 3088 printer->Print( |
| 2667 " $index$,\n" | 3089 " $index$,\n" |
| 2668 " {$name$: 0},\n" | 3090 " {$name$: 0},\n" |
| 2669 " $ctor$,\n" | 3091 " $ctor$,\n" |
| 2670 " /** @type {?function((boolean|undefined),!jspb.Message=): " | 3092 " /** @type {?function((boolean|undefined),!jspb.Message=): " |
| 2671 "!Object} */ (\n" | 3093 "!Object} */ (\n" |
| 2672 " $toObject$),\n" | 3094 " $toObject$),\n" |
| 2673 " $repeated$", | 3095 " $repeated$);\n", |
| 2674 "index", SimpleItoa(field->number()), | 3096 "index", SimpleItoa(field->number()), |
| 2675 "name", JSObjectFieldName(field), | 3097 "name", JSObjectFieldName(options, field), |
| 2676 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? | 3098 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? |
| 2677 SubmessageTypeRef(options, field) : string("null")), | 3099 SubmessageTypeRef(options, field) : string("null")), |
| 2678 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? | 3100 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? |
| 2679 (SubmessageTypeRef(options, field) + ".toObject") : | 3101 (SubmessageTypeRef(options, field) + ".toObject") : |
| 2680 string("null")), | 3102 string("null")), |
| 2681 "repeated", (field->is_repeated() ? "1" : "0")); | 3103 "repeated", (field->is_repeated() ? "1" : "0")); |
| 2682 | 3104 |
| 2683 if (options.binary) { | 3105 if (options.binary) { |
| 2684 printer->Print( | 3106 printer->Print( |
| 2685 ",\n" | 3107 "\n" |
| 2686 " jspb.BinaryReader.prototype.$binaryReaderFn$,\n" | 3108 "$extendName$Binary[$index$] = new jspb.ExtensionFieldBinaryInfo(\n" |
| 2687 " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n" | 3109 " $class$.$name$,\n" |
| 3110 " $binaryReaderFn$,\n" |
| 3111 " $binaryWriterFn$,\n" |
| 2688 " $binaryMessageSerializeFn$,\n" | 3112 " $binaryMessageSerializeFn$,\n" |
| 2689 " $binaryMessageDeserializeFn$,\n" | 3113 " $binaryMessageDeserializeFn$,\n", |
| 2690 " $isPacked$);\n", | 3114 "extendName", JSExtensionsObjectName(options, field->file(), |
| 2691 "binaryReaderFn", JSBinaryReaderMethodName(field), | 3115 field->containing_type()), |
| 2692 "binaryWriterFn", JSBinaryWriterMethodName(field), | 3116 "index", SimpleItoa(field->number()), |
| 3117 "class", extension_scope, |
| 3118 "name", JSObjectFieldName(options, field), |
| 3119 "binaryReaderFn", JSBinaryReaderMethodName(options, field), |
| 3120 "binaryWriterFn", JSBinaryWriterMethodName(options, field), |
| 2693 "binaryMessageSerializeFn", | 3121 "binaryMessageSerializeFn", |
| 2694 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? | 3122 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
| 2695 (SubmessageTypeRef(options, field) + | 3123 (SubmessageTypeRef(options, field) + |
| 2696 ".serializeBinaryToWriter") : "null", | 3124 ".serializeBinaryToWriter") : "undefined", |
| 2697 "binaryMessageDeserializeFn", | 3125 "binaryMessageDeserializeFn", |
| 2698 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? | 3126 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
| 2699 (SubmessageTypeRef(options, field) + | 3127 (SubmessageTypeRef(options, field) + |
| 2700 ".deserializeBinaryFromReader") : "null", | 3128 ".deserializeBinaryFromReader") : "undefined"); |
| 3129 |
| 3130 printer->Print( |
| 3131 " $isPacked$);\n", |
| 2701 "isPacked", (field->is_packed() ? "true" : "false")); | 3132 "isPacked", (field->is_packed() ? "true" : "false")); |
| 2702 } else { | |
| 2703 printer->Print(");\n"); | |
| 2704 } | 3133 } |
| 2705 | 3134 |
| 2706 printer->Print( | 3135 printer->Print( |
| 2707 "// This registers the extension field with the extended class, so that\n" | 3136 "// This registers the extension field with the extended class, so that\n" |
| 2708 "// toObject() will function correctly.\n" | 3137 "// toObject() will function correctly.\n" |
| 2709 "$extendName$[$index$] = $class$.$name$;\n" | 3138 "$extendName$[$index$] = $class$.$name$;\n" |
| 2710 "\n", | 3139 "\n", |
| 2711 "extendName", JSExtensionsObjectName(options, field->file(), | 3140 "extendName", JSExtensionsObjectName(options, field->file(), |
| 2712 field->containing_type()), | 3141 field->containing_type()), |
| 2713 "index", SimpleItoa(field->number()), | 3142 "index", SimpleItoa(field->number()), |
| 2714 "class", extension_scope, | 3143 "class", extension_scope, |
| 2715 "name", JSObjectFieldName(field)); | 3144 "name", JSObjectFieldName(options, field)); |
| 2716 } | 3145 } |
| 2717 | 3146 |
| 2718 bool GeneratorOptions::ParseFromOptions( | 3147 bool GeneratorOptions::ParseFromOptions( |
| 2719 const vector< pair< string, string > >& options, | 3148 const vector< pair< string, string > >& options, |
| 2720 string* error) { | 3149 string* error) { |
| 2721 for (int i = 0; i < options.size(); i++) { | 3150 for (int i = 0; i < options.size(); i++) { |
| 2722 if (options[i].first == "add_require_for_enums") { | 3151 if (options[i].first == "add_require_for_enums") { |
| 2723 if (options[i].second != "") { | 3152 if (options[i].second != "") { |
| 2724 *error = "Unexpected option value for add_require_for_enums"; | 3153 *error = "Unexpected option value for add_require_for_enums"; |
| 2725 return false; | 3154 return false; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2744 } | 3173 } |
| 2745 error_on_name_conflict = true; | 3174 error_on_name_conflict = true; |
| 2746 } else if (options[i].first == "output_dir") { | 3175 } else if (options[i].first == "output_dir") { |
| 2747 output_dir = options[i].second; | 3176 output_dir = options[i].second; |
| 2748 } else if (options[i].first == "namespace_prefix") { | 3177 } else if (options[i].first == "namespace_prefix") { |
| 2749 namespace_prefix = options[i].second; | 3178 namespace_prefix = options[i].second; |
| 2750 } else if (options[i].first == "library") { | 3179 } else if (options[i].first == "library") { |
| 2751 library = options[i].second; | 3180 library = options[i].second; |
| 2752 } else if (options[i].first == "import_style") { | 3181 } else if (options[i].first == "import_style") { |
| 2753 if (options[i].second == "closure") { | 3182 if (options[i].second == "closure") { |
| 2754 import_style = IMPORT_CLOSURE; | 3183 import_style = kImportClosure; |
| 2755 } else if (options[i].second == "commonjs") { | 3184 } else if (options[i].second == "commonjs") { |
| 2756 import_style = IMPORT_COMMONJS; | 3185 import_style = kImportCommonJs; |
| 2757 } else if (options[i].second == "browser") { | 3186 } else if (options[i].second == "browser") { |
| 2758 import_style = IMPORT_BROWSER; | 3187 import_style = kImportBrowser; |
| 2759 } else if (options[i].second == "es6") { | 3188 } else if (options[i].second == "es6") { |
| 2760 import_style = IMPORT_ES6; | 3189 import_style = kImportEs6; |
| 2761 } else { | 3190 } else { |
| 2762 *error = "Unknown import style " + options[i].second + ", expected " + | 3191 *error = "Unknown import style " + options[i].second + ", expected " + |
| 2763 "one of: closure, commonjs, browser, es6."; | 3192 "one of: closure, commonjs, browser, es6."; |
| 2764 } | 3193 } |
| 3194 } else if (options[i].first == "extension") { |
| 3195 extension = options[i].second; |
| 3196 } else if (options[i].first == "one_output_file_per_input_file") { |
| 3197 if (!options[i].second.empty()) { |
| 3198 *error = "Unexpected option value for one_output_file_per_input_file"; |
| 3199 return false; |
| 3200 } |
| 3201 one_output_file_per_input_file = true; |
| 3202 } else if (options[i].first == "broken_proto3_semantics") { |
| 3203 if (!options[i].second.empty()) { |
| 3204 *error = "Unexpected option value for broken_proto3_semantics"; |
| 3205 return false; |
| 3206 } |
| 3207 broken_proto3_semantics = true; |
| 2765 } else { | 3208 } else { |
| 2766 // Assume any other option is an output directory, as long as it is a bare | 3209 // Assume any other option is an output directory, as long as it is a bare |
| 2767 // `key` rather than a `key=value` option. | 3210 // `key` rather than a `key=value` option. |
| 2768 if (options[i].second != "") { | 3211 if (options[i].second != "") { |
| 2769 *error = "Unknown option: " + options[i].first; | 3212 *error = "Unknown option: " + options[i].first; |
| 2770 return false; | 3213 return false; |
| 2771 } | 3214 } |
| 2772 output_dir = options[i].first; | 3215 output_dir = options[i].first; |
| 2773 } | 3216 } |
| 2774 } | 3217 } |
| 2775 | 3218 |
| 2776 if (!library.empty() && import_style != IMPORT_CLOSURE) { | 3219 if (import_style != kImportClosure && |
| 2777 *error = "The library option should only be used for " | 3220 (add_require_for_enums || testonly || !library.empty() || |
| 2778 "import_style=closure"; | 3221 error_on_name_conflict || broken_proto3_semantics || |
| 3222 extension != ".js" || one_output_file_per_input_file)) { |
| 3223 *error = |
| 3224 "The add_require_for_enums, testonly, library, error_on_name_conflict, " |
| 3225 "broken_proto3_semantics, extension, and " |
| 3226 "one_output_file_per_input_file options should only be used for " |
| 3227 "import_style=closure"; |
| 3228 return false; |
| 2779 } | 3229 } |
| 2780 | 3230 |
| 2781 return true; | 3231 return true; |
| 2782 } | 3232 } |
| 2783 | 3233 |
| 3234 GeneratorOptions::OutputMode GeneratorOptions::output_mode() const { |
| 3235 // We use one output file per input file if we are not using Closure or if |
| 3236 // this is explicitly requested. |
| 3237 if (import_style != kImportClosure || one_output_file_per_input_file) { |
| 3238 return kOneOutputFilePerInputFile; |
| 3239 } |
| 3240 |
| 3241 // If a library name is provided, we put everything in that one file. |
| 3242 if (!library.empty()) { |
| 3243 return kEverythingInOneFile; |
| 3244 } |
| 3245 |
| 3246 // Otherwise, we create one output file per type. |
| 3247 return kOneOutputFilePerType; |
| 3248 } |
| 3249 |
| 2784 void Generator::GenerateFilesInDepOrder( | 3250 void Generator::GenerateFilesInDepOrder( |
| 2785 const GeneratorOptions& options, | 3251 const GeneratorOptions& options, |
| 2786 io::Printer* printer, | 3252 io::Printer* printer, |
| 2787 const vector<const FileDescriptor*>& files) const { | 3253 const vector<const FileDescriptor*>& files) const { |
| 2788 // Build a std::set over all files so that the DFS can detect when it recurses | 3254 // Build a std::set over all files so that the DFS can detect when it recurses |
| 2789 // into a dep not specified in the user's command line. | 3255 // into a dep not specified in the user's command line. |
| 2790 std::set<const FileDescriptor*> all_files(files.begin(), files.end()); | 3256 std::set<const FileDescriptor*> all_files(files.begin(), files.end()); |
| 2791 // Track the in-progress set of files that have been generated already. | 3257 // Track the in-progress set of files that have been generated already. |
| 2792 std::set<const FileDescriptor*> generated; | 3258 std::set<const FileDescriptor*> generated; |
| 2793 for (int i = 0; i < files.size(); i++) { | 3259 for (int i = 0; i < files.size(); i++) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2820 GenerateClassesAndEnums(options, printer, root); | 3286 GenerateClassesAndEnums(options, printer, root); |
| 2821 } | 3287 } |
| 2822 } | 3288 } |
| 2823 | 3289 |
| 2824 void Generator::GenerateFile(const GeneratorOptions& options, | 3290 void Generator::GenerateFile(const GeneratorOptions& options, |
| 2825 io::Printer* printer, | 3291 io::Printer* printer, |
| 2826 const FileDescriptor* file) const { | 3292 const FileDescriptor* file) const { |
| 2827 GenerateHeader(options, printer); | 3293 GenerateHeader(options, printer); |
| 2828 | 3294 |
| 2829 // Generate "require" statements. | 3295 // Generate "require" statements. |
| 2830 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { | 3296 if (options.import_style == GeneratorOptions::kImportCommonJs) { |
| 2831 printer->Print("var jspb = require('google-protobuf');\n"); | 3297 printer->Print("var jspb = require('google-protobuf');\n"); |
| 2832 printer->Print("var goog = jspb;\n"); | 3298 printer->Print("var goog = jspb;\n"); |
| 2833 printer->Print("var global = Function('return this')();\n\n"); | 3299 printer->Print("var global = Function('return this')();\n\n"); |
| 2834 | 3300 |
| 2835 for (int i = 0; i < file->dependency_count(); i++) { | 3301 for (int i = 0; i < file->dependency_count(); i++) { |
| 2836 const string& name = file->dependency(i)->name(); | 3302 const string& name = file->dependency(i)->name(); |
| 2837 printer->Print( | 3303 printer->Print( |
| 2838 "var $alias$ = require('$file$');\n", | 3304 "var $alias$ = require('$file$');\n", |
| 2839 "alias", ModuleAlias(name), | 3305 "alias", ModuleAlias(name), |
| 2840 "file", GetRootPath(file->name()) + GetJSFilename(name)); | 3306 "file", GetRootPath(file->name(), name) + GetJSFilename(options, name)
); |
| 2841 } | 3307 } |
| 2842 } | 3308 } |
| 2843 | 3309 |
| 2844 // We aren't using Closure's import system, but we use goog.exportSymbol() | |
| 2845 // to construct the expected tree of objects, eg. | |
| 2846 // | |
| 2847 // goog.exportSymbol('foo.bar.Baz', null, this); | |
| 2848 // | |
| 2849 // // Later generated code expects foo.bar = {} to exist: | |
| 2850 // foo.bar.Baz = function() { /* ... */ } | |
| 2851 set<string> provided; | 3310 set<string> provided; |
| 2852 | 3311 set<const FieldDescriptor*> extensions; |
| 2853 // Cover the case where this file declares extensions but no messages. | |
| 2854 // This will ensure that the file-level object will be declared to hold | |
| 2855 // the extensions. | |
| 2856 for (int i = 0; i < file->extension_count(); i++) { | 3312 for (int i = 0; i < file->extension_count(); i++) { |
| 2857 provided.insert(file->extension(i)->full_name()); | 3313 // We honor the jspb::ignore option here only when working with |
| 3314 // Closure-style imports. Use of this option is discouraged and so we want |
| 3315 // to avoid adding new support for it. |
| 3316 if (options.import_style == GeneratorOptions::kImportClosure && |
| 3317 IgnoreField(file->extension(i))) { |
| 3318 continue; |
| 3319 } |
| 3320 provided.insert(GetPath(options, file) + "." + |
| 3321 JSObjectFieldName(options, file->extension(i))); |
| 3322 extensions.insert(file->extension(i)); |
| 2858 } | 3323 } |
| 2859 | 3324 |
| 2860 FindProvidesForFile(options, printer, file, &provided); | 3325 FindProvidesForFile(options, printer, file, &provided); |
| 2861 for (std::set<string>::iterator it = provided.begin(); | 3326 GenerateProvides(options, printer, &provided); |
| 2862 it != provided.end(); ++it) { | 3327 vector<const FileDescriptor*> files; |
| 2863 printer->Print("goog.exportSymbol('$name$', null, global);\n", | 3328 files.push_back(file); |
| 2864 "name", *it); | 3329 if (options.import_style == GeneratorOptions::kImportClosure) { |
| 3330 GenerateRequiresForLibrary(options, printer, files, &provided); |
| 2865 } | 3331 } |
| 2866 | 3332 |
| 2867 GenerateClassesAndEnums(options, printer, file); | 3333 GenerateClassesAndEnums(options, printer, file); |
| 2868 | 3334 |
| 2869 // Extensions nested inside messages are emitted inside | 3335 // Generate code for top-level extensions. Extensions nested inside messages |
| 2870 // GenerateClassesAndEnums(). | 3336 // are emitted inside GenerateClassesAndEnums(). |
| 2871 for (int i = 0; i < file->extension_count(); i++) { | 3337 for (set<const FieldDescriptor*>::const_iterator it = extensions.begin(); |
| 2872 GenerateExtension(options, printer, file->extension(i)); | 3338 it != extensions.end(); ++it) { |
| 3339 GenerateExtension(options, printer, *it); |
| 2873 } | 3340 } |
| 2874 | 3341 |
| 2875 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { | 3342 if (options.import_style == GeneratorOptions::kImportCommonJs) { |
| 2876 printer->Print("goog.object.extend(exports, $package$);\n", | 3343 printer->Print("goog.object.extend(exports, $package$);\n", |
| 2877 "package", GetPath(options, file)); | 3344 "package", GetPath(options, file)); |
| 2878 } | 3345 } |
| 2879 } | 3346 } |
| 2880 | 3347 |
| 2881 bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, | 3348 bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, |
| 2882 const string& parameter, | 3349 const string& parameter, |
| 2883 GeneratorContext* context, | 3350 GeneratorContext* context, |
| 2884 string* error) const { | 3351 string* error) const { |
| 2885 vector< pair< string, string > > option_pairs; | 3352 vector< pair< string, string > > option_pairs; |
| 2886 ParseGeneratorParameter(parameter, &option_pairs); | 3353 ParseGeneratorParameter(parameter, &option_pairs); |
| 2887 GeneratorOptions options; | 3354 GeneratorOptions options; |
| 2888 if (!options.ParseFromOptions(option_pairs, error)) { | 3355 if (!options.ParseFromOptions(option_pairs, error)) { |
| 2889 return false; | 3356 return false; |
| 2890 } | 3357 } |
| 2891 | 3358 |
| 2892 | 3359 |
| 2893 // There are three schemes for where output files go: | 3360 if (options.output_mode() == GeneratorOptions::kEverythingInOneFile) { |
| 2894 // | |
| 2895 // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file | |
| 2896 // - import_style = IMPORT_CLOSURE, library empty: one output file per type | |
| 2897 // - import_style != IMPORT_CLOSURE: one output file per .proto file | |
| 2898 if (options.import_style == GeneratorOptions::IMPORT_CLOSURE && | |
| 2899 options.library != "") { | |
| 2900 // All output should go in a single file. | 3361 // All output should go in a single file. |
| 2901 string filename = options.output_dir + "/" + options.library + ".js"; | 3362 string filename = options.output_dir + "/" + options.library + |
| 3363 options.GetFileNameExtension(); |
| 2902 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(
filename)); | 3364 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(
filename)); |
| 2903 GOOGLE_CHECK(output.get()); | 3365 GOOGLE_CHECK(output.get()); |
| 2904 io::Printer printer(output.get(), '$'); | 3366 io::Printer printer(output.get(), '$'); |
| 2905 | 3367 |
| 2906 // Pull out all extensions -- we need these to generate all | 3368 // Pull out all extensions -- we need these to generate all |
| 2907 // provides/requires. | 3369 // provides/requires. |
| 2908 vector<const FieldDescriptor*> extensions; | 3370 vector<const FieldDescriptor*> extensions; |
| 2909 for (int i = 0; i < files.size(); i++) { | 3371 for (int i = 0; i < files.size(); i++) { |
| 2910 for (int j = 0; j < files[i]->extension_count(); j++) { | 3372 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 2911 const FieldDescriptor* extension = files[i]->extension(j); | 3373 const FieldDescriptor* extension = files[i]->extension(j); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2926 | 3388 |
| 2927 for (int i = 0; i < extensions.size(); i++) { | 3389 for (int i = 0; i < extensions.size(); i++) { |
| 2928 if (ShouldGenerateExtension(extensions[i])) { | 3390 if (ShouldGenerateExtension(extensions[i])) { |
| 2929 GenerateExtension(options, &printer, extensions[i]); | 3391 GenerateExtension(options, &printer, extensions[i]); |
| 2930 } | 3392 } |
| 2931 } | 3393 } |
| 2932 | 3394 |
| 2933 if (printer.failed()) { | 3395 if (printer.failed()) { |
| 2934 return false; | 3396 return false; |
| 2935 } | 3397 } |
| 2936 } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { | 3398 } else if (options.output_mode() == GeneratorOptions::kOneOutputFilePerType) { |
| 2937 set<const void*> allowed_set; | 3399 set<const void*> allowed_set; |
| 2938 if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { | 3400 if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { |
| 2939 return false; | 3401 return false; |
| 2940 } | 3402 } |
| 2941 | 3403 |
| 2942 for (int i = 0; i < files.size(); i++) { | 3404 for (int i = 0; i < files.size(); i++) { |
| 2943 const FileDescriptor* file = files[i]; | 3405 const FileDescriptor* file = files[i]; |
| 2944 for (int j = 0; j < file->message_type_count(); j++) { | 3406 for (int j = 0; j < file->message_type_count(); j++) { |
| 2945 const Descriptor* desc = file->message_type(j); | 3407 const Descriptor* desc = file->message_type(j); |
| 2946 if (allowed_set.count(desc) == 0) { | 3408 if (allowed_set.count(desc) == 0) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3018 GenerateTestOnly(options, &printer); | 3480 GenerateTestOnly(options, &printer); |
| 3019 GenerateRequiresForExtensions(options, &printer, fields, &provided); | 3481 GenerateRequiresForExtensions(options, &printer, fields, &provided); |
| 3020 | 3482 |
| 3021 for (int j = 0; j < files[i]->extension_count(); j++) { | 3483 for (int j = 0; j < files[i]->extension_count(); j++) { |
| 3022 if (ShouldGenerateExtension(files[i]->extension(j))) { | 3484 if (ShouldGenerateExtension(files[i]->extension(j))) { |
| 3023 GenerateExtension(options, &printer, files[i]->extension(j)); | 3485 GenerateExtension(options, &printer, files[i]->extension(j)); |
| 3024 } | 3486 } |
| 3025 } | 3487 } |
| 3026 } | 3488 } |
| 3027 } | 3489 } |
| 3028 } else { | 3490 } else /* options.output_mode() == kOneOutputFilePerInputFile */ { |
| 3029 // Generate one output file per input (.proto) file. | 3491 // Generate one output file per input (.proto) file. |
| 3030 | 3492 |
| 3031 for (int i = 0; i < files.size(); i++) { | 3493 for (int i = 0; i < files.size(); i++) { |
| 3032 const google::protobuf::FileDescriptor* file = files[i]; | 3494 const google::protobuf::FileDescriptor* file = files[i]; |
| 3033 | 3495 |
| 3034 string filename = options.output_dir + "/" + GetJSFilename(file->name()); | 3496 string filename = |
| 3497 options.output_dir + "/" + GetJSFilename(options, file->name()); |
| 3035 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Ope
n(filename)); | 3498 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Ope
n(filename)); |
| 3036 GOOGLE_CHECK(output.get()); | 3499 GOOGLE_CHECK(output.get()); |
| 3037 io::Printer printer(output.get(), '$'); | 3500 io::Printer printer(output.get(), '$'); |
| 3038 | 3501 |
| 3039 GenerateFile(options, &printer, file); | 3502 GenerateFile(options, &printer, file); |
| 3040 | 3503 |
| 3041 if (printer.failed()) { | 3504 if (printer.failed()) { |
| 3042 return false; | 3505 return false; |
| 3043 } | 3506 } |
| 3044 } | 3507 } |
| 3045 } | 3508 } |
| 3046 | 3509 |
| 3047 return true; | 3510 return true; |
| 3048 } | 3511 } |
| 3049 | 3512 |
| 3050 } // namespace js | 3513 } // namespace js |
| 3051 } // namespace compiler | 3514 } // namespace compiler |
| 3052 } // namespace protobuf | 3515 } // namespace protobuf |
| 3053 } // namespace google | 3516 } // namespace google |
| OLD | NEW |