OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |