| 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 |