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

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

Issue 1983203003: Update third_party/protobuf to protobuf-v3.0.0-beta-3 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: owners Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 "void", 116 "void",
117 "volatile", 117 "volatile",
118 "while", 118 "while",
119 "with", 119 "with",
120 }; 120 };
121 121
122 static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*); 122 static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*);
123 123
124 namespace { 124 namespace {
125 125
126 // The mode of operation for bytes fields. Historically JSPB always carried
127 // bytes as JS {string}, containing base64 content by convention. With binary
128 // and proto3 serialization the new convention is to represent it as binary
129 // data in Uint8Array. See b/26173701 for background on the migration.
130 enum BytesMode {
131 BYTES_DEFAULT, // Default type for getBytesField to return.
132 BYTES_B64, // Explicitly coerce to base64 string where needed.
133 BYTES_U8, // Explicitly coerce to Uint8Array where needed.
134 };
135
126 bool IsReserved(const string& ident) { 136 bool IsReserved(const string& ident) {
127 for (int i = 0; i < kNumKeyword; i++) { 137 for (int i = 0; i < kNumKeyword; i++) {
128 if (ident == kKeyword[i]) { 138 if (ident == kKeyword[i]) {
129 return true; 139 return true;
130 } 140 }
131 } 141 }
132 return false; 142 return false;
133 } 143 }
134 144
135 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto 145 // Returns a copy of |filename| with any trailing ".protodevel" or ".proto
136 // suffix stripped. 146 // suffix stripped.
147 // TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc.
137 string StripProto(const string& filename) { 148 string StripProto(const string& filename) {
138 const char* suffix = HasSuffixString(filename, ".protodevel") 149 const char* suffix = HasSuffixString(filename, ".protodevel")
139 ? ".protodevel" : ".proto"; 150 ? ".protodevel" : ".proto";
140 return StripSuffixString(filename, suffix); 151 return StripSuffixString(filename, suffix);
141 } 152 }
142 153
154 // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript
155 // file foo/bar/baz.js.
156 string GetJSFilename(const string& filename) {
157 return StripProto(filename) + "_pb.js";
158 }
159
160 // Given a filename like foo/bar/baz.proto, returns the root directory
161 // path ../../
162 string GetRootPath(const string& filename) {
163 size_t slashes = std::count(filename.begin(), filename.end(), '/');
164 if (slashes == 0) {
165 return "./";
166 }
167 string result = "";
168 for (size_t i = 0; i < slashes; i++) {
169 result += "../";
170 }
171 return result;
172 }
173
174 // Returns the alias we assign to the module of the given .proto filename
175 // when importing.
176 string ModuleAlias(const string& filename) {
177 // This scheme could technically cause problems if a file includes any 2 of:
178 // foo/bar_baz.proto
179 // foo_bar_baz.proto
180 // foo_bar/baz.proto
181 //
182 // We'll worry about this problem if/when we actually see it. This name isn't
183 // exposed to users so we can change it later if we need to.
184 string basename = StripProto(filename);
185 StripString(&basename, "-", '$');
186 StripString(&basename, "/", '_');
187 return basename + "_pb";
188 }
189
143 // Returns the fully normalized JavaScript path for the given 190 // Returns the fully normalized JavaScript path for the given
144 // file descriptor's package. 191 // file descriptor's package.
145 string GetPath(const GeneratorOptions& options, 192 string GetPath(const GeneratorOptions& options,
146 const FileDescriptor* file) { 193 const FileDescriptor* file) {
147 if (!options.namespace_prefix.empty()) { 194 if (!options.namespace_prefix.empty()) {
148 return options.namespace_prefix; 195 return options.namespace_prefix;
149 } else if (!file->package().empty()) { 196 } else if (!file->package().empty()) {
150 return "proto." + file->package(); 197 return "proto." + file->package();
151 } else { 198 } else {
152 return "proto"; 199 return "proto";
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 255
209 // Returns the fully normalized JavaScript path for the given 256 // Returns the fully normalized JavaScript path for the given
210 // enumeration value descriptor. 257 // enumeration value descriptor.
211 string GetPath(const GeneratorOptions& options, 258 string GetPath(const GeneratorOptions& options,
212 const EnumValueDescriptor* value_descriptor) { 259 const EnumValueDescriptor* value_descriptor) {
213 return GetPath( 260 return GetPath(
214 options, 261 options,
215 value_descriptor->type()) + "." + value_descriptor->name(); 262 value_descriptor->type()) + "." + value_descriptor->name();
216 } 263 }
217 264
265 string MaybeCrossFileRef(const GeneratorOptions& options,
266 const FileDescriptor* from_file,
267 const Descriptor* to_message) {
268 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS &&
269 from_file != to_message->file()) {
270 // Cross-file ref in CommonJS needs to use the module alias instead of
271 // the global name.
272 return ModuleAlias(to_message->file()->name()) + "." + to_message->name();
273 } else {
274 // Within a single file we use a full name.
275 return GetPath(options, to_message);
276 }
277 }
278
279 string SubmessageTypeRef(const GeneratorOptions& options,
280 const FieldDescriptor* field) {
281 GOOGLE_CHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE);
282 return MaybeCrossFileRef(options, field->file(), field->message_type());
283 }
284
218 // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields 285 // - Object field name: LOWER_UNDERSCORE -> LOWER_CAMEL, except for group fields
219 // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate, 286 // (UPPER_CAMEL -> LOWER_CAMEL), with "List" (or "Map") appended if appropriate,
220 // and with reserved words triggering a "pb_" prefix. 287 // and with reserved words triggering a "pb_" prefix.
221 // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields 288 // - Getters/setters: LOWER_UNDERSCORE -> UPPER_CAMEL, except for group fields
222 // (use the name directly), then append "List" if appropriate, then append "$" 289 // (use the name directly), then append "List" if appropriate, then append "$"
223 // if resulting name is equal to a reserved word. 290 // if resulting name is equal to a reserved word.
224 // - Enums: just uppercase. 291 // - Enums: just uppercase.
225 292
226 // Locale-independent version of ToLower that deals only with ASCII A-Z. 293 // Locale-independent version of ToLower that deals only with ASCII A-Z.
227 char ToLowerASCII(char c) { 294 char ToLowerASCII(char c) {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 if ('A' <= input[i] && input[i] <= 'Z') { 386 if ('A' <= input[i] && input[i] <= 'Z') {
320 result.push_back(input[i] - 'A' + 'a'); 387 result.push_back(input[i] - 'A' + 'a');
321 } else { 388 } else {
322 result.push_back(input[i]); 389 result.push_back(input[i]);
323 } 390 }
324 } 391 }
325 392
326 return result; 393 return result;
327 } 394 }
328 395
396 // When we're generating one output file per type name, this is the filename
397 // that top-level extensions should go in.
398 string GetExtensionFileName(const GeneratorOptions& options,
399 const FileDescriptor* file) {
400 return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js";
401 }
402
403 // When we're generating one output file per type name, this is the filename
404 // that a top-level message should go in.
405 string GetMessageFileName(const GeneratorOptions& options,
406 const Descriptor* desc) {
407 return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
408 }
409
410 // When we're generating one output file per type name, this is the filename
411 // that a top-level message should go in.
412 string GetEnumFileName(const GeneratorOptions& options,
413 const EnumDescriptor* desc) {
414 return options.output_dir + "/" + ToFileName(desc->name()) + ".js";
415 }
416
329 // Returns the message/response ID, if set. 417 // Returns the message/response ID, if set.
330 string GetMessageId(const Descriptor* desc) { 418 string GetMessageId(const Descriptor* desc) {
331 return string(); 419 return string();
332 } 420 }
333 421
422 bool IgnoreExtensionField(const FieldDescriptor* field) {
423 // Exclude descriptor extensions from output "to avoid clutter" (from original
424 // codegen).
425 return field->is_extension() &&
426 field->containing_type()->file()->name() ==
427 "google/protobuf/descriptor.proto";
428 }
429
334 430
335 // Used inside Google only -- do not remove. 431 // Used inside Google only -- do not remove.
336 bool IsResponse(const Descriptor* desc) { return false; } 432 bool IsResponse(const Descriptor* desc) { return false; }
337 bool IgnoreField(const FieldDescriptor* field) { return false; } 433
434 bool IgnoreField(const FieldDescriptor* field) {
435 return IgnoreExtensionField(field);
436 }
338 437
339 438
340 // Does JSPB ignore this entire oneof? True only if all fields are ignored. 439 // Does JSPB ignore this entire oneof? True only if all fields are ignored.
341 bool IgnoreOneof(const OneofDescriptor* oneof) { 440 bool IgnoreOneof(const OneofDescriptor* oneof) {
342 for (int i = 0; i < oneof->field_count(); i++) { 441 for (int i = 0; i < oneof->field_count(); i++) {
343 if (!IgnoreField(oneof->field(i))) { 442 if (!IgnoreField(oneof->field(i))) {
344 return false; 443 return false;
345 } 444 }
346 } 445 }
347 return true; 446 return true;
(...skipping 24 matching lines...) Expand all
372 string name = JSIdent( 471 string name = JSIdent(
373 field, 472 field,
374 /* is_upper_camel = */ false, 473 /* is_upper_camel = */ false,
375 /* is_map = */ false); 474 /* is_map = */ false);
376 if (IsReserved(name)) { 475 if (IsReserved(name)) {
377 name = "pb_" + name; 476 name = "pb_" + name;
378 } 477 }
379 return name; 478 return name;
380 } 479 }
381 480
481 string JSByteGetterSuffix(BytesMode bytes_mode) {
482 switch (bytes_mode) {
483 case BYTES_DEFAULT:
484 return "";
485 case BYTES_B64:
486 return "B64";
487 case BYTES_U8:
488 return "U8";
489 default:
490 assert(false);
491 }
492 }
493
382 // Returns the field name as a capitalized portion of a getter/setter method 494 // Returns the field name as a capitalized portion of a getter/setter method
383 // name, e.g. MyField for .getMyField(). 495 // name, e.g. MyField for .getMyField().
384 string JSGetterName(const FieldDescriptor* field) { 496 string JSGetterName(const FieldDescriptor* field,
497 BytesMode bytes_mode = BYTES_DEFAULT) {
385 string name = JSIdent(field, 498 string name = JSIdent(field,
386 /* is_upper_camel = */ true, 499 /* is_upper_camel = */ true,
387 /* is_map = */ false); 500 /* is_map = */ false);
501 if (field->type() == FieldDescriptor::TYPE_BYTES) {
502 string suffix = JSByteGetterSuffix(bytes_mode);
503 if (!suffix.empty()) {
504 name += "_as" + suffix;
505 }
506 }
388 if (name == "Extension" || name == "JsPbMessageId") { 507 if (name == "Extension" || name == "JsPbMessageId") {
389 // Avoid conflicts with base-class names. 508 // Avoid conflicts with base-class names.
390 name += "$"; 509 name += "$";
391 } 510 }
392 return name; 511 return name;
393 } 512 }
394 513
395 string JSMapGetterName(const FieldDescriptor* field) { 514 string JSMapGetterName(const FieldDescriptor* field) {
396 return JSIdent(field, 515 return JSIdent(field,
397 /* is_upper_camel = */ true, 516 /* is_upper_camel = */ true,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 break; // inner loop 557 break; // inner loop
439 } 558 }
440 } 559 }
441 if (o == oneof) { 560 if (o == oneof) {
442 break; 561 break;
443 } 562 }
444 } 563 }
445 return SimpleItoa(index); 564 return SimpleItoa(index);
446 } 565 }
447 566
448 // Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only 567 // Decodes a codepoint in \x0000 -- \xFFFF.
449 // need to handle the BMP (16-bit range) here.
450 uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { 568 uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) {
451 if (*length == 0) { 569 if (*length == 0) {
452 return 0; 570 return 0;
453 } 571 }
454 size_t expected = 0; 572 size_t expected = 0;
455 if ((*bytes & 0x80) == 0) { 573 if ((*bytes & 0x80) == 0) {
456 expected = 1; 574 expected = 1;
457 } else if ((*bytes & 0xe0) == 0xc0) { 575 } else if ((*bytes & 0xe0) == 0xc0) {
458 expected = 2; 576 expected = 2;
459 } else if ((*bytes & 0xf0) == 0xe0) { 577 } else if ((*bytes & 0xf0) == 0xe0) {
(...skipping 16 matching lines...) Expand all
476 case 2: return ((bytes[0] & 0x1F) << 6) | 594 case 2: return ((bytes[0] & 0x1F) << 6) |
477 ((bytes[1] & 0x3F) << 0); 595 ((bytes[1] & 0x3F) << 0);
478 case 3: return ((bytes[0] & 0x0F) << 12) | 596 case 3: return ((bytes[0] & 0x0F) << 12) |
479 ((bytes[1] & 0x3F) << 6) | 597 ((bytes[1] & 0x3F) << 6) |
480 ((bytes[2] & 0x3F) << 0); 598 ((bytes[2] & 0x3F) << 0);
481 default: return 0; 599 default: return 0;
482 } 600 }
483 } 601 }
484 602
485 // Escapes the contents of a string to be included within double-quotes ("") in 603 // Escapes the contents of a string to be included within double-quotes ("") in
486 // JavaScript. |is_utf8| determines whether the input data (in a C++ string of 604 // JavaScript. The input data should be a UTF-8 encoded C++ string of chars.
487 // chars) is UTF-8 encoded (in which case codepoints become JavaScript string 605 // Returns false if |out| was truncated because |in| contained invalid UTF-8 or
488 // characters, escaped with 16-bit hex escapes where necessary) or raw binary 606 // codepoints outside the BMP.
489 // (in which case bytes become JavaScript string characters 0 -- 255). 607 // TODO(lukestebbing): Support codepoints outside the BMP.
490 string EscapeJSString(const string& in, bool is_utf8) { 608 bool EscapeJSString(const string& in, string* out) {
491 string result;
492 size_t decoded = 0; 609 size_t decoded = 0;
493 for (size_t i = 0; i < in.size(); i += decoded) { 610 for (size_t i = 0; i < in.size(); i += decoded) {
494 uint16 codepoint = 0; 611 uint16 codepoint = 0;
495 if (is_utf8) { 612 // Decode the next UTF-8 codepoint.
496 // Decode the next UTF-8 codepoint. 613 size_t have_bytes = in.size() - i;
497 size_t have_bytes = in.size() - i; 614 uint8 bytes[3] = {
498 uint8 bytes[3] = {
499 static_cast<uint8>(in[i]), 615 static_cast<uint8>(in[i]),
500 static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0), 616 static_cast<uint8>(((i + 1) < in.size()) ? in[i + 1] : 0),
501 static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0), 617 static_cast<uint8>(((i + 2) < in.size()) ? in[i + 2] : 0),
502 }; 618 };
503 codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); 619 codepoint = DecodeUTF8Codepoint(bytes, &have_bytes);
504 if (have_bytes == 0) { 620 if (have_bytes == 0) {
505 break; 621 return false;
506 }
507 decoded = have_bytes;
508 } else {
509 codepoint = static_cast<uint16>(static_cast<uint8>(in[i]));
510 decoded = 1;
511 } 622 }
512 623 decoded = have_bytes;
513 // Next byte -- used for minimal octal escapes below.
514 char next_byte = (i + decoded) < in.size() ?
515 in[i + decoded] : 0;
516 bool pad_octal = (next_byte >= '0' && next_byte <= '7');
517 624
518 switch (codepoint) { 625 switch (codepoint) {
519 case '\0': result += pad_octal ? "\\000" : "\\0"; break; 626 case '\'': *out += "\\x27"; break;
520 case '\b': result += "\\\b"; break; 627 case '"': *out += "\\x22"; break;
521 case '\t': result += "\\\t"; break; 628 case '<': *out += "\\x3c"; break;
522 case '\n': result += "\\\n"; break; 629 case '=': *out += "\\x3d"; break;
523 case '\r': result += "\\\r"; break; 630 case '>': *out += "\\x3e"; break;
524 case '\f': result += "\\\f"; break; 631 case '&': *out += "\\x26"; break;
525 case '\\': result += "\\\\"; break; 632 case '\b': *out += "\\b"; break;
526 case '"': result += pad_octal ? "\\042" : "\\42"; break; 633 case '\t': *out += "\\t"; break;
527 case '&': result += pad_octal ? "\\046" : "\\46"; break; 634 case '\n': *out += "\\n"; break;
528 case '\'': result += pad_octal ? "\\047" : "\\47"; break; 635 case '\f': *out += "\\f"; break;
529 case '<': result += pad_octal ? "\\074" : "\\74"; break; 636 case '\r': *out += "\\r"; break;
530 case '=': result += pad_octal ? "\\075" : "\\75"; break; 637 case '\\': *out += "\\\\"; break;
531 case '>': result += pad_octal ? "\\076" : "\\76"; break;
532 default: 638 default:
533 // All other non-ASCII codepoints are escaped. 639 // TODO(lukestebbing): Once we're supporting codepoints outside the BMP,
534 // Original codegen uses hex for >= 0x100 and octal for others. 640 // use a single Unicode codepoint escape if the output language is
641 // ECMAScript 2015 or above. Otherwise, use a surrogate pair.
642 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lex ical_grammar#String_literals
535 if (codepoint >= 0x20 && codepoint <= 0x7e) { 643 if (codepoint >= 0x20 && codepoint <= 0x7e) {
536 result += static_cast<char>(codepoint); 644 *out += static_cast<char>(codepoint);
645 } else if (codepoint >= 0x100) {
646 *out += StringPrintf("\\u%04x", codepoint);
537 } else { 647 } else {
538 if (codepoint >= 0x100) { 648 *out += StringPrintf("\\x%02x", codepoint);
539 result += StringPrintf("\\u%04x", codepoint);
540 } else {
541 if (pad_octal || codepoint >= 0100) {
542 result += "\\";
543 result += ('0' + ((codepoint >> 6) & 07));
544 result += ('0' + ((codepoint >> 3) & 07));
545 result += ('0' + ((codepoint >> 0) & 07));
546 } else if (codepoint >= 010) {
547 result += "\\";
548 result += ('0' + ((codepoint >> 3) & 07));
549 result += ('0' + ((codepoint >> 0) & 07));
550 } else {
551 result += "\\";
552 result += ('0' + ((codepoint >> 0) & 07));
553 }
554 }
555 } 649 }
556 break; 650 break;
557 } 651 }
558 } 652 }
559 return result; 653 return true;
560 } 654 }
561 655
562 string EscapeBase64(const string& in) { 656 string EscapeBase64(const string& in) {
563 static const char* kAlphabet = 657 static const char* kAlphabet =
564 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 658 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
565 string result; 659 string result;
566 660
567 for (size_t i = 0; i < in.size(); i += 3) { 661 for (size_t i = 0; i < in.size(); i += 3) {
568 int value = (in[i] << 16) | 662 int value = (in[i] << 16) |
569 (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) | 663 (((i + 1) < in.size()) ? (in[i + 1] << 8) : 0) |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
674 case FieldDescriptor::CPPTYPE_ENUM: 768 case FieldDescriptor::CPPTYPE_ENUM:
675 return SimpleItoa(field->default_value_enum()->number()); 769 return SimpleItoa(field->default_value_enum()->number());
676 case FieldDescriptor::CPPTYPE_BOOL: 770 case FieldDescriptor::CPPTYPE_BOOL:
677 return field->default_value_bool() ? "true" : "false"; 771 return field->default_value_bool() ? "true" : "false";
678 case FieldDescriptor::CPPTYPE_FLOAT: 772 case FieldDescriptor::CPPTYPE_FLOAT:
679 return FloatToString(field->default_value_float()); 773 return FloatToString(field->default_value_float());
680 case FieldDescriptor::CPPTYPE_DOUBLE: 774 case FieldDescriptor::CPPTYPE_DOUBLE:
681 return DoubleToString(field->default_value_double()); 775 return DoubleToString(field->default_value_double());
682 case FieldDescriptor::CPPTYPE_STRING: 776 case FieldDescriptor::CPPTYPE_STRING:
683 if (field->type() == FieldDescriptor::TYPE_STRING) { 777 if (field->type() == FieldDescriptor::TYPE_STRING) {
684 return "\"" + EscapeJSString(field->default_value_string(), true) + 778 string out;
685 "\""; 779 bool is_valid = EscapeJSString(field->default_value_string(), &out);
686 } else { 780 if (!is_valid) {
687 return "\"" + EscapeBase64(field->default_value_string()) + 781 // TODO(lukestebbing): Decide whether this should be a hard error.
688 "\""; 782 GOOGLE_LOG(WARNING) << "The default value for field " << field->full_n ame()
783 << " was truncated since it contained invalid UTF-8 or"
784 " codepoints outside the basic multilingual plane.";
785 }
786 return "\"" + out + "\"";
787 } else { // Bytes
788 return "\"" + EscapeBase64(field->default_value_string()) + "\"";
689 } 789 }
690 case FieldDescriptor::CPPTYPE_MESSAGE: 790 case FieldDescriptor::CPPTYPE_MESSAGE:
691 return "null"; 791 return "null";
692 } 792 }
693 GOOGLE_LOG(FATAL) << "Shouldn't reach here."; 793 GOOGLE_LOG(FATAL) << "Shouldn't reach here.";
694 return ""; 794 return "";
695 } 795 }
696 796
697 string ProtoTypeName(const GeneratorOptions& options, 797 string ProtoTypeName(const GeneratorOptions& options,
698 const FieldDescriptor* field) { 798 const FieldDescriptor* field) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 return GetPath(options, field->message_type()); 835 return GetPath(options, field->message_type());
736 default: 836 default:
737 return ""; 837 return "";
738 } 838 }
739 } 839 }
740 840
741 string JSIntegerTypeName(const FieldDescriptor* field) { 841 string JSIntegerTypeName(const FieldDescriptor* field) {
742 return "number"; 842 return "number";
743 } 843 }
744 844
845 string JSStringTypeName(const GeneratorOptions& options,
846 const FieldDescriptor* field,
847 BytesMode bytes_mode) {
848 if (field->type() == FieldDescriptor::TYPE_BYTES) {
849 switch (bytes_mode) {
850 case BYTES_DEFAULT:
851 return "(string|Uint8Array)";
852 case BYTES_B64:
853 return "string";
854 case BYTES_U8:
855 return "Uint8Array";
856 default:
857 assert(false);
858 }
859 }
860 return "string";
861 }
862
745 string JSTypeName(const GeneratorOptions& options, 863 string JSTypeName(const GeneratorOptions& options,
746 const FieldDescriptor* field) { 864 const FieldDescriptor* field,
865 BytesMode bytes_mode) {
747 switch (field->cpp_type()) { 866 switch (field->cpp_type()) {
748 case FieldDescriptor::CPPTYPE_BOOL: 867 case FieldDescriptor::CPPTYPE_BOOL:
749 return "boolean"; 868 return "boolean";
750 case FieldDescriptor::CPPTYPE_INT32: 869 case FieldDescriptor::CPPTYPE_INT32:
751 return JSIntegerTypeName(field); 870 return JSIntegerTypeName(field);
752 case FieldDescriptor::CPPTYPE_INT64: 871 case FieldDescriptor::CPPTYPE_INT64:
753 return JSIntegerTypeName(field); 872 return JSIntegerTypeName(field);
754 case FieldDescriptor::CPPTYPE_UINT32: 873 case FieldDescriptor::CPPTYPE_UINT32:
755 return JSIntegerTypeName(field); 874 return JSIntegerTypeName(field);
756 case FieldDescriptor::CPPTYPE_UINT64: 875 case FieldDescriptor::CPPTYPE_UINT64:
757 return JSIntegerTypeName(field); 876 return JSIntegerTypeName(field);
758 case FieldDescriptor::CPPTYPE_FLOAT: 877 case FieldDescriptor::CPPTYPE_FLOAT:
759 return "number"; 878 return "number";
760 case FieldDescriptor::CPPTYPE_DOUBLE: 879 case FieldDescriptor::CPPTYPE_DOUBLE:
761 return "number"; 880 return "number";
762 case FieldDescriptor::CPPTYPE_STRING: 881 case FieldDescriptor::CPPTYPE_STRING:
763 return "string"; 882 return JSStringTypeName(options, field, bytes_mode);
764 case FieldDescriptor::CPPTYPE_ENUM: 883 case FieldDescriptor::CPPTYPE_ENUM:
765 return GetPath(options, field->enum_type()); 884 return GetPath(options, field->enum_type());
766 case FieldDescriptor::CPPTYPE_MESSAGE: 885 case FieldDescriptor::CPPTYPE_MESSAGE:
767 return GetPath(options, field->message_type()); 886 return GetPath(options, field->message_type());
768 default: 887 default:
769 return ""; 888 return "";
770 } 889 }
771 } 890 }
772 891
773 bool HasFieldPresence(const FieldDescriptor* field); 892 bool HasFieldPresence(const FieldDescriptor* field);
774 893
775 string JSFieldTypeAnnotation(const GeneratorOptions& options, 894 string JSFieldTypeAnnotation(const GeneratorOptions& options,
776 const FieldDescriptor* field, 895 const FieldDescriptor* field,
777 bool force_optional, 896 bool force_optional,
778 bool force_present, 897 bool force_present,
779 bool singular_if_not_packed, 898 bool singular_if_not_packed,
780 bool always_singular) { 899 BytesMode bytes_mode = BYTES_DEFAULT) {
781 bool is_primitive = 900 bool is_primitive =
782 (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && 901 (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM &&
783 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE); 902 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE &&
903 (field->type() != FieldDescriptor::TYPE_BYTES ||
904 bytes_mode == BYTES_B64));
784 905
785 string jstype = JSTypeName(options, field); 906 string jstype = JSTypeName(options, field, bytes_mode);
786 907
787 if (field->is_repeated() && 908 if (field->is_repeated() &&
788 !always_singular &&
789 (field->is_packed() || !singular_if_not_packed)) { 909 (field->is_packed() || !singular_if_not_packed)) {
790 if (!is_primitive) { 910 if (field->type() == FieldDescriptor::TYPE_BYTES &&
791 jstype = "!" + jstype; 911 bytes_mode == BYTES_DEFAULT) {
912 jstype = "(Array<!Uint8Array>|Array<string>)";
913 } else {
914 if (!is_primitive) {
915 jstype = "!" + jstype;
916 }
917 jstype = "Array.<" + jstype + ">";
792 } 918 }
793 jstype = "Array.<" + jstype + ">";
794 if (!force_optional) { 919 if (!force_optional) {
795 jstype = "!" + jstype; 920 jstype = "!" + jstype;
796 } 921 }
797 } 922 }
798 923
799 if (field->is_optional() && is_primitive && 924 if (field->is_optional() && is_primitive &&
800 (!field->has_default_value() || force_optional) && !force_present) { 925 (!field->has_default_value() || force_optional) && !force_present) {
801 jstype += "?"; 926 jstype += "?";
802 } else if (field->is_required() && !is_primitive && !force_optional) { 927 } else if (field->is_required() && !is_primitive && !force_optional) {
803 jstype = "!" + jstype; 928 jstype = "!" + jstype;
(...skipping 14 matching lines...) Expand all
818 if (name[0] >= 'a' && name[0] <= 'z') { 943 if (name[0] >= 'a' && name[0] <= 'z') {
819 name[0] = (name[0] - 'a') + 'A'; 944 name[0] = (name[0] - 'a') + 'A';
820 } 945 }
821 946
822 return name; 947 return name;
823 } 948 }
824 949
825 string JSBinaryReadWriteMethodName(const FieldDescriptor* field, 950 string JSBinaryReadWriteMethodName(const FieldDescriptor* field,
826 bool is_writer) { 951 bool is_writer) {
827 string name = JSBinaryReaderMethodType(field); 952 string name = JSBinaryReaderMethodType(field);
828 if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) {
829 // Override for `bytes` fields: treat string as raw bytes, not base64.
830 name = "BytesRawString";
831 }
832 if (field->is_packed()) { 953 if (field->is_packed()) {
833 name = "Packed" + name; 954 name = "Packed" + name;
834 } else if (is_writer && field->is_repeated()) { 955 } else if (is_writer && field->is_repeated()) {
835 name = "Repeated" + name; 956 name = "Repeated" + name;
836 } 957 }
837 return name; 958 return name;
838 } 959 }
839 960
840 string JSBinaryReaderMethodName(const FieldDescriptor* field) { 961 string JSBinaryReaderMethodName(const FieldDescriptor* field) {
841 return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false); 962 return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 } 1066 }
946 if (type[i] == '.' && i >= package.size()) { 1067 if (type[i] == '.' && i >= package.size()) {
947 prefix = i + 1; 1068 prefix = i + 1;
948 } 1069 }
949 } 1070 }
950 1071
951 return type.substr(prefix); 1072 return type.substr(prefix);
952 } 1073 }
953 1074
954 string JSExtensionsObjectName(const GeneratorOptions& options, 1075 string JSExtensionsObjectName(const GeneratorOptions& options,
1076 const FileDescriptor* from_file,
955 const Descriptor* desc) { 1077 const Descriptor* desc) {
956 if (desc->full_name() == "google.protobuf.bridge.MessageSet") { 1078 if (desc->full_name() == "google.protobuf.bridge.MessageSet") {
1079 // TODO(haberman): fix this for the IMPORT_COMMONJS case.
957 return "jspb.Message.messageSetExtensions"; 1080 return "jspb.Message.messageSetExtensions";
958 } else { 1081 } else {
959 return GetPath(options, desc) + ".extensions"; 1082 return MaybeCrossFileRef(options, from_file, desc) + ".extensions";
960 } 1083 }
961 } 1084 }
962 1085
963 string FieldDefinition(const GeneratorOptions& options, 1086 string FieldDefinition(const GeneratorOptions& options,
964 const FieldDescriptor* field) { 1087 const FieldDescriptor* field) {
965 string qualifier = field->is_repeated() ? "repeated" : 1088 string qualifier = field->is_repeated() ? "repeated" :
966 (field->is_optional() ? "optional" : "required"); 1089 (field->is_optional() ? "optional" : "required");
967 string type, name; 1090 string type, name;
968 if (field->type() == FieldDescriptor::TYPE_ENUM || 1091 if (field->type() == FieldDescriptor::TYPE_ENUM ||
969 field->type() == FieldDescriptor::TYPE_MESSAGE) { 1092 field->type() == FieldDescriptor::TYPE_MESSAGE) {
970 type = RelativeTypeName(field); 1093 type = RelativeTypeName(field);
971 name = field->name(); 1094 name = field->name();
972 } else if (field->type() == FieldDescriptor::TYPE_GROUP) { 1095 } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
973 type = "group"; 1096 type = "group";
974 name = field->message_type()->name(); 1097 name = field->message_type()->name();
975 } else { 1098 } else {
976 type = ProtoTypeName(options, field); 1099 type = ProtoTypeName(options, field);
977 name = field->name(); 1100 name = field->name();
978 } 1101 }
979 return StringPrintf("%s %s %s = %d;", 1102 return StringPrintf("%s %s %s = %d;",
980 qualifier.c_str(), 1103 qualifier.c_str(),
981 type.c_str(), 1104 type.c_str(),
982 name.c_str(), 1105 name.c_str(),
983 field->number()); 1106 field->number());
984 } 1107 }
985 1108
986 string FieldComments(const FieldDescriptor* field) { 1109 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
987 string comments; 1110 string comments;
988 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { 1111 if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) {
989 comments += 1112 comments +=
990 " * Note that Boolean fields may be set to 0/1 when serialized from " 1113 " * Note that Boolean fields may be set to 0/1 when serialized from "
991 "a Java server.\n" 1114 "a Java server.\n"
992 " * You should avoid comparisons like {@code val === true/false} in " 1115 " * You should avoid comparisons like {@code val === true/false} in "
993 "those cases.\n"; 1116 "those cases.\n";
994 } 1117 }
995 if (field->is_repeated()) { 1118 if (field->is_repeated()) {
996 comments += 1119 comments +=
997 " * If you change this array by adding, removing or replacing " 1120 " * If you change this array by adding, removing or replacing "
998 "elements, or if you\n" 1121 "elements, or if you\n"
999 " * replace the array itself, then you must call the setter to " 1122 " * replace the array itself, then you must call the setter to "
1000 "update it.\n"; 1123 "update it.\n";
1001 } 1124 }
1125 if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) {
1126 comments +=
1127 " * Note that Uint8Array is not supported on all browsers.\n"
1128 " * @see http://caniuse.com/Uint8Array\n";
1129 }
1002 return comments; 1130 return comments;
1003 } 1131 }
1004 1132
1005 bool ShouldGenerateExtension(const FieldDescriptor* field) { 1133 bool ShouldGenerateExtension(const FieldDescriptor* field) {
1006 return 1134 return
1007 field->is_extension() && 1135 field->is_extension() &&
1008 !IgnoreField(field); 1136 !IgnoreField(field);
1009 } 1137 }
1010 1138
1011 bool HasExtensions(const Descriptor* desc) { 1139 bool HasExtensions(const Descriptor* desc) {
1012 if (desc->extension_count() > 0) { 1140 for (int i = 0; i < desc->extension_count(); i++) {
1013 return true; 1141 if (ShouldGenerateExtension(desc->extension(i))) {
1142 return true;
1143 }
1014 } 1144 }
1015 for (int i = 0; i < desc->nested_type_count(); i++) { 1145 for (int i = 0; i < desc->nested_type_count(); i++) {
1016 if (HasExtensions(desc->nested_type(i))) { 1146 if (HasExtensions(desc->nested_type(i))) {
1017 return true; 1147 return true;
1018 } 1148 }
1019 } 1149 }
1020 return false; 1150 return false;
1021 } 1151 }
1022 1152
1023 bool HasExtensions(const FileDescriptor* file) { 1153 bool HasExtensions(const FileDescriptor* file) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 int pivot = -1; 1185 int pivot = -1;
1056 if (IsExtendable(desc)) { 1186 if (IsExtendable(desc)) {
1057 pivot = ((max_field_number + 1) < kDefaultPivot) ? 1187 pivot = ((max_field_number + 1) < kDefaultPivot) ?
1058 (max_field_number + 1) : kDefaultPivot; 1188 (max_field_number + 1) : kDefaultPivot;
1059 } 1189 }
1060 1190
1061 return SimpleItoa(pivot); 1191 return SimpleItoa(pivot);
1062 } 1192 }
1063 1193
1064 // Returns true for fields that represent "null" as distinct from the default 1194 // Returns true for fields that represent "null" as distinct from the default
1065 // value. See https://go/proto3#heading=h.kozewqqcqhuz for more information. 1195 // value. See http://go/proto3#heading=h.kozewqqcqhuz for more information.
1066 bool HasFieldPresence(const FieldDescriptor* field) { 1196 bool HasFieldPresence(const FieldDescriptor* field) {
1067 return 1197 return
1068 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || 1198 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ||
1069 (field->containing_oneof() != NULL) || 1199 (field->containing_oneof() != NULL) ||
1070 (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3); 1200 (field->file()->syntax() != FileDescriptor::SYNTAX_PROTO3);
1071 } 1201 }
1072 1202
1073 // For proto3 fields without presence, returns a string representing the default 1203 // For proto3 fields without presence, returns a string representing the default
1074 // value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more 1204 // value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more
1075 // information. 1205 // information.
1076 string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { 1206 string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) {
1077 switch (field->cpp_type()) { 1207 switch (field->cpp_type()) {
1078 case FieldDescriptor::CPPTYPE_INT32: 1208 case FieldDescriptor::CPPTYPE_INT32:
1079 case FieldDescriptor::CPPTYPE_INT64: 1209 case FieldDescriptor::CPPTYPE_INT64:
1080 case FieldDescriptor::CPPTYPE_UINT32: 1210 case FieldDescriptor::CPPTYPE_UINT32:
1081 case FieldDescriptor::CPPTYPE_UINT64: { 1211 case FieldDescriptor::CPPTYPE_UINT64: {
1082 return "0"; 1212 return "0";
1083 } 1213 }
1084 1214
1085 case FieldDescriptor::CPPTYPE_ENUM: 1215 case FieldDescriptor::CPPTYPE_ENUM:
1086 case FieldDescriptor::CPPTYPE_FLOAT: 1216 case FieldDescriptor::CPPTYPE_FLOAT:
1087 case FieldDescriptor::CPPTYPE_DOUBLE: 1217 case FieldDescriptor::CPPTYPE_DOUBLE:
1088 return "0"; 1218 return "0";
1089 1219
1090 case FieldDescriptor::CPPTYPE_BOOL: 1220 case FieldDescriptor::CPPTYPE_BOOL:
1091 return "false"; 1221 return "false";
1092 1222
1093 case FieldDescriptor::CPPTYPE_STRING: 1223 case FieldDescriptor::CPPTYPE_STRING: // includes BYTES
1094 return "\"\""; 1224 return "\"\"";
1095 1225
1096 default: 1226 default:
1097 // BYTES and MESSAGE are handled separately. 1227 // MESSAGE is handled separately.
1098 assert(false); 1228 assert(false);
1099 return ""; 1229 return "";
1100 } 1230 }
1101 } 1231 }
1102 1232
1233 // 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,
1235 // but we keep a set of which descriptors were the final one for a given
1236 // filename.
1237 class FileDeduplicator {
1238 public:
1239 explicit FileDeduplicator(const GeneratorOptions& options)
1240 : error_on_conflict_(options.error_on_name_conflict) {}
1241
1242 bool AddFile(const string& filename, const void* desc, string* error) {
1243 if (descs_by_filename_.find(filename) != descs_by_filename_.end()) {
1244 if (error_on_conflict_) {
1245 *error = "Name conflict: file name " + filename +
1246 " would be generated by two descriptors";
1247 return false;
1248 }
1249 allowed_descs_.erase(descs_by_filename_[filename]);
1250 }
1251
1252 descs_by_filename_[filename] = desc;
1253 allowed_descs_.insert(desc);
1254 return true;
1255 }
1256
1257 void GetAllowedSet(set<const void*>* allowed_set) {
1258 *allowed_set = allowed_descs_;
1259 }
1260
1261 private:
1262 bool error_on_conflict_;
1263 map<string, const void*> descs_by_filename_;
1264 set<const void*> allowed_descs_;
1265 };
1266
1267 void DepthFirstSearch(const FileDescriptor* file,
1268 vector<const FileDescriptor*>* list,
1269 set<const FileDescriptor*>* seen) {
1270 if (!seen->insert(file).second) {
1271 return;
1272 }
1273
1274 // Add all dependencies.
1275 for (int i = 0; i < file->dependency_count(); i++) {
1276 DepthFirstSearch(file->dependency(i), list, seen);
1277 }
1278
1279 // Add this file.
1280 list->push_back(file);
1281 }
1282
1283 // A functor for the predicate to remove_if() below. Returns true if a given
1284 // FileDescriptor is not in the given set.
1285 class NotInSet {
1286 public:
1287 explicit NotInSet(const set<const FileDescriptor*>& file_set)
1288 : file_set_(file_set) {}
1289
1290 bool operator()(const FileDescriptor* file) {
1291 return file_set_.count(file) == 0;
1292 }
1293
1294 private:
1295 const set<const FileDescriptor*>& file_set_;
1296 };
1297
1298 // This function generates an ordering of the input FileDescriptors that matches
1299 // the logic of the old code generator. The order is significant because two
1300 // different input files can generate the same output file, and the last one
1301 // needs to win.
1302 void GenerateJspbFileOrder(const vector<const FileDescriptor*>& input,
1303 vector<const FileDescriptor*>* ordered) {
1304 // First generate an ordering of all reachable files (including dependencies)
1305 // with depth-first search. This mimics the behavior of --include_imports,
1306 // which is what the old codegen used.
1307 ordered->clear();
1308 set<const FileDescriptor*> seen;
1309 set<const FileDescriptor*> input_set;
1310 for (int i = 0; i < input.size(); i++) {
1311 DepthFirstSearch(input[i], ordered, &seen);
1312 input_set.insert(input[i]);
1313 }
1314
1315 // Now remove the entries that are not actually in our input list.
1316 ordered->erase(
1317 std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)),
1318 ordered->end());
1319 }
1320
1321 // If we're generating code in file-per-type mode, avoid overwriting files
1322 // by choosing the last descriptor that writes each filename and permitting
1323 // only those to generate code.
1324
1325 bool GenerateJspbAllowedSet(const GeneratorOptions& options,
1326 const vector<const FileDescriptor*>& files,
1327 set<const void*>* allowed_set,
1328 string* error) {
1329 vector<const FileDescriptor*> files_ordered;
1330 GenerateJspbFileOrder(files, &files_ordered);
1331
1332 // Choose the last descriptor for each filename.
1333 FileDeduplicator dedup(options);
1334 for (int i = 0; i < files_ordered.size(); i++) {
1335 for (int j = 0; j < files_ordered[i]->message_type_count(); j++) {
1336 const Descriptor* desc = files_ordered[i]->message_type(j);
1337 if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) {
1338 return false;
1339 }
1340 }
1341 for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) {
1342 const EnumDescriptor* desc = files_ordered[i]->enum_type(j);
1343 if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) {
1344 return false;
1345 }
1346 }
1347
1348 // Pull out all free-floating extensions and generate files for those too.
1349 bool has_extension = false;
1350
1351 for (int j = 0; j < files_ordered[i]->extension_count(); j++) {
1352 if (ShouldGenerateExtension(files_ordered[i]->extension(j))) {
1353 has_extension = true;
1354 }
1355 }
1356
1357 if (has_extension) {
1358 if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]),
1359 files_ordered[i], error)) {
1360 return false;
1361 }
1362 }
1363 }
1364
1365 dedup.GetAllowedSet(allowed_set);
1366
1367 return true;
1368 }
1369
1103 } // anonymous namespace 1370 } // anonymous namespace
1104 1371
1105 void Generator::GenerateHeader(const GeneratorOptions& options, 1372 void Generator::GenerateHeader(const GeneratorOptions& options,
1106 io::Printer* printer) const { 1373 io::Printer* printer) const {
1107 printer->Print("/**\n" 1374 printer->Print("/**\n"
1108 " * @fileoverview\n" 1375 " * @fileoverview\n"
1109 " * @enhanceable\n" 1376 " * @enhanceable\n"
1110 " * @public\n" 1377 " * @public\n"
1111 " */\n" 1378 " */\n"
1112 "// GENERATED CODE -- DO NOT EDIT!\n" 1379 "// GENERATED CODE -- DO NOT EDIT!\n"
1113 "\n"); 1380 "\n");
1114 } 1381 }
1115 1382
1383 void Generator::FindProvidesForFile(const GeneratorOptions& options,
1384 io::Printer* printer,
1385 const FileDescriptor* file,
1386 std::set<string>* provided) const {
1387 for (int i = 0; i < file->message_type_count(); i++) {
1388 FindProvidesForMessage(options, printer, file->message_type(i), provided);
1389 }
1390 for (int i = 0; i < file->enum_type_count(); i++) {
1391 FindProvidesForEnum(options, printer, file->enum_type(i), provided);
1392 }
1393 }
1394
1116 void Generator::FindProvides(const GeneratorOptions& options, 1395 void Generator::FindProvides(const GeneratorOptions& options,
1117 io::Printer* printer, 1396 io::Printer* printer,
1118 const vector<const FileDescriptor*>& files, 1397 const vector<const FileDescriptor*>& files,
1119 std::set<string>* provided) const { 1398 std::set<string>* provided) const {
1120 for (int i = 0; i < files.size(); i++) { 1399 for (int i = 0; i < files.size(); i++) {
1121 for (int j = 0; j < files[i]->message_type_count(); j++) { 1400 FindProvidesForFile(options, printer, files[i], provided);
1122 FindProvidesForMessage(options, printer, files[i]->message_type(j),
1123 provided);
1124 }
1125 for (int j = 0; j < files[i]->enum_type_count(); j++) {
1126 FindProvidesForEnum(options, printer, files[i]->enum_type(j),
1127 provided);
1128 }
1129 } 1401 }
1130 1402
1131 printer->Print("\n"); 1403 printer->Print("\n");
1132 } 1404 }
1133 1405
1134 void Generator::FindProvidesForMessage( 1406 void Generator::FindProvidesForMessage(
1135 const GeneratorOptions& options, 1407 const GeneratorOptions& options,
1136 io::Printer* printer, 1408 io::Printer* printer,
1137 const Descriptor* desc, 1409 const Descriptor* desc,
1138 std::set<string>* provided) const { 1410 std::set<string>* provided) const {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1178 void Generator::GenerateProvides(const GeneratorOptions& options, 1450 void Generator::GenerateProvides(const GeneratorOptions& options,
1179 io::Printer* printer, 1451 io::Printer* printer,
1180 std::set<string>* provided) const { 1452 std::set<string>* provided) const {
1181 for (std::set<string>::iterator it = provided->begin(); 1453 for (std::set<string>::iterator it = provided->begin();
1182 it != provided->end(); ++it) { 1454 it != provided->end(); ++it) {
1183 printer->Print("goog.provide('$name$');\n", 1455 printer->Print("goog.provide('$name$');\n",
1184 "name", *it); 1456 "name", *it);
1185 } 1457 }
1186 } 1458 }
1187 1459
1188 void Generator::GenerateRequires(const GeneratorOptions& options, 1460 void Generator::GenerateRequiresForMessage(const GeneratorOptions& options,
1189 io::Printer* printer, 1461 io::Printer* printer,
1190 const Descriptor* desc, 1462 const Descriptor* desc,
1191 std::set<string>* provided) const { 1463 std::set<string>* provided) const {
1192 std::set<string> required; 1464 std::set<string> required;
1193 std::set<string> forwards; 1465 std::set<string> forwards;
1194 bool have_message = false; 1466 bool have_message = false;
1195 FindRequiresForMessage(options, desc, 1467 FindRequiresForMessage(options, desc,
1196 &required, &forwards, &have_message); 1468 &required, &forwards, &have_message);
1197 1469
1198 GenerateRequiresImpl(options, printer, &required, &forwards, provided, 1470 GenerateRequiresImpl(options, printer, &required, &forwards, provided,
1199 /* require_jspb = */ have_message, 1471 /* require_jspb = */ have_message,
1200 /* require_extension = */ HasExtensions(desc)); 1472 /* require_extension = */ HasExtensions(desc));
1201 } 1473 }
1202 1474
1203 void Generator::GenerateRequires(const GeneratorOptions& options, 1475 void Generator::GenerateRequiresForLibrary(
1204 io::Printer* printer, 1476 const GeneratorOptions& options, io::Printer* printer,
1205 const vector<const FileDescriptor*>& files, 1477 const vector<const FileDescriptor*>& files,
1206 std::set<string>* provided) const { 1478 std::set<string>* provided) const {
1479 GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE);
1480 // For Closure imports we need to import every message type individually.
1207 std::set<string> required; 1481 std::set<string> required;
1208 std::set<string> forwards; 1482 std::set<string> forwards;
1209 bool have_extensions = false; 1483 bool have_extensions = false;
1210 bool have_message = false; 1484 bool have_message = false;
1211 1485
1212 for (int i = 0; i < files.size(); i++) { 1486 for (int i = 0; i < files.size(); i++) {
1213 for (int j = 0; j < files[i]->message_type_count(); j++) { 1487 for (int j = 0; j < files[i]->message_type_count(); j++) {
1214 FindRequiresForMessage(options, 1488 FindRequiresForMessage(options,
1215 files[i]->message_type(j), 1489 files[i]->message_type(j),
1216 &required, &forwards, &have_message); 1490 &required, &forwards, &have_message);
1217 } 1491 }
1218 if (!have_extensions && HasExtensions(files[i])) { 1492 if (!have_extensions && HasExtensions(files[i])) {
1219 have_extensions = true; 1493 have_extensions = true;
1220 } 1494 }
1221 1495
1222 for (int j = 0; j < files[i]->extension_count(); j++) { 1496 for (int j = 0; j < files[i]->extension_count(); j++) {
1223 const FieldDescriptor* extension = files[i]->extension(j); 1497 const FieldDescriptor* extension = files[i]->extension(j);
1224 if (IgnoreField(extension)) { 1498 if (IgnoreField(extension)) {
1225 continue; 1499 continue;
1226 } 1500 }
1227 if (extension->containing_type()->full_name() != 1501 if (extension->containing_type()->full_name() !=
1228 "google.protobuf.bridge.MessageSet") { 1502 "google.protobuf.bridge.MessageSet") {
1229 required.insert(GetPath(options, extension->containing_type())); 1503 required.insert(GetPath(options, extension->containing_type()));
1230 } 1504 }
1231 FindRequiresForField(options, extension, &required, &forwards); 1505 FindRequiresForField(options, extension, &required, &forwards);
1232 have_extensions = true; 1506 have_extensions = true;
1233 } 1507 }
1234 } 1508 }
1235 1509
1236 GenerateRequiresImpl(options, printer, &required, &forwards, provided, 1510 GenerateRequiresImpl(options, printer, &required, &forwards, provided,
1237 /* require_jspb = */ have_message, 1511 /* require_jspb = */ have_message,
1238 /* require_extension = */ have_extensions); 1512 /* require_extension = */ have_extensions);
1239 } 1513 }
1240 1514
1241 void Generator::GenerateRequires(const GeneratorOptions& options, 1515 void Generator::GenerateRequiresForExtensions(
1242 io::Printer* printer, 1516 const GeneratorOptions& options, io::Printer* printer,
1243 const vector<const FieldDescriptor*>& fields, 1517 const vector<const FieldDescriptor*>& fields,
1244 std::set<string>* provided) const { 1518 std::set<string>* provided) const {
1245 std::set<string> required; 1519 std::set<string> required;
1246 std::set<string> forwards; 1520 std::set<string> forwards;
1247 for (int i = 0; i < fields.size(); i++) { 1521 for (int i = 0; i < fields.size(); i++) {
1248 const FieldDescriptor* field = fields[i]; 1522 const FieldDescriptor* field = fields[i];
1249 if (IgnoreField(field)) { 1523 if (IgnoreField(field)) {
1250 continue; 1524 continue;
1251 } 1525 }
1252 FindRequiresForExtension(options, field, &required, &forwards); 1526 FindRequiresForExtension(options, field, &required, &forwards);
1253 } 1527 }
1254 1528
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1399 // objects. 1673 // objects.
1400 GenerateClassDeserializeBinary(options, printer, desc); 1674 GenerateClassDeserializeBinary(options, printer, desc);
1401 GenerateClassSerializeBinary(options, printer, desc); 1675 GenerateClassSerializeBinary(options, printer, desc);
1402 } 1676 }
1403 GenerateClassClone(options, printer, desc); 1677 GenerateClassClone(options, printer, desc);
1404 GenerateClassRegistration(options, printer, desc); 1678 GenerateClassRegistration(options, printer, desc);
1405 GenerateClassFields(options, printer, desc); 1679 GenerateClassFields(options, printer, desc);
1406 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa geSet") { 1680 if (IsExtendable(desc) && desc->full_name() != "google.protobuf.bridge.Messa geSet") {
1407 GenerateClassExtensionFieldInfo(options, printer, desc); 1681 GenerateClassExtensionFieldInfo(options, printer, desc);
1408 } 1682 }
1683
1684 if (options.import_style != GeneratorOptions:: IMPORT_CLOSURE) {
1685 for (int i = 0; i < desc->extension_count(); i++) {
1686 GenerateExtension(options, printer, desc->extension(i));
1687 }
1688 }
1409 } 1689 }
1410 1690
1411 // Recurse on nested types. 1691 // Recurse on nested types.
1412 for (int i = 0; i < desc->enum_type_count(); i++) { 1692 for (int i = 0; i < desc->enum_type_count(); i++) {
1413 GenerateEnum(options, printer, desc->enum_type(i)); 1693 GenerateEnum(options, printer, desc->enum_type(i));
1414 } 1694 }
1415 for (int i = 0; i < desc->nested_type_count(); i++) { 1695 for (int i = 0; i < desc->nested_type_count(); i++) {
1416 GenerateClass(options, printer, desc->nested_type(i)); 1696 GenerateClass(options, printer, desc->nested_type(i));
1417 } 1697 }
1418 } 1698 }
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
1616 } else { 1896 } else {
1617 printer->Print("\n\n };\n\n"); 1897 printer->Print("\n\n };\n\n");
1618 } 1898 }
1619 1899
1620 if (IsExtendable(desc)) { 1900 if (IsExtendable(desc)) {
1621 printer->Print( 1901 printer->Print(
1622 " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), " 1902 " jspb.Message.toObjectExtension(/** @type {!jspb.Message} */ (msg), "
1623 "obj,\n" 1903 "obj,\n"
1624 " $extObject$, $class$.prototype.getExtension,\n" 1904 " $extObject$, $class$.prototype.getExtension,\n"
1625 " includeInstance);\n", 1905 " includeInstance);\n",
1626 "extObject", JSExtensionsObjectName(options, desc), 1906 "extObject", JSExtensionsObjectName(options, desc->file(), desc),
1627 "class", GetPath(options, desc)); 1907 "class", GetPath(options, desc));
1628 } 1908 }
1629 1909
1630 printer->Print( 1910 printer->Print(
1631 " if (includeInstance) {\n" 1911 " if (includeInstance) {\n"
1632 " obj.$$jspbMessageInstance = msg\n" 1912 " obj.$$jspbMessageInstance = msg;\n"
1633 " }\n" 1913 " }\n"
1634 " return obj;\n" 1914 " return obj;\n"
1635 "};\n" 1915 "};\n"
1636 "}\n" 1916 "}\n"
1637 "\n" 1917 "\n"
1638 "\n", 1918 "\n",
1639 "classname", GetPath(options, desc)); 1919 "classname", GetPath(options, desc));
1640 } 1920 }
1641 1921
1642 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, 1922 void Generator::GenerateClassFieldToObject(const GeneratorOptions& options,
1643 io::Printer* printer, 1923 io::Printer* printer,
1644 const FieldDescriptor* field) const { 1924 const FieldDescriptor* field) const {
1645 printer->Print("$fieldname$: ", 1925 printer->Print("$fieldname$: ",
1646 "fieldname", JSObjectFieldName(field)); 1926 "fieldname", JSObjectFieldName(field));
1647 1927
1648 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 1928 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1649 // Message field. 1929 // Message field.
1650 if (field->is_repeated()) { 1930 if (field->is_repeated()) {
1651 { 1931 {
1652 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n" 1932 printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
1653 " $type$.toObject, includeInstance)", 1933 " $type$.toObject, includeInstance)",
1654 "getter", JSGetterName(field), 1934 "getter", JSGetterName(field),
1655 "type", GetPath(options, field->message_type())); 1935 "type", SubmessageTypeRef(options, field));
1656 } 1936 }
1657 } else { 1937 } else {
1658 printer->Print("(f = msg.get$getter$()) && " 1938 printer->Print("(f = msg.get$getter$()) && "
1659 "$type$.toObject(includeInstance, f)", 1939 "$type$.toObject(includeInstance, f)",
1660 "getter", JSGetterName(field), 1940 "getter", JSGetterName(field),
1661 "type", GetPath(options, field->message_type())); 1941 "type", SubmessageTypeRef(options, field));
1662 } 1942 }
1663 } else { 1943 } else {
1664 // Simple field (singular or repeated). 1944 // Simple field (singular or repeated).
1665 if (!HasFieldPresence(field) && !field->is_repeated()) { 1945 if ((!HasFieldPresence(field) && !field->is_repeated()) ||
1946 field->type() == FieldDescriptor::TYPE_BYTES) {
1666 // Delegate to the generated get<field>() method in order not to duplicate 1947 // Delegate to the generated get<field>() method in order not to duplicate
1667 // the proto3-field-default-value logic here. 1948 // the proto3-field-default-value or byte-coercion logic here.
1668 printer->Print("msg.get$getter$()", 1949 printer->Print("msg.get$getter$()",
1669 "getter", JSGetterName(field)); 1950 "getter", JSGetterName(field, BYTES_B64));
1670 } else { 1951 } else {
1671 if (field->has_default_value()) { 1952 if (field->has_default_value()) {
1672 printer->Print("jspb.Message.getField(msg, $index$) != null ? " 1953 printer->Print("jspb.Message.getField(msg, $index$) == null ? "
1673 "jspb.Message.getField(msg, $index$) : $defaultValue$", 1954 "$defaultValue$ : ",
1674 "index", JSFieldIndex(field), 1955 "index", JSFieldIndex(field),
1675 "defaultValue", JSFieldDefault(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 }
1676 } else { 1973 } else {
1677 printer->Print("jspb.Message.getField(msg, $index$)", 1974 printer->Print("jspb.Message.getField(msg, $index$)",
1678 "index", JSFieldIndex(field)); 1975 "index", JSFieldIndex(field));
1679 } 1976 }
1680 } 1977 }
1681 } 1978 }
1682 } 1979 }
1683 1980
1684 void Generator::GenerateClassFromObject(const GeneratorOptions& options, 1981 void Generator::GenerateClassFromObject(const GeneratorOptions& options,
1685 io::Printer* printer, 1982 io::Printer* printer,
(...skipping 30 matching lines...) Expand all
1716 if (field->is_repeated()) { 2013 if (field->is_repeated()) {
1717 { 2014 {
1718 printer->Print( 2015 printer->Print(
1719 " goog.isDef(obj.$name$) && " 2016 " goog.isDef(obj.$name$) && "
1720 "jspb.Message.setRepeatedWrapperField(\n" 2017 "jspb.Message.setRepeatedWrapperField(\n"
1721 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n" 2018 " msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
1722 " return $fieldclass$.fromObject(i);\n" 2019 " return $fieldclass$.fromObject(i);\n"
1723 " }));\n", 2020 " }));\n",
1724 "name", JSObjectFieldName(field), 2021 "name", JSObjectFieldName(field),
1725 "index", JSFieldIndex(field), 2022 "index", JSFieldIndex(field),
1726 "fieldclass", GetPath(options, field->message_type())); 2023 "fieldclass", SubmessageTypeRef(options, field));
1727 } 2024 }
1728 } else { 2025 } else {
1729 printer->Print( 2026 printer->Print(
1730 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n" 2027 " goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
1731 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n", 2028 " msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
1732 "name", JSObjectFieldName(field), 2029 "name", JSObjectFieldName(field),
1733 "index", JSFieldIndex(field), 2030 "index", JSFieldIndex(field),
1734 "fieldclass", GetPath(options, field->message_type())); 2031 "fieldclass", SubmessageTypeRef(options, field));
1735 } 2032 }
1736 } else { 2033 } else {
1737 // Simple (primitive) field. 2034 // Simple (primitive) field.
1738 printer->Print( 2035 printer->Print(
1739 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, " 2036 " goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
1740 "obj.$name$);\n", 2037 "obj.$name$);\n",
1741 "name", JSObjectFieldName(field), 2038 "name", JSObjectFieldName(field),
1742 "index", JSFieldIndex(field)); 2039 "index", JSFieldIndex(field));
1743 } 2040 }
1744 } 2041 }
(...skipping 29 matching lines...) Expand all
1774 void Generator::GenerateClassFields(const GeneratorOptions& options, 2071 void Generator::GenerateClassFields(const GeneratorOptions& options,
1775 io::Printer* printer, 2072 io::Printer* printer,
1776 const Descriptor* desc) const { 2073 const Descriptor* desc) const {
1777 for (int i = 0; i < desc->field_count(); i++) { 2074 for (int i = 0; i < desc->field_count(); i++) {
1778 if (!IgnoreField(desc->field(i))) { 2075 if (!IgnoreField(desc->field(i))) {
1779 GenerateClassField(options, printer, desc->field(i)); 2076 GenerateClassField(options, printer, desc->field(i));
1780 } 2077 }
1781 } 2078 }
1782 } 2079 }
1783 2080
2081 void GenerateBytesWrapper(const GeneratorOptions& options,
2082 io::Printer* printer,
2083 const FieldDescriptor* field,
2084 BytesMode bytes_mode) {
2085 string type =
2086 JSFieldTypeAnnotation(options, field,
2087 /* force_optional = */ false,
2088 /* force_present = */ !HasFieldPresence(field),
2089 /* singular_if_not_packed = */ false,
2090 bytes_mode);
2091 printer->Print(
2092 "/**\n"
2093 " * $fielddef$\n"
2094 "$comment$"
2095 " * This is a type-conversion wrapper around `get$defname$()`\n"
2096 " * @return {$type$}\n"
2097 " */\n"
2098 "$class$.prototype.get$name$ = function() {\n"
2099 " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n"
2100 " this.get$defname$()));\n"
2101 "};\n"
2102 "\n"
2103 "\n",
2104 "fielddef", FieldDefinition(options, field),
2105 "comment", FieldComments(field, bytes_mode),
2106 "type", type,
2107 "class", GetPath(options, field->containing_type()),
2108 "name", JSGetterName(field, bytes_mode),
2109 "list", field->is_repeated() ? "List" : "",
2110 "suffix", JSByteGetterSuffix(bytes_mode),
2111 "defname", JSGetterName(field, BYTES_DEFAULT));
2112 }
2113
2114
1784 void Generator::GenerateClassField(const GeneratorOptions& options, 2115 void Generator::GenerateClassField(const GeneratorOptions& options,
1785 io::Printer* printer, 2116 io::Printer* printer,
1786 const FieldDescriptor* field) const { 2117 const FieldDescriptor* field) const {
1787 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 2118 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
1788 printer->Print( 2119 printer->Print(
1789 "/**\n" 2120 "/**\n"
1790 " * $fielddef$\n" 2121 " * $fielddef$\n"
1791 "$comment$" 2122 "$comment$"
1792 " * @return {$type$}\n" 2123 " * @return {$type$}\n"
1793 " */\n", 2124 " */\n",
1794 "fielddef", FieldDefinition(options, field), 2125 "fielddef", FieldDefinition(options, field),
1795 "comment", FieldComments(field), 2126 "comment", FieldComments(field, BYTES_DEFAULT),
1796 "type", JSFieldTypeAnnotation(options, field, 2127 "type", JSFieldTypeAnnotation(options, field,
1797 /* force_optional = */ false, 2128 /* force_optional = */ false,
1798 /* force_present = */ false, 2129 /* force_present = */ false,
1799 /* singular_if_not_packed = */ false, 2130 /* singular_if_not_packed = */ false));
1800 /* always_singular = */ false));
1801 printer->Print( 2131 printer->Print(
1802 "$class$.prototype.get$name$ = function() {\n" 2132 "$class$.prototype.get$name$ = function() {\n"
1803 " return /** @type{$type$} */ (\n" 2133 " return /** @type{$type$} */ (\n"
1804 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, " 2134 " jspb.Message.get$rpt$WrapperField(this, $wrapperclass$, "
1805 "$index$$required$));\n" 2135 "$index$$required$));\n"
1806 "};\n" 2136 "};\n"
1807 "\n" 2137 "\n"
1808 "\n", 2138 "\n",
1809 "class", GetPath(options, field->containing_type()), 2139 "class", GetPath(options, field->containing_type()),
1810 "name", JSGetterName(field), 2140 "name", JSGetterName(field),
1811 "type", JSFieldTypeAnnotation(options, field, 2141 "type", JSFieldTypeAnnotation(options, field,
1812 /* force_optional = */ false, 2142 /* force_optional = */ false,
1813 /* force_present = */ false, 2143 /* force_present = */ false,
1814 /* singular_if_not_packed = */ false, 2144 /* singular_if_not_packed = */ false),
1815 /* always_singular = */ false),
1816 "rpt", (field->is_repeated() ? "Repeated" : ""), 2145 "rpt", (field->is_repeated() ? "Repeated" : ""),
1817 "index", JSFieldIndex(field), 2146 "index", JSFieldIndex(field),
1818 "wrapperclass", GetPath(options, field->message_type()), 2147 "wrapperclass", SubmessageTypeRef(options, field),
1819 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ? 2148 "required", (field->label() == FieldDescriptor::LABEL_REQUIRED ?
1820 ", 1" : "")); 2149 ", 1" : ""));
1821 printer->Print( 2150 printer->Print(
1822 "/** @param {$optionaltype$} value $returndoc$ */\n" 2151 "/** @param {$optionaltype$} value $returndoc$ */\n"
1823 "$class$.prototype.set$name$ = function(value) {\n" 2152 "$class$.prototype.set$name$ = function(value) {\n"
1824 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(", 2153 " jspb.Message.set$oneoftag$$repeatedtag$WrapperField(",
1825 "optionaltype", 2154 "optionaltype",
1826 JSFieldTypeAnnotation(options, field, 2155 JSFieldTypeAnnotation(options, field,
1827 /* force_optional = */ true, 2156 /* force_optional = */ true,
1828 /* force_present = */ false, 2157 /* force_present = */ false,
1829 /* singular_if_not_packed = */ false, 2158 /* singular_if_not_packed = */ false),
1830 /* always_singular = */ false),
1831 "returndoc", JSReturnDoc(options, field), 2159 "returndoc", JSReturnDoc(options, field),
1832 "class", GetPath(options, field->containing_type()), 2160 "class", GetPath(options, field->containing_type()),
1833 "name", JSGetterName(field), 2161 "name", JSGetterName(field),
1834 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), 2162 "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
1835 "repeatedtag", (field->is_repeated() ? "Repeated" : "")); 2163 "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
1836 2164
1837 printer->Print( 2165 printer->Print(
1838 "this, $index$$oneofgroup$, value);$returnvalue$\n" 2166 "this, $index$$oneofgroup$, value);$returnvalue$\n"
1839 "};\n" 2167 "};\n"
1840 "\n" 2168 "\n"
1841 "\n", 2169 "\n",
1842 "index", JSFieldIndex(field), 2170 "index", JSFieldIndex(field),
1843 "oneofgroup", (field->containing_oneof() ? 2171 "oneofgroup", (field->containing_oneof() ?
1844 (", " + JSOneofArray(options, field)) : ""), 2172 (", " + JSOneofArray(options, field)) : ""),
1845 "returnvalue", JSReturnClause(field)); 2173 "returnvalue", JSReturnClause(field));
1846 2174
1847 printer->Print( 2175 printer->Print(
1848 "$class$.prototype.clear$name$ = function() {\n" 2176 "$class$.prototype.clear$name$ = function() {\n"
1849 " this.set$name$($clearedvalue$);$returnvalue$\n" 2177 " this.set$name$($clearedvalue$);$returnvalue$\n"
1850 "};\n" 2178 "};\n"
1851 "\n" 2179 "\n"
1852 "\n", 2180 "\n",
1853 "class", GetPath(options, field->containing_type()), 2181 "class", GetPath(options, field->containing_type()),
1854 "name", JSGetterName(field), 2182 "name", JSGetterName(field),
1855 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"), 2183 "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
1856 "returnvalue", JSReturnClause(field)); 2184 "returnvalue", JSReturnClause(field));
1857 2185
1858 } else { 2186 } else {
1859 string typed_annotation; 2187 bool untyped =
2188 false;
1860 2189
1861 // Simple (primitive) field, either singular or repeated. 2190 // Simple (primitive) field, either singular or repeated.
1862 { 2191
1863 typed_annotation = JSFieldTypeAnnotation(options, field, 2192 // 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
2194 // type is always base64 string, pending a LSC to migrate to typed getters.
2195 BytesMode bytes_mode =
2196 field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ?
2197 BYTES_B64 : BYTES_DEFAULT;
2198 string typed_annotation =
2199 JSFieldTypeAnnotation(options, field,
1864 /* force_optional = */ false, 2200 /* force_optional = */ false,
1865 /* force_present = */ !HasFieldPresence(field), 2201 /* force_present = */ !HasFieldPresence(field),
1866 /* singular_if_not_packed = */ false, 2202 /* singular_if_not_packed = */ false,
1867 /* always_singular = */ false), 2203 /* bytes_mode = */ bytes_mode);
2204 if (untyped) {
2205 printer->Print(
2206 "/**\n"
2207 " * @return {?} Raw field, untyped.\n"
2208 " */\n");
2209 } else {
1868 printer->Print( 2210 printer->Print(
1869 "/**\n" 2211 "/**\n"
1870 " * $fielddef$\n" 2212 " * $fielddef$\n"
1871 "$comment$" 2213 "$comment$"
1872 " * @return {$type$}\n" 2214 " * @return {$type$}\n"
1873 " */\n", 2215 " */\n",
1874 "fielddef", FieldDefinition(options, field), 2216 "fielddef", FieldDefinition(options, field),
1875 "comment", FieldComments(field), 2217 "comment", FieldComments(field, bytes_mode),
1876 "type", typed_annotation); 2218 "type", typed_annotation);
1877 } 2219 }
1878 2220
1879 printer->Print( 2221 printer->Print(
1880 "$class$.prototype.get$name$ = function() {\n", 2222 "$class$.prototype.get$name$ = function() {\n",
1881 "class", GetPath(options, field->containing_type()), 2223 "class", GetPath(options, field->containing_type()),
1882 "name", JSGetterName(field)); 2224 "name", JSGetterName(field));
1883 2225
1884 { 2226 if (untyped) {
2227 printer->Print(
2228 " return ");
2229 } else {
1885 printer->Print( 2230 printer->Print(
1886 " return /** @type {$type$} */ (", 2231 " return /** @type {$type$} */ (",
1887 "type", typed_annotation); 2232 "type", typed_annotation);
1888 } 2233 }
1889 2234
1890 // For proto3 fields without presence, use special getters that will return 2235 // For proto3 fields without presence, use special getters that will return
1891 // defaults when the field is unset, possibly constructing a value if 2236 // defaults when the field is unset, possibly constructing a value if
1892 // required. 2237 // required.
1893 if (!HasFieldPresence(field) && !field->is_repeated()) { 2238 if (!HasFieldPresence(field) && !field->is_repeated()) {
1894 printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)", 2239 printer->Print("jspb.Message.getFieldProto3(this, $index$, $default$)",
1895 "index", JSFieldIndex(field), 2240 "index", JSFieldIndex(field),
1896 "default", Proto3PrimitiveFieldDefault(field)); 2241 "default", Proto3PrimitiveFieldDefault(field));
1897 } else { 2242 } else {
1898 if (field->has_default_value()) { 2243 if (field->has_default_value()) {
1899 printer->Print("jspb.Message.getField(this, $index$) != null ? " 2244 printer->Print("jspb.Message.getField(this, $index$) == null ? "
1900 "jspb.Message.getField(this, $index$) : $defaultValue$", 2245 "$defaultValue$ : ",
1901 "index", JSFieldIndex(field), 2246 "index", JSFieldIndex(field),
1902 "defaultValue", JSFieldDefault(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 }
1903 } else { 2264 } else {
1904 printer->Print("jspb.Message.getField(this, $index$)", 2265 printer->Print("jspb.Message.getField(this, $index$)",
1905 "index", JSFieldIndex(field)); 2266 "index", JSFieldIndex(field));
1906 } 2267 }
1907 } 2268 }
1908 2269
1909 { 2270 if (untyped) {
2271 printer->Print(
2272 ";\n"
2273 "};\n"
2274 "\n"
2275 "\n");
2276 } else {
1910 printer->Print( 2277 printer->Print(
1911 ");\n" 2278 ");\n"
1912 "};\n" 2279 "};\n"
1913 "\n" 2280 "\n"
1914 "\n"); 2281 "\n");
1915 } 2282 }
1916 2283
1917 { 2284 if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) {
2285 GenerateBytesWrapper(options, printer, field, BYTES_B64);
2286 GenerateBytesWrapper(options, printer, field, BYTES_U8);
2287 }
2288
2289 if (untyped) {
2290 printer->Print(
2291 "/**\n"
2292 " * @param {*} value $returndoc$\n"
2293 " */\n",
2294 "returndoc", JSReturnDoc(options, field));
2295 } else {
1918 printer->Print( 2296 printer->Print(
1919 "/** @param {$optionaltype$} value $returndoc$ */\n", 2297 "/** @param {$optionaltype$} value $returndoc$ */\n",
1920 "optionaltype", 2298 "optionaltype",
1921 JSFieldTypeAnnotation(options, field, 2299 JSFieldTypeAnnotation(options, field,
1922 /* force_optional = */ true, 2300 /* force_optional = */ true,
1923 /* force_present = */ !HasFieldPresence(field), 2301 /* force_present = */ !HasFieldPresence(field),
1924 /* singular_if_not_packed = */ false, 2302 /* singular_if_not_packed = */ false),
1925 /* always_singular = */ false),
1926 "returndoc", JSReturnDoc(options, field)); 2303 "returndoc", JSReturnDoc(options, field));
1927 } 2304 }
1928
1929 printer->Print( 2305 printer->Print(
1930 "$class$.prototype.set$name$ = function(value) {\n" 2306 "$class$.prototype.set$name$ = function(value) {\n"
1931 " jspb.Message.set$oneoftag$Field(this, $index$", 2307 " jspb.Message.set$oneoftag$Field(this, $index$",
1932 "class", GetPath(options, field->containing_type()), 2308 "class", GetPath(options, field->containing_type()),
1933 "name", JSGetterName(field), 2309 "name", JSGetterName(field),
1934 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), 2310 "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
1935 "index", JSFieldIndex(field)); 2311 "index", JSFieldIndex(field));
1936 printer->Print( 2312 printer->Print(
1937 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n" 2313 "$oneofgroup$, $type$value$rptvalueinit$$typeclose$);$returnvalue$\n"
1938 "};\n" 2314 "};\n"
1939 "\n" 2315 "\n"
1940 "\n", 2316 "\n",
1941 "type", "", 2317 "type",
1942 "typeclose", "", 2318 untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "",
2319 "typeclose", untyped ? ")" : "",
1943 "oneofgroup", 2320 "oneofgroup",
1944 (field->containing_oneof() ? (", " + JSOneofArray(options, field)) 2321 (field->containing_oneof() ? (", " + JSOneofArray(options, field))
1945 : ""), 2322 : ""),
1946 "returnvalue", JSReturnClause(field), "rptvalueinit", 2323 "returnvalue", JSReturnClause(field), "rptvalueinit",
1947 (field->is_repeated() ? " || []" : "")); 2324 (field->is_repeated() ? " || []" : ""));
1948 2325
2326 if (untyped) {
2327 printer->Print(
2328 "/**\n"
2329 " * Clears the value. $returndoc$\n"
2330 " */\n",
2331 "returndoc", JSReturnDoc(options, field));
2332 }
1949 2333
1950 if (HasFieldPresence(field)) { 2334 if (HasFieldPresence(field)) {
1951 printer->Print( 2335 printer->Print(
1952 "$class$.prototype.clear$name$ = function() {\n" 2336 "$class$.prototype.clear$name$ = function() {\n"
1953 " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ", 2337 " jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
1954 "class", GetPath(options, field->containing_type()), 2338 "class", GetPath(options, field->containing_type()),
1955 "name", JSGetterName(field), 2339 "name", JSGetterName(field),
1956 "oneoftag", (field->containing_oneof() ? "Oneof" : ""), 2340 "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
1957 "oneofgroup", (field->containing_oneof() ? 2341 "oneofgroup", (field->containing_oneof() ?
1958 (", " + JSOneofArray(options, field)) : ""), 2342 (", " + JSOneofArray(options, field)) : ""),
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
2036 } 2420 }
2037 2421
2038 printer->Print( 2422 printer->Print(
2039 " default:\n"); 2423 " default:\n");
2040 if (IsExtendable(desc)) { 2424 if (IsExtendable(desc)) {
2041 printer->Print( 2425 printer->Print(
2042 " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n" 2426 " jspb.Message.readBinaryExtension(msg, reader, $extobj$,\n"
2043 " $class$.prototype.getExtension,\n" 2427 " $class$.prototype.getExtension,\n"
2044 " $class$.prototype.setExtension);\n" 2428 " $class$.prototype.setExtension);\n"
2045 " break;\n", 2429 " break;\n",
2046 "extobj", JSExtensionsObjectName(options, desc), 2430 "extobj", JSExtensionsObjectName(options, desc->file(), desc),
2047 "class", GetPath(options, desc)); 2431 "class", GetPath(options, desc));
2048 } else { 2432 } else {
2049 printer->Print( 2433 printer->Print(
2050 " reader.skipField();\n" 2434 " reader.skipField();\n"
2051 " break;\n"); 2435 " break;\n");
2052 } 2436 }
2053 2437
2054 printer->Print( 2438 printer->Print(
2055 " }\n" 2439 " }\n"
2056 " }\n" 2440 " }\n"
2057 " return msg;\n" 2441 " return msg;\n"
2058 "};\n" 2442 "};\n"
2059 "\n" 2443 "\n"
2060 "\n"); 2444 "\n");
2061 } 2445 }
2062 2446
2063 void Generator::GenerateClassDeserializeBinaryField( 2447 void Generator::GenerateClassDeserializeBinaryField(
2064 const GeneratorOptions& options, 2448 const GeneratorOptions& options,
2065 io::Printer* printer, 2449 io::Printer* printer,
2066 const FieldDescriptor* field) const { 2450 const FieldDescriptor* field) const {
2067 2451
2068 printer->Print(" case $num$:\n", 2452 printer->Print(" case $num$:\n",
2069 "num", SimpleItoa(field->number())); 2453 "num", SimpleItoa(field->number()));
2070 2454
2071 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 2455 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2072 printer->Print( 2456 printer->Print(
2073 " var value = new $fieldclass$;\n" 2457 " var value = new $fieldclass$;\n"
2074 " reader.read$msgOrGroup$($grpfield$value," 2458 " reader.read$msgOrGroup$($grpfield$value,"
2075 "$fieldclass$.deserializeBinaryFromReader);\n", 2459 "$fieldclass$.deserializeBinaryFromReader);\n",
2076 "fieldclass", GetPath(options, field->message_type()), 2460 "fieldclass", SubmessageTypeRef(options, field),
2077 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ? 2461 "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
2078 "Group" : "Message", 2462 "Group" : "Message",
2079 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ? 2463 "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
2080 (SimpleItoa(field->number()) + ", ") : ""); 2464 (SimpleItoa(field->number()) + ", ") : "");
2081 } else { 2465 } else {
2082 printer->Print( 2466 printer->Print(
2083 " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", 2467 " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
2084 "fieldtype", JSFieldTypeAnnotation(options, field, false, true, 2468 "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
2085 /* singular_if_not_packed = */ true, 2469 /* singular_if_not_packed = */ true,
2086 /* always_singular = */ false), 2470 BYTES_U8),
2087 "reader", JSBinaryReaderMethodName(field)); 2471 "reader", JSBinaryReaderMethodName(field));
2088 } 2472 }
2089 2473
2090 if (field->is_repeated() && !field->is_packed()) { 2474 if (field->is_repeated() && !field->is_packed()) {
2091 // Repeated fields receive a |value| one at at a time; append to array 2475 // Repeated fields receive a |value| one at at a time; append to array
2092 // returned by get$name$(). 2476 // returned by get$name$(). Annoyingly, we have to call 'set' after
2093 printer->Print( 2477 // changing the array.
2094 " msg.get$name$().push(value);\n", 2478 printer->Print(" msg.get$name$().push(value);\n", "name",
2095 "name", JSGetterName(field)); 2479 JSGetterName(field));
2480 printer->Print(" msg.set$name$(msg.get$name$());\n", "name",
2481 JSGetterName(field));
2096 } else { 2482 } else {
2097 // Singular fields, and packed repeated fields, receive a |value| either as 2483 // Singular fields, and packed repeated fields, receive a |value| either as
2098 // the field's value or as the array of all the field's values; set this as 2484 // the field's value or as the array of all the field's values; set this as
2099 // the field's value directly. 2485 // the field's value directly.
2100 printer->Print( 2486 printer->Print(
2101 " msg.set$name$(value);\n", 2487 " msg.set$name$(value);\n",
2102 "name", JSGetterName(field)); 2488 "name", JSGetterName(field));
2103 } 2489 }
2104 2490
2105 printer->Print(" break;\n"); 2491 printer->Print(" break;\n");
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2142 "class", GetPath(options, desc)); 2528 "class", GetPath(options, desc));
2143 2529
2144 for (int i = 0; i < desc->field_count(); i++) { 2530 for (int i = 0; i < desc->field_count(); i++) {
2145 GenerateClassSerializeBinaryField(options, printer, desc->field(i)); 2531 GenerateClassSerializeBinaryField(options, printer, desc->field(i));
2146 } 2532 }
2147 2533
2148 if (IsExtendable(desc)) { 2534 if (IsExtendable(desc)) {
2149 printer->Print( 2535 printer->Print(
2150 " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n" 2536 " jspb.Message.serializeBinaryExtensions(this, writer, $extobj$,\n"
2151 " $class$.prototype.getExtension);\n", 2537 " $class$.prototype.getExtension);\n",
2152 "extobj", JSExtensionsObjectName(options, desc), 2538 "extobj", JSExtensionsObjectName(options, desc->file(), desc),
2153 "class", GetPath(options, desc)); 2539 "class", GetPath(options, desc));
2154 } 2540 }
2155 2541
2156 printer->Print( 2542 printer->Print(
2157 "};\n" 2543 "};\n"
2158 "\n" 2544 "\n"
2159 "\n"); 2545 "\n");
2160 } 2546 }
2161 2547
2162 void Generator::GenerateClassSerializeBinaryField( 2548 void Generator::GenerateClassSerializeBinaryField(
2163 const GeneratorOptions& options, 2549 const GeneratorOptions& options,
2164 io::Printer* printer, 2550 io::Printer* printer,
2165 const FieldDescriptor* field) const { 2551 const FieldDescriptor* field) const {
2166 printer->Print( 2552 printer->Print(
2167 " f = this.get$name$();\n", 2553 " f = this.get$name$();\n",
2168 "name", JSGetterName(field)); 2554 "name", JSGetterName(field, BYTES_U8));
2169 2555
2170 if (field->is_repeated()) { 2556 if (field->is_repeated()) {
2171 printer->Print( 2557 printer->Print(
2172 " if (f.length > 0) {\n"); 2558 " if (f.length > 0) {\n");
2173 } else { 2559 } else {
2174 if (HasFieldPresence(field)) { 2560 if (HasFieldPresence(field)) {
2175 printer->Print( 2561 printer->Print(
2176 " if (f != null) {\n"); 2562 " if (f != null) {\n");
2177 } else { 2563 } else {
2178 // No field presence: serialize onto the wire only if value is 2564 // No field presence: serialize onto the wire only if value is
(...skipping 29 matching lines...) Expand all
2208 break; 2594 break;
2209 } 2595 }
2210 } 2596 }
2211 } 2597 }
2212 2598
2213 printer->Print( 2599 printer->Print(
2214 " writer.$writer$(\n" 2600 " writer.$writer$(\n"
2215 " $index$,\n" 2601 " $index$,\n"
2216 " f", 2602 " f",
2217 "writer", JSBinaryWriterMethodName(field), 2603 "writer", JSBinaryWriterMethodName(field),
2218 "name", JSGetterName(field),
2219 "index", SimpleItoa(field->number())); 2604 "index", SimpleItoa(field->number()));
2220 2605
2221 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 2606 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
2222 printer->Print( 2607 printer->Print(
2223 ",\n" 2608 ",\n"
2224 " $submsg$.serializeBinaryToWriter\n", 2609 " $submsg$.serializeBinaryToWriter\n",
2225 "submsg", GetPath(options, field->message_type())); 2610 "submsg", SubmessageTypeRef(options, field));
2226 } else { 2611 } else {
2227 printer->Print("\n"); 2612 printer->Print("\n");
2228 } 2613 }
2229 printer->Print( 2614 printer->Print(
2230 " );\n" 2615 " );\n"
2231 " }\n"); 2616 " }\n");
2232 } 2617 }
2233 2618
2234 void Generator::GenerateEnum(const GeneratorOptions& options, 2619 void Generator::GenerateEnum(const GeneratorOptions& options,
2235 io::Printer* printer, 2620 io::Printer* printer,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2270 " * field named `$name$`.\n" 2655 " * field named `$name$`.\n"
2271 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n" 2656 " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
2272 " */\n" 2657 " */\n"
2273 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n", 2658 "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
2274 "name", JSObjectFieldName(field), 2659 "name", JSObjectFieldName(field),
2275 "class", extension_scope, 2660 "class", extension_scope,
2276 "extensionType", JSFieldTypeAnnotation( 2661 "extensionType", JSFieldTypeAnnotation(
2277 options, field, 2662 options, field,
2278 /* force_optional = */ false, 2663 /* force_optional = */ false,
2279 /* force_present = */ true, 2664 /* force_present = */ true,
2280 /* singular_if_not_packed = */ false, 2665 /* singular_if_not_packed = */ false));
2281 /* always_singular = */ false));
2282 printer->Print( 2666 printer->Print(
2283 " $index$,\n" 2667 " $index$,\n"
2284 " {$name$: 0},\n" 2668 " {$name$: 0},\n"
2285 " $ctor$,\n" 2669 " $ctor$,\n"
2286 " /** @type {?function((boolean|undefined),!jspb.Message=): " 2670 " /** @type {?function((boolean|undefined),!jspb.Message=): "
2287 "!Object} */ (\n" 2671 "!Object} */ (\n"
2288 " $toObject$),\n" 2672 " $toObject$),\n"
2289 " $repeated$", 2673 " $repeated$",
2290 "index", SimpleItoa(field->number()), 2674 "index", SimpleItoa(field->number()),
2291 "name", JSObjectFieldName(field), 2675 "name", JSObjectFieldName(field),
2292 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? 2676 "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
2293 GetPath(options, field->message_type()) : string("null")), 2677 SubmessageTypeRef(options, field) : string("null")),
2294 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ? 2678 "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
2295 (GetPath(options, field->message_type()) + ".toObject") : 2679 (SubmessageTypeRef(options, field) + ".toObject") :
2296 string("null")), 2680 string("null")),
2297 "repeated", (field->is_repeated() ? "1" : "0")); 2681 "repeated", (field->is_repeated() ? "1" : "0"));
2298 2682
2299 if (options.binary) { 2683 if (options.binary) {
2300 printer->Print( 2684 printer->Print(
2301 ",\n" 2685 ",\n"
2302 " jspb.BinaryReader.prototype.$binaryReaderFn$,\n" 2686 " jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
2303 " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n" 2687 " jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
2304 " $binaryMessageSerializeFn$,\n" 2688 " $binaryMessageSerializeFn$,\n"
2305 " $binaryMessageDeserializeFn$,\n" 2689 " $binaryMessageDeserializeFn$,\n"
2306 " $isPacked$);\n", 2690 " $isPacked$);\n",
2307 "binaryReaderFn", JSBinaryReaderMethodName(field), 2691 "binaryReaderFn", JSBinaryReaderMethodName(field),
2308 "binaryWriterFn", JSBinaryWriterMethodName(field), 2692 "binaryWriterFn", JSBinaryWriterMethodName(field),
2309 "binaryMessageSerializeFn", 2693 "binaryMessageSerializeFn",
2310 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? 2694 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
2311 (GetPath(options, field->message_type()) + 2695 (SubmessageTypeRef(options, field) +
2312 ".serializeBinaryToWriter") : "null", 2696 ".serializeBinaryToWriter") : "null",
2313 "binaryMessageDeserializeFn", 2697 "binaryMessageDeserializeFn",
2314 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? 2698 (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
2315 (GetPath(options, field->message_type()) + 2699 (SubmessageTypeRef(options, field) +
2316 ".deserializeBinaryFromReader") : "null", 2700 ".deserializeBinaryFromReader") : "null",
2317 "isPacked", (field->is_packed() ? "true" : "false")); 2701 "isPacked", (field->is_packed() ? "true" : "false"));
2318 } else { 2702 } else {
2319 printer->Print(");\n"); 2703 printer->Print(");\n");
2320 } 2704 }
2321 2705
2322 printer->Print( 2706 printer->Print(
2323 "// This registers the extension field with the extended class, so that\n" 2707 "// This registers the extension field with the extended class, so that\n"
2324 "// toObject() will function correctly.\n" 2708 "// toObject() will function correctly.\n"
2325 "$extendName$[$index$] = $class$.$name$;\n" 2709 "$extendName$[$index$] = $class$.$name$;\n"
2326 "\n", 2710 "\n",
2327 "extendName", JSExtensionsObjectName(options, field->containing_type()), 2711 "extendName", JSExtensionsObjectName(options, field->file(),
2712 field->containing_type()),
2328 "index", SimpleItoa(field->number()), 2713 "index", SimpleItoa(field->number()),
2329 "class", extension_scope, 2714 "class", extension_scope,
2330 "name", JSObjectFieldName(field)); 2715 "name", JSObjectFieldName(field));
2331 } 2716 }
2332 2717
2333 bool GeneratorOptions::ParseFromOptions( 2718 bool GeneratorOptions::ParseFromOptions(
2334 const vector< pair< string, string > >& options, 2719 const vector< pair< string, string > >& options,
2335 string* error) { 2720 string* error) {
2336 for (int i = 0; i < options.size(); i++) { 2721 for (int i = 0; i < options.size(); i++) {
2337 if (options[i].first == "add_require_for_enums") { 2722 if (options[i].first == "add_require_for_enums") {
(...skipping 19 matching lines...) Expand all
2357 *error = "Unexpected option value for error_on_name_conflict"; 2742 *error = "Unexpected option value for error_on_name_conflict";
2358 return false; 2743 return false;
2359 } 2744 }
2360 error_on_name_conflict = true; 2745 error_on_name_conflict = true;
2361 } else if (options[i].first == "output_dir") { 2746 } else if (options[i].first == "output_dir") {
2362 output_dir = options[i].second; 2747 output_dir = options[i].second;
2363 } else if (options[i].first == "namespace_prefix") { 2748 } else if (options[i].first == "namespace_prefix") {
2364 namespace_prefix = options[i].second; 2749 namespace_prefix = options[i].second;
2365 } else if (options[i].first == "library") { 2750 } else if (options[i].first == "library") {
2366 library = options[i].second; 2751 library = options[i].second;
2752 } else if (options[i].first == "import_style") {
2753 if (options[i].second == "closure") {
2754 import_style = IMPORT_CLOSURE;
2755 } else if (options[i].second == "commonjs") {
2756 import_style = IMPORT_COMMONJS;
2757 } else if (options[i].second == "browser") {
2758 import_style = IMPORT_BROWSER;
2759 } else if (options[i].second == "es6") {
2760 import_style = IMPORT_ES6;
2761 } else {
2762 *error = "Unknown import style " + options[i].second + ", expected " +
2763 "one of: closure, commonjs, browser, es6.";
2764 }
2367 } else { 2765 } else {
2368 // Assume any other option is an output directory, as long as it is a bare 2766 // Assume any other option is an output directory, as long as it is a bare
2369 // `key` rather than a `key=value` option. 2767 // `key` rather than a `key=value` option.
2370 if (options[i].second != "") { 2768 if (options[i].second != "") {
2371 *error = "Unknown option: " + options[i].first; 2769 *error = "Unknown option: " + options[i].first;
2372 return false; 2770 return false;
2373 } 2771 }
2374 output_dir = options[i].first; 2772 output_dir = options[i].first;
2375 } 2773 }
2376 } 2774 }
2377 2775
2776 if (!library.empty() && import_style != IMPORT_CLOSURE) {
2777 *error = "The library option should only be used for "
2778 "import_style=closure";
2779 }
2780
2378 return true; 2781 return true;
2379 } 2782 }
2380 2783
2381 void Generator::GenerateFilesInDepOrder( 2784 void Generator::GenerateFilesInDepOrder(
2382 const GeneratorOptions& options, 2785 const GeneratorOptions& options,
2383 io::Printer* printer, 2786 io::Printer* printer,
2384 const vector<const FileDescriptor*>& files) const { 2787 const vector<const FileDescriptor*>& files) const {
2385 // Build a std::set over all files so that the DFS can detect when it recurses 2788 // Build a std::set over all files so that the DFS can detect when it recurses
2386 // into a dep not specified in the user's command line. 2789 // into a dep not specified in the user's command line.
2387 std::set<const FileDescriptor*> all_files(files.begin(), files.end()); 2790 std::set<const FileDescriptor*> all_files(files.begin(), files.end());
(...skipping 23 matching lines...) Expand all
2411 } 2814 }
2412 2815
2413 // Generate this file's content. Only generate if the file is part of the 2816 // Generate this file's content. Only generate if the file is part of the
2414 // original set requested to be generated; i.e., don't take all transitive 2817 // original set requested to be generated; i.e., don't take all transitive
2415 // deps down to the roots. 2818 // deps down to the roots.
2416 if (all_files->find(root) != all_files->end()) { 2819 if (all_files->find(root) != all_files->end()) {
2417 GenerateClassesAndEnums(options, printer, root); 2820 GenerateClassesAndEnums(options, printer, root);
2418 } 2821 }
2419 } 2822 }
2420 2823
2824 void Generator::GenerateFile(const GeneratorOptions& options,
2825 io::Printer* printer,
2826 const FileDescriptor* file) const {
2827 GenerateHeader(options, printer);
2828
2829 // Generate "require" statements.
2830 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
2831 printer->Print("var jspb = require('google-protobuf');\n");
2832 printer->Print("var goog = jspb;\n");
2833 printer->Print("var global = Function('return this')();\n\n");
2834
2835 for (int i = 0; i < file->dependency_count(); i++) {
2836 const string& name = file->dependency(i)->name();
2837 printer->Print(
2838 "var $alias$ = require('$file$');\n",
2839 "alias", ModuleAlias(name),
2840 "file", GetRootPath(file->name()) + GetJSFilename(name));
2841 }
2842 }
2843
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;
2852
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++) {
2857 provided.insert(file->extension(i)->full_name());
2858 }
2859
2860 FindProvidesForFile(options, printer, file, &provided);
2861 for (std::set<string>::iterator it = provided.begin();
2862 it != provided.end(); ++it) {
2863 printer->Print("goog.exportSymbol('$name$', null, global);\n",
2864 "name", *it);
2865 }
2866
2867 GenerateClassesAndEnums(options, printer, file);
2868
2869 // Extensions nested inside messages are emitted inside
2870 // GenerateClassesAndEnums().
2871 for (int i = 0; i < file->extension_count(); i++) {
2872 GenerateExtension(options, printer, file->extension(i));
2873 }
2874
2875 if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) {
2876 printer->Print("goog.object.extend(exports, $package$);\n",
2877 "package", GetPath(options, file));
2878 }
2879 }
2880
2421 bool Generator::GenerateAll(const vector<const FileDescriptor*>& files, 2881 bool Generator::GenerateAll(const vector<const FileDescriptor*>& files,
2422 const string& parameter, 2882 const string& parameter,
2423 GeneratorContext* context, 2883 GeneratorContext* context,
2424 string* error) const { 2884 string* error) const {
2425 vector< pair< string, string > > option_pairs; 2885 vector< pair< string, string > > option_pairs;
2426 ParseGeneratorParameter(parameter, &option_pairs); 2886 ParseGeneratorParameter(parameter, &option_pairs);
2427 GeneratorOptions options; 2887 GeneratorOptions options;
2428 if (!options.ParseFromOptions(option_pairs, error)) { 2888 if (!options.ParseFromOptions(option_pairs, error)) {
2429 return false; 2889 return false;
2430 } 2890 }
2431 2891
2432 2892
2433 // We're either generating a single library file with definitions for message 2893 // There are three schemes for where output files go:
2434 // and enum types in *all* FileDescriptor inputs, or we're generating a single 2894 //
2435 // file for each type. 2895 // - import_style = IMPORT_CLOSURE, library non-empty: all output in one file
2436 if (options.library != "") { 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.
2437 string filename = options.output_dir + "/" + options.library + ".js"; 2901 string filename = options.output_dir + "/" + options.library + ".js";
2438 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open( filename)); 2902 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open( filename));
2439 GOOGLE_CHECK(output.get()); 2903 GOOGLE_CHECK(output.get());
2440 io::Printer printer(output.get(), '$'); 2904 io::Printer printer(output.get(), '$');
2441 2905
2442 // Pull out all extensions -- we need these to generate all 2906 // Pull out all extensions -- we need these to generate all
2443 // provides/requires. 2907 // provides/requires.
2444 vector<const FieldDescriptor*> extensions; 2908 vector<const FieldDescriptor*> extensions;
2445 for (int i = 0; i < files.size(); i++) { 2909 for (int i = 0; i < files.size(); i++) {
2446 for (int j = 0; j < files[i]->extension_count(); j++) { 2910 for (int j = 0; j < files[i]->extension_count(); j++) {
2447 const FieldDescriptor* extension = files[i]->extension(j); 2911 const FieldDescriptor* extension = files[i]->extension(j);
2448 extensions.push_back(extension); 2912 extensions.push_back(extension);
2449 } 2913 }
2450 } 2914 }
2451 2915
2452 GenerateHeader(options, &printer); 2916 GenerateHeader(options, &printer);
2453 2917
2454 std::set<string> provided; 2918 std::set<string> provided;
2455 FindProvides(options, &printer, files, &provided); 2919 FindProvides(options, &printer, files, &provided);
2456 FindProvidesForFields(options, &printer, extensions, &provided); 2920 FindProvidesForFields(options, &printer, extensions, &provided);
2457 GenerateProvides(options, &printer, &provided); 2921 GenerateProvides(options, &printer, &provided);
2458 GenerateTestOnly(options, &printer); 2922 GenerateTestOnly(options, &printer);
2459 GenerateRequires(options, &printer, files, &provided); 2923 GenerateRequiresForLibrary(options, &printer, files, &provided);
2460 2924
2461 GenerateFilesInDepOrder(options, &printer, files); 2925 GenerateFilesInDepOrder(options, &printer, files);
2462 2926
2463 for (int i = 0; i < extensions.size(); i++) { 2927 for (int i = 0; i < extensions.size(); i++) {
2464 if (ShouldGenerateExtension(extensions[i])) { 2928 if (ShouldGenerateExtension(extensions[i])) {
2465 GenerateExtension(options, &printer, extensions[i]); 2929 GenerateExtension(options, &printer, extensions[i]);
2466 } 2930 }
2467 } 2931 }
2468 2932
2469 if (printer.failed()) { 2933 if (printer.failed()) {
2470 return false; 2934 return false;
2471 } 2935 }
2472 } else { 2936 } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) {
2473 // Collect all types, and print each type to a separate file. Pull out 2937 set<const void*> allowed_set;
2474 // free-floating extensions while we make this pass. 2938 if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) {
2475 map< string, vector<const FieldDescriptor*> > extensions_by_namespace; 2939 return false;
2476
2477 // If we're generating code in file-per-type mode, avoid overwriting files
2478 // by choosing the last descriptor that writes each filename and permitting
2479 // only those to generate code.
2480
2481 // Current descriptor that will generate each filename, indexed by filename.
2482 map<string, const void*> desc_by_filename;
2483 // Set of descriptors allowed to generate files.
2484 set<const void*> allowed_descs;
2485
2486 for (int i = 0; i < files.size(); i++) {
2487 // Collect all (descriptor, filename) pairs.
2488 map<const void*, string> descs_in_file;
2489 for (int j = 0; j < files[i]->message_type_count(); j++) {
2490 const Descriptor* desc = files[i]->message_type(j);
2491 string filename =
2492 options.output_dir + "/" + ToFileName(desc->name()) + ".js";
2493 descs_in_file[desc] = filename;
2494 }
2495 for (int j = 0; j < files[i]->enum_type_count(); j++) {
2496 const EnumDescriptor* desc = files[i]->enum_type(j);
2497 string filename =
2498 options.output_dir + "/" + ToFileName(desc->name()) + ".js";
2499 descs_in_file[desc] = filename;
2500 }
2501
2502 // For each (descriptor, filename) pair, update the
2503 // descriptors-by-filename map, and if a previous descriptor was already
2504 // writing the filename, remove it from the allowed-descriptors set.
2505 map<const void*, string>::iterator it;
2506 for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) {
2507 const void* desc = it->first;
2508 const string& filename = it->second;
2509 if (desc_by_filename.find(filename) != desc_by_filename.end()) {
2510 if (options.error_on_name_conflict) {
2511 *error = "Name conflict: file name " + filename +
2512 " would be generated by two descriptors";
2513 return false;
2514 }
2515 allowed_descs.erase(desc_by_filename[filename]);
2516 }
2517 desc_by_filename[filename] = desc;
2518 allowed_descs.insert(desc);
2519 }
2520 } 2940 }
2521 2941
2522 // Generate code.
2523 for (int i = 0; i < files.size(); i++) { 2942 for (int i = 0; i < files.size(); i++) {
2524 const FileDescriptor* file = files[i]; 2943 const FileDescriptor* file = files[i];
2525 for (int j = 0; j < file->message_type_count(); j++) { 2944 for (int j = 0; j < file->message_type_count(); j++) {
2526 const Descriptor* desc = file->message_type(j); 2945 const Descriptor* desc = file->message_type(j);
2527 if (allowed_descs.find(desc) == allowed_descs.end()) { 2946 if (allowed_set.count(desc) == 0) {
2528 continue; 2947 continue;
2529 } 2948 }
2530 2949
2531 string filename = options.output_dir + "/" + 2950 string filename = GetMessageFileName(options, desc);
2532 ToFileName(desc->name()) + ".js";
2533 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( 2951 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
2534 context->Open(filename)); 2952 context->Open(filename));
2535 GOOGLE_CHECK(output.get()); 2953 GOOGLE_CHECK(output.get());
2536 io::Printer printer(output.get(), '$'); 2954 io::Printer printer(output.get(), '$');
2537 2955
2538 GenerateHeader(options, &printer); 2956 GenerateHeader(options, &printer);
2539 2957
2540 std::set<string> provided; 2958 std::set<string> provided;
2541 FindProvidesForMessage(options, &printer, desc, &provided); 2959 FindProvidesForMessage(options, &printer, desc, &provided);
2542 GenerateProvides(options, &printer, &provided); 2960 GenerateProvides(options, &printer, &provided);
2543 GenerateTestOnly(options, &printer); 2961 GenerateTestOnly(options, &printer);
2544 GenerateRequires(options, &printer, desc, &provided); 2962 GenerateRequiresForMessage(options, &printer, desc, &provided);
2545 2963
2546 GenerateClass(options, &printer, desc); 2964 GenerateClass(options, &printer, desc);
2547 2965
2548 if (printer.failed()) { 2966 if (printer.failed()) {
2549 return false; 2967 return false;
2550 } 2968 }
2551 } 2969 }
2552 for (int j = 0; j < file->enum_type_count(); j++) { 2970 for (int j = 0; j < file->enum_type_count(); j++) {
2553 const EnumDescriptor* enumdesc = file->enum_type(j); 2971 const EnumDescriptor* enumdesc = file->enum_type(j);
2554 if (allowed_descs.find(enumdesc) == allowed_descs.end()) { 2972 if (allowed_set.count(enumdesc) == 0) {
2555 continue; 2973 continue;
2556 } 2974 }
2557 2975
2558 string filename = options.output_dir + "/" + 2976 string filename = GetEnumFileName(options, enumdesc);
2559 ToFileName(enumdesc->name()) + ".js";
2560
2561 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( 2977 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
2562 context->Open(filename)); 2978 context->Open(filename));
2563 GOOGLE_CHECK(output.get()); 2979 GOOGLE_CHECK(output.get());
2564 io::Printer printer(output.get(), '$'); 2980 io::Printer printer(output.get(), '$');
2565 2981
2566 GenerateHeader(options, &printer); 2982 GenerateHeader(options, &printer);
2567 2983
2568 std::set<string> provided; 2984 std::set<string> provided;
2569 FindProvidesForEnum(options, &printer, enumdesc, &provided); 2985 FindProvidesForEnum(options, &printer, enumdesc, &provided);
2570 GenerateProvides(options, &printer, &provided); 2986 GenerateProvides(options, &printer, &provided);
2571 GenerateTestOnly(options, &printer); 2987 GenerateTestOnly(options, &printer);
2572 2988
2573 GenerateEnum(options, &printer, enumdesc); 2989 GenerateEnum(options, &printer, enumdesc);
2574 2990
2575 if (printer.failed()) { 2991 if (printer.failed()) {
2576 return false; 2992 return false;
2577 } 2993 }
2578 } 2994 }
2579 // Pull out all free-floating extensions and generate files for those too. 2995 // File-level extensions (message-level extensions are generated under
2580 for (int j = 0; j < file->extension_count(); j++) { 2996 // the enclosing message).
2581 const FieldDescriptor* extension = file->extension(j); 2997 if (allowed_set.count(file) == 1) {
2582 extensions_by_namespace[GetPath(options, files[i])] 2998 string filename = GetExtensionFileName(options, file);
2583 .push_back(extension); 2999
3000 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
3001 context->Open(filename));
3002 GOOGLE_CHECK(output.get());
3003 io::Printer printer(output.get(), '$');
3004
3005 GenerateHeader(options, &printer);
3006
3007 std::set<string> provided;
3008 vector<const FieldDescriptor*> fields;
3009
3010 for (int j = 0; j < files[i]->extension_count(); j++) {
3011 if (ShouldGenerateExtension(files[i]->extension(j))) {
3012 fields.push_back(files[i]->extension(j));
3013 }
3014 }
3015
3016 FindProvidesForFields(options, &printer, fields, &provided);
3017 GenerateProvides(options, &printer, &provided);
3018 GenerateTestOnly(options, &printer);
3019 GenerateRequiresForExtensions(options, &printer, fields, &provided);
3020
3021 for (int j = 0; j < files[i]->extension_count(); j++) {
3022 if (ShouldGenerateExtension(files[i]->extension(j))) {
3023 GenerateExtension(options, &printer, files[i]->extension(j));
3024 }
3025 }
2584 } 3026 }
2585 } 3027 }
3028 } else {
3029 // Generate one output file per input (.proto) file.
2586 3030
2587 // Generate extensions in separate files. 3031 for (int i = 0; i < files.size(); i++) {
2588 map< string, vector<const FieldDescriptor*> >::iterator it; 3032 const google::protobuf::FileDescriptor* file = files[i];
2589 for (it = extensions_by_namespace.begin();
2590 it != extensions_by_namespace.end();
2591 ++it) {
2592 string filename = options.output_dir + "/" +
2593 ToFileName(it->first) + ".js";
2594 3033
2595 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( 3034 string filename = options.output_dir + "/" + GetJSFilename(file->name());
2596 context->Open(filename)); 3035 google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Ope n(filename));
2597 GOOGLE_CHECK(output.get()); 3036 GOOGLE_CHECK(output.get());
2598 io::Printer printer(output.get(), '$'); 3037 io::Printer printer(output.get(), '$');
2599 3038
2600 GenerateHeader(options, &printer); 3039 GenerateFile(options, &printer, file);
2601 3040
2602 std::set<string> provided; 3041 if (printer.failed()) {
2603 FindProvidesForFields(options, &printer, it->second, &provided); 3042 return false;
2604 GenerateProvides(options, &printer, &provided);
2605 GenerateTestOnly(options, &printer);
2606 GenerateRequires(options, &printer, it->second, &provided);
2607
2608 for (int j = 0; j < it->second.size(); j++) {
2609 if (ShouldGenerateExtension(it->second[j])) {
2610 GenerateExtension(options, &printer, it->second[j]);
2611 }
2612 } 3043 }
2613 } 3044 }
2614 } 3045 }
2615 3046
2616 return true; 3047 return true;
2617 } 3048 }
2618 3049
2619 } // namespace js 3050 } // namespace js
2620 } // namespace compiler 3051 } // namespace compiler
2621 } // namespace protobuf 3052 } // namespace protobuf
2622 } // namespace google 3053 } // namespace google
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698